changeset 5584:4b26bd55bd24 draft

(svn r8033) [cpp] - Prepare for merge from branches/cpp (all .c files renamed to .cpp)
author KUDr <KUDr@openttd.org>
date Wed, 10 Jan 2007 18:12:09 +0000
parents 2d57664077ee
children d0ae330415c2
files src/ai/ai.c src/ai/ai.cpp src/ai/default/default.c src/ai/default/default.cpp src/ai/trolly/build.c src/ai/trolly/build.cpp src/ai/trolly/pathfinder.c src/ai/trolly/pathfinder.cpp src/ai/trolly/shared.c src/ai/trolly/shared.cpp src/ai/trolly/trolly.c src/ai/trolly/trolly.cpp src/aircraft_gui.c src/aircraft_gui.cpp src/airport.c src/airport.cpp src/airport_gui.c src/airport_gui.cpp src/aystar.c src/aystar.cpp src/bmp.c src/bmp.cpp src/bridge_gui.c src/bridge_gui.cpp src/bridge_map.c src/bridge_map.cpp src/build_vehicle_gui.c src/build_vehicle_gui.cpp src/callback_table.c src/callback_table.cpp src/clear_cmd.c src/clear_cmd.cpp src/command.c src/command.cpp src/console.c src/console.cpp src/console_cmds.c src/console_cmds.cpp src/currency.c src/currency.cpp src/date.c src/date.cpp src/debug.c src/debug.cpp src/dedicated.c src/dedicated.cpp src/depot.c src/depot.cpp src/depot_gui.c src/depot_gui.cpp src/disaster_cmd.c src/disaster_cmd.cpp src/dock_gui.c src/dock_gui.cpp src/driver.c src/driver.cpp src/dummy_land.c src/dummy_land.cpp src/economy.c src/economy.cpp src/elrail.c src/elrail.cpp src/endian_check.c src/endian_check.cpp src/engine.c src/engine.cpp src/engine_gui.c src/engine_gui.cpp src/fileio.c src/fileio.cpp src/fios.c src/fios.cpp src/fontcache.c src/fontcache.cpp src/genworld.c src/genworld.cpp src/genworld_gui.c src/genworld_gui.cpp src/gfx.c src/gfx.cpp src/gfxinit.c src/gfxinit.cpp src/graph_gui.c src/graph_gui.cpp src/heightmap.c src/heightmap.cpp src/industry_cmd.c src/industry_cmd.cpp src/industry_gui.c src/industry_gui.cpp src/intro_gui.c src/intro_gui.cpp src/landscape.c src/landscape.cpp src/main_gui.c src/main_gui.cpp src/map.c src/map.cpp src/md5.c src/md5.cpp src/mersenne.c src/mersenne.cpp src/minilzo.c src/minilzo.cpp src/misc.c src/misc.cpp src/misc_cmd.c src/misc_cmd.cpp src/misc_gui.c src/misc_gui.cpp src/mixer.c src/mixer.cpp src/music.c src/music.cpp src/music/extmidi.c src/music/extmidi.cpp src/music/null_m.c src/music/null_m.cpp src/music/os2_m.c src/music/os2_m.cpp src/music/qtmidi.c src/music/qtmidi.cpp src/music/win32_m.c src/music/win32_m.cpp src/music_gui.c src/music_gui.cpp src/namegen.c src/namegen.cpp src/network/core/core.c src/network/core/core.cpp src/network/core/packet.c src/network/core/packet.cpp src/network/core/tcp.c src/network/core/tcp.cpp src/network/core/udp.c src/network/core/udp.cpp src/network/network.c src/network/network.cpp src/network/network_client.c src/network/network_client.cpp src/network/network_data.c src/network/network_data.cpp src/network/network_gamelist.c src/network/network_gamelist.cpp src/network/network_gui.c src/network/network_gui.cpp src/network/network_server.c src/network/network_server.cpp src/network/network_udp.c src/network/network_udp.cpp src/newgrf.c src/newgrf.cpp src/newgrf_cargo.c src/newgrf_cargo.cpp src/newgrf_config.c src/newgrf_config.cpp src/newgrf_engine.c src/newgrf_engine.cpp src/newgrf_gui.c src/newgrf_gui.cpp src/newgrf_sound.c src/newgrf_sound.cpp src/newgrf_spritegroup.c src/newgrf_spritegroup.cpp src/newgrf_station.c src/newgrf_station.cpp src/newgrf_text.c src/newgrf_text.cpp src/news_gui.c src/news_gui.cpp src/npf.c src/npf.cpp src/oldloader.c src/oldloader.cpp src/oldpool.c src/oldpool.cpp src/openttd.c src/openttd.cpp src/order_cmd.c src/order_cmd.cpp src/order_gui.c src/order_gui.cpp src/os/macosx/G5_detector.c src/os/macosx/G5_detector.cpp src/os/macosx/splash.c src/os/macosx/splash.cpp src/os2.c src/os2.cpp src/os_timer.c src/os_timer.cpp src/pathfind.c src/pathfind.cpp src/player_gui.c src/player_gui.cpp src/players.c src/players.cpp src/queue.c src/queue.cpp src/rail.c src/rail.cpp src/rail_cmd.c src/rail_cmd.cpp src/rail_gui.c src/rail_gui.cpp src/road_cmd.c src/road_cmd.cpp src/road_gui.c src/road_gui.cpp src/road_map.c src/road_map.cpp src/roadveh_cmd.c src/roadveh_cmd.cpp src/roadveh_gui.c src/roadveh_gui.cpp src/saveload.c src/saveload.cpp src/screenshot.c src/screenshot.cpp src/sdl.c src/sdl.cpp src/settings.c src/settings.cpp src/settings_gui.c src/settings_gui.cpp src/ship_cmd.c src/ship_cmd.cpp src/ship_gui.c src/ship_gui.cpp src/signs.c src/signs.cpp src/smallmap_gui.c src/smallmap_gui.cpp src/sound.c src/sound.cpp src/sound/cocoa_s.c src/sound/cocoa_s.cpp src/sound/null_s.c src/sound/null_s.cpp src/sound/sdl_s.c src/sound/sdl_s.cpp src/sound/win32_s.c src/sound/win32_s.cpp src/spritecache.c src/spritecache.cpp src/station_cmd.c src/station_cmd.cpp src/station_gui.c src/station_gui.cpp src/station_map.c src/station_map.cpp src/strgen/strgen.c src/strgen/strgen.cpp src/string.c src/string.cpp src/strings.c src/strings.cpp src/subsidy_gui.c src/subsidy_gui.cpp src/terraform_gui.c src/terraform_gui.cpp src/texteff.c src/texteff.cpp src/tgp.c src/tgp.cpp src/thread.c src/thread.cpp src/tile.c src/tile.cpp src/town_cmd.c src/town_cmd.cpp src/town_gui.c src/town_gui.cpp src/train_cmd.c src/train_cmd.cpp src/train_gui.c src/train_gui.cpp src/tree_cmd.c src/tree_cmd.cpp src/tunnel_map.c src/tunnel_map.cpp src/tunnelbridge_cmd.c src/tunnelbridge_cmd.cpp src/unix.c src/unix.cpp src/unmovable_cmd.c src/unmovable_cmd.cpp src/vehicle.c src/vehicle.cpp src/vehicle_gui.c src/vehicle_gui.cpp src/video/dedicated_v.c src/video/dedicated_v.cpp src/video/null_v.c src/video/null_v.cpp src/video/sdl_v.c src/video/sdl_v.cpp src/video/win32_v.c src/video/win32_v.cpp src/viewport.c src/viewport.cpp src/water_cmd.c src/water_cmd.cpp src/waypoint.c src/waypoint.cpp src/widget.c src/widget.cpp src/win32.c src/win32.cpp src/window.c src/window.cpp
diffstat 310 files changed, 116775 insertions(+), 116775 deletions(-) [+]
line wrap: on
line diff
deleted file mode 100644
--- a/src/ai/ai.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../variables.h"
-#include "../command.h"
-#include "../network/network.h"
-#include "ai.h"
-#include "default/default.h"
-
-/**
- * Dequeues commands put in the queue via AI_PutCommandInQueue.
- */
-static void AI_DequeueCommands(PlayerID player)
-{
-	AICommand *com, *entry_com;
-
-	entry_com = _ai_player[player].queue;
-
-	/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
-	 *  to this very same queue (don't argue about this, if it currently doesn't
-	 *  happen I can tell you it will happen with AIScript -- TrueLight). If we
-	 *  do not make the queue NULL, that commands will be dequeued immediatly.
-	 *  Therefor we safe the entry-point to entry_com, and make the queue NULL, so
-	 *  the new queue can be safely built up. */
-	_ai_player[player].queue = NULL;
-	_ai_player[player].queue_tail = NULL;
-
-	/* Dequeue all commands */
-	while ((com = entry_com) != NULL) {
-		_current_player = player;
-
-		_cmd_text = com->text;
-		DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
-
-		/* Free item */
-		entry_com = com->next;
-		free(com->text);
-		free(com);
-	}
-}
-
-/**
- * Needed for SP; we need to delay DoCommand with 1 tick, because else events
- *  will make infinite loops (AIScript).
- */
-static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
-{
-	AICommand *com;
-
-	if (_ai_player[player].queue_tail == NULL) {
-		/* There is no item in the queue yet, create the queue */
-		_ai_player[player].queue = malloc(sizeof(AICommand));
-		_ai_player[player].queue_tail = _ai_player[player].queue;
-	} else {
-		/* Add an item at the end */
-		_ai_player[player].queue_tail->next = malloc(sizeof(AICommand));
-		_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
-	}
-
-	/* This is our new item */
-	com = _ai_player[player].queue_tail;
-
-	/* Assign the info */
-	com->tile  = tile;
-	com->p1    = p1;
-	com->p2    = p2;
-	com->procc = procc;
-	com->callback = callback;
-	com->next  = NULL;
-	com->text  = NULL;
-
-	/* Copy the cmd_text, if needed */
-	if (_cmd_text != NULL) {
-		com->text = strdup(_cmd_text);
-		_cmd_text = NULL;
-	}
-}
-
-/**
- * Executes a raw DoCommand for the AI.
- */
-int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
-{
-	PlayerID old_lp;
-	int32 res = 0;
-	const char* tmp_cmdtext;
-
-	/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
-	 *   person.. should we check for those funny jokes?
-	 */
-
-	/* The test already resets _cmd_text, so backup the pointer */
-	tmp_cmdtext = _cmd_text;
-
-	/* First, do a test-run to see if we can do this */
-	res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
-	/* The command failed, or you didn't want to execute, or you are quering, return */
-	if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
-		return res;
-	}
-
-	/* Restore _cmd_text */
-	_cmd_text = tmp_cmdtext;
-
-	/* If we did a DC_EXEC, and the command did not return an error, execute it
-	 * over the network */
-	if (flags & DC_AUTO)     procc |= CMD_AUTO;
-	if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
-
-	/* NetworkSend_Command needs _local_player to be set correctly, so
-	 * adjust it, and put it back right after the function */
-	old_lp = _local_player;
-	_local_player = _current_player;
-
-#ifdef ENABLE_NETWORK
-	/* Send the command */
-	if (_networking) {
-		/* Network is easy, send it to his handler */
-		NetworkSend_Command(tile, p1, p2, procc, callback);
-	} else {
-#else
-	{
-#endif
-		/* If we execute BuildCommands directly in SP, we have a big problem with events
-		 *  so we need to delay is for 1 tick */
-		AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
-	}
-
-	/* Set _local_player back */
-	_local_player = old_lp;
-
-	return res;
-}
-
-
-int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
-{
-	return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
-}
-
-
-/**
- * Run 1 tick of the AI. Don't overdo it, keep it realistic.
- */
-static void AI_RunTick(PlayerID player)
-{
-	extern void AiNewDoGameLoop(Player *p);
-
-	Player *p = GetPlayer(player);
-	_current_player = player;
-
-	if (_patches.ainew_active) {
-		AiNewDoGameLoop(p);
-	} else {
-		/* Enable all kind of cheats the old AI needs in order to operate correctly... */
-		_is_old_ai_player = true;
-		AiDoGameLoop(p);
-		_is_old_ai_player = false;
-	}
-}
-
-
-/**
- * The gameloop for AIs.
- *  Handles one tick for all the AIs.
- */
-void AI_RunGameLoop(void)
-{
-	/* Don't do anything if ai is disabled */
-	if (!_ai.enabled) return;
-
-	/* Don't do anything if we are a network-client, or the AI has been disabled */
-	if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;
-
-	/* New tick */
-	_ai.tick++;
-
-	/* Make sure the AI follows the difficulty rule.. */
-	assert(_opt.diff.competitor_speed <= 4);
-	if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
-
-	/* Check for AI-client (so joining a network with an AI) */
-	if (!_networking || _network_server) {
-		/* Check if we want to run AIs (server or SP only) */
-		const Player* p;
-
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && p->is_ai) {
-				/* This should always be true, else something went wrong... */
-				assert(_ai_player[p->index].active);
-
-				/* Run the script */
-				AI_DequeueCommands(p->index);
-				AI_RunTick(p->index);
-			}
-		}
-	}
-
-	_current_player = OWNER_NONE;
-}
-
-/**
- * A new AI sees the day of light. You can do here what ever you think is needed.
- */
-void AI_StartNewAI(PlayerID player)
-{
-	assert(IsValidPlayer(player));
-
-	/* Called if a new AI is booted */
-	_ai_player[player].active = true;
-}
-
-/**
- * This AI player died. Give it some chance to make a final puf.
- */
-void AI_PlayerDied(PlayerID player)
-{
-	/* Called if this AI died */
-	_ai_player[player].active = false;
-}
-
-/**
- * Initialize some AI-related stuff.
- */
-void AI_Initialize(void)
-{
-	/* First, make sure all AIs are DEAD! */
-	AI_Uninitialize();
-
-	memset(&_ai, 0, sizeof(_ai));
-	memset(&_ai_player, 0, sizeof(_ai_player));
-
-	_ai.enabled = true;
-}
-
-/**
- * Deinitializer for AI-related stuff.
- */
-void AI_Uninitialize(void)
-{
-	const Player* p;
-
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/ai.cpp
@@ -0,0 +1,247 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../variables.h"
+#include "../command.h"
+#include "../network/network.h"
+#include "ai.h"
+#include "default/default.h"
+
+/**
+ * Dequeues commands put in the queue via AI_PutCommandInQueue.
+ */
+static void AI_DequeueCommands(PlayerID player)
+{
+	AICommand *com, *entry_com;
+
+	entry_com = _ai_player[player].queue;
+
+	/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
+	 *  to this very same queue (don't argue about this, if it currently doesn't
+	 *  happen I can tell you it will happen with AIScript -- TrueLight). If we
+	 *  do not make the queue NULL, that commands will be dequeued immediatly.
+	 *  Therefor we safe the entry-point to entry_com, and make the queue NULL, so
+	 *  the new queue can be safely built up. */
+	_ai_player[player].queue = NULL;
+	_ai_player[player].queue_tail = NULL;
+
+	/* Dequeue all commands */
+	while ((com = entry_com) != NULL) {
+		_current_player = player;
+
+		_cmd_text = com->text;
+		DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
+
+		/* Free item */
+		entry_com = com->next;
+		free(com->text);
+		free(com);
+	}
+}
+
+/**
+ * Needed for SP; we need to delay DoCommand with 1 tick, because else events
+ *  will make infinite loops (AIScript).
+ */
+static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
+{
+	AICommand *com;
+
+	if (_ai_player[player].queue_tail == NULL) {
+		/* There is no item in the queue yet, create the queue */
+		_ai_player[player].queue = malloc(sizeof(AICommand));
+		_ai_player[player].queue_tail = _ai_player[player].queue;
+	} else {
+		/* Add an item at the end */
+		_ai_player[player].queue_tail->next = malloc(sizeof(AICommand));
+		_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
+	}
+
+	/* This is our new item */
+	com = _ai_player[player].queue_tail;
+
+	/* Assign the info */
+	com->tile  = tile;
+	com->p1    = p1;
+	com->p2    = p2;
+	com->procc = procc;
+	com->callback = callback;
+	com->next  = NULL;
+	com->text  = NULL;
+
+	/* Copy the cmd_text, if needed */
+	if (_cmd_text != NULL) {
+		com->text = strdup(_cmd_text);
+		_cmd_text = NULL;
+	}
+}
+
+/**
+ * Executes a raw DoCommand for the AI.
+ */
+int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
+{
+	PlayerID old_lp;
+	int32 res = 0;
+	const char* tmp_cmdtext;
+
+	/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
+	 *   person.. should we check for those funny jokes?
+	 */
+
+	/* The test already resets _cmd_text, so backup the pointer */
+	tmp_cmdtext = _cmd_text;
+
+	/* First, do a test-run to see if we can do this */
+	res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
+	/* The command failed, or you didn't want to execute, or you are quering, return */
+	if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
+		return res;
+	}
+
+	/* Restore _cmd_text */
+	_cmd_text = tmp_cmdtext;
+
+	/* If we did a DC_EXEC, and the command did not return an error, execute it
+	 * over the network */
+	if (flags & DC_AUTO)     procc |= CMD_AUTO;
+	if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
+
+	/* NetworkSend_Command needs _local_player to be set correctly, so
+	 * adjust it, and put it back right after the function */
+	old_lp = _local_player;
+	_local_player = _current_player;
+
+#ifdef ENABLE_NETWORK
+	/* Send the command */
+	if (_networking) {
+		/* Network is easy, send it to his handler */
+		NetworkSend_Command(tile, p1, p2, procc, callback);
+	} else {
+#else
+	{
+#endif
+		/* If we execute BuildCommands directly in SP, we have a big problem with events
+		 *  so we need to delay is for 1 tick */
+		AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
+	}
+
+	/* Set _local_player back */
+	_local_player = old_lp;
+
+	return res;
+}
+
+
+int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
+{
+	return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
+}
+
+
+/**
+ * Run 1 tick of the AI. Don't overdo it, keep it realistic.
+ */
+static void AI_RunTick(PlayerID player)
+{
+	extern void AiNewDoGameLoop(Player *p);
+
+	Player *p = GetPlayer(player);
+	_current_player = player;
+
+	if (_patches.ainew_active) {
+		AiNewDoGameLoop(p);
+	} else {
+		/* Enable all kind of cheats the old AI needs in order to operate correctly... */
+		_is_old_ai_player = true;
+		AiDoGameLoop(p);
+		_is_old_ai_player = false;
+	}
+}
+
+
+/**
+ * The gameloop for AIs.
+ *  Handles one tick for all the AIs.
+ */
+void AI_RunGameLoop(void)
+{
+	/* Don't do anything if ai is disabled */
+	if (!_ai.enabled) return;
+
+	/* Don't do anything if we are a network-client, or the AI has been disabled */
+	if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;
+
+	/* New tick */
+	_ai.tick++;
+
+	/* Make sure the AI follows the difficulty rule.. */
+	assert(_opt.diff.competitor_speed <= 4);
+	if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
+
+	/* Check for AI-client (so joining a network with an AI) */
+	if (!_networking || _network_server) {
+		/* Check if we want to run AIs (server or SP only) */
+		const Player* p;
+
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && p->is_ai) {
+				/* This should always be true, else something went wrong... */
+				assert(_ai_player[p->index].active);
+
+				/* Run the script */
+				AI_DequeueCommands(p->index);
+				AI_RunTick(p->index);
+			}
+		}
+	}
+
+	_current_player = OWNER_NONE;
+}
+
+/**
+ * A new AI sees the day of light. You can do here what ever you think is needed.
+ */
+void AI_StartNewAI(PlayerID player)
+{
+	assert(IsValidPlayer(player));
+
+	/* Called if a new AI is booted */
+	_ai_player[player].active = true;
+}
+
+/**
+ * This AI player died. Give it some chance to make a final puf.
+ */
+void AI_PlayerDied(PlayerID player)
+{
+	/* Called if this AI died */
+	_ai_player[player].active = false;
+}
+
+/**
+ * Initialize some AI-related stuff.
+ */
+void AI_Initialize(void)
+{
+	/* First, make sure all AIs are DEAD! */
+	AI_Uninitialize();
+
+	memset(&_ai, 0, sizeof(_ai));
+	memset(&_ai_player, 0, sizeof(_ai_player));
+
+	_ai.enabled = true;
+}
+
+/**
+ * Deinitializer for AI-related stuff.
+ */
+void AI_Uninitialize(void)
+{
+	const Player* p;
+
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
+	}
+}
deleted file mode 100644
--- a/src/ai/default/default.c
+++ /dev/null
@@ -1,3934 +0,0 @@
-/* $Id$ */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../aircraft.h"
-#include "../../bridge_map.h"
-#include "../../functions.h"
-#include "../../map.h"
-#include "../../rail_map.h"
-#include "../../road_map.h"
-#include "../../roadveh.h"
-#include "../../station_map.h"
-#include "../../tile.h"
-#include "../../player.h"
-#include "../../tunnel_map.h"
-#include "../../vehicle.h"
-#include "../../engine.h"
-#include "../../command.h"
-#include "../../town.h"
-#include "../../industry.h"
-#include "../../station.h"
-#include "../../pathfind.h"
-#include "../../economy.h"
-#include "../../airport.h"
-#include "../../depot.h"
-#include "../../variables.h"
-#include "../../bridge.h"
-#include "../../date.h"
-#include "default.h"
-
-// remove some day perhaps?
-static uint _ai_service_interval;
-
-typedef void AiStateAction(Player *p);
-
-enum {
-	AIS_0                            =  0,
-	AIS_1                            =  1,
-	AIS_VEH_LOOP                     =  2,
-	AIS_VEH_CHECK_REPLACE_VEHICLE    =  3,
-	AIS_VEH_DO_REPLACE_VEHICLE       =  4,
-	AIS_WANT_NEW_ROUTE               =  5,
-	AIS_BUILD_DEFAULT_RAIL_BLOCKS    =  6,
-	AIS_BUILD_RAIL                   =  7,
-	AIS_BUILD_RAIL_VEH               =  8,
-	AIS_DELETE_RAIL_BLOCKS           =  9,
-	AIS_BUILD_DEFAULT_ROAD_BLOCKS    = 10,
-	AIS_BUILD_ROAD                   = 11,
-	AIS_BUILD_ROAD_VEHICLES          = 12,
-	AIS_DELETE_ROAD_BLOCKS           = 13,
-	AIS_AIRPORT_STUFF                = 14,
-	AIS_BUILD_DEFAULT_AIRPORT_BLOCKS = 15,
-	AIS_BUILD_AIRCRAFT_VEHICLES      = 16,
-	AIS_CHECK_SHIP_STUFF             = 17,
-	AIS_BUILD_DEFAULT_SHIP_BLOCKS    = 18,
-	AIS_DO_SHIP_STUFF                = 19,
-	AIS_SELL_VEHICLE                 = 20,
-	AIS_REMOVE_STATION               = 21,
-	AIS_REMOVE_TRACK                 = 22,
-	AIS_REMOVE_SINGLE_RAIL_TILE      = 23
-};
-
-
-#include "../../table/ai_rail.h"
-
-static byte GetRailTrackStatus(TileIndex tile)
-{
-	uint32 r = GetTileTrackStatus(tile, TRANSPORT_RAIL);
-	return (byte) (r | r >> 8);
-}
-
-
-static void AiCase0(Player *p)
-{
-	p->ai.state = AIS_REMOVE_TRACK;
-	p->ai.state_counter = 0;
-}
-
-static void AiCase1(Player *p)
-{
-	p->ai.cur_veh = NULL;
-	p->ai.state = AIS_VEH_LOOP;
-}
-
-static void AiStateVehLoop(Player *p)
-{
-	Vehicle *v;
-	uint index;
-
-	index = (p->ai.cur_veh == NULL) ? 0 : p->ai.cur_veh->index + 1;
-
-	FOR_ALL_VEHICLES_FROM(v, index) {
-		if (v->owner != _current_player) continue;
-
-		if ((v->type == VEH_Train && v->subtype == 0) ||
-				v->type == VEH_Road ||
-				(v->type == VEH_Aircraft && v->subtype <= 2) ||
-				v->type == VEH_Ship) {
-			/* replace engine? */
-			if (v->type == VEH_Train && v->engine_type < 3 &&
-					(_price.build_railvehicle >> 3) < p->player_money) {
-				p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE;
-				p->ai.cur_veh = v;
-				return;
-			}
-
-			/* not profitable? */
-			if (v->age >= 730 &&
-					v->profit_last_year < _price.station_value * 5 &&
-					v->profit_this_year < _price.station_value * 5) {
-				p->ai.state_counter = 0;
-				p->ai.state = AIS_SELL_VEHICLE;
-				p->ai.cur_veh = v;
-				return;
-			}
-
-			/* not reliable? */
-			if (v->age >= v->max_age || (
-						v->age != 0 &&
-						GetEngine(v->engine_type)->reliability < 35389
-					)) {
-				p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE;
-				p->ai.cur_veh = v;
-				return;
-			}
-		}
-	}
-
-	p->ai.state = AIS_WANT_NEW_ROUTE;
-	p->ai.state_counter = 0;
-}
-
-static EngineID AiChooseTrainToBuild(RailType railtype, int32 money, byte flag, TileIndex tile)
-{
-	EngineID best_veh_index = INVALID_ENGINE;
-	byte best_veh_score = 0;
-	int32 ret;
-	EngineID i;
-
-	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
-		const RailVehicleInfo *rvi = RailVehInfo(i);
-		const Engine* e = GetEngine(i);
-
-		if (!IsCompatibleRail(e->railtype, railtype) ||
-				rvi->flags & RVI_WAGON ||
-				(rvi->flags & RVI_MULTIHEAD && flag & 1) ||
-				!HASBIT(e->player_avail, _current_player) ||
-				e->reliability < 0x8A3D) {
-			continue;
-		}
-
-		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_RAIL_VEHICLE);
-		if (!CmdFailed(ret) && ret <= money && rvi->ai_rank >= best_veh_score) {
-			best_veh_score = rvi->ai_rank;
-			best_veh_index = i;
-		}
-	}
-
-	return best_veh_index;
-}
-
-static EngineID AiChooseRoadVehToBuild(CargoID cargo, int32 money, TileIndex tile)
-{
-	EngineID best_veh_index = INVALID_ENGINE;
-	int32 best_veh_rating = 0;
-	EngineID i = ROAD_ENGINES_INDEX;
-	EngineID end = i + NUM_ROAD_ENGINES;
-
-	for (; i != end; i++) {
-		const RoadVehicleInfo *rvi = RoadVehInfo(i);
-		const Engine* e = GetEngine(i);
-		int32 rating;
-		int32 ret;
-
-		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
-			continue;
-		}
-
-		/* Skip vehicles which can't take our cargo type */
-		if (rvi->cargo_type != cargo && !CanRefitTo(i, cargo)) continue;
-
-		/* Rate and compare the engine by speed & capacity */
-		rating = rvi->max_speed * rvi->capacity;
-		if (rating <= best_veh_rating) continue;
-
-		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_ROAD_VEH);
-		if (CmdFailed(ret)) continue;
-
-		/* Add the cost of refitting */
-		if (rvi->cargo_type != cargo) ret += GetRefitCost(i);
-		if (ret > money) continue;
-
-		best_veh_rating = rating;
-		best_veh_index = i;
-	}
-
-	return best_veh_index;
-}
-
-static EngineID AiChooseAircraftToBuild(int32 money, byte flag)
-{
-	EngineID best_veh_index = INVALID_ENGINE;
-	int32 best_veh_cost = 0;
-	EngineID i;
-
-	for (i = AIRCRAFT_ENGINES_INDEX; i != AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
-		const Engine* e = GetEngine(i);
-		int32 ret;
-
-		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
-			continue;
-		}
-
-		if ((AircraftVehInfo(i)->subtype & AIR_CTOL) != flag) continue;
-
-		ret = DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_AIRCRAFT);
-		if (!CmdFailed(ret) && ret <= money && ret >= best_veh_cost) {
-			best_veh_cost = ret;
-			best_veh_index = i;
-		}
-	}
-
-	return best_veh_index;
-}
-
-static int32 AiGetBasePrice(const Player* p)
-{
-	int32 base = _price.station_value;
-
-	// adjust base price when more expensive vehicles are available
-	switch (p->ai.railtype_to_use) {
-		default: NOT_REACHED();
-		case RAILTYPE_RAIL:     break;
-		case RAILTYPE_ELECTRIC: break;
-		case RAILTYPE_MONO:     base = (base * 3) >> 1; break;
-		case RAILTYPE_MAGLEV:   base *= 2; break;
-	}
-
-	return base;
-}
-
-#if 0
-static EngineID AiChooseShipToBuild(byte cargo, int32 money)
-{
-	// XXX: not done
-	return INVALID_ENGINE;
-}
-#endif
-
-static EngineID AiChooseRoadVehToReplaceWith(const Player* p, const Vehicle* v)
-{
-	int32 avail_money = p->player_money + v->value;
-	return AiChooseRoadVehToBuild(v->cargo_type, avail_money, v->tile);
-}
-
-static EngineID AiChooseAircraftToReplaceWith(const Player* p, const Vehicle* v)
-{
-	int32 avail_money = p->player_money + v->value;
-	return AiChooseAircraftToBuild(
-		avail_money, AircraftVehInfo(v->engine_type)->subtype & AIR_CTOL
-	);
-}
-
-static EngineID AiChooseTrainToReplaceWith(const Player* p, const Vehicle* v)
-{
-	int32 avail_money = p->player_money + v->value;
-	const Vehicle* u = v;
-	int num = 0;
-
-	while (++num, u->next != NULL) {
-		u = u->next;
-	}
-
-	// XXX: check if a wagon
-	return AiChooseTrainToBuild(v->u.rail.railtype, avail_money, 0, v->tile);
-}
-
-static EngineID AiChooseShipToReplaceWith(const Player* p, const Vehicle* v)
-{
-	error("!AiChooseShipToReplaceWith");
-
-	/* maybe useless, but avoids compiler warning this way */
-	return INVALID_ENGINE;
-}
-
-static void AiHandleGotoDepot(Player *p, int cmd)
-{
-	if (p->ai.cur_veh->current_order.type != OT_GOTO_DEPOT)
-		DoCommand(0, p->ai.cur_veh->index, 0, DC_EXEC, cmd);
-
-	if (++p->ai.state_counter <= 1387) {
-		p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE;
-		return;
-	}
-
-	if (p->ai.cur_veh->current_order.type == OT_GOTO_DEPOT) {
-		p->ai.cur_veh->current_order.type = OT_DUMMY;
-		p->ai.cur_veh->current_order.flags = 0;
-		InvalidateWindow(WC_VEHICLE_VIEW, p->ai.cur_veh->index);
-	}
-}
-
-static void AiRestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
-{
-	uint i;
-
-	for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
-		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
-			break;
-	}
-}
-
-static void AiHandleReplaceTrain(Player *p)
-{
-	const Vehicle* v = p->ai.cur_veh;
-	BackuppedOrders orderbak[1];
-	EngineID veh;
-
-	// wait until the vehicle reaches the depot.
-	if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
-		AiHandleGotoDepot(p, CMD_SEND_TRAIN_TO_DEPOT);
-		return;
-	}
-
-	veh = AiChooseTrainToReplaceWith(p, v);
-	if (veh != INVALID_ENGINE) {
-		TileIndex tile;
-
-		BackupVehicleOrders(v, orderbak);
-		tile = v->tile;
-
-		if (!CmdFailed(DoCommand(0, v->index, 2, DC_EXEC, CMD_SELL_RAIL_WAGON)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE))) {
-			VehicleID veh = _new_vehicle_id;
-			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
-			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_TRAIN);
-
-			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-		}
-	}
-}
-
-static void AiHandleReplaceRoadVeh(Player *p)
-{
-	const Vehicle* v = p->ai.cur_veh;
-	BackuppedOrders orderbak[1];
-	EngineID veh;
-
-	if (!IsRoadVehInDepotStopped(v)) {
-		AiHandleGotoDepot(p, CMD_SEND_ROADVEH_TO_DEPOT);
-		return;
-	}
-
-	veh = AiChooseRoadVehToReplaceWith(p, v);
-	if (veh != INVALID_ENGINE) {
-		TileIndex tile;
-
-		BackupVehicleOrders(v, orderbak);
-		tile = v->tile;
-
-		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) {
-			VehicleID veh = _new_vehicle_id;
-
-			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
-			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
-			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-		}
-	}
-}
-
-static void AiHandleReplaceAircraft(Player *p)
-{
-	const Vehicle* v = p->ai.cur_veh;
-	BackuppedOrders orderbak[1];
-	EngineID veh;
-
-	if (!IsAircraftInHangarStopped(v)) {
-		AiHandleGotoDepot(p, CMD_SEND_AIRCRAFT_TO_HANGAR);
-		return;
-	}
-
-	veh = AiChooseAircraftToReplaceWith(p, v);
-	if (veh != INVALID_ENGINE) {
-		TileIndex tile;
-
-		BackupVehicleOrders(v, orderbak);
-		tile = v->tile;
-
-		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
-				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) {
-			VehicleID veh = _new_vehicle_id;
-			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
-			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
-
-			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-		}
-	}
-}
-
-static void AiHandleReplaceShip(Player *p)
-{
-	error("!AiHandleReplaceShip");
-}
-
-typedef EngineID CheckReplaceProc(const Player* p, const Vehicle* v);
-
-static CheckReplaceProc* const _veh_check_replace_proc[] = {
-	AiChooseTrainToReplaceWith,
-	AiChooseRoadVehToReplaceWith,
-	AiChooseShipToReplaceWith,
-	AiChooseAircraftToReplaceWith,
-};
-
-typedef void DoReplaceProc(Player *p);
-static DoReplaceProc* const _veh_do_replace_proc[] = {
-	AiHandleReplaceTrain,
-	AiHandleReplaceRoadVeh,
-	AiHandleReplaceShip,
-	AiHandleReplaceAircraft
-};
-
-static void AiStateCheckReplaceVehicle(Player *p)
-{
-	const Vehicle* v = p->ai.cur_veh;
-
-	if (!IsValidVehicle(v) ||
-			v->owner != _current_player ||
-			v->type > VEH_Ship ||
-			_veh_check_replace_proc[v->type - VEH_Train](p, v) == INVALID_ENGINE) {
-		p->ai.state = AIS_VEH_LOOP;
-	} else {
-		p->ai.state_counter = 0;
-		p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE;
-	}
-}
-
-static void AiStateDoReplaceVehicle(Player *p)
-{
-	const Vehicle* v = p->ai.cur_veh;
-
-	p->ai.state = AIS_VEH_LOOP;
-	// vehicle is not owned by the player anymore, something went very wrong.
-	if (!IsValidVehicle(v) || v->owner != _current_player) return;
-	_veh_do_replace_proc[v->type - VEH_Train](p);
-}
-
-typedef struct FoundRoute {
-	int distance;
-	CargoID cargo;
-	void *from;
-	void *to;
-} FoundRoute;
-
-static Town *AiFindRandomTown(void)
-{
-	return GetRandomTown();
-}
-
-static Industry *AiFindRandomIndustry(void)
-{
-	return GetRandomIndustry();
-}
-
-static void AiFindSubsidyIndustryRoute(FoundRoute *fr)
-{
-	uint i;
-	CargoID cargo;
-	const Subsidy* s;
-	Industry* from;
-	TileIndex to_xy;
-
-	// initially error
-	fr->distance = -1;
-
-	// Randomize subsidy index..
-	i = RandomRange(lengthof(_subsidies) * 3);
-	if (i >= lengthof(_subsidies)) return;
-
-	s = &_subsidies[i];
-
-	// Don't want passengers or mail
-	cargo = s->cargo_type;
-	if (cargo == CT_INVALID ||
-			cargo == CT_PASSENGERS ||
-			cargo == CT_MAIL ||
-			s->age > 7) {
-		return;
-	}
-	fr->cargo = cargo;
-
-	fr->from = from = GetIndustry(s->from);
-
-	if (cargo == CT_GOODS || cargo == CT_FOOD) {
-		Town* to_tow = GetTown(s->to);
-
-		if (to_tow->population < (cargo == CT_FOOD ? 200U : 900U)) return; // error
-		fr->to = to_tow;
-		to_xy = to_tow->xy;
-	} else {
-		Industry* to_ind = GetIndustry(s->to);
-
-		fr->to = to_ind;
-		to_xy = to_ind->xy;
-	}
-
-	fr->distance = DistanceManhattan(from->xy, to_xy);
-}
-
-static void AiFindSubsidyPassengerRoute(FoundRoute *fr)
-{
-	uint i;
-	const Subsidy* s;
-	Town *from,*to;
-
-	// initially error
-	fr->distance = -1;
-
-	// Randomize subsidy index..
-	i = RandomRange(lengthof(_subsidies) * 3);
-	if (i >= lengthof(_subsidies)) return;
-
-	s = &_subsidies[i];
-
-	// Only want passengers
-	if (s->cargo_type != CT_PASSENGERS || s->age > 7) return;
-	fr->cargo = s->cargo_type;
-
-	fr->from = from = GetTown(s->from);
-	fr->to = to = GetTown(s->to);
-
-	// They must be big enough
-	if (from->population < 400 || to->population < 400) return;
-
-	fr->distance = DistanceManhattan(from->xy, to->xy);
-}
-
-static void AiFindRandomIndustryRoute(FoundRoute *fr)
-{
-	Industry* i;
-	uint32 r;
-	CargoID cargo;
-
-	// initially error
-	fr->distance = -1;
-
-	r = Random();
-
-	// pick a source
-	fr->from = i = AiFindRandomIndustry();
-	if (i == NULL) return;
-
-	// pick a random produced cargo
-	cargo = i->produced_cargo[0];
-	if (r & 1 && i->produced_cargo[1] != CT_INVALID) cargo = i->produced_cargo[1];
-
-	fr->cargo = cargo;
-
-	// don't allow passengers
-	if (cargo == CT_INVALID || cargo == CT_PASSENGERS) return;
-
-	if (cargo != CT_GOODS && cargo != CT_FOOD) {
-		// pick a dest, and see if it can receive
-		Industry* i2 = AiFindRandomIndustry();
-
-		if (i2 == NULL || i == i2 || (
-					i2->accepts_cargo[0] != cargo &&
-					i2->accepts_cargo[1] != cargo &&
-					i2->accepts_cargo[2] != cargo)
-				) {
-			return;
-		}
-
-		fr->to = i2;
-		fr->distance = DistanceManhattan(i->xy, i2->xy);
-	} else {
-		// pick a dest town, and see if it's big enough
-		Town* t = AiFindRandomTown();
-
-		if (t == NULL || t->population < (cargo == CT_FOOD ? 200U : 900U)) return;
-
-		fr->to = t;
-		fr->distance = DistanceManhattan(i->xy, t->xy);
-	}
-}
-
-static void AiFindRandomPassengerRoute(FoundRoute *fr)
-{
-	Town* source;
-	Town* dest;
-
-	// initially error
-	fr->distance = -1;
-
-	fr->from = source = AiFindRandomTown();
-	if (source == NULL || source->population < 400) return;
-
-	fr->to = dest = AiFindRandomTown();
-	if (dest == NULL || source == dest || dest->population < 400) return;
-
-	fr->distance = DistanceManhattan(source->xy, dest->xy);
-}
-
-// Warn: depends on 'xy' being the first element in both Town and Industry
-#define GET_TOWN_OR_INDUSTRY_TILE(p) (((Town*)(p))->xy)
-
-static bool AiCheckIfRouteIsGood(Player *p, FoundRoute *fr, byte bitmask)
-{
-	TileIndex from_tile, to_tile;
-	Station *st;
-	int dist;
-	uint same_station = 0;
-
-	// Make sure distance to closest station is < 37 pixels.
-	from_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->from);
-	to_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->to);
-
-	dist = 0xFFFF;
-	FOR_ALL_STATIONS(st) {
-		int cur;
-
-		if (st->owner != _current_player) continue;
-		cur = DistanceMax(from_tile, st->xy);
-		if (cur < dist) dist = cur;
-		cur = DistanceMax(to_tile, st->xy);
-		if (cur < dist) dist = cur;
-		if (to_tile == from_tile && st->xy == to_tile) same_station++;
-	}
-
-	// To prevent the AI from building ten busstations in the same town, do some calculations
-	//  For each road or airport station, we want 350 of population!
-	if ((bitmask == 2 || bitmask == 4) &&
-			same_station > 2 &&
-			((Town*)fr->from)->population < same_station * 350) {
-		return false;
-	}
-
-	if (dist != 0xFFFF && dist > 37) return false;
-
-	if (p->ai.route_type_mask != 0 &&
-			!(p->ai.route_type_mask & bitmask) &&
-			!CHANCE16(1, 5)) {
-		return false;
-	}
-
-	if (fr->cargo == CT_PASSENGERS || fr->cargo == CT_MAIL) {
-		const Town* from = fr->from;
-		const Town* to   = fr->to;
-
-		if (from->pct_pass_transported > 0x99 ||
-				to->pct_pass_transported > 0x99) {
-			return false;
-		}
-
-		// Make sure it has a reasonably good rating
-		if (from->ratings[_current_player] < -100 ||
-				to->ratings[_current_player] < -100) {
-			return false;
-		}
-	} else {
-		const Industry* i = (const Industry*)fr->from;
-
-		if (i->pct_transported[fr->cargo != i->produced_cargo[0]] > 0x99 ||
-				i->total_production[fr->cargo != i->produced_cargo[0]] == 0) {
-			return false;
-		}
-	}
-
-	p->ai.route_type_mask |= bitmask;
-	return true;
-}
-
-static byte AiGetDirectionBetweenTiles(TileIndex a, TileIndex b)
-{
-	byte i = (TileX(a) < TileX(b)) ? 1 : 0;
-	if (TileY(a) >= TileY(b)) i ^= 3;
-	return i;
-}
-
-static TileIndex AiGetPctTileBetween(TileIndex a, TileIndex b, byte pct)
-{
-	return TileXY(
-		TileX(a) + ((TileX(b) - TileX(a)) * pct >> 8),
-		TileY(a) + ((TileY(b) - TileY(a)) * pct >> 8)
-	);
-}
-
-static void AiWantLongIndustryRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 60, 90 + 1)) break;
-
-		// try a random one
-		AiFindRandomIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 60, 90 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
-
-	// Fill the source field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 9;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.unk6 = 1;
-	p->ai.src.unk7 = 0;
-	p->ai.src.buildcmd_a = 0x24;
-	p->ai.src.buildcmd_b = 0xFF;
-	p->ai.src.direction = AiGetDirectionBetweenTiles(
-		p->ai.src.spec_tile,
-		p->ai.dst.spec_tile
-	);
-	p->ai.src.cargo = fr.cargo | 0x80;
-
-	// Fill the dest field
-
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 9;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.unk6 = 1;
-	p->ai.dst.unk7 = 0;
-	p->ai.dst.buildcmd_a = 0x34;
-	p->ai.dst.buildcmd_b = 0xFF;
-	p->ai.dst.direction = AiGetDirectionBetweenTiles(
-		p->ai.dst.spec_tile,
-		p->ai.src.spec_tile
-	);
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill middle field 1
-	p->ai.mid1.spec_tile = AiGetPctTileBetween(
-		p->ai.src.spec_tile,
-		p->ai.dst.spec_tile,
-		0x55
-	);
-	p->ai.mid1.use_tile = 0;
-	p->ai.mid1.rand_rng = 6;
-	p->ai.mid1.cur_building_rule = 0xFF;
-	p->ai.mid1.unk6 = 2;
-	p->ai.mid1.unk7 = 1;
-	p->ai.mid1.buildcmd_a = 0x30;
-	p->ai.mid1.buildcmd_b = 0xFF;
-	p->ai.mid1.direction = p->ai.src.direction;
-	p->ai.mid1.cargo = fr.cargo;
-
-	// Fill middle field 2
-	p->ai.mid2.spec_tile = AiGetPctTileBetween(
-		p->ai.src.spec_tile,
-		p->ai.dst.spec_tile,
-		0xAA
-	);
-	p->ai.mid2.use_tile = 0;
-	p->ai.mid2.rand_rng = 6;
-	p->ai.mid2.cur_building_rule = 0xFF;
-	p->ai.mid2.unk6 = 2;
-	p->ai.mid2.unk7 = 1;
-	p->ai.mid2.buildcmd_a = 0xFF;
-	p->ai.mid2.buildcmd_b = 0xFF;
-	p->ai.mid2.direction = p->ai.dst.direction;
-	p->ai.mid2.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_wagons = 3;
-	p->ai.build_kind = 2;
-	p->ai.num_build_rec = 4;
-	p->ai.num_loco_to_build = 2;
-	p->ai.num_want_fullload = 2;
-	p->ai.wagon_list[0] = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantMediumIndustryRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 40, 60 + 1)) break;
-
-		// try a random one
-		AiFindRandomIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 40, 60 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 9;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.unk6 = 1;
-	p->ai.src.unk7 = 0;
-	p->ai.src.buildcmd_a = 0x10;
-	p->ai.src.buildcmd_b = 0xFF;
-	p->ai.src.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
-	);
-	p->ai.src.cargo = fr.cargo | 0x80;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 9;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.unk6 = 1;
-	p->ai.dst.unk7 = 0;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.buildcmd_b = 0xFF;
-	p->ai.dst.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
-	);
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_wagons = 3;
-	p->ai.build_kind = 1;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 1;
-	p->ai.wagon_list[0] = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantShortIndustryRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
-
-		// try a random one
-		AiFindRandomIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 9;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.unk6 = 1;
-	p->ai.src.unk7 = 0;
-	p->ai.src.buildcmd_a = 0x10;
-	p->ai.src.buildcmd_b = 0xFF;
-	p->ai.src.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
-	);
-	p->ai.src.cargo = fr.cargo | 0x80;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 9;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.unk6 = 1;
-	p->ai.dst.unk7 = 0;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.buildcmd_b = 0xFF;
-	p->ai.dst.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
-	);
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_wagons = 2;
-	p->ai.build_kind = 1;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 1;
-	p->ai.wagon_list[0] = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantMailRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 60, 110 + 1)) break;
-
-		// try a random one
-		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 60, 110 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_MAIL;
-	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 7;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.unk6 = 1;
-	p->ai.src.unk7 = 0;
-	p->ai.src.buildcmd_a = 0x24;
-	p->ai.src.buildcmd_b = 0xFF;
-	p->ai.src.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
-	);
-	p->ai.src.cargo = fr.cargo;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 7;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.unk6 = 1;
-	p->ai.dst.unk7 = 0;
-	p->ai.dst.buildcmd_a = 0x34;
-	p->ai.dst.buildcmd_b = 0xFF;
-	p->ai.dst.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
-	);
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill middle field 1
-	p->ai.mid1.spec_tile = AiGetPctTileBetween(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		0x55
-	);
-	p->ai.mid1.use_tile = 0;
-	p->ai.mid1.rand_rng = 6;
-	p->ai.mid1.cur_building_rule = 0xFF;
-	p->ai.mid1.unk6 = 2;
-	p->ai.mid1.unk7 = 1;
-	p->ai.mid1.buildcmd_a = 0x30;
-	p->ai.mid1.buildcmd_b = 0xFF;
-	p->ai.mid1.direction = p->ai.src.direction;
-	p->ai.mid1.cargo = fr.cargo;
-
-	// Fill middle field 2
-	p->ai.mid2.spec_tile = AiGetPctTileBetween(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		0xAA
-	);
-	p->ai.mid2.use_tile = 0;
-	p->ai.mid2.rand_rng = 6;
-	p->ai.mid2.cur_building_rule = 0xFF;
-	p->ai.mid2.unk6 = 2;
-	p->ai.mid2.unk7 = 1;
-	p->ai.mid2.buildcmd_a = 0xFF;
-	p->ai.mid2.buildcmd_b = 0xFF;
-	p->ai.mid2.direction = p->ai.dst.direction;
-	p->ai.mid2.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_wagons = 3;
-	p->ai.build_kind = 2;
-	p->ai.num_build_rec = 4;
-	p->ai.num_loco_to_build = 2;
-	p->ai.num_want_fullload = 0;
-	p->ai.wagon_list[0] = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantPassengerRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 55 + 1)) break;
-
-		// try a random one
-		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 55 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_PASSENGERS;
-	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 7;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.unk6 = 1;
-	p->ai.src.unk7 = 0;
-	p->ai.src.buildcmd_a = 0x10;
-	p->ai.src.buildcmd_b = 0xFF;
-	p->ai.src.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
-	);
-	p->ai.src.cargo = fr.cargo;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 7;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.unk6 = 1;
-	p->ai.dst.unk7 = 0;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.buildcmd_b = 0xFF;
-	p->ai.dst.direction = AiGetDirectionBetweenTiles(
-		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
-		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
-	);
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_wagons = 2;
-	p->ai.build_kind = 1;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 0;
-	p->ai.wagon_list[0] = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantTrainRoute(Player *p)
-{
-	uint16 r = GB(Random(), 0, 16);
-
-	p->ai.railtype_to_use = GetBestRailtype(p);
-
-	if (r > 0xD000) {
-		AiWantLongIndustryRoute(p);
-	} else if (r > 0x6000) {
-		AiWantMediumIndustryRoute(p);
-	} else if (r > 0x1000) {
-		AiWantShortIndustryRoute(p);
-	} else if (r > 0x800) {
-		AiWantPassengerRoute(p);
-	} else {
-		AiWantMailRoute(p);
-	}
-}
-
-static void AiWantLongRoadIndustryRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 35, 55 + 1)) break;
-
-		// try a random one
-		AiFindRandomIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 35, 55 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 9;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.buildcmd_a = 1;
-	p->ai.src.direction = 0;
-	p->ai.src.cargo = fr.cargo | 0x80;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 9;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.direction = 0;
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 5;
-	p->ai.num_want_fullload = 5;
-
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantMediumRoadIndustryRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
-
-		// try a random one
-		AiFindRandomIndustryRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 9;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.buildcmd_a = 1;
-	p->ai.src.direction = 0;
-	p->ai.src.cargo = fr.cargo | 0x80;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 9;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.direction = 0;
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 3;
-	p->ai.num_want_fullload = 3;
-
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantLongRoadPassengerRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 55, 180 + 1)) break;
-
-		// try a random one
-		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 55, 180 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_PASSENGERS;
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 10;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.buildcmd_a = 1;
-	p->ai.src.direction = 0;
-	p->ai.src.cargo = CT_PASSENGERS;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 10;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.direction = 0;
-	p->ai.dst.cargo = CT_PASSENGERS;
-
-	// Fill common fields
-	p->ai.cargo_type = CT_PASSENGERS;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 4;
-	p->ai.num_want_fullload = 0;
-
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantPassengerRouteInsideTown(Player *p)
-{
-	int i;
-	FoundRoute fr;
-	Town *t;
-
-	i = 60;
-	for (;;) {
-		// Find a town big enough
-		t = AiFindRandomTown();
-		if (t != NULL && t->population >= 700) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_PASSENGERS;
-	fr.from = fr.to = t;
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = t->xy;
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 10;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.buildcmd_a = 1;
-	p->ai.src.direction = 0;
-	p->ai.src.cargo = CT_PASSENGERS;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = t->xy;
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 10;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.buildcmd_a = 0xFF;
-	p->ai.dst.direction = 0;
-	p->ai.dst.cargo = CT_PASSENGERS;
-
-	// Fill common fields
-	p->ai.cargo_type = CT_PASSENGERS;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 2;
-	p->ai.num_want_fullload = 0;
-
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
-	p->ai.state_mode = -1;
-	p->ai.state_counter = 0;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantRoadRoute(Player *p)
-{
-	uint16 r = GB(Random(), 0, 16);
-
-	if (r > 0x4000) {
-		AiWantLongRoadIndustryRoute(p);
-	} else if (r > 0x2000) {
-		AiWantMediumRoadIndustryRoute(p);
-	} else if (r > 0x1000) {
-		AiWantLongRoadPassengerRoute(p);
-	} else {
-		AiWantPassengerRouteInsideTown(p);
-	}
-}
-
-static void AiWantPassengerAircraftRoute(Player *p)
-{
-	FoundRoute fr;
-	int i;
-
-	i = 60;
-	for (;;) {
-		// look for one from the subsidy list
-		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
-
-		// try a random one
-		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_PASSENGERS;
-	if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
-
-
-	// Fill the source field
-	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 12;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.cargo = fr.cargo;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 12;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.cargo = fr.cargo;
-
-	// Fill common fields
-	p->ai.cargo_type = fr.cargo;
-	p->ai.build_kind = 0;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 1;
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_AIRPORT_STUFF;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantOilRigAircraftRoute(Player *p)
-{
-	int i;
-	FoundRoute fr;
-	Town *t;
-	Industry *in;
-
-	i = 60;
-	for (;;) {
-		// Find a town
-		t = AiFindRandomTown();
-		if (t != NULL) {
-			// Find a random oil rig industry
-			in = AiFindRandomIndustry();
-			if (in != NULL && in->type == IT_OIL_RIG) {
-				if (DistanceManhattan(t->xy, in->xy) < 60)
-					break;
-			}
-		}
-
-		// only test 60 times
-		if (--i == 0) return;
-	}
-
-	fr.cargo = CT_PASSENGERS;
-	fr.from = fr.to = t;
-
-	if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
-
-	// Fill the source field
-	p->ai.src.spec_tile = t->xy;
-	p->ai.src.use_tile = 0;
-	p->ai.src.rand_rng = 12;
-	p->ai.src.cur_building_rule = 0xFF;
-	p->ai.src.cargo = CT_PASSENGERS;
-
-	// Fill the dest field
-	p->ai.dst.spec_tile = in->xy;
-	p->ai.dst.use_tile = 0;
-	p->ai.dst.rand_rng = 5;
-	p->ai.dst.cur_building_rule = 0xFF;
-	p->ai.dst.cargo = CT_PASSENGERS;
-
-	// Fill common fields
-	p->ai.cargo_type = CT_PASSENGERS;
-	p->ai.build_kind = 1;
-	p->ai.num_build_rec = 2;
-	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 0;
-//	p->ai.loco_id = INVALID_VEHICLE;
-	p->ai.order_list_blocks[0] = 0;
-	p->ai.order_list_blocks[1] = 1;
-	p->ai.order_list_blocks[2] = 255;
-
-	p->ai.state = AIS_AIRPORT_STUFF;
-	p->ai.timeout_counter = 0;
-}
-
-static void AiWantAircraftRoute(Player *p)
-{
-	uint16 r = (uint16)Random();
-
-	if (r >= 0x2AAA || _date < 0x3912 + DAYS_TILL_ORIGINAL_BASE_YEAR) {
-		AiWantPassengerAircraftRoute(p);
-	} else {
-		AiWantOilRigAircraftRoute(p);
-	}
-}
-
-static void AiWantShipRoute(Player *p)
-{
-	// XXX
-//	error("AiWaitShipRoute");
-}
-
-
-
-static void AiStateWantNewRoute(Player *p)
-{
-	uint16 r;
-	int i;
-
-	if (p->player_money < AiGetBasePrice(p) * 500) {
-		p->ai.state = AIS_0;
-		return;
-	}
-
-	i = 200;
-	for (;;) {
-		r = (uint16)Random();
-
-		if (_patches.ai_disable_veh_train &&
-				_patches.ai_disable_veh_roadveh &&
-				_patches.ai_disable_veh_aircraft &&
-				_patches.ai_disable_veh_ship) {
-			return;
-		}
-
-		if (r < 0x7626) {
-			if (_patches.ai_disable_veh_train) continue;
-			AiWantTrainRoute(p);
-		} else if (r < 0xC4EA) {
-			if (_patches.ai_disable_veh_roadveh) continue;
-			AiWantRoadRoute(p);
-		} else if (r < 0xD89B) {
-			if (_patches.ai_disable_veh_aircraft) continue;
-			AiWantAircraftRoute(p);
-		} else {
-			if (_patches.ai_disable_veh_ship) continue;
-			AiWantShipRoute(p);
-		}
-
-		// got a route?
-		if (p->ai.state != AIS_WANT_NEW_ROUTE) break;
-
-		// time out?
-		if (--i == 0) {
-			if (++p->ai.state_counter == 556) p->ai.state = AIS_0;
-			break;
-		}
-	}
-}
-
-static bool AiCheckTrackResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
-{
-	uint rad = (_patches.modified_catchment) ? CA_TRAIN : 4;
-
-	for (; p->mode != 4; p++) {
-		AcceptedCargo values;
-		TileIndex tile2;
-		uint w;
-		uint h;
-
-		if (p->mode != 1) continue;
-
-		tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
-		w = GB(p->attr, 1, 3);
-		h = GB(p->attr, 4, 3);
-
-		if (p->attr & 1) uintswap(w, h);
-
-		if (cargo & 0x80) {
-			GetProductionAroundTiles(values, tile2, w, h, rad);
-			return values[cargo & 0x7F] != 0;
-		} else {
-			GetAcceptanceAroundTiles(values, tile2, w, h, rad);
-			if (!(values[cargo] & ~7))
-				return false;
-			if (cargo != CT_MAIL)
-				return true;
-			return !!((values[cargo]>>1) & ~7);
-		}
-	}
-
-	return true;
-}
-
-static int32 AiDoBuildDefaultRailTrack(TileIndex tile, const AiDefaultBlockData* p, RailType railtype, byte flag)
-{
-	int32 ret;
-	int32 total_cost = 0;
-	Town *t = NULL;
-	int rating = 0;
-	int i,j,k;
-
-	for (;;) {
-		// This will seldomly overflow for valid reasons. Mask it to be on the safe side.
-		uint c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
-
-		_cleared_town = NULL;
-
-		if (p->mode < 2) {
-			if (p->mode == 0) {
-				// Depot
-				ret = DoCommand(c, railtype, p->attr, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_TRAIN_DEPOT);
-			} else {
-				// Station
-				ret = DoCommand(c, (p->attr&1) | (p->attr>>4)<<8 | (p->attr>>1&7)<<16, railtype, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_RAILROAD_STATION);
-			}
-
-			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
-
-clear_town_stuff:;
-			if (_cleared_town != NULL) {
-				if (t != NULL && t != _cleared_town)
-					return CMD_ERROR;
-				t = _cleared_town;
-				rating += _cleared_town_rating;
-			}
-		} else if (p->mode == 2) {
-			// Rail
-			if (IsTileType(c, MP_RAILWAY)) return CMD_ERROR;
-
-			j = p->attr;
-			k = 0;
-
-			// Build the rail
-			for (i = 0; i != 6; i++, j >>= 1) {
-				if (j&1) {
-					k = i;
-					ret = DoCommand(c, railtype, i, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
-					if (CmdFailed(ret)) return CMD_ERROR;
-					total_cost += ret;
-				}
-			}
-
-			/* signals too? */
-			if (j & 3) {
-				// Can't build signals on a road.
-				if (IsTileType(c, MP_STREET)) return CMD_ERROR;
-
-				if (flag & DC_EXEC) {
-					j = 4 - j;
-					do {
-						ret = DoCommand(c, k, 0, flag, CMD_BUILD_SIGNALS);
-					} while (--j);
-				} else {
-					ret = _price.build_signals;
-				}
-				if (CmdFailed(ret)) return CMD_ERROR;
-				total_cost += ret;
-			}
-		} else if (p->mode == 3) {
-			//Clear stuff and then build single rail.
-			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
-			ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
-			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret + _price.build_rail;
-
-			if (flag & DC_EXEC) {
-				DoCommand(c, railtype, p->attr&1, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_SINGLE_RAIL);
-			}
-
-			goto clear_town_stuff;
-		} else {
-			// Unk
-			break;
-		}
-
-		p++;
-	}
-
-	if (!(flag & DC_EXEC)) {
-		if (t != NULL && rating > t->ratings[_current_player]) {
-			return CMD_ERROR;
-		}
-	}
-
-	return total_cost;
-}
-
-// Returns rule and cost
-static int AiBuildDefaultRailTrack(TileIndex tile, byte p0, byte p1, byte p2, byte p3, byte dir, byte cargo, RailType railtype, int32* cost)
-{
-	int i;
-	const AiDefaultRailBlock *p;
-
-	for (i = 0; (p = _default_rail_track_data[i]) != NULL; i++) {
-		if (p->p0 == p0 && p->p1 == p1 && p->p2 == p2 && p->p3 == p3 &&
-				(p->dir == 0xFF || p->dir == dir || ((p->dir - 1) & 3) == dir)) {
-			*cost = AiDoBuildDefaultRailTrack(tile, p->data, railtype, DC_NO_TOWN_RATING);
-			if (!CmdFailed(*cost) && AiCheckTrackResources(tile, p->data, cargo))
-				return i;
-		}
-	}
-
-	return -1;
-}
-
-static const byte _terraform_up_flags[] = {
-	14, 13, 12, 11,
-	10,  9,  8,  7,
-	 6,  5,  4,  3,
-	 2,  1,  0,  1,
-	 2,  1,  4,  1,
-	 2,  1,  8,  1,
-	 2,  1,  4,  2,
-	 2,  1
-};
-
-static const byte _terraform_down_flags[] = {
-	1,  2, 3,  4,
-	5,  6, 1,  8,
-	9, 10, 8, 12,
-	4,  2, 0,  0,
-	1,  2, 3,  4,
-	5,  6, 2,  8,
-	9, 10, 1, 12,
-	8,  4
-};
-
-static void AiDoTerraformLand(TileIndex tile, int dir, int unk, int mode)
-{
-	PlayerID old_player;
-	uint32 r;
-	Slope slope;
-	uint h;
-
-	old_player = _current_player;
-	_current_player = OWNER_NONE;
-
-	r = Random();
-
-	unk &= (int)r;
-
-	do {
-		tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
-
-		r >>= 2;
-		if (r & 2) {
-			dir++;
-			if (r & 1) dir -= 2;
-		}
-		dir &= 3;
-	} while (--unk >= 0);
-
-	slope = GetTileSlope(tile, &h);
-
-	if (slope != SLOPE_FLAT) {
-		if (mode > 0 || (mode == 0 && !(r & 0xC))) {
-			// Terraform up
-			DoCommand(tile, _terraform_up_flags[slope - 1], 1,
-				DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
-		} else if (h != 0) {
-			// Terraform down
-			DoCommand(tile, _terraform_down_flags[slope - 1], 0,
-				DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
-		}
-	}
-
-	_current_player = old_player;
-}
-
-static void AiStateBuildDefaultRailBlocks(Player *p)
-{
-	uint i;
-	int j;
-	AiBuildRec *aib;
-	int rule;
-	int32 cost;
-
-	// time out?
-	if (++p->ai.timeout_counter == 1388) {
-		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
-		return;
-	}
-
-	// do the following 8 times
-	for (i = 0; i < 8; i++) {
-		// check if we can build the default track
-		aib = &p->ai.src;
-		j = p->ai.num_build_rec;
-		do {
-			// this item has already been built?
-			if (aib->cur_building_rule != 255) continue;
-
-			// adjust the coordinate randomly,
-			// to make sure that we find a position.
-			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
-
-			// check if the track can be build there.
-			rule = AiBuildDefaultRailTrack(aib->use_tile,
-				p->ai.build_kind, p->ai.num_wagons,
-				aib->unk6, aib->unk7,
-				aib->direction, aib->cargo,
-				p->ai.railtype_to_use,
-				&cost
-			);
-
-			if (rule == -1) {
-				// cannot build, terraform after a while
-				if (p->ai.state_counter >= 600) {
-					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
-				}
-				// also try the other terraform direction
-				if (++p->ai.state_counter >= 1000) {
-					p->ai.state_counter = 0;
-					p->ai.state_mode = -p->ai.state_mode;
-				}
-			} else if (CheckPlayerHasMoney(cost)) {
-				int32 r;
-				// player has money, build it.
-				aib->cur_building_rule = rule;
-
-				r = AiDoBuildDefaultRailTrack(
-					aib->use_tile,
-					_default_rail_track_data[rule]->data,
-					p->ai.railtype_to_use,
-					DC_EXEC | DC_NO_TOWN_RATING
-				);
-				assert(!CmdFailed(r));
-			}
-		} while (++aib,--j);
-	}
-
-	// check if we're done with all of them
-	aib = &p->ai.src;
-	j = p->ai.num_build_rec;
-	do {
-		if (aib->cur_building_rule == 255) return;
-	} while (++aib,--j);
-
-	// yep, all are done. switch state to the rail building state.
-	p->ai.state = AIS_BUILD_RAIL;
-	p->ai.state_mode = 255;
-}
-
-static TileIndex AiGetEdgeOfDefaultRailBlock(byte rule, TileIndex tile, byte cmd, int *dir)
-{
-	const AiDefaultBlockData *p = _default_rail_track_data[rule]->data;
-
-	while (p->mode != 3 || !((--cmd) & 0x80)) p++;
-
-	return tile + ToTileIndexDiff(p->tileoffs) - TileOffsByDiagDir(*dir = p->attr);
-}
-
-typedef struct AiRailPathFindData {
-	TileIndex tile;
-	TileIndex tile2;
-	int count;
-	bool flag;
-} AiRailPathFindData;
-
-static bool AiEnumFollowTrack(TileIndex tile, AiRailPathFindData *a, int track, uint length, byte *state)
-{
-	if (a->flag) return true;
-
-	if (length > 20 || tile == a->tile) {
-		a->flag = true;
-		return true;
-	}
-
-	if (DistanceMax(tile, a->tile2) < 4) a->count++;
-
-	return false;
-}
-
-static bool AiDoFollowTrack(const Player* p)
-{
-	AiRailPathFindData arpfd;
-
-	arpfd.tile = p->ai.start_tile_a;
-	arpfd.tile2 = p->ai.cur_tile_a;
-	arpfd.flag = false;
-	arpfd.count = 0;
-	FollowTrack(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a), 0x2000 | TRANSPORT_RAIL, p->ai.cur_dir_a^2,
-		(TPFEnumProc*)AiEnumFollowTrack, NULL, &arpfd);
-	return arpfd.count > 8;
-}
-
-typedef struct AiRailFinder {
-	TileIndex final_tile;
-	byte final_dir;
-	byte depth;
-	byte recursive_mode;
-	byte cur_best_dir;
-	byte best_dir;
-	byte cur_best_depth;
-	byte best_depth;
-	uint cur_best_dist;
-	const byte *best_ptr;
-	uint best_dist;
-	TileIndex cur_best_tile, best_tile;
-	TileIndex bridge_end_tile;
-	Player *player;
-} AiRailFinder;
-
-static const byte _ai_table_15[4][8] = {
-	{0, 0, 4, 3, 3, 1, 128 + 0, 64},
-	{1, 1, 2, 0, 4, 2, 128 + 1, 65},
-	{0, 2, 2, 3, 5, 1, 128 + 2, 66},
-	{1, 3, 5, 0, 3, 2, 128 + 3, 67}
-};
-
-static const byte _dir_table_1[] = { 3, 9, 12, 6};
-static const byte _dir_table_2[] = {12, 6,  3, 9};
-
-
-static bool AiIsTileBanned(const Player* p, TileIndex tile, byte val)
-{
-	int i;
-
-	for (i = 0; i != p->ai.banned_tile_count; i++) {
-		if (p->ai.banned_tiles[i] == tile && p->ai.banned_val[i] == val) {
-			return true;
-		}
-	}
-	return false;
-}
-
-static void AiBanTile(Player* p, TileIndex tile, byte val)
-{
-	uint i;
-
-	for (i = lengthof(p->ai.banned_tiles) - 1; i != 0; i--) {
-		p->ai.banned_tiles[i] = p->ai.banned_tiles[i - 1];
-		p->ai.banned_val[i] = p->ai.banned_val[i - 1];
-	}
-
-	p->ai.banned_tiles[0] = tile;
-	p->ai.banned_val[0] = val;
-
-	if (p->ai.banned_tile_count != lengthof(p->ai.banned_tiles)) {
-		p->ai.banned_tile_count++;
-	}
-}
-
-static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, int dir);
-
-static bool AiCheckRailPathBetter(AiRailFinder *arf, const byte *p)
-{
-	bool better = false;
-
-	if (arf->recursive_mode < 1) {
-		// Mode is 0. This means destination has not been found yet.
-		// If the found path is shorter than the current one, remember it.
-		if (arf->cur_best_dist < arf->best_dist) {
-			arf->best_dir = arf->cur_best_dir;
-			arf->best_dist = arf->cur_best_dist;
-			arf->best_ptr = p;
-			arf->best_tile = arf->cur_best_tile;
-			better = true;
-		}
-	} else if (arf->recursive_mode > 1) {
-		// Mode is 2.
-		if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
-			arf->best_depth = arf->cur_best_depth;
-			arf->best_dist = 0;
-			arf->best_ptr = p;
-			arf->best_tile = 0;
-			better = true;
-		}
-	}
-	arf->recursive_mode = 0;
-	arf->cur_best_dist = (uint)-1;
-	arf->cur_best_depth = 0xff;
-
-	return better;
-}
-
-static inline void AiCheckBuildRailBridgeHere(AiRailFinder *arf, TileIndex tile, const byte *p)
-{
-	Slope tileh;
-	uint z;
-	bool flag;
-
-	int dir2 = p[0] & 3;
-
-	tileh = GetTileSlope(tile, &z);
-	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
-		TileIndex tile_new = tile;
-
-		// Allow bridges directly over bottom tiles
-		flag = z == 0;
-		for (;;) {
-			TileType type;
-
-			if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return; // Wraping around map, no bridge possible!
-			tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
-			type = GetTileType(tile_new);
-
-			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile_new, NULL) != SLOPE_FLAT) {
-				if (!flag) return;
-				break;
-			}
-			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
-			flag = true;
-		}
-
-		// Is building a (rail)bridge possible at this place (type doesn't matter)?
-		if (CmdFailed(DoCommand(tile_new, tile, 0 | arf->player->ai.railtype_to_use << 8, DC_AUTO, CMD_BUILD_BRIDGE))) {
-			return;
-		}
-		AiBuildRailRecursive(arf, tile_new, dir2);
-
-		// At the bottom depth, check if the new path is better than the old one.
-		if (arf->depth == 1) {
-			if (AiCheckRailPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
-		}
-	}
-}
-
-static inline void AiCheckBuildRailTunnelHere(AiRailFinder *arf, TileIndex tile, const byte *p)
-{
-	uint z;
-
-	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
-		int32 cost = DoCommand(tile, arf->player->ai.railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-
-		if (!CmdFailed(cost) && cost <= (arf->player->player_money>>4)) {
-			AiBuildRailRecursive(arf, _build_tunnel_endtile, p[0]&3);
-			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
-		}
-	}
-}
-
-
-static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, int dir)
-{
-	const byte *p;
-
-	tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
-
-	// Reached destination?
-	if (tile == arf->final_tile) {
-		if (arf->final_dir != (dir^2)) {
-			if (arf->recursive_mode != 2) arf->recursive_mode = 1;
-		} else if (arf->recursive_mode != 2) {
-			arf->recursive_mode = 2;
-			arf->cur_best_depth = arf->depth;
-		} else {
-			if (arf->depth < arf->cur_best_depth) arf->cur_best_depth = arf->depth;
-		}
-		return;
-	}
-
-	// Depth too deep?
-	if (arf->depth >= 4) {
-		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
-
-		if (dist < arf->cur_best_dist) {
-			// Store the tile that is closest to the final position.
-			arf->cur_best_depth = arf->depth;
-			arf->cur_best_dist = dist;
-			arf->cur_best_tile = tile;
-			arf->cur_best_dir = dir;
-		}
-		return;
-	}
-
-	// Increase recursion depth
-	arf->depth++;
-
-	// Grab pointer to list of stuff that is possible to build
-	p = _ai_table_15[dir];
-
-	// Try to build a single rail in all directions.
-	if (GetTileZ(tile) == 0) {
-		p += 6;
-	} else {
-		do {
-			// Make sure the tile is not in the list of banned tiles and that a rail can be built here.
-			if (!AiIsTileBanned(arf->player, tile, p[0]) &&
-					!CmdFailed(DoCommand(tile, arf->player->ai.railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) {
-				AiBuildRailRecursive(arf, tile, p[1]);
-			}
-
-			// At the bottom depth?
-			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
-
-			p += 2;
-		} while (!(p[0]&0x80));
-	}
-
-	AiCheckBuildRailBridgeHere(arf, tile, p);
-	AiCheckBuildRailTunnelHere(arf, tile, p+1);
-
-	arf->depth--;
-}
-
-
-static const byte _dir_table_3[]= {0x25, 0x2A, 0x19, 0x16};
-
-static void AiBuildRailConstruct(Player *p)
-{
-	AiRailFinder arf;
-	int i;
-
-	// Check too much lookahead?
-	if (AiDoFollowTrack(p)) {
-		p->ai.state_counter = (Random()&0xE)+6; // Destruct this amount of blocks
-		p->ai.state_mode = 1; // Start destruct
-
-		// Ban this tile and don't reach it for a while.
-		AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a)));
-		return;
-	}
-
-	// Setup recursive finder and call it.
-	arf.player = p;
-	arf.final_tile = p->ai.cur_tile_b;
-	arf.final_dir = p->ai.cur_dir_b;
-	arf.depth = 0;
-	arf.recursive_mode = 0;
-	arf.best_ptr = NULL;
-	arf.cur_best_dist = (uint)-1;
-	arf.cur_best_depth = 0xff;
-	arf.best_dist = (uint)-1;
-	arf.best_depth = 0xff;
-	arf.cur_best_tile = 0;
-	arf.best_tile = 0;
-	AiBuildRailRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a);
-
-	// Reached destination?
-	if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
-		p->ai.state_mode = 255;
-		return;
-	}
-
-	// Didn't find anything to build?
-	if (arf.best_ptr == NULL) {
-		// Terraform some
-		for (i = 0; i != 5; i++) {
-			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
-		}
-
-		if (++p->ai.state_counter == 21) {
-			p->ai.state_counter = 40;
-			p->ai.state_mode = 1;
-
-			// Ban this tile
-			AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a)));
-		}
-		return;
-	}
-
-	p->ai.cur_tile_a += TileOffsByDiagDir(p->ai.cur_dir_a);
-
-	if (arf.best_ptr[0] & 0x80) {
-		int i;
-		int32 bridge_len = GetBridgeLength(arf.bridge_end_tile, p->ai.cur_tile_a);
-
-		/* Figure out which (rail)bridge type to build
-		 * start with best bridge, then go down to worse and worse bridges
-		 * unnecessary to check for worst bridge (i=0), since AI will always build
-		 * that. AI is so fucked up that fixing this small thing will probably not
-		 * solve a thing
-		 */
-		for (i = MAX_BRIDGES - 1; i != 0; i--) {
-			if (CheckBridge_Stuff(i, bridge_len)) {
-				int32 cost = DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE);
-				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
-			}
-		}
-
-		// Build it
-		DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
-
-		p->ai.cur_tile_a = arf.bridge_end_tile;
-		p->ai.state_counter = 0;
-	} else if (arf.best_ptr[0] & 0x40) {
-		// tunnel
-		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
-		p->ai.cur_tile_a = _build_tunnel_endtile;
-		p->ai.state_counter = 0;
-	} else {
-		// rail
-		p->ai.cur_dir_a = arf.best_ptr[1];
-		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, arf.best_ptr[0],
-			DC_EXEC | DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL);
-		p->ai.state_counter = 0;
-	}
-
-	if (arf.best_tile != 0) {
-		for (i = 0; i != 2; i++) {
-			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
-		}
-	}
-}
-
-static bool AiRemoveTileAndGoForward(Player *p)
-{
-	byte b;
-	int bit;
-	const byte *ptr;
-	TileIndex tile = p->ai.cur_tile_a;
-	TileIndex tilenew;
-
-	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		if (IsTunnel(tile)) {
-			// Clear the tunnel and continue at the other side of it.
-			if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
-				return false;
-			p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(p->ai.cur_dir_a));
-			return true;
-		} else {
-			// Check if the bridge points in the right direction.
-			// This is not really needed the first place AiRemoveTileAndGoForward is called.
-			if (DiagDirToAxis(GetBridgeRampDirection(tile)) != (p->ai.cur_dir_a & 1U)) return false;
-
-			tile = GetOtherBridgeEnd(tile);
-
-			tilenew = TILE_MASK(tile - TileOffsByDiagDir(p->ai.cur_dir_a));
-			// And clear the bridge.
-			if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
-				return false;
-			p->ai.cur_tile_a = tilenew;
-			return true;
-		}
-	}
-
-	// Find the railtype at the position. Quit if no rail there.
-	b = GetRailTrackStatus(tile) & _dir_table_3[p->ai.cur_dir_a];
-	if (b == 0) return false;
-
-	// Convert into a bit position that CMD_REMOVE_SINGLE_RAIL expects.
-	bit = FindFirstBit(b);
-
-	// Then remove and signals if there are any.
-	if (IsTileType(tile, MP_RAILWAY) &&
-			GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_SIGNALS);
-	}
-
-	// And also remove the rail.
-	if (CmdFailed(DoCommand(tile, 0, bit, DC_EXEC, CMD_REMOVE_SINGLE_RAIL)))
-		return false;
-
-	// Find the direction at the other edge of the rail.
-	ptr = _ai_table_15[p->ai.cur_dir_a ^ 2];
-	while (ptr[0] != bit) ptr += 2;
-	p->ai.cur_dir_a = ptr[1] ^ 2;
-
-	// And then also switch tile.
-	p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a - TileOffsByDiagDir(p->ai.cur_dir_a));
-
-	return true;
-}
-
-
-static void AiBuildRailDestruct(Player *p)
-{
-	// Decrease timeout.
-	if (!--p->ai.state_counter) {
-		p->ai.state_mode = 2;
-		p->ai.state_counter = 0;
-	}
-
-	// Don't do anything if the destination is already reached.
-	if (p->ai.cur_tile_a == p->ai.start_tile_a) return;
-
-	AiRemoveTileAndGoForward(p);
-}
-
-
-static void AiBuildRail(Player *p)
-{
-	switch (p->ai.state_mode) {
-		case 0: // Construct mode, build new rail.
-			AiBuildRailConstruct(p);
-			break;
-
-		case 1: // Destruct mode, destroy the rail currently built.
-			AiBuildRailDestruct(p);
-			break;
-
-		case 2: {
-			uint i;
-
-			// Terraform some and then try building again.
-			for (i = 0; i != 4; i++) {
-				AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
-			}
-
-			if (++p->ai.state_counter == 4) {
-				p->ai.state_counter = 0;
-				p->ai.state_mode = 0;
-			}
-		}
-
-		default: break;
-	}
-}
-
-static void AiStateBuildRail(Player *p)
-{
-	int num;
-	AiBuildRec *aib;
-	byte cmd;
-	TileIndex tile;
-	int dir;
-
-	// time out?
-	if (++p->ai.timeout_counter == 1388) {
-		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
-		return;
-	}
-
-	// Currently building a rail between two points?
-	if (p->ai.state_mode != 255) {
-		AiBuildRail(p);
-
-		// Alternate between edges
-		swap_tile(&p->ai.start_tile_a, &p->ai.start_tile_b);
-		swap_tile(&p->ai.cur_tile_a, &p->ai.cur_tile_b);
-		swap_byte(&p->ai.start_dir_a, &p->ai.start_dir_b);
-		swap_byte(&p->ai.cur_dir_a, &p->ai.cur_dir_b);
-		return;
-	}
-
-	// Now, find two new points to build between
-	num = p->ai.num_build_rec;
-	aib = &p->ai.src;
-
-	for (;;) {
-		cmd = aib->buildcmd_a;
-		aib->buildcmd_a = 255;
-		if (cmd != 255) break;
-
-		cmd = aib->buildcmd_b;
-		aib->buildcmd_b = 255;
-		if (cmd != 255) break;
-
-		aib++;
-		if (--num == 0) {
-			p->ai.state = AIS_BUILD_RAIL_VEH;
-			p->ai.state_counter = 0; // timeout
-			return;
-		}
-	}
-
-	// Find first edge to build from.
-	tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, cmd&3, &dir);
-	p->ai.start_tile_a = tile;
-	p->ai.cur_tile_a = tile;
-	p->ai.start_dir_a = dir;
-	p->ai.cur_dir_a = dir;
-	DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir&1)?1:0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
-
-	assert(TILE_MASK(tile) != 0xFF00);
-
-	// Find second edge to build to
-	aib = (&p->ai.src) + ((cmd >> 4)&0xF);
-	tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, (cmd>>2)&3, &dir);
-	p->ai.start_tile_b = tile;
-	p->ai.cur_tile_b = tile;
-	p->ai.start_dir_b = dir;
-	p->ai.cur_dir_b = dir;
-	DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir&1)?1:0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
-
-	assert(TILE_MASK(tile) != 0xFF00);
-
-	// And setup state.
-	p->ai.state_mode = 2;
-	p->ai.state_counter = 0;
-	p->ai.banned_tile_count = 0;
-}
-
-static StationID AiGetStationIdByDef(TileIndex tile, int id)
-{
-	const AiDefaultBlockData *p = _default_rail_track_data[id]->data;
-	while (p->mode != 1) p++;
-	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
-}
-
-static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
-{
-	EngineID best_veh_index = INVALID_ENGINE;
-	EngineID i;
-	uint16 best_capacity = 0;
-	uint16 best_speed    = 0;
-	uint speed;
-
-	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
-		const RailVehicleInfo *rvi = RailVehInfo(i);
-		const Engine* e = GetEngine(i);
-
-		if (!IsCompatibleRail(e->railtype, railtype) ||
-				!(rvi->flags & RVI_WAGON) ||
-				!HASBIT(e->player_avail, _current_player)) {
-			continue;
-		}
-
-		if (rvi->cargo_type != cargo) continue;
-
-		/* max_speed of 0 indicates no speed limit */
-		speed = rvi->max_speed == 0 ? 0xFFFF : rvi->max_speed;
-
-		if (rvi->capacity >= best_capacity && speed >= best_speed) {
-			best_capacity = rvi->capacity;
-			best_speed    = best_speed;
-			best_veh_index = i;
-		}
-	}
-
-	return best_veh_index;
-}
-
-static void AiStateBuildRailVeh(Player *p)
-{
-	const AiDefaultBlockData *ptr;
-	TileIndex tile;
-	EngineID veh;
-	int i;
-	CargoID cargo;
-	int32 cost;
-	Vehicle *v;
-	VehicleID loco_id;
-
-	ptr = _default_rail_track_data[p->ai.src.cur_building_rule]->data;
-	while (ptr->mode != 0) ptr++;
-
-	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
-
-
-	cargo = p->ai.cargo_type;
-	for (i = 0;;) {
-		if (p->ai.wagon_list[i] == INVALID_VEHICLE) {
-			veh = AiFindBestWagon(cargo, p->ai.railtype_to_use);
-			/* veh will return INVALID_ENGINE if no suitable wagon is available.
-			 * We shall treat this in the same way as having no money */
-			if (veh == INVALID_ENGINE) goto handle_nocash;
-			cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
-			if (CmdFailed(cost)) goto handle_nocash;
-			p->ai.wagon_list[i] = _new_vehicle_id;
-			p->ai.wagon_list[i + 1] = INVALID_VEHICLE;
-			return;
-		}
-		if (cargo == CT_MAIL) cargo = CT_PASSENGERS;
-		if (++i == p->ai.num_wagons * 2 - 1) break;
-	}
-
-	// Which locomotive to build?
-	veh = AiChooseTrainToBuild(p->ai.railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile);
-	if (veh == INVALID_ENGINE) {
-handle_nocash:
-		// after a while, if AI still doesn't have cash, get out of this block by selling the wagons.
-		if (++p->ai.state_counter == 1000) {
-			for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
-				cost = DoCommand(tile, p->ai.wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
-				assert(!CmdFailed(cost));
-			}
-			p->ai.state = AIS_0;
-		}
-		return;
-	}
-
-	// Try to build the locomotive
-	cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
-	assert(!CmdFailed(cost));
-	loco_id = _new_vehicle_id;
-
-	// Sell a vehicle if the train is double headed.
-	v = GetVehicle(loco_id);
-	if (v->next != NULL) {
-		i = p->ai.wagon_list[p->ai.num_wagons * 2 - 2];
-		p->ai.wagon_list[p->ai.num_wagons * 2 - 2] = INVALID_VEHICLE;
-		DoCommand(tile, i, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
-	}
-
-	// Move the wagons onto the train
-	for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
-		DoCommand(tile, p->ai.wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-	}
-
-	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
-		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
-		bool is_pass = (
-			p->ai.cargo_type == CT_PASSENGERS ||
-			p->ai.cargo_type == CT_MAIL ||
-			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
-		);
-		Order order;
-
-		order.type = OT_GOTO_STATION;
-		order.flags = 0;
-		order.dest = AiGetStationIdByDef(aib->use_tile, aib->cur_building_rule);
-
-		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
-		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
-			order.flags |= OF_FULL_LOAD;
-
-		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-	}
-
-	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_TRAIN);
-
-	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-
-	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
-
-	if (--p->ai.num_loco_to_build != 0) {
-//		p->ai.loco_id = INVALID_VEHICLE;
-		p->ai.wagon_list[0] = INVALID_VEHICLE;
-	} else {
-		p->ai.state = AIS_0;
-	}
-}
-
-static void AiStateDeleteRailBlocks(Player *p)
-{
-	const AiBuildRec* aib = &p->ai.src;
-	uint num = p->ai.num_build_rec;
-
-	do {
-		const AiDefaultBlockData* b;
-
-		if (aib->cur_building_rule == 255) continue;
-		for (b = _default_rail_track_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
-			DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		}
-	} while (++aib,--num);
-
-	p->ai.state = AIS_0;
-}
-
-static bool AiCheckRoadResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
-{
-	uint values[NUM_CARGO];
-	int rad;
-
-	if (_patches.modified_catchment) {
-		rad = CA_TRUCK; // Same as CA_BUS at the moment?
-	} else { // change that at some point?
-		rad = 4;
-	}
-
-	for (;; p++) {
-		if (p->mode == 4) {
-			return true;
-		} else if (p->mode == 1) {
-			TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
-
-			if (cargo & 0x80) {
-				GetProductionAroundTiles(values, tile2, 1, 1, rad);
-				return values[cargo & 0x7F] != 0;
-			} else {
-				GetAcceptanceAroundTiles(values, tile2, 1, 1, rad);
-				return (values[cargo]&~7) != 0;
-			}
-		}
-	}
-}
-
-static bool _want_road_truck_station;
-static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag);
-
-// Returns rule and cost
-static int AiFindBestDefaultRoadBlock(TileIndex tile, byte direction, byte cargo, int32 *cost)
-{
-	int i;
-	const AiDefaultRoadBlock *p;
-
-	_want_road_truck_station = (cargo & 0x7F) != CT_PASSENGERS;
-
-	for (i = 0; (p = _road_default_block_data[i]) != NULL; i++) {
-		if (p->dir == direction) {
-			*cost = AiDoBuildDefaultRoadBlock(tile, p->data, 0);
-			if (!CmdFailed(*cost) && AiCheckRoadResources(tile, p->data, cargo))
-				return i;
-		}
-	}
-
-	return -1;
-}
-
-static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
-{
-	int32 ret;
-	int32 total_cost = 0;
-	Town *t = NULL;
-	int rating = 0;
-	int roadflag = 0;
-
-	for (;p->mode != 4;p++) {
-		TileIndex c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
-
-		_cleared_town = NULL;
-
-		if (p->mode == 2) {
-			if (IsTileType(c, MP_STREET) &&
-					GetRoadTileType(c) == ROAD_TILE_NORMAL &&
-					(GetRoadBits(c) & p->attr) != 0) {
-				roadflag |= 2;
-
-				// all bits are already built?
-				if ((GetRoadBits(c) & p->attr) == p->attr) continue;
-			}
-
-			ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
-			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
-
-			continue;
-		}
-
-		if (p->mode == 0) {
-			// Depot
-			ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_DEPOT);
-			goto clear_town_stuff;
-		} else if (p->mode == 1) {
-			if (_want_road_truck_station) {
-				// Truck station
-				ret = DoCommand(c, p->attr, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
-			} else {
-				// Bus station
-				ret = DoCommand(c, p->attr, RS_BUS, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
-			}
-clear_town_stuff:;
-
-			if (CmdFailed(ret)) return CMD_ERROR;
-			total_cost += ret;
-
-			if (_cleared_town != NULL) {
-				if (t != NULL && t != _cleared_town) return CMD_ERROR;
-				t = _cleared_town;
-				rating += _cleared_town_rating;
-			}
-		} else if (p->mode == 3) {
-			if (flag & DC_EXEC) continue;
-
-			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
-
-			if (!IsTileType(c, MP_STREET) || GetRoadTileType(c) != ROAD_TILE_NORMAL) {
-				ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
-				if (CmdFailed(ret)) return CMD_ERROR;
-			}
-
-		}
-	}
-
-	if (!_want_road_truck_station && !(roadflag & 2)) return CMD_ERROR;
-
-	if (!(flag & DC_EXEC)) {
-		if (t != NULL && rating > t->ratings[_current_player]) return CMD_ERROR;
-	}
-	return total_cost;
-}
-
-// Make sure the blocks are not too close to each other
-static bool AiCheckBlockDistances(Player *p, TileIndex tile)
-{
-	const AiBuildRec* aib = &p->ai.src;
-	uint num = p->ai.num_build_rec;
-
-	do {
-		if (aib->cur_building_rule != 255) {
-			if (DistanceManhattan(aib->use_tile, tile) < 9) return false;
-		}
-	} while (++aib, --num);
-
-	return true;
-}
-
-
-static void AiStateBuildDefaultRoadBlocks(Player *p)
-{
-	uint i;
-	int j;
-	AiBuildRec *aib;
-	int rule;
-	int32 cost;
-
-	// time out?
-	if (++p->ai.timeout_counter == 1388) {
-		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
-		return;
-	}
-
-	// do the following 8 times
-	for (i = 0; i != 8; i++) {
-		// check if we can build the default track
-		aib = &p->ai.src;
-		j = p->ai.num_build_rec;
-		do {
-			// this item has already been built?
-			if (aib->cur_building_rule != 255) continue;
-
-			// adjust the coordinate randomly,
-			// to make sure that we find a position.
-			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
-
-			// check if the road can be built there.
-			rule = AiFindBestDefaultRoadBlock(
-				aib->use_tile, aib->direction, aib->cargo, &cost
-			);
-
-			if (rule == -1) {
-				// cannot build, terraform after a while
-				if (p->ai.state_counter >= 600) {
-					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
-				}
-				// also try the other terraform direction
-				if (++p->ai.state_counter >= 1000) {
-					p->ai.state_counter = 0;
-					p->ai.state_mode = -p->ai.state_mode;
-				}
-			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p,aib->use_tile)) {
-				int32 r;
-
-				// player has money, build it.
-				aib->cur_building_rule = rule;
-
-				r = AiDoBuildDefaultRoadBlock(
-					aib->use_tile,
-					_road_default_block_data[rule]->data,
-					DC_EXEC | DC_NO_TOWN_RATING
-				);
-				assert(!CmdFailed(r));
-			}
-		} while (++aib,--j);
-	}
-
-	// check if we're done with all of them
-	aib = &p->ai.src;
-	j = p->ai.num_build_rec;
-	do {
-		if (aib->cur_building_rule == 255) return;
-	} while (++aib,--j);
-
-	// yep, all are done. switch state to the rail building state.
-	p->ai.state = AIS_BUILD_ROAD;
-	p->ai.state_mode = 255;
-}
-
-typedef struct {
-	TileIndex final_tile;
-	byte final_dir;
-	byte depth;
-	byte recursive_mode;
-	byte cur_best_dir;
-	byte best_dir;
-	byte cur_best_depth;
-	byte best_depth;
-	uint cur_best_dist;
-	const byte *best_ptr;
-	uint best_dist;
-	TileIndex cur_best_tile, best_tile;
-	TileIndex bridge_end_tile;
-	Player *player;
-} AiRoadFinder;
-
-typedef struct AiRoadEnum {
-	TileIndex dest;
-	TileIndex best_tile;
-	int best_track;
-	uint best_dist;
-} AiRoadEnum;
-
-static const byte _dir_by_track[] = {
-	0, 1, 0, 1, 2, 1,
-	0, 0,
-	2, 3, 3, 2, 3, 0,
-};
-
-static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, int dir);
-
-static bool AiCheckRoadPathBetter(AiRoadFinder *arf, const byte *p)
-{
-	bool better = false;
-
-	if (arf->recursive_mode < 1) {
-		// Mode is 0. This means destination has not been found yet.
-		// If the found path is shorter than the current one, remember it.
-		if (arf->cur_best_dist < arf->best_dist ||
-			(arf->cur_best_dist == arf->best_dist && arf->cur_best_depth < arf->best_depth)) {
-			arf->best_depth = arf->cur_best_depth;
-			arf->best_dist = arf->cur_best_dist;
-			arf->best_dir = arf->cur_best_dir;
-			arf->best_ptr = p;
-			arf->best_tile = arf->cur_best_tile;
-			better = true;
-		}
-	} else if (arf->recursive_mode > 1) {
-		// Mode is 2.
-		if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
-			arf->best_depth = arf->cur_best_depth;
-			arf->best_dist = 0;
-			arf->best_ptr = p;
-			arf->best_tile = 0;
-			better = true;
-		}
-	}
-	arf->recursive_mode = 0;
-	arf->cur_best_dist = (uint)-1;
-	arf->cur_best_depth = 0xff;
-
-	return better;
-}
-
-
-static bool AiEnumFollowRoad(TileIndex tile, AiRoadEnum *a, int track, uint length, byte *state)
-{
-	uint dist = DistanceManhattan(tile, a->dest);
-
-	if (dist <= a->best_dist) {
-		TileIndex tile2 = TILE_MASK(tile + TileOffsByDiagDir(_dir_by_track[track]));
-
-		if (IsTileType(tile2, MP_STREET) && GetRoadTileType(tile2) == ROAD_TILE_NORMAL) {
-			a->best_dist = dist;
-			a->best_tile = tile;
-			a->best_track = track;
-		}
-	}
-
-	return false;
-}
-
-static const uint16 _ai_road_table_and[4] = {
-	0x1009,
-	0x16,
-	0x520,
-	0x2A00,
-};
-
-static bool AiCheckRoadFinished(Player *p)
-{
-	AiRoadEnum are;
-	TileIndex tile;
-	int dir = p->ai.cur_dir_a;
-	uint32 bits;
-	int i;
-
-	are.dest = p->ai.cur_tile_b;
-	tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(dir));
-
-	if (IsRoadStopTile(tile) || IsTileDepotType(tile, TRANSPORT_ROAD)) return false;
-	bits = GetTileTrackStatus(tile, TRANSPORT_ROAD) & _ai_road_table_and[dir];
-	if (bits == 0) return false;
-
-	are.best_dist = (uint)-1;
-
-	for_each_bit(i, bits) {
-		FollowTrack(tile, 0x3000 | TRANSPORT_ROAD, _dir_by_track[i], (TPFEnumProc*)AiEnumFollowRoad, NULL, &are);
-	}
-
-	if (DistanceManhattan(tile, are.dest) <= are.best_dist) return false;
-
-	if (are.best_dist == 0) return true;
-
-	p->ai.cur_tile_a = are.best_tile;
-	p->ai.cur_dir_a = _dir_by_track[are.best_track];
-	return false;
-}
-
-
-static bool AiBuildRoadHelper(TileIndex tile, int flags, int type)
-{
-	static const RoadBits _road_bits[] = {
-		ROAD_X,
-		ROAD_Y,
-		ROAD_NW | ROAD_NE,
-		ROAD_SW | ROAD_SE,
-		ROAD_NW | ROAD_SW,
-		ROAD_SE | ROAD_NE
-	};
-	return !CmdFailed(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
-}
-
-static inline void AiCheckBuildRoadBridgeHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
-{
-	Slope tileh;
-	uint z;
-	bool flag;
-
-	int dir2 = p[0] & 3;
-
-	tileh = GetTileSlope(tile, &z);
-	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
-		TileIndex tile_new = tile;
-
-		// Allow bridges directly over bottom tiles
-		flag = z == 0;
-		for (;;) {
-			TileType type;
-
-			if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return; // Wraping around map, no bridge possible!
-			tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
-			type = GetTileType(tile_new);
-
-			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
-				// Allow a bridge if either we have a tile that's water, rail or street,
-				// or if we found an up tile.
-				if (!flag) return;
-				break;
-			}
-			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
-			flag = true;
-		}
-
-		// Is building a (rail)bridge possible at this place (type doesn't matter)?
-		if (CmdFailed(DoCommand(tile_new, tile, 0x8000, DC_AUTO, CMD_BUILD_BRIDGE)))
-			return;
-		AiBuildRoadRecursive(arf, tile_new, dir2);
-
-		// At the bottom depth, check if the new path is better than the old one.
-		if (arf->depth == 1) {
-			if (AiCheckRoadPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
-		}
-	}
-}
-
-static inline void AiCheckBuildRoadTunnelHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
-{
-	uint z;
-
-	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
-		int32 cost = DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-
-		if (!CmdFailed(cost) && cost <= (arf->player->player_money>>4)) {
-			AiBuildRoadRecursive(arf, _build_tunnel_endtile, p[0]&3);
-			if (arf->depth == 1)  AiCheckRoadPathBetter(arf, p);
-		}
-	}
-}
-
-
-
-static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, int dir)
-{
-	const byte *p;
-
-	tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
-
-	// Reached destination?
-	if (tile == arf->final_tile) {
-		if ((arf->final_dir^2) == dir) {
-			arf->recursive_mode = 2;
-			arf->cur_best_depth = arf->depth;
-		}
-		return;
-	}
-
-	// Depth too deep?
-	if (arf->depth >= 4) {
-		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
-		if (dist < arf->cur_best_dist) {
-			// Store the tile that is closest to the final position.
-			arf->cur_best_dist = dist;
-			arf->cur_best_tile = tile;
-			arf->cur_best_dir = dir;
-			arf->cur_best_depth = arf->depth;
-		}
-		return;
-	}
-
-	// Increase recursion depth
-	arf->depth++;
-
-	// Grab pointer to list of stuff that is possible to build
-	p = _ai_table_15[dir];
-
-	// Try to build a single rail in all directions.
-	if (GetTileZ(tile) == 0) {
-		p += 6;
-	} else {
-		do {
-			// Make sure that a road can be built here.
-			if (AiBuildRoadHelper(tile, DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, p[0])) {
-				AiBuildRoadRecursive(arf, tile, p[1]);
-			}
-
-			// At the bottom depth?
-			if (arf->depth == 1) AiCheckRoadPathBetter(arf, p);
-
-			p += 2;
-		} while (!(p[0] & 0x80));
-	}
-
-	AiCheckBuildRoadBridgeHere(arf, tile, p);
-	AiCheckBuildRoadTunnelHere(arf, tile, p+1);
-
-	arf->depth--;
-}
-
-
-static void AiBuildRoadConstruct(Player *p)
-{
-	AiRoadFinder arf;
-	int i;
-	TileIndex tile;
-
-	// Reached destination?
-	if (AiCheckRoadFinished(p)) {
-		p->ai.state_mode = 255;
-		return;
-	}
-
-	// Setup recursive finder and call it.
-	arf.player = p;
-	arf.final_tile = p->ai.cur_tile_b;
-	arf.final_dir = p->ai.cur_dir_b;
-	arf.depth = 0;
-	arf.recursive_mode = 0;
-	arf.best_ptr = NULL;
-	arf.cur_best_dist = (uint)-1;
-	arf.cur_best_depth = 0xff;
-	arf.best_dist = (uint)-1;
-	arf.best_depth =  0xff;
-	arf.cur_best_tile = 0;
-	arf.best_tile = 0;
-	AiBuildRoadRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a);
-
-	// Reached destination?
-	if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
-		p->ai.state_mode = 255;
-		return;
-	}
-
-	// Didn't find anything to build?
-	if (arf.best_ptr == NULL) {
-		// Terraform some
-do_some_terraform:
-		for (i = 0; i != 5; i++)
-			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
-
-		if (++p->ai.state_counter == 21) {
-			p->ai.state_mode = 1;
-
-			p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a));
-			p->ai.cur_dir_a ^= 2;
-			p->ai.state_counter = 0;
-		}
-		return;
-	}
-
-	tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a));
-
-	if (arf.best_ptr[0]&0x80) {
-		int i;
-		int32 bridge_len;
-		p->ai.cur_tile_a = arf.bridge_end_tile;
-		bridge_len = GetBridgeLength(tile, p->ai.cur_tile_a); // tile
-
-		/* Figure out what (road)bridge type to build
-		 * start with best bridge, then go down to worse and worse bridges
-		 * unnecessary to check for worse bridge (i=0), since AI will always build that.
-		 *AI is so fucked up that fixing this small thing will probably not solve a thing
-		 */
-		for (i = 10; i != 0; i--) {
-			if (CheckBridge_Stuff(i, bridge_len)) {
-				int32 cost = DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO, CMD_BUILD_BRIDGE);
-				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
-			}
-		}
-
-		// Build it
-		DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
-
-		p->ai.state_counter = 0;
-	} else if (arf.best_ptr[0]&0x40) {
-		// tunnel
-		DoCommand(tile, 0x200, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
-		p->ai.cur_tile_a = _build_tunnel_endtile;
-		p->ai.state_counter = 0;
-	} else {
-		// road
-		if (!AiBuildRoadHelper(tile, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, arf.best_ptr[0]))
-			goto do_some_terraform;
-
-		p->ai.cur_dir_a = arf.best_ptr[1];
-		p->ai.cur_tile_a = tile;
-		p->ai.state_counter = 0;
-	}
-
-	if (arf.best_tile != 0) {
-		for (i = 0; i != 2; i++)
-			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
-	}
-}
-
-
-static void AiBuildRoad(Player *p)
-{
-	if (p->ai.state_mode < 1) {
-		// Construct mode, build new road.
-		AiBuildRoadConstruct(p);
-	} else if (p->ai.state_mode == 1) {
-		// Destruct mode, not implemented for roads.
-		p->ai.state_mode = 2;
-		p->ai.state_counter = 0;
-	} else if (p->ai.state_mode == 2) {
-		uint i;
-
-		// Terraform some and then try building again.
-		for (i = 0; i != 4; i++) {
-			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
-		}
-
-		if (++p->ai.state_counter == 4) {
-			p->ai.state_counter = 0;
-			p->ai.state_mode = 0;
-		}
-	}
-}
-
-static TileIndex AiGetRoadBlockEdge(byte rule, TileIndex tile, int *dir)
-{
-	const AiDefaultBlockData *p = _road_default_block_data[rule]->data;
-	while (p->mode != 1) p++;
-	*dir = p->attr;
-	return TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
-}
-
-
-static void AiStateBuildRoad(Player *p)
-{
-	int num;
-	AiBuildRec *aib;
-	byte cmd;
-	TileIndex tile;
-	int dir;
-
-	// time out?
-	if (++p->ai.timeout_counter == 1388) {
-		p->ai.state = AIS_DELETE_ROAD_BLOCKS;
-		return;
-	}
-
-	// Currently building a road between two points?
-	if (p->ai.state_mode != 255) {
-		AiBuildRoad(p);
-
-		// Alternate between edges
-		swap_tile(&p->ai.start_tile_a, &p->ai.start_tile_b);
-		swap_tile(&p->ai.cur_tile_a, &p->ai.cur_tile_b);
-		swap_byte(&p->ai.start_dir_a, &p->ai.start_dir_b);
-		swap_byte(&p->ai.cur_dir_a, &p->ai.cur_dir_b);
-
-		return;
-	}
-
-	// Now, find two new points to build between
-	num = p->ai.num_build_rec;
-	aib = &p->ai.src;
-
-	for (;;) {
-		cmd = aib->buildcmd_a;
-		aib->buildcmd_a = 255;
-		if (cmd != 255) break;
-
-		aib++;
-		if (--num == 0) {
-			p->ai.state = AIS_BUILD_ROAD_VEHICLES;
-			return;
-		}
-	}
-
-	// Find first edge to build from.
-	tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
-	p->ai.start_tile_a = tile;
-	p->ai.cur_tile_a = tile;
-	p->ai.start_dir_a = dir;
-	p->ai.cur_dir_a = dir;
-
-	// Find second edge to build to
-	aib = (&p->ai.src) + (cmd&0xF);
-	tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
-	p->ai.start_tile_b = tile;
-	p->ai.cur_tile_b = tile;
-	p->ai.start_dir_b = dir;
-	p->ai.cur_dir_b = dir;
-
-	// And setup state.
-	p->ai.state_mode = 2;
-	p->ai.state_counter = 0;
-	p->ai.banned_tile_count = 0;
-}
-
-static StationID AiGetStationIdFromRoadBlock(TileIndex tile, int id)
-{
-	const AiDefaultBlockData *p = _road_default_block_data[id]->data;
-	while (p->mode != 1) p++;
-	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
-}
-
-static void AiStateBuildRoadVehicles(Player *p)
-{
-	const AiDefaultBlockData *ptr;
-	TileIndex tile;
-	VehicleID loco_id;
-	EngineID veh;
-	uint i;
-
-	ptr = _road_default_block_data[p->ai.src.cur_building_rule]->data;
-	for (; ptr->mode != 0; ptr++) {}
-	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
-
-	veh = AiChooseRoadVehToBuild(p->ai.cargo_type, p->player_money, tile);
-	if (veh == INVALID_ENGINE) {
-		p->ai.state = AIS_0;
-		return;
-	}
-
-	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) return;
-
-	loco_id = _new_vehicle_id;
-
-	if (GetVehicle(loco_id)->cargo_type != p->ai.cargo_type) {
-		/* Cargo type doesn't match, so refit it */
-		if (CmdFailed(DoCommand(tile, loco_id, p->ai.cargo_type, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
-			/* Refit failed... sell the vehicle */
-			DoCommand(tile, loco_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
-			return;
-		}
-	}
-
-	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
-		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
-		bool is_pass = (
-			p->ai.cargo_type == CT_PASSENGERS ||
-			p->ai.cargo_type == CT_MAIL ||
-			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
-		);
-		Order order;
-
-		order.type = OT_GOTO_STATION;
-		order.flags = 0;
-		order.dest = AiGetStationIdFromRoadBlock(aib->use_tile, aib->cur_building_rule);
-
-		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
-		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
-			order.flags |= OF_FULL_LOAD;
-
-		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-	}
-
-	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
-	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-
-	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
-	if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0;
-}
-
-static void AiStateDeleteRoadBlocks(Player *p)
-{
-	const AiBuildRec* aib = &p->ai.src;
-	uint num = p->ai.num_build_rec;
-
-	do {
-		const AiDefaultBlockData* b;
-
-		if (aib->cur_building_rule == 255) continue;
-		for (b = _road_default_block_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
-			if (b->mode > 1) continue;
-			DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		}
-	} while (++aib,--num);
-
-	p->ai.state = AIS_0;
-}
-
-
-static void AiStateAirportStuff(Player *p)
-{
-	const Station* st;
-	byte acc_planes;
-	int i;
-	AiBuildRec *aib;
-	byte rule;
-
-	// Here we look for an airport we could use instead of building a new
-	// one. If we find such an aiport for any waypoint,
-	// AiStateBuildDefaultAirportBlocks() will kindly skip that one when
-	// building the waypoints.
-
-	i = 0;
-	do {
-		// We do this all twice - once for the source (town in the case
-		// of oilrig route) and then for the destination (oilrig in the
-		// case of oilrig route).
-		aib = &p->ai.src + i;
-
-		FOR_ALL_STATIONS(st) {
-			// Is this an airport?
-			if (!(st->facilities & FACIL_AIRPORT)) continue;
-
-			// Do we own the airport? (Oilrigs aren't owned, though.)
-			if (st->owner != OWNER_NONE && st->owner != _current_player) continue;
-
-			acc_planes = GetAirport(st->airport_type)->acc_planes;
-
-			// Dismiss heliports, unless we are checking an oilrig.
-			if (acc_planes == HELICOPTERS_ONLY && (p->ai.build_kind != 1 || i != 1))
-				continue;
-
-			// Dismiss country airports if we are doing the other
-			// endpoint of an oilrig route.
-			if (acc_planes == AIRCRAFT_ONLY && (p->ai.build_kind == 1 && i == 0))
-				continue;
-
-			// Dismiss airports too far away.
-			if (DistanceMax(st->airport_tile, aib->spec_tile) > aib->rand_rng)
-				continue;
-
-			// It's ideal airport, let's take it!
-
-			/* XXX: This part is utterly broken - rule should
-			 * contain number of the rule appropriate for the
-			 * airport type (country, town, ...), see
-			 * _airport_default_block_data (rule is just an index
-			 * in this array). But the only difference between the
-			 * currently existing two rules (rule 0 - town and rule
-			 * 1 - country) is the attr field which is used only
-			 * when building new airports - and that's irrelevant
-			 * for us. So using just about any rule will suffice
-			 * here for now (some of the new airport types would be
-			 * broken because they will probably need different
-			 * tileoff values etc), no matter that
-			 * IsHangarTile() makes no sense. --pasky */
-			if (acc_planes == HELICOPTERS_ONLY) {
-				/* Heliports should have maybe own rulesets but
-				 * OTOH we don't want AI to pick them up when
-				 * looking for a suitable airport type to build.
-				 * So any of rules 0 or 1 would do for now. The
-				 * original rule number was 2 but that's a bug
-				 * because we have no such rule. */
-				rule = 1;
-			} else {
-				rule = IsHangarTile(st->airport_tile);
-			}
-
-			aib->cur_building_rule = rule;
-			aib->use_tile = st->airport_tile;
-			break;
-		}
-	} while (++i != p->ai.num_build_rec);
-
-	p->ai.state = AIS_BUILD_DEFAULT_AIRPORT_BLOCKS;
-	p->ai.state_mode = 255;
-	p->ai.state_counter = 0;
-}
-
-static int32 AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
-{
-	int32 total_cost = 0, ret;
-
-	for (; p->mode == 0; p++) {
-		if (!HASBIT(_avail_aircraft, p->attr)) return CMD_ERROR;
-		ret = DoCommand(TILE_MASK(tile + ToTileIndexDiff(p->tileoffs)), p->attr,0,flag | DC_AUTO | DC_NO_WATER,CMD_BUILD_AIRPORT);
-		if (CmdFailed(ret)) return CMD_ERROR;
-		total_cost += ret;
-	}
-
-	return total_cost;
-}
-
-static bool AiCheckAirportResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
-{
-	uint values[NUM_CARGO];
-	int rad;
-
-	if (_patches.modified_catchment) {
-		rad = CA_AIR_LARGE; // I Have NFI what airport the
-	} else { // AI is going to build here
-		rad = 4;
-	}
-
-	for (; p->mode == 0; p++) {
-		TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
-		const AirportFTAClass* airport = GetAirport(p->attr);
-		uint w = airport->size_x;
-		uint h = airport->size_y;
-
-		if (cargo & 0x80) {
-			GetProductionAroundTiles(values, tile2, w, h, rad);
-			return values[cargo & 0x7F] != 0;
-		} else {
-			GetAcceptanceAroundTiles(values, tile2, w, h, rad);
-			return values[cargo] >= 8;
-		}
-	}
-	return true;
-}
-
-static int AiFindBestDefaultAirportBlock(TileIndex tile, byte cargo, byte heli, int32 *cost)
-{
-	const AiDefaultBlockData *p;
-	uint i;
-
-	for (i = 0; (p = _airport_default_block_data[i]) != NULL; i++) {
-		// If we are doing a helicopter service, avoid building
-		// airports where they can't land.
-		if (heli && GetAirport(p->attr)->acc_planes == AIRCRAFT_ONLY) continue;
-
-		*cost = AiDoBuildDefaultAirportBlock(tile, p, 0);
-		if (!CmdFailed(*cost) && AiCheckAirportResources(tile, p, cargo))
-			return i;
-	}
-	return -1;
-}
-
-static void AiStateBuildDefaultAirportBlocks(Player *p)
-{
-	int i, j;
-	AiBuildRec *aib;
-	int rule;
-	int32 cost;
-
-	// time out?
-	if (++p->ai.timeout_counter == 1388) {
-		p->ai.state = AIS_0;
-		return;
-	}
-
-	// do the following 8 times
-	i = 8;
-	do {
-		// check if we can build the default
-		aib = &p->ai.src;
-		j = p->ai.num_build_rec;
-		do {
-			// this item has already been built?
-			if (aib->cur_building_rule != 255) continue;
-
-			// adjust the coordinate randomly,
-			// to make sure that we find a position.
-			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
-
-			// check if the aircraft stuff can be built there.
-			rule = AiFindBestDefaultAirportBlock(aib->use_tile, aib->cargo, p->ai.build_kind, &cost);
-
-//			SetRedErrorSquare(aib->use_tile);
-
-			if (rule == -1) {
-				// cannot build, terraform after a while
-				if (p->ai.state_counter >= 600) {
-					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
-				}
-				// also try the other terraform direction
-				if (++p->ai.state_counter >= 1000) {
-					p->ai.state_counter = 0;
-					p->ai.state_mode = -p->ai.state_mode;
-				}
-			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p,aib->use_tile)) {
-				// player has money, build it.
-				int32 r;
-
-				aib->cur_building_rule = rule;
-
-				r = AiDoBuildDefaultAirportBlock(
-					aib->use_tile,
-					_airport_default_block_data[rule],
-					DC_EXEC | DC_NO_TOWN_RATING
-				);
-				assert(!CmdFailed(r));
-			}
-		} while (++aib,--j);
-	} while (--i);
-
-	// check if we're done with all of them
-	aib = &p->ai.src;
-	j = p->ai.num_build_rec;
-	do {
-		if (aib->cur_building_rule == 255) return;
-	} while (++aib,--j);
-
-	// yep, all are done. switch state.
-	p->ai.state = AIS_BUILD_AIRCRAFT_VEHICLES;
-}
-
-static StationID AiGetStationIdFromAircraftBlock(TileIndex tile, int id)
-{
-	const AiDefaultBlockData *p = _airport_default_block_data[id];
-	while (p->mode != 1) p++;
-	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
-}
-
-static void AiStateBuildAircraftVehicles(Player *p)
-{
-	const AiDefaultBlockData *ptr;
-	TileIndex tile;
-	EngineID veh;
-	int i;
-	VehicleID loco_id;
-
-	ptr = _airport_default_block_data[p->ai.src.cur_building_rule];
-	for (; ptr->mode != 0; ptr++) {}
-
-	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
-
-	veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL);
-	if (veh == INVALID_ENGINE) return;
-
-	/* XXX - Have the AI pick the hangar terminal in an airport. Eg get airport-type
-	 * and offset to the FIRST depot because the AI picks the st->xy tile */
-	tile += ToTileIndexDiff(GetAirport(GetStationByTile(tile)->airport_type)->airport_depots[0]);
-	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) return;
-	loco_id = _new_vehicle_id;
-
-	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
-		AiBuildRec *aib = (&p->ai.src) + p->ai.order_list_blocks[i];
-		bool is_pass = (p->ai.cargo_type == CT_PASSENGERS || p->ai.cargo_type == CT_MAIL);
-		Order order;
-
-		order.type = OT_GOTO_STATION;
-		order.flags = 0;
-		order.dest = AiGetStationIdFromAircraftBlock(aib->use_tile, aib->cur_building_rule);
-
-		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
-		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
-			order.flags |= OF_FULL_LOAD;
-
-		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-	}
-
-	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
-
-	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
-
-	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
-
-	if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0;
-}
-
-static void AiStateCheckShipStuff(Player *p)
-{
-	// XXX
-	error("!AiStateCheckShipStuff");
-}
-
-static void AiStateBuildDefaultShipBlocks(Player *p)
-{
-	// XXX
-	error("!AiStateBuildDefaultShipBlocks");
-}
-
-static void AiStateDoShipStuff(Player *p)
-{
-	// XXX
-	error("!AiStateDoShipStuff");
-}
-
-static void AiStateSellVeh(Player *p)
-{
-	Vehicle *v = p->ai.cur_veh;
-
-	if (v->owner == _current_player) {
-		if (v->type == VEH_Train) {
-
-			if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
-				if (v->current_order.type != OT_GOTO_DEPOT)
-					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_TRAIN_TO_DEPOT);
-				goto going_to_depot;
-			}
-
-			// Sell whole train
-			DoCommand(v->tile, v->index, 1, DC_EXEC, CMD_SELL_RAIL_WAGON);
-
-		} else if (v->type == VEH_Road) {
-			if (!IsRoadVehInDepotStopped(v)) {
-				if (v->current_order.type != OT_GOTO_DEPOT)
-					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
-				goto going_to_depot;
-			}
-
-			DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
-		} else if (v->type == VEH_Aircraft) {
-			if (!IsAircraftInHangarStopped(v)) {
-				if (v->current_order.type != OT_GOTO_DEPOT)
-					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
-				goto going_to_depot;
-			}
-
-			DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT);
-			} else if (v->type == VEH_Ship) {
-			// XXX: not implemented
-			error("!v->type == VEH_Ship");
-		}
-	}
-
-	goto return_to_loop;
-going_to_depot:;
-	if (++p->ai.state_counter <= 832) return;
-
-	if (v->current_order.type == OT_GOTO_DEPOT) {
-		v->current_order.type = OT_DUMMY;
-		v->current_order.flags = 0;
-		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-	}
-return_to_loop:;
-	p->ai.state = AIS_VEH_LOOP;
-}
-
-static void AiStateRemoveStation(Player *p)
-{
-	// Remove stations that aren't in use by any vehicle
-	byte *in_use;
-	const Order *ord;
-	const Station *st;
-	TileIndex tile;
-
-	// Go to this state when we're done.
-	p->ai.state = AIS_1;
-
-	// Get a list of all stations that are in use by a vehicle
-	in_use = malloc(GetMaxStationIndex() + 1);
-	memset(in_use, 0, GetMaxStationIndex() + 1);
-	FOR_ALL_ORDERS(ord) {
-		if (ord->type == OT_GOTO_STATION) in_use[ord->dest] = 1;
-	}
-
-	// Go through all stations and delete those that aren't in use
-	FOR_ALL_STATIONS(st) {
-		if (st->owner == _current_player && !in_use[st->index] &&
-				( (st->bus_stops != NULL && (tile = st->bus_stops->xy) != 0) ||
-					(st->truck_stops != NULL && (tile = st->truck_stops->xy)) != 0 ||
-					(tile = st->train_tile) != 0 ||
-					(tile = st->dock_tile) != 0 ||
-					(tile = st->airport_tile) != 0)) {
-			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		}
-	}
-
-	free(in_use);
-}
-
-static void AiRemovePlayerRailOrRoad(Player *p, TileIndex tile)
-{
-	TrackBits rails;
-
-	if (IsTileType(tile, MP_RAILWAY)) {
-		if (!IsTileOwner(tile, _current_player)) return;
-
-		if (IsPlainRailTile(tile)) {
-is_rail_crossing:;
-			rails = GetRailTrackStatus(tile);
-
-			if (rails == TRACK_BIT_HORZ || rails == TRACK_BIT_VERT) return;
-
-			if (rails & TRACK_BIT_3WAY_NE) {
-pos_0:
-				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(1, 0))) & TRACK_BIT_3WAY_SW) == 0) {
-					p->ai.cur_dir_a = 0;
-					p->ai.cur_tile_a = tile;
-					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
-					return;
-				}
-			}
-
-			if (rails & TRACK_BIT_3WAY_SE) {
-pos_1:
-				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(0, 1))) & TRACK_BIT_3WAY_NW) == 0) {
-					p->ai.cur_dir_a = 1;
-					p->ai.cur_tile_a = tile;
-					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
-					return;
-				}
-			}
-
-			if (rails & TRACK_BIT_3WAY_SW) {
-pos_2:
-				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(1, 0))) & TRACK_BIT_3WAY_NE) == 0) {
-					p->ai.cur_dir_a = 2;
-					p->ai.cur_tile_a = tile;
-					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
-					return;
-				}
-			}
-
-			if (rails & TRACK_BIT_3WAY_NW) {
-pos_3:
-				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) {
-					p->ai.cur_dir_a = 3;
-					p->ai.cur_tile_a = tile;
-					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
-					return;
-				}
-			}
-		} else {
-			static const byte _depot_bits[] = {0x19,0x16,0x25,0x2A};
-
-			DiagDirection dir = GetRailDepotDirection(tile);
-
-			if (GetRailTrackStatus(tile + TileOffsByDiagDir(dir)) & _depot_bits[dir])
-				return;
-
-			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		}
-	} else if (IsTileType(tile, MP_STREET)) {
-		if (!IsTileOwner(tile, _current_player)) return;
-
-		if (IsLevelCrossing(tile)) goto is_rail_crossing;
-
-		if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) {
-			DiagDirection dir;
-			TileIndex t;
-
-			// Check if there are any stations around.
-			t = tile + TileDiffXY(-1, 0);
-			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
-
-			t = tile + TileDiffXY(1, 0);
-			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
-
-			t = tile + TileDiffXY(0, -1);
-			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
-
-			t = tile + TileDiffXY(0, 1);
-			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
-
-			dir = GetRoadDepotDirection(tile);
-
-			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-			DoCommand(
-				TILE_MASK(tile + TileOffsByDiagDir(dir)),
-				DiagDirToRoadBits(ReverseDiagDir(dir)),
-				0,
-				DC_EXEC,
-				CMD_REMOVE_ROAD);
-		}
-	} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		if (!IsTileOwner(tile, _current_player) ||
-				!IsBridge(tile) ||
-				GetBridgeTransportType(tile) != TRANSPORT_RAIL) {
-			return;
-		}
-
-		rails = 0;
-
-		switch (GetBridgeRampDirection(tile)) {
-			default:
-			case DIAGDIR_NE: goto pos_2;
-			case DIAGDIR_SE: goto pos_3;
-			case DIAGDIR_SW: goto pos_0;
-			case DIAGDIR_NW: goto pos_1;
-		}
-	}
-}
-
-static void AiStateRemoveTrack(Player *p)
-{
-	/* Was 1000 for standard 8x8 maps. */
-	int num = MapSizeX() * 4;
-
-	do {
-		TileIndex tile = ++p->ai.state_counter;
-
-		// Iterated all tiles?
-		if (tile >= MapSize()) {
-			p->ai.state = AIS_REMOVE_STATION;
-			return;
-		}
-
-		// Remove player stuff in that tile
-		AiRemovePlayerRailOrRoad(p, tile);
-		if (p->ai.state != AIS_REMOVE_TRACK) return;
-	} while (--num);
-}
-
-static void AiStateRemoveSingleRailTile(Player *p)
-{
-	// Remove until we can't remove more.
-	if (!AiRemoveTileAndGoForward(p)) p->ai.state = AIS_REMOVE_TRACK;
-}
-
-static AiStateAction * const _ai_actions[] = {
-	AiCase0,
-	AiCase1,
-	AiStateVehLoop,
-	AiStateCheckReplaceVehicle,
-	AiStateDoReplaceVehicle,
-	AiStateWantNewRoute,
-
-	AiStateBuildDefaultRailBlocks,
-	AiStateBuildRail,
-	AiStateBuildRailVeh,
-	AiStateDeleteRailBlocks,
-
-	AiStateBuildDefaultRoadBlocks,
-	AiStateBuildRoad,
-	AiStateBuildRoadVehicles,
-	AiStateDeleteRoadBlocks,
-
-	AiStateAirportStuff,
-	AiStateBuildDefaultAirportBlocks,
-	AiStateBuildAircraftVehicles,
-
-	AiStateCheckShipStuff,
-	AiStateBuildDefaultShipBlocks,
-	AiStateDoShipStuff,
-
-	AiStateSellVeh,
-	AiStateRemoveStation,
-	AiStateRemoveTrack,
-
-	AiStateRemoveSingleRailTile
-};
-
-extern void ShowBuyCompanyDialog(uint player);
-
-static void AiHandleTakeover(Player *p)
-{
-	if (p->bankrupt_timeout != 0) {
-		p->bankrupt_timeout -= 8;
-		if (p->bankrupt_timeout > 0) return;
-		p->bankrupt_timeout = 0;
-		DeleteWindowById(WC_BUY_COMPANY, _current_player);
-		if (IsLocalPlayer()) {
-			AskExitToGameMenu();
-			return;
-		}
-		if (IsHumanPlayer(_current_player)) return;
-	}
-
-	if (p->bankrupt_asked == 255) return;
-
-	{
-		uint asked = p->bankrupt_asked;
-		Player *pp, *best_pl = NULL;
-		int32 best_val = -1;
-		uint old_p;
-
-		// Ask the guy with the highest performance hist.
-		FOR_ALL_PLAYERS(pp) {
-			if (pp->is_active &&
-					!(asked&1) &&
-					pp->bankrupt_asked == 0 &&
-					best_val < pp->old_economy[1].performance_history) {
-				best_val = pp->old_economy[1].performance_history;
-				best_pl = pp;
-			}
-			asked>>=1;
-		}
-
-		// Asked all players?
-		if (best_val == -1) {
-			p->bankrupt_asked = 255;
-			return;
-		}
-
-		SETBIT(p->bankrupt_asked, best_pl->index);
-
-		if (best_pl->index == _local_player) {
-			p->bankrupt_timeout = 4440;
-			ShowBuyCompanyDialog(_current_player);
-			return;
-		}
-		if (IsHumanPlayer(best_pl->index)) return;
-
-		// Too little money for computer to buy it?
-		if (best_pl->player_money >> 1 >= p->bankrupt_value) {
-			// Computer wants to buy it.
-			old_p = _current_player;
-			_current_player = p->index;
-			DoCommand(0, old_p, 0, DC_EXEC, CMD_BUY_COMPANY);
-			_current_player = old_p;
-		}
-	}
-}
-
-static void AiAdjustLoan(const Player* p)
-{
-	int32 base = AiGetBasePrice(p);
-
-	if (p->player_money > base * 1400) {
-		// Decrease loan
-		if (p->current_loan != 0) {
-			DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN);
-		}
-	} else if (p->player_money < base * 500) {
-		// Increase loan
-		if (p->current_loan < _economy.max_loan &&
-				p->num_valid_stat_ent >= 2 &&
-				-(p->old_economy[0].expenses+p->old_economy[1].expenses) < base * 60) {
-			DoCommand(0, 0, 0, DC_EXEC, CMD_INCREASE_LOAN);
-		}
-	}
-}
-
-static void AiBuildCompanyHQ(Player *p)
-{
-	TileIndex tile;
-
-	if (p->location_of_house == 0 &&
-			p->last_build_coordinate != 0) {
-		tile = AdjustTileCoordRandomly(p->last_build_coordinate, 8);
-		DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
-	}
-}
-
-
-void AiDoGameLoop(Player *p)
-{
-	if (p->bankrupt_asked != 0) {
-		AiHandleTakeover(p);
-		return;
-	}
-
-	// Ugly hack to make sure the service interval of the AI is good, not looking
-	//  to the patch-setting
-	// Also, it takes into account the setting if the service-interval is in days
-	//  or in %
-	_ai_service_interval = _patches.servint_ispercent?80:180;
-
-	if (IsHumanPlayer(_current_player)) return;
-
-	AiAdjustLoan(p);
-	AiBuildCompanyHQ(p);
-
-#if 0
-	{
-		static byte old_state = 99;
-		static bool hasdots = false;
-		char *_ai_state_names[]={
-			"AiCase0",
-			"AiCase1",
-			"AiStateVehLoop",
-			"AiStateCheckReplaceVehicle",
-			"AiStateDoReplaceVehicle",
-			"AiStateWantNewRoute",
-			"AiStateBuildDefaultRailBlocks",
-			"AiStateBuildRail",
-			"AiStateBuildRailVeh",
-			"AiStateDeleteRailBlocks",
-			"AiStateBuildDefaultRoadBlocks",
-			"AiStateBuildRoad",
-			"AiStateBuildRoadVehicles",
-			"AiStateDeleteRoadBlocks",
-			"AiStateAirportStuff",
-			"AiStateBuildDefaultAirportBlocks",
-			"AiStateBuildAircraftVehicles",
-			"AiStateCheckShipStuff",
-			"AiStateBuildDefaultShipBlocks",
-			"AiStateDoShipStuff",
-			"AiStateSellVeh",
-			"AiStateRemoveStation",
-			"AiStateRemoveTrack",
-			"AiStateRemoveSingleRailTile"
-		};
-
-		if (p->ai.state != old_state) {
-			if (hasdots)
-				printf("\n");
-			hasdots=false;
-			printf("AiState: %s\n", _ai_state_names[old_state=p->ai.state]);
-		} else {
-			printf(".");
-			hasdots=true;
-		}
-	}
-#endif
-
-	_ai_actions[p->ai.state](p);
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/default/default.cpp
@@ -0,0 +1,3934 @@
+/* $Id$ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../aircraft.h"
+#include "../../bridge_map.h"
+#include "../../functions.h"
+#include "../../map.h"
+#include "../../rail_map.h"
+#include "../../road_map.h"
+#include "../../roadveh.h"
+#include "../../station_map.h"
+#include "../../tile.h"
+#include "../../player.h"
+#include "../../tunnel_map.h"
+#include "../../vehicle.h"
+#include "../../engine.h"
+#include "../../command.h"
+#include "../../town.h"
+#include "../../industry.h"
+#include "../../station.h"
+#include "../../pathfind.h"
+#include "../../economy.h"
+#include "../../airport.h"
+#include "../../depot.h"
+#include "../../variables.h"
+#include "../../bridge.h"
+#include "../../date.h"
+#include "default.h"
+
+// remove some day perhaps?
+static uint _ai_service_interval;
+
+typedef void AiStateAction(Player *p);
+
+enum {
+	AIS_0                            =  0,
+	AIS_1                            =  1,
+	AIS_VEH_LOOP                     =  2,
+	AIS_VEH_CHECK_REPLACE_VEHICLE    =  3,
+	AIS_VEH_DO_REPLACE_VEHICLE       =  4,
+	AIS_WANT_NEW_ROUTE               =  5,
+	AIS_BUILD_DEFAULT_RAIL_BLOCKS    =  6,
+	AIS_BUILD_RAIL                   =  7,
+	AIS_BUILD_RAIL_VEH               =  8,
+	AIS_DELETE_RAIL_BLOCKS           =  9,
+	AIS_BUILD_DEFAULT_ROAD_BLOCKS    = 10,
+	AIS_BUILD_ROAD                   = 11,
+	AIS_BUILD_ROAD_VEHICLES          = 12,
+	AIS_DELETE_ROAD_BLOCKS           = 13,
+	AIS_AIRPORT_STUFF                = 14,
+	AIS_BUILD_DEFAULT_AIRPORT_BLOCKS = 15,
+	AIS_BUILD_AIRCRAFT_VEHICLES      = 16,
+	AIS_CHECK_SHIP_STUFF             = 17,
+	AIS_BUILD_DEFAULT_SHIP_BLOCKS    = 18,
+	AIS_DO_SHIP_STUFF                = 19,
+	AIS_SELL_VEHICLE                 = 20,
+	AIS_REMOVE_STATION               = 21,
+	AIS_REMOVE_TRACK                 = 22,
+	AIS_REMOVE_SINGLE_RAIL_TILE      = 23
+};
+
+
+#include "../../table/ai_rail.h"
+
+static byte GetRailTrackStatus(TileIndex tile)
+{
+	uint32 r = GetTileTrackStatus(tile, TRANSPORT_RAIL);
+	return (byte) (r | r >> 8);
+}
+
+
+static void AiCase0(Player *p)
+{
+	p->ai.state = AIS_REMOVE_TRACK;
+	p->ai.state_counter = 0;
+}
+
+static void AiCase1(Player *p)
+{
+	p->ai.cur_veh = NULL;
+	p->ai.state = AIS_VEH_LOOP;
+}
+
+static void AiStateVehLoop(Player *p)
+{
+	Vehicle *v;
+	uint index;
+
+	index = (p->ai.cur_veh == NULL) ? 0 : p->ai.cur_veh->index + 1;
+
+	FOR_ALL_VEHICLES_FROM(v, index) {
+		if (v->owner != _current_player) continue;
+
+		if ((v->type == VEH_Train && v->subtype == 0) ||
+				v->type == VEH_Road ||
+				(v->type == VEH_Aircraft && v->subtype <= 2) ||
+				v->type == VEH_Ship) {
+			/* replace engine? */
+			if (v->type == VEH_Train && v->engine_type < 3 &&
+					(_price.build_railvehicle >> 3) < p->player_money) {
+				p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE;
+				p->ai.cur_veh = v;
+				return;
+			}
+
+			/* not profitable? */
+			if (v->age >= 730 &&
+					v->profit_last_year < _price.station_value * 5 &&
+					v->profit_this_year < _price.station_value * 5) {
+				p->ai.state_counter = 0;
+				p->ai.state = AIS_SELL_VEHICLE;
+				p->ai.cur_veh = v;
+				return;
+			}
+
+			/* not reliable? */
+			if (v->age >= v->max_age || (
+						v->age != 0 &&
+						GetEngine(v->engine_type)->reliability < 35389
+					)) {
+				p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE;
+				p->ai.cur_veh = v;
+				return;
+			}
+		}
+	}
+
+	p->ai.state = AIS_WANT_NEW_ROUTE;
+	p->ai.state_counter = 0;
+}
+
+static EngineID AiChooseTrainToBuild(RailType railtype, int32 money, byte flag, TileIndex tile)
+{
+	EngineID best_veh_index = INVALID_ENGINE;
+	byte best_veh_score = 0;
+	int32 ret;
+	EngineID i;
+
+	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
+		const RailVehicleInfo *rvi = RailVehInfo(i);
+		const Engine* e = GetEngine(i);
+
+		if (!IsCompatibleRail(e->railtype, railtype) ||
+				rvi->flags & RVI_WAGON ||
+				(rvi->flags & RVI_MULTIHEAD && flag & 1) ||
+				!HASBIT(e->player_avail, _current_player) ||
+				e->reliability < 0x8A3D) {
+			continue;
+		}
+
+		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_RAIL_VEHICLE);
+		if (!CmdFailed(ret) && ret <= money && rvi->ai_rank >= best_veh_score) {
+			best_veh_score = rvi->ai_rank;
+			best_veh_index = i;
+		}
+	}
+
+	return best_veh_index;
+}
+
+static EngineID AiChooseRoadVehToBuild(CargoID cargo, int32 money, TileIndex tile)
+{
+	EngineID best_veh_index = INVALID_ENGINE;
+	int32 best_veh_rating = 0;
+	EngineID i = ROAD_ENGINES_INDEX;
+	EngineID end = i + NUM_ROAD_ENGINES;
+
+	for (; i != end; i++) {
+		const RoadVehicleInfo *rvi = RoadVehInfo(i);
+		const Engine* e = GetEngine(i);
+		int32 rating;
+		int32 ret;
+
+		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
+			continue;
+		}
+
+		/* Skip vehicles which can't take our cargo type */
+		if (rvi->cargo_type != cargo && !CanRefitTo(i, cargo)) continue;
+
+		/* Rate and compare the engine by speed & capacity */
+		rating = rvi->max_speed * rvi->capacity;
+		if (rating <= best_veh_rating) continue;
+
+		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_ROAD_VEH);
+		if (CmdFailed(ret)) continue;
+
+		/* Add the cost of refitting */
+		if (rvi->cargo_type != cargo) ret += GetRefitCost(i);
+		if (ret > money) continue;
+
+		best_veh_rating = rating;
+		best_veh_index = i;
+	}
+
+	return best_veh_index;
+}
+
+static EngineID AiChooseAircraftToBuild(int32 money, byte flag)
+{
+	EngineID best_veh_index = INVALID_ENGINE;
+	int32 best_veh_cost = 0;
+	EngineID i;
+
+	for (i = AIRCRAFT_ENGINES_INDEX; i != AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
+		const Engine* e = GetEngine(i);
+		int32 ret;
+
+		if (!HASBIT(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
+			continue;
+		}
+
+		if ((AircraftVehInfo(i)->subtype & AIR_CTOL) != flag) continue;
+
+		ret = DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_AIRCRAFT);
+		if (!CmdFailed(ret) && ret <= money && ret >= best_veh_cost) {
+			best_veh_cost = ret;
+			best_veh_index = i;
+		}
+	}
+
+	return best_veh_index;
+}
+
+static int32 AiGetBasePrice(const Player* p)
+{
+	int32 base = _price.station_value;
+
+	// adjust base price when more expensive vehicles are available
+	switch (p->ai.railtype_to_use) {
+		default: NOT_REACHED();
+		case RAILTYPE_RAIL:     break;
+		case RAILTYPE_ELECTRIC: break;
+		case RAILTYPE_MONO:     base = (base * 3) >> 1; break;
+		case RAILTYPE_MAGLEV:   base *= 2; break;
+	}
+
+	return base;
+}
+
+#if 0
+static EngineID AiChooseShipToBuild(byte cargo, int32 money)
+{
+	// XXX: not done
+	return INVALID_ENGINE;
+}
+#endif
+
+static EngineID AiChooseRoadVehToReplaceWith(const Player* p, const Vehicle* v)
+{
+	int32 avail_money = p->player_money + v->value;
+	return AiChooseRoadVehToBuild(v->cargo_type, avail_money, v->tile);
+}
+
+static EngineID AiChooseAircraftToReplaceWith(const Player* p, const Vehicle* v)
+{
+	int32 avail_money = p->player_money + v->value;
+	return AiChooseAircraftToBuild(
+		avail_money, AircraftVehInfo(v->engine_type)->subtype & AIR_CTOL
+	);
+}
+
+static EngineID AiChooseTrainToReplaceWith(const Player* p, const Vehicle* v)
+{
+	int32 avail_money = p->player_money + v->value;
+	const Vehicle* u = v;
+	int num = 0;
+
+	while (++num, u->next != NULL) {
+		u = u->next;
+	}
+
+	// XXX: check if a wagon
+	return AiChooseTrainToBuild(v->u.rail.railtype, avail_money, 0, v->tile);
+}
+
+static EngineID AiChooseShipToReplaceWith(const Player* p, const Vehicle* v)
+{
+	error("!AiChooseShipToReplaceWith");
+
+	/* maybe useless, but avoids compiler warning this way */
+	return INVALID_ENGINE;
+}
+
+static void AiHandleGotoDepot(Player *p, int cmd)
+{
+	if (p->ai.cur_veh->current_order.type != OT_GOTO_DEPOT)
+		DoCommand(0, p->ai.cur_veh->index, 0, DC_EXEC, cmd);
+
+	if (++p->ai.state_counter <= 1387) {
+		p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE;
+		return;
+	}
+
+	if (p->ai.cur_veh->current_order.type == OT_GOTO_DEPOT) {
+		p->ai.cur_veh->current_order.type = OT_DUMMY;
+		p->ai.cur_veh->current_order.flags = 0;
+		InvalidateWindow(WC_VEHICLE_VIEW, p->ai.cur_veh->index);
+	}
+}
+
+static void AiRestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
+{
+	uint i;
+
+	for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
+		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
+			break;
+	}
+}
+
+static void AiHandleReplaceTrain(Player *p)
+{
+	const Vehicle* v = p->ai.cur_veh;
+	BackuppedOrders orderbak[1];
+	EngineID veh;
+
+	// wait until the vehicle reaches the depot.
+	if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
+		AiHandleGotoDepot(p, CMD_SEND_TRAIN_TO_DEPOT);
+		return;
+	}
+
+	veh = AiChooseTrainToReplaceWith(p, v);
+	if (veh != INVALID_ENGINE) {
+		TileIndex tile;
+
+		BackupVehicleOrders(v, orderbak);
+		tile = v->tile;
+
+		if (!CmdFailed(DoCommand(0, v->index, 2, DC_EXEC, CMD_SELL_RAIL_WAGON)) &&
+				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE))) {
+			VehicleID veh = _new_vehicle_id;
+			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
+			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_TRAIN);
+
+			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+		}
+	}
+}
+
+static void AiHandleReplaceRoadVeh(Player *p)
+{
+	const Vehicle* v = p->ai.cur_veh;
+	BackuppedOrders orderbak[1];
+	EngineID veh;
+
+	if (!IsRoadVehInDepotStopped(v)) {
+		AiHandleGotoDepot(p, CMD_SEND_ROADVEH_TO_DEPOT);
+		return;
+	}
+
+	veh = AiChooseRoadVehToReplaceWith(p, v);
+	if (veh != INVALID_ENGINE) {
+		TileIndex tile;
+
+		BackupVehicleOrders(v, orderbak);
+		tile = v->tile;
+
+		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH)) &&
+				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) {
+			VehicleID veh = _new_vehicle_id;
+
+			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
+			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
+			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+		}
+	}
+}
+
+static void AiHandleReplaceAircraft(Player *p)
+{
+	const Vehicle* v = p->ai.cur_veh;
+	BackuppedOrders orderbak[1];
+	EngineID veh;
+
+	if (!IsAircraftInHangarStopped(v)) {
+		AiHandleGotoDepot(p, CMD_SEND_AIRCRAFT_TO_HANGAR);
+		return;
+	}
+
+	veh = AiChooseAircraftToReplaceWith(p, v);
+	if (veh != INVALID_ENGINE) {
+		TileIndex tile;
+
+		BackupVehicleOrders(v, orderbak);
+		tile = v->tile;
+
+		if (!CmdFailed(DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT)) &&
+				!CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) {
+			VehicleID veh = _new_vehicle_id;
+			AiRestoreVehicleOrders(GetVehicle(veh), orderbak);
+			DoCommand(0, veh, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
+
+			DoCommand(0, veh, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+		}
+	}
+}
+
+static void AiHandleReplaceShip(Player *p)
+{
+	error("!AiHandleReplaceShip");
+}
+
+typedef EngineID CheckReplaceProc(const Player* p, const Vehicle* v);
+
+static CheckReplaceProc* const _veh_check_replace_proc[] = {
+	AiChooseTrainToReplaceWith,
+	AiChooseRoadVehToReplaceWith,
+	AiChooseShipToReplaceWith,
+	AiChooseAircraftToReplaceWith,
+};
+
+typedef void DoReplaceProc(Player *p);
+static DoReplaceProc* const _veh_do_replace_proc[] = {
+	AiHandleReplaceTrain,
+	AiHandleReplaceRoadVeh,
+	AiHandleReplaceShip,
+	AiHandleReplaceAircraft
+};
+
+static void AiStateCheckReplaceVehicle(Player *p)
+{
+	const Vehicle* v = p->ai.cur_veh;
+
+	if (!IsValidVehicle(v) ||
+			v->owner != _current_player ||
+			v->type > VEH_Ship ||
+			_veh_check_replace_proc[v->type - VEH_Train](p, v) == INVALID_ENGINE) {
+		p->ai.state = AIS_VEH_LOOP;
+	} else {
+		p->ai.state_counter = 0;
+		p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE;
+	}
+}
+
+static void AiStateDoReplaceVehicle(Player *p)
+{
+	const Vehicle* v = p->ai.cur_veh;
+
+	p->ai.state = AIS_VEH_LOOP;
+	// vehicle is not owned by the player anymore, something went very wrong.
+	if (!IsValidVehicle(v) || v->owner != _current_player) return;
+	_veh_do_replace_proc[v->type - VEH_Train](p);
+}
+
+typedef struct FoundRoute {
+	int distance;
+	CargoID cargo;
+	void *from;
+	void *to;
+} FoundRoute;
+
+static Town *AiFindRandomTown(void)
+{
+	return GetRandomTown();
+}
+
+static Industry *AiFindRandomIndustry(void)
+{
+	return GetRandomIndustry();
+}
+
+static void AiFindSubsidyIndustryRoute(FoundRoute *fr)
+{
+	uint i;
+	CargoID cargo;
+	const Subsidy* s;
+	Industry* from;
+	TileIndex to_xy;
+
+	// initially error
+	fr->distance = -1;
+
+	// Randomize subsidy index..
+	i = RandomRange(lengthof(_subsidies) * 3);
+	if (i >= lengthof(_subsidies)) return;
+
+	s = &_subsidies[i];
+
+	// Don't want passengers or mail
+	cargo = s->cargo_type;
+	if (cargo == CT_INVALID ||
+			cargo == CT_PASSENGERS ||
+			cargo == CT_MAIL ||
+			s->age > 7) {
+		return;
+	}
+	fr->cargo = cargo;
+
+	fr->from = from = GetIndustry(s->from);
+
+	if (cargo == CT_GOODS || cargo == CT_FOOD) {
+		Town* to_tow = GetTown(s->to);
+
+		if (to_tow->population < (cargo == CT_FOOD ? 200U : 900U)) return; // error
+		fr->to = to_tow;
+		to_xy = to_tow->xy;
+	} else {
+		Industry* to_ind = GetIndustry(s->to);
+
+		fr->to = to_ind;
+		to_xy = to_ind->xy;
+	}
+
+	fr->distance = DistanceManhattan(from->xy, to_xy);
+}
+
+static void AiFindSubsidyPassengerRoute(FoundRoute *fr)
+{
+	uint i;
+	const Subsidy* s;
+	Town *from,*to;
+
+	// initially error
+	fr->distance = -1;
+
+	// Randomize subsidy index..
+	i = RandomRange(lengthof(_subsidies) * 3);
+	if (i >= lengthof(_subsidies)) return;
+
+	s = &_subsidies[i];
+
+	// Only want passengers
+	if (s->cargo_type != CT_PASSENGERS || s->age > 7) return;
+	fr->cargo = s->cargo_type;
+
+	fr->from = from = GetTown(s->from);
+	fr->to = to = GetTown(s->to);
+
+	// They must be big enough
+	if (from->population < 400 || to->population < 400) return;
+
+	fr->distance = DistanceManhattan(from->xy, to->xy);
+}
+
+static void AiFindRandomIndustryRoute(FoundRoute *fr)
+{
+	Industry* i;
+	uint32 r;
+	CargoID cargo;
+
+	// initially error
+	fr->distance = -1;
+
+	r = Random();
+
+	// pick a source
+	fr->from = i = AiFindRandomIndustry();
+	if (i == NULL) return;
+
+	// pick a random produced cargo
+	cargo = i->produced_cargo[0];
+	if (r & 1 && i->produced_cargo[1] != CT_INVALID) cargo = i->produced_cargo[1];
+
+	fr->cargo = cargo;
+
+	// don't allow passengers
+	if (cargo == CT_INVALID || cargo == CT_PASSENGERS) return;
+
+	if (cargo != CT_GOODS && cargo != CT_FOOD) {
+		// pick a dest, and see if it can receive
+		Industry* i2 = AiFindRandomIndustry();
+
+		if (i2 == NULL || i == i2 || (
+					i2->accepts_cargo[0] != cargo &&
+					i2->accepts_cargo[1] != cargo &&
+					i2->accepts_cargo[2] != cargo)
+				) {
+			return;
+		}
+
+		fr->to = i2;
+		fr->distance = DistanceManhattan(i->xy, i2->xy);
+	} else {
+		// pick a dest town, and see if it's big enough
+		Town* t = AiFindRandomTown();
+
+		if (t == NULL || t->population < (cargo == CT_FOOD ? 200U : 900U)) return;
+
+		fr->to = t;
+		fr->distance = DistanceManhattan(i->xy, t->xy);
+	}
+}
+
+static void AiFindRandomPassengerRoute(FoundRoute *fr)
+{
+	Town* source;
+	Town* dest;
+
+	// initially error
+	fr->distance = -1;
+
+	fr->from = source = AiFindRandomTown();
+	if (source == NULL || source->population < 400) return;
+
+	fr->to = dest = AiFindRandomTown();
+	if (dest == NULL || source == dest || dest->population < 400) return;
+
+	fr->distance = DistanceManhattan(source->xy, dest->xy);
+}
+
+// Warn: depends on 'xy' being the first element in both Town and Industry
+#define GET_TOWN_OR_INDUSTRY_TILE(p) (((Town*)(p))->xy)
+
+static bool AiCheckIfRouteIsGood(Player *p, FoundRoute *fr, byte bitmask)
+{
+	TileIndex from_tile, to_tile;
+	Station *st;
+	int dist;
+	uint same_station = 0;
+
+	// Make sure distance to closest station is < 37 pixels.
+	from_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->from);
+	to_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->to);
+
+	dist = 0xFFFF;
+	FOR_ALL_STATIONS(st) {
+		int cur;
+
+		if (st->owner != _current_player) continue;
+		cur = DistanceMax(from_tile, st->xy);
+		if (cur < dist) dist = cur;
+		cur = DistanceMax(to_tile, st->xy);
+		if (cur < dist) dist = cur;
+		if (to_tile == from_tile && st->xy == to_tile) same_station++;
+	}
+
+	// To prevent the AI from building ten busstations in the same town, do some calculations
+	//  For each road or airport station, we want 350 of population!
+	if ((bitmask == 2 || bitmask == 4) &&
+			same_station > 2 &&
+			((Town*)fr->from)->population < same_station * 350) {
+		return false;
+	}
+
+	if (dist != 0xFFFF && dist > 37) return false;
+
+	if (p->ai.route_type_mask != 0 &&
+			!(p->ai.route_type_mask & bitmask) &&
+			!CHANCE16(1, 5)) {
+		return false;
+	}
+
+	if (fr->cargo == CT_PASSENGERS || fr->cargo == CT_MAIL) {
+		const Town* from = fr->from;
+		const Town* to   = fr->to;
+
+		if (from->pct_pass_transported > 0x99 ||
+				to->pct_pass_transported > 0x99) {
+			return false;
+		}
+
+		// Make sure it has a reasonably good rating
+		if (from->ratings[_current_player] < -100 ||
+				to->ratings[_current_player] < -100) {
+			return false;
+		}
+	} else {
+		const Industry* i = (const Industry*)fr->from;
+
+		if (i->pct_transported[fr->cargo != i->produced_cargo[0]] > 0x99 ||
+				i->total_production[fr->cargo != i->produced_cargo[0]] == 0) {
+			return false;
+		}
+	}
+
+	p->ai.route_type_mask |= bitmask;
+	return true;
+}
+
+static byte AiGetDirectionBetweenTiles(TileIndex a, TileIndex b)
+{
+	byte i = (TileX(a) < TileX(b)) ? 1 : 0;
+	if (TileY(a) >= TileY(b)) i ^= 3;
+	return i;
+}
+
+static TileIndex AiGetPctTileBetween(TileIndex a, TileIndex b, byte pct)
+{
+	return TileXY(
+		TileX(a) + ((TileX(b) - TileX(a)) * pct >> 8),
+		TileY(a) + ((TileY(b) - TileY(a)) * pct >> 8)
+	);
+}
+
+static void AiWantLongIndustryRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 60, 90 + 1)) break;
+
+		// try a random one
+		AiFindRandomIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 60, 90 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
+
+	// Fill the source field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 9;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.unk6 = 1;
+	p->ai.src.unk7 = 0;
+	p->ai.src.buildcmd_a = 0x24;
+	p->ai.src.buildcmd_b = 0xFF;
+	p->ai.src.direction = AiGetDirectionBetweenTiles(
+		p->ai.src.spec_tile,
+		p->ai.dst.spec_tile
+	);
+	p->ai.src.cargo = fr.cargo | 0x80;
+
+	// Fill the dest field
+
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 9;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.unk6 = 1;
+	p->ai.dst.unk7 = 0;
+	p->ai.dst.buildcmd_a = 0x34;
+	p->ai.dst.buildcmd_b = 0xFF;
+	p->ai.dst.direction = AiGetDirectionBetweenTiles(
+		p->ai.dst.spec_tile,
+		p->ai.src.spec_tile
+	);
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill middle field 1
+	p->ai.mid1.spec_tile = AiGetPctTileBetween(
+		p->ai.src.spec_tile,
+		p->ai.dst.spec_tile,
+		0x55
+	);
+	p->ai.mid1.use_tile = 0;
+	p->ai.mid1.rand_rng = 6;
+	p->ai.mid1.cur_building_rule = 0xFF;
+	p->ai.mid1.unk6 = 2;
+	p->ai.mid1.unk7 = 1;
+	p->ai.mid1.buildcmd_a = 0x30;
+	p->ai.mid1.buildcmd_b = 0xFF;
+	p->ai.mid1.direction = p->ai.src.direction;
+	p->ai.mid1.cargo = fr.cargo;
+
+	// Fill middle field 2
+	p->ai.mid2.spec_tile = AiGetPctTileBetween(
+		p->ai.src.spec_tile,
+		p->ai.dst.spec_tile,
+		0xAA
+	);
+	p->ai.mid2.use_tile = 0;
+	p->ai.mid2.rand_rng = 6;
+	p->ai.mid2.cur_building_rule = 0xFF;
+	p->ai.mid2.unk6 = 2;
+	p->ai.mid2.unk7 = 1;
+	p->ai.mid2.buildcmd_a = 0xFF;
+	p->ai.mid2.buildcmd_b = 0xFF;
+	p->ai.mid2.direction = p->ai.dst.direction;
+	p->ai.mid2.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_wagons = 3;
+	p->ai.build_kind = 2;
+	p->ai.num_build_rec = 4;
+	p->ai.num_loco_to_build = 2;
+	p->ai.num_want_fullload = 2;
+	p->ai.wagon_list[0] = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantMediumIndustryRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 40, 60 + 1)) break;
+
+		// try a random one
+		AiFindRandomIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 40, 60 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 9;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.unk6 = 1;
+	p->ai.src.unk7 = 0;
+	p->ai.src.buildcmd_a = 0x10;
+	p->ai.src.buildcmd_b = 0xFF;
+	p->ai.src.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
+	);
+	p->ai.src.cargo = fr.cargo | 0x80;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 9;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.unk6 = 1;
+	p->ai.dst.unk7 = 0;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.buildcmd_b = 0xFF;
+	p->ai.dst.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
+	);
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_wagons = 3;
+	p->ai.build_kind = 1;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 1;
+	p->ai.num_want_fullload = 1;
+	p->ai.wagon_list[0] = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantShortIndustryRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
+
+		// try a random one
+		AiFindRandomIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 9;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.unk6 = 1;
+	p->ai.src.unk7 = 0;
+	p->ai.src.buildcmd_a = 0x10;
+	p->ai.src.buildcmd_b = 0xFF;
+	p->ai.src.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
+	);
+	p->ai.src.cargo = fr.cargo | 0x80;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 9;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.unk6 = 1;
+	p->ai.dst.unk7 = 0;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.buildcmd_b = 0xFF;
+	p->ai.dst.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
+	);
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_wagons = 2;
+	p->ai.build_kind = 1;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 1;
+	p->ai.num_want_fullload = 1;
+	p->ai.wagon_list[0] = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantMailRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 60, 110 + 1)) break;
+
+		// try a random one
+		AiFindRandomPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 60, 110 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_MAIL;
+	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 7;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.unk6 = 1;
+	p->ai.src.unk7 = 0;
+	p->ai.src.buildcmd_a = 0x24;
+	p->ai.src.buildcmd_b = 0xFF;
+	p->ai.src.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
+	);
+	p->ai.src.cargo = fr.cargo;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 7;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.unk6 = 1;
+	p->ai.dst.unk7 = 0;
+	p->ai.dst.buildcmd_a = 0x34;
+	p->ai.dst.buildcmd_b = 0xFF;
+	p->ai.dst.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
+	);
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill middle field 1
+	p->ai.mid1.spec_tile = AiGetPctTileBetween(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		0x55
+	);
+	p->ai.mid1.use_tile = 0;
+	p->ai.mid1.rand_rng = 6;
+	p->ai.mid1.cur_building_rule = 0xFF;
+	p->ai.mid1.unk6 = 2;
+	p->ai.mid1.unk7 = 1;
+	p->ai.mid1.buildcmd_a = 0x30;
+	p->ai.mid1.buildcmd_b = 0xFF;
+	p->ai.mid1.direction = p->ai.src.direction;
+	p->ai.mid1.cargo = fr.cargo;
+
+	// Fill middle field 2
+	p->ai.mid2.spec_tile = AiGetPctTileBetween(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		0xAA
+	);
+	p->ai.mid2.use_tile = 0;
+	p->ai.mid2.rand_rng = 6;
+	p->ai.mid2.cur_building_rule = 0xFF;
+	p->ai.mid2.unk6 = 2;
+	p->ai.mid2.unk7 = 1;
+	p->ai.mid2.buildcmd_a = 0xFF;
+	p->ai.mid2.buildcmd_b = 0xFF;
+	p->ai.mid2.direction = p->ai.dst.direction;
+	p->ai.mid2.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_wagons = 3;
+	p->ai.build_kind = 2;
+	p->ai.num_build_rec = 4;
+	p->ai.num_loco_to_build = 2;
+	p->ai.num_want_fullload = 0;
+	p->ai.wagon_list[0] = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantPassengerRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 0, 55 + 1)) break;
+
+		// try a random one
+		AiFindRandomPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 0, 55 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_PASSENGERS;
+	if (!AiCheckIfRouteIsGood(p, &fr, 1)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 7;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.unk6 = 1;
+	p->ai.src.unk7 = 0;
+	p->ai.src.buildcmd_a = 0x10;
+	p->ai.src.buildcmd_b = 0xFF;
+	p->ai.src.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to)
+	);
+	p->ai.src.cargo = fr.cargo;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 7;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.unk6 = 1;
+	p->ai.dst.unk7 = 0;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.buildcmd_b = 0xFF;
+	p->ai.dst.direction = AiGetDirectionBetweenTiles(
+		GET_TOWN_OR_INDUSTRY_TILE(fr.to),
+		GET_TOWN_OR_INDUSTRY_TILE(fr.from)
+	);
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_wagons = 2;
+	p->ai.build_kind = 1;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 1;
+	p->ai.num_want_fullload = 0;
+	p->ai.wagon_list[0] = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+	p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantTrainRoute(Player *p)
+{
+	uint16 r = GB(Random(), 0, 16);
+
+	p->ai.railtype_to_use = GetBestRailtype(p);
+
+	if (r > 0xD000) {
+		AiWantLongIndustryRoute(p);
+	} else if (r > 0x6000) {
+		AiWantMediumIndustryRoute(p);
+	} else if (r > 0x1000) {
+		AiWantShortIndustryRoute(p);
+	} else if (r > 0x800) {
+		AiWantPassengerRoute(p);
+	} else {
+		AiWantMailRoute(p);
+	}
+}
+
+static void AiWantLongRoadIndustryRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 35, 55 + 1)) break;
+
+		// try a random one
+		AiFindRandomIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 35, 55 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 9;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.buildcmd_a = 1;
+	p->ai.src.direction = 0;
+	p->ai.src.cargo = fr.cargo | 0x80;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 9;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.direction = 0;
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 5;
+	p->ai.num_want_fullload = 5;
+
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantMediumRoadIndustryRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
+
+		// try a random one
+		AiFindRandomIndustryRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 15, 40 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 9;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.buildcmd_a = 1;
+	p->ai.src.direction = 0;
+	p->ai.src.cargo = fr.cargo | 0x80;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 9;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.direction = 0;
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 3;
+	p->ai.num_want_fullload = 3;
+
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantLongRoadPassengerRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 55, 180 + 1)) break;
+
+		// try a random one
+		AiFindRandomPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 55, 180 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_PASSENGERS;
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 10;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.buildcmd_a = 1;
+	p->ai.src.direction = 0;
+	p->ai.src.cargo = CT_PASSENGERS;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 10;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.direction = 0;
+	p->ai.dst.cargo = CT_PASSENGERS;
+
+	// Fill common fields
+	p->ai.cargo_type = CT_PASSENGERS;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 4;
+	p->ai.num_want_fullload = 0;
+
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantPassengerRouteInsideTown(Player *p)
+{
+	int i;
+	FoundRoute fr;
+	Town *t;
+
+	i = 60;
+	for (;;) {
+		// Find a town big enough
+		t = AiFindRandomTown();
+		if (t != NULL && t->population >= 700) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_PASSENGERS;
+	fr.from = fr.to = t;
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 2)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = t->xy;
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 10;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.buildcmd_a = 1;
+	p->ai.src.direction = 0;
+	p->ai.src.cargo = CT_PASSENGERS;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = t->xy;
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 10;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.buildcmd_a = 0xFF;
+	p->ai.dst.direction = 0;
+	p->ai.dst.cargo = CT_PASSENGERS;
+
+	// Fill common fields
+	p->ai.cargo_type = CT_PASSENGERS;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 2;
+	p->ai.num_want_fullload = 0;
+
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS;
+	p->ai.state_mode = -1;
+	p->ai.state_counter = 0;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantRoadRoute(Player *p)
+{
+	uint16 r = GB(Random(), 0, 16);
+
+	if (r > 0x4000) {
+		AiWantLongRoadIndustryRoute(p);
+	} else if (r > 0x2000) {
+		AiWantMediumRoadIndustryRoute(p);
+	} else if (r > 0x1000) {
+		AiWantLongRoadPassengerRoute(p);
+	} else {
+		AiWantPassengerRouteInsideTown(p);
+	}
+}
+
+static void AiWantPassengerAircraftRoute(Player *p)
+{
+	FoundRoute fr;
+	int i;
+
+	i = 60;
+	for (;;) {
+		// look for one from the subsidy list
+		AiFindSubsidyPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+
+		// try a random one
+		AiFindRandomPassengerRoute(&fr);
+		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_PASSENGERS;
+	if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
+
+
+	// Fill the source field
+	p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to);
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 12;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.cargo = fr.cargo;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from);
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 12;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.cargo = fr.cargo;
+
+	// Fill common fields
+	p->ai.cargo_type = fr.cargo;
+	p->ai.build_kind = 0;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 1;
+	p->ai.num_want_fullload = 1;
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_AIRPORT_STUFF;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantOilRigAircraftRoute(Player *p)
+{
+	int i;
+	FoundRoute fr;
+	Town *t;
+	Industry *in;
+
+	i = 60;
+	for (;;) {
+		// Find a town
+		t = AiFindRandomTown();
+		if (t != NULL) {
+			// Find a random oil rig industry
+			in = AiFindRandomIndustry();
+			if (in != NULL && in->type == IT_OIL_RIG) {
+				if (DistanceManhattan(t->xy, in->xy) < 60)
+					break;
+			}
+		}
+
+		// only test 60 times
+		if (--i == 0) return;
+	}
+
+	fr.cargo = CT_PASSENGERS;
+	fr.from = fr.to = t;
+
+	if (!AiCheckIfRouteIsGood(p, &fr, 4)) return;
+
+	// Fill the source field
+	p->ai.src.spec_tile = t->xy;
+	p->ai.src.use_tile = 0;
+	p->ai.src.rand_rng = 12;
+	p->ai.src.cur_building_rule = 0xFF;
+	p->ai.src.cargo = CT_PASSENGERS;
+
+	// Fill the dest field
+	p->ai.dst.spec_tile = in->xy;
+	p->ai.dst.use_tile = 0;
+	p->ai.dst.rand_rng = 5;
+	p->ai.dst.cur_building_rule = 0xFF;
+	p->ai.dst.cargo = CT_PASSENGERS;
+
+	// Fill common fields
+	p->ai.cargo_type = CT_PASSENGERS;
+	p->ai.build_kind = 1;
+	p->ai.num_build_rec = 2;
+	p->ai.num_loco_to_build = 1;
+	p->ai.num_want_fullload = 0;
+//	p->ai.loco_id = INVALID_VEHICLE;
+	p->ai.order_list_blocks[0] = 0;
+	p->ai.order_list_blocks[1] = 1;
+	p->ai.order_list_blocks[2] = 255;
+
+	p->ai.state = AIS_AIRPORT_STUFF;
+	p->ai.timeout_counter = 0;
+}
+
+static void AiWantAircraftRoute(Player *p)
+{
+	uint16 r = (uint16)Random();
+
+	if (r >= 0x2AAA || _date < 0x3912 + DAYS_TILL_ORIGINAL_BASE_YEAR) {
+		AiWantPassengerAircraftRoute(p);
+	} else {
+		AiWantOilRigAircraftRoute(p);
+	}
+}
+
+static void AiWantShipRoute(Player *p)
+{
+	// XXX
+//	error("AiWaitShipRoute");
+}
+
+
+
+static void AiStateWantNewRoute(Player *p)
+{
+	uint16 r;
+	int i;
+
+	if (p->player_money < AiGetBasePrice(p) * 500) {
+		p->ai.state = AIS_0;
+		return;
+	}
+
+	i = 200;
+	for (;;) {
+		r = (uint16)Random();
+
+		if (_patches.ai_disable_veh_train &&
+				_patches.ai_disable_veh_roadveh &&
+				_patches.ai_disable_veh_aircraft &&
+				_patches.ai_disable_veh_ship) {
+			return;
+		}
+
+		if (r < 0x7626) {
+			if (_patches.ai_disable_veh_train) continue;
+			AiWantTrainRoute(p);
+		} else if (r < 0xC4EA) {
+			if (_patches.ai_disable_veh_roadveh) continue;
+			AiWantRoadRoute(p);
+		} else if (r < 0xD89B) {
+			if (_patches.ai_disable_veh_aircraft) continue;
+			AiWantAircraftRoute(p);
+		} else {
+			if (_patches.ai_disable_veh_ship) continue;
+			AiWantShipRoute(p);
+		}
+
+		// got a route?
+		if (p->ai.state != AIS_WANT_NEW_ROUTE) break;
+
+		// time out?
+		if (--i == 0) {
+			if (++p->ai.state_counter == 556) p->ai.state = AIS_0;
+			break;
+		}
+	}
+}
+
+static bool AiCheckTrackResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
+{
+	uint rad = (_patches.modified_catchment) ? CA_TRAIN : 4;
+
+	for (; p->mode != 4; p++) {
+		AcceptedCargo values;
+		TileIndex tile2;
+		uint w;
+		uint h;
+
+		if (p->mode != 1) continue;
+
+		tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
+		w = GB(p->attr, 1, 3);
+		h = GB(p->attr, 4, 3);
+
+		if (p->attr & 1) uintswap(w, h);
+
+		if (cargo & 0x80) {
+			GetProductionAroundTiles(values, tile2, w, h, rad);
+			return values[cargo & 0x7F] != 0;
+		} else {
+			GetAcceptanceAroundTiles(values, tile2, w, h, rad);
+			if (!(values[cargo] & ~7))
+				return false;
+			if (cargo != CT_MAIL)
+				return true;
+			return !!((values[cargo]>>1) & ~7);
+		}
+	}
+
+	return true;
+}
+
+static int32 AiDoBuildDefaultRailTrack(TileIndex tile, const AiDefaultBlockData* p, RailType railtype, byte flag)
+{
+	int32 ret;
+	int32 total_cost = 0;
+	Town *t = NULL;
+	int rating = 0;
+	int i,j,k;
+
+	for (;;) {
+		// This will seldomly overflow for valid reasons. Mask it to be on the safe side.
+		uint c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
+
+		_cleared_town = NULL;
+
+		if (p->mode < 2) {
+			if (p->mode == 0) {
+				// Depot
+				ret = DoCommand(c, railtype, p->attr, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_TRAIN_DEPOT);
+			} else {
+				// Station
+				ret = DoCommand(c, (p->attr&1) | (p->attr>>4)<<8 | (p->attr>>1&7)<<16, railtype, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_RAILROAD_STATION);
+			}
+
+			if (CmdFailed(ret)) return CMD_ERROR;
+			total_cost += ret;
+
+clear_town_stuff:;
+			if (_cleared_town != NULL) {
+				if (t != NULL && t != _cleared_town)
+					return CMD_ERROR;
+				t = _cleared_town;
+				rating += _cleared_town_rating;
+			}
+		} else if (p->mode == 2) {
+			// Rail
+			if (IsTileType(c, MP_RAILWAY)) return CMD_ERROR;
+
+			j = p->attr;
+			k = 0;
+
+			// Build the rail
+			for (i = 0; i != 6; i++, j >>= 1) {
+				if (j&1) {
+					k = i;
+					ret = DoCommand(c, railtype, i, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
+					if (CmdFailed(ret)) return CMD_ERROR;
+					total_cost += ret;
+				}
+			}
+
+			/* signals too? */
+			if (j & 3) {
+				// Can't build signals on a road.
+				if (IsTileType(c, MP_STREET)) return CMD_ERROR;
+
+				if (flag & DC_EXEC) {
+					j = 4 - j;
+					do {
+						ret = DoCommand(c, k, 0, flag, CMD_BUILD_SIGNALS);
+					} while (--j);
+				} else {
+					ret = _price.build_signals;
+				}
+				if (CmdFailed(ret)) return CMD_ERROR;
+				total_cost += ret;
+			}
+		} else if (p->mode == 3) {
+			//Clear stuff and then build single rail.
+			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
+			ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
+			if (CmdFailed(ret)) return CMD_ERROR;
+			total_cost += ret + _price.build_rail;
+
+			if (flag & DC_EXEC) {
+				DoCommand(c, railtype, p->attr&1, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_SINGLE_RAIL);
+			}
+
+			goto clear_town_stuff;
+		} else {
+			// Unk
+			break;
+		}
+
+		p++;
+	}
+
+	if (!(flag & DC_EXEC)) {
+		if (t != NULL && rating > t->ratings[_current_player]) {
+			return CMD_ERROR;
+		}
+	}
+
+	return total_cost;
+}
+
+// Returns rule and cost
+static int AiBuildDefaultRailTrack(TileIndex tile, byte p0, byte p1, byte p2, byte p3, byte dir, byte cargo, RailType railtype, int32* cost)
+{
+	int i;
+	const AiDefaultRailBlock *p;
+
+	for (i = 0; (p = _default_rail_track_data[i]) != NULL; i++) {
+		if (p->p0 == p0 && p->p1 == p1 && p->p2 == p2 && p->p3 == p3 &&
+				(p->dir == 0xFF || p->dir == dir || ((p->dir - 1) & 3) == dir)) {
+			*cost = AiDoBuildDefaultRailTrack(tile, p->data, railtype, DC_NO_TOWN_RATING);
+			if (!CmdFailed(*cost) && AiCheckTrackResources(tile, p->data, cargo))
+				return i;
+		}
+	}
+
+	return -1;
+}
+
+static const byte _terraform_up_flags[] = {
+	14, 13, 12, 11,
+	10,  9,  8,  7,
+	 6,  5,  4,  3,
+	 2,  1,  0,  1,
+	 2,  1,  4,  1,
+	 2,  1,  8,  1,
+	 2,  1,  4,  2,
+	 2,  1
+};
+
+static const byte _terraform_down_flags[] = {
+	1,  2, 3,  4,
+	5,  6, 1,  8,
+	9, 10, 8, 12,
+	4,  2, 0,  0,
+	1,  2, 3,  4,
+	5,  6, 2,  8,
+	9, 10, 1, 12,
+	8,  4
+};
+
+static void AiDoTerraformLand(TileIndex tile, int dir, int unk, int mode)
+{
+	PlayerID old_player;
+	uint32 r;
+	Slope slope;
+	uint h;
+
+	old_player = _current_player;
+	_current_player = OWNER_NONE;
+
+	r = Random();
+
+	unk &= (int)r;
+
+	do {
+		tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
+
+		r >>= 2;
+		if (r & 2) {
+			dir++;
+			if (r & 1) dir -= 2;
+		}
+		dir &= 3;
+	} while (--unk >= 0);
+
+	slope = GetTileSlope(tile, &h);
+
+	if (slope != SLOPE_FLAT) {
+		if (mode > 0 || (mode == 0 && !(r & 0xC))) {
+			// Terraform up
+			DoCommand(tile, _terraform_up_flags[slope - 1], 1,
+				DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
+		} else if (h != 0) {
+			// Terraform down
+			DoCommand(tile, _terraform_down_flags[slope - 1], 0,
+				DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
+		}
+	}
+
+	_current_player = old_player;
+}
+
+static void AiStateBuildDefaultRailBlocks(Player *p)
+{
+	uint i;
+	int j;
+	AiBuildRec *aib;
+	int rule;
+	int32 cost;
+
+	// time out?
+	if (++p->ai.timeout_counter == 1388) {
+		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
+		return;
+	}
+
+	// do the following 8 times
+	for (i = 0; i < 8; i++) {
+		// check if we can build the default track
+		aib = &p->ai.src;
+		j = p->ai.num_build_rec;
+		do {
+			// this item has already been built?
+			if (aib->cur_building_rule != 255) continue;
+
+			// adjust the coordinate randomly,
+			// to make sure that we find a position.
+			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
+
+			// check if the track can be build there.
+			rule = AiBuildDefaultRailTrack(aib->use_tile,
+				p->ai.build_kind, p->ai.num_wagons,
+				aib->unk6, aib->unk7,
+				aib->direction, aib->cargo,
+				p->ai.railtype_to_use,
+				&cost
+			);
+
+			if (rule == -1) {
+				// cannot build, terraform after a while
+				if (p->ai.state_counter >= 600) {
+					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
+				}
+				// also try the other terraform direction
+				if (++p->ai.state_counter >= 1000) {
+					p->ai.state_counter = 0;
+					p->ai.state_mode = -p->ai.state_mode;
+				}
+			} else if (CheckPlayerHasMoney(cost)) {
+				int32 r;
+				// player has money, build it.
+				aib->cur_building_rule = rule;
+
+				r = AiDoBuildDefaultRailTrack(
+					aib->use_tile,
+					_default_rail_track_data[rule]->data,
+					p->ai.railtype_to_use,
+					DC_EXEC | DC_NO_TOWN_RATING
+				);
+				assert(!CmdFailed(r));
+			}
+		} while (++aib,--j);
+	}
+
+	// check if we're done with all of them
+	aib = &p->ai.src;
+	j = p->ai.num_build_rec;
+	do {
+		if (aib->cur_building_rule == 255) return;
+	} while (++aib,--j);
+
+	// yep, all are done. switch state to the rail building state.
+	p->ai.state = AIS_BUILD_RAIL;
+	p->ai.state_mode = 255;
+}
+
+static TileIndex AiGetEdgeOfDefaultRailBlock(byte rule, TileIndex tile, byte cmd, int *dir)
+{
+	const AiDefaultBlockData *p = _default_rail_track_data[rule]->data;
+
+	while (p->mode != 3 || !((--cmd) & 0x80)) p++;
+
+	return tile + ToTileIndexDiff(p->tileoffs) - TileOffsByDiagDir(*dir = p->attr);
+}
+
+typedef struct AiRailPathFindData {
+	TileIndex tile;
+	TileIndex tile2;
+	int count;
+	bool flag;
+} AiRailPathFindData;
+
+static bool AiEnumFollowTrack(TileIndex tile, AiRailPathFindData *a, int track, uint length, byte *state)
+{
+	if (a->flag) return true;
+
+	if (length > 20 || tile == a->tile) {
+		a->flag = true;
+		return true;
+	}
+
+	if (DistanceMax(tile, a->tile2) < 4) a->count++;
+
+	return false;
+}
+
+static bool AiDoFollowTrack(const Player* p)
+{
+	AiRailPathFindData arpfd;
+
+	arpfd.tile = p->ai.start_tile_a;
+	arpfd.tile2 = p->ai.cur_tile_a;
+	arpfd.flag = false;
+	arpfd.count = 0;
+	FollowTrack(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a), 0x2000 | TRANSPORT_RAIL, p->ai.cur_dir_a^2,
+		(TPFEnumProc*)AiEnumFollowTrack, NULL, &arpfd);
+	return arpfd.count > 8;
+}
+
+typedef struct AiRailFinder {
+	TileIndex final_tile;
+	byte final_dir;
+	byte depth;
+	byte recursive_mode;
+	byte cur_best_dir;
+	byte best_dir;
+	byte cur_best_depth;
+	byte best_depth;
+	uint cur_best_dist;
+	const byte *best_ptr;
+	uint best_dist;
+	TileIndex cur_best_tile, best_tile;
+	TileIndex bridge_end_tile;
+	Player *player;
+} AiRailFinder;
+
+static const byte _ai_table_15[4][8] = {
+	{0, 0, 4, 3, 3, 1, 128 + 0, 64},
+	{1, 1, 2, 0, 4, 2, 128 + 1, 65},
+	{0, 2, 2, 3, 5, 1, 128 + 2, 66},
+	{1, 3, 5, 0, 3, 2, 128 + 3, 67}
+};
+
+static const byte _dir_table_1[] = { 3, 9, 12, 6};
+static const byte _dir_table_2[] = {12, 6,  3, 9};
+
+
+static bool AiIsTileBanned(const Player* p, TileIndex tile, byte val)
+{
+	int i;
+
+	for (i = 0; i != p->ai.banned_tile_count; i++) {
+		if (p->ai.banned_tiles[i] == tile && p->ai.banned_val[i] == val) {
+			return true;
+		}
+	}
+	return false;
+}
+
+static void AiBanTile(Player* p, TileIndex tile, byte val)
+{
+	uint i;
+
+	for (i = lengthof(p->ai.banned_tiles) - 1; i != 0; i--) {
+		p->ai.banned_tiles[i] = p->ai.banned_tiles[i - 1];
+		p->ai.banned_val[i] = p->ai.banned_val[i - 1];
+	}
+
+	p->ai.banned_tiles[0] = tile;
+	p->ai.banned_val[0] = val;
+
+	if (p->ai.banned_tile_count != lengthof(p->ai.banned_tiles)) {
+		p->ai.banned_tile_count++;
+	}
+}
+
+static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, int dir);
+
+static bool AiCheckRailPathBetter(AiRailFinder *arf, const byte *p)
+{
+	bool better = false;
+
+	if (arf->recursive_mode < 1) {
+		// Mode is 0. This means destination has not been found yet.
+		// If the found path is shorter than the current one, remember it.
+		if (arf->cur_best_dist < arf->best_dist) {
+			arf->best_dir = arf->cur_best_dir;
+			arf->best_dist = arf->cur_best_dist;
+			arf->best_ptr = p;
+			arf->best_tile = arf->cur_best_tile;
+			better = true;
+		}
+	} else if (arf->recursive_mode > 1) {
+		// Mode is 2.
+		if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
+			arf->best_depth = arf->cur_best_depth;
+			arf->best_dist = 0;
+			arf->best_ptr = p;
+			arf->best_tile = 0;
+			better = true;
+		}
+	}
+	arf->recursive_mode = 0;
+	arf->cur_best_dist = (uint)-1;
+	arf->cur_best_depth = 0xff;
+
+	return better;
+}
+
+static inline void AiCheckBuildRailBridgeHere(AiRailFinder *arf, TileIndex tile, const byte *p)
+{
+	Slope tileh;
+	uint z;
+	bool flag;
+
+	int dir2 = p[0] & 3;
+
+	tileh = GetTileSlope(tile, &z);
+	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
+		TileIndex tile_new = tile;
+
+		// Allow bridges directly over bottom tiles
+		flag = z == 0;
+		for (;;) {
+			TileType type;
+
+			if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return; // Wraping around map, no bridge possible!
+			tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
+			type = GetTileType(tile_new);
+
+			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile_new, NULL) != SLOPE_FLAT) {
+				if (!flag) return;
+				break;
+			}
+			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
+			flag = true;
+		}
+
+		// Is building a (rail)bridge possible at this place (type doesn't matter)?
+		if (CmdFailed(DoCommand(tile_new, tile, 0 | arf->player->ai.railtype_to_use << 8, DC_AUTO, CMD_BUILD_BRIDGE))) {
+			return;
+		}
+		AiBuildRailRecursive(arf, tile_new, dir2);
+
+		// At the bottom depth, check if the new path is better than the old one.
+		if (arf->depth == 1) {
+			if (AiCheckRailPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
+		}
+	}
+}
+
+static inline void AiCheckBuildRailTunnelHere(AiRailFinder *arf, TileIndex tile, const byte *p)
+{
+	uint z;
+
+	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
+		int32 cost = DoCommand(tile, arf->player->ai.railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+
+		if (!CmdFailed(cost) && cost <= (arf->player->player_money>>4)) {
+			AiBuildRailRecursive(arf, _build_tunnel_endtile, p[0]&3);
+			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
+		}
+	}
+}
+
+
+static void AiBuildRailRecursive(AiRailFinder *arf, TileIndex tile, int dir)
+{
+	const byte *p;
+
+	tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
+
+	// Reached destination?
+	if (tile == arf->final_tile) {
+		if (arf->final_dir != (dir^2)) {
+			if (arf->recursive_mode != 2) arf->recursive_mode = 1;
+		} else if (arf->recursive_mode != 2) {
+			arf->recursive_mode = 2;
+			arf->cur_best_depth = arf->depth;
+		} else {
+			if (arf->depth < arf->cur_best_depth) arf->cur_best_depth = arf->depth;
+		}
+		return;
+	}
+
+	// Depth too deep?
+	if (arf->depth >= 4) {
+		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
+
+		if (dist < arf->cur_best_dist) {
+			// Store the tile that is closest to the final position.
+			arf->cur_best_depth = arf->depth;
+			arf->cur_best_dist = dist;
+			arf->cur_best_tile = tile;
+			arf->cur_best_dir = dir;
+		}
+		return;
+	}
+
+	// Increase recursion depth
+	arf->depth++;
+
+	// Grab pointer to list of stuff that is possible to build
+	p = _ai_table_15[dir];
+
+	// Try to build a single rail in all directions.
+	if (GetTileZ(tile) == 0) {
+		p += 6;
+	} else {
+		do {
+			// Make sure the tile is not in the list of banned tiles and that a rail can be built here.
+			if (!AiIsTileBanned(arf->player, tile, p[0]) &&
+					!CmdFailed(DoCommand(tile, arf->player->ai.railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) {
+				AiBuildRailRecursive(arf, tile, p[1]);
+			}
+
+			// At the bottom depth?
+			if (arf->depth == 1) AiCheckRailPathBetter(arf, p);
+
+			p += 2;
+		} while (!(p[0]&0x80));
+	}
+
+	AiCheckBuildRailBridgeHere(arf, tile, p);
+	AiCheckBuildRailTunnelHere(arf, tile, p+1);
+
+	arf->depth--;
+}
+
+
+static const byte _dir_table_3[]= {0x25, 0x2A, 0x19, 0x16};
+
+static void AiBuildRailConstruct(Player *p)
+{
+	AiRailFinder arf;
+	int i;
+
+	// Check too much lookahead?
+	if (AiDoFollowTrack(p)) {
+		p->ai.state_counter = (Random()&0xE)+6; // Destruct this amount of blocks
+		p->ai.state_mode = 1; // Start destruct
+
+		// Ban this tile and don't reach it for a while.
+		AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a)));
+		return;
+	}
+
+	// Setup recursive finder and call it.
+	arf.player = p;
+	arf.final_tile = p->ai.cur_tile_b;
+	arf.final_dir = p->ai.cur_dir_b;
+	arf.depth = 0;
+	arf.recursive_mode = 0;
+	arf.best_ptr = NULL;
+	arf.cur_best_dist = (uint)-1;
+	arf.cur_best_depth = 0xff;
+	arf.best_dist = (uint)-1;
+	arf.best_depth = 0xff;
+	arf.cur_best_tile = 0;
+	arf.best_tile = 0;
+	AiBuildRailRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a);
+
+	// Reached destination?
+	if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
+		p->ai.state_mode = 255;
+		return;
+	}
+
+	// Didn't find anything to build?
+	if (arf.best_ptr == NULL) {
+		// Terraform some
+		for (i = 0; i != 5; i++) {
+			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
+		}
+
+		if (++p->ai.state_counter == 21) {
+			p->ai.state_counter = 40;
+			p->ai.state_mode = 1;
+
+			// Ban this tile
+			AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a)));
+		}
+		return;
+	}
+
+	p->ai.cur_tile_a += TileOffsByDiagDir(p->ai.cur_dir_a);
+
+	if (arf.best_ptr[0] & 0x80) {
+		int i;
+		int32 bridge_len = GetBridgeLength(arf.bridge_end_tile, p->ai.cur_tile_a);
+
+		/* Figure out which (rail)bridge type to build
+		 * start with best bridge, then go down to worse and worse bridges
+		 * unnecessary to check for worst bridge (i=0), since AI will always build
+		 * that. AI is so fucked up that fixing this small thing will probably not
+		 * solve a thing
+		 */
+		for (i = MAX_BRIDGES - 1; i != 0; i--) {
+			if (CheckBridge_Stuff(i, bridge_len)) {
+				int32 cost = DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE);
+				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
+			}
+		}
+
+		// Build it
+		DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
+
+		p->ai.cur_tile_a = arf.bridge_end_tile;
+		p->ai.state_counter = 0;
+	} else if (arf.best_ptr[0] & 0x40) {
+		// tunnel
+		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
+		p->ai.cur_tile_a = _build_tunnel_endtile;
+		p->ai.state_counter = 0;
+	} else {
+		// rail
+		p->ai.cur_dir_a = arf.best_ptr[1];
+		DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, arf.best_ptr[0],
+			DC_EXEC | DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL);
+		p->ai.state_counter = 0;
+	}
+
+	if (arf.best_tile != 0) {
+		for (i = 0; i != 2; i++) {
+			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
+		}
+	}
+}
+
+static bool AiRemoveTileAndGoForward(Player *p)
+{
+	byte b;
+	int bit;
+	const byte *ptr;
+	TileIndex tile = p->ai.cur_tile_a;
+	TileIndex tilenew;
+
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (IsTunnel(tile)) {
+			// Clear the tunnel and continue at the other side of it.
+			if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
+				return false;
+			p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(p->ai.cur_dir_a));
+			return true;
+		} else {
+			// Check if the bridge points in the right direction.
+			// This is not really needed the first place AiRemoveTileAndGoForward is called.
+			if (DiagDirToAxis(GetBridgeRampDirection(tile)) != (p->ai.cur_dir_a & 1U)) return false;
+
+			tile = GetOtherBridgeEnd(tile);
+
+			tilenew = TILE_MASK(tile - TileOffsByDiagDir(p->ai.cur_dir_a));
+			// And clear the bridge.
+			if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR)))
+				return false;
+			p->ai.cur_tile_a = tilenew;
+			return true;
+		}
+	}
+
+	// Find the railtype at the position. Quit if no rail there.
+	b = GetRailTrackStatus(tile) & _dir_table_3[p->ai.cur_dir_a];
+	if (b == 0) return false;
+
+	// Convert into a bit position that CMD_REMOVE_SINGLE_RAIL expects.
+	bit = FindFirstBit(b);
+
+	// Then remove and signals if there are any.
+	if (IsTileType(tile, MP_RAILWAY) &&
+			GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_SIGNALS);
+	}
+
+	// And also remove the rail.
+	if (CmdFailed(DoCommand(tile, 0, bit, DC_EXEC, CMD_REMOVE_SINGLE_RAIL)))
+		return false;
+
+	// Find the direction at the other edge of the rail.
+	ptr = _ai_table_15[p->ai.cur_dir_a ^ 2];
+	while (ptr[0] != bit) ptr += 2;
+	p->ai.cur_dir_a = ptr[1] ^ 2;
+
+	// And then also switch tile.
+	p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a - TileOffsByDiagDir(p->ai.cur_dir_a));
+
+	return true;
+}
+
+
+static void AiBuildRailDestruct(Player *p)
+{
+	// Decrease timeout.
+	if (!--p->ai.state_counter) {
+		p->ai.state_mode = 2;
+		p->ai.state_counter = 0;
+	}
+
+	// Don't do anything if the destination is already reached.
+	if (p->ai.cur_tile_a == p->ai.start_tile_a) return;
+
+	AiRemoveTileAndGoForward(p);
+}
+
+
+static void AiBuildRail(Player *p)
+{
+	switch (p->ai.state_mode) {
+		case 0: // Construct mode, build new rail.
+			AiBuildRailConstruct(p);
+			break;
+
+		case 1: // Destruct mode, destroy the rail currently built.
+			AiBuildRailDestruct(p);
+			break;
+
+		case 2: {
+			uint i;
+
+			// Terraform some and then try building again.
+			for (i = 0; i != 4; i++) {
+				AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
+			}
+
+			if (++p->ai.state_counter == 4) {
+				p->ai.state_counter = 0;
+				p->ai.state_mode = 0;
+			}
+		}
+
+		default: break;
+	}
+}
+
+static void AiStateBuildRail(Player *p)
+{
+	int num;
+	AiBuildRec *aib;
+	byte cmd;
+	TileIndex tile;
+	int dir;
+
+	// time out?
+	if (++p->ai.timeout_counter == 1388) {
+		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
+		return;
+	}
+
+	// Currently building a rail between two points?
+	if (p->ai.state_mode != 255) {
+		AiBuildRail(p);
+
+		// Alternate between edges
+		swap_tile(&p->ai.start_tile_a, &p->ai.start_tile_b);
+		swap_tile(&p->ai.cur_tile_a, &p->ai.cur_tile_b);
+		swap_byte(&p->ai.start_dir_a, &p->ai.start_dir_b);
+		swap_byte(&p->ai.cur_dir_a, &p->ai.cur_dir_b);
+		return;
+	}
+
+	// Now, find two new points to build between
+	num = p->ai.num_build_rec;
+	aib = &p->ai.src;
+
+	for (;;) {
+		cmd = aib->buildcmd_a;
+		aib->buildcmd_a = 255;
+		if (cmd != 255) break;
+
+		cmd = aib->buildcmd_b;
+		aib->buildcmd_b = 255;
+		if (cmd != 255) break;
+
+		aib++;
+		if (--num == 0) {
+			p->ai.state = AIS_BUILD_RAIL_VEH;
+			p->ai.state_counter = 0; // timeout
+			return;
+		}
+	}
+
+	// Find first edge to build from.
+	tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, cmd&3, &dir);
+	p->ai.start_tile_a = tile;
+	p->ai.cur_tile_a = tile;
+	p->ai.start_dir_a = dir;
+	p->ai.cur_dir_a = dir;
+	DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir&1)?1:0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
+
+	assert(TILE_MASK(tile) != 0xFF00);
+
+	// Find second edge to build to
+	aib = (&p->ai.src) + ((cmd >> 4)&0xF);
+	tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, (cmd>>2)&3, &dir);
+	p->ai.start_tile_b = tile;
+	p->ai.cur_tile_b = tile;
+	p->ai.start_dir_b = dir;
+	p->ai.cur_dir_b = dir;
+	DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir&1)?1:0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL);
+
+	assert(TILE_MASK(tile) != 0xFF00);
+
+	// And setup state.
+	p->ai.state_mode = 2;
+	p->ai.state_counter = 0;
+	p->ai.banned_tile_count = 0;
+}
+
+static StationID AiGetStationIdByDef(TileIndex tile, int id)
+{
+	const AiDefaultBlockData *p = _default_rail_track_data[id]->data;
+	while (p->mode != 1) p++;
+	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
+}
+
+static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
+{
+	EngineID best_veh_index = INVALID_ENGINE;
+	EngineID i;
+	uint16 best_capacity = 0;
+	uint16 best_speed    = 0;
+	uint speed;
+
+	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
+		const RailVehicleInfo *rvi = RailVehInfo(i);
+		const Engine* e = GetEngine(i);
+
+		if (!IsCompatibleRail(e->railtype, railtype) ||
+				!(rvi->flags & RVI_WAGON) ||
+				!HASBIT(e->player_avail, _current_player)) {
+			continue;
+		}
+
+		if (rvi->cargo_type != cargo) continue;
+
+		/* max_speed of 0 indicates no speed limit */
+		speed = rvi->max_speed == 0 ? 0xFFFF : rvi->max_speed;
+
+		if (rvi->capacity >= best_capacity && speed >= best_speed) {
+			best_capacity = rvi->capacity;
+			best_speed    = best_speed;
+			best_veh_index = i;
+		}
+	}
+
+	return best_veh_index;
+}
+
+static void AiStateBuildRailVeh(Player *p)
+{
+	const AiDefaultBlockData *ptr;
+	TileIndex tile;
+	EngineID veh;
+	int i;
+	CargoID cargo;
+	int32 cost;
+	Vehicle *v;
+	VehicleID loco_id;
+
+	ptr = _default_rail_track_data[p->ai.src.cur_building_rule]->data;
+	while (ptr->mode != 0) ptr++;
+
+	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
+
+
+	cargo = p->ai.cargo_type;
+	for (i = 0;;) {
+		if (p->ai.wagon_list[i] == INVALID_VEHICLE) {
+			veh = AiFindBestWagon(cargo, p->ai.railtype_to_use);
+			/* veh will return INVALID_ENGINE if no suitable wagon is available.
+			 * We shall treat this in the same way as having no money */
+			if (veh == INVALID_ENGINE) goto handle_nocash;
+			cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
+			if (CmdFailed(cost)) goto handle_nocash;
+			p->ai.wagon_list[i] = _new_vehicle_id;
+			p->ai.wagon_list[i + 1] = INVALID_VEHICLE;
+			return;
+		}
+		if (cargo == CT_MAIL) cargo = CT_PASSENGERS;
+		if (++i == p->ai.num_wagons * 2 - 1) break;
+	}
+
+	// Which locomotive to build?
+	veh = AiChooseTrainToBuild(p->ai.railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile);
+	if (veh == INVALID_ENGINE) {
+handle_nocash:
+		// after a while, if AI still doesn't have cash, get out of this block by selling the wagons.
+		if (++p->ai.state_counter == 1000) {
+			for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
+				cost = DoCommand(tile, p->ai.wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
+				assert(!CmdFailed(cost));
+			}
+			p->ai.state = AIS_0;
+		}
+		return;
+	}
+
+	// Try to build the locomotive
+	cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE);
+	assert(!CmdFailed(cost));
+	loco_id = _new_vehicle_id;
+
+	// Sell a vehicle if the train is double headed.
+	v = GetVehicle(loco_id);
+	if (v->next != NULL) {
+		i = p->ai.wagon_list[p->ai.num_wagons * 2 - 2];
+		p->ai.wagon_list[p->ai.num_wagons * 2 - 2] = INVALID_VEHICLE;
+		DoCommand(tile, i, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
+	}
+
+	// Move the wagons onto the train
+	for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) {
+		DoCommand(tile, p->ai.wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+	}
+
+	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
+		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
+		bool is_pass = (
+			p->ai.cargo_type == CT_PASSENGERS ||
+			p->ai.cargo_type == CT_MAIL ||
+			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
+		);
+		Order order;
+
+		order.type = OT_GOTO_STATION;
+		order.flags = 0;
+		order.dest = AiGetStationIdByDef(aib->use_tile, aib->cur_building_rule);
+
+		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
+		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
+			order.flags |= OF_FULL_LOAD;
+
+		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+	}
+
+	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_TRAIN);
+
+	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+
+	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
+
+	if (--p->ai.num_loco_to_build != 0) {
+//		p->ai.loco_id = INVALID_VEHICLE;
+		p->ai.wagon_list[0] = INVALID_VEHICLE;
+	} else {
+		p->ai.state = AIS_0;
+	}
+}
+
+static void AiStateDeleteRailBlocks(Player *p)
+{
+	const AiBuildRec* aib = &p->ai.src;
+	uint num = p->ai.num_build_rec;
+
+	do {
+		const AiDefaultBlockData* b;
+
+		if (aib->cur_building_rule == 255) continue;
+		for (b = _default_rail_track_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
+			DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		}
+	} while (++aib,--num);
+
+	p->ai.state = AIS_0;
+}
+
+static bool AiCheckRoadResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
+{
+	uint values[NUM_CARGO];
+	int rad;
+
+	if (_patches.modified_catchment) {
+		rad = CA_TRUCK; // Same as CA_BUS at the moment?
+	} else { // change that at some point?
+		rad = 4;
+	}
+
+	for (;; p++) {
+		if (p->mode == 4) {
+			return true;
+		} else if (p->mode == 1) {
+			TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
+
+			if (cargo & 0x80) {
+				GetProductionAroundTiles(values, tile2, 1, 1, rad);
+				return values[cargo & 0x7F] != 0;
+			} else {
+				GetAcceptanceAroundTiles(values, tile2, 1, 1, rad);
+				return (values[cargo]&~7) != 0;
+			}
+		}
+	}
+}
+
+static bool _want_road_truck_station;
+static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag);
+
+// Returns rule and cost
+static int AiFindBestDefaultRoadBlock(TileIndex tile, byte direction, byte cargo, int32 *cost)
+{
+	int i;
+	const AiDefaultRoadBlock *p;
+
+	_want_road_truck_station = (cargo & 0x7F) != CT_PASSENGERS;
+
+	for (i = 0; (p = _road_default_block_data[i]) != NULL; i++) {
+		if (p->dir == direction) {
+			*cost = AiDoBuildDefaultRoadBlock(tile, p->data, 0);
+			if (!CmdFailed(*cost) && AiCheckRoadResources(tile, p->data, cargo))
+				return i;
+		}
+	}
+
+	return -1;
+}
+
+static int32 AiDoBuildDefaultRoadBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
+{
+	int32 ret;
+	int32 total_cost = 0;
+	Town *t = NULL;
+	int rating = 0;
+	int roadflag = 0;
+
+	for (;p->mode != 4;p++) {
+		TileIndex c = TILE_MASK(tile + ToTileIndexDiff(p->tileoffs));
+
+		_cleared_town = NULL;
+
+		if (p->mode == 2) {
+			if (IsTileType(c, MP_STREET) &&
+					GetRoadTileType(c) == ROAD_TILE_NORMAL &&
+					(GetRoadBits(c) & p->attr) != 0) {
+				roadflag |= 2;
+
+				// all bits are already built?
+				if ((GetRoadBits(c) & p->attr) == p->attr) continue;
+			}
+
+			ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
+			if (CmdFailed(ret)) return CMD_ERROR;
+			total_cost += ret;
+
+			continue;
+		}
+
+		if (p->mode == 0) {
+			// Depot
+			ret = DoCommand(c, p->attr, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_DEPOT);
+			goto clear_town_stuff;
+		} else if (p->mode == 1) {
+			if (_want_road_truck_station) {
+				// Truck station
+				ret = DoCommand(c, p->attr, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
+			} else {
+				// Bus station
+				ret = DoCommand(c, p->attr, RS_BUS, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_BUILD_ROAD_STOP);
+			}
+clear_town_stuff:;
+
+			if (CmdFailed(ret)) return CMD_ERROR;
+			total_cost += ret;
+
+			if (_cleared_town != NULL) {
+				if (t != NULL && t != _cleared_town) return CMD_ERROR;
+				t = _cleared_town;
+				rating += _cleared_town_rating;
+			}
+		} else if (p->mode == 3) {
+			if (flag & DC_EXEC) continue;
+
+			if (GetTileSlope(c, NULL) != SLOPE_FLAT) return CMD_ERROR;
+
+			if (!IsTileType(c, MP_STREET) || GetRoadTileType(c) != ROAD_TILE_NORMAL) {
+				ret = DoCommand(c, 0, 0, flag | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, CMD_LANDSCAPE_CLEAR);
+				if (CmdFailed(ret)) return CMD_ERROR;
+			}
+
+		}
+	}
+
+	if (!_want_road_truck_station && !(roadflag & 2)) return CMD_ERROR;
+
+	if (!(flag & DC_EXEC)) {
+		if (t != NULL && rating > t->ratings[_current_player]) return CMD_ERROR;
+	}
+	return total_cost;
+}
+
+// Make sure the blocks are not too close to each other
+static bool AiCheckBlockDistances(Player *p, TileIndex tile)
+{
+	const AiBuildRec* aib = &p->ai.src;
+	uint num = p->ai.num_build_rec;
+
+	do {
+		if (aib->cur_building_rule != 255) {
+			if (DistanceManhattan(aib->use_tile, tile) < 9) return false;
+		}
+	} while (++aib, --num);
+
+	return true;
+}
+
+
+static void AiStateBuildDefaultRoadBlocks(Player *p)
+{
+	uint i;
+	int j;
+	AiBuildRec *aib;
+	int rule;
+	int32 cost;
+
+	// time out?
+	if (++p->ai.timeout_counter == 1388) {
+		p->ai.state = AIS_DELETE_RAIL_BLOCKS;
+		return;
+	}
+
+	// do the following 8 times
+	for (i = 0; i != 8; i++) {
+		// check if we can build the default track
+		aib = &p->ai.src;
+		j = p->ai.num_build_rec;
+		do {
+			// this item has already been built?
+			if (aib->cur_building_rule != 255) continue;
+
+			// adjust the coordinate randomly,
+			// to make sure that we find a position.
+			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
+
+			// check if the road can be built there.
+			rule = AiFindBestDefaultRoadBlock(
+				aib->use_tile, aib->direction, aib->cargo, &cost
+			);
+
+			if (rule == -1) {
+				// cannot build, terraform after a while
+				if (p->ai.state_counter >= 600) {
+					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
+				}
+				// also try the other terraform direction
+				if (++p->ai.state_counter >= 1000) {
+					p->ai.state_counter = 0;
+					p->ai.state_mode = -p->ai.state_mode;
+				}
+			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p,aib->use_tile)) {
+				int32 r;
+
+				// player has money, build it.
+				aib->cur_building_rule = rule;
+
+				r = AiDoBuildDefaultRoadBlock(
+					aib->use_tile,
+					_road_default_block_data[rule]->data,
+					DC_EXEC | DC_NO_TOWN_RATING
+				);
+				assert(!CmdFailed(r));
+			}
+		} while (++aib,--j);
+	}
+
+	// check if we're done with all of them
+	aib = &p->ai.src;
+	j = p->ai.num_build_rec;
+	do {
+		if (aib->cur_building_rule == 255) return;
+	} while (++aib,--j);
+
+	// yep, all are done. switch state to the rail building state.
+	p->ai.state = AIS_BUILD_ROAD;
+	p->ai.state_mode = 255;
+}
+
+typedef struct {
+	TileIndex final_tile;
+	byte final_dir;
+	byte depth;
+	byte recursive_mode;
+	byte cur_best_dir;
+	byte best_dir;
+	byte cur_best_depth;
+	byte best_depth;
+	uint cur_best_dist;
+	const byte *best_ptr;
+	uint best_dist;
+	TileIndex cur_best_tile, best_tile;
+	TileIndex bridge_end_tile;
+	Player *player;
+} AiRoadFinder;
+
+typedef struct AiRoadEnum {
+	TileIndex dest;
+	TileIndex best_tile;
+	int best_track;
+	uint best_dist;
+} AiRoadEnum;
+
+static const byte _dir_by_track[] = {
+	0, 1, 0, 1, 2, 1,
+	0, 0,
+	2, 3, 3, 2, 3, 0,
+};
+
+static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, int dir);
+
+static bool AiCheckRoadPathBetter(AiRoadFinder *arf, const byte *p)
+{
+	bool better = false;
+
+	if (arf->recursive_mode < 1) {
+		// Mode is 0. This means destination has not been found yet.
+		// If the found path is shorter than the current one, remember it.
+		if (arf->cur_best_dist < arf->best_dist ||
+			(arf->cur_best_dist == arf->best_dist && arf->cur_best_depth < arf->best_depth)) {
+			arf->best_depth = arf->cur_best_depth;
+			arf->best_dist = arf->cur_best_dist;
+			arf->best_dir = arf->cur_best_dir;
+			arf->best_ptr = p;
+			arf->best_tile = arf->cur_best_tile;
+			better = true;
+		}
+	} else if (arf->recursive_mode > 1) {
+		// Mode is 2.
+		if (arf->best_dist != 0 || arf->cur_best_depth < arf->best_depth) {
+			arf->best_depth = arf->cur_best_depth;
+			arf->best_dist = 0;
+			arf->best_ptr = p;
+			arf->best_tile = 0;
+			better = true;
+		}
+	}
+	arf->recursive_mode = 0;
+	arf->cur_best_dist = (uint)-1;
+	arf->cur_best_depth = 0xff;
+
+	return better;
+}
+
+
+static bool AiEnumFollowRoad(TileIndex tile, AiRoadEnum *a, int track, uint length, byte *state)
+{
+	uint dist = DistanceManhattan(tile, a->dest);
+
+	if (dist <= a->best_dist) {
+		TileIndex tile2 = TILE_MASK(tile + TileOffsByDiagDir(_dir_by_track[track]));
+
+		if (IsTileType(tile2, MP_STREET) && GetRoadTileType(tile2) == ROAD_TILE_NORMAL) {
+			a->best_dist = dist;
+			a->best_tile = tile;
+			a->best_track = track;
+		}
+	}
+
+	return false;
+}
+
+static const uint16 _ai_road_table_and[4] = {
+	0x1009,
+	0x16,
+	0x520,
+	0x2A00,
+};
+
+static bool AiCheckRoadFinished(Player *p)
+{
+	AiRoadEnum are;
+	TileIndex tile;
+	int dir = p->ai.cur_dir_a;
+	uint32 bits;
+	int i;
+
+	are.dest = p->ai.cur_tile_b;
+	tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(dir));
+
+	if (IsRoadStopTile(tile) || IsTileDepotType(tile, TRANSPORT_ROAD)) return false;
+	bits = GetTileTrackStatus(tile, TRANSPORT_ROAD) & _ai_road_table_and[dir];
+	if (bits == 0) return false;
+
+	are.best_dist = (uint)-1;
+
+	for_each_bit(i, bits) {
+		FollowTrack(tile, 0x3000 | TRANSPORT_ROAD, _dir_by_track[i], (TPFEnumProc*)AiEnumFollowRoad, NULL, &are);
+	}
+
+	if (DistanceManhattan(tile, are.dest) <= are.best_dist) return false;
+
+	if (are.best_dist == 0) return true;
+
+	p->ai.cur_tile_a = are.best_tile;
+	p->ai.cur_dir_a = _dir_by_track[are.best_track];
+	return false;
+}
+
+
+static bool AiBuildRoadHelper(TileIndex tile, int flags, int type)
+{
+	static const RoadBits _road_bits[] = {
+		ROAD_X,
+		ROAD_Y,
+		ROAD_NW | ROAD_NE,
+		ROAD_SW | ROAD_SE,
+		ROAD_NW | ROAD_SW,
+		ROAD_SE | ROAD_NE
+	};
+	return !CmdFailed(DoCommand(tile, _road_bits[type], 0, flags, CMD_BUILD_ROAD));
+}
+
+static inline void AiCheckBuildRoadBridgeHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
+{
+	Slope tileh;
+	uint z;
+	bool flag;
+
+	int dir2 = p[0] & 3;
+
+	tileh = GetTileSlope(tile, &z);
+	if (tileh == _dir_table_1[dir2] || (tileh == SLOPE_FLAT && z != 0)) {
+		TileIndex tile_new = tile;
+
+		// Allow bridges directly over bottom tiles
+		flag = z == 0;
+		for (;;) {
+			TileType type;
+
+			if ((TileIndexDiff)tile_new < -TileOffsByDiagDir(dir2)) return; // Wraping around map, no bridge possible!
+			tile_new = TILE_MASK(tile_new + TileOffsByDiagDir(dir2));
+			type = GetTileType(tile_new);
+
+			if (type == MP_CLEAR || type == MP_TREES || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
+				// Allow a bridge if either we have a tile that's water, rail or street,
+				// or if we found an up tile.
+				if (!flag) return;
+				break;
+			}
+			if (type != MP_WATER && type != MP_RAILWAY && type != MP_STREET) return;
+			flag = true;
+		}
+
+		// Is building a (rail)bridge possible at this place (type doesn't matter)?
+		if (CmdFailed(DoCommand(tile_new, tile, 0x8000, DC_AUTO, CMD_BUILD_BRIDGE)))
+			return;
+		AiBuildRoadRecursive(arf, tile_new, dir2);
+
+		// At the bottom depth, check if the new path is better than the old one.
+		if (arf->depth == 1) {
+			if (AiCheckRoadPathBetter(arf, p)) arf->bridge_end_tile = tile_new;
+		}
+	}
+}
+
+static inline void AiCheckBuildRoadTunnelHere(AiRoadFinder *arf, TileIndex tile, const byte *p)
+{
+	uint z;
+
+	if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) {
+		int32 cost = DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+
+		if (!CmdFailed(cost) && cost <= (arf->player->player_money>>4)) {
+			AiBuildRoadRecursive(arf, _build_tunnel_endtile, p[0]&3);
+			if (arf->depth == 1)  AiCheckRoadPathBetter(arf, p);
+		}
+	}
+}
+
+
+
+static void AiBuildRoadRecursive(AiRoadFinder *arf, TileIndex tile, int dir)
+{
+	const byte *p;
+
+	tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
+
+	// Reached destination?
+	if (tile == arf->final_tile) {
+		if ((arf->final_dir^2) == dir) {
+			arf->recursive_mode = 2;
+			arf->cur_best_depth = arf->depth;
+		}
+		return;
+	}
+
+	// Depth too deep?
+	if (arf->depth >= 4) {
+		uint dist = DistanceMaxPlusManhattan(tile, arf->final_tile);
+		if (dist < arf->cur_best_dist) {
+			// Store the tile that is closest to the final position.
+			arf->cur_best_dist = dist;
+			arf->cur_best_tile = tile;
+			arf->cur_best_dir = dir;
+			arf->cur_best_depth = arf->depth;
+		}
+		return;
+	}
+
+	// Increase recursion depth
+	arf->depth++;
+
+	// Grab pointer to list of stuff that is possible to build
+	p = _ai_table_15[dir];
+
+	// Try to build a single rail in all directions.
+	if (GetTileZ(tile) == 0) {
+		p += 6;
+	} else {
+		do {
+			// Make sure that a road can be built here.
+			if (AiBuildRoadHelper(tile, DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, p[0])) {
+				AiBuildRoadRecursive(arf, tile, p[1]);
+			}
+
+			// At the bottom depth?
+			if (arf->depth == 1) AiCheckRoadPathBetter(arf, p);
+
+			p += 2;
+		} while (!(p[0] & 0x80));
+	}
+
+	AiCheckBuildRoadBridgeHere(arf, tile, p);
+	AiCheckBuildRoadTunnelHere(arf, tile, p+1);
+
+	arf->depth--;
+}
+
+
+static void AiBuildRoadConstruct(Player *p)
+{
+	AiRoadFinder arf;
+	int i;
+	TileIndex tile;
+
+	// Reached destination?
+	if (AiCheckRoadFinished(p)) {
+		p->ai.state_mode = 255;
+		return;
+	}
+
+	// Setup recursive finder and call it.
+	arf.player = p;
+	arf.final_tile = p->ai.cur_tile_b;
+	arf.final_dir = p->ai.cur_dir_b;
+	arf.depth = 0;
+	arf.recursive_mode = 0;
+	arf.best_ptr = NULL;
+	arf.cur_best_dist = (uint)-1;
+	arf.cur_best_depth = 0xff;
+	arf.best_dist = (uint)-1;
+	arf.best_depth =  0xff;
+	arf.cur_best_tile = 0;
+	arf.best_tile = 0;
+	AiBuildRoadRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a);
+
+	// Reached destination?
+	if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) {
+		p->ai.state_mode = 255;
+		return;
+	}
+
+	// Didn't find anything to build?
+	if (arf.best_ptr == NULL) {
+		// Terraform some
+do_some_terraform:
+		for (i = 0; i != 5; i++)
+			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
+
+		if (++p->ai.state_counter == 21) {
+			p->ai.state_mode = 1;
+
+			p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a));
+			p->ai.cur_dir_a ^= 2;
+			p->ai.state_counter = 0;
+		}
+		return;
+	}
+
+	tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a));
+
+	if (arf.best_ptr[0]&0x80) {
+		int i;
+		int32 bridge_len;
+		p->ai.cur_tile_a = arf.bridge_end_tile;
+		bridge_len = GetBridgeLength(tile, p->ai.cur_tile_a); // tile
+
+		/* Figure out what (road)bridge type to build
+		 * start with best bridge, then go down to worse and worse bridges
+		 * unnecessary to check for worse bridge (i=0), since AI will always build that.
+		 *AI is so fucked up that fixing this small thing will probably not solve a thing
+		 */
+		for (i = 10; i != 0; i--) {
+			if (CheckBridge_Stuff(i, bridge_len)) {
+				int32 cost = DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO, CMD_BUILD_BRIDGE);
+				if (!CmdFailed(cost) && cost < (p->player_money >> 5)) break;
+			}
+		}
+
+		// Build it
+		DoCommand(tile, p->ai.cur_tile_a, i + (0x80 << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE);
+
+		p->ai.state_counter = 0;
+	} else if (arf.best_ptr[0]&0x40) {
+		// tunnel
+		DoCommand(tile, 0x200, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL);
+		p->ai.cur_tile_a = _build_tunnel_endtile;
+		p->ai.state_counter = 0;
+	} else {
+		// road
+		if (!AiBuildRoadHelper(tile, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, arf.best_ptr[0]))
+			goto do_some_terraform;
+
+		p->ai.cur_dir_a = arf.best_ptr[1];
+		p->ai.cur_tile_a = tile;
+		p->ai.state_counter = 0;
+	}
+
+	if (arf.best_tile != 0) {
+		for (i = 0; i != 2; i++)
+			AiDoTerraformLand(arf.best_tile, arf.best_dir, 3, 0);
+	}
+}
+
+
+static void AiBuildRoad(Player *p)
+{
+	if (p->ai.state_mode < 1) {
+		// Construct mode, build new road.
+		AiBuildRoadConstruct(p);
+	} else if (p->ai.state_mode == 1) {
+		// Destruct mode, not implemented for roads.
+		p->ai.state_mode = 2;
+		p->ai.state_counter = 0;
+	} else if (p->ai.state_mode == 2) {
+		uint i;
+
+		// Terraform some and then try building again.
+		for (i = 0; i != 4; i++) {
+			AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0);
+		}
+
+		if (++p->ai.state_counter == 4) {
+			p->ai.state_counter = 0;
+			p->ai.state_mode = 0;
+		}
+	}
+}
+
+static TileIndex AiGetRoadBlockEdge(byte rule, TileIndex tile, int *dir)
+{
+	const AiDefaultBlockData *p = _road_default_block_data[rule]->data;
+	while (p->mode != 1) p++;
+	*dir = p->attr;
+	return TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
+}
+
+
+static void AiStateBuildRoad(Player *p)
+{
+	int num;
+	AiBuildRec *aib;
+	byte cmd;
+	TileIndex tile;
+	int dir;
+
+	// time out?
+	if (++p->ai.timeout_counter == 1388) {
+		p->ai.state = AIS_DELETE_ROAD_BLOCKS;
+		return;
+	}
+
+	// Currently building a road between two points?
+	if (p->ai.state_mode != 255) {
+		AiBuildRoad(p);
+
+		// Alternate between edges
+		swap_tile(&p->ai.start_tile_a, &p->ai.start_tile_b);
+		swap_tile(&p->ai.cur_tile_a, &p->ai.cur_tile_b);
+		swap_byte(&p->ai.start_dir_a, &p->ai.start_dir_b);
+		swap_byte(&p->ai.cur_dir_a, &p->ai.cur_dir_b);
+
+		return;
+	}
+
+	// Now, find two new points to build between
+	num = p->ai.num_build_rec;
+	aib = &p->ai.src;
+
+	for (;;) {
+		cmd = aib->buildcmd_a;
+		aib->buildcmd_a = 255;
+		if (cmd != 255) break;
+
+		aib++;
+		if (--num == 0) {
+			p->ai.state = AIS_BUILD_ROAD_VEHICLES;
+			return;
+		}
+	}
+
+	// Find first edge to build from.
+	tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
+	p->ai.start_tile_a = tile;
+	p->ai.cur_tile_a = tile;
+	p->ai.start_dir_a = dir;
+	p->ai.cur_dir_a = dir;
+
+	// Find second edge to build to
+	aib = (&p->ai.src) + (cmd&0xF);
+	tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir);
+	p->ai.start_tile_b = tile;
+	p->ai.cur_tile_b = tile;
+	p->ai.start_dir_b = dir;
+	p->ai.cur_dir_b = dir;
+
+	// And setup state.
+	p->ai.state_mode = 2;
+	p->ai.state_counter = 0;
+	p->ai.banned_tile_count = 0;
+}
+
+static StationID AiGetStationIdFromRoadBlock(TileIndex tile, int id)
+{
+	const AiDefaultBlockData *p = _road_default_block_data[id]->data;
+	while (p->mode != 1) p++;
+	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
+}
+
+static void AiStateBuildRoadVehicles(Player *p)
+{
+	const AiDefaultBlockData *ptr;
+	TileIndex tile;
+	VehicleID loco_id;
+	EngineID veh;
+	uint i;
+
+	ptr = _road_default_block_data[p->ai.src.cur_building_rule]->data;
+	for (; ptr->mode != 0; ptr++) {}
+	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
+
+	veh = AiChooseRoadVehToBuild(p->ai.cargo_type, p->player_money, tile);
+	if (veh == INVALID_ENGINE) {
+		p->ai.state = AIS_0;
+		return;
+	}
+
+	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_ROAD_VEH))) return;
+
+	loco_id = _new_vehicle_id;
+
+	if (GetVehicle(loco_id)->cargo_type != p->ai.cargo_type) {
+		/* Cargo type doesn't match, so refit it */
+		if (CmdFailed(DoCommand(tile, loco_id, p->ai.cargo_type, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
+			/* Refit failed... sell the vehicle */
+			DoCommand(tile, loco_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
+			return;
+		}
+	}
+
+	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
+		const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i];
+		bool is_pass = (
+			p->ai.cargo_type == CT_PASSENGERS ||
+			p->ai.cargo_type == CT_MAIL ||
+			(_opt.landscape == LT_NORMAL && p->ai.cargo_type == CT_VALUABLES)
+		);
+		Order order;
+
+		order.type = OT_GOTO_STATION;
+		order.flags = 0;
+		order.dest = AiGetStationIdFromRoadBlock(aib->use_tile, aib->cur_building_rule);
+
+		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
+		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
+			order.flags |= OF_FULL_LOAD;
+
+		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+	}
+
+	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
+	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+
+	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
+	if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0;
+}
+
+static void AiStateDeleteRoadBlocks(Player *p)
+{
+	const AiBuildRec* aib = &p->ai.src;
+	uint num = p->ai.num_build_rec;
+
+	do {
+		const AiDefaultBlockData* b;
+
+		if (aib->cur_building_rule == 255) continue;
+		for (b = _road_default_block_data[aib->cur_building_rule]->data; b->mode != 4; b++) {
+			if (b->mode > 1) continue;
+			DoCommand(TILE_ADD(aib->use_tile, ToTileIndexDiff(b->tileoffs)), 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		}
+	} while (++aib,--num);
+
+	p->ai.state = AIS_0;
+}
+
+
+static void AiStateAirportStuff(Player *p)
+{
+	const Station* st;
+	byte acc_planes;
+	int i;
+	AiBuildRec *aib;
+	byte rule;
+
+	// Here we look for an airport we could use instead of building a new
+	// one. If we find such an aiport for any waypoint,
+	// AiStateBuildDefaultAirportBlocks() will kindly skip that one when
+	// building the waypoints.
+
+	i = 0;
+	do {
+		// We do this all twice - once for the source (town in the case
+		// of oilrig route) and then for the destination (oilrig in the
+		// case of oilrig route).
+		aib = &p->ai.src + i;
+
+		FOR_ALL_STATIONS(st) {
+			// Is this an airport?
+			if (!(st->facilities & FACIL_AIRPORT)) continue;
+
+			// Do we own the airport? (Oilrigs aren't owned, though.)
+			if (st->owner != OWNER_NONE && st->owner != _current_player) continue;
+
+			acc_planes = GetAirport(st->airport_type)->acc_planes;
+
+			// Dismiss heliports, unless we are checking an oilrig.
+			if (acc_planes == HELICOPTERS_ONLY && (p->ai.build_kind != 1 || i != 1))
+				continue;
+
+			// Dismiss country airports if we are doing the other
+			// endpoint of an oilrig route.
+			if (acc_planes == AIRCRAFT_ONLY && (p->ai.build_kind == 1 && i == 0))
+				continue;
+
+			// Dismiss airports too far away.
+			if (DistanceMax(st->airport_tile, aib->spec_tile) > aib->rand_rng)
+				continue;
+
+			// It's ideal airport, let's take it!
+
+			/* XXX: This part is utterly broken - rule should
+			 * contain number of the rule appropriate for the
+			 * airport type (country, town, ...), see
+			 * _airport_default_block_data (rule is just an index
+			 * in this array). But the only difference between the
+			 * currently existing two rules (rule 0 - town and rule
+			 * 1 - country) is the attr field which is used only
+			 * when building new airports - and that's irrelevant
+			 * for us. So using just about any rule will suffice
+			 * here for now (some of the new airport types would be
+			 * broken because they will probably need different
+			 * tileoff values etc), no matter that
+			 * IsHangarTile() makes no sense. --pasky */
+			if (acc_planes == HELICOPTERS_ONLY) {
+				/* Heliports should have maybe own rulesets but
+				 * OTOH we don't want AI to pick them up when
+				 * looking for a suitable airport type to build.
+				 * So any of rules 0 or 1 would do for now. The
+				 * original rule number was 2 but that's a bug
+				 * because we have no such rule. */
+				rule = 1;
+			} else {
+				rule = IsHangarTile(st->airport_tile);
+			}
+
+			aib->cur_building_rule = rule;
+			aib->use_tile = st->airport_tile;
+			break;
+		}
+	} while (++i != p->ai.num_build_rec);
+
+	p->ai.state = AIS_BUILD_DEFAULT_AIRPORT_BLOCKS;
+	p->ai.state_mode = 255;
+	p->ai.state_counter = 0;
+}
+
+static int32 AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag)
+{
+	int32 total_cost = 0, ret;
+
+	for (; p->mode == 0; p++) {
+		if (!HASBIT(_avail_aircraft, p->attr)) return CMD_ERROR;
+		ret = DoCommand(TILE_MASK(tile + ToTileIndexDiff(p->tileoffs)), p->attr,0,flag | DC_AUTO | DC_NO_WATER,CMD_BUILD_AIRPORT);
+		if (CmdFailed(ret)) return CMD_ERROR;
+		total_cost += ret;
+	}
+
+	return total_cost;
+}
+
+static bool AiCheckAirportResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo)
+{
+	uint values[NUM_CARGO];
+	int rad;
+
+	if (_patches.modified_catchment) {
+		rad = CA_AIR_LARGE; // I Have NFI what airport the
+	} else { // AI is going to build here
+		rad = 4;
+	}
+
+	for (; p->mode == 0; p++) {
+		TileIndex tile2 = TILE_ADD(tile, ToTileIndexDiff(p->tileoffs));
+		const AirportFTAClass* airport = GetAirport(p->attr);
+		uint w = airport->size_x;
+		uint h = airport->size_y;
+
+		if (cargo & 0x80) {
+			GetProductionAroundTiles(values, tile2, w, h, rad);
+			return values[cargo & 0x7F] != 0;
+		} else {
+			GetAcceptanceAroundTiles(values, tile2, w, h, rad);
+			return values[cargo] >= 8;
+		}
+	}
+	return true;
+}
+
+static int AiFindBestDefaultAirportBlock(TileIndex tile, byte cargo, byte heli, int32 *cost)
+{
+	const AiDefaultBlockData *p;
+	uint i;
+
+	for (i = 0; (p = _airport_default_block_data[i]) != NULL; i++) {
+		// If we are doing a helicopter service, avoid building
+		// airports where they can't land.
+		if (heli && GetAirport(p->attr)->acc_planes == AIRCRAFT_ONLY) continue;
+
+		*cost = AiDoBuildDefaultAirportBlock(tile, p, 0);
+		if (!CmdFailed(*cost) && AiCheckAirportResources(tile, p, cargo))
+			return i;
+	}
+	return -1;
+}
+
+static void AiStateBuildDefaultAirportBlocks(Player *p)
+{
+	int i, j;
+	AiBuildRec *aib;
+	int rule;
+	int32 cost;
+
+	// time out?
+	if (++p->ai.timeout_counter == 1388) {
+		p->ai.state = AIS_0;
+		return;
+	}
+
+	// do the following 8 times
+	i = 8;
+	do {
+		// check if we can build the default
+		aib = &p->ai.src;
+		j = p->ai.num_build_rec;
+		do {
+			// this item has already been built?
+			if (aib->cur_building_rule != 255) continue;
+
+			// adjust the coordinate randomly,
+			// to make sure that we find a position.
+			aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng);
+
+			// check if the aircraft stuff can be built there.
+			rule = AiFindBestDefaultAirportBlock(aib->use_tile, aib->cargo, p->ai.build_kind, &cost);
+
+//			SetRedErrorSquare(aib->use_tile);
+
+			if (rule == -1) {
+				// cannot build, terraform after a while
+				if (p->ai.state_counter >= 600) {
+					AiDoTerraformLand(aib->use_tile, Random()&3, 3, (int8)p->ai.state_mode);
+				}
+				// also try the other terraform direction
+				if (++p->ai.state_counter >= 1000) {
+					p->ai.state_counter = 0;
+					p->ai.state_mode = -p->ai.state_mode;
+				}
+			} else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p,aib->use_tile)) {
+				// player has money, build it.
+				int32 r;
+
+				aib->cur_building_rule = rule;
+
+				r = AiDoBuildDefaultAirportBlock(
+					aib->use_tile,
+					_airport_default_block_data[rule],
+					DC_EXEC | DC_NO_TOWN_RATING
+				);
+				assert(!CmdFailed(r));
+			}
+		} while (++aib,--j);
+	} while (--i);
+
+	// check if we're done with all of them
+	aib = &p->ai.src;
+	j = p->ai.num_build_rec;
+	do {
+		if (aib->cur_building_rule == 255) return;
+	} while (++aib,--j);
+
+	// yep, all are done. switch state.
+	p->ai.state = AIS_BUILD_AIRCRAFT_VEHICLES;
+}
+
+static StationID AiGetStationIdFromAircraftBlock(TileIndex tile, int id)
+{
+	const AiDefaultBlockData *p = _airport_default_block_data[id];
+	while (p->mode != 1) p++;
+	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
+}
+
+static void AiStateBuildAircraftVehicles(Player *p)
+{
+	const AiDefaultBlockData *ptr;
+	TileIndex tile;
+	EngineID veh;
+	int i;
+	VehicleID loco_id;
+
+	ptr = _airport_default_block_data[p->ai.src.cur_building_rule];
+	for (; ptr->mode != 0; ptr++) {}
+
+	tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs));
+
+	veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL);
+	if (veh == INVALID_ENGINE) return;
+
+	/* XXX - Have the AI pick the hangar terminal in an airport. Eg get airport-type
+	 * and offset to the FIRST depot because the AI picks the st->xy tile */
+	tile += ToTileIndexDiff(GetAirport(GetStationByTile(tile)->airport_type)->airport_depots[0]);
+	if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) return;
+	loco_id = _new_vehicle_id;
+
+	for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) {
+		AiBuildRec *aib = (&p->ai.src) + p->ai.order_list_blocks[i];
+		bool is_pass = (p->ai.cargo_type == CT_PASSENGERS || p->ai.cargo_type == CT_MAIL);
+		Order order;
+
+		order.type = OT_GOTO_STATION;
+		order.flags = 0;
+		order.dest = AiGetStationIdFromAircraftBlock(aib->use_tile, aib->cur_building_rule);
+
+		if (!is_pass && i == 1) order.flags |= OF_UNLOAD;
+		if (p->ai.num_want_fullload != 0 && (is_pass || i == 0))
+			order.flags |= OF_FULL_LOAD;
+
+		DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+	}
+
+	DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_AIRCRAFT);
+
+	DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT);
+
+	if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--;
+
+	if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0;
+}
+
+static void AiStateCheckShipStuff(Player *p)
+{
+	// XXX
+	error("!AiStateCheckShipStuff");
+}
+
+static void AiStateBuildDefaultShipBlocks(Player *p)
+{
+	// XXX
+	error("!AiStateBuildDefaultShipBlocks");
+}
+
+static void AiStateDoShipStuff(Player *p)
+{
+	// XXX
+	error("!AiStateDoShipStuff");
+}
+
+static void AiStateSellVeh(Player *p)
+{
+	Vehicle *v = p->ai.cur_veh;
+
+	if (v->owner == _current_player) {
+		if (v->type == VEH_Train) {
+
+			if (!IsTileDepotType(v->tile, TRANSPORT_RAIL) || v->u.rail.track != 0x80 || !(v->vehstatus&VS_STOPPED)) {
+				if (v->current_order.type != OT_GOTO_DEPOT)
+					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_TRAIN_TO_DEPOT);
+				goto going_to_depot;
+			}
+
+			// Sell whole train
+			DoCommand(v->tile, v->index, 1, DC_EXEC, CMD_SELL_RAIL_WAGON);
+
+		} else if (v->type == VEH_Road) {
+			if (!IsRoadVehInDepotStopped(v)) {
+				if (v->current_order.type != OT_GOTO_DEPOT)
+					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
+				goto going_to_depot;
+			}
+
+			DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
+		} else if (v->type == VEH_Aircraft) {
+			if (!IsAircraftInHangarStopped(v)) {
+				if (v->current_order.type != OT_GOTO_DEPOT)
+					DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR);
+				goto going_to_depot;
+			}
+
+			DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_AIRCRAFT);
+			} else if (v->type == VEH_Ship) {
+			// XXX: not implemented
+			error("!v->type == VEH_Ship");
+		}
+	}
+
+	goto return_to_loop;
+going_to_depot:;
+	if (++p->ai.state_counter <= 832) return;
+
+	if (v->current_order.type == OT_GOTO_DEPOT) {
+		v->current_order.type = OT_DUMMY;
+		v->current_order.flags = 0;
+		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+	}
+return_to_loop:;
+	p->ai.state = AIS_VEH_LOOP;
+}
+
+static void AiStateRemoveStation(Player *p)
+{
+	// Remove stations that aren't in use by any vehicle
+	byte *in_use;
+	const Order *ord;
+	const Station *st;
+	TileIndex tile;
+
+	// Go to this state when we're done.
+	p->ai.state = AIS_1;
+
+	// Get a list of all stations that are in use by a vehicle
+	in_use = malloc(GetMaxStationIndex() + 1);
+	memset(in_use, 0, GetMaxStationIndex() + 1);
+	FOR_ALL_ORDERS(ord) {
+		if (ord->type == OT_GOTO_STATION) in_use[ord->dest] = 1;
+	}
+
+	// Go through all stations and delete those that aren't in use
+	FOR_ALL_STATIONS(st) {
+		if (st->owner == _current_player && !in_use[st->index] &&
+				( (st->bus_stops != NULL && (tile = st->bus_stops->xy) != 0) ||
+					(st->truck_stops != NULL && (tile = st->truck_stops->xy)) != 0 ||
+					(tile = st->train_tile) != 0 ||
+					(tile = st->dock_tile) != 0 ||
+					(tile = st->airport_tile) != 0)) {
+			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		}
+	}
+
+	free(in_use);
+}
+
+static void AiRemovePlayerRailOrRoad(Player *p, TileIndex tile)
+{
+	TrackBits rails;
+
+	if (IsTileType(tile, MP_RAILWAY)) {
+		if (!IsTileOwner(tile, _current_player)) return;
+
+		if (IsPlainRailTile(tile)) {
+is_rail_crossing:;
+			rails = GetRailTrackStatus(tile);
+
+			if (rails == TRACK_BIT_HORZ || rails == TRACK_BIT_VERT) return;
+
+			if (rails & TRACK_BIT_3WAY_NE) {
+pos_0:
+				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(1, 0))) & TRACK_BIT_3WAY_SW) == 0) {
+					p->ai.cur_dir_a = 0;
+					p->ai.cur_tile_a = tile;
+					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
+					return;
+				}
+			}
+
+			if (rails & TRACK_BIT_3WAY_SE) {
+pos_1:
+				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(0, 1))) & TRACK_BIT_3WAY_NW) == 0) {
+					p->ai.cur_dir_a = 1;
+					p->ai.cur_tile_a = tile;
+					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
+					return;
+				}
+			}
+
+			if (rails & TRACK_BIT_3WAY_SW) {
+pos_2:
+				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(1, 0))) & TRACK_BIT_3WAY_NE) == 0) {
+					p->ai.cur_dir_a = 2;
+					p->ai.cur_tile_a = tile;
+					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
+					return;
+				}
+			}
+
+			if (rails & TRACK_BIT_3WAY_NW) {
+pos_3:
+				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) {
+					p->ai.cur_dir_a = 3;
+					p->ai.cur_tile_a = tile;
+					p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE;
+					return;
+				}
+			}
+		} else {
+			static const byte _depot_bits[] = {0x19,0x16,0x25,0x2A};
+
+			DiagDirection dir = GetRailDepotDirection(tile);
+
+			if (GetRailTrackStatus(tile + TileOffsByDiagDir(dir)) & _depot_bits[dir])
+				return;
+
+			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		}
+	} else if (IsTileType(tile, MP_STREET)) {
+		if (!IsTileOwner(tile, _current_player)) return;
+
+		if (IsLevelCrossing(tile)) goto is_rail_crossing;
+
+		if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) {
+			DiagDirection dir;
+			TileIndex t;
+
+			// Check if there are any stations around.
+			t = tile + TileDiffXY(-1, 0);
+			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
+
+			t = tile + TileDiffXY(1, 0);
+			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
+
+			t = tile + TileDiffXY(0, -1);
+			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
+
+			t = tile + TileDiffXY(0, 1);
+			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
+
+			dir = GetRoadDepotDirection(tile);
+
+			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+			DoCommand(
+				TILE_MASK(tile + TileOffsByDiagDir(dir)),
+				DiagDirToRoadBits(ReverseDiagDir(dir)),
+				0,
+				DC_EXEC,
+				CMD_REMOVE_ROAD);
+		}
+	} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (!IsTileOwner(tile, _current_player) ||
+				!IsBridge(tile) ||
+				GetBridgeTransportType(tile) != TRANSPORT_RAIL) {
+			return;
+		}
+
+		rails = 0;
+
+		switch (GetBridgeRampDirection(tile)) {
+			default:
+			case DIAGDIR_NE: goto pos_2;
+			case DIAGDIR_SE: goto pos_3;
+			case DIAGDIR_SW: goto pos_0;
+			case DIAGDIR_NW: goto pos_1;
+		}
+	}
+}
+
+static void AiStateRemoveTrack(Player *p)
+{
+	/* Was 1000 for standard 8x8 maps. */
+	int num = MapSizeX() * 4;
+
+	do {
+		TileIndex tile = ++p->ai.state_counter;
+
+		// Iterated all tiles?
+		if (tile >= MapSize()) {
+			p->ai.state = AIS_REMOVE_STATION;
+			return;
+		}
+
+		// Remove player stuff in that tile
+		AiRemovePlayerRailOrRoad(p, tile);
+		if (p->ai.state != AIS_REMOVE_TRACK) return;
+	} while (--num);
+}
+
+static void AiStateRemoveSingleRailTile(Player *p)
+{
+	// Remove until we can't remove more.
+	if (!AiRemoveTileAndGoForward(p)) p->ai.state = AIS_REMOVE_TRACK;
+}
+
+static AiStateAction * const _ai_actions[] = {
+	AiCase0,
+	AiCase1,
+	AiStateVehLoop,
+	AiStateCheckReplaceVehicle,
+	AiStateDoReplaceVehicle,
+	AiStateWantNewRoute,
+
+	AiStateBuildDefaultRailBlocks,
+	AiStateBuildRail,
+	AiStateBuildRailVeh,
+	AiStateDeleteRailBlocks,
+
+	AiStateBuildDefaultRoadBlocks,
+	AiStateBuildRoad,
+	AiStateBuildRoadVehicles,
+	AiStateDeleteRoadBlocks,
+
+	AiStateAirportStuff,
+	AiStateBuildDefaultAirportBlocks,
+	AiStateBuildAircraftVehicles,
+
+	AiStateCheckShipStuff,
+	AiStateBuildDefaultShipBlocks,
+	AiStateDoShipStuff,
+
+	AiStateSellVeh,
+	AiStateRemoveStation,
+	AiStateRemoveTrack,
+
+	AiStateRemoveSingleRailTile
+};
+
+extern void ShowBuyCompanyDialog(uint player);
+
+static void AiHandleTakeover(Player *p)
+{
+	if (p->bankrupt_timeout != 0) {
+		p->bankrupt_timeout -= 8;
+		if (p->bankrupt_timeout > 0) return;
+		p->bankrupt_timeout = 0;
+		DeleteWindowById(WC_BUY_COMPANY, _current_player);
+		if (IsLocalPlayer()) {
+			AskExitToGameMenu();
+			return;
+		}
+		if (IsHumanPlayer(_current_player)) return;
+	}
+
+	if (p->bankrupt_asked == 255) return;
+
+	{
+		uint asked = p->bankrupt_asked;
+		Player *pp, *best_pl = NULL;
+		int32 best_val = -1;
+		uint old_p;
+
+		// Ask the guy with the highest performance hist.
+		FOR_ALL_PLAYERS(pp) {
+			if (pp->is_active &&
+					!(asked&1) &&
+					pp->bankrupt_asked == 0 &&
+					best_val < pp->old_economy[1].performance_history) {
+				best_val = pp->old_economy[1].performance_history;
+				best_pl = pp;
+			}
+			asked>>=1;
+		}
+
+		// Asked all players?
+		if (best_val == -1) {
+			p->bankrupt_asked = 255;
+			return;
+		}
+
+		SETBIT(p->bankrupt_asked, best_pl->index);
+
+		if (best_pl->index == _local_player) {
+			p->bankrupt_timeout = 4440;
+			ShowBuyCompanyDialog(_current_player);
+			return;
+		}
+		if (IsHumanPlayer(best_pl->index)) return;
+
+		// Too little money for computer to buy it?
+		if (best_pl->player_money >> 1 >= p->bankrupt_value) {
+			// Computer wants to buy it.
+			old_p = _current_player;
+			_current_player = p->index;
+			DoCommand(0, old_p, 0, DC_EXEC, CMD_BUY_COMPANY);
+			_current_player = old_p;
+		}
+	}
+}
+
+static void AiAdjustLoan(const Player* p)
+{
+	int32 base = AiGetBasePrice(p);
+
+	if (p->player_money > base * 1400) {
+		// Decrease loan
+		if (p->current_loan != 0) {
+			DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN);
+		}
+	} else if (p->player_money < base * 500) {
+		// Increase loan
+		if (p->current_loan < _economy.max_loan &&
+				p->num_valid_stat_ent >= 2 &&
+				-(p->old_economy[0].expenses+p->old_economy[1].expenses) < base * 60) {
+			DoCommand(0, 0, 0, DC_EXEC, CMD_INCREASE_LOAN);
+		}
+	}
+}
+
+static void AiBuildCompanyHQ(Player *p)
+{
+	TileIndex tile;
+
+	if (p->location_of_house == 0 &&
+			p->last_build_coordinate != 0) {
+		tile = AdjustTileCoordRandomly(p->last_build_coordinate, 8);
+		DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
+	}
+}
+
+
+void AiDoGameLoop(Player *p)
+{
+	if (p->bankrupt_asked != 0) {
+		AiHandleTakeover(p);
+		return;
+	}
+
+	// Ugly hack to make sure the service interval of the AI is good, not looking
+	//  to the patch-setting
+	// Also, it takes into account the setting if the service-interval is in days
+	//  or in %
+	_ai_service_interval = _patches.servint_ispercent?80:180;
+
+	if (IsHumanPlayer(_current_player)) return;
+
+	AiAdjustLoan(p);
+	AiBuildCompanyHQ(p);
+
+#if 0
+	{
+		static byte old_state = 99;
+		static bool hasdots = false;
+		char *_ai_state_names[]={
+			"AiCase0",
+			"AiCase1",
+			"AiStateVehLoop",
+			"AiStateCheckReplaceVehicle",
+			"AiStateDoReplaceVehicle",
+			"AiStateWantNewRoute",
+			"AiStateBuildDefaultRailBlocks",
+			"AiStateBuildRail",
+			"AiStateBuildRailVeh",
+			"AiStateDeleteRailBlocks",
+			"AiStateBuildDefaultRoadBlocks",
+			"AiStateBuildRoad",
+			"AiStateBuildRoadVehicles",
+			"AiStateDeleteRoadBlocks",
+			"AiStateAirportStuff",
+			"AiStateBuildDefaultAirportBlocks",
+			"AiStateBuildAircraftVehicles",
+			"AiStateCheckShipStuff",
+			"AiStateBuildDefaultShipBlocks",
+			"AiStateDoShipStuff",
+			"AiStateSellVeh",
+			"AiStateRemoveStation",
+			"AiStateRemoveTrack",
+			"AiStateRemoveSingleRailTile"
+		};
+
+		if (p->ai.state != old_state) {
+			if (hasdots)
+				printf("\n");
+			hasdots=false;
+			printf("AiState: %s\n", _ai_state_names[old_state=p->ai.state]);
+		} else {
+			printf(".");
+			hasdots=true;
+		}
+	}
+#endif
+
+	_ai_actions[p->ai.state](p);
+}
deleted file mode 100644
--- a/src/ai/trolly/build.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/* $Id$ */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../debug.h"
-#include "../../functions.h"
-#include "../../map.h"
-#include "../../road_map.h"
-#include "../../tile.h"
-#include "../../vehicle.h"
-#include "../../command.h"
-#include "trolly.h"
-#include "../../engine.h"
-#include "../../station.h"
-#include "../../variables.h"
-#include "../../bridge.h"
-#include "../ai.h"
-
-// Build HQ
-//  Params:
-//    tile : tile where HQ is going to be build
-bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile)
-{
-	if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ)))
-		return false;
-	AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
-	return true;
-}
-
-
-// Build station
-//  Params:
-//    type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
-//    tile : tile where station is going to be build
-//    length : in case of AI_TRAIN: length of station
-//    numtracks : in case of AI_TRAIN: tracks of station
-//    direction : the direction of the station
-//    flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
-int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag)
-{
-	if (type == AI_TRAIN)
-		return AI_DoCommand(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
-
-	if (type == AI_BUS)
-		return AI_DoCommand(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
-
-	return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
-}
-
-
-// Builds a brdige. The second best out of the ones available for this player
-//  Params:
-//   tile_a : starting point
-//   tile_b : end point
-//   flag : flag passed to DoCommand
-int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag)
-{
-	int bridge_type, bridge_len, type, type2;
-
-	// Find a good bridgetype (the best money can buy)
-	bridge_len = GetBridgeLength(tile_a, tile_b);
-	type = type2 = 0;
-	for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
-		if (CheckBridge_Stuff(bridge_type, bridge_len)) {
-			type2 = type;
-			type = bridge_type;
-			// We found two bridges, exit
-			if (type2 != 0) break;
-		}
-	}
-	// There is only one bridge that can be built
-	if (type2 == 0 && type != 0) type2 = type;
-
-	// Now, simply, build the bridge!
-	if (p->ainew.tbt == AI_TRAIN) {
-		return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
-	} else {
-		return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
-	}
-}
-
-
-// Build the route part by part
-// Basicly what this function do, is build that amount of parts of the route
-//  that go in the same direction. It sets 'part' to the last part of the route builded.
-//  The return value is the cost for the builded parts
-//
-//  Params:
-//   PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
-//   part : Which part we need to build
-//
-// TODO: skip already builded road-pieces (e.g.: cityroad)
-int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag)
-{
-	int part = PathFinderInfo->position;
-	byte *route_extra = PathFinderInfo->route_extra;
-	TileIndex *route = PathFinderInfo->route;
-	int dir;
-	int old_dir = -1;
-	int cost = 0;
-	int res;
-	// We need to calculate the direction with the parent of the parent.. so we skip
-	//  the first pieces and the last piece
-	if (part < 1) part = 1;
-	// When we are done, stop it
-	if (part >= PathFinderInfo->route_length - 1) {
-		PathFinderInfo->position = -2;
-		return 0;
-	}
-
-
-	if (PathFinderInfo->rail_or_road) {
-		// Tunnel code
-		if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
-			cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
-			PathFinderInfo->position++;
-			// TODO: problems!
-			if (CmdFailed(cost)) {
-				DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]);
-				return 0;
-			}
-			return cost;
-		}
-		// Bridge code
-		if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
-			cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
-			PathFinderInfo->position++;
-			// TODO: problems!
-			if (CmdFailed(cost)) {
-				DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part - 1]);
-				return 0;
-			}
-			return cost;
-		}
-
-		// Build normal rail
-		// Keep it doing till we go an other way
-		if (route_extra[part - 1] == 0 && route_extra[part] == 0) {
-			while (route_extra[part] == 0) {
-				// Get the current direction
-				dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
-				// Is it the same as the last one?
-				if (old_dir != -1 && old_dir != dir) break;
-				old_dir = dir;
-				// Build the tile
-				res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
-				if (CmdFailed(res)) {
-					// Problem.. let's just abort it all!
-					p->ainew.state = AI_STATE_NOTHING;
-					return 0;
-				}
-				cost += res;
-				// Go to the next tile
-				part++;
-				// Check if it is still in range..
-				if (part >= PathFinderInfo->route_length - 1) break;
-			}
-			part--;
-		}
-		// We want to return the last position, so we go back one
-		PathFinderInfo->position = part;
-	} else {
-		// Tunnel code
-		if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
-			cost += AI_DoCommand(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
-			PathFinderInfo->position++;
-			// TODO: problems!
-			if (CmdFailed(cost)) {
-				DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]);
-				return 0;
-			}
-			return cost;
-		}
-		// Bridge code
-		if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
-			cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
-			PathFinderInfo->position++;
-			// TODO: problems!
-			if (CmdFailed(cost)) {
-				DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part + 1]);
-				return 0;
-			}
-			return cost;
-		}
-
-		// Build normal road
-		// Keep it doing till we go an other way
-		// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
-		//  it will wait till the vehicle is gone..
-		if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
-			while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
-				// Get the current direction
-				dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
-				// Is it the same as the last one?
-				if (old_dir != -1 && old_dir != dir) break;
-				old_dir = dir;
-				// There is already some road, and it is a bridge.. don't build!!!
-				if (!IsTileType(route[part], MP_TUNNELBRIDGE)) {
-					// Build the tile
-					res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
-					// Currently, we ignore CMD_ERRORs!
-					if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
-						// Problem.. let's just abort it all!
-						DEBUG(ai, 0, "[BuidPath] route building failed at tile 0x%X, aborting", route[part]);
-						p->ainew.state = AI_STATE_NOTHING;
-						return 0;
-					}
-
-					if (!CmdFailed(res)) cost += res;
-				}
-				// Go to the next tile
-				part++;
-				// Check if it is still in range..
-				if (part >= PathFinderInfo->route_length - 1) break;
-			}
-			part--;
-			// We want to return the last position, so we go back one
-		}
-		if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
-		PathFinderInfo->position = part;
-	}
-
-	return cost;
-}
-
-
-// This functions tries to find the best vehicle for this type of cargo
-// It returns INVALID_ENGINE if not suitable engine is found
-EngineID AiNew_PickVehicle(Player *p)
-{
-	if (p->ainew.tbt == AI_TRAIN) {
-		// Not supported yet
-		return INVALID_ENGINE;
-	} else {
-		EngineID best_veh_index = INVALID_ENGINE;
-		int32 best_veh_rating = 0;
-		EngineID start = ROAD_ENGINES_INDEX;
-		EngineID end   = ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES;
-		EngineID i;
-
-		/* Loop through all road vehicles */
-		for (i = start; i != end; i++) {
-			const RoadVehicleInfo *rvi = RoadVehInfo(i);
-			const Engine* e = GetEngine(i);
-			int32 rating;
-			int32 ret;
-
-			/* Skip vehicles which can't take our cargo type */
-			if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue;
-
-			// Is it availiable?
-			// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
-			if (!HASBIT(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
-
-			/* Rate and compare the engine by speed & capacity */
-			rating = rvi->max_speed * rvi->capacity;
-			if (rating <= best_veh_rating) continue;
-
-			// Can we build it?
-			ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
-			if (CmdFailed(ret)) continue;
-
-			best_veh_rating = rating;
-			best_veh_index = i;
-		}
-
-		return best_veh_index;
-	}
-}
-
-
-void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	Player* p = GetPlayer(_current_player);
-
-	if (success) {
-		p->ainew.state = AI_STATE_GIVE_ORDERS;
-		p->ainew.veh_id = _new_vehicle_id;
-
-		if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) {
-			/* Cargo type doesn't match, so refit it */
-			if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
-				/* Refit failed, so sell the vehicle */
-				DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
-				p->ainew.state = AI_STATE_NOTHING;
-			}
-		}
-	} else {
-		/* XXX this should be handled more gracefully */
-		p->ainew.state = AI_STATE_NOTHING;
-	}
-}
-
-
-// Builds the best vehicle possible
-int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
-{
-	EngineID i = AiNew_PickVehicle(p);
-
-	if (i == INVALID_ENGINE) return CMD_ERROR;
-	if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
-
-	if (flag & DC_EXEC) {
-		return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI);
-	} else {
-		return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
-	}
-}
-
-int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
-{
-	int ret, ret2;
-	if (p->ainew.tbt == AI_TRAIN) {
-		return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
-	} else {
-		ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
-		if (CmdFailed(ret)) return ret;
-		// Try to build the road from the depot
-		ret2 = AI_DoCommand(tile + TileOffsByDiagDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
-		// If it fails, ignore it..
-		if (CmdFailed(ret2)) return ret;
-		return ret + ret2;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/trolly/build.cpp
@@ -0,0 +1,324 @@
+/* $Id$ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../debug.h"
+#include "../../functions.h"
+#include "../../map.h"
+#include "../../road_map.h"
+#include "../../tile.h"
+#include "../../vehicle.h"
+#include "../../command.h"
+#include "trolly.h"
+#include "../../engine.h"
+#include "../../station.h"
+#include "../../variables.h"
+#include "../../bridge.h"
+#include "../ai.h"
+
+// Build HQ
+//  Params:
+//    tile : tile where HQ is going to be build
+bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile)
+{
+	if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ)))
+		return false;
+	AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
+	return true;
+}
+
+
+// Build station
+//  Params:
+//    type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
+//    tile : tile where station is going to be build
+//    length : in case of AI_TRAIN: length of station
+//    numtracks : in case of AI_TRAIN: tracks of station
+//    direction : the direction of the station
+//    flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
+int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag)
+{
+	if (type == AI_TRAIN)
+		return AI_DoCommand(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
+
+	if (type == AI_BUS)
+		return AI_DoCommand(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
+
+	return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
+}
+
+
+// Builds a brdige. The second best out of the ones available for this player
+//  Params:
+//   tile_a : starting point
+//   tile_b : end point
+//   flag : flag passed to DoCommand
+int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag)
+{
+	int bridge_type, bridge_len, type, type2;
+
+	// Find a good bridgetype (the best money can buy)
+	bridge_len = GetBridgeLength(tile_a, tile_b);
+	type = type2 = 0;
+	for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
+		if (CheckBridge_Stuff(bridge_type, bridge_len)) {
+			type2 = type;
+			type = bridge_type;
+			// We found two bridges, exit
+			if (type2 != 0) break;
+		}
+	}
+	// There is only one bridge that can be built
+	if (type2 == 0 && type != 0) type2 = type;
+
+	// Now, simply, build the bridge!
+	if (p->ainew.tbt == AI_TRAIN) {
+		return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
+	} else {
+		return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
+	}
+}
+
+
+// Build the route part by part
+// Basicly what this function do, is build that amount of parts of the route
+//  that go in the same direction. It sets 'part' to the last part of the route builded.
+//  The return value is the cost for the builded parts
+//
+//  Params:
+//   PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
+//   part : Which part we need to build
+//
+// TODO: skip already builded road-pieces (e.g.: cityroad)
+int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag)
+{
+	int part = PathFinderInfo->position;
+	byte *route_extra = PathFinderInfo->route_extra;
+	TileIndex *route = PathFinderInfo->route;
+	int dir;
+	int old_dir = -1;
+	int cost = 0;
+	int res;
+	// We need to calculate the direction with the parent of the parent.. so we skip
+	//  the first pieces and the last piece
+	if (part < 1) part = 1;
+	// When we are done, stop it
+	if (part >= PathFinderInfo->route_length - 1) {
+		PathFinderInfo->position = -2;
+		return 0;
+	}
+
+
+	if (PathFinderInfo->rail_or_road) {
+		// Tunnel code
+		if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
+			cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
+			PathFinderInfo->position++;
+			// TODO: problems!
+			if (CmdFailed(cost)) {
+				DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]);
+				return 0;
+			}
+			return cost;
+		}
+		// Bridge code
+		if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
+			cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
+			PathFinderInfo->position++;
+			// TODO: problems!
+			if (CmdFailed(cost)) {
+				DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part - 1]);
+				return 0;
+			}
+			return cost;
+		}
+
+		// Build normal rail
+		// Keep it doing till we go an other way
+		if (route_extra[part - 1] == 0 && route_extra[part] == 0) {
+			while (route_extra[part] == 0) {
+				// Get the current direction
+				dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
+				// Is it the same as the last one?
+				if (old_dir != -1 && old_dir != dir) break;
+				old_dir = dir;
+				// Build the tile
+				res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
+				if (CmdFailed(res)) {
+					// Problem.. let's just abort it all!
+					p->ainew.state = AI_STATE_NOTHING;
+					return 0;
+				}
+				cost += res;
+				// Go to the next tile
+				part++;
+				// Check if it is still in range..
+				if (part >= PathFinderInfo->route_length - 1) break;
+			}
+			part--;
+		}
+		// We want to return the last position, so we go back one
+		PathFinderInfo->position = part;
+	} else {
+		// Tunnel code
+		if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
+			cost += AI_DoCommand(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
+			PathFinderInfo->position++;
+			// TODO: problems!
+			if (CmdFailed(cost)) {
+				DEBUG(ai, 0, "[BuildPath] tunnel could not be built (0x%X)", route[part]);
+				return 0;
+			}
+			return cost;
+		}
+		// Bridge code
+		if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
+			cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
+			PathFinderInfo->position++;
+			// TODO: problems!
+			if (CmdFailed(cost)) {
+				DEBUG(ai, 0, "[BuildPath] bridge could not be built (0x%X, 0x%X)", route[part], route[part + 1]);
+				return 0;
+			}
+			return cost;
+		}
+
+		// Build normal road
+		// Keep it doing till we go an other way
+		// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
+		//  it will wait till the vehicle is gone..
+		if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
+			while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
+				// Get the current direction
+				dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
+				// Is it the same as the last one?
+				if (old_dir != -1 && old_dir != dir) break;
+				old_dir = dir;
+				// There is already some road, and it is a bridge.. don't build!!!
+				if (!IsTileType(route[part], MP_TUNNELBRIDGE)) {
+					// Build the tile
+					res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
+					// Currently, we ignore CMD_ERRORs!
+					if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
+						// Problem.. let's just abort it all!
+						DEBUG(ai, 0, "[BuidPath] route building failed at tile 0x%X, aborting", route[part]);
+						p->ainew.state = AI_STATE_NOTHING;
+						return 0;
+					}
+
+					if (!CmdFailed(res)) cost += res;
+				}
+				// Go to the next tile
+				part++;
+				// Check if it is still in range..
+				if (part >= PathFinderInfo->route_length - 1) break;
+			}
+			part--;
+			// We want to return the last position, so we go back one
+		}
+		if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
+		PathFinderInfo->position = part;
+	}
+
+	return cost;
+}
+
+
+// This functions tries to find the best vehicle for this type of cargo
+// It returns INVALID_ENGINE if not suitable engine is found
+EngineID AiNew_PickVehicle(Player *p)
+{
+	if (p->ainew.tbt == AI_TRAIN) {
+		// Not supported yet
+		return INVALID_ENGINE;
+	} else {
+		EngineID best_veh_index = INVALID_ENGINE;
+		int32 best_veh_rating = 0;
+		EngineID start = ROAD_ENGINES_INDEX;
+		EngineID end   = ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES;
+		EngineID i;
+
+		/* Loop through all road vehicles */
+		for (i = start; i != end; i++) {
+			const RoadVehicleInfo *rvi = RoadVehInfo(i);
+			const Engine* e = GetEngine(i);
+			int32 rating;
+			int32 ret;
+
+			/* Skip vehicles which can't take our cargo type */
+			if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue;
+
+			// Is it availiable?
+			// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
+			if (!HASBIT(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
+
+			/* Rate and compare the engine by speed & capacity */
+			rating = rvi->max_speed * rvi->capacity;
+			if (rating <= best_veh_rating) continue;
+
+			// Can we build it?
+			ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
+			if (CmdFailed(ret)) continue;
+
+			best_veh_rating = rating;
+			best_veh_index = i;
+		}
+
+		return best_veh_index;
+	}
+}
+
+
+void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	Player* p = GetPlayer(_current_player);
+
+	if (success) {
+		p->ainew.state = AI_STATE_GIVE_ORDERS;
+		p->ainew.veh_id = _new_vehicle_id;
+
+		if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) {
+			/* Cargo type doesn't match, so refit it */
+			if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
+				/* Refit failed, so sell the vehicle */
+				DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
+				p->ainew.state = AI_STATE_NOTHING;
+			}
+		}
+	} else {
+		/* XXX this should be handled more gracefully */
+		p->ainew.state = AI_STATE_NOTHING;
+	}
+}
+
+
+// Builds the best vehicle possible
+int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
+{
+	EngineID i = AiNew_PickVehicle(p);
+
+	if (i == INVALID_ENGINE) return CMD_ERROR;
+	if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
+
+	if (flag & DC_EXEC) {
+		return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI);
+	} else {
+		return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
+	}
+}
+
+int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
+{
+	int ret, ret2;
+	if (p->ainew.tbt == AI_TRAIN) {
+		return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
+	} else {
+		ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
+		if (CmdFailed(ret)) return ret;
+		// Try to build the road from the depot
+		ret2 = AI_DoCommand(tile + TileOffsByDiagDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
+		// If it fails, ignore it..
+		if (CmdFailed(ret2)) return ret;
+		return ret + ret2;
+	}
+}
deleted file mode 100644
--- a/src/ai/trolly/pathfinder.c
+++ /dev/null
@@ -1,510 +0,0 @@
-/* $Id$ */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../bridge_map.h"
-#include "../../debug.h"
-#include "../../functions.h"
-#include "../../map.h"
-#include "../../tile.h"
-#include "../../command.h"
-#include "trolly.h"
-#include "../../depot.h"
-#include "../../tunnel_map.h"
-#include "../../bridge.h"
-#include "../ai.h"
-
-#define TEST_STATION_NO_DIR 0xFF
-
-// Tests if a station can be build on the given spot
-// TODO: make it train compatible
-static bool TestCanBuildStationHere(TileIndex tile, byte dir)
-{
-	Player *p = GetPlayer(_current_player);
-
-	if (dir == TEST_STATION_NO_DIR) {
-		int32 ret;
-		// TODO: currently we only allow spots that can be access from al 4 directions...
-		//  should be fixed!!!
-		for (dir = 0; dir < 4; dir++) {
-			ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
-			if (!CmdFailed(ret)) return true;
-		}
-		return false;
-	}
-
-	// return true if command succeeded, so the inverse of CmdFailed()
-	return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
-}
-
-
-static bool IsRoad(TileIndex tile)
-{
-	return
-		// MP_STREET, but not a road depot?
-		(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
-		(IsTileType(tile, MP_TUNNELBRIDGE) && (
-			(IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) ||
-			(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD)
-		));
-}
-
-
-// Checks if a tile 'a' is between the tiles 'b' and 'c'
-#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
-
-
-// Check if the current tile is in our end-area
-static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
-{
-	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
-
-	// It is not allowed to have a station on the end of a bridge or tunnel ;)
-	if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
-	if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
-		if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
-			if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile, AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
-				return AYSTAR_FOUND_END_NODE;
-
-	return AYSTAR_DONE;
-}
-
-
-// Calculates the hash
-//   Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
-static uint AiPathFinder_Hash(uint key1, uint key2)
-{
-	return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
-}
-
-
-// Clear the memory of all the things
-static void AyStar_AiPathFinder_Free(AyStar *aystar)
-{
-	AyStarMain_Free(aystar);
-	free(aystar);
-}
-
-
-static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
-static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
-static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
-static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
-
-
-// This creates the AiPathFinder
-AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo)
-{
-	PathNode start_node;
-	uint x;
-	uint y;
-	// Create AyStar
-	AyStar *result = malloc(sizeof(AyStar));
-	init_AyStar(result, AiPathFinder_Hash, 1 << 10);
-	// Set the function pointers
-	result->CalculateG = AyStar_AiPathFinder_CalculateG;
-	result->CalculateH = AyStar_AiPathFinder_CalculateH;
-	result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
-	result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
-	result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
-
-	result->free = AyStar_AiPathFinder_Free;
-
-	// Set some information
-	result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
-	result->max_path_cost = 0;
-	result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
-
-	// Set the user_data to the PathFinderInfo
-	result->user_target = PathFinderInfo;
-
-	// Set the start node
-	start_node.parent = NULL;
-	start_node.node.direction = 0;
-	start_node.node.user_data[0] = 0;
-
-	// Now we add all the starting tiles
-	for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
-		for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
-			start_node.node.tile = TileXY(x, y);
-			result->addstart(result, &start_node.node, 0);
-		}
-	}
-
-	return result;
-}
-
-
-// To reuse AyStar we sometimes have to clean all the memory
-void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo)
-{
-	PathNode start_node;
-	uint x;
-	uint y;
-
-	aystar->clear(aystar);
-
-	// Set the user_data to the PathFinderInfo
-	aystar->user_target = PathFinderInfo;
-
-	// Set the start node
-	start_node.parent = NULL;
-	start_node.node.direction = 0;
-	start_node.node.user_data[0] = 0;
-	start_node.node.tile = PathFinderInfo->start_tile_tl;
-
-	// Now we add all the starting tiles
-	for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
-		for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
-			TileIndex tile = TileXY(x, y);
-
-			if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) continue;
-			if (!TestCanBuildStationHere(tile, TEST_STATION_NO_DIR)) continue;
-			start_node.node.tile = tile;
-			aystar->addstart(aystar, &start_node.node, 0);
-		}
-	}
-}
-
-
-// The h-value, simple calculation
-static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
-{
-	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
-	int r, r2;
-
-	if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
-		// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
-		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDiagDir(PathFinderInfo->end_direction));
-		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDiagDir(PathFinderInfo->end_direction));
-	} else {
-		// No direction, so just get the fastest route to the station
-		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
-		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br);
-	}
-	// See if the bottomright is faster than the topleft..
-	if (r2 < r) r = r2;
-	return r * AI_PATHFINDER_H_MULTIPLER;
-}
-
-
-// We found the end.. let's get the route back and put it in an array
-static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current)
-{
-	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
-	uint i = 0;
-	PathNode *parent = &current->path;
-
-	do {
-		PathFinderInfo->route_extra[i] = parent->node.user_data[0];
-		PathFinderInfo->route[i++] = parent->node.tile;
-		if (i > lengthof(PathFinderInfo->route)) {
-			// We ran out of space for the PathFinder
-			DEBUG(ai, 0, "No more space in pathfinder route[] array");
-			PathFinderInfo->route_length = -1; // -1 indicates out of space
-			return;
-		}
-		parent = parent->parent;
-	} while (parent != NULL);
-	PathFinderInfo->route_length = i;
-	DEBUG(ai, 1, "Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash));
-}
-
-
-// What tiles are around us.
-static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current)
-{
-	uint i;
-	int ret;
-	int dir;
-
-	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
-
-	aystar->num_neighbours = 0;
-
-	// Go through all surrounding tiles and check if they are within the limits
-	for (i = 0; i < 4; i++) {
-		TileIndex ctile = current->path.node.tile; // Current tile
-		TileIndex atile = ctile + TileOffsByDiagDir(i); // Adjacent tile
-
-		if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 &&
-				TileY(atile) > 1 && TileY(atile) < MapMaxY() - 1) {
-			// We also directly test if the current tile can connect to this tile..
-			//  We do this simply by just building the tile!
-
-			// If the next step is a bridge, we have to enter it the right way
-			if (!PathFinderInfo->rail_or_road && IsRoad(atile)) {
-				if (IsTileType(atile, MP_TUNNELBRIDGE)) {
-					if (IsTunnel(atile)) {
-						if (GetTunnelDirection(atile) != i) continue;
-					} else {
-						if ((_m[atile].m5 & 1U) != DiagDirToAxis(i)) continue;
-					}
-				}
-			}
-			// But also if we are on a bridge, we can only move a certain direction
-			if (!PathFinderInfo->rail_or_road && IsRoad(ctile)) {
-				if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
-					// An existing bridge/tunnel... let's test the direction ;)
-					if ((_m[ctile].m5 & 1U) != (i & 1)) continue;
-				}
-			}
-
-			if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
-					(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
-				// We are a bridge/tunnel, how cool!!
-				//  This means we can only point forward.. get the direction from the user_data
-				if (i != (current->path.node.user_data[0] >> 8)) continue;
-			}
-			dir = 0;
-
-			// First, check if we have a parent
-			if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
-				// If not, this means we are at the starting station
-				if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
-					// We do need a direction?
-					if (AiNew_GetDirection(ctile, atile) != PathFinderInfo->start_direction) {
-						// We are not pointing the right way, invalid tile
-						continue;
-					}
-				}
-			} else if (current->path.node.user_data[0] == 0) {
-				if (PathFinderInfo->rail_or_road) {
-					// Rail check
-					dir = AiNew_GetRailDirection(current->path.parent->node.tile, ctile, atile);
-					ret = AI_DoCommand(ctile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
-					if (CmdFailed(ret)) continue;
-#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
-					if (current->path.parent->parent != NULL) {
-						// Check if we don't make a 90degree curve
-						int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, ctile);
-						if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
-							continue;
-						}
-					}
-#endif
-				} else {
-					// Road check
-					dir = AiNew_GetRoadDirection(current->path.parent->node.tile, ctile, atile);
-					if (IsRoad(ctile)) {
-						if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
-							// We have a bridge, how nicely! We should mark it...
-							dir = 0;
-						} else {
-							// It already has road.. check if we miss any bits!
-							if ((_m[ctile].m5 & dir) != dir) {
-								// We do miss some pieces :(
-								dir &= ~_m[ctile].m5;
-							} else {
-								dir = 0;
-							}
-						}
-					}
-					// Only destruct things if it is MP_CLEAR of MP_TREES
-					if (dir != 0) {
-						ret = AI_DoCommand(ctile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
-						if (CmdFailed(ret)) continue;
-					}
-				}
-			}
-
-			// The tile can be connected
-			aystar->neighbours[aystar->num_neighbours].tile = atile;
-			aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
-			aystar->neighbours[aystar->num_neighbours++].direction = 0;
-		}
-	}
-
-	// Next step, check for bridges and tunnels
-	if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
-		// First we get the dir from this tile and his parent
-		DiagDirection dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
-		// It means we can only walk with the track, so the bridge has to be in the same direction
-		TileIndex tile = current->path.node.tile;
-		TileIndex new_tile = tile;
-		Slope tileh = GetTileSlope(tile, NULL);
-
-		// Bridges can only be build on land that is not flat
-		//  And if there is a road or rail blocking
-		if (tileh != SLOPE_FLAT ||
-				(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_STREET)) ||
-				(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_RAILWAY))) {
-			for (;;) {
-				new_tile += TileOffsByDiagDir(dir);
-
-				// Precheck, is the length allowed?
-				if (!CheckBridge_Stuff(0, GetBridgeLength(tile, new_tile))) break;
-
-				// Check if we hit the station-tile.. we don't like that!
-				if (TILES_BETWEEN(new_tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) break;
-
-				// Try building the bridge..
-				ret = AI_DoCommand(tile, new_tile, (0 << 8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
-				if (CmdFailed(ret)) continue;
-				// We can build a bridge here.. add him to the neighbours
-				aystar->neighbours[aystar->num_neighbours].tile = new_tile;
-				aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
-				aystar->neighbours[aystar->num_neighbours++].direction = 0;
-				// We can only have 12 neighbours, and we need 1 left for tunnels
-				if (aystar->num_neighbours == 11) break;
-			}
-		}
-
-		// Next, check for tunnels!
-		// Tunnels can only be built on slopes corresponding to the direction
-		//  For now, we check both sides for this tile.. terraforming gives fuzzy result
-		if ((dir == DIAGDIR_NE && tileh == SLOPE_NE) ||
-				(dir == DIAGDIR_SE && tileh == SLOPE_SE) ||
-				(dir == DIAGDIR_SW && tileh == SLOPE_SW) ||
-				(dir == DIAGDIR_NW && tileh == SLOPE_NW)) {
-			// Now simply check if a tunnel can be build
-			ret = AI_DoCommand(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
-			tileh = GetTileSlope(_build_tunnel_endtile, NULL);
-			if (!CmdFailed(ret) && (tileh == SLOPE_SW || tileh == SLOPE_SE || tileh == SLOPE_NW || tileh == SLOPE_NE)) {
-				aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
-				aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
-				aystar->neighbours[aystar->num_neighbours++].direction = 0;
-			}
-		}
-	}
-}
-
-
-extern uint GetRailFoundation(Slope tileh, TrackBits bits); // XXX function declaration in .c
-extern uint GetRoadFoundation(Slope tileh, uint bits); // XXX function declaration in .c
-extern uint GetBridgeFoundation(Slope tileh, Axis); // XXX function declaration in .c
-enum {
-	BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
-};
-
-// The most important function: it calculates the g-value
-static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
-{
-	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
-	int r, res = 0;
-	Slope tileh = GetTileSlope(current->tile, NULL);
-	Slope parent_tileh = GetTileSlope(parent->path.node.tile, NULL);
-
-	// Check if we hit the end-tile
-	if (TILES_BETWEEN(current->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) {
-		// We are at the end-tile, check if we had a direction or something...
-		if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction) {
-			// We are not pointing the right way, invalid tile
-			return AYSTAR_INVALID_NODE;
-		}
-		// If it was valid, drop out.. we don't build on the endtile
-		return 0;
-	}
-
-	// Give everything a small penalty
-	res += AI_PATHFINDER_PENALTY;
-
-	if (!PathFinderInfo->rail_or_road) {
-		// Road has the lovely advantage it can use other road... check if
-		//  the current tile is road, and if so, give a good bonus
-		if (IsRoad(current->tile)) {
-			res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
-		}
-	}
-
-	// We should give a penalty when the tile is going up or down.. this is one way to do so!
-	//  Too bad we have to count it from the parent.. but that is not so bad.
-	// We also dislike long routes on slopes, since they do not look too realistic
-	//  when there is a flat land all around, they are more expensive to build, and
-	//  especially they essentially block the ability to connect or cross the road
-	//  from one side.
-	if (parent_tileh != SLOPE_FLAT && parent->path.parent != NULL) {
-		// Skip if the tile was from a bridge or tunnel
-		if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
-			if (PathFinderInfo->rail_or_road) {
-				r = GetRailFoundation(parent_tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
-				// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
-				if (r >= 15 || (r == 0 && HASBIT(BRIDGE_NO_FOUNDATION, tileh))) {
-					res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
-				} else {
-					res += AI_PATHFINDER_FOUNDATION_PENALTY;
-				}
-			} else {
-				if (!IsRoad(parent->path.node.tile) || !IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE)) {
-					r = GetRoadFoundation(parent_tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
-					if (r >= 15 || r == 0) {
-						res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
-					} else {
-						res += AI_PATHFINDER_FOUNDATION_PENALTY;
-					}
-				}
-			}
-		}
-	}
-
-	// Are we part of a tunnel?
-	if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
-		// Tunnels are very expensive when build on long routes..
-		// Ironicly, we are using BridgeCode here ;)
-		r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
-		res += r + (r >> 8);
-	}
-
-	// Are we part of a bridge?
-	if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
-		// That means for every length a penalty
-		res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
-		// Check if we are going up or down, first for the starting point
-		// In user_data[0] is at the 8th bit the direction
-		if (!HASBIT(BRIDGE_NO_FOUNDATION, parent_tileh)) {
-			if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15) {
-				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
-			}
-		}
-		// Second for the end point
-		if (!HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
-			if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15) {
-				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
-			}
-		}
-		if (parent_tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
-		if (tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
-	}
-
-	//  To prevent the AI from taking the fastest way in tiles, but not the fastest way
-	//    in speed, we have to give a good penalty to direction changing
-	//  This way, we get almost the fastest way in tiles, and a very good speed on the track
-	if (!PathFinderInfo->rail_or_road) {
-		if (parent->path.parent != NULL &&
-				AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
-			// When road exists, we don't like turning, but its free, so don't be to piggy about it
-			if (IsRoad(parent->path.node.tile)) {
-				res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
-			} else {
-				res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
-			}
-		}
-	} else {
-		// For rail we have 1 exeption: diagonal rail..
-		// So we fetch 2 raildirection. That of the current one, and of the one before that
-		if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
-			int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
-			int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
-			// First, see if we are on diagonal path, that is better than straight path
-			if (dir1 > 1) res -= AI_PATHFINDER_DIAGONAL_BONUS;
-
-			// First see if they are different
-			if (dir1 != dir2) {
-				// dir 2 and 3 are 1 diagonal track, and 4 and 5.
-				if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
-					// It is not, so we changed of direction
-					res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
-				}
-				if (parent->path.parent->parent->parent != NULL) {
-					int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
-					// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
-					if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
-						res += AI_PATHFINDER_CURVE_PENALTY;
-					}
-				}
-			}
-		}
-	}
-
-	return (res < 0) ? 0 : res;
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/trolly/pathfinder.cpp
@@ -0,0 +1,510 @@
+/* $Id$ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../bridge_map.h"
+#include "../../debug.h"
+#include "../../functions.h"
+#include "../../map.h"
+#include "../../tile.h"
+#include "../../command.h"
+#include "trolly.h"
+#include "../../depot.h"
+#include "../../tunnel_map.h"
+#include "../../bridge.h"
+#include "../ai.h"
+
+#define TEST_STATION_NO_DIR 0xFF
+
+// Tests if a station can be build on the given spot
+// TODO: make it train compatible
+static bool TestCanBuildStationHere(TileIndex tile, byte dir)
+{
+	Player *p = GetPlayer(_current_player);
+
+	if (dir == TEST_STATION_NO_DIR) {
+		int32 ret;
+		// TODO: currently we only allow spots that can be access from al 4 directions...
+		//  should be fixed!!!
+		for (dir = 0; dir < 4; dir++) {
+			ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
+			if (!CmdFailed(ret)) return true;
+		}
+		return false;
+	}
+
+	// return true if command succeeded, so the inverse of CmdFailed()
+	return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
+}
+
+
+static bool IsRoad(TileIndex tile)
+{
+	return
+		// MP_STREET, but not a road depot?
+		(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
+		(IsTileType(tile, MP_TUNNELBRIDGE) && (
+			(IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) ||
+			(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD)
+		));
+}
+
+
+// Checks if a tile 'a' is between the tiles 'b' and 'c'
+#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
+
+
+// Check if the current tile is in our end-area
+static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
+{
+	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
+
+	// It is not allowed to have a station on the end of a bridge or tunnel ;)
+	if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
+	if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
+		if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
+			if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile, AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
+				return AYSTAR_FOUND_END_NODE;
+
+	return AYSTAR_DONE;
+}
+
+
+// Calculates the hash
+//   Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
+static uint AiPathFinder_Hash(uint key1, uint key2)
+{
+	return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
+}
+
+
+// Clear the memory of all the things
+static void AyStar_AiPathFinder_Free(AyStar *aystar)
+{
+	AyStarMain_Free(aystar);
+	free(aystar);
+}
+
+
+static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
+static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
+static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
+static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
+
+
+// This creates the AiPathFinder
+AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo)
+{
+	PathNode start_node;
+	uint x;
+	uint y;
+	// Create AyStar
+	AyStar *result = malloc(sizeof(AyStar));
+	init_AyStar(result, AiPathFinder_Hash, 1 << 10);
+	// Set the function pointers
+	result->CalculateG = AyStar_AiPathFinder_CalculateG;
+	result->CalculateH = AyStar_AiPathFinder_CalculateH;
+	result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
+	result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
+	result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
+
+	result->free = AyStar_AiPathFinder_Free;
+
+	// Set some information
+	result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
+	result->max_path_cost = 0;
+	result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
+
+	// Set the user_data to the PathFinderInfo
+	result->user_target = PathFinderInfo;
+
+	// Set the start node
+	start_node.parent = NULL;
+	start_node.node.direction = 0;
+	start_node.node.user_data[0] = 0;
+
+	// Now we add all the starting tiles
+	for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
+		for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
+			start_node.node.tile = TileXY(x, y);
+			result->addstart(result, &start_node.node, 0);
+		}
+	}
+
+	return result;
+}
+
+
+// To reuse AyStar we sometimes have to clean all the memory
+void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo)
+{
+	PathNode start_node;
+	uint x;
+	uint y;
+
+	aystar->clear(aystar);
+
+	// Set the user_data to the PathFinderInfo
+	aystar->user_target = PathFinderInfo;
+
+	// Set the start node
+	start_node.parent = NULL;
+	start_node.node.direction = 0;
+	start_node.node.user_data[0] = 0;
+	start_node.node.tile = PathFinderInfo->start_tile_tl;
+
+	// Now we add all the starting tiles
+	for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
+		for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
+			TileIndex tile = TileXY(x, y);
+
+			if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) continue;
+			if (!TestCanBuildStationHere(tile, TEST_STATION_NO_DIR)) continue;
+			start_node.node.tile = tile;
+			aystar->addstart(aystar, &start_node.node, 0);
+		}
+	}
+}
+
+
+// The h-value, simple calculation
+static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
+{
+	const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
+	int r, r2;
+
+	if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
+		// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
+		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDiagDir(PathFinderInfo->end_direction));
+		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDiagDir(PathFinderInfo->end_direction));
+	} else {
+		// No direction, so just get the fastest route to the station
+		r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
+		r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br);
+	}
+	// See if the bottomright is faster than the topleft..
+	if (r2 < r) r = r2;
+	return r * AI_PATHFINDER_H_MULTIPLER;
+}
+
+
+// We found the end.. let's get the route back and put it in an array
+static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current)
+{
+	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
+	uint i = 0;
+	PathNode *parent = &current->path;
+
+	do {
+		PathFinderInfo->route_extra[i] = parent->node.user_data[0];
+		PathFinderInfo->route[i++] = parent->node.tile;
+		if (i > lengthof(PathFinderInfo->route)) {
+			// We ran out of space for the PathFinder
+			DEBUG(ai, 0, "No more space in pathfinder route[] array");
+			PathFinderInfo->route_length = -1; // -1 indicates out of space
+			return;
+		}
+		parent = parent->parent;
+	} while (parent != NULL);
+	PathFinderInfo->route_length = i;
+	DEBUG(ai, 1, "Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash));
+}
+
+
+// What tiles are around us.
+static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current)
+{
+	uint i;
+	int ret;
+	int dir;
+
+	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
+
+	aystar->num_neighbours = 0;
+
+	// Go through all surrounding tiles and check if they are within the limits
+	for (i = 0; i < 4; i++) {
+		TileIndex ctile = current->path.node.tile; // Current tile
+		TileIndex atile = ctile + TileOffsByDiagDir(i); // Adjacent tile
+
+		if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 &&
+				TileY(atile) > 1 && TileY(atile) < MapMaxY() - 1) {
+			// We also directly test if the current tile can connect to this tile..
+			//  We do this simply by just building the tile!
+
+			// If the next step is a bridge, we have to enter it the right way
+			if (!PathFinderInfo->rail_or_road && IsRoad(atile)) {
+				if (IsTileType(atile, MP_TUNNELBRIDGE)) {
+					if (IsTunnel(atile)) {
+						if (GetTunnelDirection(atile) != i) continue;
+					} else {
+						if ((_m[atile].m5 & 1U) != DiagDirToAxis(i)) continue;
+					}
+				}
+			}
+			// But also if we are on a bridge, we can only move a certain direction
+			if (!PathFinderInfo->rail_or_road && IsRoad(ctile)) {
+				if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
+					// An existing bridge/tunnel... let's test the direction ;)
+					if ((_m[ctile].m5 & 1U) != (i & 1)) continue;
+				}
+			}
+
+			if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
+					(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
+				// We are a bridge/tunnel, how cool!!
+				//  This means we can only point forward.. get the direction from the user_data
+				if (i != (current->path.node.user_data[0] >> 8)) continue;
+			}
+			dir = 0;
+
+			// First, check if we have a parent
+			if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
+				// If not, this means we are at the starting station
+				if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
+					// We do need a direction?
+					if (AiNew_GetDirection(ctile, atile) != PathFinderInfo->start_direction) {
+						// We are not pointing the right way, invalid tile
+						continue;
+					}
+				}
+			} else if (current->path.node.user_data[0] == 0) {
+				if (PathFinderInfo->rail_or_road) {
+					// Rail check
+					dir = AiNew_GetRailDirection(current->path.parent->node.tile, ctile, atile);
+					ret = AI_DoCommand(ctile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
+					if (CmdFailed(ret)) continue;
+#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
+					if (current->path.parent->parent != NULL) {
+						// Check if we don't make a 90degree curve
+						int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, ctile);
+						if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
+							continue;
+						}
+					}
+#endif
+				} else {
+					// Road check
+					dir = AiNew_GetRoadDirection(current->path.parent->node.tile, ctile, atile);
+					if (IsRoad(ctile)) {
+						if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
+							// We have a bridge, how nicely! We should mark it...
+							dir = 0;
+						} else {
+							// It already has road.. check if we miss any bits!
+							if ((_m[ctile].m5 & dir) != dir) {
+								// We do miss some pieces :(
+								dir &= ~_m[ctile].m5;
+							} else {
+								dir = 0;
+							}
+						}
+					}
+					// Only destruct things if it is MP_CLEAR of MP_TREES
+					if (dir != 0) {
+						ret = AI_DoCommand(ctile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
+						if (CmdFailed(ret)) continue;
+					}
+				}
+			}
+
+			// The tile can be connected
+			aystar->neighbours[aystar->num_neighbours].tile = atile;
+			aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
+			aystar->neighbours[aystar->num_neighbours++].direction = 0;
+		}
+	}
+
+	// Next step, check for bridges and tunnels
+	if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
+		// First we get the dir from this tile and his parent
+		DiagDirection dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
+		// It means we can only walk with the track, so the bridge has to be in the same direction
+		TileIndex tile = current->path.node.tile;
+		TileIndex new_tile = tile;
+		Slope tileh = GetTileSlope(tile, NULL);
+
+		// Bridges can only be build on land that is not flat
+		//  And if there is a road or rail blocking
+		if (tileh != SLOPE_FLAT ||
+				(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_STREET)) ||
+				(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_RAILWAY))) {
+			for (;;) {
+				new_tile += TileOffsByDiagDir(dir);
+
+				// Precheck, is the length allowed?
+				if (!CheckBridge_Stuff(0, GetBridgeLength(tile, new_tile))) break;
+
+				// Check if we hit the station-tile.. we don't like that!
+				if (TILES_BETWEEN(new_tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) break;
+
+				// Try building the bridge..
+				ret = AI_DoCommand(tile, new_tile, (0 << 8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
+				if (CmdFailed(ret)) continue;
+				// We can build a bridge here.. add him to the neighbours
+				aystar->neighbours[aystar->num_neighbours].tile = new_tile;
+				aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
+				aystar->neighbours[aystar->num_neighbours++].direction = 0;
+				// We can only have 12 neighbours, and we need 1 left for tunnels
+				if (aystar->num_neighbours == 11) break;
+			}
+		}
+
+		// Next, check for tunnels!
+		// Tunnels can only be built on slopes corresponding to the direction
+		//  For now, we check both sides for this tile.. terraforming gives fuzzy result
+		if ((dir == DIAGDIR_NE && tileh == SLOPE_NE) ||
+				(dir == DIAGDIR_SE && tileh == SLOPE_SE) ||
+				(dir == DIAGDIR_SW && tileh == SLOPE_SW) ||
+				(dir == DIAGDIR_NW && tileh == SLOPE_NW)) {
+			// Now simply check if a tunnel can be build
+			ret = AI_DoCommand(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
+			tileh = GetTileSlope(_build_tunnel_endtile, NULL);
+			if (!CmdFailed(ret) && (tileh == SLOPE_SW || tileh == SLOPE_SE || tileh == SLOPE_NW || tileh == SLOPE_NE)) {
+				aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
+				aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
+				aystar->neighbours[aystar->num_neighbours++].direction = 0;
+			}
+		}
+	}
+}
+
+
+extern uint GetRailFoundation(Slope tileh, TrackBits bits); // XXX function declaration in .c
+extern uint GetRoadFoundation(Slope tileh, uint bits); // XXX function declaration in .c
+extern uint GetBridgeFoundation(Slope tileh, Axis); // XXX function declaration in .c
+enum {
+	BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
+};
+
+// The most important function: it calculates the g-value
+static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
+{
+	Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
+	int r, res = 0;
+	Slope tileh = GetTileSlope(current->tile, NULL);
+	Slope parent_tileh = GetTileSlope(parent->path.node.tile, NULL);
+
+	// Check if we hit the end-tile
+	if (TILES_BETWEEN(current->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) {
+		// We are at the end-tile, check if we had a direction or something...
+		if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction) {
+			// We are not pointing the right way, invalid tile
+			return AYSTAR_INVALID_NODE;
+		}
+		// If it was valid, drop out.. we don't build on the endtile
+		return 0;
+	}
+
+	// Give everything a small penalty
+	res += AI_PATHFINDER_PENALTY;
+
+	if (!PathFinderInfo->rail_or_road) {
+		// Road has the lovely advantage it can use other road... check if
+		//  the current tile is road, and if so, give a good bonus
+		if (IsRoad(current->tile)) {
+			res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
+		}
+	}
+
+	// We should give a penalty when the tile is going up or down.. this is one way to do so!
+	//  Too bad we have to count it from the parent.. but that is not so bad.
+	// We also dislike long routes on slopes, since they do not look too realistic
+	//  when there is a flat land all around, they are more expensive to build, and
+	//  especially they essentially block the ability to connect or cross the road
+	//  from one side.
+	if (parent_tileh != SLOPE_FLAT && parent->path.parent != NULL) {
+		// Skip if the tile was from a bridge or tunnel
+		if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
+			if (PathFinderInfo->rail_or_road) {
+				r = GetRailFoundation(parent_tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
+				// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
+				if (r >= 15 || (r == 0 && HASBIT(BRIDGE_NO_FOUNDATION, tileh))) {
+					res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
+				} else {
+					res += AI_PATHFINDER_FOUNDATION_PENALTY;
+				}
+			} else {
+				if (!IsRoad(parent->path.node.tile) || !IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE)) {
+					r = GetRoadFoundation(parent_tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
+					if (r >= 15 || r == 0) {
+						res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
+					} else {
+						res += AI_PATHFINDER_FOUNDATION_PENALTY;
+					}
+				}
+			}
+		}
+	}
+
+	// Are we part of a tunnel?
+	if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
+		// Tunnels are very expensive when build on long routes..
+		// Ironicly, we are using BridgeCode here ;)
+		r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
+		res += r + (r >> 8);
+	}
+
+	// Are we part of a bridge?
+	if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
+		// That means for every length a penalty
+		res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
+		// Check if we are going up or down, first for the starting point
+		// In user_data[0] is at the 8th bit the direction
+		if (!HASBIT(BRIDGE_NO_FOUNDATION, parent_tileh)) {
+			if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15) {
+				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
+			}
+		}
+		// Second for the end point
+		if (!HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
+			if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15) {
+				res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
+			}
+		}
+		if (parent_tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
+		if (tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
+	}
+
+	//  To prevent the AI from taking the fastest way in tiles, but not the fastest way
+	//    in speed, we have to give a good penalty to direction changing
+	//  This way, we get almost the fastest way in tiles, and a very good speed on the track
+	if (!PathFinderInfo->rail_or_road) {
+		if (parent->path.parent != NULL &&
+				AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
+			// When road exists, we don't like turning, but its free, so don't be to piggy about it
+			if (IsRoad(parent->path.node.tile)) {
+				res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
+			} else {
+				res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
+			}
+		}
+	} else {
+		// For rail we have 1 exeption: diagonal rail..
+		// So we fetch 2 raildirection. That of the current one, and of the one before that
+		if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
+			int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
+			int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
+			// First, see if we are on diagonal path, that is better than straight path
+			if (dir1 > 1) res -= AI_PATHFINDER_DIAGONAL_BONUS;
+
+			// First see if they are different
+			if (dir1 != dir2) {
+				// dir 2 and 3 are 1 diagonal track, and 4 and 5.
+				if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
+					// It is not, so we changed of direction
+					res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
+				}
+				if (parent->path.parent->parent->parent != NULL) {
+					int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
+					// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
+					if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
+						res += AI_PATHFINDER_CURVE_PENALTY;
+					}
+				}
+			}
+		}
+	}
+
+	return (res < 0) ? 0 : res;
+}
deleted file mode 100644
--- a/src/ai/trolly/shared.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* $Id$ */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../debug.h"
-#include "../../map.h"
-#include "trolly.h"
-#include "../../vehicle.h"
-
-int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
-{
-	// 0 = vert
-	// 1 = horz
-	// 2 = dig up-left
-	// 3 = dig down-right
-	// 4 = dig down-left
-	// 5 = dig up-right
-
-	uint x1 = TileX(tile_a);
-	uint x2 = TileX(tile_b);
-	uint x3 = TileX(tile_c);
-
-	uint y1 = TileY(tile_a);
-	uint y2 = TileY(tile_b);
-	uint y3 = TileY(tile_c);
-
-	if (y1 == y2 && y2 == y3) return 0;
-	if (x1 == x2 && x2 == x3) return 1;
-	if (y2 > y1) return x2 > x3 ? 2 : 4;
-	if (x2 > x1) return y2 > y3 ? 2 : 5;
-	if (y1 > y2) return x2 > x3 ? 5 : 3;
-	if (x1 > x2) return y2 > y3 ? 4 : 3;
-
-	return 0;
-}
-
-int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
-{
-	int x1, x2, x3;
-	int y1, y2, y3;
-	int r;
-
-	x1 = TileX(tile_a);
-	x2 = TileX(tile_b);
-	x3 = TileX(tile_c);
-
-	y1 = TileY(tile_a);
-	y2 = TileY(tile_b);
-	y3 = TileY(tile_c);
-
-	r = 0;
-
-	if (x1 < x2) r += 8;
-	if (y1 < y2) r += 1;
-	if (x1 > x2) r += 2;
-	if (y1 > y2) r += 4;
-
-	if (x2 < x3) r += 2;
-	if (y2 < y3) r += 4;
-	if (x2 > x3) r += 8;
-	if (y2 > y3) r += 1;
-
-	return r;
-}
-
-// Get's the direction between 2 tiles seen from tile_a
-DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b)
-{
-	if (TileY(tile_a) < TileY(tile_b)) return DIAGDIR_SE;
-	if (TileY(tile_a) > TileY(tile_b)) return DIAGDIR_NW;
-	if (TileX(tile_a) < TileX(tile_b)) return DIAGDIR_SW;
-	return DIAGDIR_NE;
-}
-
-
-// This functions looks up if this vehicle is special for this AI
-//  and returns his flag
-uint AiNew_GetSpecialVehicleFlag(Player* p, Vehicle* v)
-{
-	uint i;
-
-	for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
-		if (p->ainew.special_vehicles[i].veh_id == v->index) {
-			return p->ainew.special_vehicles[i].flag;
-		}
-	}
-
-	// Not found :(
-	return 0;
-}
-
-
-bool AiNew_SetSpecialVehicleFlag(Player* p, Vehicle* v, uint flag)
-{
-	int new_id = -1;
-	uint i;
-
-	for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
-		if (p->ainew.special_vehicles[i].veh_id == v->index) {
-			p->ainew.special_vehicles[i].flag |= flag;
-			return true;
-		}
-		if (new_id == -1 &&
-				p->ainew.special_vehicles[i].veh_id == 0 &&
-				p->ainew.special_vehicles[i].flag == 0) {
-			new_id = i;
-		}
-	}
-
-	// Out of special_vehicle spots :s
-	if (new_id == -1) {
-		DEBUG(ai, 1, "special_vehicles list is too small");
-		return false;
-	}
-	p->ainew.special_vehicles[new_id].veh_id = v->index;
-	p->ainew.special_vehicles[new_id].flag = flag;
-	return true;
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/trolly/shared.cpp
@@ -0,0 +1,118 @@
+/* $Id$ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../debug.h"
+#include "../../map.h"
+#include "trolly.h"
+#include "../../vehicle.h"
+
+int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
+{
+	// 0 = vert
+	// 1 = horz
+	// 2 = dig up-left
+	// 3 = dig down-right
+	// 4 = dig down-left
+	// 5 = dig up-right
+
+	uint x1 = TileX(tile_a);
+	uint x2 = TileX(tile_b);
+	uint x3 = TileX(tile_c);
+
+	uint y1 = TileY(tile_a);
+	uint y2 = TileY(tile_b);
+	uint y3 = TileY(tile_c);
+
+	if (y1 == y2 && y2 == y3) return 0;
+	if (x1 == x2 && x2 == x3) return 1;
+	if (y2 > y1) return x2 > x3 ? 2 : 4;
+	if (x2 > x1) return y2 > y3 ? 2 : 5;
+	if (y1 > y2) return x2 > x3 ? 5 : 3;
+	if (x1 > x2) return y2 > y3 ? 4 : 3;
+
+	return 0;
+}
+
+int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
+{
+	int x1, x2, x3;
+	int y1, y2, y3;
+	int r;
+
+	x1 = TileX(tile_a);
+	x2 = TileX(tile_b);
+	x3 = TileX(tile_c);
+
+	y1 = TileY(tile_a);
+	y2 = TileY(tile_b);
+	y3 = TileY(tile_c);
+
+	r = 0;
+
+	if (x1 < x2) r += 8;
+	if (y1 < y2) r += 1;
+	if (x1 > x2) r += 2;
+	if (y1 > y2) r += 4;
+
+	if (x2 < x3) r += 2;
+	if (y2 < y3) r += 4;
+	if (x2 > x3) r += 8;
+	if (y2 > y3) r += 1;
+
+	return r;
+}
+
+// Get's the direction between 2 tiles seen from tile_a
+DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b)
+{
+	if (TileY(tile_a) < TileY(tile_b)) return DIAGDIR_SE;
+	if (TileY(tile_a) > TileY(tile_b)) return DIAGDIR_NW;
+	if (TileX(tile_a) < TileX(tile_b)) return DIAGDIR_SW;
+	return DIAGDIR_NE;
+}
+
+
+// This functions looks up if this vehicle is special for this AI
+//  and returns his flag
+uint AiNew_GetSpecialVehicleFlag(Player* p, Vehicle* v)
+{
+	uint i;
+
+	for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
+		if (p->ainew.special_vehicles[i].veh_id == v->index) {
+			return p->ainew.special_vehicles[i].flag;
+		}
+	}
+
+	// Not found :(
+	return 0;
+}
+
+
+bool AiNew_SetSpecialVehicleFlag(Player* p, Vehicle* v, uint flag)
+{
+	int new_id = -1;
+	uint i;
+
+	for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
+		if (p->ainew.special_vehicles[i].veh_id == v->index) {
+			p->ainew.special_vehicles[i].flag |= flag;
+			return true;
+		}
+		if (new_id == -1 &&
+				p->ainew.special_vehicles[i].veh_id == 0 &&
+				p->ainew.special_vehicles[i].flag == 0) {
+			new_id = i;
+		}
+	}
+
+	// Out of special_vehicle spots :s
+	if (new_id == -1) {
+		DEBUG(ai, 1, "special_vehicles list is too small");
+		return false;
+	}
+	p->ainew.special_vehicles[new_id].veh_id = v->index;
+	p->ainew.special_vehicles[new_id].flag = flag;
+	return true;
+}
deleted file mode 100644
--- a/src/ai/trolly/trolly.c
+++ /dev/null
@@ -1,1353 +0,0 @@
-/* $Id$ */
-
-/*
- * This AI was created as a direct reaction to the big demand for some good AIs
- * in OTTD. Too bad it never left alpha-stage, and it is considered dead in its
- * current form.
- * By the time of writing this, we, the creator of this AI and a good friend of
- * mine, are designing a whole new AI-system that allows us to create AIs
- * easier and without all the fuzz we encountered while I was working on this
- * AI. By the time that system is finished, you can expect that this AI will
- * dissapear, because it is pretty obselete and bad programmed.
- *
- * Meanwhile I wish you all much fun with this AI; if you are interested as
- * AI-developer in this AI, I advise you not stare too long to some code, some
- * things in here really are... strange ;) But in either way: enjoy :)
- *
- *  -- TrueLight :: 2005-09-01
- */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../debug.h"
-#include "../../functions.h"
-#include "../../road_map.h"
-#include "../../station_map.h"
-#include "table/strings.h"
-#include "../../map.h"
-#include "../../tile.h"
-#include "../../command.h"
-#include "trolly.h"
-#include "../../town.h"
-#include "../../industry.h"
-#include "../../station.h"
-#include "../../engine.h"
-#include "../../gui.h"
-#include "../../depot.h"
-#include "../../vehicle.h"
-#include "../../date.h"
-#include "../ai.h"
-
-// This function is called after StartUp. It is the init of an AI
-static void AiNew_State_FirstTime(Player *p)
-{
-	// This assert is used to protect those function from misuse
-	//   You have quickly a small mistake in the state-array
-	//   With that, everything would go wrong. Finding that, is almost impossible
-	//   With this assert, that problem can never happen.
-	assert(p->ainew.state == AI_STATE_FIRST_TIME);
-	// We first have to init some things
-
-	if (_current_player == 1) ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_IN_PROGRESS, 0, 0);
-
-	// The PathFinder (AyStar)
-	// TODO: Maybe when an AI goes bankrupt, this is de-init
-	//  or when coming from a savegame.. should be checked out!
-	p->ainew.path_info.start_tile_tl = 0;
-	p->ainew.path_info.start_tile_br = 0;
-	p->ainew.path_info.end_tile_tl = 0;
-	p->ainew.path_info.end_tile_br = 0;
-	p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info);
-
-	p->ainew.idle = 0;
-	p->ainew.last_vehiclecheck_date = _date;
-
-	// We ALWAYS start with a bus route.. just some basic money ;)
-	p->ainew.action = AI_ACTION_BUS_ROUTE;
-
-	// Let's popup the news, and after that, start building..
-	p->ainew.state = AI_STATE_WAKE_UP;
-}
-
-
-// This function just waste some time
-//  It keeps it more real. The AI can build on such tempo no normal user
-//  can ever keep up with that. The competitor_speed already delays a bit
-//  but after the AI finished a track it really needs to go to sleep.
-//
-// Let's say, we sleep between one and three days if the AI is put on Very Fast.
-//  This means that on Very Slow it will be between 16 and 48 days.. slow enough?
-static void AiNew_State_Nothing(Player *p)
-{
-	assert(p->ainew.state == AI_STATE_NOTHING);
-	// If we are done idling, start over again
-	if (p->ainew.idle == 0) p->ainew.idle = AI_RandomRange(DAY_TICKS * 2) + DAY_TICKS;
-	if (--p->ainew.idle == 0) {
-		// We are done idling.. what you say? Let's do something!
-		// I mean.. the next tick ;)
-		p->ainew.state = AI_STATE_WAKE_UP;
-	}
-}
-
-
-// This function picks out a task we are going to do.
-//  Currently supported:
-//    - Make new route
-//    - Check route
-//    - Build HQ
-static void AiNew_State_WakeUp(Player *p)
-{
-	int32 money;
-	int c;
-	assert(p->ainew.state == AI_STATE_WAKE_UP);
-	// First, check if we have a HQ
-	if (p->location_of_house == 0) {
-		// We have no HQ yet, build one on a random place
-		// Random till we found a place for it!
-		// TODO: this should not be on a random place..
-		AiNew_Build_CompanyHQ(p, AI_Random() % MapSize());
-		// Enough for now, but we want to come back here the next time
-		//  so we do not change any status
-		return;
-	}
-
-	money = p->player_money - AI_MINIMUM_MONEY;
-
-	// Let's pick an action!
-	if (p->ainew.action == AI_ACTION_NONE) {
-		c = AI_Random() & 0xFF;
-		if (p->current_loan > 0 &&
-				p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN &&
-				c < 10) {
-			p->ainew.action = AI_ACTION_REPAY_LOAN;
-		} else if (p->ainew.last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) {
-			// Check all vehicles once in a while
-			p->ainew.action = AI_ACTION_CHECK_ALL_VEHICLES;
-			p->ainew.last_vehiclecheck_date = _date;
-		} else if (c < 100 && !_patches.ai_disable_veh_roadveh) {
-			// Do we have any spots for road-vehicles left open?
-			if (GetFreeUnitNumber(VEH_Road) <= _patches.max_roadveh) {
-				if (c < 85) {
-					p->ainew.action = AI_ACTION_TRUCK_ROUTE;
-				} else {
-					p->ainew.action = AI_ACTION_BUS_ROUTE;
-				}
-			}
-#if 0
-		} else if (c < 200 && !_patches.ai_disable_veh_train) {
-			if (GetFreeUnitNumber(VEH_Train) <= _patches.max_trains) {
-				p->ainew.action = AI_ACTION_TRAIN_ROUTE;
-			}
-#endif
-		}
-
-		p->ainew.counter = 0;
-	}
-
-	if (p->ainew.counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) {
-		p->ainew.action = AI_ACTION_NONE;
-		return;
-	}
-
-	if (_patches.ai_disable_veh_roadveh && (
-				p->ainew.action == AI_ACTION_BUS_ROUTE ||
-				p->ainew.action == AI_ACTION_TRUCK_ROUTE
-			)) {
-		p->ainew.action = AI_ACTION_NONE;
-		return;
-	}
-
-	if (p->ainew.action == AI_ACTION_REPAY_LOAN &&
-			money > AI_MINIMUM_LOAN_REPAY_MONEY) {
-		// We start repaying some money..
-		p->ainew.state = AI_STATE_REPAY_MONEY;
-		return;
-	}
-
-	if (p->ainew.action == AI_ACTION_CHECK_ALL_VEHICLES) {
-		p->ainew.state = AI_STATE_CHECK_ALL_VEHICLES;
-		return;
-	}
-
-	// It is useless to start finding a route if we don't have enough money
-	//  to build the route anyway..
-	if (p->ainew.action == AI_ACTION_BUS_ROUTE &&
-			money > AI_MINIMUM_BUS_ROUTE_MONEY) {
-		if (GetFreeUnitNumber(VEH_Road) > _patches.max_roadveh) {
-			p->ainew.action = AI_ACTION_NONE;
-			return;
-		}
-		p->ainew.cargo = AI_NEED_CARGO;
-		p->ainew.state = AI_STATE_LOCATE_ROUTE;
-		p->ainew.tbt = AI_BUS; // Bus-route
-		return;
-	}
-	if (p->ainew.action == AI_ACTION_TRUCK_ROUTE &&
-			money > AI_MINIMUM_TRUCK_ROUTE_MONEY) {
-		if (GetFreeUnitNumber(VEH_Road) > _patches.max_roadveh) {
-			p->ainew.action = AI_ACTION_NONE;
-			return;
-		}
-		p->ainew.cargo = AI_NEED_CARGO;
-		p->ainew.last_id = 0;
-		p->ainew.state = AI_STATE_LOCATE_ROUTE;
-		p->ainew.tbt = AI_TRUCK;
-		return;
-	}
-
-	p->ainew.state = AI_STATE_NOTHING;
-}
-
-
-static void AiNew_State_ActionDone(Player *p)
-{
-	p->ainew.action = AI_ACTION_NONE;
-	p->ainew.state = AI_STATE_NOTHING;
-}
-
-
-// Check if a city or industry is good enough to start a route there
-static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type)
-{
-	if (type == AI_CITY) {
-		const Town* t = GetTown(ic);
-		const Station* st;
-		uint count = 0;
-		int j = 0;
-
-		// We don't like roadconstructions, don't even true such a city
-		if (t->road_build_months != 0) return false;
-
-		// Check if the rating in a city is high enough
-		//  If not, take a chance if we want to continue
-		if (t->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
-
-		if (t->max_pass - t->act_pass < AI_CHECKCITY_NEEDED_CARGO && !AI_CHANCE16(1,AI_CHECKCITY_CITY_CHANCE)) return false;
-
-		// Check if we have build a station in this town the last 6 months
-		//  else we don't do it. This is done, because stat updates can be slow
-		//  and sometimes it takes up to 4 months before the stats are corectly.
-		//  This way we don't get 12 busstations in one city of 100 population ;)
-		FOR_ALL_STATIONS(st) {
-			// Do we own it?
-			if (st->owner == _current_player) {
-				// Are we talking busses?
-				if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) != FACIL_BUS_STOP) continue;
-				// Is it the same city as we are in now?
-				if (st->town != t) continue;
-				// When was this station build?
-				if (_date - st->build_date < AI_CHECKCITY_DATE_BETWEEN) return false;
-				// Cound the amount of stations in this city that we own
-				count++;
-			} else {
-				// We do not own it, request some info about the station
-				//  we want to know if this station gets the same good. If so,
-				//  we want to know its rating. If it is too high, we are not going
-				//  to build there
-				if (!st->goods[CT_PASSENGERS].last_speed) continue;
-				// Is it around our city
-				if (DistanceManhattan(st->xy, t->xy) > 10) continue;
-				// It does take this cargo.. what is his rating?
-				if (st->goods[CT_PASSENGERS].rating < AI_CHECKCITY_CARGO_RATING) continue;
-				j++;
-				// When this is the first station, we build a second with no problem ;)
-				if (j == 1) continue;
-				// The rating is high.. second station...
-				//  a little chance that we still continue
-				//  But if there are 3 stations of this size, we never go on...
-				if (j == 2 && AI_CHANCE16(1, AI_CHECKCITY_CARGO_RATING_CHANCE)) continue;
-				// We don't like this station :(
-				return false;
-			}
-		}
-
-		// We are about to add one...
-		count++;
-		// Check if we the city can provide enough cargo for this amount of stations..
-		if (count * AI_CHECKCITY_CARGO_PER_STATION > t->max_pass) return false;
-
-		// All check are okay, so we can build here!
-		return true;
-	}
-	if (type == AI_INDUSTRY) {
-		const Industry* i = GetIndustry(ic);
-		const Station* st;
-		int count = 0;
-		int j = 0;
-
-		if (i->town != NULL && i->town->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
-
-		// No limits on delevering stations!
-		//  Or for industry that does not give anything yet
-		if (i->produced_cargo[0] == CT_INVALID || i->total_production[0] == 0) return true;
-
-		if (i->total_production[0] - i->total_transported[0] < AI_CHECKCITY_NEEDED_CARGO) return false;
-
-		// Check if we have build a station in this town the last 6 months
-		//  else we don't do it. This is done, because stat updates can be slow
-		//  and sometimes it takes up to 4 months before the stats are corectly.
-		FOR_ALL_STATIONS(st) {
-			// Do we own it?
-			if (st->owner == _current_player) {
-				// Are we talking trucks?
-				if (p->ainew.tbt == AI_TRUCK && (FACIL_TRUCK_STOP & st->facilities) != FACIL_TRUCK_STOP) continue;
-				// Is it the same city as we are in now?
-				if (st->town != i->town) continue;
-				// When was this station build?
-				if (_date - st->build_date < AI_CHECKCITY_DATE_BETWEEN) return false;
-				// Cound the amount of stations in this city that we own
-				count++;
-			} else {
-				// We do not own it, request some info about the station
-				//  we want to know if this station gets the same good. If so,
-				//  we want to know its rating. If it is too high, we are not going
-				//  to build there
-				if (i->produced_cargo[0] == CT_INVALID) continue;
-				// It does not take this cargo
-				if (!st->goods[i->produced_cargo[0]].last_speed) continue;
-				// Is it around our industry
-				if (DistanceManhattan(st->xy, i->xy) > 5) continue;
-				// It does take this cargo.. what is his rating?
-				if (st->goods[i->produced_cargo[0]].rating < AI_CHECKCITY_CARGO_RATING) continue;
-				j++;
-				// The rating is high.. a little chance that we still continue
-				//  But if there are 2 stations of this size, we never go on...
-				if (j == 1 && AI_CHANCE16(1, AI_CHECKCITY_CARGO_RATING_CHANCE)) continue;
-				// We don't like this station :(
-				return false;
-			}
-		}
-
-		// We are about to add one...
-		count++;
-		// Check if we the city can provide enough cargo for this amount of stations..
-		if (count * AI_CHECKCITY_CARGO_PER_STATION > i->total_production[0]) return false;
-
-		// All check are okay, so we can build here!
-		return true;
-	}
-
-	return true;
-}
-
-
-// This functions tries to locate a good route
-static void AiNew_State_LocateRoute(Player *p)
-{
-	assert(p->ainew.state == AI_STATE_LOCATE_ROUTE);
-	// For now, we only support PASSENGERS, CITY and BUSSES
-
-	// We don't have a route yet
-	if (p->ainew.cargo == AI_NEED_CARGO) {
-		p->ainew.new_cost = 0; // No cost yet
-		p->ainew.temp = -1;
-		// Reset the counter
-		p->ainew.counter = 0;
-
-		p->ainew.from_ic = -1;
-		p->ainew.to_ic = -1;
-		if (p->ainew.tbt == AI_BUS) {
-			// For now we only have a passenger route
-			p->ainew.cargo = CT_PASSENGERS;
-
-			// Find a route to cities
-			p->ainew.from_type = AI_CITY;
-			p->ainew.to_type = AI_CITY;
-		} else if (p->ainew.tbt == AI_TRUCK) {
-			p->ainew.cargo = AI_NO_CARGO;
-
-			p->ainew.from_type = AI_INDUSTRY;
-			p->ainew.to_type = AI_INDUSTRY;
-		}
-
-		// Now we are doing initing, we wait one tick
-		return;
-	}
-
-	// Increase the counter and abort if it is taking too long!
-	p->ainew.counter++;
-	if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) {
-		// Switch back to doing nothing!
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-
-	// We are going to locate a city from where we are going to connect
-	if (p->ainew.from_ic == -1) {
-		if (p->ainew.temp == -1) {
-			// First, we pick a random spot to search from
-			if (p->ainew.from_type == AI_CITY) {
-				p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1);
-			} else {
-				p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1);
-			}
-		}
-
-		if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) {
-			// It was not a valid city
-			//  increase the temp with one, and return. We will come back later here
-			//  to try again
-			p->ainew.temp++;
-			if (p->ainew.from_type == AI_CITY) {
-				if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0;
-			} else {
-				if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0;
-			}
-
-			// Don't do an attempt if we are trying the same id as the last time...
-			if (p->ainew.last_id == p->ainew.temp) return;
-			p->ainew.last_id = p->ainew.temp;
-
-			return;
-		}
-
-		// We found a good city/industry, save the data of it
-		p->ainew.from_ic = p->ainew.temp;
-
-		// Start the next tick with finding a to-city
-		p->ainew.temp = -1;
-		return;
-	}
-
-	// Find a to-city
-	if (p->ainew.temp == -1) {
-		// First, we pick a random spot to search to
-		if (p->ainew.to_type == AI_CITY) {
-			p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1);
-		} else {
-			p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1);
-		}
-	}
-
-	// The same city is not allowed
-	// Also check if the city is valid
-	if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) {
-		// Maybe it is valid..
-
-		/* We need to know if they are not to far apart from eachother..
-		 * We do that by checking how much cargo we have to move and how long the
-		 * route is.
-		 */
-
-		if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) {
-			const Town* town_from = GetTown(p->ainew.from_ic);
-			const Town* town_temp = GetTown(p->ainew.temp);
-			uint distance = DistanceManhattan(town_from->xy, town_temp->xy);
-			int max_cargo;
-
-			max_cargo  = town_from->max_pass + town_temp->max_pass;
-			max_cargo -= town_from->act_pass + town_temp->act_pass;
-
-			// max_cargo is now the amount of cargo we can move between the two cities
-			// If it is more than the distance, we allow it
-			if (distance <= max_cargo * AI_LOCATEROUTE_BUS_CARGO_DISTANCE) {
-				// We found a good city/industry, save the data of it
-				p->ainew.to_ic = p->ainew.temp;
-				p->ainew.state = AI_STATE_FIND_STATION;
-
-				DEBUG(ai, 1, "[LocateRoute] found bus-route of %d tiles long (from %d to %d)",
-					distance,
-					p->ainew.from_ic,
-					p->ainew.temp
-				);
-
-				p->ainew.from_tile = 0;
-				p->ainew.to_tile = 0;
-
-				return;
-			}
-		} else if (p->ainew.tbt == AI_TRUCK) {
-			const Industry* ind_from = GetIndustry(p->ainew.from_ic);
-			const Industry* ind_temp = GetIndustry(p->ainew.temp);
-			bool found = false;
-			int max_cargo = 0;
-			uint i;
-
-			// TODO: in max_cargo, also check other cargo (beside [0])
-			// First we check if the from_ic produces cargo that this ic accepts
-			if (ind_from->produced_cargo[0] != CT_INVALID && ind_from->total_production[0] != 0) {
-				for (i = 0; i < lengthof(ind_temp->accepts_cargo); i++) {
-					if (ind_temp->accepts_cargo[i] == CT_INVALID) break;
-					if (ind_from->produced_cargo[0] == ind_temp->accepts_cargo[i]) {
-						// Found a compatible industry
-						max_cargo = ind_from->total_production[0] - ind_from->total_transported[0];
-						found = true;
-						p->ainew.from_deliver = true;
-						p->ainew.to_deliver = false;
-						break;
-					}
-				}
-			}
-			if (!found && ind_temp->produced_cargo[0] != CT_INVALID && ind_temp->total_production[0] != 0) {
-				// If not check if the current ic produces cargo that the from_ic accepts
-				for (i = 0; i < lengthof(ind_from->accepts_cargo); i++) {
-					if (ind_from->accepts_cargo[i] == CT_INVALID) break;
-					if (ind_temp->produced_cargo[0] == ind_from->accepts_cargo[i]) {
-						// Found a compatbiel industry
-						found = true;
-						max_cargo = ind_temp->total_production[0] - ind_temp->total_transported[0];
-						p->ainew.from_deliver = false;
-						p->ainew.to_deliver = true;
-						break;
-					}
-				}
-			}
-			if (found) {
-				// Yeah, they are compatible!!!
-				// Check the length against the amount of goods
-				uint distance = DistanceManhattan(ind_from->xy, ind_temp->xy);
-
-				if (distance > AI_LOCATEROUTE_TRUCK_MIN_DISTANCE &&
-						distance <= max_cargo * AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE) {
-					p->ainew.to_ic = p->ainew.temp;
-					if (p->ainew.from_deliver) {
-						p->ainew.cargo = ind_from->produced_cargo[0];
-					} else {
-						p->ainew.cargo = ind_temp->produced_cargo[0];
-					}
-					p->ainew.state = AI_STATE_FIND_STATION;
-
-					DEBUG(ai, 1, "[LocateRoute] found truck-route of %d tiles long (from %d to %d)",
-						distance,
-						p->ainew.from_ic,
-						p->ainew.temp
-					);
-
-					p->ainew.from_tile = 0;
-					p->ainew.to_tile = 0;
-
-					return;
-				}
-			}
-		}
-	}
-
-	// It was not a valid city
-	//  increase the temp with one, and return. We will come back later here
-	//  to try again
-	p->ainew.temp++;
-	if (p->ainew.to_type == AI_CITY) {
-		if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0;
-	} else {
-		if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0;
-	}
-
-	// Don't do an attempt if we are trying the same id as the last time...
-	if (p->ainew.last_id == p->ainew.temp) return;
-	p->ainew.last_id = p->ainew.temp;
-}
-
-
-// Check if there are not more than a certain amount of vehicles pointed to a certain
-//  station. This to prevent 10 busses going to one station, which gives... problems ;)
-static bool AiNew_CheckVehicleStation(Player *p, Station *st)
-{
-	int count = 0;
-	Vehicle *v;
-
-	// Also check if we don't have already a lot of busses to this city...
-	FOR_ALL_VEHICLES(v) {
-		if (v->owner == _current_player) {
-			const Order *order;
-
-			FOR_VEHICLE_ORDERS(v, order) {
-				if (order->type == OT_GOTO_STATION && GetStation(order->dest) == st) {
-					// This vehicle has this city in its list
-					count++;
-				}
-			}
-		}
-	}
-
-	if (count > AI_CHECK_MAX_VEHICLE_PER_STATION) return false;
-	return true;
-}
-
-// This function finds a good spot for a station
-static void AiNew_State_FindStation(Player *p)
-{
-	TileIndex tile;
-	Station *st;
-	int count = 0;
-	EngineID i;
-	TileIndex new_tile = 0;
-	byte direction = 0;
-	Town *town = NULL;
-	assert(p->ainew.state == AI_STATE_FIND_STATION);
-
-	if (p->ainew.from_tile == 0) {
-		// First we scan for a station in the from-city
-		if (p->ainew.from_type == AI_CITY) {
-			town = GetTown(p->ainew.from_ic);
-			tile = town->xy;
-		} else {
-			tile = GetIndustry(p->ainew.from_ic)->xy;
-		}
-	} else if (p->ainew.to_tile == 0) {
-		// Second we scan for a station in the to-city
-		if (p->ainew.to_type == AI_CITY) {
-			town = GetTown(p->ainew.to_ic);
-			tile = town->xy;
-		} else {
-			tile = GetIndustry(p->ainew.to_ic)->xy;
-		}
-	} else {
-		// Unsupported request
-		// Go to FIND_PATH
-		p->ainew.temp = -1;
-		p->ainew.state = AI_STATE_FIND_PATH;
-		return;
-	}
-
-	// First, we are going to look at the stations that already exist inside the city
-	//  If there is enough cargo left in the station, we take that station
-	//  If that is not possible, and there are more than 2 stations in the city, abort
-	i = AiNew_PickVehicle(p);
-	// Euhmz, this should not happen _EVER_
-	// Quit finding a route...
-	if (i == INVALID_ENGINE) {
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-
-	FOR_ALL_STATIONS(st) {
-		if (st->owner == _current_player) {
-			if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) == FACIL_BUS_STOP) {
-				if (st->town == town) {
-					// Check how much cargo there is left in the station
-					if ((st->goods[p->ainew.cargo].waiting_acceptance & 0xFFF) > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) {
-						if (AiNew_CheckVehicleStation(p, st)) {
-							// We did found a station that was good enough!
-							new_tile = st->xy;
-							direction = GetRoadStopDir(st->xy);
-							break;
-						}
-					}
-					count++;
-				}
-			}
-		}
-	}
-	// We are going to add a new station...
-	if (new_tile == 0) count++;
-	// No more than 2 stations allowed in a city
-	//  This is because only the best 2 stations of one cargo do get any cargo
-	if (count > 2) {
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-
-	if (new_tile == 0 && p->ainew.tbt == AI_BUS) {
-		uint x, y, i = 0;
-		int r;
-		uint best;
-		uint accepts[NUM_CARGO];
-		TileIndex found_spot[AI_FINDSTATION_TILE_RANGE*AI_FINDSTATION_TILE_RANGE*4];
-		uint found_best[AI_FINDSTATION_TILE_RANGE*AI_FINDSTATION_TILE_RANGE*4];
-		// To find a good spot we scan a range from the center, a get the point
-		//  where we get the most cargo and where it is buildable.
-		// TODO: also check for station of myself and make sure we are not
-		//   taking eachothers passangers away (bad result when it does not)
-		for (x = TileX(tile) - AI_FINDSTATION_TILE_RANGE; x <= TileX(tile) + AI_FINDSTATION_TILE_RANGE; x++) {
-			for (y = TileY(tile) - AI_FINDSTATION_TILE_RANGE; y <= TileY(tile) + AI_FINDSTATION_TILE_RANGE; y++) {
-				new_tile = TileXY(x, y);
-				if (IsTileType(new_tile, MP_CLEAR) || IsTileType(new_tile, MP_TREES)) {
-					// This tile we can build on!
-					// Check acceptance
-					// XXX - Get the catchment area
-					GetAcceptanceAroundTiles(accepts, new_tile, 1, 1, 4);
-					// >> 3 == 0 means no cargo
-					if (accepts[p->ainew.cargo] >> 3 == 0) continue;
-					// See if we can build the station
-					r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
-					if (CmdFailed(r)) continue;
-					// We can build it, so add it to found_spot
-					found_spot[i] = new_tile;
-					found_best[i++] = accepts[p->ainew.cargo];
-				}
-			}
-		}
-
-		// If i is still zero, we did not find anything
-		if (i == 0) {
-			p->ainew.state = AI_STATE_NOTHING;
-			return;
-		}
-
-		// Go through all the found_best and check which has the highest value
-		best = 0;
-		new_tile = 0;
-
-		for (x = 0; x < i; x++) {
-			if (found_best[x] > best ||
-					(found_best[x] == best && DistanceManhattan(tile, new_tile) > DistanceManhattan(tile, found_spot[x]))) {
-				new_tile = found_spot[x];
-				best = found_best[x];
-			}
-		}
-
-		// See how much it is going to cost us...
-		r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
-		p->ainew.new_cost += r;
-
-		direction = AI_PATHFINDER_NO_DIRECTION;
-	} else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) {
-		// Truck station locater works differently.. a station can be on any place
-		//  as long as it is in range. So we give back code AI_STATION_RANGE
-		//  so the pathfinder routine can work it out!
-		new_tile = AI_STATION_RANGE;
-		direction = AI_PATHFINDER_NO_DIRECTION;
-	}
-
-	if (p->ainew.from_tile == 0) {
-		p->ainew.from_tile = new_tile;
-		p->ainew.from_direction = direction;
-		// Now we found thisone, go in for to_tile
-		return;
-	} else if (p->ainew.to_tile == 0) {
-		p->ainew.to_tile = new_tile;
-		p->ainew.to_direction = direction;
-		// K, done placing stations!
-		p->ainew.temp = -1;
-		p->ainew.state = AI_STATE_FIND_PATH;
-		return;
-	}
-}
-
-
-// We try to find a path between 2 points
-static void AiNew_State_FindPath(Player *p)
-{
-	int r;
-	assert(p->ainew.state == AI_STATE_FIND_PATH);
-
-	// First time, init some data
-	if (p->ainew.temp == -1) {
-		// Init path_info
-		if (p->ainew.from_tile == AI_STATION_RANGE) {
-			const Industry* i = GetIndustry(p->ainew.from_ic);
-
-			// For truck routes we take a range around the industry
-			p->ainew.path_info.start_tile_tl = i->xy - TileDiffXY(1, 1);
-			p->ainew.path_info.start_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
-			p->ainew.path_info.start_direction = p->ainew.from_direction;
-		} else {
-			p->ainew.path_info.start_tile_tl = p->ainew.from_tile;
-			p->ainew.path_info.start_tile_br = p->ainew.from_tile;
-			p->ainew.path_info.start_direction = p->ainew.from_direction;
-		}
-
-		if (p->ainew.to_tile == AI_STATION_RANGE) {
-			const Industry* i = GetIndustry(p->ainew.to_ic);
-
-			p->ainew.path_info.end_tile_tl = i->xy - TileDiffXY(1, 1);
-			p->ainew.path_info.end_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
-			p->ainew.path_info.end_direction = p->ainew.to_direction;
-		} else {
-			p->ainew.path_info.end_tile_tl = p->ainew.to_tile;
-			p->ainew.path_info.end_tile_br = p->ainew.to_tile;
-			p->ainew.path_info.end_direction = p->ainew.to_direction;
-		}
-
-		p->ainew.path_info.rail_or_road = (p->ainew.tbt == AI_TRAIN);
-
-		// First, clean the pathfinder with our new begin and endpoints
-		clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info);
-
-		p->ainew.temp = 0;
-	}
-
-	// Start the pathfinder
-	r = p->ainew.pathfinder->main(p->ainew.pathfinder);
-	switch (r) {
-		case AYSTAR_NO_PATH:
-			DEBUG(ai, 1, "No route found by pathfinder");
-			// Start all over again
-			p->ainew.state = AI_STATE_NOTHING;
-			break;
-
-		case AYSTAR_FOUND_END_NODE: // We found the end-point
-			p->ainew.temp = -1;
-			p->ainew.state = AI_STATE_FIND_DEPOT;
-			break;
-
-		// In any other case, we are still busy finding the route
-		default: break;
-	}
-}
-
-
-// This function tries to locate a good place for a depot!
-static void AiNew_State_FindDepot(Player *p)
-{
-	// To place the depot, we walk through the route, and if we find a lovely spot (MP_CLEAR, MP_TREES), we place it there..
-	// Simple, easy, works!
-	// To make the depot stand in the middle of the route, we start from the center..
-	// But first we walk through the route see if we can find a depot that is ours
-	//  this keeps things nice ;)
-	int g, i, r;
-	DiagDirection j;
-	TileIndex tile;
-	assert(p->ainew.state == AI_STATE_FIND_DEPOT);
-
-	p->ainew.depot_tile = 0;
-
-	for (i=2;i<p->ainew.path_info.route_length-2;i++) {
-		tile = p->ainew.path_info.route[i];
-		for (j = 0; j < 4; j++) {
-			TileIndex t = tile + TileOffsByDiagDir(j);
-
-			if (IsTileType(t, MP_STREET) &&
-					GetRoadTileType(t) == ROAD_TILE_DEPOT &&
-					IsTileOwner(t, _current_player) &&
-					GetRoadDepotDirection(t) == ReverseDiagDir(j)) {
-				p->ainew.depot_tile = t;
-				p->ainew.depot_direction = ReverseDiagDir(j);
-				p->ainew.state = AI_STATE_VERIFY_ROUTE;
-				return;
-			}
-		}
-	}
-
-	// This routine let depot finding start in the middle, and work his way to the stations
-	// It makes depot placing nicer :)
-	i = p->ainew.path_info.route_length / 2;
-	g = 1;
-	while (i > 1 && i < p->ainew.path_info.route_length - 2) {
-		i += g;
-		g *= -1;
-		(g < 0?g--:g++);
-
-		if (p->ainew.path_info.route_extra[i] != 0 || p->ainew.path_info.route_extra[i+1] != 0) {
-			// Bridge or tunnel.. we can't place a depot there
-			continue;
-		}
-
-		tile = p->ainew.path_info.route[i];
-
-		for (j = 0; j < 4; j++) {
-			TileIndex t = tile + TileOffsByDiagDir(j);
-
-			// It may not be placed on the road/rail itself
-			// And because it is not build yet, we can't see it on the tile..
-			// So check the surrounding tiles :)
-			if (t == p->ainew.path_info.route[i - 1] ||
-					t == p->ainew.path_info.route[i + 1]) {
-				continue;
-			}
-			// Not around a bridge?
-			if (p->ainew.path_info.route_extra[i] != 0) continue;
-			if (IsTileType(tile, MP_TUNNELBRIDGE)) continue;
-			// Is the terrain clear?
-			if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) {
-				// If the current tile is on a slope then we do not allow this
-				if (GetTileSlope(tile, NULL) != SLOPE_FLAT) continue;
-				// Check if everything went okay..
-				r = AiNew_Build_Depot(p, t, ReverseDiagDir(j), 0);
-				if (CmdFailed(r)) continue;
-				// Found a spot!
-				p->ainew.new_cost += r;
-				p->ainew.depot_tile = t;
-				p->ainew.depot_direction = ReverseDiagDir(j); // Reverse direction
-				p->ainew.state = AI_STATE_VERIFY_ROUTE;
-				return;
-			}
-		}
-	}
-
-	// Failed to find a depot?
-	p->ainew.state = AI_STATE_NOTHING;
-}
-
-
-// This function calculates how many vehicles there are needed on this
-//  traject.
-// It works pretty simple: get the length, see how much we move around
-//  and hussle that, and you know how many vehicles there are needed.
-// It returns the cost for the vehicles
-static int AiNew_HowManyVehicles(Player *p)
-{
-	if (p->ainew.tbt == AI_BUS) {
-		// For bus-routes we look at the time before we are back in the station
-		EngineID i;
-		int length, tiles_a_day;
-		int amount;
-		i = AiNew_PickVehicle(p);
-		if (i == INVALID_ENGINE) return 0;
-		// Passenger run.. how long is the route?
-		length = p->ainew.path_info.route_length;
-		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
-		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
-		// We want a vehicle in a station once a month at least, so, calculate it!
-		// (the * 2 is because we have 2 stations ;))
-		amount = length * 2 * 2 / tiles_a_day / 30;
-		if (amount == 0) amount = 1;
-		return amount;
-	} else if (p->ainew.tbt == AI_TRUCK) {
-		// For truck-routes we look at the cargo
-		EngineID i;
-		int length, amount, tiles_a_day;
-		int max_cargo;
-		i = AiNew_PickVehicle(p);
-		if (i == INVALID_ENGINE) return 0;
-		// Passenger run.. how long is the route?
-		length = p->ainew.path_info.route_length;
-		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
-		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
-		if (p->ainew.from_deliver) {
-			max_cargo = GetIndustry(p->ainew.from_ic)->total_production[0];
-		} else {
-			max_cargo = GetIndustry(p->ainew.to_ic)->total_production[0];
-		}
-
-		// This is because moving 60% is more than we can dream of!
-		max_cargo *= 0.6;
-		// We want all the cargo to be gone in a month.. so, we know the cargo it delivers
-		//  we know what the vehicle takes with him, and we know the time it takes him
-		//  to get back here.. now let's do some math!
-		amount = 2 * length * max_cargo / tiles_a_day / 30 / RoadVehInfo(i)->capacity;
-		amount += 1;
-		return amount;
-	} else {
-		// Currently not supported
-		return 0;
-	}
-}
-
-
-// This function checks:
-//   - If the route went okay
-//   - Calculates the amount of money needed to build the route
-//   - Calculates how much vehicles needed for the route
-static void AiNew_State_VerifyRoute(Player *p)
-{
-	int res, i;
-	assert(p->ainew.state == AI_STATE_VERIFY_ROUTE);
-
-	// Let's calculate the cost of the path..
-	//  new_cost already contains the cost of the stations
-	p->ainew.path_info.position = -1;
-
-	do {
-		p->ainew.path_info.position++;
-		p->ainew.new_cost += AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_QUERY_COST);
-	} while (p->ainew.path_info.position != -2);
-
-	// Now we know the price of build station + path. Now check how many vehicles
-	//  we need and what the price for that will be
-	res = AiNew_HowManyVehicles(p);
-	// If res == 0, no vehicle was found, or an other problem did occour
-	if (res == 0) {
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-	p->ainew.amount_veh = res;
-	p->ainew.cur_veh = 0;
-
-	// Check how much it it going to cost us..
-	for (i=0;i<res;i++) {
-		p->ainew.new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST);
-	}
-
-	// Now we know how much the route is going to cost us
-	//  Check if we have enough money for it!
-	if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) {
-		// Too bad..
-		DEBUG(ai, 1, "Insufficient funds to build route (%d)", p->ainew.new_cost);
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-
-	// Now we can build the route, check the direction of the stations!
-	if (p->ainew.from_direction == AI_PATHFINDER_NO_DIRECTION) {
-		p->ainew.from_direction = AiNew_GetDirection(p->ainew.path_info.route[p->ainew.path_info.route_length-1], p->ainew.path_info.route[p->ainew.path_info.route_length-2]);
-	}
-	if (p->ainew.to_direction == AI_PATHFINDER_NO_DIRECTION) {
-		p->ainew.to_direction = AiNew_GetDirection(p->ainew.path_info.route[0], p->ainew.path_info.route[1]);
-	}
-	if (p->ainew.from_tile == AI_STATION_RANGE)
-		p->ainew.from_tile = p->ainew.path_info.route[p->ainew.path_info.route_length-1];
-	if (p->ainew.to_tile == AI_STATION_RANGE)
-		p->ainew.to_tile = p->ainew.path_info.route[0];
-
-	p->ainew.state = AI_STATE_BUILD_STATION;
-	p->ainew.temp = 0;
-
-	DEBUG(ai, 1, "The route is set and buildable, building 0x%X to 0x%X...", p->ainew.from_tile, p->ainew.to_tile);
-}
-
-
-// Build the stations
-static void AiNew_State_BuildStation(Player *p)
-{
-	int res = 0;
-	assert(p->ainew.state == AI_STATE_BUILD_STATION);
-	if (p->ainew.temp == 0) {
-		if (!IsTileType(p->ainew.from_tile, MP_STATION))
-			res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.from_tile, 0, 0, p->ainew.from_direction, DC_EXEC);
-	} else {
-		if (!IsTileType(p->ainew.to_tile, MP_STATION))
-			res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.to_tile, 0, 0, p->ainew.to_direction, DC_EXEC);
-		p->ainew.state = AI_STATE_BUILD_PATH;
-	}
-	if (CmdFailed(res)) {
-		DEBUG(ai, 0, "[BuildStation] station could not be built (0x%X)", p->ainew.to_tile);
-		p->ainew.state = AI_STATE_NOTHING;
-		// If the first station _was_ build, destroy it
-		if (p->ainew.temp != 0)
-			AI_DoCommand(p->ainew.from_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		return;
-	}
-	p->ainew.temp++;
-}
-
-
-// Build the path
-static void AiNew_State_BuildPath(Player *p)
-{
-	assert(p->ainew.state == AI_STATE_BUILD_PATH);
-	// p->ainew.temp is set to -1 when this function is called for the first time
-	if (p->ainew.temp == -1) {
-		DEBUG(ai, 1, "Starting to build new path");
-		// Init the counter
-		p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1;
-		// Set the position to the startingplace (-1 because in a minute we do ++)
-		p->ainew.path_info.position = -1;
-		// And don't do this again
-		p->ainew.temp = 0;
-	}
-	// Building goes very fast on normal rate, so we are going to slow it down..
-	//  By let the counter count from AI_BUILDPATH_PAUSE to 0, we have a nice way :)
-	if (--p->ainew.counter != 0) return;
-	p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1;
-
-	// Increase the building position
-	p->ainew.path_info.position++;
-	// Build route
-	AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_EXEC);
-	if (p->ainew.path_info.position == -2) {
-		// This means we are done building!
-
-		if (p->ainew.tbt == AI_TRUCK && !_patches.roadveh_queue) {
-			// If they not queue, they have to go up and down to try again at a station...
-			// We don't want that, so try building some road left or right of the station
-			int dir1, dir2, dir3;
-			TileIndex tile;
-			int i, ret;
-			for (i=0;i<2;i++) {
-				if (i == 0) {
-					tile = p->ainew.from_tile + TileOffsByDiagDir(p->ainew.from_direction);
-					dir1 = p->ainew.from_direction - 1;
-					if (dir1 < 0) dir1 = 3;
-					dir2 = p->ainew.from_direction + 1;
-					if (dir2 > 3) dir2 = 0;
-					dir3 = p->ainew.from_direction;
-				} else {
-					tile = p->ainew.to_tile + TileOffsByDiagDir(p->ainew.to_direction);
-					dir1 = p->ainew.to_direction - 1;
-					if (dir1 < 0) dir1 = 3;
-					dir2 = p->ainew.to_direction + 1;
-					if (dir2 > 3) dir2 = 0;
-					dir3 = p->ainew.to_direction;
-				}
-
-				ret = AI_DoCommand(tile, DiagDirToRoadBits(ReverseDiagDir(dir1)), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-				if (!CmdFailed(ret)) {
-					dir1 = TileOffsByDiagDir(dir1);
-					if (IsTileType(tile + dir1, MP_CLEAR) || IsTileType(tile + dir1, MP_TREES)) {
-						ret = AI_DoCommand(tile+dir1, AiNew_GetRoadDirection(tile, tile+dir1, tile+dir1+dir1), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						if (!CmdFailed(ret)) {
-							if (IsTileType(tile + dir1 + dir1, MP_CLEAR) || IsTileType(tile + dir1 + dir1, MP_TREES))
-								AI_DoCommand(tile+dir1+dir1, AiNew_GetRoadDirection(tile+dir1, tile+dir1+dir1, tile+dir1+dir1+dir1), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						}
-					}
-				}
-
-				ret = AI_DoCommand(tile, DiagDirToRoadBits(ReverseDiagDir(dir2)), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-				if (!CmdFailed(ret)) {
-					dir2 = TileOffsByDiagDir(dir2);
-					if (IsTileType(tile + dir2, MP_CLEAR) || IsTileType(tile + dir2, MP_TREES)) {
-						ret = AI_DoCommand(tile+dir2, AiNew_GetRoadDirection(tile, tile+dir2, tile+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						if (!CmdFailed(ret)) {
-							if (IsTileType(tile + dir2 + dir2, MP_CLEAR) || IsTileType(tile + dir2 + dir2, MP_TREES))
-								AI_DoCommand(tile+dir2+dir2, AiNew_GetRoadDirection(tile+dir2, tile+dir2+dir2, tile+dir2+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						}
-					}
-				}
-
-				ret = AI_DoCommand(tile, DiagDirToRoadBits(dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-				if (!CmdFailed(ret)) {
-					dir3 = TileOffsByDiagDir(dir3);
-					if (IsTileType(tile + dir3, MP_CLEAR) || IsTileType(tile + dir3, MP_TREES)) {
-						ret = AI_DoCommand(tile+dir3, AiNew_GetRoadDirection(tile, tile+dir3, tile+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						if (!CmdFailed(ret)) {
-							if (IsTileType(tile + dir3 + dir3, MP_CLEAR) || IsTileType(tile + dir3 + dir3, MP_TREES))
-								AI_DoCommand(tile+dir3+dir3, AiNew_GetRoadDirection(tile+dir3, tile+dir3+dir3, tile+dir3+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
-						}
-					}
-				}
-			}
-		}
-
-		DEBUG(ai, 1, "Finished building path, cost: %d", p->ainew.new_cost);
-		p->ainew.state = AI_STATE_BUILD_DEPOT;
-	}
-}
-
-
-// Builds the depot
-static void AiNew_State_BuildDepot(Player *p)
-{
-	int res = 0;
-	assert(p->ainew.state == AI_STATE_BUILD_DEPOT);
-
-	if (IsTileType(p->ainew.depot_tile, MP_STREET) && GetRoadTileType(p->ainew.depot_tile) == ROAD_TILE_DEPOT) {
-		if (IsTileOwner(p->ainew.depot_tile, _current_player)) {
-			// The depot is already built
-			p->ainew.state = AI_STATE_BUILD_VEHICLE;
-			return;
-		} else {
-			// There is a depot, but not of our team! :(
-			p->ainew.state = AI_STATE_NOTHING;
-			return;
-		}
-	}
-
-	// There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p)
-	if (!EnsureNoVehicle(p->ainew.depot_tile + TileOffsByDiagDir(p->ainew.depot_direction)))
-		return;
-
-	res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC);
-	if (CmdFailed(res)) {
-		DEBUG(ai, 0, "[BuildDepot] depot could not be built (0x%X)", p->ainew.depot_tile);
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-
-	p->ainew.state = AI_STATE_BUILD_VEHICLE;
-	p->ainew.idle = 10;
-	p->ainew.veh_main_id = INVALID_VEHICLE;
-}
-
-
-// Build vehicles
-static void AiNew_State_BuildVehicle(Player *p)
-{
-	int res;
-	assert(p->ainew.state == AI_STATE_BUILD_VEHICLE);
-
-	// Check if we need to build a vehicle
-	if (p->ainew.amount_veh == 0) {
-		// Nope, we are done!
-		// This means: we are all done! The route is open.. go back to NOTHING
-		//  He will idle some time and it will all start over again.. :)
-		p->ainew.state = AI_STATE_ACTION_DONE;
-		return;
-	}
-	if (--p->ainew.idle != 0) return;
-	// It is realistic that the AI can only build 1 vehicle a day..
-	// This makes sure of that!
-	p->ainew.idle = AI_BUILD_VEHICLE_TIME_BETWEEN;
-
-	// Build the vehicle
-	res = AiNew_Build_Vehicle(p, p->ainew.depot_tile, DC_EXEC);
-	if (CmdFailed(res)) {
-		// This happens when the AI can't build any more vehicles!
-		p->ainew.state = AI_STATE_NOTHING;
-		return;
-	}
-	// Increase the current counter
-	p->ainew.cur_veh++;
-	// Decrease the total counter
-	p->ainew.amount_veh--;
-	// Go give some orders!
-	p->ainew.state = AI_STATE_WAIT_FOR_BUILD;
-}
-
-
-// Put the stations in the order list
-static void AiNew_State_GiveOrders(Player *p)
-{
-	int idx;
-	Order order;
-
-	assert(p->ainew.state == AI_STATE_GIVE_ORDERS);
-
-	if (p->ainew.veh_main_id != INVALID_VEHICLE) {
-		AI_DoCommand(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER);
-
-		p->ainew.state = AI_STATE_START_VEHICLE;
-		return;
-	} else {
-		p->ainew.veh_main_id = p->ainew.veh_id;
-	}
-
-	// Very handy for AI, goto depot.. but yeah, it needs to be activated ;)
-	if (_patches.gotodepot) {
-		idx = 0;
-		order.type = OT_GOTO_DEPOT;
-		order.flags = OF_UNLOAD;
-		order.dest = GetDepotByTile(p->ainew.depot_tile)->index;
-		AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-	}
-
-	idx = 0;
-	order.type = OT_GOTO_STATION;
-	order.flags = 0;
-	order.dest = GetStationIndex(p->ainew.to_tile);
-	if (p->ainew.tbt == AI_TRUCK && p->ainew.to_deliver)
-		order.flags |= OF_FULL_LOAD;
-	AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-
-	idx = 0;
-	order.type = OT_GOTO_STATION;
-	order.flags = 0;
-	order.dest = GetStationIndex(p->ainew.from_tile);
-	if (p->ainew.tbt == AI_TRUCK && p->ainew.from_deliver)
-		order.flags |= OF_FULL_LOAD;
-	AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
-
-	// Start the engines!
-	p->ainew.state = AI_STATE_START_VEHICLE;
-}
-
-
-// Start the vehicle
-static void AiNew_State_StartVehicle(Player *p)
-{
-	assert(p->ainew.state == AI_STATE_START_VEHICLE);
-
-	// Skip the first order if it is a second vehicle
-	//  This to make vehicles go different ways..
-	if (p->ainew.cur_veh & 1)
-		AI_DoCommand(0, p->ainew.veh_id, 0, DC_EXEC, CMD_SKIP_ORDER);
-
-	// 3, 2, 1... go! (give START_STOP command ;))
-	AI_DoCommand(0, p->ainew.veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
-	// Try to build an other vehicle (that function will stop building when needed)
-	p->ainew.idle  = 10;
-	p->ainew.state = AI_STATE_BUILD_VEHICLE;
-}
-
-
-// Repays money
-static void AiNew_State_RepayMoney(Player *p)
-{
-	uint i;
-
-	for (i = 0; i < AI_LOAN_REPAY; i++) {
-		AI_DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN);
-	}
-	p->ainew.state = AI_STATE_ACTION_DONE;
-}
-
-
-static void AiNew_CheckVehicle(Player *p, Vehicle *v)
-{
-	// When a vehicle is under the 6 months, we don't check for anything
-	if (v->age < 180) return;
-
-	// When a vehicle is older then 1 year, it should make money...
-	if (v->age > 360) {
-		// If both years together are not more than AI_MINIMUM_ROUTE_PROFIT,
-		//  it is not worth the line I guess...
-		if (v->profit_last_year + v->profit_this_year < AI_MINIMUM_ROUTE_PROFIT ||
-				(v->reliability * 100 >> 16) < 40) {
-			// There is a possibility that the route is fucked up...
-			if (v->cargo_days > AI_VEHICLE_LOST_DAYS) {
-				// The vehicle is lost.. check the route, or else, get the vehicle
-				//  back to a depot
-				// TODO: make this piece of code
-			}
-
-
-			// We are already sending him back
-			if (AiNew_GetSpecialVehicleFlag(p, v) & AI_VEHICLEFLAG_SELL) {
-				if (v->type == VEH_Road && IsTileDepotType(v->tile, TRANSPORT_ROAD) &&
-						(v->vehstatus&VS_STOPPED)) {
-					// We are at the depot, sell the vehicle
-					AI_DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
-				}
-				return;
-			}
-
-			if (!AiNew_SetSpecialVehicleFlag(p, v, AI_VEHICLEFLAG_SELL)) return;
-			{
-				int ret = 0;
-				if (v->type == VEH_Road)
-					ret = AI_DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
-				// This means we can not find a depot :s
-				//				if (CmdFailed(ret))
-			}
-		}
-	}
-}
-
-
-// Checks all vehicles if they are still valid and make money and stuff
-static void AiNew_State_CheckAllVehicles(Player *p)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->owner != p->index) continue;
-		// Currently, we only know how to handle road-vehicles
-		if (v->type != VEH_Road) continue;
-
-		AiNew_CheckVehicle(p, v);
-	}
-
-	p->ainew.state = AI_STATE_ACTION_DONE;
-}
-
-
-// Using the technique simular to the original AI
-//   Keeps things logical
-// It really should be in the same order as the AI_STATE's are!
-static AiNew_StateFunction* const _ainew_state[] = {
-	NULL,
-	AiNew_State_FirstTime,
-	AiNew_State_Nothing,
-	AiNew_State_WakeUp,
-	AiNew_State_LocateRoute,
-	AiNew_State_FindStation,
-	AiNew_State_FindPath,
-	AiNew_State_FindDepot,
-	AiNew_State_VerifyRoute,
-	AiNew_State_BuildStation,
-	AiNew_State_BuildPath,
-	AiNew_State_BuildDepot,
-	AiNew_State_BuildVehicle,
-	NULL,
-	AiNew_State_GiveOrders,
-	AiNew_State_StartVehicle,
-	AiNew_State_RepayMoney,
-	AiNew_State_CheckAllVehicles,
-	AiNew_State_ActionDone,
-	NULL,
-};
-
-static void AiNew_OnTick(Player *p)
-{
-	if (_ainew_state[p->ainew.state] != NULL)
-		_ainew_state[p->ainew.state](p);
-}
-
-
-void AiNewDoGameLoop(Player *p)
-{
-	if (p->ainew.state == AI_STATE_STARTUP) {
-		// The AI just got alive!
-		p->ainew.state = AI_STATE_FIRST_TIME;
-		p->ainew.tick = 0;
-
-		// Only startup the AI
-		return;
-	}
-
-	// We keep a ticker. We use it for competitor_speed
-	p->ainew.tick++;
-
-	// If we come here, we can do a tick.. do so!
-	AiNew_OnTick(p);
-}
new file mode 100644
--- /dev/null
+++ b/src/ai/trolly/trolly.cpp
@@ -0,0 +1,1353 @@
+/* $Id$ */
+
+/*
+ * This AI was created as a direct reaction to the big demand for some good AIs
+ * in OTTD. Too bad it never left alpha-stage, and it is considered dead in its
+ * current form.
+ * By the time of writing this, we, the creator of this AI and a good friend of
+ * mine, are designing a whole new AI-system that allows us to create AIs
+ * easier and without all the fuzz we encountered while I was working on this
+ * AI. By the time that system is finished, you can expect that this AI will
+ * dissapear, because it is pretty obselete and bad programmed.
+ *
+ * Meanwhile I wish you all much fun with this AI; if you are interested as
+ * AI-developer in this AI, I advise you not stare too long to some code, some
+ * things in here really are... strange ;) But in either way: enjoy :)
+ *
+ *  -- TrueLight :: 2005-09-01
+ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../debug.h"
+#include "../../functions.h"
+#include "../../road_map.h"
+#include "../../station_map.h"
+#include "table/strings.h"
+#include "../../map.h"
+#include "../../tile.h"
+#include "../../command.h"
+#include "trolly.h"
+#include "../../town.h"
+#include "../../industry.h"
+#include "../../station.h"
+#include "../../engine.h"
+#include "../../gui.h"
+#include "../../depot.h"
+#include "../../vehicle.h"
+#include "../../date.h"
+#include "../ai.h"
+
+// This function is called after StartUp. It is the init of an AI
+static void AiNew_State_FirstTime(Player *p)
+{
+	// This assert is used to protect those function from misuse
+	//   You have quickly a small mistake in the state-array
+	//   With that, everything would go wrong. Finding that, is almost impossible
+	//   With this assert, that problem can never happen.
+	assert(p->ainew.state == AI_STATE_FIRST_TIME);
+	// We first have to init some things
+
+	if (_current_player == 1) ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_IN_PROGRESS, 0, 0);
+
+	// The PathFinder (AyStar)
+	// TODO: Maybe when an AI goes bankrupt, this is de-init
+	//  or when coming from a savegame.. should be checked out!
+	p->ainew.path_info.start_tile_tl = 0;
+	p->ainew.path_info.start_tile_br = 0;
+	p->ainew.path_info.end_tile_tl = 0;
+	p->ainew.path_info.end_tile_br = 0;
+	p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info);
+
+	p->ainew.idle = 0;
+	p->ainew.last_vehiclecheck_date = _date;
+
+	// We ALWAYS start with a bus route.. just some basic money ;)
+	p->ainew.action = AI_ACTION_BUS_ROUTE;
+
+	// Let's popup the news, and after that, start building..
+	p->ainew.state = AI_STATE_WAKE_UP;
+}
+
+
+// This function just waste some time
+//  It keeps it more real. The AI can build on such tempo no normal user
+//  can ever keep up with that. The competitor_speed already delays a bit
+//  but after the AI finished a track it really needs to go to sleep.
+//
+// Let's say, we sleep between one and three days if the AI is put on Very Fast.
+//  This means that on Very Slow it will be between 16 and 48 days.. slow enough?
+static void AiNew_State_Nothing(Player *p)
+{
+	assert(p->ainew.state == AI_STATE_NOTHING);
+	// If we are done idling, start over again
+	if (p->ainew.idle == 0) p->ainew.idle = AI_RandomRange(DAY_TICKS * 2) + DAY_TICKS;
+	if (--p->ainew.idle == 0) {
+		// We are done idling.. what you say? Let's do something!
+		// I mean.. the next tick ;)
+		p->ainew.state = AI_STATE_WAKE_UP;
+	}
+}
+
+
+// This function picks out a task we are going to do.
+//  Currently supported:
+//    - Make new route
+//    - Check route
+//    - Build HQ
+static void AiNew_State_WakeUp(Player *p)
+{
+	int32 money;
+	int c;
+	assert(p->ainew.state == AI_STATE_WAKE_UP);
+	// First, check if we have a HQ
+	if (p->location_of_house == 0) {
+		// We have no HQ yet, build one on a random place
+		// Random till we found a place for it!
+		// TODO: this should not be on a random place..
+		AiNew_Build_CompanyHQ(p, AI_Random() % MapSize());
+		// Enough for now, but we want to come back here the next time
+		//  so we do not change any status
+		return;
+	}
+
+	money = p->player_money - AI_MINIMUM_MONEY;
+
+	// Let's pick an action!
+	if (p->ainew.action == AI_ACTION_NONE) {
+		c = AI_Random() & 0xFF;
+		if (p->current_loan > 0 &&
+				p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN &&
+				c < 10) {
+			p->ainew.action = AI_ACTION_REPAY_LOAN;
+		} else if (p->ainew.last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) {
+			// Check all vehicles once in a while
+			p->ainew.action = AI_ACTION_CHECK_ALL_VEHICLES;
+			p->ainew.last_vehiclecheck_date = _date;
+		} else if (c < 100 && !_patches.ai_disable_veh_roadveh) {
+			// Do we have any spots for road-vehicles left open?
+			if (GetFreeUnitNumber(VEH_Road) <= _patches.max_roadveh) {
+				if (c < 85) {
+					p->ainew.action = AI_ACTION_TRUCK_ROUTE;
+				} else {
+					p->ainew.action = AI_ACTION_BUS_ROUTE;
+				}
+			}
+#if 0
+		} else if (c < 200 && !_patches.ai_disable_veh_train) {
+			if (GetFreeUnitNumber(VEH_Train) <= _patches.max_trains) {
+				p->ainew.action = AI_ACTION_TRAIN_ROUTE;
+			}
+#endif
+		}
+
+		p->ainew.counter = 0;
+	}
+
+	if (p->ainew.counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) {
+		p->ainew.action = AI_ACTION_NONE;
+		return;
+	}
+
+	if (_patches.ai_disable_veh_roadveh && (
+				p->ainew.action == AI_ACTION_BUS_ROUTE ||
+				p->ainew.action == AI_ACTION_TRUCK_ROUTE
+			)) {
+		p->ainew.action = AI_ACTION_NONE;
+		return;
+	}
+
+	if (p->ainew.action == AI_ACTION_REPAY_LOAN &&
+			money > AI_MINIMUM_LOAN_REPAY_MONEY) {
+		// We start repaying some money..
+		p->ainew.state = AI_STATE_REPAY_MONEY;
+		return;
+	}
+
+	if (p->ainew.action == AI_ACTION_CHECK_ALL_VEHICLES) {
+		p->ainew.state = AI_STATE_CHECK_ALL_VEHICLES;
+		return;
+	}
+
+	// It is useless to start finding a route if we don't have enough money
+	//  to build the route anyway..
+	if (p->ainew.action == AI_ACTION_BUS_ROUTE &&
+			money > AI_MINIMUM_BUS_ROUTE_MONEY) {
+		if (GetFreeUnitNumber(VEH_Road) > _patches.max_roadveh) {
+			p->ainew.action = AI_ACTION_NONE;
+			return;
+		}
+		p->ainew.cargo = AI_NEED_CARGO;
+		p->ainew.state = AI_STATE_LOCATE_ROUTE;
+		p->ainew.tbt = AI_BUS; // Bus-route
+		return;
+	}
+	if (p->ainew.action == AI_ACTION_TRUCK_ROUTE &&
+			money > AI_MINIMUM_TRUCK_ROUTE_MONEY) {
+		if (GetFreeUnitNumber(VEH_Road) > _patches.max_roadveh) {
+			p->ainew.action = AI_ACTION_NONE;
+			return;
+		}
+		p->ainew.cargo = AI_NEED_CARGO;
+		p->ainew.last_id = 0;
+		p->ainew.state = AI_STATE_LOCATE_ROUTE;
+		p->ainew.tbt = AI_TRUCK;
+		return;
+	}
+
+	p->ainew.state = AI_STATE_NOTHING;
+}
+
+
+static void AiNew_State_ActionDone(Player *p)
+{
+	p->ainew.action = AI_ACTION_NONE;
+	p->ainew.state = AI_STATE_NOTHING;
+}
+
+
+// Check if a city or industry is good enough to start a route there
+static bool AiNew_Check_City_or_Industry(Player *p, int ic, byte type)
+{
+	if (type == AI_CITY) {
+		const Town* t = GetTown(ic);
+		const Station* st;
+		uint count = 0;
+		int j = 0;
+
+		// We don't like roadconstructions, don't even true such a city
+		if (t->road_build_months != 0) return false;
+
+		// Check if the rating in a city is high enough
+		//  If not, take a chance if we want to continue
+		if (t->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
+
+		if (t->max_pass - t->act_pass < AI_CHECKCITY_NEEDED_CARGO && !AI_CHANCE16(1,AI_CHECKCITY_CITY_CHANCE)) return false;
+
+		// Check if we have build a station in this town the last 6 months
+		//  else we don't do it. This is done, because stat updates can be slow
+		//  and sometimes it takes up to 4 months before the stats are corectly.
+		//  This way we don't get 12 busstations in one city of 100 population ;)
+		FOR_ALL_STATIONS(st) {
+			// Do we own it?
+			if (st->owner == _current_player) {
+				// Are we talking busses?
+				if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) != FACIL_BUS_STOP) continue;
+				// Is it the same city as we are in now?
+				if (st->town != t) continue;
+				// When was this station build?
+				if (_date - st->build_date < AI_CHECKCITY_DATE_BETWEEN) return false;
+				// Cound the amount of stations in this city that we own
+				count++;
+			} else {
+				// We do not own it, request some info about the station
+				//  we want to know if this station gets the same good. If so,
+				//  we want to know its rating. If it is too high, we are not going
+				//  to build there
+				if (!st->goods[CT_PASSENGERS].last_speed) continue;
+				// Is it around our city
+				if (DistanceManhattan(st->xy, t->xy) > 10) continue;
+				// It does take this cargo.. what is his rating?
+				if (st->goods[CT_PASSENGERS].rating < AI_CHECKCITY_CARGO_RATING) continue;
+				j++;
+				// When this is the first station, we build a second with no problem ;)
+				if (j == 1) continue;
+				// The rating is high.. second station...
+				//  a little chance that we still continue
+				//  But if there are 3 stations of this size, we never go on...
+				if (j == 2 && AI_CHANCE16(1, AI_CHECKCITY_CARGO_RATING_CHANCE)) continue;
+				// We don't like this station :(
+				return false;
+			}
+		}
+
+		// We are about to add one...
+		count++;
+		// Check if we the city can provide enough cargo for this amount of stations..
+		if (count * AI_CHECKCITY_CARGO_PER_STATION > t->max_pass) return false;
+
+		// All check are okay, so we can build here!
+		return true;
+	}
+	if (type == AI_INDUSTRY) {
+		const Industry* i = GetIndustry(ic);
+		const Station* st;
+		int count = 0;
+		int j = 0;
+
+		if (i->town != NULL && i->town->ratings[_current_player] < 0 && AI_CHANCE16(1,4)) return false;
+
+		// No limits on delevering stations!
+		//  Or for industry that does not give anything yet
+		if (i->produced_cargo[0] == CT_INVALID || i->total_production[0] == 0) return true;
+
+		if (i->total_production[0] - i->total_transported[0] < AI_CHECKCITY_NEEDED_CARGO) return false;
+
+		// Check if we have build a station in this town the last 6 months
+		//  else we don't do it. This is done, because stat updates can be slow
+		//  and sometimes it takes up to 4 months before the stats are corectly.
+		FOR_ALL_STATIONS(st) {
+			// Do we own it?
+			if (st->owner == _current_player) {
+				// Are we talking trucks?
+				if (p->ainew.tbt == AI_TRUCK && (FACIL_TRUCK_STOP & st->facilities) != FACIL_TRUCK_STOP) continue;
+				// Is it the same city as we are in now?
+				if (st->town != i->town) continue;
+				// When was this station build?
+				if (_date - st->build_date < AI_CHECKCITY_DATE_BETWEEN) return false;
+				// Cound the amount of stations in this city that we own
+				count++;
+			} else {
+				// We do not own it, request some info about the station
+				//  we want to know if this station gets the same good. If so,
+				//  we want to know its rating. If it is too high, we are not going
+				//  to build there
+				if (i->produced_cargo[0] == CT_INVALID) continue;
+				// It does not take this cargo
+				if (!st->goods[i->produced_cargo[0]].last_speed) continue;
+				// Is it around our industry
+				if (DistanceManhattan(st->xy, i->xy) > 5) continue;
+				// It does take this cargo.. what is his rating?
+				if (st->goods[i->produced_cargo[0]].rating < AI_CHECKCITY_CARGO_RATING) continue;
+				j++;
+				// The rating is high.. a little chance that we still continue
+				//  But if there are 2 stations of this size, we never go on...
+				if (j == 1 && AI_CHANCE16(1, AI_CHECKCITY_CARGO_RATING_CHANCE)) continue;
+				// We don't like this station :(
+				return false;
+			}
+		}
+
+		// We are about to add one...
+		count++;
+		// Check if we the city can provide enough cargo for this amount of stations..
+		if (count * AI_CHECKCITY_CARGO_PER_STATION > i->total_production[0]) return false;
+
+		// All check are okay, so we can build here!
+		return true;
+	}
+
+	return true;
+}
+
+
+// This functions tries to locate a good route
+static void AiNew_State_LocateRoute(Player *p)
+{
+	assert(p->ainew.state == AI_STATE_LOCATE_ROUTE);
+	// For now, we only support PASSENGERS, CITY and BUSSES
+
+	// We don't have a route yet
+	if (p->ainew.cargo == AI_NEED_CARGO) {
+		p->ainew.new_cost = 0; // No cost yet
+		p->ainew.temp = -1;
+		// Reset the counter
+		p->ainew.counter = 0;
+
+		p->ainew.from_ic = -1;
+		p->ainew.to_ic = -1;
+		if (p->ainew.tbt == AI_BUS) {
+			// For now we only have a passenger route
+			p->ainew.cargo = CT_PASSENGERS;
+
+			// Find a route to cities
+			p->ainew.from_type = AI_CITY;
+			p->ainew.to_type = AI_CITY;
+		} else if (p->ainew.tbt == AI_TRUCK) {
+			p->ainew.cargo = AI_NO_CARGO;
+
+			p->ainew.from_type = AI_INDUSTRY;
+			p->ainew.to_type = AI_INDUSTRY;
+		}
+
+		// Now we are doing initing, we wait one tick
+		return;
+	}
+
+	// Increase the counter and abort if it is taking too long!
+	p->ainew.counter++;
+	if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) {
+		// Switch back to doing nothing!
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+
+	// We are going to locate a city from where we are going to connect
+	if (p->ainew.from_ic == -1) {
+		if (p->ainew.temp == -1) {
+			// First, we pick a random spot to search from
+			if (p->ainew.from_type == AI_CITY) {
+				p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1);
+			} else {
+				p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1);
+			}
+		}
+
+		if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) {
+			// It was not a valid city
+			//  increase the temp with one, and return. We will come back later here
+			//  to try again
+			p->ainew.temp++;
+			if (p->ainew.from_type == AI_CITY) {
+				if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0;
+			} else {
+				if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0;
+			}
+
+			// Don't do an attempt if we are trying the same id as the last time...
+			if (p->ainew.last_id == p->ainew.temp) return;
+			p->ainew.last_id = p->ainew.temp;
+
+			return;
+		}
+
+		// We found a good city/industry, save the data of it
+		p->ainew.from_ic = p->ainew.temp;
+
+		// Start the next tick with finding a to-city
+		p->ainew.temp = -1;
+		return;
+	}
+
+	// Find a to-city
+	if (p->ainew.temp == -1) {
+		// First, we pick a random spot to search to
+		if (p->ainew.to_type == AI_CITY) {
+			p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1);
+		} else {
+			p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1);
+		}
+	}
+
+	// The same city is not allowed
+	// Also check if the city is valid
+	if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) {
+		// Maybe it is valid..
+
+		/* We need to know if they are not to far apart from eachother..
+		 * We do that by checking how much cargo we have to move and how long the
+		 * route is.
+		 */
+
+		if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) {
+			const Town* town_from = GetTown(p->ainew.from_ic);
+			const Town* town_temp = GetTown(p->ainew.temp);
+			uint distance = DistanceManhattan(town_from->xy, town_temp->xy);
+			int max_cargo;
+
+			max_cargo  = town_from->max_pass + town_temp->max_pass;
+			max_cargo -= town_from->act_pass + town_temp->act_pass;
+
+			// max_cargo is now the amount of cargo we can move between the two cities
+			// If it is more than the distance, we allow it
+			if (distance <= max_cargo * AI_LOCATEROUTE_BUS_CARGO_DISTANCE) {
+				// We found a good city/industry, save the data of it
+				p->ainew.to_ic = p->ainew.temp;
+				p->ainew.state = AI_STATE_FIND_STATION;
+
+				DEBUG(ai, 1, "[LocateRoute] found bus-route of %d tiles long (from %d to %d)",
+					distance,
+					p->ainew.from_ic,
+					p->ainew.temp
+				);
+
+				p->ainew.from_tile = 0;
+				p->ainew.to_tile = 0;
+
+				return;
+			}
+		} else if (p->ainew.tbt == AI_TRUCK) {
+			const Industry* ind_from = GetIndustry(p->ainew.from_ic);
+			const Industry* ind_temp = GetIndustry(p->ainew.temp);
+			bool found = false;
+			int max_cargo = 0;
+			uint i;
+
+			// TODO: in max_cargo, also check other cargo (beside [0])
+			// First we check if the from_ic produces cargo that this ic accepts
+			if (ind_from->produced_cargo[0] != CT_INVALID && ind_from->total_production[0] != 0) {
+				for (i = 0; i < lengthof(ind_temp->accepts_cargo); i++) {
+					if (ind_temp->accepts_cargo[i] == CT_INVALID) break;
+					if (ind_from->produced_cargo[0] == ind_temp->accepts_cargo[i]) {
+						// Found a compatible industry
+						max_cargo = ind_from->total_production[0] - ind_from->total_transported[0];
+						found = true;
+						p->ainew.from_deliver = true;
+						p->ainew.to_deliver = false;
+						break;
+					}
+				}
+			}
+			if (!found && ind_temp->produced_cargo[0] != CT_INVALID && ind_temp->total_production[0] != 0) {
+				// If not check if the current ic produces cargo that the from_ic accepts
+				for (i = 0; i < lengthof(ind_from->accepts_cargo); i++) {
+					if (ind_from->accepts_cargo[i] == CT_INVALID) break;
+					if (ind_temp->produced_cargo[0] == ind_from->accepts_cargo[i]) {
+						// Found a compatbiel industry
+						found = true;
+						max_cargo = ind_temp->total_production[0] - ind_temp->total_transported[0];
+						p->ainew.from_deliver = false;
+						p->ainew.to_deliver = true;
+						break;
+					}
+				}
+			}
+			if (found) {
+				// Yeah, they are compatible!!!
+				// Check the length against the amount of goods
+				uint distance = DistanceManhattan(ind_from->xy, ind_temp->xy);
+
+				if (distance > AI_LOCATEROUTE_TRUCK_MIN_DISTANCE &&
+						distance <= max_cargo * AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE) {
+					p->ainew.to_ic = p->ainew.temp;
+					if (p->ainew.from_deliver) {
+						p->ainew.cargo = ind_from->produced_cargo[0];
+					} else {
+						p->ainew.cargo = ind_temp->produced_cargo[0];
+					}
+					p->ainew.state = AI_STATE_FIND_STATION;
+
+					DEBUG(ai, 1, "[LocateRoute] found truck-route of %d tiles long (from %d to %d)",
+						distance,
+						p->ainew.from_ic,
+						p->ainew.temp
+					);
+
+					p->ainew.from_tile = 0;
+					p->ainew.to_tile = 0;
+
+					return;
+				}
+			}
+		}
+	}
+
+	// It was not a valid city
+	//  increase the temp with one, and return. We will come back later here
+	//  to try again
+	p->ainew.temp++;
+	if (p->ainew.to_type == AI_CITY) {
+		if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0;
+	} else {
+		if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0;
+	}
+
+	// Don't do an attempt if we are trying the same id as the last time...
+	if (p->ainew.last_id == p->ainew.temp) return;
+	p->ainew.last_id = p->ainew.temp;
+}
+
+
+// Check if there are not more than a certain amount of vehicles pointed to a certain
+//  station. This to prevent 10 busses going to one station, which gives... problems ;)
+static bool AiNew_CheckVehicleStation(Player *p, Station *st)
+{
+	int count = 0;
+	Vehicle *v;
+
+	// Also check if we don't have already a lot of busses to this city...
+	FOR_ALL_VEHICLES(v) {
+		if (v->owner == _current_player) {
+			const Order *order;
+
+			FOR_VEHICLE_ORDERS(v, order) {
+				if (order->type == OT_GOTO_STATION && GetStation(order->dest) == st) {
+					// This vehicle has this city in its list
+					count++;
+				}
+			}
+		}
+	}
+
+	if (count > AI_CHECK_MAX_VEHICLE_PER_STATION) return false;
+	return true;
+}
+
+// This function finds a good spot for a station
+static void AiNew_State_FindStation(Player *p)
+{
+	TileIndex tile;
+	Station *st;
+	int count = 0;
+	EngineID i;
+	TileIndex new_tile = 0;
+	byte direction = 0;
+	Town *town = NULL;
+	assert(p->ainew.state == AI_STATE_FIND_STATION);
+
+	if (p->ainew.from_tile == 0) {
+		// First we scan for a station in the from-city
+		if (p->ainew.from_type == AI_CITY) {
+			town = GetTown(p->ainew.from_ic);
+			tile = town->xy;
+		} else {
+			tile = GetIndustry(p->ainew.from_ic)->xy;
+		}
+	} else if (p->ainew.to_tile == 0) {
+		// Second we scan for a station in the to-city
+		if (p->ainew.to_type == AI_CITY) {
+			town = GetTown(p->ainew.to_ic);
+			tile = town->xy;
+		} else {
+			tile = GetIndustry(p->ainew.to_ic)->xy;
+		}
+	} else {
+		// Unsupported request
+		// Go to FIND_PATH
+		p->ainew.temp = -1;
+		p->ainew.state = AI_STATE_FIND_PATH;
+		return;
+	}
+
+	// First, we are going to look at the stations that already exist inside the city
+	//  If there is enough cargo left in the station, we take that station
+	//  If that is not possible, and there are more than 2 stations in the city, abort
+	i = AiNew_PickVehicle(p);
+	// Euhmz, this should not happen _EVER_
+	// Quit finding a route...
+	if (i == INVALID_ENGINE) {
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+
+	FOR_ALL_STATIONS(st) {
+		if (st->owner == _current_player) {
+			if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) == FACIL_BUS_STOP) {
+				if (st->town == town) {
+					// Check how much cargo there is left in the station
+					if ((st->goods[p->ainew.cargo].waiting_acceptance & 0xFFF) > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) {
+						if (AiNew_CheckVehicleStation(p, st)) {
+							// We did found a station that was good enough!
+							new_tile = st->xy;
+							direction = GetRoadStopDir(st->xy);
+							break;
+						}
+					}
+					count++;
+				}
+			}
+		}
+	}
+	// We are going to add a new station...
+	if (new_tile == 0) count++;
+	// No more than 2 stations allowed in a city
+	//  This is because only the best 2 stations of one cargo do get any cargo
+	if (count > 2) {
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+
+	if (new_tile == 0 && p->ainew.tbt == AI_BUS) {
+		uint x, y, i = 0;
+		int r;
+		uint best;
+		uint accepts[NUM_CARGO];
+		TileIndex found_spot[AI_FINDSTATION_TILE_RANGE*AI_FINDSTATION_TILE_RANGE*4];
+		uint found_best[AI_FINDSTATION_TILE_RANGE*AI_FINDSTATION_TILE_RANGE*4];
+		// To find a good spot we scan a range from the center, a get the point
+		//  where we get the most cargo and where it is buildable.
+		// TODO: also check for station of myself and make sure we are not
+		//   taking eachothers passangers away (bad result when it does not)
+		for (x = TileX(tile) - AI_FINDSTATION_TILE_RANGE; x <= TileX(tile) + AI_FINDSTATION_TILE_RANGE; x++) {
+			for (y = TileY(tile) - AI_FINDSTATION_TILE_RANGE; y <= TileY(tile) + AI_FINDSTATION_TILE_RANGE; y++) {
+				new_tile = TileXY(x, y);
+				if (IsTileType(new_tile, MP_CLEAR) || IsTileType(new_tile, MP_TREES)) {
+					// This tile we can build on!
+					// Check acceptance
+					// XXX - Get the catchment area
+					GetAcceptanceAroundTiles(accepts, new_tile, 1, 1, 4);
+					// >> 3 == 0 means no cargo
+					if (accepts[p->ainew.cargo] >> 3 == 0) continue;
+					// See if we can build the station
+					r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
+					if (CmdFailed(r)) continue;
+					// We can build it, so add it to found_spot
+					found_spot[i] = new_tile;
+					found_best[i++] = accepts[p->ainew.cargo];
+				}
+			}
+		}
+
+		// If i is still zero, we did not find anything
+		if (i == 0) {
+			p->ainew.state = AI_STATE_NOTHING;
+			return;
+		}
+
+		// Go through all the found_best and check which has the highest value
+		best = 0;
+		new_tile = 0;
+
+		for (x = 0; x < i; x++) {
+			if (found_best[x] > best ||
+					(found_best[x] == best && DistanceManhattan(tile, new_tile) > DistanceManhattan(tile, found_spot[x]))) {
+				new_tile = found_spot[x];
+				best = found_best[x];
+			}
+		}
+
+		// See how much it is going to cost us...
+		r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST);
+		p->ainew.new_cost += r;
+
+		direction = AI_PATHFINDER_NO_DIRECTION;
+	} else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) {
+		// Truck station locater works differently.. a station can be on any place
+		//  as long as it is in range. So we give back code AI_STATION_RANGE
+		//  so the pathfinder routine can work it out!
+		new_tile = AI_STATION_RANGE;
+		direction = AI_PATHFINDER_NO_DIRECTION;
+	}
+
+	if (p->ainew.from_tile == 0) {
+		p->ainew.from_tile = new_tile;
+		p->ainew.from_direction = direction;
+		// Now we found thisone, go in for to_tile
+		return;
+	} else if (p->ainew.to_tile == 0) {
+		p->ainew.to_tile = new_tile;
+		p->ainew.to_direction = direction;
+		// K, done placing stations!
+		p->ainew.temp = -1;
+		p->ainew.state = AI_STATE_FIND_PATH;
+		return;
+	}
+}
+
+
+// We try to find a path between 2 points
+static void AiNew_State_FindPath(Player *p)
+{
+	int r;
+	assert(p->ainew.state == AI_STATE_FIND_PATH);
+
+	// First time, init some data
+	if (p->ainew.temp == -1) {
+		// Init path_info
+		if (p->ainew.from_tile == AI_STATION_RANGE) {
+			const Industry* i = GetIndustry(p->ainew.from_ic);
+
+			// For truck routes we take a range around the industry
+			p->ainew.path_info.start_tile_tl = i->xy - TileDiffXY(1, 1);
+			p->ainew.path_info.start_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
+			p->ainew.path_info.start_direction = p->ainew.from_direction;
+		} else {
+			p->ainew.path_info.start_tile_tl = p->ainew.from_tile;
+			p->ainew.path_info.start_tile_br = p->ainew.from_tile;
+			p->ainew.path_info.start_direction = p->ainew.from_direction;
+		}
+
+		if (p->ainew.to_tile == AI_STATION_RANGE) {
+			const Industry* i = GetIndustry(p->ainew.to_ic);
+
+			p->ainew.path_info.end_tile_tl = i->xy - TileDiffXY(1, 1);
+			p->ainew.path_info.end_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1);
+			p->ainew.path_info.end_direction = p->ainew.to_direction;
+		} else {
+			p->ainew.path_info.end_tile_tl = p->ainew.to_tile;
+			p->ainew.path_info.end_tile_br = p->ainew.to_tile;
+			p->ainew.path_info.end_direction = p->ainew.to_direction;
+		}
+
+		p->ainew.path_info.rail_or_road = (p->ainew.tbt == AI_TRAIN);
+
+		// First, clean the pathfinder with our new begin and endpoints
+		clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info);
+
+		p->ainew.temp = 0;
+	}
+
+	// Start the pathfinder
+	r = p->ainew.pathfinder->main(p->ainew.pathfinder);
+	switch (r) {
+		case AYSTAR_NO_PATH:
+			DEBUG(ai, 1, "No route found by pathfinder");
+			// Start all over again
+			p->ainew.state = AI_STATE_NOTHING;
+			break;
+
+		case AYSTAR_FOUND_END_NODE: // We found the end-point
+			p->ainew.temp = -1;
+			p->ainew.state = AI_STATE_FIND_DEPOT;
+			break;
+
+		// In any other case, we are still busy finding the route
+		default: break;
+	}
+}
+
+
+// This function tries to locate a good place for a depot!
+static void AiNew_State_FindDepot(Player *p)
+{
+	// To place the depot, we walk through the route, and if we find a lovely spot (MP_CLEAR, MP_TREES), we place it there..
+	// Simple, easy, works!
+	// To make the depot stand in the middle of the route, we start from the center..
+	// But first we walk through the route see if we can find a depot that is ours
+	//  this keeps things nice ;)
+	int g, i, r;
+	DiagDirection j;
+	TileIndex tile;
+	assert(p->ainew.state == AI_STATE_FIND_DEPOT);
+
+	p->ainew.depot_tile = 0;
+
+	for (i=2;i<p->ainew.path_info.route_length-2;i++) {
+		tile = p->ainew.path_info.route[i];
+		for (j = 0; j < 4; j++) {
+			TileIndex t = tile + TileOffsByDiagDir(j);
+
+			if (IsTileType(t, MP_STREET) &&
+					GetRoadTileType(t) == ROAD_TILE_DEPOT &&
+					IsTileOwner(t, _current_player) &&
+					GetRoadDepotDirection(t) == ReverseDiagDir(j)) {
+				p->ainew.depot_tile = t;
+				p->ainew.depot_direction = ReverseDiagDir(j);
+				p->ainew.state = AI_STATE_VERIFY_ROUTE;
+				return;
+			}
+		}
+	}
+
+	// This routine let depot finding start in the middle, and work his way to the stations
+	// It makes depot placing nicer :)
+	i = p->ainew.path_info.route_length / 2;
+	g = 1;
+	while (i > 1 && i < p->ainew.path_info.route_length - 2) {
+		i += g;
+		g *= -1;
+		(g < 0?g--:g++);
+
+		if (p->ainew.path_info.route_extra[i] != 0 || p->ainew.path_info.route_extra[i+1] != 0) {
+			// Bridge or tunnel.. we can't place a depot there
+			continue;
+		}
+
+		tile = p->ainew.path_info.route[i];
+
+		for (j = 0; j < 4; j++) {
+			TileIndex t = tile + TileOffsByDiagDir(j);
+
+			// It may not be placed on the road/rail itself
+			// And because it is not build yet, we can't see it on the tile..
+			// So check the surrounding tiles :)
+			if (t == p->ainew.path_info.route[i - 1] ||
+					t == p->ainew.path_info.route[i + 1]) {
+				continue;
+			}
+			// Not around a bridge?
+			if (p->ainew.path_info.route_extra[i] != 0) continue;
+			if (IsTileType(tile, MP_TUNNELBRIDGE)) continue;
+			// Is the terrain clear?
+			if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) {
+				// If the current tile is on a slope then we do not allow this
+				if (GetTileSlope(tile, NULL) != SLOPE_FLAT) continue;
+				// Check if everything went okay..
+				r = AiNew_Build_Depot(p, t, ReverseDiagDir(j), 0);
+				if (CmdFailed(r)) continue;
+				// Found a spot!
+				p->ainew.new_cost += r;
+				p->ainew.depot_tile = t;
+				p->ainew.depot_direction = ReverseDiagDir(j); // Reverse direction
+				p->ainew.state = AI_STATE_VERIFY_ROUTE;
+				return;
+			}
+		}
+	}
+
+	// Failed to find a depot?
+	p->ainew.state = AI_STATE_NOTHING;
+}
+
+
+// This function calculates how many vehicles there are needed on this
+//  traject.
+// It works pretty simple: get the length, see how much we move around
+//  and hussle that, and you know how many vehicles there are needed.
+// It returns the cost for the vehicles
+static int AiNew_HowManyVehicles(Player *p)
+{
+	if (p->ainew.tbt == AI_BUS) {
+		// For bus-routes we look at the time before we are back in the station
+		EngineID i;
+		int length, tiles_a_day;
+		int amount;
+		i = AiNew_PickVehicle(p);
+		if (i == INVALID_ENGINE) return 0;
+		// Passenger run.. how long is the route?
+		length = p->ainew.path_info.route_length;
+		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
+		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
+		// We want a vehicle in a station once a month at least, so, calculate it!
+		// (the * 2 is because we have 2 stations ;))
+		amount = length * 2 * 2 / tiles_a_day / 30;
+		if (amount == 0) amount = 1;
+		return amount;
+	} else if (p->ainew.tbt == AI_TRUCK) {
+		// For truck-routes we look at the cargo
+		EngineID i;
+		int length, amount, tiles_a_day;
+		int max_cargo;
+		i = AiNew_PickVehicle(p);
+		if (i == INVALID_ENGINE) return 0;
+		// Passenger run.. how long is the route?
+		length = p->ainew.path_info.route_length;
+		// Calculating tiles a day a vehicle moves is not easy.. this is how it must be done!
+		tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
+		if (p->ainew.from_deliver) {
+			max_cargo = GetIndustry(p->ainew.from_ic)->total_production[0];
+		} else {
+			max_cargo = GetIndustry(p->ainew.to_ic)->total_production[0];
+		}
+
+		// This is because moving 60% is more than we can dream of!
+		max_cargo *= 0.6;
+		// We want all the cargo to be gone in a month.. so, we know the cargo it delivers
+		//  we know what the vehicle takes with him, and we know the time it takes him
+		//  to get back here.. now let's do some math!
+		amount = 2 * length * max_cargo / tiles_a_day / 30 / RoadVehInfo(i)->capacity;
+		amount += 1;
+		return amount;
+	} else {
+		// Currently not supported
+		return 0;
+	}
+}
+
+
+// This function checks:
+//   - If the route went okay
+//   - Calculates the amount of money needed to build the route
+//   - Calculates how much vehicles needed for the route
+static void AiNew_State_VerifyRoute(Player *p)
+{
+	int res, i;
+	assert(p->ainew.state == AI_STATE_VERIFY_ROUTE);
+
+	// Let's calculate the cost of the path..
+	//  new_cost already contains the cost of the stations
+	p->ainew.path_info.position = -1;
+
+	do {
+		p->ainew.path_info.position++;
+		p->ainew.new_cost += AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_QUERY_COST);
+	} while (p->ainew.path_info.position != -2);
+
+	// Now we know the price of build station + path. Now check how many vehicles
+	//  we need and what the price for that will be
+	res = AiNew_HowManyVehicles(p);
+	// If res == 0, no vehicle was found, or an other problem did occour
+	if (res == 0) {
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+	p->ainew.amount_veh = res;
+	p->ainew.cur_veh = 0;
+
+	// Check how much it it going to cost us..
+	for (i=0;i<res;i++) {
+		p->ainew.new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST);
+	}
+
+	// Now we know how much the route is going to cost us
+	//  Check if we have enough money for it!
+	if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) {
+		// Too bad..
+		DEBUG(ai, 1, "Insufficient funds to build route (%d)", p->ainew.new_cost);
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+
+	// Now we can build the route, check the direction of the stations!
+	if (p->ainew.from_direction == AI_PATHFINDER_NO_DIRECTION) {
+		p->ainew.from_direction = AiNew_GetDirection(p->ainew.path_info.route[p->ainew.path_info.route_length-1], p->ainew.path_info.route[p->ainew.path_info.route_length-2]);
+	}
+	if (p->ainew.to_direction == AI_PATHFINDER_NO_DIRECTION) {
+		p->ainew.to_direction = AiNew_GetDirection(p->ainew.path_info.route[0], p->ainew.path_info.route[1]);
+	}
+	if (p->ainew.from_tile == AI_STATION_RANGE)
+		p->ainew.from_tile = p->ainew.path_info.route[p->ainew.path_info.route_length-1];
+	if (p->ainew.to_tile == AI_STATION_RANGE)
+		p->ainew.to_tile = p->ainew.path_info.route[0];
+
+	p->ainew.state = AI_STATE_BUILD_STATION;
+	p->ainew.temp = 0;
+
+	DEBUG(ai, 1, "The route is set and buildable, building 0x%X to 0x%X...", p->ainew.from_tile, p->ainew.to_tile);
+}
+
+
+// Build the stations
+static void AiNew_State_BuildStation(Player *p)
+{
+	int res = 0;
+	assert(p->ainew.state == AI_STATE_BUILD_STATION);
+	if (p->ainew.temp == 0) {
+		if (!IsTileType(p->ainew.from_tile, MP_STATION))
+			res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.from_tile, 0, 0, p->ainew.from_direction, DC_EXEC);
+	} else {
+		if (!IsTileType(p->ainew.to_tile, MP_STATION))
+			res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.to_tile, 0, 0, p->ainew.to_direction, DC_EXEC);
+		p->ainew.state = AI_STATE_BUILD_PATH;
+	}
+	if (CmdFailed(res)) {
+		DEBUG(ai, 0, "[BuildStation] station could not be built (0x%X)", p->ainew.to_tile);
+		p->ainew.state = AI_STATE_NOTHING;
+		// If the first station _was_ build, destroy it
+		if (p->ainew.temp != 0)
+			AI_DoCommand(p->ainew.from_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		return;
+	}
+	p->ainew.temp++;
+}
+
+
+// Build the path
+static void AiNew_State_BuildPath(Player *p)
+{
+	assert(p->ainew.state == AI_STATE_BUILD_PATH);
+	// p->ainew.temp is set to -1 when this function is called for the first time
+	if (p->ainew.temp == -1) {
+		DEBUG(ai, 1, "Starting to build new path");
+		// Init the counter
+		p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1;
+		// Set the position to the startingplace (-1 because in a minute we do ++)
+		p->ainew.path_info.position = -1;
+		// And don't do this again
+		p->ainew.temp = 0;
+	}
+	// Building goes very fast on normal rate, so we are going to slow it down..
+	//  By let the counter count from AI_BUILDPATH_PAUSE to 0, we have a nice way :)
+	if (--p->ainew.counter != 0) return;
+	p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1;
+
+	// Increase the building position
+	p->ainew.path_info.position++;
+	// Build route
+	AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_EXEC);
+	if (p->ainew.path_info.position == -2) {
+		// This means we are done building!
+
+		if (p->ainew.tbt == AI_TRUCK && !_patches.roadveh_queue) {
+			// If they not queue, they have to go up and down to try again at a station...
+			// We don't want that, so try building some road left or right of the station
+			int dir1, dir2, dir3;
+			TileIndex tile;
+			int i, ret;
+			for (i=0;i<2;i++) {
+				if (i == 0) {
+					tile = p->ainew.from_tile + TileOffsByDiagDir(p->ainew.from_direction);
+					dir1 = p->ainew.from_direction - 1;
+					if (dir1 < 0) dir1 = 3;
+					dir2 = p->ainew.from_direction + 1;
+					if (dir2 > 3) dir2 = 0;
+					dir3 = p->ainew.from_direction;
+				} else {
+					tile = p->ainew.to_tile + TileOffsByDiagDir(p->ainew.to_direction);
+					dir1 = p->ainew.to_direction - 1;
+					if (dir1 < 0) dir1 = 3;
+					dir2 = p->ainew.to_direction + 1;
+					if (dir2 > 3) dir2 = 0;
+					dir3 = p->ainew.to_direction;
+				}
+
+				ret = AI_DoCommand(tile, DiagDirToRoadBits(ReverseDiagDir(dir1)), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+				if (!CmdFailed(ret)) {
+					dir1 = TileOffsByDiagDir(dir1);
+					if (IsTileType(tile + dir1, MP_CLEAR) || IsTileType(tile + dir1, MP_TREES)) {
+						ret = AI_DoCommand(tile+dir1, AiNew_GetRoadDirection(tile, tile+dir1, tile+dir1+dir1), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						if (!CmdFailed(ret)) {
+							if (IsTileType(tile + dir1 + dir1, MP_CLEAR) || IsTileType(tile + dir1 + dir1, MP_TREES))
+								AI_DoCommand(tile+dir1+dir1, AiNew_GetRoadDirection(tile+dir1, tile+dir1+dir1, tile+dir1+dir1+dir1), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						}
+					}
+				}
+
+				ret = AI_DoCommand(tile, DiagDirToRoadBits(ReverseDiagDir(dir2)), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+				if (!CmdFailed(ret)) {
+					dir2 = TileOffsByDiagDir(dir2);
+					if (IsTileType(tile + dir2, MP_CLEAR) || IsTileType(tile + dir2, MP_TREES)) {
+						ret = AI_DoCommand(tile+dir2, AiNew_GetRoadDirection(tile, tile+dir2, tile+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						if (!CmdFailed(ret)) {
+							if (IsTileType(tile + dir2 + dir2, MP_CLEAR) || IsTileType(tile + dir2 + dir2, MP_TREES))
+								AI_DoCommand(tile+dir2+dir2, AiNew_GetRoadDirection(tile+dir2, tile+dir2+dir2, tile+dir2+dir2+dir2), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						}
+					}
+				}
+
+				ret = AI_DoCommand(tile, DiagDirToRoadBits(dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+				if (!CmdFailed(ret)) {
+					dir3 = TileOffsByDiagDir(dir3);
+					if (IsTileType(tile + dir3, MP_CLEAR) || IsTileType(tile + dir3, MP_TREES)) {
+						ret = AI_DoCommand(tile+dir3, AiNew_GetRoadDirection(tile, tile+dir3, tile+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						if (!CmdFailed(ret)) {
+							if (IsTileType(tile + dir3 + dir3, MP_CLEAR) || IsTileType(tile + dir3 + dir3, MP_TREES))
+								AI_DoCommand(tile+dir3+dir3, AiNew_GetRoadDirection(tile+dir3, tile+dir3+dir3, tile+dir3+dir3+dir3), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD);
+						}
+					}
+				}
+			}
+		}
+
+		DEBUG(ai, 1, "Finished building path, cost: %d", p->ainew.new_cost);
+		p->ainew.state = AI_STATE_BUILD_DEPOT;
+	}
+}
+
+
+// Builds the depot
+static void AiNew_State_BuildDepot(Player *p)
+{
+	int res = 0;
+	assert(p->ainew.state == AI_STATE_BUILD_DEPOT);
+
+	if (IsTileType(p->ainew.depot_tile, MP_STREET) && GetRoadTileType(p->ainew.depot_tile) == ROAD_TILE_DEPOT) {
+		if (IsTileOwner(p->ainew.depot_tile, _current_player)) {
+			// The depot is already built
+			p->ainew.state = AI_STATE_BUILD_VEHICLE;
+			return;
+		} else {
+			// There is a depot, but not of our team! :(
+			p->ainew.state = AI_STATE_NOTHING;
+			return;
+		}
+	}
+
+	// There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p)
+	if (!EnsureNoVehicle(p->ainew.depot_tile + TileOffsByDiagDir(p->ainew.depot_direction)))
+		return;
+
+	res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC);
+	if (CmdFailed(res)) {
+		DEBUG(ai, 0, "[BuildDepot] depot could not be built (0x%X)", p->ainew.depot_tile);
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+
+	p->ainew.state = AI_STATE_BUILD_VEHICLE;
+	p->ainew.idle = 10;
+	p->ainew.veh_main_id = INVALID_VEHICLE;
+}
+
+
+// Build vehicles
+static void AiNew_State_BuildVehicle(Player *p)
+{
+	int res;
+	assert(p->ainew.state == AI_STATE_BUILD_VEHICLE);
+
+	// Check if we need to build a vehicle
+	if (p->ainew.amount_veh == 0) {
+		// Nope, we are done!
+		// This means: we are all done! The route is open.. go back to NOTHING
+		//  He will idle some time and it will all start over again.. :)
+		p->ainew.state = AI_STATE_ACTION_DONE;
+		return;
+	}
+	if (--p->ainew.idle != 0) return;
+	// It is realistic that the AI can only build 1 vehicle a day..
+	// This makes sure of that!
+	p->ainew.idle = AI_BUILD_VEHICLE_TIME_BETWEEN;
+
+	// Build the vehicle
+	res = AiNew_Build_Vehicle(p, p->ainew.depot_tile, DC_EXEC);
+	if (CmdFailed(res)) {
+		// This happens when the AI can't build any more vehicles!
+		p->ainew.state = AI_STATE_NOTHING;
+		return;
+	}
+	// Increase the current counter
+	p->ainew.cur_veh++;
+	// Decrease the total counter
+	p->ainew.amount_veh--;
+	// Go give some orders!
+	p->ainew.state = AI_STATE_WAIT_FOR_BUILD;
+}
+
+
+// Put the stations in the order list
+static void AiNew_State_GiveOrders(Player *p)
+{
+	int idx;
+	Order order;
+
+	assert(p->ainew.state == AI_STATE_GIVE_ORDERS);
+
+	if (p->ainew.veh_main_id != INVALID_VEHICLE) {
+		AI_DoCommand(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER);
+
+		p->ainew.state = AI_STATE_START_VEHICLE;
+		return;
+	} else {
+		p->ainew.veh_main_id = p->ainew.veh_id;
+	}
+
+	// Very handy for AI, goto depot.. but yeah, it needs to be activated ;)
+	if (_patches.gotodepot) {
+		idx = 0;
+		order.type = OT_GOTO_DEPOT;
+		order.flags = OF_UNLOAD;
+		order.dest = GetDepotByTile(p->ainew.depot_tile)->index;
+		AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+	}
+
+	idx = 0;
+	order.type = OT_GOTO_STATION;
+	order.flags = 0;
+	order.dest = GetStationIndex(p->ainew.to_tile);
+	if (p->ainew.tbt == AI_TRUCK && p->ainew.to_deliver)
+		order.flags |= OF_FULL_LOAD;
+	AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+
+	idx = 0;
+	order.type = OT_GOTO_STATION;
+	order.flags = 0;
+	order.dest = GetStationIndex(p->ainew.from_tile);
+	if (p->ainew.tbt == AI_TRUCK && p->ainew.from_deliver)
+		order.flags |= OF_FULL_LOAD;
+	AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER);
+
+	// Start the engines!
+	p->ainew.state = AI_STATE_START_VEHICLE;
+}
+
+
+// Start the vehicle
+static void AiNew_State_StartVehicle(Player *p)
+{
+	assert(p->ainew.state == AI_STATE_START_VEHICLE);
+
+	// Skip the first order if it is a second vehicle
+	//  This to make vehicles go different ways..
+	if (p->ainew.cur_veh & 1)
+		AI_DoCommand(0, p->ainew.veh_id, 0, DC_EXEC, CMD_SKIP_ORDER);
+
+	// 3, 2, 1... go! (give START_STOP command ;))
+	AI_DoCommand(0, p->ainew.veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH);
+	// Try to build an other vehicle (that function will stop building when needed)
+	p->ainew.idle  = 10;
+	p->ainew.state = AI_STATE_BUILD_VEHICLE;
+}
+
+
+// Repays money
+static void AiNew_State_RepayMoney(Player *p)
+{
+	uint i;
+
+	for (i = 0; i < AI_LOAN_REPAY; i++) {
+		AI_DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN);
+	}
+	p->ainew.state = AI_STATE_ACTION_DONE;
+}
+
+
+static void AiNew_CheckVehicle(Player *p, Vehicle *v)
+{
+	// When a vehicle is under the 6 months, we don't check for anything
+	if (v->age < 180) return;
+
+	// When a vehicle is older then 1 year, it should make money...
+	if (v->age > 360) {
+		// If both years together are not more than AI_MINIMUM_ROUTE_PROFIT,
+		//  it is not worth the line I guess...
+		if (v->profit_last_year + v->profit_this_year < AI_MINIMUM_ROUTE_PROFIT ||
+				(v->reliability * 100 >> 16) < 40) {
+			// There is a possibility that the route is fucked up...
+			if (v->cargo_days > AI_VEHICLE_LOST_DAYS) {
+				// The vehicle is lost.. check the route, or else, get the vehicle
+				//  back to a depot
+				// TODO: make this piece of code
+			}
+
+
+			// We are already sending him back
+			if (AiNew_GetSpecialVehicleFlag(p, v) & AI_VEHICLEFLAG_SELL) {
+				if (v->type == VEH_Road && IsTileDepotType(v->tile, TRANSPORT_ROAD) &&
+						(v->vehstatus&VS_STOPPED)) {
+					// We are at the depot, sell the vehicle
+					AI_DoCommand(0, v->index, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
+				}
+				return;
+			}
+
+			if (!AiNew_SetSpecialVehicleFlag(p, v, AI_VEHICLEFLAG_SELL)) return;
+			{
+				int ret = 0;
+				if (v->type == VEH_Road)
+					ret = AI_DoCommand(0, v->index, 0, DC_EXEC, CMD_SEND_ROADVEH_TO_DEPOT);
+				// This means we can not find a depot :s
+				//				if (CmdFailed(ret))
+			}
+		}
+	}
+}
+
+
+// Checks all vehicles if they are still valid and make money and stuff
+static void AiNew_State_CheckAllVehicles(Player *p)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->owner != p->index) continue;
+		// Currently, we only know how to handle road-vehicles
+		if (v->type != VEH_Road) continue;
+
+		AiNew_CheckVehicle(p, v);
+	}
+
+	p->ainew.state = AI_STATE_ACTION_DONE;
+}
+
+
+// Using the technique simular to the original AI
+//   Keeps things logical
+// It really should be in the same order as the AI_STATE's are!
+static AiNew_StateFunction* const _ainew_state[] = {
+	NULL,
+	AiNew_State_FirstTime,
+	AiNew_State_Nothing,
+	AiNew_State_WakeUp,
+	AiNew_State_LocateRoute,
+	AiNew_State_FindStation,
+	AiNew_State_FindPath,
+	AiNew_State_FindDepot,
+	AiNew_State_VerifyRoute,
+	AiNew_State_BuildStation,
+	AiNew_State_BuildPath,
+	AiNew_State_BuildDepot,
+	AiNew_State_BuildVehicle,
+	NULL,
+	AiNew_State_GiveOrders,
+	AiNew_State_StartVehicle,
+	AiNew_State_RepayMoney,
+	AiNew_State_CheckAllVehicles,
+	AiNew_State_ActionDone,
+	NULL,
+};
+
+static void AiNew_OnTick(Player *p)
+{
+	if (_ainew_state[p->ainew.state] != NULL)
+		_ainew_state[p->ainew.state](p);
+}
+
+
+void AiNewDoGameLoop(Player *p)
+{
+	if (p->ainew.state == AI_STATE_STARTUP) {
+		// The AI just got alive!
+		p->ainew.state = AI_STATE_FIRST_TIME;
+		p->ainew.tick = 0;
+
+		// Only startup the AI
+		return;
+	}
+
+	// We keep a ticker. We use it for competitor_speed
+	p->ainew.tick++;
+
+	// If we come here, we can do a tick.. do so!
+	AiNew_OnTick(p);
+}
deleted file mode 100644
--- a/src/aircraft_gui.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "aircraft.h"
-#include "debug.h"
-#include "functions.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "vehicle.h"
-#include "gfx.h"
-#include "command.h"
-#include "engine.h"
-#include "viewport.h"
-#include "player.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "newgrf_engine.h"
-
-
-void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) ShowAircraftViewWindow(GetVehicle(_new_vehicle_id));
-}
-
-static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Vehicle *v = GetVehicle(w->window_number);
-
-		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
-
-		/* Disable service-scroller when interval is set to disabled */
-		SetWindowWidgetDisabledState(w, 5, !_patches.servint_aircraft);
-		SetWindowWidgetDisabledState(w, 6, !_patches.servint_aircraft);
-
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		/* Draw running cost */
-		{
-			int year = v->age / 366;
-
-			SetDParam(1, year);
-
-			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
-			SetDParam(2, v->max_age / 366);
-			SetDParam(3, _price.aircraft_running * AircraftVehInfo(v->engine_type)->running_cost >> 8);
-			DrawString(2, 15, STR_A00D_AGE_RUNNING_COST_YR, 0);
-		}
-
-		/* Draw max speed */
-		{
-			SetDParam(0, v->max_speed * 128 / 10);
-			DrawString(2, 25, STR_A00E_MAX_SPEED, 0);
-		}
-
-		/* Draw profit */
-		{
-			SetDParam(0, v->profit_this_year);
-			SetDParam(1, v->profit_last_year);
-			DrawString(2, 35, STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
-		}
-
-		/* Draw breakdown & reliability */
-		{
-			SetDParam(0, v->reliability * 100 >> 16);
-			SetDParam(1, v->breakdowns_since_last_service);
-			DrawString(2, 45, STR_A010_RELIABILITY_BREAKDOWNS, 0);
-		}
-
-		/* Draw service interval text */
-		{
-			SetDParam(0, v->service_interval);
-			SetDParam(1, v->date_of_last_service);
-			DrawString(13, 103, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
-		}
-
-		DrawAircraftImage(v, 3, 57, INVALID_VEHICLE);
-
-		{
-			const Vehicle *u;
-			int y = 57;
-
-			do {
-				if (v->subtype <= 2) {
-					SetDParam(0, GetCustomEngineName(v->engine_type));
-					SetDParam(1, v->build_year);
-					SetDParam(2, v->value);
-					DrawString(60, y, STR_A011_BUILT_VALUE, 0);
-					y += 10;
-
-					SetDParam(0, v->cargo_type);
-					SetDParam(1, v->cargo_cap);
-					u = v->next;
-					SetDParam(2, u->cargo_type);
-					SetDParam(3, u->cargo_cap);
-					DrawString(60, y, (u->cargo_cap != 0) ? STR_A019_CAPACITY : STR_A01A_CAPACITY, 0);
-					y += 14;
-				}
-
-				if (v->cargo_count != 0) {
-
-					/* Cargo names (fix pluralness) */
-					SetDParam(0, v->cargo_type);
-					SetDParam(1, v->cargo_count);
-					SetDParam(2, v->cargo_source);
-					DrawString(60, y, STR_8813_FROM, 0);
-
-					y += 10;
-				}
-			} while ( (v=v->next) != NULL);
-		}
-	} break;
-
-	case WE_CLICK: {
-		int mod;
-		const Vehicle *v;
-		switch (e->we.click.widget) {
-		case 2: /* rename */
-			v = GetVehicle(w->window_number);
-			SetDParam(0, v->unitnumber);
-			ShowQueryString(v->string_id, STR_A030_NAME_AIRCRAFT, 31, 150, w, CS_ALPHANUMERAL);
-			break;
-		case 5: /* increase int */
-			mod = _ctrl_pressed? 5 : 10;
-			goto do_change_service_int;
-		case 6: /* decrease int */
-			mod = _ctrl_pressed?- 5 : -10;
-do_change_service_int:
-			v = GetVehicle(w->window_number);
-
-			mod = GetServiceIntervalClamped(mod + v->service_interval);
-			if (mod == v->service_interval) return;
-
-			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
-			break;
-		}
-	} break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_NAME_VEHICLE | CMD_MSG(STR_A031_CAN_T_NAME_AIRCRAFT));
-		}
-		break;
-	}
-}
-
-
-static const Widget _aircraft_details_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   349,     0,    13, STR_A00C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   350,   389,     0,    13, STR_01AA_NAME,    STR_A032_NAME_AIRCRAFT },
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   389,    14,    55, 0x0,              STR_NULL },
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   389,    56,   101, 0x0,              STR_NULL },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,   102,   107, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,   108,   113, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL },
-{      WWT_PANEL,   RESIZE_NONE,    14,    11,   389,   102,   113, 0x0,              STR_NULL },
-{   WIDGETS_END},
-};
-
-static const WindowDesc _aircraft_details_desc = {
-	WDP_AUTO, WDP_AUTO, 390, 114,
-	WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_aircraft_details_widgets,
-	AircraftDetailsWndProc
-};
-
-
-static void ShowAircraftDetailsWindow(const Vehicle *v)
-{
-	Window *w;
-	VehicleID veh = v->index;
-
-	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
-	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
-
-	w = AllocateWindowDescFront(&_aircraft_details_desc, veh);
-	w->caption_color = v->owner;
-//	w->vscroll.cap = 6;
-//	w->traindetails_d.tab = 0;
-}
-
-
-static const Widget _aircraft_view_widgets[] = {
-{   WWT_CLOSEBOX,  RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                 STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION, RESIZE_RIGHT,  14,  11, 237,   0,  13, STR_A00A,                 STR_018C_WINDOW_TITLE_DRAG_THIS },
-{  WWT_STICKYBOX,    RESIZE_LR,  14, 238, 249,   0,  13, 0x0,                      STR_STICKY_BUTTON },
-{      WWT_PANEL,    RESIZE_RB,  14,   0, 231,  14, 103, 0x0,                      STR_NULL },
-{      WWT_INSET,    RESIZE_RB,  14,   2, 229,  16, 101, 0x0,                      STR_NULL },
-{    WWT_PUSHBTN,   RESIZE_RTB,  14,   0, 237, 104, 115, 0x0,                      STR_A027_CURRENT_AIRCRAFT_ACTION },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE,  STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  32,  49, SPR_SEND_AIRCRAFT_TODEPOT,STR_A02A_SEND_AIRCRAFT_TO_HANGAR },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,        STR_A03B_REFIT_AIRCRAFT_TO_CARRY },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  68,  85, SPR_SHOW_ORDERS,          STR_A028_SHOW_AIRCRAFT_S_ORDERS },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS, STR_A02B_SHOW_AIRCRAFT_DETAILS },
-{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  32,  49, SPR_CLONE_AIRCRAFT,       STR_CLONE_AIRCRAFT_INFO },
-{      WWT_PANEL,   RESIZE_LRB,  14, 232, 249, 104, 103, 0x0,                      STR_NULL },
-{  WWT_RESIZEBOX,  RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                      STR_NULL },
-{   WIDGETS_END},
-};
-
-
-static void AircraftViewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		StringID str;
-		bool is_localplayer = v->owner == _local_player;
-
-		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
-		SetWindowWidgetDisabledState(w,  8, !IsAircraftInHangarStopped(v) || !is_localplayer);
-		SetWindowWidgetDisabledState(w, 11, !is_localplayer);
-
-
-		/* draw widgets & caption */
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		if (v->vehstatus & VS_CRASHED) {
-			str = STR_8863_CRASHED;
-		} else if (v->vehstatus & VS_STOPPED) {
-			str = STR_8861_STOPPED;
-		} else {
-			switch (v->current_order.type) {
-			case OT_GOTO_STATION: {
-				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->cur_speed * 128 / 10);
-				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
-			} break;
-
-			case OT_GOTO_DEPOT: {
-				/* Aircrafts always go to a station, even if you say depot */
-				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->cur_speed * 128 / 10);
-				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-					str = STR_HEADING_FOR_HANGAR + _patches.vehicle_speed;
-				} else {
-					str = STR_HEADING_FOR_HANGAR_SERVICE + _patches.vehicle_speed;
-				}
-			} break;
-
-			case OT_LOADING:
-				str = STR_882F_LOADING_UNLOADING;
-				break;
-
-			default:
-				if (v->num_orders == 0) {
-					str = STR_NO_ORDERS + _patches.vehicle_speed;
-					SetDParam(0, v->cur_speed * 128 / 10);
-				} else {
-					str = STR_EMPTY;
-				}
-				break;
-			}
-		}
-
-		/* draw the flag plus orders */
-		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
-		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
-		DrawWindowViewport(w);
-	} break;
-
-	case WE_CLICK: {
-		const Vehicle *v = GetVehicle(w->window_number);
-
-		switch (e->we.click.widget) {
-		case 5: /* start stop */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT));
-			break;
-		case 6: /* center main view */
-			ScrollMainWindowTo(v->x_pos, v->y_pos);
-			break;
-		case 7: /* goto hangar */
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_MSG(STR_A012_CAN_T_SEND_AIRCRAFT_TO));
-			break;
-		case 8: /* refit */
-			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
-			break;
-		case 9: /* show orders */
-			ShowOrdersWindow(v);
-			break;
-		case 10: /* show details */
-			ShowAircraftDetailsWindow(v);
-			break;
-		case 11:
-			/* clone vehicle */
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneAircraft, CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
-			break;
-		}
-	} break;
-
-	case WE_RESIZE:
-		w->viewport->width          += e->we.sizing.diff.x;
-		w->viewport->height         += e->we.sizing.diff.y;
-		w->viewport->virtual_width  += e->we.sizing.diff.x;
-		w->viewport->virtual_height += e->we.sizing.diff.y;
-		break;
-
-	case WE_DESTROY:
-		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
-		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
-		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
-		break;
-
-	case WE_MOUSELOOP: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		bool plane_stopped = IsAircraftInHangarStopped(v);
-
-		/* Widget 7 (send to hangar) must be hidden if the plane is already stopped in hangar.
-		 * Widget 11 (clone) should then be shown, since cloning is allowed only while in hangar and stopped.
-		 * This sytem allows to have two buttons, on top of each other*/
-		if (plane_stopped != IsWindowWidgetHidden(w, 7) || plane_stopped == IsWindowWidgetHidden(w, 11)) {
-			SetWindowWidgetHiddenState(w,  7, plane_stopped);  // send to hangar
-			SetWindowWidgetHiddenState(w, 11, !plane_stopped); // clone
-			SetWindowDirty(w);
-		}
-	} break;
-	}
-}
-
-
-static const WindowDesc _aircraft_view_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 116,
-	WC_VEHICLE_VIEW ,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_aircraft_view_widgets,
-	AircraftViewWndProc
-};
-
-
-void ShowAircraftViewWindow(const Vehicle *v)
-{
-	Window *w = AllocateWindowDescFront(&_aircraft_view_desc, v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/aircraft_gui.cpp
@@ -0,0 +1,350 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "aircraft.h"
+#include "debug.h"
+#include "functions.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "vehicle.h"
+#include "gfx.h"
+#include "command.h"
+#include "engine.h"
+#include "viewport.h"
+#include "player.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "newgrf_engine.h"
+
+
+void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) ShowAircraftViewWindow(GetVehicle(_new_vehicle_id));
+}
+
+static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Vehicle *v = GetVehicle(w->window_number);
+
+		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
+
+		/* Disable service-scroller when interval is set to disabled */
+		SetWindowWidgetDisabledState(w, 5, !_patches.servint_aircraft);
+		SetWindowWidgetDisabledState(w, 6, !_patches.servint_aircraft);
+
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		/* Draw running cost */
+		{
+			int year = v->age / 366;
+
+			SetDParam(1, year);
+
+			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+			SetDParam(2, v->max_age / 366);
+			SetDParam(3, _price.aircraft_running * AircraftVehInfo(v->engine_type)->running_cost >> 8);
+			DrawString(2, 15, STR_A00D_AGE_RUNNING_COST_YR, 0);
+		}
+
+		/* Draw max speed */
+		{
+			SetDParam(0, v->max_speed * 128 / 10);
+			DrawString(2, 25, STR_A00E_MAX_SPEED, 0);
+		}
+
+		/* Draw profit */
+		{
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(2, 35, STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+		}
+
+		/* Draw breakdown & reliability */
+		{
+			SetDParam(0, v->reliability * 100 >> 16);
+			SetDParam(1, v->breakdowns_since_last_service);
+			DrawString(2, 45, STR_A010_RELIABILITY_BREAKDOWNS, 0);
+		}
+
+		/* Draw service interval text */
+		{
+			SetDParam(0, v->service_interval);
+			SetDParam(1, v->date_of_last_service);
+			DrawString(13, 103, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
+		}
+
+		DrawAircraftImage(v, 3, 57, INVALID_VEHICLE);
+
+		{
+			const Vehicle *u;
+			int y = 57;
+
+			do {
+				if (v->subtype <= 2) {
+					SetDParam(0, GetCustomEngineName(v->engine_type));
+					SetDParam(1, v->build_year);
+					SetDParam(2, v->value);
+					DrawString(60, y, STR_A011_BUILT_VALUE, 0);
+					y += 10;
+
+					SetDParam(0, v->cargo_type);
+					SetDParam(1, v->cargo_cap);
+					u = v->next;
+					SetDParam(2, u->cargo_type);
+					SetDParam(3, u->cargo_cap);
+					DrawString(60, y, (u->cargo_cap != 0) ? STR_A019_CAPACITY : STR_A01A_CAPACITY, 0);
+					y += 14;
+				}
+
+				if (v->cargo_count != 0) {
+
+					/* Cargo names (fix pluralness) */
+					SetDParam(0, v->cargo_type);
+					SetDParam(1, v->cargo_count);
+					SetDParam(2, v->cargo_source);
+					DrawString(60, y, STR_8813_FROM, 0);
+
+					y += 10;
+				}
+			} while ( (v=v->next) != NULL);
+		}
+	} break;
+
+	case WE_CLICK: {
+		int mod;
+		const Vehicle *v;
+		switch (e->we.click.widget) {
+		case 2: /* rename */
+			v = GetVehicle(w->window_number);
+			SetDParam(0, v->unitnumber);
+			ShowQueryString(v->string_id, STR_A030_NAME_AIRCRAFT, 31, 150, w, CS_ALPHANUMERAL);
+			break;
+		case 5: /* increase int */
+			mod = _ctrl_pressed? 5 : 10;
+			goto do_change_service_int;
+		case 6: /* decrease int */
+			mod = _ctrl_pressed?- 5 : -10;
+do_change_service_int:
+			v = GetVehicle(w->window_number);
+
+			mod = GetServiceIntervalClamped(mod + v->service_interval);
+			if (mod == v->service_interval) return;
+
+			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+			break;
+		}
+	} break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_NAME_VEHICLE | CMD_MSG(STR_A031_CAN_T_NAME_AIRCRAFT));
+		}
+		break;
+	}
+}
+
+
+static const Widget _aircraft_details_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   349,     0,    13, STR_A00C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   350,   389,     0,    13, STR_01AA_NAME,    STR_A032_NAME_AIRCRAFT },
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   389,    14,    55, 0x0,              STR_NULL },
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   389,    56,   101, 0x0,              STR_NULL },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,   102,   107, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,   108,   113, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL },
+{      WWT_PANEL,   RESIZE_NONE,    14,    11,   389,   102,   113, 0x0,              STR_NULL },
+{   WIDGETS_END},
+};
+
+static const WindowDesc _aircraft_details_desc = {
+	WDP_AUTO, WDP_AUTO, 390, 114,
+	WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_aircraft_details_widgets,
+	AircraftDetailsWndProc
+};
+
+
+static void ShowAircraftDetailsWindow(const Vehicle *v)
+{
+	Window *w;
+	VehicleID veh = v->index;
+
+	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
+	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
+
+	w = AllocateWindowDescFront(&_aircraft_details_desc, veh);
+	w->caption_color = v->owner;
+//	w->vscroll.cap = 6;
+//	w->traindetails_d.tab = 0;
+}
+
+
+static const Widget _aircraft_view_widgets[] = {
+{   WWT_CLOSEBOX,  RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                 STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION, RESIZE_RIGHT,  14,  11, 237,   0,  13, STR_A00A,                 STR_018C_WINDOW_TITLE_DRAG_THIS },
+{  WWT_STICKYBOX,    RESIZE_LR,  14, 238, 249,   0,  13, 0x0,                      STR_STICKY_BUTTON },
+{      WWT_PANEL,    RESIZE_RB,  14,   0, 231,  14, 103, 0x0,                      STR_NULL },
+{      WWT_INSET,    RESIZE_RB,  14,   2, 229,  16, 101, 0x0,                      STR_NULL },
+{    WWT_PUSHBTN,   RESIZE_RTB,  14,   0, 237, 104, 115, 0x0,                      STR_A027_CURRENT_AIRCRAFT_ACTION },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE,  STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  32,  49, SPR_SEND_AIRCRAFT_TODEPOT,STR_A02A_SEND_AIRCRAFT_TO_HANGAR },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,        STR_A03B_REFIT_AIRCRAFT_TO_CARRY },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  68,  85, SPR_SHOW_ORDERS,          STR_A028_SHOW_AIRCRAFT_S_ORDERS },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS, STR_A02B_SHOW_AIRCRAFT_DETAILS },
+{ WWT_PUSHIMGBTN,    RESIZE_LR,  14, 232, 249,  32,  49, SPR_CLONE_AIRCRAFT,       STR_CLONE_AIRCRAFT_INFO },
+{      WWT_PANEL,   RESIZE_LRB,  14, 232, 249, 104, 103, 0x0,                      STR_NULL },
+{  WWT_RESIZEBOX,  RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                      STR_NULL },
+{   WIDGETS_END},
+};
+
+
+static void AircraftViewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		StringID str;
+		bool is_localplayer = v->owner == _local_player;
+
+		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
+		SetWindowWidgetDisabledState(w,  8, !IsAircraftInHangarStopped(v) || !is_localplayer);
+		SetWindowWidgetDisabledState(w, 11, !is_localplayer);
+
+
+		/* draw widgets & caption */
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		if (v->vehstatus & VS_CRASHED) {
+			str = STR_8863_CRASHED;
+		} else if (v->vehstatus & VS_STOPPED) {
+			str = STR_8861_STOPPED;
+		} else {
+			switch (v->current_order.type) {
+			case OT_GOTO_STATION: {
+				SetDParam(0, v->current_order.dest);
+				SetDParam(1, v->cur_speed * 128 / 10);
+				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+			} break;
+
+			case OT_GOTO_DEPOT: {
+				/* Aircrafts always go to a station, even if you say depot */
+				SetDParam(0, v->current_order.dest);
+				SetDParam(1, v->cur_speed * 128 / 10);
+				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
+					str = STR_HEADING_FOR_HANGAR + _patches.vehicle_speed;
+				} else {
+					str = STR_HEADING_FOR_HANGAR_SERVICE + _patches.vehicle_speed;
+				}
+			} break;
+
+			case OT_LOADING:
+				str = STR_882F_LOADING_UNLOADING;
+				break;
+
+			default:
+				if (v->num_orders == 0) {
+					str = STR_NO_ORDERS + _patches.vehicle_speed;
+					SetDParam(0, v->cur_speed * 128 / 10);
+				} else {
+					str = STR_EMPTY;
+				}
+				break;
+			}
+		}
+
+		/* draw the flag plus orders */
+		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
+		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
+		DrawWindowViewport(w);
+	} break;
+
+	case WE_CLICK: {
+		const Vehicle *v = GetVehicle(w->window_number);
+
+		switch (e->we.click.widget) {
+		case 5: /* start stop */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT));
+			break;
+		case 6: /* center main view */
+			ScrollMainWindowTo(v->x_pos, v->y_pos);
+			break;
+		case 7: /* goto hangar */
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_MSG(STR_A012_CAN_T_SEND_AIRCRAFT_TO));
+			break;
+		case 8: /* refit */
+			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+			break;
+		case 9: /* show orders */
+			ShowOrdersWindow(v);
+			break;
+		case 10: /* show details */
+			ShowAircraftDetailsWindow(v);
+			break;
+		case 11:
+			/* clone vehicle */
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneAircraft, CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
+			break;
+		}
+	} break;
+
+	case WE_RESIZE:
+		w->viewport->width          += e->we.sizing.diff.x;
+		w->viewport->height         += e->we.sizing.diff.y;
+		w->viewport->virtual_width  += e->we.sizing.diff.x;
+		w->viewport->virtual_height += e->we.sizing.diff.y;
+		break;
+
+	case WE_DESTROY:
+		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
+		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
+		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
+		break;
+
+	case WE_MOUSELOOP: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		bool plane_stopped = IsAircraftInHangarStopped(v);
+
+		/* Widget 7 (send to hangar) must be hidden if the plane is already stopped in hangar.
+		 * Widget 11 (clone) should then be shown, since cloning is allowed only while in hangar and stopped.
+		 * This sytem allows to have two buttons, on top of each other*/
+		if (plane_stopped != IsWindowWidgetHidden(w, 7) || plane_stopped == IsWindowWidgetHidden(w, 11)) {
+			SetWindowWidgetHiddenState(w,  7, plane_stopped);  // send to hangar
+			SetWindowWidgetHiddenState(w, 11, !plane_stopped); // clone
+			SetWindowDirty(w);
+		}
+	} break;
+	}
+}
+
+
+static const WindowDesc _aircraft_view_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 116,
+	WC_VEHICLE_VIEW ,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_aircraft_view_widgets,
+	AircraftViewWndProc
+};
+
+
+void ShowAircraftViewWindow(const Vehicle *v)
+{
+	Window *w = AllocateWindowDescFront(&_aircraft_view_desc, v->index);
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
+	}
+}
deleted file mode 100644
--- a/src/airport.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "map.h"
-#include "airport.h"
-#include "macros.h"
-#include "variables.h"
-#include "airport_movement.h"
-#include "date.h"
-
-/* Uncomment this to print out a full report of the airport-structure
- * You should either use
- * - true: full-report, print out every state and choice with string-names
- * OR
- * - false: give a summarized report which only shows current and next position */
-//#define DEBUG_AIRPORT false
-
-static AirportFTAClass *CountryAirport;
-static AirportFTAClass *CityAirport;
-static AirportFTAClass *Oilrig;
-static AirportFTAClass *Heliport;
-static AirportFTAClass *MetropolitanAirport;
-static AirportFTAClass *InternationalAirport;
-static AirportFTAClass *CommuterAirport;
-static AirportFTAClass *HeliDepot;
-static AirportFTAClass *IntercontinentalAirport;
-static AirportFTAClass *HeliStation;
-
-static void AirportFTAClass_Constructor(AirportFTAClass *apc,
-	const byte *terminals, const byte *helipads,
-	const byte entry_point,  const byte acc_planes,
-	const AirportFTAbuildup *apFA,
-	const TileIndexDiffC *depots, const byte nof_depots,
-	uint size_x, uint size_y
-);
-static void AirportFTAClass_Destructor(AirportFTAClass *apc);
-
-static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
-static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA);
-static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
-static byte AirportTestFTA(const AirportFTAClass *apc);
-
-#ifdef DEBUG_AIRPORT
-static void AirportPrintOut(const AirportFTAClass *apc, bool full_report);
-#endif /* DEBUG_AIRPORT */
-
-void InitializeAirports(void)
-{
-	// country airport
-	CountryAirport = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		CountryAirport,
-		_airport_terminal_country,
-		NULL,
-		16,
-		ALL,
-		_airport_fta_country,
-		_airport_depots_country,
-		lengthof(_airport_depots_country),
-		4, 3
-	);
-
-	// city airport
-	CityAirport = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		CityAirport,
-		_airport_terminal_city,
-		NULL,
-		19,
-		ALL,
-		_airport_fta_city,
-		_airport_depots_city,
-		lengthof(_airport_depots_city),
-		6, 6
-	);
-
-	// metropolitan airport
-	MetropolitanAirport = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		MetropolitanAirport,
-		_airport_terminal_metropolitan,
-		NULL,
-		20,
-		ALL,
-		_airport_fta_metropolitan,
-		_airport_depots_metropolitan,
-		lengthof(_airport_depots_metropolitan),
-		6, 6
-	);
-
-	// international airport
-	InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		InternationalAirport,
-		_airport_terminal_international,
-		_airport_helipad_international,
-		37,
-		ALL,
-		_airport_fta_international,
-		_airport_depots_international,
-		lengthof(_airport_depots_international),
-		7, 7
-	);
-
-	// intercontintental airport
-	IntercontinentalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		IntercontinentalAirport,
-		_airport_terminal_intercontinental,
-		_airport_helipad_intercontinental,
-		43,
-		ALL,
-		_airport_fta_intercontinental,
-		_airport_depots_intercontinental,
-		lengthof(_airport_depots_intercontinental),
-		9,11
-	);
-
-	// heliport, oilrig
-	Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		Heliport,
-		NULL,
-		_airport_helipad_heliport_oilrig,
-		7,
-		HELICOPTERS_ONLY,
-		_airport_fta_heliport_oilrig,
-		NULL,
-		0,
-		1, 1
-	);
-
-	Oilrig = Heliport;  // exactly the same structure for heliport/oilrig, so share state machine
-
-	// commuter airport
-	CommuterAirport = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		CommuterAirport,
-		_airport_terminal_commuter,
-		_airport_helipad_commuter,
-		22,
-		ALL,
-		_airport_fta_commuter,
-		_airport_depots_commuter,
-		lengthof(_airport_depots_commuter),
-		5,4
-	);
-
-	// helidepot airport
-	HeliDepot = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		HeliDepot,
-		NULL,
-		_airport_helipad_helidepot,
-		4,
-		HELICOPTERS_ONLY,
-		_airport_fta_helidepot,
-		_airport_depots_helidepot,
-		lengthof(_airport_depots_helidepot),
-		2,2
-	);
-
-	// helistation airport
-	HeliStation = malloc(sizeof(AirportFTAClass));
-
-	AirportFTAClass_Constructor(
-		HeliStation,
-		NULL,
-		_airport_helipad_helistation,
-		25,
-		HELICOPTERS_ONLY,
-		_airport_fta_helistation,
-		_airport_depots_helistation,
-		lengthof(_airport_depots_helistation),
-		4,2
-	);
-
-}
-
-void UnInitializeAirports(void)
-{
-	AirportFTAClass_Destructor(CountryAirport);
-	AirportFTAClass_Destructor(CityAirport);
-	AirportFTAClass_Destructor(Heliport);
-	AirportFTAClass_Destructor(MetropolitanAirport);
-	AirportFTAClass_Destructor(InternationalAirport);
-	AirportFTAClass_Destructor(CommuterAirport);
-	AirportFTAClass_Destructor(HeliDepot);
-	AirportFTAClass_Destructor(IntercontinentalAirport);
-	AirportFTAClass_Destructor(HeliStation);
-}
-
-static void AirportFTAClass_Constructor(AirportFTAClass *apc,
-	const byte *terminals, const byte *helipads,
-	const byte entry_point, const byte acc_planes,
-	const AirportFTAbuildup *apFA,
-	const TileIndexDiffC *depots, const byte nof_depots,
-	uint size_x, uint size_y
-)
-{
-	byte nofterminals, nofhelipads;
-	byte nofterminalgroups, nofhelipadgroups;
-
-	apc->size_x = size_x;
-	apc->size_y = size_y;
-
-	/* Set up the terminal and helipad count for an airport.
-	 * TODO: If there are more than 10 terminals or 4 helipads, internal variables
-	 * need to be changed, so don't allow that for now */
-	nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
-	if (nofterminals > MAX_TERMINALS) {
-		DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
-		assert(nofterminals <= MAX_TERMINALS);
-	}
-	apc->terminals = terminals;
-
-	nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
-	if (nofhelipads > MAX_HELIPADS) {
-		DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
-		assert(nofhelipads <= MAX_HELIPADS);
-	}
-	apc->helipads = helipads;
-
-	/* Get the number of elements from the source table. We also double check this
-	 * with the entry point which must be within bounds and use this information
-	 * later on to build and validate the state machine */
-	apc->nofelements = AirportGetNofElements(apFA);
-	if (entry_point >= apc->nofelements) {
-		DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_point, apc->nofelements);
-		assert(entry_point < apc->nofelements);
-	}
-
-	apc->acc_planes     = acc_planes;
-	apc->entry_point    = entry_point;
-	apc->airport_depots = depots;
-	apc->nof_depots     = nof_depots;
-
-	/* Build the state machine itself */
-	AirportBuildAutomata(apc, apFA);
-	DEBUG(misc, 2, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entry %3d",
-		apc->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, apc->entry_point);
-
-	/* Test if everything went allright. This is only a rude static test checking
-	 * the symantic correctness. By no means does passing the test mean that the
-	 * airport is working correctly or will not deadlock for example */
-	{ byte ret = AirportTestFTA(apc);
-		if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
-		assert(ret == MAX_ELEMENTS);
-	}
-
-#ifdef DEBUG_AIRPORT
-	AirportPrintOut(apc, DEBUG_AIRPORT);
-#endif
-}
-
-static void AirportFTAClass_Destructor(AirportFTAClass *apc)
-{
-	int i;
-	AirportFTA *current, *next;
-
-	for (i = 0; i < apc->nofelements; i++) {
-		current = apc->layout[i].next;
-		while (current != NULL) {
-			next = current->next;
-			free(current);
-			current = next;
-		};
-	}
-	free(apc->layout);
-	free(apc);
-}
-
-/** Get the number of elements of a source Airport state automata
- * Since it is actually just a big array of AirportFTA types, we only
- * know one element from the other by differing 'position' identifiers */
-static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
-{
-	int i;
-	uint16 nofelements = 0;
-	int temp = apFA[0].position;
-
-	for (i = 0; i < MAX_ELEMENTS; i++) {
-		if (temp != apFA[i].position) {
-			nofelements++;
-			temp = apFA[i].position;
-		}
-		if (apFA[i].position == MAX_ELEMENTS) break;
-	}
-	return nofelements;
-}
-
-/* We calculate the terminal/helipod count based on the data passed to us
- * This data (terminals) contains an index as a first element as to how many
- * groups there are, and then the number of terminals for each group */
-static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
-{
-	byte i;
-	byte nof_terminals = 0;
-	*groups = 0;
-
-	if (terminals != NULL) {
-		i = terminals[0];
-		*groups = i;
-		while (i-- > 0) {
-			terminals++;
-			assert(*terminals != 0); // no empty groups please
-			nof_terminals += *terminals;
-		}
-	}
-	return nof_terminals;
-}
-
-static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA)
-{
-	AirportFTA *current;
-	AirportFTA *FAutomata = malloc(sizeof(AirportFTA) * apc->nofelements);
-	uint16 internalcounter = 0;
-	uint16 i;
-
-	apc->layout = FAutomata;
-	for (i = 0; i < apc->nofelements; i++) {
-		current = &apc->layout[i];
-		current->position      = apFA[internalcounter].position;
-		current->heading       = apFA[internalcounter].heading;
-		current->block         = apFA[internalcounter].block;
-		current->next_position = apFA[internalcounter].next;
-
-		// outgoing nodes from the same position, create linked list
-		while (current->position == apFA[internalcounter + 1].position) {
-			AirportFTA *newNode = malloc(sizeof(AirportFTA));
-
-			newNode->position      = apFA[internalcounter + 1].position;
-			newNode->heading       = apFA[internalcounter + 1].heading;
-			newNode->block         = apFA[internalcounter + 1].block;
-			newNode->next_position = apFA[internalcounter + 1].next;
-			// create link
-			current->next = newNode;
-			current = current->next;
-			internalcounter++;
-		} // while
-		current->next = NULL;
-		internalcounter++;
-	}
-}
-
-static byte AirportTestFTA(const AirportFTAClass *apc)
-{
-	byte position, i, next_position;
-	AirportFTA *current, *first;
-	next_position = 0;
-
-	for (i = 0; i < apc->nofelements; i++) {
-		position = apc->layout[i].position;
-		if (position != next_position) return i;
-		current = first = &apc->layout[i];
-
-		for (; current != NULL; current = current->next) {
-			/* A heading must always be valid. The only exceptions are
-			 * - multiple choices as start, identified by a special value of 255
-			 * - terminal group which is identified by a special value of 255 */
-			if (current->heading > MAX_HEADINGS) {
-				if (current->heading != 255) return i;
-				if (current == first && current->next == NULL) return i;
-				if (current != first && current->next_position > apc->terminals[0]) return i;
-			}
-
-			/* If there is only one choice, it must be at the end */
-			if (current->heading == 0 && current->next != NULL) return i;
-			/* Obviously the elements of the linked list must have the same identifier */
-			if (position != current->position) return i;
-			/* A next position must be within bounds */
-			if (current->next_position >= apc->nofelements) return i;
-		}
-		next_position++;
-	}
-	return MAX_ELEMENTS;
-}
-
-#ifdef DEBUG_AIRPORT
-static const char* const _airport_heading_strings[] = {
-	"TO_ALL",
-	"HANGAR",
-	"TERM1",
-	"TERM2",
-	"TERM3",
-	"TERM4",
-	"TERM5",
-	"TERM6",
-	"HELIPAD1",
-	"HELIPAD2",
-	"TAKEOFF",
-	"STARTTAKEOFF",
-	"ENDTAKEOFF",
-	"HELITAKEOFF",
-	"FLYING",
-	"LANDING",
-	"ENDLANDING",
-	"HELILANDING",
-	"HELIENDLANDING",
-	"TERM7",
-	"TERM8",
-	"HELIPAD3",
-	"HELIPAD4",
-	"DUMMY" // extra heading for 255
-};
-
-static uint AirportBlockToString(uint32 block)
-{
-	uint i = 0;
-	if (block & 0xffff0000) { block >>= 16; i += 16; }
-	if (block & 0x0000ff00) { block >>=  8; i +=  8; }
-	if (block & 0x000000f0) { block >>=  4; i +=  4; }
-	if (block & 0x0000000c) { block >>=  2; i +=  2; }
-	if (block & 0x00000002) { i += 1; }
-	return i;
-}
-
-static void AirportPrintOut(const AirportFTAClass *apc, bool full_report)
-{
-	uint16 i;
-
-	if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
-
-	for (i = 0; i < apc->nofelements; i++) {
-		AirportFTA *current = &apc->layout[i];
-
-		for (; current != NULL; current = current->next) {
-			if (full_report) {
-				byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
-				printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
-					    current->next_position, _airport_heading_strings[heading],
-							AirportBlockToString(current->block));
-			} else {
-				printf("P:%2d NP:%2d", current->position, current->next_position);
-			}
-		}
-		printf("\n");
-	}
-}
-#endif
-
-const AirportFTAClass *GetAirport(const byte airport_type)
-{
-	//FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
-	// needs constant change if more airports are added
-	switch (airport_type) {
-		default:               NOT_REACHED();
-		case AT_SMALL:         return CountryAirport;
-		case AT_LARGE:         return CityAirport;
-		case AT_METROPOLITAN:  return MetropolitanAirport;
-		case AT_HELIPORT:      return Heliport;
-		case AT_OILRIG:        return Oilrig;
-		case AT_INTERNATIONAL: return InternationalAirport;
-		case AT_COMMUTER:      return CommuterAirport;
-		case AT_HELIDEPOT:     return HeliDepot;
-		case AT_INTERCON:      return IntercontinentalAirport;
-		case AT_HELISTATION:   return HeliStation;
-	}
-}
-
-const AirportMovingData *GetAirportMovingData(byte airport_type, byte position)
-{
-	assert(airport_type < lengthof(_airport_moving_datas));
-	assert(position < GetAirport(airport_type)->nofelements);
-	return &_airport_moving_datas[airport_type][position];
-}
-
-uint32 GetValidAirports(void)
-{
-	uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
-
-	if (_cur_year >= 1980) SETBIT(bytemask, 3); // metropolitan airport
-	if (_cur_year >= 1990) SETBIT(bytemask, 4); // international airport
-	if (_cur_year >= 1983) SETBIT(bytemask, 5); // commuter airport
-	if (_cur_year >= 1976) SETBIT(bytemask, 6); // helidepot
-	if (_cur_year >= 2002) SETBIT(bytemask, 7); // intercontinental airport
-	if (_cur_year >= 1980) SETBIT(bytemask, 8); // helistation
-	return bytemask;
-}
new file mode 100644
--- /dev/null
+++ b/src/airport.cpp
@@ -0,0 +1,489 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "map.h"
+#include "airport.h"
+#include "macros.h"
+#include "variables.h"
+#include "airport_movement.h"
+#include "date.h"
+
+/* Uncomment this to print out a full report of the airport-structure
+ * You should either use
+ * - true: full-report, print out every state and choice with string-names
+ * OR
+ * - false: give a summarized report which only shows current and next position */
+//#define DEBUG_AIRPORT false
+
+static AirportFTAClass *CountryAirport;
+static AirportFTAClass *CityAirport;
+static AirportFTAClass *Oilrig;
+static AirportFTAClass *Heliport;
+static AirportFTAClass *MetropolitanAirport;
+static AirportFTAClass *InternationalAirport;
+static AirportFTAClass *CommuterAirport;
+static AirportFTAClass *HeliDepot;
+static AirportFTAClass *IntercontinentalAirport;
+static AirportFTAClass *HeliStation;
+
+static void AirportFTAClass_Constructor(AirportFTAClass *apc,
+	const byte *terminals, const byte *helipads,
+	const byte entry_point,  const byte acc_planes,
+	const AirportFTAbuildup *apFA,
+	const TileIndexDiffC *depots, const byte nof_depots,
+	uint size_x, uint size_y
+);
+static void AirportFTAClass_Destructor(AirportFTAClass *apc);
+
+static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
+static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA);
+static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
+static byte AirportTestFTA(const AirportFTAClass *apc);
+
+#ifdef DEBUG_AIRPORT
+static void AirportPrintOut(const AirportFTAClass *apc, bool full_report);
+#endif /* DEBUG_AIRPORT */
+
+void InitializeAirports(void)
+{
+	// country airport
+	CountryAirport = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		CountryAirport,
+		_airport_terminal_country,
+		NULL,
+		16,
+		ALL,
+		_airport_fta_country,
+		_airport_depots_country,
+		lengthof(_airport_depots_country),
+		4, 3
+	);
+
+	// city airport
+	CityAirport = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		CityAirport,
+		_airport_terminal_city,
+		NULL,
+		19,
+		ALL,
+		_airport_fta_city,
+		_airport_depots_city,
+		lengthof(_airport_depots_city),
+		6, 6
+	);
+
+	// metropolitan airport
+	MetropolitanAirport = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		MetropolitanAirport,
+		_airport_terminal_metropolitan,
+		NULL,
+		20,
+		ALL,
+		_airport_fta_metropolitan,
+		_airport_depots_metropolitan,
+		lengthof(_airport_depots_metropolitan),
+		6, 6
+	);
+
+	// international airport
+	InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		InternationalAirport,
+		_airport_terminal_international,
+		_airport_helipad_international,
+		37,
+		ALL,
+		_airport_fta_international,
+		_airport_depots_international,
+		lengthof(_airport_depots_international),
+		7, 7
+	);
+
+	// intercontintental airport
+	IntercontinentalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		IntercontinentalAirport,
+		_airport_terminal_intercontinental,
+		_airport_helipad_intercontinental,
+		43,
+		ALL,
+		_airport_fta_intercontinental,
+		_airport_depots_intercontinental,
+		lengthof(_airport_depots_intercontinental),
+		9,11
+	);
+
+	// heliport, oilrig
+	Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		Heliport,
+		NULL,
+		_airport_helipad_heliport_oilrig,
+		7,
+		HELICOPTERS_ONLY,
+		_airport_fta_heliport_oilrig,
+		NULL,
+		0,
+		1, 1
+	);
+
+	Oilrig = Heliport;  // exactly the same structure for heliport/oilrig, so share state machine
+
+	// commuter airport
+	CommuterAirport = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		CommuterAirport,
+		_airport_terminal_commuter,
+		_airport_helipad_commuter,
+		22,
+		ALL,
+		_airport_fta_commuter,
+		_airport_depots_commuter,
+		lengthof(_airport_depots_commuter),
+		5,4
+	);
+
+	// helidepot airport
+	HeliDepot = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		HeliDepot,
+		NULL,
+		_airport_helipad_helidepot,
+		4,
+		HELICOPTERS_ONLY,
+		_airport_fta_helidepot,
+		_airport_depots_helidepot,
+		lengthof(_airport_depots_helidepot),
+		2,2
+	);
+
+	// helistation airport
+	HeliStation = malloc(sizeof(AirportFTAClass));
+
+	AirportFTAClass_Constructor(
+		HeliStation,
+		NULL,
+		_airport_helipad_helistation,
+		25,
+		HELICOPTERS_ONLY,
+		_airport_fta_helistation,
+		_airport_depots_helistation,
+		lengthof(_airport_depots_helistation),
+		4,2
+	);
+
+}
+
+void UnInitializeAirports(void)
+{
+	AirportFTAClass_Destructor(CountryAirport);
+	AirportFTAClass_Destructor(CityAirport);
+	AirportFTAClass_Destructor(Heliport);
+	AirportFTAClass_Destructor(MetropolitanAirport);
+	AirportFTAClass_Destructor(InternationalAirport);
+	AirportFTAClass_Destructor(CommuterAirport);
+	AirportFTAClass_Destructor(HeliDepot);
+	AirportFTAClass_Destructor(IntercontinentalAirport);
+	AirportFTAClass_Destructor(HeliStation);
+}
+
+static void AirportFTAClass_Constructor(AirportFTAClass *apc,
+	const byte *terminals, const byte *helipads,
+	const byte entry_point, const byte acc_planes,
+	const AirportFTAbuildup *apFA,
+	const TileIndexDiffC *depots, const byte nof_depots,
+	uint size_x, uint size_y
+)
+{
+	byte nofterminals, nofhelipads;
+	byte nofterminalgroups, nofhelipadgroups;
+
+	apc->size_x = size_x;
+	apc->size_y = size_y;
+
+	/* Set up the terminal and helipad count for an airport.
+	 * TODO: If there are more than 10 terminals or 4 helipads, internal variables
+	 * need to be changed, so don't allow that for now */
+	nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
+	if (nofterminals > MAX_TERMINALS) {
+		DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
+		assert(nofterminals <= MAX_TERMINALS);
+	}
+	apc->terminals = terminals;
+
+	nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
+	if (nofhelipads > MAX_HELIPADS) {
+		DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
+		assert(nofhelipads <= MAX_HELIPADS);
+	}
+	apc->helipads = helipads;
+
+	/* Get the number of elements from the source table. We also double check this
+	 * with the entry point which must be within bounds and use this information
+	 * later on to build and validate the state machine */
+	apc->nofelements = AirportGetNofElements(apFA);
+	if (entry_point >= apc->nofelements) {
+		DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_point, apc->nofelements);
+		assert(entry_point < apc->nofelements);
+	}
+
+	apc->acc_planes     = acc_planes;
+	apc->entry_point    = entry_point;
+	apc->airport_depots = depots;
+	apc->nof_depots     = nof_depots;
+
+	/* Build the state machine itself */
+	AirportBuildAutomata(apc, apFA);
+	DEBUG(misc, 2, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entry %3d",
+		apc->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, apc->entry_point);
+
+	/* Test if everything went allright. This is only a rude static test checking
+	 * the symantic correctness. By no means does passing the test mean that the
+	 * airport is working correctly or will not deadlock for example */
+	{ byte ret = AirportTestFTA(apc);
+		if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
+		assert(ret == MAX_ELEMENTS);
+	}
+
+#ifdef DEBUG_AIRPORT
+	AirportPrintOut(apc, DEBUG_AIRPORT);
+#endif
+}
+
+static void AirportFTAClass_Destructor(AirportFTAClass *apc)
+{
+	int i;
+	AirportFTA *current, *next;
+
+	for (i = 0; i < apc->nofelements; i++) {
+		current = apc->layout[i].next;
+		while (current != NULL) {
+			next = current->next;
+			free(current);
+			current = next;
+		};
+	}
+	free(apc->layout);
+	free(apc);
+}
+
+/** Get the number of elements of a source Airport state automata
+ * Since it is actually just a big array of AirportFTA types, we only
+ * know one element from the other by differing 'position' identifiers */
+static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
+{
+	int i;
+	uint16 nofelements = 0;
+	int temp = apFA[0].position;
+
+	for (i = 0; i < MAX_ELEMENTS; i++) {
+		if (temp != apFA[i].position) {
+			nofelements++;
+			temp = apFA[i].position;
+		}
+		if (apFA[i].position == MAX_ELEMENTS) break;
+	}
+	return nofelements;
+}
+
+/* We calculate the terminal/helipod count based on the data passed to us
+ * This data (terminals) contains an index as a first element as to how many
+ * groups there are, and then the number of terminals for each group */
+static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
+{
+	byte i;
+	byte nof_terminals = 0;
+	*groups = 0;
+
+	if (terminals != NULL) {
+		i = terminals[0];
+		*groups = i;
+		while (i-- > 0) {
+			terminals++;
+			assert(*terminals != 0); // no empty groups please
+			nof_terminals += *terminals;
+		}
+	}
+	return nof_terminals;
+}
+
+static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA)
+{
+	AirportFTA *current;
+	AirportFTA *FAutomata = malloc(sizeof(AirportFTA) * apc->nofelements);
+	uint16 internalcounter = 0;
+	uint16 i;
+
+	apc->layout = FAutomata;
+	for (i = 0; i < apc->nofelements; i++) {
+		current = &apc->layout[i];
+		current->position      = apFA[internalcounter].position;
+		current->heading       = apFA[internalcounter].heading;
+		current->block         = apFA[internalcounter].block;
+		current->next_position = apFA[internalcounter].next;
+
+		// outgoing nodes from the same position, create linked list
+		while (current->position == apFA[internalcounter + 1].position) {
+			AirportFTA *newNode = malloc(sizeof(AirportFTA));
+
+			newNode->position      = apFA[internalcounter + 1].position;
+			newNode->heading       = apFA[internalcounter + 1].heading;
+			newNode->block         = apFA[internalcounter + 1].block;
+			newNode->next_position = apFA[internalcounter + 1].next;
+			// create link
+			current->next = newNode;
+			current = current->next;
+			internalcounter++;
+		} // while
+		current->next = NULL;
+		internalcounter++;
+	}
+}
+
+static byte AirportTestFTA(const AirportFTAClass *apc)
+{
+	byte position, i, next_position;
+	AirportFTA *current, *first;
+	next_position = 0;
+
+	for (i = 0; i < apc->nofelements; i++) {
+		position = apc->layout[i].position;
+		if (position != next_position) return i;
+		current = first = &apc->layout[i];
+
+		for (; current != NULL; current = current->next) {
+			/* A heading must always be valid. The only exceptions are
+			 * - multiple choices as start, identified by a special value of 255
+			 * - terminal group which is identified by a special value of 255 */
+			if (current->heading > MAX_HEADINGS) {
+				if (current->heading != 255) return i;
+				if (current == first && current->next == NULL) return i;
+				if (current != first && current->next_position > apc->terminals[0]) return i;
+			}
+
+			/* If there is only one choice, it must be at the end */
+			if (current->heading == 0 && current->next != NULL) return i;
+			/* Obviously the elements of the linked list must have the same identifier */
+			if (position != current->position) return i;
+			/* A next position must be within bounds */
+			if (current->next_position >= apc->nofelements) return i;
+		}
+		next_position++;
+	}
+	return MAX_ELEMENTS;
+}
+
+#ifdef DEBUG_AIRPORT
+static const char* const _airport_heading_strings[] = {
+	"TO_ALL",
+	"HANGAR",
+	"TERM1",
+	"TERM2",
+	"TERM3",
+	"TERM4",
+	"TERM5",
+	"TERM6",
+	"HELIPAD1",
+	"HELIPAD2",
+	"TAKEOFF",
+	"STARTTAKEOFF",
+	"ENDTAKEOFF",
+	"HELITAKEOFF",
+	"FLYING",
+	"LANDING",
+	"ENDLANDING",
+	"HELILANDING",
+	"HELIENDLANDING",
+	"TERM7",
+	"TERM8",
+	"HELIPAD3",
+	"HELIPAD4",
+	"DUMMY" // extra heading for 255
+};
+
+static uint AirportBlockToString(uint32 block)
+{
+	uint i = 0;
+	if (block & 0xffff0000) { block >>= 16; i += 16; }
+	if (block & 0x0000ff00) { block >>=  8; i +=  8; }
+	if (block & 0x000000f0) { block >>=  4; i +=  4; }
+	if (block & 0x0000000c) { block >>=  2; i +=  2; }
+	if (block & 0x00000002) { i += 1; }
+	return i;
+}
+
+static void AirportPrintOut(const AirportFTAClass *apc, bool full_report)
+{
+	uint16 i;
+
+	if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
+
+	for (i = 0; i < apc->nofelements; i++) {
+		AirportFTA *current = &apc->layout[i];
+
+		for (; current != NULL; current = current->next) {
+			if (full_report) {
+				byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
+				printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
+					    current->next_position, _airport_heading_strings[heading],
+							AirportBlockToString(current->block));
+			} else {
+				printf("P:%2d NP:%2d", current->position, current->next_position);
+			}
+		}
+		printf("\n");
+	}
+}
+#endif
+
+const AirportFTAClass *GetAirport(const byte airport_type)
+{
+	//FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
+	// needs constant change if more airports are added
+	switch (airport_type) {
+		default:               NOT_REACHED();
+		case AT_SMALL:         return CountryAirport;
+		case AT_LARGE:         return CityAirport;
+		case AT_METROPOLITAN:  return MetropolitanAirport;
+		case AT_HELIPORT:      return Heliport;
+		case AT_OILRIG:        return Oilrig;
+		case AT_INTERNATIONAL: return InternationalAirport;
+		case AT_COMMUTER:      return CommuterAirport;
+		case AT_HELIDEPOT:     return HeliDepot;
+		case AT_INTERCON:      return IntercontinentalAirport;
+		case AT_HELISTATION:   return HeliStation;
+	}
+}
+
+const AirportMovingData *GetAirportMovingData(byte airport_type, byte position)
+{
+	assert(airport_type < lengthof(_airport_moving_datas));
+	assert(position < GetAirport(airport_type)->nofelements);
+	return &_airport_moving_datas[airport_type][position];
+}
+
+uint32 GetValidAirports(void)
+{
+	uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
+
+	if (_cur_year >= 1980) SETBIT(bytemask, 3); // metropolitan airport
+	if (_cur_year >= 1990) SETBIT(bytemask, 4); // international airport
+	if (_cur_year >= 1983) SETBIT(bytemask, 5); // commuter airport
+	if (_cur_year >= 1976) SETBIT(bytemask, 6); // helidepot
+	if (_cur_year >= 2002) SETBIT(bytemask, 7); // intercontinental airport
+	if (_cur_year >= 1980) SETBIT(bytemask, 8); // helistation
+	return bytemask;
+}
deleted file mode 100644
--- a/src/airport_gui.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "sound.h"
-#include "command.h"
-#include "vehicle.h"
-#include "station.h"
-#include "airport.h"
-#include "depot.h"
-
-static byte _selected_airport_type;
-
-static void ShowBuildAirportPicker(void);
-
-
-void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_1F_SPLAT, tile);
-		ResetObjectToPlace();
-	}
-}
-
-static void PlaceAirport(TileIndex tile)
-{
-	DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
-}
-
-static void PlaceAir_DemolishArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, 4);
-}
-
-
-enum {
-	ATW_AIRPORT  = 3,
-	ATW_DEMOLISH = 4
-};
-
-
-static void BuildAirClick_Airport(Window *w)
-{
-	if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker();
-}
-
-static void BuildAirClick_Demolish(Window *w)
-{
-	HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceAir_DemolishArea);
-}
-
-static void BuildAirClick_Landscaping(Window *w)
-{
-	ShowTerraformToolbar();
-}
-
-typedef void OnButtonClick(Window *w);
-static OnButtonClick * const _build_air_button_proc[] = {
-	BuildAirClick_Airport,
-	BuildAirClick_Demolish,
-	BuildAirClick_Landscaping,
-};
-
-static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK:
-		if (e->we.click.widget - 3 >= 0)
-			_build_air_button_proc[e->we.click.widget - 3](w);
-		break;
-
-	case WE_KEYPRESS: {
-		switch (e->we.keypress.keycode) {
-			case '1': BuildAirClick_Airport(w); break;
-			case '2': BuildAirClick_Demolish(w); break;
-			case 'l': BuildAirClick_Landscaping(w); break;
-			default: return;
-		}
-	} break;
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		break;
-
-	case WE_PLACE_DRAG:
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
-		break;
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
-		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-
-		w = FindWindowById(WC_BUILD_STATION, 0);
-		if (w != 0)
-			WP(w,def_d).close = true;
-		break;
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
-	}
-}
-
-static const Widget _air_toolbar_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,    73,     0,    13, STR_A000_AIRPORTS,   STR_018C_WINDOW_TITLE_DRAG_THIS },
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,    74,    85,     0,    13, 0x0,                 STR_STICKY_BUTTON },
-{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    41,    14,    35, SPR_IMG_AIRPORT,     STR_A01E_BUILD_AIRPORT },
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    42,    63,    14,    35, SPR_IMG_DYNAMITE,    STR_018D_DEMOLISH_BUILDINGS_ETC },
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    64,    85,    14,    35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP },
-{   WIDGETS_END},
-};
-
-
-static const WindowDesc _air_toolbar_desc = {
-	WDP_ALIGN_TBR, 22, 86, 36,
-	WC_BUILD_TOOLBAR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_air_toolbar_widgets,
-	BuildAirToolbWndProc
-};
-
-void ShowBuildAirToolbar(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-
-	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
-	AllocateWindowDescFront(&_air_toolbar_desc, 0);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
-}
-
-static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
-		SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
-		LowerWindowWidget(w, _selected_airport_type + 7);
-		break;
-
-	case WE_PAINT: {
-		int i; // airport enabling loop
-		int rad = 4; // default catchment radious
-		uint32 avail_airports;
-		const AirportFTAClass *airport;
-
-		if (WP(w,def_d).close) return;
-
-		avail_airports = GetValidAirports();
-
-		RaiseWindowWidget(w, _selected_airport_type + 7);
-		if (!HASBIT(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
-		if (!HASBIT(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
-		LowerWindowWidget(w, _selected_airport_type + 7);
-
-		/* 'Country Airport' starts at widget 7, and if its bit is set, it is
-		 * available, so take its opposite value to set the disabled state.
-		 * There are 9 buildable airports
-		 * XXX TODO : all airports should be held in arrays, with all relevant data.
-		 * This should be part of newgrf-airports, i suppose
-		 */
-		for (i = 0; i < 9; i++) SetWindowWidgetDisabledState(w, i + 7, !HASBIT(avail_airports, i));
-
-		// select default the coverage area to 'Off' (16)
-		airport = GetAirport(_selected_airport_type);
-		SetTileSelectSize(airport->size_x, airport->size_y);
-
-		if (_patches.modified_catchment) {
-			switch (_selected_airport_type) {
-				case AT_OILRIG:        rad = CA_AIR_OILPAD;   break;
-				case AT_HELIPORT:      rad = CA_AIR_HELIPORT; break;
-				case AT_SMALL:         rad = CA_AIR_SMALL;    break;
-				case AT_LARGE:         rad = CA_AIR_LARGE;    break;
-				case AT_METROPOLITAN:  rad = CA_AIR_METRO;    break;
-				case AT_INTERNATIONAL: rad = CA_AIR_INTER;    break;
-				case AT_COMMUTER:      rad = CA_AIR_COMMUTER; break;
-				case AT_HELIDEPOT:     rad = CA_AIR_HELIDEPOT; break;
-				case AT_INTERCON:      rad = CA_AIR_INTERCON; break;
-				case AT_HELISTATION:   rad = CA_AIR_HELISTATION; break;
-			}
-		}
-
-		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-
-		DrawWindowWidgets(w);
-		// strings such as 'Size' and 'Coverage Area'
-		// 'Coverage Area'
-		DrawStationCoverageAreaText(2, 206, (uint)-1, rad);
-		break;
-	}
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
-			RaiseWindowWidget(w, _selected_airport_type + 7);
-			_selected_airport_type = e->we.click.widget - 7;
-			LowerWindowWidget(w, _selected_airport_type + 7);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		case 16: case 17:
-			_station_show_coverage = e->we.click.widget - 16;
-			SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
-			SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		}
-	} break;
-
-	case WE_MOUSELOOP: {
-		if (WP(w,def_d).close) {
-			DeleteWindow(w);
-			return;
-		}
-
-		CheckRedrawStationCoverage(w);
-	} break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_airport_picker_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3001_AIRPORT_SELECTION,       STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    52, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    53,    89, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    90,   127, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   128,   177, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   178,   239, 0x0,                              STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    27,    38, STR_SMALL_AIRPORT,                STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    65,    76, STR_CITY_AIRPORT,                 STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   141,   152, STR_HELIPORT,                     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    77,    88, STR_METRO_AIRPORT ,               STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   103,   114, STR_INTERNATIONAL_AIRPORT,        STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    39,    50, STR_COMMUTER_AIRPORT,             STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   165,   176, STR_HELIDEPOT,                    STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   115,   126, STR_INTERCONTINENTAL_AIRPORT,     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   153,   164, STR_HELISTATION,                  STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   191,   202, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   191,   202, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    14,    27, STR_SMALL_AIRPORTS,               STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    52,    65, STR_LARGE_AIRPORTS,               STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    90,   103, STR_HUB_AIRPORTS,                 STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   128,   141, STR_HELIPORTS,                    STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   178,   191, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_airport_desc = {
-	WDP_AUTO, WDP_AUTO, 148, 240,
-	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_airport_picker_widgets,
-	BuildAirportPickerWndProc
-};
-
-static void ShowBuildAirportPicker(void)
-{
-	AllocateWindowDesc(&_build_airport_desc);
-}
-
-void InitializeAirportGui(void)
-{
-	_selected_airport_type = AT_SMALL;
-}
new file mode 100644
--- /dev/null
+++ b/src/airport_gui.cpp
@@ -0,0 +1,286 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "sound.h"
+#include "command.h"
+#include "vehicle.h"
+#include "station.h"
+#include "airport.h"
+#include "depot.h"
+
+static byte _selected_airport_type;
+
+static void ShowBuildAirportPicker(void);
+
+
+void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_1F_SPLAT, tile);
+		ResetObjectToPlace();
+	}
+}
+
+static void PlaceAirport(TileIndex tile)
+{
+	DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
+}
+
+static void PlaceAir_DemolishArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, 4);
+}
+
+
+enum {
+	ATW_AIRPORT  = 3,
+	ATW_DEMOLISH = 4
+};
+
+
+static void BuildAirClick_Airport(Window *w)
+{
+	if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker();
+}
+
+static void BuildAirClick_Demolish(Window *w)
+{
+	HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceAir_DemolishArea);
+}
+
+static void BuildAirClick_Landscaping(Window *w)
+{
+	ShowTerraformToolbar();
+}
+
+typedef void OnButtonClick(Window *w);
+static OnButtonClick * const _build_air_button_proc[] = {
+	BuildAirClick_Airport,
+	BuildAirClick_Demolish,
+	BuildAirClick_Landscaping,
+};
+
+static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK:
+		if (e->we.click.widget - 3 >= 0)
+			_build_air_button_proc[e->we.click.widget - 3](w);
+		break;
+
+	case WE_KEYPRESS: {
+		switch (e->we.keypress.keycode) {
+			case '1': BuildAirClick_Airport(w); break;
+			case '2': BuildAirClick_Demolish(w); break;
+			case 'l': BuildAirClick_Landscaping(w); break;
+			default: return;
+		}
+	} break;
+
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		break;
+
+	case WE_PLACE_DRAG:
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
+		break;
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
+		}
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+
+		w = FindWindowById(WC_BUILD_STATION, 0);
+		if (w != 0)
+			WP(w,def_d).close = true;
+		break;
+
+	case WE_DESTROY:
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+		break;
+	}
+}
+
+static const Widget _air_toolbar_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,    73,     0,    13, STR_A000_AIRPORTS,   STR_018C_WINDOW_TITLE_DRAG_THIS },
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,    74,    85,     0,    13, 0x0,                 STR_STICKY_BUTTON },
+{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    41,    14,    35, SPR_IMG_AIRPORT,     STR_A01E_BUILD_AIRPORT },
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    42,    63,    14,    35, SPR_IMG_DYNAMITE,    STR_018D_DEMOLISH_BUILDINGS_ETC },
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    64,    85,    14,    35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP },
+{   WIDGETS_END},
+};
+
+
+static const WindowDesc _air_toolbar_desc = {
+	WDP_ALIGN_TBR, 22, 86, 36,
+	WC_BUILD_TOOLBAR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_air_toolbar_widgets,
+	BuildAirToolbWndProc
+};
+
+void ShowBuildAirToolbar(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+
+	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
+	AllocateWindowDescFront(&_air_toolbar_desc, 0);
+	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
+}
+
+static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE:
+		SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
+		SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
+		LowerWindowWidget(w, _selected_airport_type + 7);
+		break;
+
+	case WE_PAINT: {
+		int i; // airport enabling loop
+		int rad = 4; // default catchment radious
+		uint32 avail_airports;
+		const AirportFTAClass *airport;
+
+		if (WP(w,def_d).close) return;
+
+		avail_airports = GetValidAirports();
+
+		RaiseWindowWidget(w, _selected_airport_type + 7);
+		if (!HASBIT(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
+		if (!HASBIT(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
+		LowerWindowWidget(w, _selected_airport_type + 7);
+
+		/* 'Country Airport' starts at widget 7, and if its bit is set, it is
+		 * available, so take its opposite value to set the disabled state.
+		 * There are 9 buildable airports
+		 * XXX TODO : all airports should be held in arrays, with all relevant data.
+		 * This should be part of newgrf-airports, i suppose
+		 */
+		for (i = 0; i < 9; i++) SetWindowWidgetDisabledState(w, i + 7, !HASBIT(avail_airports, i));
+
+		// select default the coverage area to 'Off' (16)
+		airport = GetAirport(_selected_airport_type);
+		SetTileSelectSize(airport->size_x, airport->size_y);
+
+		if (_patches.modified_catchment) {
+			switch (_selected_airport_type) {
+				case AT_OILRIG:        rad = CA_AIR_OILPAD;   break;
+				case AT_HELIPORT:      rad = CA_AIR_HELIPORT; break;
+				case AT_SMALL:         rad = CA_AIR_SMALL;    break;
+				case AT_LARGE:         rad = CA_AIR_LARGE;    break;
+				case AT_METROPOLITAN:  rad = CA_AIR_METRO;    break;
+				case AT_INTERNATIONAL: rad = CA_AIR_INTER;    break;
+				case AT_COMMUTER:      rad = CA_AIR_COMMUTER; break;
+				case AT_HELIDEPOT:     rad = CA_AIR_HELIDEPOT; break;
+				case AT_INTERCON:      rad = CA_AIR_INTERCON; break;
+				case AT_HELISTATION:   rad = CA_AIR_HELISTATION; break;
+			}
+		}
+
+		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+
+		DrawWindowWidgets(w);
+		// strings such as 'Size' and 'Coverage Area'
+		// 'Coverage Area'
+		DrawStationCoverageAreaText(2, 206, (uint)-1, rad);
+		break;
+	}
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
+			RaiseWindowWidget(w, _selected_airport_type + 7);
+			_selected_airport_type = e->we.click.widget - 7;
+			LowerWindowWidget(w, _selected_airport_type + 7);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		case 16: case 17:
+			_station_show_coverage = e->we.click.widget - 16;
+			SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
+			SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		}
+	} break;
+
+	case WE_MOUSELOOP: {
+		if (WP(w,def_d).close) {
+			DeleteWindow(w);
+			return;
+		}
+
+		CheckRedrawStationCoverage(w);
+	} break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_airport_picker_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3001_AIRPORT_SELECTION,       STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    52, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    53,    89, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    90,   127, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   128,   177, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   178,   239, 0x0,                              STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    27,    38, STR_SMALL_AIRPORT,                STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    65,    76, STR_CITY_AIRPORT,                 STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   141,   152, STR_HELIPORT,                     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    77,    88, STR_METRO_AIRPORT ,               STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   103,   114, STR_INTERNATIONAL_AIRPORT,        STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,    39,    50, STR_COMMUTER_AIRPORT,             STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   165,   176, STR_HELIDEPOT,                    STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   115,   126, STR_INTERCONTINENTAL_AIRPORT,     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   153,   164, STR_HELISTATION,                  STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   191,   202, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   191,   202, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    14,    27, STR_SMALL_AIRPORTS,               STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    52,    65, STR_LARGE_AIRPORTS,               STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    90,   103, STR_HUB_AIRPORTS,                 STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   128,   141, STR_HELIPORTS,                    STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   178,   191, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_airport_desc = {
+	WDP_AUTO, WDP_AUTO, 148, 240,
+	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_airport_picker_widgets,
+	BuildAirportPickerWndProc
+};
+
+static void ShowBuildAirportPicker(void)
+{
+	AllocateWindowDesc(&_build_airport_desc);
+}
+
+void InitializeAirportGui(void)
+{
+	_selected_airport_type = AT_SMALL;
+}
deleted file mode 100644
--- a/src/aystar.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/* $Id$ */
-
-/*
- * This file has the core function for AyStar
- *  AyStar is a fast pathfinding routine and is used for things like
- *  AI_pathfinding and Train_pathfinding.
- *  For more information about AyStar (A* Algorithm), you can look at
- *    http://en.wikipedia.org/wiki/A-star_search_algorithm
- */
-
-/*
- * Friendly reminder:
- *  Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
- *  And when not free'd, it can cause system-crashes.
- * Also remember that when you stop an algorithm before it is finished, your
- * should call clear() yourself!
- */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "aystar.h"
-
-int _aystar_stats_open_size;
-int _aystar_stats_closed_size;
-
-// This looks in the Hash if a node exists in ClosedList
-//  If so, it returns the PathNode, else NULL
-static PathNode* AyStarMain_ClosedList_IsInList(AyStar *aystar, const AyStarNode *node)
-{
-	return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
-}
-
-// This adds a node to the ClosedList
-//  It makes a copy of the data
-static void AyStarMain_ClosedList_Add(AyStar *aystar, const PathNode *node)
-{
-	// Add a node to the ClosedList
-	PathNode *new_node = malloc(sizeof(*new_node));
-	*new_node = *node;
-	Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
-}
-
-// Checks if a node is in the OpenList
-//   If so, it returns the OpenListNode, else NULL
-static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNode *node)
-{
-	return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
-}
-
-// Gets the best node from OpenList
-//  returns the best node, or NULL of none is found
-// Also it deletes the node from the OpenList
-static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
-{
-	// Return the item the Queue returns.. the best next OpenList item.
-	OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
-	if (res != NULL) {
-		Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
-	}
-
-	return res;
-}
-
-// Adds a node to the OpenList
-//  It makes a copy of node, and puts the pointer of parent in the struct
-static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, const AyStarNode *node, int f, int g)
-{
-	// Add a new Node to the OpenList
-	OpenListNode *new_node = malloc(sizeof(*new_node));
-	new_node->g = g;
-	new_node->path.parent = parent;
-	new_node->path.node = *node;
-	Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
-
-	// Add it to the queue
-	aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
-}
-
-/*
- * Checks one tile and calculate his f-value
- *  return values:
- * AYSTAR_DONE : indicates we are done
- */
-int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
-{
-	int new_f, new_g, new_h;
-	PathNode *closedlist_parent;
-	OpenListNode *check;
-
-	// Check the new node against the ClosedList
-	if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
-
-	// Calculate the G-value for this node
-	new_g = aystar->CalculateG(aystar, current, parent);
-	// If the value was INVALID_NODE, we don't do anything with this node
-	if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
-
-	// There should not be given any other error-code..
-	assert(new_g >= 0);
-	// Add the parent g-value to the new g-value
-	new_g += parent->g;
-	if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
-
-	// Calculate the h-value
-	new_h = aystar->CalculateH(aystar, current, parent);
-	// There should not be given any error-code..
-	assert(new_h >= 0);
-
-	// The f-value if g + h
-	new_f = new_g + new_h;
-
-	// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
-	closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
-
-	// Check if this item is already in the OpenList
-	check = AyStarMain_OpenList_IsInList(aystar, current);
-	if (check != NULL) {
-		uint i;
-		// Yes, check if this g value is lower..
-		if (new_g > check->g) return AYSTAR_DONE;
-		aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
-		// It is lower, so change it to this item
-		check->g = new_g;
-		check->path.parent = closedlist_parent;
-		/* Copy user data, will probably have changed */
-		for (i = 0; i < lengthof(current->user_data); i++) {
-			check->path.node.user_data[i] = current->user_data[i];
-		}
-		// Readd him in the OpenListQueue
-		aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
-	} else {
-		// A new node, add him to the OpenList
-		AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g);
-	}
-
-	return AYSTAR_DONE;
-}
-
-/*
- * This function is the core of AyStar. It handles one item and checks
- *  his neighbour items. If they are valid, they are added to be checked too.
- *  return values:
- *   AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
- *    has been found.
- *   AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
- *    reached.
- *   AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
- *   AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
- */
-int AyStarMain_Loop(AyStar *aystar)
-{
-	int i, r;
-
-	// Get the best node from OpenList
-	OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
-	// If empty, drop an error
-	if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
-
-	// Check for end node and if found, return that code
-	if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
-		if (aystar->FoundEndNode != NULL)
-			aystar->FoundEndNode(aystar, current);
-		free(current);
-		return AYSTAR_FOUND_END_NODE;
-	}
-
-	// Add the node to the ClosedList
-	AyStarMain_ClosedList_Add(aystar, &current->path);
-
-	// Load the neighbours
-	aystar->GetNeighbours(aystar, current);
-
-	// Go through all neighbours
-	for (i = 0; i < aystar->num_neighbours; i++) {
-		// Check and add them to the OpenList if needed
-		r = aystar->checktile(aystar, &aystar->neighbours[i], current);
-	}
-
-	// Free the node
-	free(current);
-
-	if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
-		/* We've expanded enough nodes */
-		return AYSTAR_LIMIT_REACHED;
-	} else {
-		// Return that we are still busy
-		return AYSTAR_STILL_BUSY;
-	}
-}
-
-/*
- * This function frees the memory it allocated
- */
-void AyStarMain_Free(AyStar *aystar)
-{
-	aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
-	/* 2nd argument above is false, below is true, to free the values only
-	 * once */
-	delete_Hash(&aystar->OpenListHash, true);
-	delete_Hash(&aystar->ClosedListHash, true);
-#ifdef AYSTAR_DEBUG
-	printf("[AyStar] Memory free'd\n");
-#endif
-}
-
-/*
- * This function make the memory go back to zero
- *  This function should be called when you are using the same instance again.
- */
-void AyStarMain_Clear(AyStar *aystar)
-{
-	// Clean the Queue, but not the elements within. That will be done by
-	// the hash.
-	aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
-	// Clean the hashes
-	clear_Hash(&aystar->OpenListHash, true);
-	clear_Hash(&aystar->ClosedListHash, true);
-
-#ifdef AYSTAR_DEBUG
-	printf("[AyStar] Cleared AyStar\n");
-#endif
-}
-
-/*
- * This is the function you call to run AyStar.
- *  return values:
- *   AYSTAR_FOUND_END_NODE : indicates we found an end node.
- *   AYSTAR_NO_PATH : indicates that there was no path found.
- *   AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
- * When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
- * aystar->clear() is called. Note that when you stop the algorithm halfway,
- * you should still call clear() yourself!
- */
-int AyStarMain_Main(AyStar *aystar) {
-	int r, i = 0;
-	// Loop through the OpenList
-	//  Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick
-	while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
-#ifdef AYSTAR_DEBUG
-	switch (r) {
-		case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
-		case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
-		case AYSTAR_LIMIT_REACHED:  printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
-		default: break;
-	}
-#endif
-	if (r != AYSTAR_STILL_BUSY) {
-		/* We're done, clean up */
-		_aystar_stats_open_size = aystar->OpenListHash.size;
-		_aystar_stats_closed_size = aystar->ClosedListHash.size;
-		aystar->clear(aystar);
-	}
-
-	switch (r) {
-		case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
-		case AYSTAR_EMPTY_OPENLIST:
-		case AYSTAR_LIMIT_REACHED:  return AYSTAR_NO_PATH;
-		default:                    return AYSTAR_STILL_BUSY;
-	}
-}
-
-/*
- * Adds a node from where to start an algorithm. Multiple nodes can be added
- * if wanted. You should make sure that clear() is called before adding nodes
- * if the AyStar has been used before (though the normal main loop calls
- * clear() automatically when the algorithm finishes
- * g is the cost for starting with this node.
- */
-void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
-{
-#ifdef AYSTAR_DEBUG
-	printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
-		TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
-#endif
-	AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g);
-}
-
-void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
-{
-	// Allocated the Hash for the OpenList and ClosedList
-	init_Hash(&aystar->OpenListHash, hash, num_buckets);
-	init_Hash(&aystar->ClosedListHash, hash, num_buckets);
-
-	// Set up our sorting queue
-	//  BinaryHeap allocates a block of 1024 nodes
-	//  When thatone gets full it reserves an otherone, till this number
-	//  That is why it can stay this high
-	init_BinaryHeap(&aystar->OpenListQueue, 102400);
-
-	aystar->addstart  = AyStarMain_AddStartNode;
-	aystar->main      = AyStarMain_Main;
-	aystar->loop      = AyStarMain_Loop;
-	aystar->free      = AyStarMain_Free;
-	aystar->clear     = AyStarMain_Clear;
-	aystar->checktile = AyStarMain_CheckTile;
-}
new file mode 100644
--- /dev/null
+++ b/src/aystar.cpp
@@ -0,0 +1,296 @@
+/* $Id$ */
+
+/*
+ * This file has the core function for AyStar
+ *  AyStar is a fast pathfinding routine and is used for things like
+ *  AI_pathfinding and Train_pathfinding.
+ *  For more information about AyStar (A* Algorithm), you can look at
+ *    http://en.wikipedia.org/wiki/A-star_search_algorithm
+ */
+
+/*
+ * Friendly reminder:
+ *  Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
+ *  And when not free'd, it can cause system-crashes.
+ * Also remember that when you stop an algorithm before it is finished, your
+ * should call clear() yourself!
+ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "aystar.h"
+
+int _aystar_stats_open_size;
+int _aystar_stats_closed_size;
+
+// This looks in the Hash if a node exists in ClosedList
+//  If so, it returns the PathNode, else NULL
+static PathNode* AyStarMain_ClosedList_IsInList(AyStar *aystar, const AyStarNode *node)
+{
+	return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
+}
+
+// This adds a node to the ClosedList
+//  It makes a copy of the data
+static void AyStarMain_ClosedList_Add(AyStar *aystar, const PathNode *node)
+{
+	// Add a node to the ClosedList
+	PathNode *new_node = malloc(sizeof(*new_node));
+	*new_node = *node;
+	Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
+}
+
+// Checks if a node is in the OpenList
+//   If so, it returns the OpenListNode, else NULL
+static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNode *node)
+{
+	return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
+}
+
+// Gets the best node from OpenList
+//  returns the best node, or NULL of none is found
+// Also it deletes the node from the OpenList
+static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
+{
+	// Return the item the Queue returns.. the best next OpenList item.
+	OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
+	if (res != NULL) {
+		Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
+	}
+
+	return res;
+}
+
+// Adds a node to the OpenList
+//  It makes a copy of node, and puts the pointer of parent in the struct
+static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, const AyStarNode *node, int f, int g)
+{
+	// Add a new Node to the OpenList
+	OpenListNode *new_node = malloc(sizeof(*new_node));
+	new_node->g = g;
+	new_node->path.parent = parent;
+	new_node->path.node = *node;
+	Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
+
+	// Add it to the queue
+	aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
+}
+
+/*
+ * Checks one tile and calculate his f-value
+ *  return values:
+ * AYSTAR_DONE : indicates we are done
+ */
+int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
+{
+	int new_f, new_g, new_h;
+	PathNode *closedlist_parent;
+	OpenListNode *check;
+
+	// Check the new node against the ClosedList
+	if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
+
+	// Calculate the G-value for this node
+	new_g = aystar->CalculateG(aystar, current, parent);
+	// If the value was INVALID_NODE, we don't do anything with this node
+	if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
+
+	// There should not be given any other error-code..
+	assert(new_g >= 0);
+	// Add the parent g-value to the new g-value
+	new_g += parent->g;
+	if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
+
+	// Calculate the h-value
+	new_h = aystar->CalculateH(aystar, current, parent);
+	// There should not be given any error-code..
+	assert(new_h >= 0);
+
+	// The f-value if g + h
+	new_f = new_g + new_h;
+
+	// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
+	closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
+
+	// Check if this item is already in the OpenList
+	check = AyStarMain_OpenList_IsInList(aystar, current);
+	if (check != NULL) {
+		uint i;
+		// Yes, check if this g value is lower..
+		if (new_g > check->g) return AYSTAR_DONE;
+		aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
+		// It is lower, so change it to this item
+		check->g = new_g;
+		check->path.parent = closedlist_parent;
+		/* Copy user data, will probably have changed */
+		for (i = 0; i < lengthof(current->user_data); i++) {
+			check->path.node.user_data[i] = current->user_data[i];
+		}
+		// Readd him in the OpenListQueue
+		aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
+	} else {
+		// A new node, add him to the OpenList
+		AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g);
+	}
+
+	return AYSTAR_DONE;
+}
+
+/*
+ * This function is the core of AyStar. It handles one item and checks
+ *  his neighbour items. If they are valid, they are added to be checked too.
+ *  return values:
+ *   AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
+ *    has been found.
+ *   AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
+ *    reached.
+ *   AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
+ *   AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
+ */
+int AyStarMain_Loop(AyStar *aystar)
+{
+	int i, r;
+
+	// Get the best node from OpenList
+	OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
+	// If empty, drop an error
+	if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
+
+	// Check for end node and if found, return that code
+	if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
+		if (aystar->FoundEndNode != NULL)
+			aystar->FoundEndNode(aystar, current);
+		free(current);
+		return AYSTAR_FOUND_END_NODE;
+	}
+
+	// Add the node to the ClosedList
+	AyStarMain_ClosedList_Add(aystar, &current->path);
+
+	// Load the neighbours
+	aystar->GetNeighbours(aystar, current);
+
+	// Go through all neighbours
+	for (i = 0; i < aystar->num_neighbours; i++) {
+		// Check and add them to the OpenList if needed
+		r = aystar->checktile(aystar, &aystar->neighbours[i], current);
+	}
+
+	// Free the node
+	free(current);
+
+	if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
+		/* We've expanded enough nodes */
+		return AYSTAR_LIMIT_REACHED;
+	} else {
+		// Return that we are still busy
+		return AYSTAR_STILL_BUSY;
+	}
+}
+
+/*
+ * This function frees the memory it allocated
+ */
+void AyStarMain_Free(AyStar *aystar)
+{
+	aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
+	/* 2nd argument above is false, below is true, to free the values only
+	 * once */
+	delete_Hash(&aystar->OpenListHash, true);
+	delete_Hash(&aystar->ClosedListHash, true);
+#ifdef AYSTAR_DEBUG
+	printf("[AyStar] Memory free'd\n");
+#endif
+}
+
+/*
+ * This function make the memory go back to zero
+ *  This function should be called when you are using the same instance again.
+ */
+void AyStarMain_Clear(AyStar *aystar)
+{
+	// Clean the Queue, but not the elements within. That will be done by
+	// the hash.
+	aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
+	// Clean the hashes
+	clear_Hash(&aystar->OpenListHash, true);
+	clear_Hash(&aystar->ClosedListHash, true);
+
+#ifdef AYSTAR_DEBUG
+	printf("[AyStar] Cleared AyStar\n");
+#endif
+}
+
+/*
+ * This is the function you call to run AyStar.
+ *  return values:
+ *   AYSTAR_FOUND_END_NODE : indicates we found an end node.
+ *   AYSTAR_NO_PATH : indicates that there was no path found.
+ *   AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
+ * When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
+ * aystar->clear() is called. Note that when you stop the algorithm halfway,
+ * you should still call clear() yourself!
+ */
+int AyStarMain_Main(AyStar *aystar) {
+	int r, i = 0;
+	// Loop through the OpenList
+	//  Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick
+	while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
+#ifdef AYSTAR_DEBUG
+	switch (r) {
+		case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
+		case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
+		case AYSTAR_LIMIT_REACHED:  printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
+		default: break;
+	}
+#endif
+	if (r != AYSTAR_STILL_BUSY) {
+		/* We're done, clean up */
+		_aystar_stats_open_size = aystar->OpenListHash.size;
+		_aystar_stats_closed_size = aystar->ClosedListHash.size;
+		aystar->clear(aystar);
+	}
+
+	switch (r) {
+		case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
+		case AYSTAR_EMPTY_OPENLIST:
+		case AYSTAR_LIMIT_REACHED:  return AYSTAR_NO_PATH;
+		default:                    return AYSTAR_STILL_BUSY;
+	}
+}
+
+/*
+ * Adds a node from where to start an algorithm. Multiple nodes can be added
+ * if wanted. You should make sure that clear() is called before adding nodes
+ * if the AyStar has been used before (though the normal main loop calls
+ * clear() automatically when the algorithm finishes
+ * g is the cost for starting with this node.
+ */
+void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
+{
+#ifdef AYSTAR_DEBUG
+	printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
+		TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
+#endif
+	AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g);
+}
+
+void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
+{
+	// Allocated the Hash for the OpenList and ClosedList
+	init_Hash(&aystar->OpenListHash, hash, num_buckets);
+	init_Hash(&aystar->ClosedListHash, hash, num_buckets);
+
+	// Set up our sorting queue
+	//  BinaryHeap allocates a block of 1024 nodes
+	//  When thatone gets full it reserves an otherone, till this number
+	//  That is why it can stay this high
+	init_BinaryHeap(&aystar->OpenListQueue, 102400);
+
+	aystar->addstart  = AyStarMain_AddStartNode;
+	aystar->main      = AyStarMain_Main;
+	aystar->loop      = AyStarMain_Loop;
+	aystar->free      = AyStarMain_Free;
+	aystar->clear     = AyStarMain_Clear;
+	aystar->checktile = AyStarMain_CheckTile;
+}
deleted file mode 100644
--- a/src/bmp.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "gfx.h"
-#include "bmp.h"
-#include "macros.h"
-
-void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file) {
-	buffer->pos      = -1;
-	buffer->file     = file;
-	buffer->read     = 0;
-	buffer->real_pos = ftell(file);
-}
-
-static inline void AdvanceBuffer(BmpBuffer *buffer)
-{
-	buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
-	buffer->pos  = 0;
-}
-
-static inline bool EndOfBuffer(BmpBuffer *buffer)
-{
-	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
-	return buffer->pos == buffer->read;
-}
-
-static inline byte ReadByte(BmpBuffer *buffer)
-{
-	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
-	buffer->real_pos++;
-	return buffer->data[buffer->pos++];
-}
-
-static inline uint16 ReadWord(BmpBuffer *buffer)
-{
-	uint16 var = ReadByte(buffer);
-	return var | (ReadByte(buffer) << 8);
-}
-
-static inline uint32 ReadDword(BmpBuffer *buffer)
-{
-	uint32 var = ReadWord(buffer);
-	return var | (ReadWord(buffer) << 16);
-}
-
-static inline void SkipBytes(BmpBuffer *buffer, int bytes)
-{
-	int i;
-	for (i = 0; i < bytes; i++) ReadByte(buffer);
-}
-
-static inline void SetStreamOffset(BmpBuffer *buffer, int offset)
-{
-	fseek(buffer->file, offset, SEEK_SET);
-	buffer->pos = -1;
-	buffer->real_pos = offset;
-	AdvanceBuffer(buffer);
-}
-
-/**
- * Reads a 1 bpp uncompressed bitmap
- * The bitmap is converted to a 8 bpp bitmap
- */
-static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint x, y, i;
-	byte pad = GB(4 - info->width / 8, 0, 2);
-	byte *pixel_row;
-	byte b;
-	for (y = info->height; y > 0; y--) {
-		x = 0;
-		pixel_row = &data->bitmap[(y - 1) * info->width];
-		while (x < info->width) {
-			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
-			b = ReadByte(buffer);
-			for (i = 8; i > 0; i--) {
-				if (x < info->width) *pixel_row++ = GB(b, i - 1, 1);
-				x++;
-			}
-		}
-		/* Padding for 32 bit align */
-		SkipBytes(buffer, pad);
-	}
-	return true;
-}
-
-/**
- * Reads a 4 bpp uncompressed bitmap
- * The bitmap is converted to a 8 bpp bitmap
- */
-static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint x, y;
-	byte pad = GB(4 - info->width / 2, 0, 2);
-	byte *pixel_row;
-	byte b;
-	for (y = info->height; y > 0; y--) {
-		x = 0;
-		pixel_row = &data->bitmap[(y - 1) * info->width];
-		while (x < info->width) {
-			if (EndOfBuffer(buffer)) return false;  // the file is shorter than expected
-			b = ReadByte(buffer);
-			*pixel_row++ = GB(b, 4, 4);
-			x++;
-			if (x < info->width) {
-				*pixel_row++ = GB(b, 0, 4);
-				x++;
-			}
-		}
-		/* Padding for 32 bit align */
-		SkipBytes(buffer, pad);
-	}
-	return true;
-}
-
-/**
- * Reads a 4-bit RLE compressed bitmap
- * The bitmap is converted to a 8 bpp bitmap
- */
-static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint i;
-	uint x = 0;
-	uint y = info->height - 1;
-	byte n, c, b;
-	byte *pixel = &data->bitmap[y * info->width];
-	while (y != 0 || x < info->width) {
-		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
-		n = ReadByte(buffer);
-		c = ReadByte(buffer);
-		if (n == 0) {
-			switch (c) {
-			case 0: // end of line
-				x = 0;
-				pixel = &data->bitmap[--y * info->width];
-				break;
-			case 1: // end of bitmap
-				x = info->width;
-				y = 0;
-				pixel = NULL;
-				break;
-			case 2: // delta
-				x += ReadByte(buffer);
-				i = ReadByte(buffer);
-				if (x >= info->width || (y == 0 && i > 0)) return false;
-				y -= i;
-				pixel = &data->bitmap[y * info->width + x];
-				break;
-			default: // uncompressed
-				i = 0;
-				while (i++ < c) {
-					if (EndOfBuffer(buffer) || x >= info->width) return false;
-					b = ReadByte(buffer);
-					*pixel++ = GB(b, 4, 4);
-					x++;
-					if (x < info->width && i++ < c) {
-						*pixel++ = GB(b, 0, 4);
-						x++;
-					}
-				}
-				/* Padding for 16 bit align */
-				SkipBytes(buffer, ((c + 1) / 2) % 2);
-				break;
-			}
-		} else {
-			i = 0;
-			while (i++ < n) {
-				if (EndOfBuffer(buffer) || x >= info->width) return false;
-				*pixel++ = GB(c, 4, 4);
-				x++;
-				if (x < info->width && i++ < n) {
-					*pixel++ = GB(c, 0, 4);
-					x++;
-				}
-			}
-		}
-	}
-	return true;
-}
-
-/**
- * Reads a 8 bpp bitmap
- */
-static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint i;
-	uint y;
-	byte pad = GB(4 - info->width, 0, 2);
-	byte *pixel;
-	for (y = info->height; y > 0; y--) {
-		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
-		pixel = &data->bitmap[(y - 1) * info->width];
-		for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer);
-		/* Padding for 32 bit align */
-		SkipBytes(buffer, pad);
-	}
-	return true;
-}
-
-/**
- * Reads a 8-bit RLE compressed bpp bitmap
- */
-static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint i;
-	uint x = 0;
-	uint y = info->height - 1;
-	byte n, c;
-	byte *pixel = &data->bitmap[y * info->width];
-	while (y != 0 || x < info->width) {
-		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
-		n = ReadByte(buffer);
-		c = ReadByte(buffer);
-		if (n == 0) {
-			switch (c) {
-			case 0: // end of line
-				x = 0;
-				pixel = &data->bitmap[--y * info->width];
-				break;
-			case 1: // end of bitmap
-				x = info->width;
-				y = 0;
-				pixel = NULL;
-				break;
-			case 2: // delta
-				x += ReadByte(buffer);
-				i = ReadByte(buffer);
-				if (x >= info->width || (y == 0 && i > 0)) return false;
-				y -= i;
-				pixel = &data->bitmap[y * info->width + x];
-				break;
-			default: // uncompressed
-				if ((x += c) > info->width) return false;
-				for (i = 0; i < c; i++) *pixel++ = ReadByte(buffer);
-				/* Padding for 16 bit align */
-				SkipBytes(buffer, c % 2);
-				break;
-			}
-		} else {
-			for (i = 0; i < n; i++) {
-				if (x >= info->width) return false;
-				*pixel++ = c;
-				x++;
-			}
-		}
-	}
-	return true;
-}
-
-/**
- * Reads a 24 bpp uncompressed bitmap
- */
-static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint x, y;
-	byte pad = GB(4 - info->width * 3, 0, 2);
-	byte *pixel_row;
-	for (y = info->height; y > 0; y--) {
-		pixel_row = &data->bitmap[(y - 1) * info->width * 3];
-		for (x = 0; x < info->width; x++) {
-			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
-			*(pixel_row + 2) = ReadByte(buffer); // green
-			*(pixel_row + 1) = ReadByte(buffer); // blue
-			*pixel_row       = ReadByte(buffer); // red
-			pixel_row += 3;
-		}
-		/* Padding for 32 bit align */
-		SkipBytes(buffer, pad);
-	}
-	return true;
-}
-
-/*
- * Reads bitmap headers, and palette (if any)
- */
-bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	uint32 header_size;
-	assert(info != NULL);
-
-	/* Reading BMP header */
-	if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM'
-	SkipBytes(buffer, 8); // skip file size and reserved
-	info->offset = ReadDword(buffer);
-
-	/* Reading info header */
-	header_size = ReadDword(buffer);
-	if (header_size < 12) return false; // info header should be at least 12 bytes long
-
-	info->os2_bmp = (header_size == 12); // OS/2 1.x or windows 2.x info header is 12 bytes long
-
-	if (info->os2_bmp) {
-		info->width = ReadWord(buffer);
-		info->height = ReadWord(buffer);
-		header_size -= 8;
-	} else {
-		info->width = ReadDword(buffer);
-		info->height = ReadDword(buffer);
-		header_size -= 12;
-	}
-
-	if (ReadWord(buffer) != 1) return false; // BMP can have only 1 plane
-
-	info->bpp = ReadWord(buffer);
-	if (info->bpp != 1 && info->bpp != 4 && info->bpp != 8 && info->bpp != 24) {
-		/* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */
-		return false;
-	}
-
-	/* Reads compression method if available in info header*/
-	if ((header_size -= 4) >= 4) {
-		info->compression = ReadDword(buffer);
-		header_size -= 4;
-	}
-
-	/* Only 4-bit and 8-bit rle compression is supported */
-	if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false;
-
-	if (info->bpp <= 8) {
-		uint i;
-
-		/* Reads number of colors if available in info header */
-		if (header_size >= 16) {
-			SkipBytes(buffer, 12);                  // skip image size and resolution
-			info->palette_size = ReadDword(buffer); // number of colors in palette
-			SkipBytes(buffer, header_size - 16);    // skip the end of info header
-		}
-		if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
-
-		data->palette = calloc(info->palette_size, sizeof(*(data->palette)));
-		if (data->palette == NULL) return false;
-
-		for (i = 0; i < info->palette_size; i++) {
-			data->palette[i].b = ReadByte(buffer);
-			data->palette[i].g = ReadByte(buffer);
-			data->palette[i].r = ReadByte(buffer);
-			if (!info->os2_bmp) SkipBytes(buffer, 1); // unused
-		}
-	}
-
-	return buffer->real_pos <= info->offset;
-}
-
-/*
- * Reads the bitmap
- * 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
- */
-bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
-{
-	assert(info != NULL && data != NULL);
-
-	data->bitmap = calloc(info->width * info->height, ((info->bpp == 24) ? 3 : 1) * sizeof(byte));
-	if (data->bitmap == NULL) return false;
-
-	/* Load image */
-	SetStreamOffset(buffer, info->offset);
-	switch (info->compression) {
-	case 0: // no compression
-		switch (info->bpp) {
-		case 1:  return BmpRead1(buffer, info, data);
-		case 4:  return BmpRead4(buffer, info, data);
-		case 8:  return BmpRead8(buffer, info, data);
-		case 24: return BmpRead24(buffer, info, data);
-		default: NOT_REACHED(); return false;
-		}
-	case 1:  return BmpRead8Rle(buffer, info, data); // 8-bit RLE compression
-	case 2:  return BmpRead4Rle(buffer, info, data); // 4-bit RLE compression
-	default: NOT_REACHED(); return false;
-	}
-}
-
-void BmpDestroyData(BmpData *data)
-{
-	assert(data != NULL);
-	free(data->palette);
-	free(data->bitmap);
-}
new file mode 100644
--- /dev/null
+++ b/src/bmp.cpp
@@ -0,0 +1,378 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "gfx.h"
+#include "bmp.h"
+#include "macros.h"
+
+void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file) {
+	buffer->pos      = -1;
+	buffer->file     = file;
+	buffer->read     = 0;
+	buffer->real_pos = ftell(file);
+}
+
+static inline void AdvanceBuffer(BmpBuffer *buffer)
+{
+	buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
+	buffer->pos  = 0;
+}
+
+static inline bool EndOfBuffer(BmpBuffer *buffer)
+{
+	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
+	return buffer->pos == buffer->read;
+}
+
+static inline byte ReadByte(BmpBuffer *buffer)
+{
+	if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
+	buffer->real_pos++;
+	return buffer->data[buffer->pos++];
+}
+
+static inline uint16 ReadWord(BmpBuffer *buffer)
+{
+	uint16 var = ReadByte(buffer);
+	return var | (ReadByte(buffer) << 8);
+}
+
+static inline uint32 ReadDword(BmpBuffer *buffer)
+{
+	uint32 var = ReadWord(buffer);
+	return var | (ReadWord(buffer) << 16);
+}
+
+static inline void SkipBytes(BmpBuffer *buffer, int bytes)
+{
+	int i;
+	for (i = 0; i < bytes; i++) ReadByte(buffer);
+}
+
+static inline void SetStreamOffset(BmpBuffer *buffer, int offset)
+{
+	fseek(buffer->file, offset, SEEK_SET);
+	buffer->pos = -1;
+	buffer->real_pos = offset;
+	AdvanceBuffer(buffer);
+}
+
+/**
+ * Reads a 1 bpp uncompressed bitmap
+ * The bitmap is converted to a 8 bpp bitmap
+ */
+static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint x, y, i;
+	byte pad = GB(4 - info->width / 8, 0, 2);
+	byte *pixel_row;
+	byte b;
+	for (y = info->height; y > 0; y--) {
+		x = 0;
+		pixel_row = &data->bitmap[(y - 1) * info->width];
+		while (x < info->width) {
+			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
+			b = ReadByte(buffer);
+			for (i = 8; i > 0; i--) {
+				if (x < info->width) *pixel_row++ = GB(b, i - 1, 1);
+				x++;
+			}
+		}
+		/* Padding for 32 bit align */
+		SkipBytes(buffer, pad);
+	}
+	return true;
+}
+
+/**
+ * Reads a 4 bpp uncompressed bitmap
+ * The bitmap is converted to a 8 bpp bitmap
+ */
+static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint x, y;
+	byte pad = GB(4 - info->width / 2, 0, 2);
+	byte *pixel_row;
+	byte b;
+	for (y = info->height; y > 0; y--) {
+		x = 0;
+		pixel_row = &data->bitmap[(y - 1) * info->width];
+		while (x < info->width) {
+			if (EndOfBuffer(buffer)) return false;  // the file is shorter than expected
+			b = ReadByte(buffer);
+			*pixel_row++ = GB(b, 4, 4);
+			x++;
+			if (x < info->width) {
+				*pixel_row++ = GB(b, 0, 4);
+				x++;
+			}
+		}
+		/* Padding for 32 bit align */
+		SkipBytes(buffer, pad);
+	}
+	return true;
+}
+
+/**
+ * Reads a 4-bit RLE compressed bitmap
+ * The bitmap is converted to a 8 bpp bitmap
+ */
+static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint i;
+	uint x = 0;
+	uint y = info->height - 1;
+	byte n, c, b;
+	byte *pixel = &data->bitmap[y * info->width];
+	while (y != 0 || x < info->width) {
+		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
+		n = ReadByte(buffer);
+		c = ReadByte(buffer);
+		if (n == 0) {
+			switch (c) {
+			case 0: // end of line
+				x = 0;
+				pixel = &data->bitmap[--y * info->width];
+				break;
+			case 1: // end of bitmap
+				x = info->width;
+				y = 0;
+				pixel = NULL;
+				break;
+			case 2: // delta
+				x += ReadByte(buffer);
+				i = ReadByte(buffer);
+				if (x >= info->width || (y == 0 && i > 0)) return false;
+				y -= i;
+				pixel = &data->bitmap[y * info->width + x];
+				break;
+			default: // uncompressed
+				i = 0;
+				while (i++ < c) {
+					if (EndOfBuffer(buffer) || x >= info->width) return false;
+					b = ReadByte(buffer);
+					*pixel++ = GB(b, 4, 4);
+					x++;
+					if (x < info->width && i++ < c) {
+						*pixel++ = GB(b, 0, 4);
+						x++;
+					}
+				}
+				/* Padding for 16 bit align */
+				SkipBytes(buffer, ((c + 1) / 2) % 2);
+				break;
+			}
+		} else {
+			i = 0;
+			while (i++ < n) {
+				if (EndOfBuffer(buffer) || x >= info->width) return false;
+				*pixel++ = GB(c, 4, 4);
+				x++;
+				if (x < info->width && i++ < n) {
+					*pixel++ = GB(c, 0, 4);
+					x++;
+				}
+			}
+		}
+	}
+	return true;
+}
+
+/**
+ * Reads a 8 bpp bitmap
+ */
+static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint i;
+	uint y;
+	byte pad = GB(4 - info->width, 0, 2);
+	byte *pixel;
+	for (y = info->height; y > 0; y--) {
+		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
+		pixel = &data->bitmap[(y - 1) * info->width];
+		for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer);
+		/* Padding for 32 bit align */
+		SkipBytes(buffer, pad);
+	}
+	return true;
+}
+
+/**
+ * Reads a 8-bit RLE compressed bpp bitmap
+ */
+static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint i;
+	uint x = 0;
+	uint y = info->height - 1;
+	byte n, c;
+	byte *pixel = &data->bitmap[y * info->width];
+	while (y != 0 || x < info->width) {
+		if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
+		n = ReadByte(buffer);
+		c = ReadByte(buffer);
+		if (n == 0) {
+			switch (c) {
+			case 0: // end of line
+				x = 0;
+				pixel = &data->bitmap[--y * info->width];
+				break;
+			case 1: // end of bitmap
+				x = info->width;
+				y = 0;
+				pixel = NULL;
+				break;
+			case 2: // delta
+				x += ReadByte(buffer);
+				i = ReadByte(buffer);
+				if (x >= info->width || (y == 0 && i > 0)) return false;
+				y -= i;
+				pixel = &data->bitmap[y * info->width + x];
+				break;
+			default: // uncompressed
+				if ((x += c) > info->width) return false;
+				for (i = 0; i < c; i++) *pixel++ = ReadByte(buffer);
+				/* Padding for 16 bit align */
+				SkipBytes(buffer, c % 2);
+				break;
+			}
+		} else {
+			for (i = 0; i < n; i++) {
+				if (x >= info->width) return false;
+				*pixel++ = c;
+				x++;
+			}
+		}
+	}
+	return true;
+}
+
+/**
+ * Reads a 24 bpp uncompressed bitmap
+ */
+static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint x, y;
+	byte pad = GB(4 - info->width * 3, 0, 2);
+	byte *pixel_row;
+	for (y = info->height; y > 0; y--) {
+		pixel_row = &data->bitmap[(y - 1) * info->width * 3];
+		for (x = 0; x < info->width; x++) {
+			if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
+			*(pixel_row + 2) = ReadByte(buffer); // green
+			*(pixel_row + 1) = ReadByte(buffer); // blue
+			*pixel_row       = ReadByte(buffer); // red
+			pixel_row += 3;
+		}
+		/* Padding for 32 bit align */
+		SkipBytes(buffer, pad);
+	}
+	return true;
+}
+
+/*
+ * Reads bitmap headers, and palette (if any)
+ */
+bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	uint32 header_size;
+	assert(info != NULL);
+
+	/* Reading BMP header */
+	if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM'
+	SkipBytes(buffer, 8); // skip file size and reserved
+	info->offset = ReadDword(buffer);
+
+	/* Reading info header */
+	header_size = ReadDword(buffer);
+	if (header_size < 12) return false; // info header should be at least 12 bytes long
+
+	info->os2_bmp = (header_size == 12); // OS/2 1.x or windows 2.x info header is 12 bytes long
+
+	if (info->os2_bmp) {
+		info->width = ReadWord(buffer);
+		info->height = ReadWord(buffer);
+		header_size -= 8;
+	} else {
+		info->width = ReadDword(buffer);
+		info->height = ReadDword(buffer);
+		header_size -= 12;
+	}
+
+	if (ReadWord(buffer) != 1) return false; // BMP can have only 1 plane
+
+	info->bpp = ReadWord(buffer);
+	if (info->bpp != 1 && info->bpp != 4 && info->bpp != 8 && info->bpp != 24) {
+		/* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */
+		return false;
+	}
+
+	/* Reads compression method if available in info header*/
+	if ((header_size -= 4) >= 4) {
+		info->compression = ReadDword(buffer);
+		header_size -= 4;
+	}
+
+	/* Only 4-bit and 8-bit rle compression is supported */
+	if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false;
+
+	if (info->bpp <= 8) {
+		uint i;
+
+		/* Reads number of colors if available in info header */
+		if (header_size >= 16) {
+			SkipBytes(buffer, 12);                  // skip image size and resolution
+			info->palette_size = ReadDword(buffer); // number of colors in palette
+			SkipBytes(buffer, header_size - 16);    // skip the end of info header
+		}
+		if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
+
+		data->palette = calloc(info->palette_size, sizeof(*(data->palette)));
+		if (data->palette == NULL) return false;
+
+		for (i = 0; i < info->palette_size; i++) {
+			data->palette[i].b = ReadByte(buffer);
+			data->palette[i].g = ReadByte(buffer);
+			data->palette[i].r = ReadByte(buffer);
+			if (!info->os2_bmp) SkipBytes(buffer, 1); // unused
+		}
+	}
+
+	return buffer->real_pos <= info->offset;
+}
+
+/*
+ * Reads the bitmap
+ * 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
+ */
+bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
+{
+	assert(info != NULL && data != NULL);
+
+	data->bitmap = calloc(info->width * info->height, ((info->bpp == 24) ? 3 : 1) * sizeof(byte));
+	if (data->bitmap == NULL) return false;
+
+	/* Load image */
+	SetStreamOffset(buffer, info->offset);
+	switch (info->compression) {
+	case 0: // no compression
+		switch (info->bpp) {
+		case 1:  return BmpRead1(buffer, info, data);
+		case 4:  return BmpRead4(buffer, info, data);
+		case 8:  return BmpRead8(buffer, info, data);
+		case 24: return BmpRead24(buffer, info, data);
+		default: NOT_REACHED(); return false;
+		}
+	case 1:  return BmpRead8Rle(buffer, info, data); // 8-bit RLE compression
+	case 2:  return BmpRead4Rle(buffer, info, data); // 4-bit RLE compression
+	default: NOT_REACHED(); return false;
+	}
+}
+
+void BmpDestroyData(BmpData *data)
+{
+	assert(data != NULL);
+	free(data->palette);
+	free(data->bitmap);
+}
deleted file mode 100644
--- a/src/bridge_gui.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* $Id$ */
-
-/** @file bridge_gui.c Graphical user interface for bridge construction*/
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "command.h"
-#include "sound.h"
-#include "variables.h"
-#include "bridge.h"
-
-static struct BridgeData {
-	uint count;
-	TileIndex start_tile;
-	TileIndex end_tile;
-	byte type;
-	byte indexes[MAX_BRIDGES];
-	int32 costs[MAX_BRIDGES];
-} _bridgedata;
-
-void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
-}
-
-static void BuildBridge(Window *w, int i)
-{
-	DeleteWindow(w);
-	DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
-		_bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge,
-		CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
-}
-
-static void BuildBridgeWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		uint i;
-
-		DrawWindowWidgets(w);
-
-		for (i = 0; i < 4 && i + w->vscroll.pos < _bridgedata.count; i++) {
-			const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]];
-
-			SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
-			SetDParam(1, b->speed);
-			SetDParam(0, b->material);
-			DrawSprite(b->sprite, 3, 15 + i * 22);
-
-			DrawString(44, 15 + i * 22 , STR_500D, 0);
-		}
-	} break;
-
-	case WE_KEYPRESS: {
-		uint i = e->we.keypress.keycode - '1';
-		if (i < 9 && i < _bridgedata.count) {
-			e->we.keypress.cont = false;
-			BuildBridge(w, i);
-		}
-
-		break;
-	}
-
-	case WE_CLICK:
-		if (e->we.click.widget == 2) {
-			uint ind = ((int)e->we.click.pt.y - 14) / 22;
-			if (ind < 4 && (ind += w->vscroll.pos) < _bridgedata.count)
-				BuildBridge(w, ind);
-		}
-		break;
-	}
-}
-
-static const Widget _build_bridge_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   199,     0,    13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX,   RESIZE_NONE,     7,     0,   187,    14,   101, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},
-{  WWT_SCROLLBAR,   RESIZE_NONE,     7,   188,   199,    14,   101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_bridge_desc = {
-	WDP_AUTO, WDP_AUTO, 200, 102,
-	WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_bridge_widgets,
-	BuildBridgeWndProc
-};
-
-
-static const Widget _build_road_bridge_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   199,     0,    13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX,   RESIZE_NONE,     7,     0,   187,    14,   101, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},
-{  WWT_SCROLLBAR,   RESIZE_NONE,     7,   188,   199,    14,   101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_road_bridge_desc = {
-	WDP_AUTO, WDP_AUTO, 200, 102,
-	WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_road_bridge_widgets,
-	BuildBridgeWndProc
-};
-
-
-void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type)
-{
-	uint j = 0;
-	int32 ret;
-	StringID errmsg;
-
-	DeleteWindowById(WC_BUILD_BRIDGE, 0);
-
-	_bridgedata.type = bridge_type;
-	_bridgedata.start_tile = start;
-	_bridgedata.end_tile = end;
-
-	errmsg = INVALID_STRING_ID;
-
-	// only query bridge building possibility once, result is the same for all bridges!
-	// returns CMD_ERROR on failure, and price on success
-	ret = DoCommand(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
-
-	if (CmdFailed(ret)) {
-		errmsg = _error_message;
-	} else {
-		// check which bridges can be built
-		int bridge_len;         // length of the middle parts of the bridge
-		int tot_bridgedata_len; // total length of bridge
-
-		// get absolute bridge length
-		bridge_len = GetBridgeLength(start, end);
-		tot_bridgedata_len = bridge_len + 2;
-
-		tot_bridgedata_len = CalcBridgeLenCostFactor(tot_bridgedata_len);
-
-		for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
-			if (CheckBridge_Stuff(bridge_type, bridge_len)) {
-				const Bridge *b = &_bridge[bridge_type];
-				// bridge is accepted, add to list
-				// add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST)
-				_bridgedata.costs[j] = ret + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8);
-				_bridgedata.indexes[j] = bridge_type;
-				j++;
-			}
-		}
-	}
-
-	_bridgedata.count = j;
-
-	if (j != 0) {
-		Window *w = AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc);
-		w->vscroll.cap = 4;
-		w->vscroll.count = (byte)j;
-	} else {
-		ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/bridge_gui.cpp
@@ -0,0 +1,167 @@
+/* $Id$ */
+
+/** @file bridge_gui.c Graphical user interface for bridge construction*/
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "command.h"
+#include "sound.h"
+#include "variables.h"
+#include "bridge.h"
+
+static struct BridgeData {
+	uint count;
+	TileIndex start_tile;
+	TileIndex end_tile;
+	byte type;
+	byte indexes[MAX_BRIDGES];
+	int32 costs[MAX_BRIDGES];
+} _bridgedata;
+
+void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
+}
+
+static void BuildBridge(Window *w, int i)
+{
+	DeleteWindow(w);
+	DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
+		_bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge,
+		CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
+}
+
+static void BuildBridgeWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		uint i;
+
+		DrawWindowWidgets(w);
+
+		for (i = 0; i < 4 && i + w->vscroll.pos < _bridgedata.count; i++) {
+			const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]];
+
+			SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
+			SetDParam(1, b->speed);
+			SetDParam(0, b->material);
+			DrawSprite(b->sprite, 3, 15 + i * 22);
+
+			DrawString(44, 15 + i * 22 , STR_500D, 0);
+		}
+	} break;
+
+	case WE_KEYPRESS: {
+		uint i = e->we.keypress.keycode - '1';
+		if (i < 9 && i < _bridgedata.count) {
+			e->we.keypress.cont = false;
+			BuildBridge(w, i);
+		}
+
+		break;
+	}
+
+	case WE_CLICK:
+		if (e->we.click.widget == 2) {
+			uint ind = ((int)e->we.click.pt.y - 14) / 22;
+			if (ind < 4 && (ind += w->vscroll.pos) < _bridgedata.count)
+				BuildBridge(w, ind);
+		}
+		break;
+	}
+}
+
+static const Widget _build_bridge_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   199,     0,    13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_MATRIX,   RESIZE_NONE,     7,     0,   187,    14,   101, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},
+{  WWT_SCROLLBAR,   RESIZE_NONE,     7,   188,   199,    14,   101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_bridge_desc = {
+	WDP_AUTO, WDP_AUTO, 200, 102,
+	WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_bridge_widgets,
+	BuildBridgeWndProc
+};
+
+
+static const Widget _build_road_bridge_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   199,     0,    13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_MATRIX,   RESIZE_NONE,     7,     0,   187,    14,   101, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},
+{  WWT_SCROLLBAR,   RESIZE_NONE,     7,   188,   199,    14,   101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_road_bridge_desc = {
+	WDP_AUTO, WDP_AUTO, 200, 102,
+	WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_road_bridge_widgets,
+	BuildBridgeWndProc
+};
+
+
+void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type)
+{
+	uint j = 0;
+	int32 ret;
+	StringID errmsg;
+
+	DeleteWindowById(WC_BUILD_BRIDGE, 0);
+
+	_bridgedata.type = bridge_type;
+	_bridgedata.start_tile = start;
+	_bridgedata.end_tile = end;
+
+	errmsg = INVALID_STRING_ID;
+
+	// only query bridge building possibility once, result is the same for all bridges!
+	// returns CMD_ERROR on failure, and price on success
+	ret = DoCommand(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
+
+	if (CmdFailed(ret)) {
+		errmsg = _error_message;
+	} else {
+		// check which bridges can be built
+		int bridge_len;         // length of the middle parts of the bridge
+		int tot_bridgedata_len; // total length of bridge
+
+		// get absolute bridge length
+		bridge_len = GetBridgeLength(start, end);
+		tot_bridgedata_len = bridge_len + 2;
+
+		tot_bridgedata_len = CalcBridgeLenCostFactor(tot_bridgedata_len);
+
+		for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
+			if (CheckBridge_Stuff(bridge_type, bridge_len)) {
+				const Bridge *b = &_bridge[bridge_type];
+				// bridge is accepted, add to list
+				// add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST)
+				_bridgedata.costs[j] = ret + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8);
+				_bridgedata.indexes[j] = bridge_type;
+				j++;
+			}
+		}
+	}
+
+	_bridgedata.count = j;
+
+	if (j != 0) {
+		Window *w = AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc);
+		w->vscroll.cap = 4;
+		w->vscroll.count = (byte)j;
+	} else {
+		ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
+	}
+}
deleted file mode 100644
--- a/src/bridge_map.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "variables.h"
-
-
-TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
-{
-	TileIndexDiff delta = TileOffsByDiagDir(dir);
-
-	dir = ReverseDiagDir(dir);
-	do {
-		tile += delta;
-	} while (!IsBridgeTile(tile) || GetBridgeRampDirection(tile) != dir);
-
-	return tile;
-}
-
-
-TileIndex GetNorthernBridgeEnd(TileIndex t)
-{
-	return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t))));
-}
-
-
-TileIndex GetSouthernBridgeEnd(TileIndex t)
-{
-	return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
-}
-
-
-TileIndex GetOtherBridgeEnd(TileIndex tile)
-{
-	assert(IsBridgeTile(tile));
-	return GetBridgeEnd(tile, GetBridgeRampDirection(tile));
-}
-
-uint GetBridgeHeight(TileIndex t)
-{
-	uint h;
-	uint tileh = GetTileSlope(t, &h);
-	uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(t)));
-
-	// one height level extra if the ramp is on a flat foundation
-	return
-		h + TILE_HEIGHT +
-		(IS_INT_INSIDE(f, 1, 15) ? TILE_HEIGHT : 0) +
-		(IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/bridge_map.cpp
@@ -0,0 +1,51 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "variables.h"
+
+
+TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
+{
+	TileIndexDiff delta = TileOffsByDiagDir(dir);
+
+	dir = ReverseDiagDir(dir);
+	do {
+		tile += delta;
+	} while (!IsBridgeTile(tile) || GetBridgeRampDirection(tile) != dir);
+
+	return tile;
+}
+
+
+TileIndex GetNorthernBridgeEnd(TileIndex t)
+{
+	return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t))));
+}
+
+
+TileIndex GetSouthernBridgeEnd(TileIndex t)
+{
+	return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
+}
+
+
+TileIndex GetOtherBridgeEnd(TileIndex tile)
+{
+	assert(IsBridgeTile(tile));
+	return GetBridgeEnd(tile, GetBridgeRampDirection(tile));
+}
+
+uint GetBridgeHeight(TileIndex t)
+{
+	uint h;
+	uint tileh = GetTileSlope(t, &h);
+	uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(t)));
+
+	// one height level extra if the ramp is on a flat foundation
+	return
+		h + TILE_HEIGHT +
+		(IS_INT_INSIDE(f, 1, 15) ? TILE_HEIGHT : 0) +
+		(IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
+}
deleted file mode 100644
--- a/src/build_vehicle_gui.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "aircraft.h"
-#include "debug.h"
-#include "functions.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "window.h"
-#include "gui.h"
-#include "vehicle.h"
-#include "gfx.h"
-#include "station.h"
-#include "command.h"
-#include "engine.h"
-#include "player.h"
-#include "depot.h"
-#include "airport.h"
-#include "vehicle_gui.h"
-#include "newgrf_engine.h"
-#include "date.h"
-#include "strings.h"
-
-
-enum BuildVehicleWidgets {
-	BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
-	BUILD_VEHICLE_WIDGET_CAPTION,
-	BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
-	BUILD_VEHICLE_WIDGET_SORT_TEXT,
-	BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
-	BUILD_VEHICLE_WIDGET_LIST,
-	BUILD_VEHICLE_WIDGET_SCROLLBAR,
-	BUILD_VEHICLE_WIDGET_PANEL,
-	BUILD_VEHICLE_WIDGET_BUILD,
-	BUILD_VEHICLE_WIDGET_RENAME,
-	BUILD_VEHICLE_WIDGET_RESIZE,
-};
-
-static const Widget _build_vehicle_widgets[] = {
-	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW },
-	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   239,     0,    13, STR_A005_NEW_AIRCRAFT,   STR_018C_WINDOW_TITLE_DRAG_THIS },
-	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,             STR_SORT_ORDER_TIP},
-	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   227,    14,    25, 0x0,                     STR_SORT_CRITERIA_TIP},
-	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   228,   239,    14,    25, STR_0225,                STR_SORT_CRITERIA_TIP},
-	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   227,    26,   121, 0x401,                   STR_A025_AIRCRAFT_SELECTION_LIST },
-	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   228,   239,    26,   121, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST },
-	{      WWT_PANEL,     RESIZE_TB,    14,     0,   239,   122,   213, 0x0,                     STR_NULL },
-
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   114,   214,   225, STR_A006_BUILD_AIRCRAFT, STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT },
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   115,   227,   214,   225, STR_A037_RENAME,         STR_A038_RENAME_AIRCRAFT_TYPE },
-	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   228,   239,   214,   225, 0x0,                     STR_RESIZE_BUTTON },
-	{   WIDGETS_END},
-};
-
-static bool _internal_sort_order; // descending/ascending
-static byte _last_sort_criteria = 0;
-static bool _last_sort_order = false;
-
-static int CDECL EngineNumberSorter(const void *a, const void *b)
-{
-	const EngineID va = *(const EngineID*)a;
-	const EngineID vb = *(const EngineID*)b;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL EngineIntroDateSorter(const void *a, const void *b)
-{
-	const int va = GetEngine(*(const EngineID*)a)->intro_date;
-	const int vb = GetEngine(*(const EngineID*)b)->intro_date;
-	const int r = va - vb;
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL EngineNameSorter(const void *a, const void *b)
-{
-	static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
-	static char     last_name[2][64] = { "\0", "\0" };
-
-	const EngineID va = *(const EngineID*)a;
-	const EngineID vb = *(const EngineID*)b;
-	int r;
-
-	if (va != last_engine[0]) {
-		last_engine[0] = va;
-		GetString(last_name[0], GetCustomEngineName(va), lastof(last_name[0]));
-	}
-
-	if (vb != last_engine[1]) {
-		last_engine[1] = vb;
-		GetString(last_name[1], GetCustomEngineName(vb), lastof(last_name[1]));
-	}
-
-	r = strcmp(last_name[0], last_name[1]); // sort by name
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL EngineReliabilitySorter(const void *a, const void *b)
-{
-	const int va = GetEngine(*(const EngineID*)a)->reliability;
-	const int vb = GetEngine(*(const EngineID*)b)->reliability;
-	const int r = va - vb;
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-/* Aircraft sorting functions */
-
-static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
-{
-	const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost;
-	const int vb = AircraftVehInfo(*(const EngineID*)b)->base_cost;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
-{
-	const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
-	const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
-	const int r = va - vb;
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL AircraftEngineRunningCostSorter(const void *a, const void *b)
-{
-	const int va = AircraftVehInfo(*(const EngineID*)a)->running_cost;
-	const int vb = AircraftVehInfo(*(const EngineID*)b)->running_cost;
-	const int r = va - vb;
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
-{
-	const int va = AircraftVehInfo(*(const EngineID*)a)->passenger_capacity;
-	const int vb = AircraftVehInfo(*(const EngineID*)b)->passenger_capacity;
-	const int r = va - vb;
-
-	if (r == 0) {
-		/* Use EngineID to sort instead since we want consistent sorting */
-		return EngineNumberSorter(a, b);
-	}
-	return _internal_sort_order ? -r : r;
-}
-
-static EngList_SortTypeFunction * const _aircraft_sorter[] = {
-	&EngineNumberSorter,
-	&AircraftEngineCostSorter,
-	&AircraftEngineSpeedSorter,
-	&EngineIntroDateSorter,
-	&EngineNameSorter,
-	&AircraftEngineRunningCostSorter,
-	&EngineReliabilitySorter,
-	&AircraftEngineCargoSorter,
-};
-
-static const StringID _aircraft_sort_listing[] = {
-	STR_ENGINE_SORT_ENGINE_ID,
-	STR_ENGINE_SORT_COST,
-	STR_SORT_BY_MAX_SPEED,
-	STR_ENGINE_SORT_INTRO_DATE,
-	STR_SORT_BY_DROPDOWN_NAME,
-	STR_ENGINE_SORT_RUNNING_COST,
-	STR_SORT_BY_RELIABILITY,
-	STR_ENGINE_SORT_CARGO_CAPACITY,
-	INVALID_STRING_ID
-};
-
-
-/**
-* Draw the purchase info details of an aircraft at a given location.
- * @param x,y location where to draw the info
- * @param engine_number the engine of which to draw the info of
- */
-void DrawAircraftPurchaseInfo(int x, int y, uint w, EngineID engine_number)
-{
-	const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number);
-	const Engine *e = GetEngine(engine_number);
-	CargoID cargo;
-	YearMonthDay ymd;
-	ConvertDateToYMD(e->intro_date, &ymd);
-
-	/* Purchase cost - Max speed */
-	SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
-	SetDParam(1, avi->max_speed * 128 / 10);
-	DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
-	y += 10;
-
-	/* Cargo capacity */
-	cargo = FindFirstRefittableCargo(engine_number);
-	if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
-		SetDParam(0, avi->passenger_capacity);
-		SetDParam(1, avi->mail_capacity);
-		DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, 0);
-	} else {
-		/* Note, if the default capacity is selected by the refit capacity
-		* callback, then the capacity shown is likely to be incorrect. */
-		SetDParam(0, cargo);
-		SetDParam(1, AircraftDefaultCargoCapacity(cargo, engine_number));
-		SetDParam(2, STR_9842_REFITTABLE);
-		DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
-	}
-	y += 10;
-
-	/* Running cost */
-	SetDParam(0, avi->running_cost * _price.aircraft_running >> 8);
-	DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
-	y += 10;
-
-	/* Design date - Life length */
-	SetDParam(0, ymd.year);
-	SetDParam(1, e->lifelength);
-	DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
-	y += 10;
-
-	/* Reliability */
-	SetDParam(0, e->reliability * 100 >> 16);
-	DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
-	y += 10;
-
-	/* Additional text from NewGRF */
-	y += ShowAdditionalText(x, y, w, engine_number);
-	y += ShowRefitOptionsList(x, y, w, engine_number);
-}
-
-void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection)
-{
-	PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-	DrawSprite(GetAircraftImage(v, DIR_W) | pal, x + 25, y + 10);
-	if (v->subtype == 0) {
-		SpriteID rotor_sprite = GetCustomRotorSprite(v, true);
-		if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
-		DrawSprite(rotor_sprite, x + 25, y + 5);
-	}
-	if (v->index == selection) {
-		DrawFrameRect(x - 1, y - 1, x + 58, y + 21, 0xF, FR_BORDERONLY);
-	}
-}
-
-void CcBuildAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		const Vehicle *v = GetVehicle(_new_vehicle_id);
-
-		if (v->tile == _backup_orders_tile) {
-			_backup_orders_tile = 0;
-			RestoreVehicleOrders(v, _backup_orders_data);
-		}
-		ShowAircraftViewWindow(v);
-	}
-}
-
-static void GenerateBuildAircraftList(Window *w)
-{
-	EngineID eid, sel_id;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	EngList_RemoveAll(&bv->eng_list);
-
-	/* Make list of all available planes.
-	 * Also check to see if the previously selected plane is still available,
-	 * and if not, reset selection to INVALID_ENGINE. This could be the case
-	 * when planes become obsolete and are removed */
-	sel_id = INVALID_ENGINE;
-	for (eid = AIRCRAFT_ENGINES_INDEX; eid < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; eid++) {
-		if (IsEngineBuildable(eid, VEH_Aircraft, _local_player)) {
-			const AircraftVehicleInfo *avi = AircraftVehInfo(eid);
-			switch (bv->filter.acc_planes) {
-				case HELICOPTERS_ONLY:
-					if (avi->subtype != 0) continue; // if not helicopter
-					break;
-
-				case AIRCRAFT_ONLY:
-					if (avi->subtype == 0) continue; // if helicopter
-					break;
-
-				case ALL: break;
-			}
-			EngList_Add(&bv->eng_list, eid);
-
-			if (eid == bv->sel_engine) sel_id = eid;
-		}
-	}
-
-	bv->sel_engine = sel_id;
-}
-
-static void GenerateBuildList(Window *w)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	switch (bv->vehicle_type) {
-		case VEH_Aircraft:
-			GenerateBuildAircraftList(w);
-			_internal_sort_order = bv->descending_sort_order;
-			EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]);
-			break;
-
-		default: NOT_REACHED();
-	}
-}
-
-static void DrawBuildAircraftWindow(Window *w)
-{
-	const buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0);
-
-	SetVScrollCount(w, EngList_Count(&bv->eng_list));
-	DrawWindowWidgets(w);
-
-	{
-		int x = 2;
-		int y = 27;
-		EngineID selected_id = bv->sel_engine;
-		EngineID eid = w->vscroll.pos;
-		uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list));
-
-		for (; eid < max; eid++) {
-			const EngineID engine = bv->eng_list[eid];
-
-			DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10);
-			DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player));
-			y += 24;
-		}
-
-		if (selected_id != INVALID_ENGINE) {
-			const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
-			DrawAircraftPurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id);
-		}
-	}
-	DrawString(85, 15, _aircraft_sort_listing[bv->sort_criteria], 0x10);
-	DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
-}
-
-static void BuildAircraftClickEvent(Window *w, WindowEvent *e)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	switch (e->we.click.widget) {
-		case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
-			bv->descending_sort_order ^= true;
-			_last_sort_order = bv->descending_sort_order;
-			GenerateBuildList(w);
-			SetWindowDirty(w);
-			break;
-
-		case BUILD_VEHICLE_WIDGET_LIST: {
-			uint i = (e->we.click.pt.y - 26) / 24 + w->vscroll.pos;
-			uint num_items = EngList_Count(&bv->eng_list);
-			bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
-			SetWindowDirty(w);
-			break;
-		}
-
-		case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
-			return;
-
-		case BUILD_VEHICLE_WIDGET_BUILD: {
-			EngineID sel_eng = bv->sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
-			}
-			break;
-		}
-
-		case BUILD_VEHICLE_WIDGET_RENAME: {
-			EngineID sel_eng = bv->sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				bv->rename_engine = sel_eng;
-				ShowQueryString(GetCustomEngineName(sel_eng), STR_A039_RENAME_AIRCRAFT_TYPE, 31, 160, w, CS_ALPHANUMERAL);
-			}
-			break;
-		}
-	}
-}
-
-static void NewAircraftWndProc(Window *w, WindowEvent *e)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	switch (e->event) {
-		case WE_INVALIDATE_DATA:
-			GenerateBuildList(w);
-			break;
-
-		case WE_DESTROY:
-			EngList_Destroy(&bv->eng_list);
-			break;
-
-		case WE_PAINT:
-			DrawBuildAircraftWindow(w);
-			break;
-
-		case WE_CLICK:
-			BuildAircraftClickEvent(w, e);
-			break;
-
-		case WE_ON_EDIT_TEXT: {
-			if (e->we.edittext.str[0] != '\0') {
-				_cmd_text = e->we.edittext.str;
-				DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE));
-			}
-			break;
-		}
-
-		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-			if (bv->sort_criteria != e->we.dropdown.index) {
-				bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
-				GenerateBuildList(w);
-			}
-			SetWindowDirty(w);
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 24;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-			break;
-	}
-}
-
-static const WindowDesc _build_vehicle_desc = {
-	WDP_AUTO, WDP_AUTO, 240, 226,
-	WC_BUILD_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_build_vehicle_widgets,
-	NewAircraftWndProc
-};
-
-void ShowBuildVehicleWindow(TileIndex tile, byte type)
-{
-	buildvehicle_d *bv;
-	Window *w;
-
-	DeleteWindowById(WC_BUILD_VEHICLE, tile);
-	w = AllocateWindowDescFront(&_build_vehicle_desc, tile);
-	if (w == NULL) return;
-
-	w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
-	w->resize.step_height = GetVehicleListHeight(type);
-	w->vscroll.cap = 4;
-	w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-
-	bv = &WP(w, buildvehicle_d);
-	EngList_Create(&bv->eng_list);
-	bv->sel_engine            = INVALID_ENGINE;
-	bv->sort_criteria         = _last_sort_criteria;
-	bv->descending_sort_order = _last_sort_order;
-
-	bv->vehicle_type = type;
-
-	switch (type) {
-		case VEH_Aircraft: {
-			byte acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes;
-			bv->filter.acc_planes = acc_planes;
-			break;
-		}
-		default: NOT_REACHED();
-	}
-
-	GenerateBuildList(w);
-	/* Select the first plane in the list as default when opening the window */
-	if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
-}
new file mode 100644
--- /dev/null
+++ b/src/build_vehicle_gui.cpp
@@ -0,0 +1,492 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "aircraft.h"
+#include "debug.h"
+#include "functions.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "window.h"
+#include "gui.h"
+#include "vehicle.h"
+#include "gfx.h"
+#include "station.h"
+#include "command.h"
+#include "engine.h"
+#include "player.h"
+#include "depot.h"
+#include "airport.h"
+#include "vehicle_gui.h"
+#include "newgrf_engine.h"
+#include "date.h"
+#include "strings.h"
+
+
+enum BuildVehicleWidgets {
+	BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
+	BUILD_VEHICLE_WIDGET_CAPTION,
+	BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
+	BUILD_VEHICLE_WIDGET_SORT_TEXT,
+	BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
+	BUILD_VEHICLE_WIDGET_LIST,
+	BUILD_VEHICLE_WIDGET_SCROLLBAR,
+	BUILD_VEHICLE_WIDGET_PANEL,
+	BUILD_VEHICLE_WIDGET_BUILD,
+	BUILD_VEHICLE_WIDGET_RENAME,
+	BUILD_VEHICLE_WIDGET_RESIZE,
+};
+
+static const Widget _build_vehicle_widgets[] = {
+	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW },
+	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   239,     0,    13, STR_A005_NEW_AIRCRAFT,   STR_018C_WINDOW_TITLE_DRAG_THIS },
+	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,             STR_SORT_ORDER_TIP},
+	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   227,    14,    25, 0x0,                     STR_SORT_CRITERIA_TIP},
+	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   228,   239,    14,    25, STR_0225,                STR_SORT_CRITERIA_TIP},
+	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   227,    26,   121, 0x401,                   STR_A025_AIRCRAFT_SELECTION_LIST },
+	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   228,   239,    26,   121, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST },
+	{      WWT_PANEL,     RESIZE_TB,    14,     0,   239,   122,   213, 0x0,                     STR_NULL },
+
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   114,   214,   225, STR_A006_BUILD_AIRCRAFT, STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT },
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   115,   227,   214,   225, STR_A037_RENAME,         STR_A038_RENAME_AIRCRAFT_TYPE },
+	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   228,   239,   214,   225, 0x0,                     STR_RESIZE_BUTTON },
+	{   WIDGETS_END},
+};
+
+static bool _internal_sort_order; // descending/ascending
+static byte _last_sort_criteria = 0;
+static bool _last_sort_order = false;
+
+static int CDECL EngineNumberSorter(const void *a, const void *b)
+{
+	const EngineID va = *(const EngineID*)a;
+	const EngineID vb = *(const EngineID*)b;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL EngineIntroDateSorter(const void *a, const void *b)
+{
+	const int va = GetEngine(*(const EngineID*)a)->intro_date;
+	const int vb = GetEngine(*(const EngineID*)b)->intro_date;
+	const int r = va - vb;
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL EngineNameSorter(const void *a, const void *b)
+{
+	static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
+	static char     last_name[2][64] = { "\0", "\0" };
+
+	const EngineID va = *(const EngineID*)a;
+	const EngineID vb = *(const EngineID*)b;
+	int r;
+
+	if (va != last_engine[0]) {
+		last_engine[0] = va;
+		GetString(last_name[0], GetCustomEngineName(va), lastof(last_name[0]));
+	}
+
+	if (vb != last_engine[1]) {
+		last_engine[1] = vb;
+		GetString(last_name[1], GetCustomEngineName(vb), lastof(last_name[1]));
+	}
+
+	r = strcmp(last_name[0], last_name[1]); // sort by name
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL EngineReliabilitySorter(const void *a, const void *b)
+{
+	const int va = GetEngine(*(const EngineID*)a)->reliability;
+	const int vb = GetEngine(*(const EngineID*)b)->reliability;
+	const int r = va - vb;
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+/* Aircraft sorting functions */
+
+static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
+{
+	const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost;
+	const int vb = AircraftVehInfo(*(const EngineID*)b)->base_cost;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
+{
+	const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
+	const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
+	const int r = va - vb;
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL AircraftEngineRunningCostSorter(const void *a, const void *b)
+{
+	const int va = AircraftVehInfo(*(const EngineID*)a)->running_cost;
+	const int vb = AircraftVehInfo(*(const EngineID*)b)->running_cost;
+	const int r = va - vb;
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
+{
+	const int va = AircraftVehInfo(*(const EngineID*)a)->passenger_capacity;
+	const int vb = AircraftVehInfo(*(const EngineID*)b)->passenger_capacity;
+	const int r = va - vb;
+
+	if (r == 0) {
+		/* Use EngineID to sort instead since we want consistent sorting */
+		return EngineNumberSorter(a, b);
+	}
+	return _internal_sort_order ? -r : r;
+}
+
+static EngList_SortTypeFunction * const _aircraft_sorter[] = {
+	&EngineNumberSorter,
+	&AircraftEngineCostSorter,
+	&AircraftEngineSpeedSorter,
+	&EngineIntroDateSorter,
+	&EngineNameSorter,
+	&AircraftEngineRunningCostSorter,
+	&EngineReliabilitySorter,
+	&AircraftEngineCargoSorter,
+};
+
+static const StringID _aircraft_sort_listing[] = {
+	STR_ENGINE_SORT_ENGINE_ID,
+	STR_ENGINE_SORT_COST,
+	STR_SORT_BY_MAX_SPEED,
+	STR_ENGINE_SORT_INTRO_DATE,
+	STR_SORT_BY_DROPDOWN_NAME,
+	STR_ENGINE_SORT_RUNNING_COST,
+	STR_SORT_BY_RELIABILITY,
+	STR_ENGINE_SORT_CARGO_CAPACITY,
+	INVALID_STRING_ID
+};
+
+
+/**
+* Draw the purchase info details of an aircraft at a given location.
+ * @param x,y location where to draw the info
+ * @param engine_number the engine of which to draw the info of
+ */
+void DrawAircraftPurchaseInfo(int x, int y, uint w, EngineID engine_number)
+{
+	const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number);
+	const Engine *e = GetEngine(engine_number);
+	CargoID cargo;
+	YearMonthDay ymd;
+	ConvertDateToYMD(e->intro_date, &ymd);
+
+	/* Purchase cost - Max speed */
+	SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
+	SetDParam(1, avi->max_speed * 128 / 10);
+	DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
+	y += 10;
+
+	/* Cargo capacity */
+	cargo = FindFirstRefittableCargo(engine_number);
+	if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
+		SetDParam(0, avi->passenger_capacity);
+		SetDParam(1, avi->mail_capacity);
+		DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, 0);
+	} else {
+		/* Note, if the default capacity is selected by the refit capacity
+		* callback, then the capacity shown is likely to be incorrect. */
+		SetDParam(0, cargo);
+		SetDParam(1, AircraftDefaultCargoCapacity(cargo, engine_number));
+		SetDParam(2, STR_9842_REFITTABLE);
+		DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
+	}
+	y += 10;
+
+	/* Running cost */
+	SetDParam(0, avi->running_cost * _price.aircraft_running >> 8);
+	DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
+	y += 10;
+
+	/* Design date - Life length */
+	SetDParam(0, ymd.year);
+	SetDParam(1, e->lifelength);
+	DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
+	y += 10;
+
+	/* Reliability */
+	SetDParam(0, e->reliability * 100 >> 16);
+	DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
+	y += 10;
+
+	/* Additional text from NewGRF */
+	y += ShowAdditionalText(x, y, w, engine_number);
+	y += ShowRefitOptionsList(x, y, w, engine_number);
+}
+
+void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection)
+{
+	PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
+	DrawSprite(GetAircraftImage(v, DIR_W) | pal, x + 25, y + 10);
+	if (v->subtype == 0) {
+		SpriteID rotor_sprite = GetCustomRotorSprite(v, true);
+		if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
+		DrawSprite(rotor_sprite, x + 25, y + 5);
+	}
+	if (v->index == selection) {
+		DrawFrameRect(x - 1, y - 1, x + 58, y + 21, 0xF, FR_BORDERONLY);
+	}
+}
+
+void CcBuildAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		const Vehicle *v = GetVehicle(_new_vehicle_id);
+
+		if (v->tile == _backup_orders_tile) {
+			_backup_orders_tile = 0;
+			RestoreVehicleOrders(v, _backup_orders_data);
+		}
+		ShowAircraftViewWindow(v);
+	}
+}
+
+static void GenerateBuildAircraftList(Window *w)
+{
+	EngineID eid, sel_id;
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	EngList_RemoveAll(&bv->eng_list);
+
+	/* Make list of all available planes.
+	 * Also check to see if the previously selected plane is still available,
+	 * and if not, reset selection to INVALID_ENGINE. This could be the case
+	 * when planes become obsolete and are removed */
+	sel_id = INVALID_ENGINE;
+	for (eid = AIRCRAFT_ENGINES_INDEX; eid < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; eid++) {
+		if (IsEngineBuildable(eid, VEH_Aircraft, _local_player)) {
+			const AircraftVehicleInfo *avi = AircraftVehInfo(eid);
+			switch (bv->filter.acc_planes) {
+				case HELICOPTERS_ONLY:
+					if (avi->subtype != 0) continue; // if not helicopter
+					break;
+
+				case AIRCRAFT_ONLY:
+					if (avi->subtype == 0) continue; // if helicopter
+					break;
+
+				case ALL: break;
+			}
+			EngList_Add(&bv->eng_list, eid);
+
+			if (eid == bv->sel_engine) sel_id = eid;
+		}
+	}
+
+	bv->sel_engine = sel_id;
+}
+
+static void GenerateBuildList(Window *w)
+{
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	switch (bv->vehicle_type) {
+		case VEH_Aircraft:
+			GenerateBuildAircraftList(w);
+			_internal_sort_order = bv->descending_sort_order;
+			EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]);
+			break;
+
+		default: NOT_REACHED();
+	}
+}
+
+static void DrawBuildAircraftWindow(Window *w)
+{
+	const buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0);
+
+	SetVScrollCount(w, EngList_Count(&bv->eng_list));
+	DrawWindowWidgets(w);
+
+	{
+		int x = 2;
+		int y = 27;
+		EngineID selected_id = bv->sel_engine;
+		EngineID eid = w->vscroll.pos;
+		uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list));
+
+		for (; eid < max; eid++) {
+			const EngineID engine = bv->eng_list[eid];
+
+			DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10);
+			DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player));
+			y += 24;
+		}
+
+		if (selected_id != INVALID_ENGINE) {
+			const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
+			DrawAircraftPurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id);
+		}
+	}
+	DrawString(85, 15, _aircraft_sort_listing[bv->sort_criteria], 0x10);
+	DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
+}
+
+static void BuildAircraftClickEvent(Window *w, WindowEvent *e)
+{
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	switch (e->we.click.widget) {
+		case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
+			bv->descending_sort_order ^= true;
+			_last_sort_order = bv->descending_sort_order;
+			GenerateBuildList(w);
+			SetWindowDirty(w);
+			break;
+
+		case BUILD_VEHICLE_WIDGET_LIST: {
+			uint i = (e->we.click.pt.y - 26) / 24 + w->vscroll.pos;
+			uint num_items = EngList_Count(&bv->eng_list);
+			bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
+			SetWindowDirty(w);
+			break;
+		}
+
+		case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
+			ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
+			return;
+
+		case BUILD_VEHICLE_WIDGET_BUILD: {
+			EngineID sel_eng = bv->sel_engine;
+			if (sel_eng != INVALID_ENGINE) {
+				DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
+			}
+			break;
+		}
+
+		case BUILD_VEHICLE_WIDGET_RENAME: {
+			EngineID sel_eng = bv->sel_engine;
+			if (sel_eng != INVALID_ENGINE) {
+				bv->rename_engine = sel_eng;
+				ShowQueryString(GetCustomEngineName(sel_eng), STR_A039_RENAME_AIRCRAFT_TYPE, 31, 160, w, CS_ALPHANUMERAL);
+			}
+			break;
+		}
+	}
+}
+
+static void NewAircraftWndProc(Window *w, WindowEvent *e)
+{
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	switch (e->event) {
+		case WE_INVALIDATE_DATA:
+			GenerateBuildList(w);
+			break;
+
+		case WE_DESTROY:
+			EngList_Destroy(&bv->eng_list);
+			break;
+
+		case WE_PAINT:
+			DrawBuildAircraftWindow(w);
+			break;
+
+		case WE_CLICK:
+			BuildAircraftClickEvent(w, e);
+			break;
+
+		case WE_ON_EDIT_TEXT: {
+			if (e->we.edittext.str[0] != '\0') {
+				_cmd_text = e->we.edittext.str;
+				DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE));
+			}
+			break;
+		}
+
+		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+			if (bv->sort_criteria != e->we.dropdown.index) {
+				bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
+				GenerateBuildList(w);
+			}
+			SetWindowDirty(w);
+			break;
+
+		case WE_RESIZE:
+			w->vscroll.cap += e->we.sizing.diff.y / 24;
+			w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+			break;
+	}
+}
+
+static const WindowDesc _build_vehicle_desc = {
+	WDP_AUTO, WDP_AUTO, 240, 226,
+	WC_BUILD_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_build_vehicle_widgets,
+	NewAircraftWndProc
+};
+
+void ShowBuildVehicleWindow(TileIndex tile, byte type)
+{
+	buildvehicle_d *bv;
+	Window *w;
+
+	DeleteWindowById(WC_BUILD_VEHICLE, tile);
+	w = AllocateWindowDescFront(&_build_vehicle_desc, tile);
+	if (w == NULL) return;
+
+	w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
+	w->resize.step_height = GetVehicleListHeight(type);
+	w->vscroll.cap = 4;
+	w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+
+	bv = &WP(w, buildvehicle_d);
+	EngList_Create(&bv->eng_list);
+	bv->sel_engine            = INVALID_ENGINE;
+	bv->sort_criteria         = _last_sort_criteria;
+	bv->descending_sort_order = _last_sort_order;
+
+	bv->vehicle_type = type;
+
+	switch (type) {
+		case VEH_Aircraft: {
+			byte acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes;
+			bv->filter.acc_planes = acc_planes;
+			break;
+		}
+		default: NOT_REACHED();
+	}
+
+	GenerateBuildList(w);
+	/* Select the first plane in the list as default when opening the window */
+	if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
+}
deleted file mode 100644
--- a/src/callback_table.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "callback_table.h"
-#include "functions.h"
-
-// If you add a callback for DoCommandP, also add the callback in here
-//   see below for the full list!
-// If you don't do it, it won't work across the network!!
-
-/* aircraft_gui.c */
-CommandCallback CcBuildAircraft;
-CommandCallback CcCloneAircraft;
-
-/* airport_gui.c */
-CommandCallback CcBuildAirport;
-
-/* bridge_gui.c */
-CommandCallback CcBuildBridge;
-
-/* dock_gui.c */
-CommandCallback CcBuildDocks;
-CommandCallback CcBuildCanal;
-
-/* depot_gui.c */
-CommandCallback CcCloneVehicle;
-
-/* main_gui.c */
-CommandCallback CcPlaySound10;
-CommandCallback CcPlaceSign;
-CommandCallback CcTerraform;
-CommandCallback CcBuildTown;
-
-/* rail_gui.c */
-CommandCallback CcPlaySound1E;
-CommandCallback CcRailDepot;
-CommandCallback CcStation;
-CommandCallback CcBuildRailTunnel;
-
-/* road_gui.c */
-CommandCallback CcPlaySound1D;
-CommandCallback CcBuildRoadTunnel;
-CommandCallback CcRoadDepot;
-
-/* roadveh_gui.c */
-CommandCallback CcBuildRoadVeh;
-CommandCallback CcCloneRoadVeh;
-
-/* ship_gui.c */
-CommandCallback CcBuildShip;
-CommandCallback CcCloneShip;
-
-/* train_gui.c */
-CommandCallback CcBuildWagon;
-CommandCallback CcBuildLoco;
-CommandCallback CcCloneTrain;
-
-CommandCallback CcAI;
-
-CommandCallback *_callback_table[] = {
-	/* 0x00 */ NULL,
-	/* 0x01 */ CcBuildAircraft,
-	/* 0x02 */ CcBuildAirport,
-	/* 0x03 */ CcBuildBridge,
-	/* 0x04 */ CcBuildCanal,
-	/* 0x05 */ CcBuildDocks,
-	/* 0x06 */ CcBuildLoco,
-	/* 0x07 */ CcBuildRoadVeh,
-	/* 0x08 */ CcBuildShip,
-	/* 0x09 */ CcBuildTown,
-	/* 0x0A */ CcBuildRoadTunnel,
-	/* 0x0B */ CcBuildRailTunnel,
-	/* 0x0C */ CcBuildWagon,
-	/* 0x0D */ CcRoadDepot,
-	/* 0x0E */ CcRailDepot,
-	/* 0x0F */ CcPlaceSign,
-	/* 0x10 */ CcPlaySound10,
-	/* 0x11 */ CcPlaySound1D,
-	/* 0x12 */ CcPlaySound1E,
-	/* 0x13 */ CcStation,
-	/* 0x14 */ CcTerraform,
-	/* 0x15 */ CcCloneAircraft,
-	/* 0x16 */ CcCloneRoadVeh,
-	/* 0x17 */ CcCloneShip,
-	/* 0x18 */ CcCloneTrain,
-	/* 0x19 */ CcAI,
-	/* 0x1A */ CcCloneVehicle
-};
-
-const int _callback_table_count = lengthof(_callback_table);
new file mode 100644
--- /dev/null
+++ b/src/callback_table.cpp
@@ -0,0 +1,91 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "callback_table.h"
+#include "functions.h"
+
+// If you add a callback for DoCommandP, also add the callback in here
+//   see below for the full list!
+// If you don't do it, it won't work across the network!!
+
+/* aircraft_gui.c */
+CommandCallback CcBuildAircraft;
+CommandCallback CcCloneAircraft;
+
+/* airport_gui.c */
+CommandCallback CcBuildAirport;
+
+/* bridge_gui.c */
+CommandCallback CcBuildBridge;
+
+/* dock_gui.c */
+CommandCallback CcBuildDocks;
+CommandCallback CcBuildCanal;
+
+/* depot_gui.c */
+CommandCallback CcCloneVehicle;
+
+/* main_gui.c */
+CommandCallback CcPlaySound10;
+CommandCallback CcPlaceSign;
+CommandCallback CcTerraform;
+CommandCallback CcBuildTown;
+
+/* rail_gui.c */
+CommandCallback CcPlaySound1E;
+CommandCallback CcRailDepot;
+CommandCallback CcStation;
+CommandCallback CcBuildRailTunnel;
+
+/* road_gui.c */
+CommandCallback CcPlaySound1D;
+CommandCallback CcBuildRoadTunnel;
+CommandCallback CcRoadDepot;
+
+/* roadveh_gui.c */
+CommandCallback CcBuildRoadVeh;
+CommandCallback CcCloneRoadVeh;
+
+/* ship_gui.c */
+CommandCallback CcBuildShip;
+CommandCallback CcCloneShip;
+
+/* train_gui.c */
+CommandCallback CcBuildWagon;
+CommandCallback CcBuildLoco;
+CommandCallback CcCloneTrain;
+
+CommandCallback CcAI;
+
+CommandCallback *_callback_table[] = {
+	/* 0x00 */ NULL,
+	/* 0x01 */ CcBuildAircraft,
+	/* 0x02 */ CcBuildAirport,
+	/* 0x03 */ CcBuildBridge,
+	/* 0x04 */ CcBuildCanal,
+	/* 0x05 */ CcBuildDocks,
+	/* 0x06 */ CcBuildLoco,
+	/* 0x07 */ CcBuildRoadVeh,
+	/* 0x08 */ CcBuildShip,
+	/* 0x09 */ CcBuildTown,
+	/* 0x0A */ CcBuildRoadTunnel,
+	/* 0x0B */ CcBuildRailTunnel,
+	/* 0x0C */ CcBuildWagon,
+	/* 0x0D */ CcRoadDepot,
+	/* 0x0E */ CcRailDepot,
+	/* 0x0F */ CcPlaceSign,
+	/* 0x10 */ CcPlaySound10,
+	/* 0x11 */ CcPlaySound1D,
+	/* 0x12 */ CcPlaySound1E,
+	/* 0x13 */ CcStation,
+	/* 0x14 */ CcTerraform,
+	/* 0x15 */ CcCloneAircraft,
+	/* 0x16 */ CcCloneRoadVeh,
+	/* 0x17 */ CcCloneShip,
+	/* 0x18 */ CcCloneTrain,
+	/* 0x19 */ CcAI,
+	/* 0x1A */ CcCloneVehicle
+};
+
+const int _callback_table_count = lengthof(_callback_table);
deleted file mode 100644
--- a/src/clear_cmd.c
+++ /dev/null
@@ -1,803 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "clear_map.h"
-#include "rail_map.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "player.h"
-#include "tile.h"
-#include "viewport.h"
-#include "command.h"
-#include "tunnel_map.h"
-#include "bridge_map.h"
-#include "variables.h"
-#include "table/sprites.h"
-#include "unmovable_map.h"
-#include "genworld.h"
-#include "industry.h"
-
-typedef struct TerraformerHeightMod {
-	TileIndex tile;
-	byte height;
-} TerraformerHeightMod;
-
-typedef struct TerraformerState {
-	int height[4];
-	uint32 flags;
-
-	int direction;
-	int modheight_count;
-	int tile_table_count;
-
-	int32 cost;
-
-	TileIndex *tile_table;
-	TerraformerHeightMod *modheight;
-
-} TerraformerState;
-
-static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
-{
-	TileIndex *t;
-	int count;
-
-	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
-
-	t = ts->tile_table;
-	for (count = ts->tile_table_count; count != 0; count--, t++) {
-		if (*t == tile) return 0;
-	}
-
-	return 1;
-}
-
-static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
-{
-	TerraformerHeightMod *mod = ts->modheight;
-	int count;
-
-	for (count = ts->modheight_count; count != 0; count--, mod++) {
-		if (mod->tile == tile) return mod->height;
-	}
-
-	return TileHeight(tile);
-}
-
-static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
-{
-	int count;
-	TileIndex *t;
-
-	count = ts->tile_table_count;
-
-	if (count >= 625) return;
-
-	for (t = ts->tile_table; count != 0; count--,t++) {
-		if (*t == tile) return;
-	}
-
-	ts->tile_table[ts->tile_table_count++] = tile;
-}
-
-static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
-{
-	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
-	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
-	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
-	TerraformAddDirtyTile(ts, tile);
-}
-
-static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
-{
-	int r;
-	int32 ret;
-
-	assert(tile < MapSize());
-
-	r = TerraformAllowTileProcess(ts, tile);
-	if (r <= 0) return r;
-
-	if (IsTileType(tile, MP_RAILWAY)) {
-		static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
-		static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
-
-		Slope tileh;
-		uint z;
-
-		// Nothing could be built at the steep slope - this avoids a bug
-		// when you have a single diagonal track in one corner on a
-		// basement and then you raise/lower the other corner.
-		tileh = GetTileSlope(tile, &z);
-		if (tileh == unsafe_slope[mode] ||
-				tileh == ComplementSlope(unsafe_slope[mode])) {
-			_terraform_err_tile = tile;
-			_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
-			return -1;
-		}
-
-		// If we have a single diagonal track there, the other side of
-		// tile can be terraformed.
-		if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
-			/* If terraforming downwards prevent damaging a potential tunnel below.
-			 * This check is only necessary for flat tiles, because if the tile is
-			 * non-flat, then the corner opposing the rail is raised. Only this corner
-			 * can be lowered and this is a safe action
-			 */
-			if (tileh == SLOPE_FLAT &&
-					ts->direction == -1 &&
-					IsTunnelInWay(tile, z - TILE_HEIGHT)) {
-				_terraform_err_tile = tile;
-				_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
-				return -1;
-			}
-			return 0;
-		}
-	}
-
-	ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
-
-	if (CmdFailed(ret)) {
-		_terraform_err_tile = tile;
-		return -1;
-	}
-
-	ts->cost += ret;
-
-	if (ts->tile_table_count >= 625) return -1;
-	ts->tile_table[ts->tile_table_count++] = tile;
-
-	return 0;
-}
-
-static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
-{
-	int nh;
-	TerraformerHeightMod *mod;
-	int count;
-
-	assert(tile < MapSize());
-
-	if (height < 0) {
-		_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
-		return false;
-	}
-
-	_error_message = STR_1004_TOO_HIGH;
-
-	if (height > 15) return false;
-
-	nh = TerraformGetHeightOfTile(ts, tile);
-	if (nh < 0 || height == nh) return false;
-
-	if (TerraformProc(ts, tile, 0) < 0) return false;
-	if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
-	if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
-	if (TerraformProc(ts, tile + TileDiffXY(-1,  0), 3) < 0) return false;
-
-	mod = ts->modheight;
-	count = ts->modheight_count;
-
-	for (;;) {
-		if (count == 0) {
-			if (ts->modheight_count >= 576) return false;
-			ts->modheight_count++;
-			break;
-		}
-		if (mod->tile == tile) break;
-		mod++;
-		count--;
-	}
-
-	mod->tile = tile;
-	mod->height = (byte)height;
-
-	ts->cost += _price.terraform;
-
-	{
-		int direction = ts->direction, r;
-		const TileIndexDiffC *ttm;
-
-		static const TileIndexDiffC _terraform_tilepos[] = {
-			{ 1,  0},
-			{-2,  0},
-			{ 1,  1},
-			{ 0, -2}
-		};
-
-		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
-			tile += ToTileIndexDiff(*ttm);
-
-			r = TerraformGetHeightOfTile(ts, tile);
-			if (r != height && r-direction != height && r+direction != height) {
-				if (!TerraformTileHeight(ts, tile, r+direction))
-					return false;
-			}
-		}
-	}
-
-	return true;
-}
-
-/** Terraform land
- * @param tile tile to terraform
- * @param p1 corners to terraform.
- * @param p2 direction; eg up or down
- */
-int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TerraformerState ts;
-	TileIndex t;
-	int direction;
-
-	TerraformerHeightMod modheight_data[576];
-	TileIndex tile_table_data[625];
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	_terraform_err_tile = 0;
-
-	ts.direction = direction = p2 ? 1 : -1;
-	ts.flags = flags;
-	ts.modheight_count = ts.tile_table_count = 0;
-	ts.cost = 0;
-	ts.modheight = modheight_data;
-	ts.tile_table = tile_table_data;
-
-	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
-	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
-
-	if (p1 & 1) {
-		t = tile + TileDiffXY(1, 0);
-		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
-			return CMD_ERROR;
-		}
-	}
-
-	if (p1 & 2) {
-		t = tile + TileDiffXY(1, 1);
-		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
-			return CMD_ERROR;
-		}
-	}
-
-	if (p1 & 4) {
-		t = tile + TileDiffXY(0, 1);
-		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
-			return CMD_ERROR;
-		}
-	}
-
-	if (p1 & 8) {
-		t = tile + TileDiffXY(0, 0);
-		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
-			return CMD_ERROR;
-		}
-	}
-
-	{
-		/* Check if tunnel would take damage */
-		int count;
-		TileIndex *ti = ts.tile_table;
-
-		for (count = ts.tile_table_count; count != 0; count--, ti++) {
-			TileIndex tile = *ti;
-
-			if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
-				return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-			}
-
-			if (direction == -1) {
-				uint z, t;
-
-				z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
-				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
-				if (t <= z) z = t;
-				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
-				if (t <= z) z = t;
-				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
-				if (t <= z) z = t;
-
-				if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
-					return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
-				}
-			}
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		/* Clear the landscape at the tiles */
-		{
-			int count;
-			TileIndex *ti = ts.tile_table;
-			for (count = ts.tile_table_count; count != 0; count--, ti++) {
-				DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			}
-		}
-
-		/* change the height */
-		{
-			int count;
-			TerraformerHeightMod *mod;
-
-			mod = ts.modheight;
-			for (count = ts.modheight_count; count != 0; count--, mod++) {
-				TileIndex til = mod->tile;
-
-				SetTileHeight(til, mod->height);
-				TerraformAddDirtyTileAround(&ts, til);
-			}
-		}
-
-		/* finally mark the dirty tiles dirty */
-		{
-			int count;
-			TileIndex *ti = ts.tile_table;
-			for (count = ts.tile_table_count; count != 0; count--, ti++) {
-				MarkTileDirtyByTile(*ti);
-			}
-		}
-	}
-	return ts.cost;
-}
-
-
-/** Levels a selected (rectangle) area of land
- * @param tile end tile of area-drag
- * @param p1 start tile of area drag
- * @param p2 unused
- */
-int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int size_x, size_y;
-	int ex;
-	int ey;
-	int sx, sy;
-	uint h, curh;
-	int32 ret, cost, money;
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	// remember level height
-	h = TileHeight(p1);
-
-	// make sure sx,sy are smaller than ex,ey
-	ex = TileX(tile);
-	ey = TileY(tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-	tile = TileXY(sx, sy);
-
-	size_x = ex-sx+1;
-	size_y = ey-sy+1;
-
-	money = GetAvailableMoneyForCommand();
-	cost = 0;
-
-	BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
-		curh = TileHeight(tile2);
-		while (curh != h) {
-			ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
-			if (CmdFailed(ret)) break;
-			cost += ret;
-
-			if (flags & DC_EXEC) {
-				if ((money -= ret) < 0) {
-					_additional_cash_required = ret;
-					return cost - ret;
-				}
-				DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
-			}
-
-			curh += (curh > h) ? -1 : 1;
-		}
-	} END_TILE_LOOP(tile2, size_x, size_y, tile)
-
-	return (cost == 0) ? CMD_ERROR : cost;
-}
-
-/** Purchase a land area. Actually you only purchase one tile, so
- * the name is a bit confusing ;p
- * @param tile the tile the player is purchasing
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
-		return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
-	}
-
-	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(cost)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		MakeOwnedLand(tile, _current_player);
-		MarkTileDirtyByTile(tile);
-	}
-
-	return cost + _price.purchase_land * 10;
-}
-
-
-static int32 ClearTile_Clear(TileIndex tile, byte flags)
-{
-	static const int32* clear_price_table[] = {
-		&_price.clear_1,
-		&_price.purchase_land,
-		&_price.clear_2,
-		&_price.clear_3,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.clear_2, // XXX unused?
-	};
-	int32 price;
-
-	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
-		price = 0;
-	} else {
-		price = *clear_price_table[GetClearGround(tile)];
-	}
-
-	if (flags & DC_EXEC) DoClearSquare(tile);
-
-	return price;
-}
-
-/** Sell a land area. Actually you only sell one tile, so
- * the name is a bit confusing ;p
- * @param tile the tile the player is selling
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!IsOwnedLandTile(tile)) return CMD_ERROR;
-	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
-
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) DoClearSquare(tile);
-
-	return - _price.purchase_land * 2;
-}
-
-
-#include "table/clear_land.h"
-
-
-void DrawClearLandTile(const TileInfo *ti, byte set)
-{
-	DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
-}
-
-void DrawHillyLandTile(const TileInfo *ti)
-{
-	if (ti->tileh != SLOPE_FLAT) {
-		DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
-	} else {
-		DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
-	}
-}
-
-void DrawClearLandFence(const TileInfo *ti)
-{
-	byte z = ti->z;
-
-	if (ti->tileh & SLOPE_S) {
-		z += TILE_HEIGHT;
-		if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT;
-	}
-
-	if (GetFenceSW(ti->tile) != 0) {
-		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
-	}
-
-	if (GetFenceSE(ti->tile) != 0) {
-		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
-	}
-}
-
-static void DrawTile_Clear(TileInfo *ti)
-{
-	switch (GetClearGround(ti->tile)) {
-		case CLEAR_GRASS:
-			DrawClearLandTile(ti, GetClearDensity(ti->tile));
-			break;
-
-		case CLEAR_ROUGH:
-			DrawHillyLandTile(ti);
-			break;
-
-		case CLEAR_ROCKS:
-			DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
-			break;
-
-		case CLEAR_FIELDS:
-			DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]);
-			break;
-
-		case CLEAR_SNOW:
-			DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
-			break;
-
-		case CLEAR_DESERT:
-			DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
-			break;
-	}
-
-	DrawClearLandFence(ti);
-	DrawBridgeMiddle(ti);
-}
-
-static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	uint tileh = GetTileSlope(tile, &z);
-
-	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-}
-
-static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh)
-{
-	return tileh;
-}
-
-static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac)
-{
-	/* unused */
-}
-
-static void AnimateTile_Clear(TileIndex tile)
-{
-	/* unused */
-}
-
-void TileLoopClearHelper(TileIndex tile)
-{
-	byte self;
-	byte neighbour;
-	TileIndex dirty = INVALID_TILE;
-
-	self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
-
-	neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
-	if (GetFenceSW(tile) == 0) {
-		if (self != neighbour) {
-			SetFenceSW(tile, 3);
-			dirty = tile;
-		}
-	} else {
-		if (self == 0 && neighbour == 0) {
-			SetFenceSW(tile, 0);
-			dirty = tile;
-		}
-	}
-
-	neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
-	if (GetFenceSE(tile) == 0) {
-		if (self != neighbour) {
-			SetFenceSE(tile, 3);
-			dirty = tile;
-		}
-	} else {
-		if (self == 0 && neighbour == 0) {
-			SetFenceSE(tile, 0);
-			dirty = tile;
-		}
-	}
-
-	if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
-}
-
-
-/* convert into snowy tiles */
-static void TileLoopClearAlps(TileIndex tile)
-{
-	int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
-
-	if (k < 0) { // well below the snow line
-		if (!IsClearGround(tile, CLEAR_SNOW)) return;
-		if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
-	} else {
-		if (!IsClearGround(tile, CLEAR_SNOW)) {
-			SetClearGroundDensity(tile, CLEAR_SNOW, 0);
-		} else {
-			uint density = min((uint)k / TILE_HEIGHT, 3);
-
-			if (GetClearDensity(tile) < density) {
-				AddClearDensity(tile, 1);
-			} else if (GetClearDensity(tile) > density) {
-				AddClearDensity(tile, -1);
-			} else {
-				return;
-			}
-		}
-	}
-
-	MarkTileDirtyByTile(tile);
-}
-
-static void TileLoopClearDesert(TileIndex tile)
-{
-	if (IsClearGround(tile, CLEAR_DESERT)) return;
-
-	if (GetTropicZone(tile) == TROPICZONE_DESERT) {
-		SetClearGroundDensity(tile, CLEAR_DESERT, 3);
-	} else {
-		if (GetTropicZone(tile + TileDiffXY( 1,  0)) != TROPICZONE_DESERT &&
-				GetTropicZone(tile + TileDiffXY(-1,  0)) != TROPICZONE_DESERT &&
-				GetTropicZone(tile + TileDiffXY( 0,  1)) != TROPICZONE_DESERT &&
-				GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT)
-			return;
-		SetClearGroundDensity(tile, CLEAR_DESERT, 1);
-	}
-
-	MarkTileDirtyByTile(tile);
-}
-
-static void TileLoop_Clear(TileIndex tile)
-{
-	TileLoopClearHelper(tile);
-
-	switch (_opt.landscape) {
-		case LT_DESERT: TileLoopClearDesert(tile); break;
-		case LT_HILLY:  TileLoopClearAlps(tile);   break;
-	}
-
-	switch (GetClearGround(tile)) {
-		case CLEAR_GRASS:
-			if (GetClearDensity(tile) == 3) return;
-
-			if (_game_mode != GM_EDITOR) {
-				if (GetClearCounter(tile) < 7) {
-					AddClearCounter(tile, 1);
-					return;
-				} else {
-					SetClearCounter(tile, 0);
-					AddClearDensity(tile, 1);
-				}
-			} else {
-				SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
-			}
-			break;
-
-		case CLEAR_FIELDS: {
-			uint field_type;
-
-			if (_game_mode == GM_EDITOR) return;
-
-			if (GetClearCounter(tile) < 7) {
-				AddClearCounter(tile, 1);
-				return;
-			} else {
-				SetClearCounter(tile, 0);
-			}
-
-			if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
-				/* This farmfield is no longer farmfield, so make it grass again */
-				MakeClear(tile, CLEAR_GRASS, 2);
-			} else {
-				field_type = GetFieldType(tile);
-				field_type = (field_type < 8) ? field_type + 1 : 0;
-				SetFieldType(tile, field_type);
-			}
-			break;
-		}
-
-		default:
-			return;
-	}
-
-	MarkTileDirtyByTile(tile);
-}
-
-void GenerateClearTile(void)
-{
-	uint i, gi;
-	TileIndex tile;
-
-	/* add rough tiles */
-	i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
-	gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
-
-	SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
-	do {
-		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
-		tile = RandomTile();
-		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
-	} while (--i);
-
-	/* add rocky tiles */
-	i = gi;
-	do {
-		uint32 r = Random();
-		tile = RandomTileSeed(r);
-
-		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
-		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
-			uint j = GB(r, 16, 4) + 5;
-			for (;;) {
-				TileIndex tile_new;
-
-				SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
-				do {
-					if (--j == 0) goto get_out;
-					tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2));
-				} while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
-				tile = tile_new;
-			}
-get_out:;
-		}
-	} while (--i);
-}
-
-static void ClickTile_Clear(TileIndex tile)
-{
-	/* not used */
-}
-
-static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode)
-{
-	return 0;
-}
-
-static const StringID _clear_land_str[] = {
-	STR_080D_GRASS,
-	STR_080B_ROUGH_LAND,
-	STR_080A_ROCKS,
-	STR_080E_FIELDS,
-	STR_080F_SNOW_COVERED_LAND,
-	STR_0810_DESERT
-};
-
-static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
-{
-	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
-		td->str = STR_080C_BARE_LAND;
-	} else {
-		td->str = _clear_land_str[GetClearGround(tile)];
-	}
-	td->owner = GetTileOwner(tile);
-}
-
-static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	return;
-}
-
-void InitializeClearLand(void)
-{
-	_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
-}
-
-const TileTypeProcs _tile_type_clear_procs = {
-	DrawTile_Clear,           /* draw_tile_proc */
-	GetSlopeZ_Clear,          /* get_slope_z_proc */
-	ClearTile_Clear,          /* clear_tile_proc */
-	GetAcceptedCargo_Clear,   /* get_accepted_cargo_proc */
-	GetTileDesc_Clear,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Clear, /* get_tile_track_status_proc */
-	ClickTile_Clear,          /* click_tile_proc */
-	AnimateTile_Clear,        /* animate_tile_proc */
-	TileLoop_Clear,           /* tile_loop_clear */
-	ChangeTileOwner_Clear,    /* change_tile_owner_clear */
-	NULL,                     /* get_produced_cargo_proc */
-	NULL,                     /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Clear,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/clear_cmd.cpp
@@ -0,0 +1,803 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "clear_map.h"
+#include "rail_map.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "player.h"
+#include "tile.h"
+#include "viewport.h"
+#include "command.h"
+#include "tunnel_map.h"
+#include "bridge_map.h"
+#include "variables.h"
+#include "table/sprites.h"
+#include "unmovable_map.h"
+#include "genworld.h"
+#include "industry.h"
+
+typedef struct TerraformerHeightMod {
+	TileIndex tile;
+	byte height;
+} TerraformerHeightMod;
+
+typedef struct TerraformerState {
+	int height[4];
+	uint32 flags;
+
+	int direction;
+	int modheight_count;
+	int tile_table_count;
+
+	int32 cost;
+
+	TileIndex *tile_table;
+	TerraformerHeightMod *modheight;
+
+} TerraformerState;
+
+static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
+{
+	TileIndex *t;
+	int count;
+
+	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
+
+	t = ts->tile_table;
+	for (count = ts->tile_table_count; count != 0; count--, t++) {
+		if (*t == tile) return 0;
+	}
+
+	return 1;
+}
+
+static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
+{
+	TerraformerHeightMod *mod = ts->modheight;
+	int count;
+
+	for (count = ts->modheight_count; count != 0; count--, mod++) {
+		if (mod->tile == tile) return mod->height;
+	}
+
+	return TileHeight(tile);
+}
+
+static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
+{
+	int count;
+	TileIndex *t;
+
+	count = ts->tile_table_count;
+
+	if (count >= 625) return;
+
+	for (t = ts->tile_table; count != 0; count--,t++) {
+		if (*t == tile) return;
+	}
+
+	ts->tile_table[ts->tile_table_count++] = tile;
+}
+
+static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
+{
+	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
+	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
+	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
+	TerraformAddDirtyTile(ts, tile);
+}
+
+static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
+{
+	int r;
+	int32 ret;
+
+	assert(tile < MapSize());
+
+	r = TerraformAllowTileProcess(ts, tile);
+	if (r <= 0) return r;
+
+	if (IsTileType(tile, MP_RAILWAY)) {
+		static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
+		static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
+
+		Slope tileh;
+		uint z;
+
+		// Nothing could be built at the steep slope - this avoids a bug
+		// when you have a single diagonal track in one corner on a
+		// basement and then you raise/lower the other corner.
+		tileh = GetTileSlope(tile, &z);
+		if (tileh == unsafe_slope[mode] ||
+				tileh == ComplementSlope(unsafe_slope[mode])) {
+			_terraform_err_tile = tile;
+			_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
+			return -1;
+		}
+
+		// If we have a single diagonal track there, the other side of
+		// tile can be terraformed.
+		if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
+			/* If terraforming downwards prevent damaging a potential tunnel below.
+			 * This check is only necessary for flat tiles, because if the tile is
+			 * non-flat, then the corner opposing the rail is raised. Only this corner
+			 * can be lowered and this is a safe action
+			 */
+			if (tileh == SLOPE_FLAT &&
+					ts->direction == -1 &&
+					IsTunnelInWay(tile, z - TILE_HEIGHT)) {
+				_terraform_err_tile = tile;
+				_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
+				return -1;
+			}
+			return 0;
+		}
+	}
+
+	ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
+
+	if (CmdFailed(ret)) {
+		_terraform_err_tile = tile;
+		return -1;
+	}
+
+	ts->cost += ret;
+
+	if (ts->tile_table_count >= 625) return -1;
+	ts->tile_table[ts->tile_table_count++] = tile;
+
+	return 0;
+}
+
+static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
+{
+	int nh;
+	TerraformerHeightMod *mod;
+	int count;
+
+	assert(tile < MapSize());
+
+	if (height < 0) {
+		_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
+		return false;
+	}
+
+	_error_message = STR_1004_TOO_HIGH;
+
+	if (height > 15) return false;
+
+	nh = TerraformGetHeightOfTile(ts, tile);
+	if (nh < 0 || height == nh) return false;
+
+	if (TerraformProc(ts, tile, 0) < 0) return false;
+	if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
+	if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
+	if (TerraformProc(ts, tile + TileDiffXY(-1,  0), 3) < 0) return false;
+
+	mod = ts->modheight;
+	count = ts->modheight_count;
+
+	for (;;) {
+		if (count == 0) {
+			if (ts->modheight_count >= 576) return false;
+			ts->modheight_count++;
+			break;
+		}
+		if (mod->tile == tile) break;
+		mod++;
+		count--;
+	}
+
+	mod->tile = tile;
+	mod->height = (byte)height;
+
+	ts->cost += _price.terraform;
+
+	{
+		int direction = ts->direction, r;
+		const TileIndexDiffC *ttm;
+
+		static const TileIndexDiffC _terraform_tilepos[] = {
+			{ 1,  0},
+			{-2,  0},
+			{ 1,  1},
+			{ 0, -2}
+		};
+
+		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
+			tile += ToTileIndexDiff(*ttm);
+
+			r = TerraformGetHeightOfTile(ts, tile);
+			if (r != height && r-direction != height && r+direction != height) {
+				if (!TerraformTileHeight(ts, tile, r+direction))
+					return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+/** Terraform land
+ * @param tile tile to terraform
+ * @param p1 corners to terraform.
+ * @param p2 direction; eg up or down
+ */
+int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TerraformerState ts;
+	TileIndex t;
+	int direction;
+
+	TerraformerHeightMod modheight_data[576];
+	TileIndex tile_table_data[625];
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	_terraform_err_tile = 0;
+
+	ts.direction = direction = p2 ? 1 : -1;
+	ts.flags = flags;
+	ts.modheight_count = ts.tile_table_count = 0;
+	ts.cost = 0;
+	ts.modheight = modheight_data;
+	ts.tile_table = tile_table_data;
+
+	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
+	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
+
+	if (p1 & 1) {
+		t = tile + TileDiffXY(1, 0);
+		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
+			return CMD_ERROR;
+		}
+	}
+
+	if (p1 & 2) {
+		t = tile + TileDiffXY(1, 1);
+		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
+			return CMD_ERROR;
+		}
+	}
+
+	if (p1 & 4) {
+		t = tile + TileDiffXY(0, 1);
+		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
+			return CMD_ERROR;
+		}
+	}
+
+	if (p1 & 8) {
+		t = tile + TileDiffXY(0, 0);
+		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
+			return CMD_ERROR;
+		}
+	}
+
+	{
+		/* Check if tunnel would take damage */
+		int count;
+		TileIndex *ti = ts.tile_table;
+
+		for (count = ts.tile_table_count; count != 0; count--, ti++) {
+			TileIndex tile = *ti;
+
+			if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
+				return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+			}
+
+			if (direction == -1) {
+				uint z, t;
+
+				z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
+				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
+				if (t <= z) z = t;
+				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
+				if (t <= z) z = t;
+				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
+				if (t <= z) z = t;
+
+				if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
+					return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
+				}
+			}
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		/* Clear the landscape at the tiles */
+		{
+			int count;
+			TileIndex *ti = ts.tile_table;
+			for (count = ts.tile_table_count; count != 0; count--, ti++) {
+				DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			}
+		}
+
+		/* change the height */
+		{
+			int count;
+			TerraformerHeightMod *mod;
+
+			mod = ts.modheight;
+			for (count = ts.modheight_count; count != 0; count--, mod++) {
+				TileIndex til = mod->tile;
+
+				SetTileHeight(til, mod->height);
+				TerraformAddDirtyTileAround(&ts, til);
+			}
+		}
+
+		/* finally mark the dirty tiles dirty */
+		{
+			int count;
+			TileIndex *ti = ts.tile_table;
+			for (count = ts.tile_table_count; count != 0; count--, ti++) {
+				MarkTileDirtyByTile(*ti);
+			}
+		}
+	}
+	return ts.cost;
+}
+
+
+/** Levels a selected (rectangle) area of land
+ * @param tile end tile of area-drag
+ * @param p1 start tile of area drag
+ * @param p2 unused
+ */
+int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int size_x, size_y;
+	int ex;
+	int ey;
+	int sx, sy;
+	uint h, curh;
+	int32 ret, cost, money;
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	// remember level height
+	h = TileHeight(p1);
+
+	// make sure sx,sy are smaller than ex,ey
+	ex = TileX(tile);
+	ey = TileY(tile);
+	sx = TileX(p1);
+	sy = TileY(p1);
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+	tile = TileXY(sx, sy);
+
+	size_x = ex-sx+1;
+	size_y = ey-sy+1;
+
+	money = GetAvailableMoneyForCommand();
+	cost = 0;
+
+	BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
+		curh = TileHeight(tile2);
+		while (curh != h) {
+			ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
+			if (CmdFailed(ret)) break;
+			cost += ret;
+
+			if (flags & DC_EXEC) {
+				if ((money -= ret) < 0) {
+					_additional_cash_required = ret;
+					return cost - ret;
+				}
+				DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
+			}
+
+			curh += (curh > h) ? -1 : 1;
+		}
+	} END_TILE_LOOP(tile2, size_x, size_y, tile)
+
+	return (cost == 0) ? CMD_ERROR : cost;
+}
+
+/** Purchase a land area. Actually you only purchase one tile, so
+ * the name is a bit confusing ;p
+ * @param tile the tile the player is purchasing
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
+		return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
+	}
+
+	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(cost)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		MakeOwnedLand(tile, _current_player);
+		MarkTileDirtyByTile(tile);
+	}
+
+	return cost + _price.purchase_land * 10;
+}
+
+
+static int32 ClearTile_Clear(TileIndex tile, byte flags)
+{
+	static const int32* clear_price_table[] = {
+		&_price.clear_1,
+		&_price.purchase_land,
+		&_price.clear_2,
+		&_price.clear_3,
+		&_price.purchase_land,
+		&_price.purchase_land,
+		&_price.clear_2, // XXX unused?
+	};
+	int32 price;
+
+	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
+		price = 0;
+	} else {
+		price = *clear_price_table[GetClearGround(tile)];
+	}
+
+	if (flags & DC_EXEC) DoClearSquare(tile);
+
+	return price;
+}
+
+/** Sell a land area. Actually you only sell one tile, so
+ * the name is a bit confusing ;p
+ * @param tile the tile the player is selling
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!IsOwnedLandTile(tile)) return CMD_ERROR;
+	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
+
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) DoClearSquare(tile);
+
+	return - _price.purchase_land * 2;
+}
+
+
+#include "table/clear_land.h"
+
+
+void DrawClearLandTile(const TileInfo *ti, byte set)
+{
+	DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
+}
+
+void DrawHillyLandTile(const TileInfo *ti)
+{
+	if (ti->tileh != SLOPE_FLAT) {
+		DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
+	} else {
+		DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
+	}
+}
+
+void DrawClearLandFence(const TileInfo *ti)
+{
+	byte z = ti->z;
+
+	if (ti->tileh & SLOPE_S) {
+		z += TILE_HEIGHT;
+		if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT;
+	}
+
+	if (GetFenceSW(ti->tile) != 0) {
+		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
+	}
+
+	if (GetFenceSE(ti->tile) != 0) {
+		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
+	}
+}
+
+static void DrawTile_Clear(TileInfo *ti)
+{
+	switch (GetClearGround(ti->tile)) {
+		case CLEAR_GRASS:
+			DrawClearLandTile(ti, GetClearDensity(ti->tile));
+			break;
+
+		case CLEAR_ROUGH:
+			DrawHillyLandTile(ti);
+			break;
+
+		case CLEAR_ROCKS:
+			DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
+			break;
+
+		case CLEAR_FIELDS:
+			DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]);
+			break;
+
+		case CLEAR_SNOW:
+			DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
+			break;
+
+		case CLEAR_DESERT:
+			DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
+			break;
+	}
+
+	DrawClearLandFence(ti);
+	DrawBridgeMiddle(ti);
+}
+
+static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	uint tileh = GetTileSlope(tile, &z);
+
+	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+}
+
+static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh)
+{
+	return tileh;
+}
+
+static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac)
+{
+	/* unused */
+}
+
+static void AnimateTile_Clear(TileIndex tile)
+{
+	/* unused */
+}
+
+void TileLoopClearHelper(TileIndex tile)
+{
+	byte self;
+	byte neighbour;
+	TileIndex dirty = INVALID_TILE;
+
+	self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
+
+	neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
+	if (GetFenceSW(tile) == 0) {
+		if (self != neighbour) {
+			SetFenceSW(tile, 3);
+			dirty = tile;
+		}
+	} else {
+		if (self == 0 && neighbour == 0) {
+			SetFenceSW(tile, 0);
+			dirty = tile;
+		}
+	}
+
+	neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
+	if (GetFenceSE(tile) == 0) {
+		if (self != neighbour) {
+			SetFenceSE(tile, 3);
+			dirty = tile;
+		}
+	} else {
+		if (self == 0 && neighbour == 0) {
+			SetFenceSE(tile, 0);
+			dirty = tile;
+		}
+	}
+
+	if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
+}
+
+
+/* convert into snowy tiles */
+static void TileLoopClearAlps(TileIndex tile)
+{
+	int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
+
+	if (k < 0) { // well below the snow line
+		if (!IsClearGround(tile, CLEAR_SNOW)) return;
+		if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
+	} else {
+		if (!IsClearGround(tile, CLEAR_SNOW)) {
+			SetClearGroundDensity(tile, CLEAR_SNOW, 0);
+		} else {
+			uint density = min((uint)k / TILE_HEIGHT, 3);
+
+			if (GetClearDensity(tile) < density) {
+				AddClearDensity(tile, 1);
+			} else if (GetClearDensity(tile) > density) {
+				AddClearDensity(tile, -1);
+			} else {
+				return;
+			}
+		}
+	}
+
+	MarkTileDirtyByTile(tile);
+}
+
+static void TileLoopClearDesert(TileIndex tile)
+{
+	if (IsClearGround(tile, CLEAR_DESERT)) return;
+
+	if (GetTropicZone(tile) == TROPICZONE_DESERT) {
+		SetClearGroundDensity(tile, CLEAR_DESERT, 3);
+	} else {
+		if (GetTropicZone(tile + TileDiffXY( 1,  0)) != TROPICZONE_DESERT &&
+				GetTropicZone(tile + TileDiffXY(-1,  0)) != TROPICZONE_DESERT &&
+				GetTropicZone(tile + TileDiffXY( 0,  1)) != TROPICZONE_DESERT &&
+				GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT)
+			return;
+		SetClearGroundDensity(tile, CLEAR_DESERT, 1);
+	}
+
+	MarkTileDirtyByTile(tile);
+}
+
+static void TileLoop_Clear(TileIndex tile)
+{
+	TileLoopClearHelper(tile);
+
+	switch (_opt.landscape) {
+		case LT_DESERT: TileLoopClearDesert(tile); break;
+		case LT_HILLY:  TileLoopClearAlps(tile);   break;
+	}
+
+	switch (GetClearGround(tile)) {
+		case CLEAR_GRASS:
+			if (GetClearDensity(tile) == 3) return;
+
+			if (_game_mode != GM_EDITOR) {
+				if (GetClearCounter(tile) < 7) {
+					AddClearCounter(tile, 1);
+					return;
+				} else {
+					SetClearCounter(tile, 0);
+					AddClearDensity(tile, 1);
+				}
+			} else {
+				SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
+			}
+			break;
+
+		case CLEAR_FIELDS: {
+			uint field_type;
+
+			if (_game_mode == GM_EDITOR) return;
+
+			if (GetClearCounter(tile) < 7) {
+				AddClearCounter(tile, 1);
+				return;
+			} else {
+				SetClearCounter(tile, 0);
+			}
+
+			if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
+				/* This farmfield is no longer farmfield, so make it grass again */
+				MakeClear(tile, CLEAR_GRASS, 2);
+			} else {
+				field_type = GetFieldType(tile);
+				field_type = (field_type < 8) ? field_type + 1 : 0;
+				SetFieldType(tile, field_type);
+			}
+			break;
+		}
+
+		default:
+			return;
+	}
+
+	MarkTileDirtyByTile(tile);
+}
+
+void GenerateClearTile(void)
+{
+	uint i, gi;
+	TileIndex tile;
+
+	/* add rough tiles */
+	i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
+	gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
+
+	SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
+	do {
+		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
+		tile = RandomTile();
+		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
+	} while (--i);
+
+	/* add rocky tiles */
+	i = gi;
+	do {
+		uint32 r = Random();
+		tile = RandomTileSeed(r);
+
+		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
+		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
+			uint j = GB(r, 16, 4) + 5;
+			for (;;) {
+				TileIndex tile_new;
+
+				SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
+				do {
+					if (--j == 0) goto get_out;
+					tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2));
+				} while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
+				tile = tile_new;
+			}
+get_out:;
+		}
+	} while (--i);
+}
+
+static void ClickTile_Clear(TileIndex tile)
+{
+	/* not used */
+}
+
+static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode)
+{
+	return 0;
+}
+
+static const StringID _clear_land_str[] = {
+	STR_080D_GRASS,
+	STR_080B_ROUGH_LAND,
+	STR_080A_ROCKS,
+	STR_080E_FIELDS,
+	STR_080F_SNOW_COVERED_LAND,
+	STR_0810_DESERT
+};
+
+static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
+{
+	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
+		td->str = STR_080C_BARE_LAND;
+	} else {
+		td->str = _clear_land_str[GetClearGround(tile)];
+	}
+	td->owner = GetTileOwner(tile);
+}
+
+static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	return;
+}
+
+void InitializeClearLand(void)
+{
+	_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
+}
+
+const TileTypeProcs _tile_type_clear_procs = {
+	DrawTile_Clear,           /* draw_tile_proc */
+	GetSlopeZ_Clear,          /* get_slope_z_proc */
+	ClearTile_Clear,          /* clear_tile_proc */
+	GetAcceptedCargo_Clear,   /* get_accepted_cargo_proc */
+	GetTileDesc_Clear,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Clear, /* get_tile_track_status_proc */
+	ClickTile_Clear,          /* click_tile_proc */
+	AnimateTile_Clear,        /* animate_tile_proc */
+	TileLoop_Clear,           /* tile_loop_clear */
+	ChangeTileOwner_Clear,    /* change_tile_owner_clear */
+	NULL,                     /* get_produced_cargo_proc */
+	NULL,                     /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Clear,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/command.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "gui.h"
-#include "command.h"
-#include "player.h"
-#include "network/network.h"
-#include "variables.h"
-#include "genworld.h"
-
-const char* _cmd_text = NULL;
-
-#define DEF_COMMAND(yyyy) int32 yyyy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-
-DEF_COMMAND(CmdBuildRailroadTrack);
-DEF_COMMAND(CmdRemoveRailroadTrack);
-DEF_COMMAND(CmdBuildSingleRail);
-DEF_COMMAND(CmdRemoveSingleRail);
-
-DEF_COMMAND(CmdLandscapeClear);
-
-DEF_COMMAND(CmdBuildBridge);
-
-DEF_COMMAND(CmdBuildRailroadStation);
-DEF_COMMAND(CmdRemoveFromRailroadStation);
-DEF_COMMAND(CmdConvertRail);
-
-DEF_COMMAND(CmdBuildSingleSignal);
-DEF_COMMAND(CmdRemoveSingleSignal);
-
-DEF_COMMAND(CmdTerraformLand);
-
-DEF_COMMAND(CmdPurchaseLandArea);
-DEF_COMMAND(CmdSellLandArea);
-
-DEF_COMMAND(CmdBuildTunnel);
-
-DEF_COMMAND(CmdBuildTrainDepot);
-DEF_COMMAND(CmdBuildTrainWaypoint);
-DEF_COMMAND(CmdRenameWaypoint);
-DEF_COMMAND(CmdRemoveTrainWaypoint);
-
-DEF_COMMAND(CmdBuildRoadStop);
-
-DEF_COMMAND(CmdBuildLongRoad);
-DEF_COMMAND(CmdRemoveLongRoad);
-DEF_COMMAND(CmdBuildRoad);
-DEF_COMMAND(CmdRemoveRoad);
-
-DEF_COMMAND(CmdBuildRoadDepot);
-
-DEF_COMMAND(CmdBuildAirport);
-
-DEF_COMMAND(CmdBuildDock);
-
-DEF_COMMAND(CmdBuildShipDepot);
-
-DEF_COMMAND(CmdBuildBuoy);
-
-DEF_COMMAND(CmdPlantTree);
-
-DEF_COMMAND(CmdBuildRailVehicle);
-DEF_COMMAND(CmdMoveRailVehicle);
-
-DEF_COMMAND(CmdStartStopTrain);
-
-DEF_COMMAND(CmdSellRailWagon);
-
-DEF_COMMAND(CmdSendTrainToDepot);
-DEF_COMMAND(CmdForceTrainProceed);
-DEF_COMMAND(CmdReverseTrainDirection);
-
-DEF_COMMAND(CmdModifyOrder);
-DEF_COMMAND(CmdSkipOrder);
-DEF_COMMAND(CmdDeleteOrder);
-DEF_COMMAND(CmdInsertOrder);
-DEF_COMMAND(CmdChangeServiceInt);
-DEF_COMMAND(CmdRestoreOrderIndex);
-
-DEF_COMMAND(CmdBuildIndustry);
-
-DEF_COMMAND(CmdBuildCompanyHQ);
-DEF_COMMAND(CmdSetPlayerFace);
-DEF_COMMAND(CmdSetPlayerColor);
-
-DEF_COMMAND(CmdIncreaseLoan);
-DEF_COMMAND(CmdDecreaseLoan);
-
-DEF_COMMAND(CmdWantEnginePreview);
-
-DEF_COMMAND(CmdNameVehicle);
-DEF_COMMAND(CmdRenameEngine);
-
-DEF_COMMAND(CmdChangeCompanyName);
-DEF_COMMAND(CmdChangePresidentName);
-
-DEF_COMMAND(CmdRenameStation);
-
-DEF_COMMAND(CmdSellAircraft);
-DEF_COMMAND(CmdStartStopAircraft);
-DEF_COMMAND(CmdBuildAircraft);
-DEF_COMMAND(CmdSendAircraftToHangar);
-DEF_COMMAND(CmdRefitAircraft);
-
-DEF_COMMAND(CmdPlaceSign);
-DEF_COMMAND(CmdRenameSign);
-
-DEF_COMMAND(CmdBuildRoadVeh);
-DEF_COMMAND(CmdStartStopRoadVeh);
-DEF_COMMAND(CmdSellRoadVeh);
-DEF_COMMAND(CmdSendRoadVehToDepot);
-DEF_COMMAND(CmdTurnRoadVeh);
-DEF_COMMAND(CmdRefitRoadVeh);
-
-DEF_COMMAND(CmdPause);
-
-DEF_COMMAND(CmdBuyShareInCompany);
-DEF_COMMAND(CmdSellShareInCompany);
-DEF_COMMAND(CmdBuyCompany);
-
-DEF_COMMAND(CmdBuildTown);
-
-DEF_COMMAND(CmdRenameTown);
-DEF_COMMAND(CmdDoTownAction);
-
-DEF_COMMAND(CmdSetRoadDriveSide);
-
-DEF_COMMAND(CmdChangeDifficultyLevel);
-DEF_COMMAND(CmdChangePatchSetting);
-
-DEF_COMMAND(CmdStartStopShip);
-DEF_COMMAND(CmdSellShip);
-DEF_COMMAND(CmdBuildShip);
-DEF_COMMAND(CmdSendShipToDepot);
-DEF_COMMAND(CmdRefitShip);
-
-DEF_COMMAND(CmdOrderRefit);
-DEF_COMMAND(CmdCloneOrder);
-
-DEF_COMMAND(CmdClearArea);
-
-DEF_COMMAND(CmdGiveMoney);
-DEF_COMMAND(CmdMoneyCheat);
-DEF_COMMAND(CmdBuildCanal);
-DEF_COMMAND(CmdBuildLock);
-
-DEF_COMMAND(CmdPlayerCtrl);
-
-DEF_COMMAND(CmdLevelLand);
-
-DEF_COMMAND(CmdRefitRailVehicle);
-
-DEF_COMMAND(CmdBuildSignalTrack);
-DEF_COMMAND(CmdRemoveSignalTrack);
-
-DEF_COMMAND(CmdSetAutoReplace);
-
-DEF_COMMAND(CmdCloneVehicle);
-DEF_COMMAND(CmdMassStartStopVehicle);
-DEF_COMMAND(CmdDepotSellAllVehicles);
-DEF_COMMAND(CmdDepotMassAutoReplace);
-
-/* The master command table */
-static const Command _command_proc_table[] = {
-	{CmdBuildRailroadTrack,                  0}, /*   0 */
-	{CmdRemoveRailroadTrack,                 0}, /*   1 */
-	{CmdBuildSingleRail,                     0}, /*   2 */
-	{CmdRemoveSingleRail,                    0}, /*   3 */
-	{CmdLandscapeClear,                      0}, /*   4 */
-	{CmdBuildBridge,                         0}, /*   5 */
-	{CmdBuildRailroadStation,                0}, /*   6 */
-	{CmdBuildTrainDepot,                     0}, /*   7 */
-	{CmdBuildSingleSignal,                   0}, /*   8 */
-	{CmdRemoveSingleSignal,                  0}, /*   9 */
-	{CmdTerraformLand,                       0}, /*  10 */
-	{CmdPurchaseLandArea,                    0}, /*  11 */
-	{CmdSellLandArea,                        0}, /*  12 */
-	{CmdBuildTunnel,                         0}, /*  13 */
-	{CmdRemoveFromRailroadStation,           0}, /*  14 */
-	{CmdConvertRail,                         0}, /*  15 */
-	{CmdBuildTrainWaypoint,                  0}, /*  16 */
-	{CmdRenameWaypoint,                      0}, /*  17 */
-	{CmdRemoveTrainWaypoint,                 0}, /*  18 */
-	{NULL,                                   0}, /*  19 */
-	{NULL,                                   0}, /*  20 */
-	{CmdBuildRoadStop,                       0}, /*  21 */
-	{NULL,                                   0}, /*  22 */
-	{CmdBuildLongRoad,                       0}, /*  23 */
-	{CmdRemoveLongRoad,                      0}, /*  24 */
-	{CmdBuildRoad,                           0}, /*  25 */
-	{CmdRemoveRoad,                          0}, /*  26 */
-	{CmdBuildRoadDepot,                      0}, /*  27 */
-	{NULL,                                   0}, /*  28 */
-	{CmdBuildAirport,                        0}, /*  29 */
-	{CmdBuildDock,                           0}, /*  30 */
-	{CmdBuildShipDepot,                      0}, /*  31 */
-	{CmdBuildBuoy,                           0}, /*  32 */
-	{CmdPlantTree,                           0}, /*  33 */
-	{CmdBuildRailVehicle,                    0}, /*  34 */
-	{CmdMoveRailVehicle,                     0}, /*  35 */
-	{CmdStartStopTrain,                      0}, /*  36 */
-	{NULL,                                   0}, /*  37 */
-	{CmdSellRailWagon,                       0}, /*  38 */
-	{CmdSendTrainToDepot,                    0}, /*  39 */
-	{CmdForceTrainProceed,                   0}, /*  40 */
-	{CmdReverseTrainDirection,               0}, /*  41 */
-
-	{CmdModifyOrder,                         0}, /*  42 */
-	{CmdSkipOrder,                           0}, /*  43 */
-	{CmdDeleteOrder,                         0}, /*  44 */
-	{CmdInsertOrder,                         0}, /*  45 */
-
-	{CmdChangeServiceInt,                    0}, /*  46 */
-
-	{CmdBuildIndustry,                       0}, /*  47 */
-	{CmdBuildCompanyHQ,                      0}, /*  48 */
-	{CmdSetPlayerFace,                       0}, /*  49 */
-	{CmdSetPlayerColor,                      0}, /*  50 */
-
-	{CmdIncreaseLoan,                        0}, /*  51 */
-	{CmdDecreaseLoan,                        0}, /*  52 */
-
-	{CmdWantEnginePreview,                   0}, /*  53 */
-
-	{CmdNameVehicle,                         0}, /*  54 */
-	{CmdRenameEngine,                        0}, /*  55 */
-
-	{CmdChangeCompanyName,                   0}, /*  56 */
-	{CmdChangePresidentName,                 0}, /*  57 */
-
-	{CmdRenameStation,                       0}, /*  58 */
-
-	{CmdSellAircraft,                        0}, /*  59 */
-	{CmdStartStopAircraft,                   0}, /*  60 */
-
-	{CmdBuildAircraft,                       0}, /*  61 */
-	{CmdSendAircraftToHangar,                0}, /*  62 */
-	{NULL,                                   0}, /*  63 */
-	{CmdRefitAircraft,                       0}, /*  64 */
-
-	{CmdPlaceSign,                           0}, /*  65 */
-	{CmdRenameSign,                          0}, /*  66 */
-
-	{CmdBuildRoadVeh,                        0}, /*  67 */
-	{CmdStartStopRoadVeh,                    0}, /*  68 */
-	{CmdSellRoadVeh,                         0}, /*  69 */
-	{CmdSendRoadVehToDepot,                  0}, /*  70 */
-	{CmdTurnRoadVeh,                         0}, /*  71 */
-	{CmdRefitRoadVeh,                        0}, /*  72 */
-
-	{CmdPause,                      CMD_SERVER}, /*  73 */
-
-	{CmdBuyShareInCompany,                   0}, /*  74 */
-	{CmdSellShareInCompany,                  0}, /*  75 */
-	{CmdBuyCompany,                          0}, /*  76 */
-
-	{CmdBuildTown,                 CMD_OFFLINE}, /*  77 */
-	{NULL,                                   0}, /*  78 */
-	{NULL,                                   0}, /*  79 */
-	{CmdRenameTown,                 CMD_SERVER}, /*  80 */
-	{CmdDoTownAction,                        0}, /*  81 */
-
-	{CmdSetRoadDriveSide,           CMD_SERVER}, /*  82 */
-	{NULL,                                   0}, /*  83 */
-	{NULL,                                   0}, /*  84 */
-	{CmdChangeDifficultyLevel,      CMD_SERVER}, /*  85 */
-
-	{CmdStartStopShip,                       0}, /*  86 */
-	{CmdSellShip,                            0}, /*  87 */
-	{CmdBuildShip,                           0}, /*  88 */
-	{CmdSendShipToDepot,                     0}, /*  89 */
-	{NULL,                                   0}, /*  90 */
-	{CmdRefitShip,                           0}, /*  91 */
-
-	{NULL,                                   0}, /*  92 */
-	{NULL,                                   0}, /*  93 */
-	{NULL,                                   0}, /*  94 */
-	{NULL,                                   0}, /*  95 */
-	{NULL,                                   0}, /*  96 */
-	{NULL,                                   0}, /*  97 */
-
-	{CmdOrderRefit,                          0}, /*  98 */
-	{CmdCloneOrder,                          0}, /*  99 */
-
-	{CmdClearArea,                           0}, /* 100 */
-	{NULL,                                   0}, /* 101 */
-
-	{CmdMoneyCheat,                CMD_OFFLINE}, /* 102 */
-	{CmdBuildCanal,                          0}, /* 103 */
-	{CmdPlayerCtrl,                          0}, /* 104 */
-
-	{CmdLevelLand,                           0}, /* 105 */
-
-	{CmdRefitRailVehicle,                    0}, /* 106 */
-	{CmdRestoreOrderIndex,                   0}, /* 107 */
-	{CmdBuildLock,                           0}, /* 108 */
-	{NULL,                                   0}, /* 109 */
-	{CmdBuildSignalTrack,                    0}, /* 110 */
-	{CmdRemoveSignalTrack,                   0}, /* 111 */
-	{NULL,                                   0}, /* 112 */
-	{CmdGiveMoney,                           0}, /* 113 */
-	{CmdChangePatchSetting,         CMD_SERVER}, /* 114 */
-	{CmdSetAutoReplace,                      0}, /* 115 */
-	{CmdCloneVehicle,                        0}, /* 116 */
-	{CmdMassStartStopVehicle,                0}, /* 117 */
-	{CmdDepotSellAllVehicles,                0}, /* 118 */
-	{CmdDepotMassAutoReplace,                0}, /* 119 */
-};
-
-/* This function range-checks a cmd, and checks if the cmd is not NULL */
-bool IsValidCommand(uint cmd)
-{
-	cmd &= 0xFF;
-
-	return
-		cmd < lengthof(_command_proc_table) &&
-		_command_proc_table[cmd].proc != NULL;
-}
-
-byte GetCommandFlags(uint cmd)
-{
-	return _command_proc_table[cmd & 0xFF].flags;
-}
-
-
-static int _docommand_recursive;
-
-int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
-{
-	int32 res;
-	CommandProc *proc;
-
-	/* Do not even think about executing out-of-bounds tile-commands */
-	if (tile >= MapSize()) {
-		_cmd_text = NULL;
-		return CMD_ERROR;
-	}
-
-	proc = _command_proc_table[procc].proc;
-
-	if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
-
-	_docommand_recursive++;
-
-	// only execute the test call if it's toplevel, or we're not execing.
-	if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) {
-		res = proc(tile, flags & ~DC_EXEC, p1, p2);
-		if (CmdFailed(res)) {
-			if (res & 0xFFFF) _error_message = res & 0xFFFF;
-			goto error;
-		}
-
-		if (_docommand_recursive == 1 &&
-				!(flags & DC_QUERY_COST) &&
-				res != 0 &&
-				!CheckPlayerHasMoney(res)) {
-			goto error;
-		}
-
-		if (!(flags & DC_EXEC)) {
-			_docommand_recursive--;
-			_cmd_text = NULL;
-			return res;
-		}
-	}
-
-	/* Execute the command here. All cost-relevant functions set the expenses type
-	 * themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */
-	res = proc(tile, flags, p1, p2);
-	if (CmdFailed(res)) {
-		if (res & 0xFFFF) _error_message = res & 0xFFFF;
-error:
-		_docommand_recursive--;
-		_cmd_text = NULL;
-		return CMD_ERROR;
-	}
-
-	// if toplevel, subtract the money.
-	if (--_docommand_recursive == 0) {
-		SubtractMoneyFromPlayer(res);
-		// XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player
-		if (tile != 0 && IsValidPlayer(_current_player)) {
-			GetPlayer(_current_player)->last_build_coordinate = tile;
-		}
-	}
-
-	_cmd_text = NULL;
-	return res;
-}
-
-int32 GetAvailableMoneyForCommand(void)
-{
-	PlayerID pid = _current_player;
-	if (!IsValidPlayer(pid)) return 0x7FFFFFFF; // max int
-	return GetPlayer(pid)->player_money;
-}
-
-// toplevel network safe docommand function for the current player. must not be called recursively.
-// the callback is called when the command succeeded or failed.
-bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
-{
-	int32 res = 0,res2;
-	CommandProc *proc;
-	uint32 flags;
-	bool notest;
-	StringID error_part1;
-
-	int x = TileX(tile) * TILE_SIZE;
-	int y = TileY(tile) * TILE_SIZE;
-
-	/* Do not even think about executing out-of-bounds tile-commands */
-	if (tile >= MapSize()) {
-		_cmd_text = NULL;
-		return false;
-	}
-
-	assert(_docommand_recursive == 0);
-
-	_error_message = INVALID_STRING_ID;
-	error_part1 = GB(cmd, 16, 16);
-	_additional_cash_required = 0;
-
-	/** Spectator has no rights except for the (dedicated) server which
-	 * is/can be a spectator but as the server it can do anything */
-	if (_current_player == PLAYER_SPECTATOR && !_network_server) {
-		ShowErrorMessage(_error_message, error_part1, x, y);
-		_cmd_text = NULL;
-		return false;
-	}
-
-	flags = 0;
-	if (cmd & CMD_AUTO) flags |= DC_AUTO;
-	if (cmd & CMD_NO_WATER) flags |= DC_NO_WATER;
-
-	// get pointer to command handler
-	assert((cmd & 0xFF) < lengthof(_command_proc_table));
-	proc = _command_proc_table[cmd & 0xFF].proc;
-	if (proc == NULL) {
-		_cmd_text = NULL;
-		return false;
-	}
-
-	// Some commands have a different output in dryrun than the realrun
-	//  e.g.: if you demolish a whole town, the dryrun would say okay.
-	//  but by really destroying, your rating drops and at a certain point
-	//  it will fail. so res and res2 are different
-	// CMD_REMOVE_ROAD: This command has special local authority
-	// restrictions which may cause the test run to fail (the previous
-	// road fragments still stay there and the town won't let you
-	// disconnect the road system), but the exec will succeed and this
-	// fact will trigger an assertion failure. --pasky
-	notest =
-		(cmd & 0xFF) == CMD_CLEAR_AREA ||
-		(cmd & 0xFF) == CMD_CONVERT_RAIL ||
-		(cmd & 0xFF) == CMD_LEVEL_LAND ||
-		(cmd & 0xFF) == CMD_REMOVE_ROAD ||
-		(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD;
-
-	_docommand_recursive = 1;
-
-	// cost estimation only?
-	if (!IsGeneratingWorld() &&
-			_shift_pressed &&
-			IsLocalPlayer() &&
-			!(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR)) &&
-			(cmd & 0xFF) != CMD_PAUSE) {
-		// estimate the cost.
-		res = proc(tile, flags, p1, p2);
-		if (CmdFailed(res)) {
-			if (res & 0xFFFF) _error_message = res & 0xFFFF;
-			ShowErrorMessage(_error_message, error_part1, x, y);
-		} else {
-			ShowEstimatedCostOrIncome(res, x, y);
-		}
-
-		_docommand_recursive = 0;
-		_cmd_text = NULL;
-		return false;
-	}
-
-
-	if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
-		// first test if the command can be executed.
-		res = proc(tile, flags, p1, p2);
-		if (CmdFailed(res)) {
-			if (res & 0xFFFF) _error_message = res & 0xFFFF;
-			goto show_error;
-		}
-		// no money? Only check if notest is off
-		if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
-	}
-
-#ifdef ENABLE_NETWORK
-	/** If we are in network, and the command is not from the network
-	 * send it to the command-queue and abort execution
-	 * If we are a dedicated server temporarily switch local player, otherwise
-	 * the other parties won't be able to execute our command and will desync.
-	 * We also need to do this if the server's company has gone bankrupt
-	 * @todo Rewrite (dedicated) server to something more than a dirty hack!
-	 */
-	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
-		PlayerID pbck = _local_player;
-		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = 0;
-		NetworkSend_Command(tile, p1, p2, cmd, callback);
-		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck;
-		_docommand_recursive = 0;
-		_cmd_text = NULL;
-		return true;
-	}
-#endif /* ENABLE_NETWORK */
-
-	// update last build coordinate of player.
-	if (tile != 0 && IsValidPlayer(_current_player)) {
-		GetPlayer(_current_player)->last_build_coordinate = tile;
-	}
-
-	/* Actually try and execute the command. If no cost-type is given
-	 * use the construction one */
-	_yearly_expenses_type = EXPENSES_CONSTRUCTION;
-	res2 = proc(tile, flags | DC_EXEC, p1, p2);
-
-	// If notest is on, it means the result of the test can be different than
-	//   the real command.. so ignore the test
-	if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
-		assert(res == res2); // sanity check
-	} else {
-		if (CmdFailed(res2)) {
-			if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
-			goto show_error;
-		}
-	}
-
-	SubtractMoneyFromPlayer(res2);
-
-	if (IsLocalPlayer() && _game_mode != GM_EDITOR) {
-		if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
-		if (_additional_cash_required) {
-			SetDParam(0, _additional_cash_required);
-			ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y);
-			if (res2 == 0) goto callb_err;
-		}
-	}
-
-	_docommand_recursive = 0;
-
-	if (callback) callback(true, tile, p1, p2);
-	_cmd_text = NULL;
-	return true;
-
-show_error:
-	// show error message if the command fails?
-	if (IsLocalPlayer() && error_part1 != 0) {
-		ShowErrorMessage(_error_message, error_part1, x,y);
-	}
-
-callb_err:
-	_docommand_recursive = 0;
-
-	if (callback) callback(false, tile, p1, p2);
-	_cmd_text = NULL;
-	return false;
-}
new file mode 100644
--- /dev/null
+++ b/src/command.cpp
@@ -0,0 +1,566 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "gui.h"
+#include "command.h"
+#include "player.h"
+#include "network/network.h"
+#include "variables.h"
+#include "genworld.h"
+
+const char* _cmd_text = NULL;
+
+#define DEF_COMMAND(yyyy) int32 yyyy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+
+DEF_COMMAND(CmdBuildRailroadTrack);
+DEF_COMMAND(CmdRemoveRailroadTrack);
+DEF_COMMAND(CmdBuildSingleRail);
+DEF_COMMAND(CmdRemoveSingleRail);
+
+DEF_COMMAND(CmdLandscapeClear);
+
+DEF_COMMAND(CmdBuildBridge);
+
+DEF_COMMAND(CmdBuildRailroadStation);
+DEF_COMMAND(CmdRemoveFromRailroadStation);
+DEF_COMMAND(CmdConvertRail);
+
+DEF_COMMAND(CmdBuildSingleSignal);
+DEF_COMMAND(CmdRemoveSingleSignal);
+
+DEF_COMMAND(CmdTerraformLand);
+
+DEF_COMMAND(CmdPurchaseLandArea);
+DEF_COMMAND(CmdSellLandArea);
+
+DEF_COMMAND(CmdBuildTunnel);
+
+DEF_COMMAND(CmdBuildTrainDepot);
+DEF_COMMAND(CmdBuildTrainWaypoint);
+DEF_COMMAND(CmdRenameWaypoint);
+DEF_COMMAND(CmdRemoveTrainWaypoint);
+
+DEF_COMMAND(CmdBuildRoadStop);
+
+DEF_COMMAND(CmdBuildLongRoad);
+DEF_COMMAND(CmdRemoveLongRoad);
+DEF_COMMAND(CmdBuildRoad);
+DEF_COMMAND(CmdRemoveRoad);
+
+DEF_COMMAND(CmdBuildRoadDepot);
+
+DEF_COMMAND(CmdBuildAirport);
+
+DEF_COMMAND(CmdBuildDock);
+
+DEF_COMMAND(CmdBuildShipDepot);
+
+DEF_COMMAND(CmdBuildBuoy);
+
+DEF_COMMAND(CmdPlantTree);
+
+DEF_COMMAND(CmdBuildRailVehicle);
+DEF_COMMAND(CmdMoveRailVehicle);
+
+DEF_COMMAND(CmdStartStopTrain);
+
+DEF_COMMAND(CmdSellRailWagon);
+
+DEF_COMMAND(CmdSendTrainToDepot);
+DEF_COMMAND(CmdForceTrainProceed);
+DEF_COMMAND(CmdReverseTrainDirection);
+
+DEF_COMMAND(CmdModifyOrder);
+DEF_COMMAND(CmdSkipOrder);
+DEF_COMMAND(CmdDeleteOrder);
+DEF_COMMAND(CmdInsertOrder);
+DEF_COMMAND(CmdChangeServiceInt);
+DEF_COMMAND(CmdRestoreOrderIndex);
+
+DEF_COMMAND(CmdBuildIndustry);
+
+DEF_COMMAND(CmdBuildCompanyHQ);
+DEF_COMMAND(CmdSetPlayerFace);
+DEF_COMMAND(CmdSetPlayerColor);
+
+DEF_COMMAND(CmdIncreaseLoan);
+DEF_COMMAND(CmdDecreaseLoan);
+
+DEF_COMMAND(CmdWantEnginePreview);
+
+DEF_COMMAND(CmdNameVehicle);
+DEF_COMMAND(CmdRenameEngine);
+
+DEF_COMMAND(CmdChangeCompanyName);
+DEF_COMMAND(CmdChangePresidentName);
+
+DEF_COMMAND(CmdRenameStation);
+
+DEF_COMMAND(CmdSellAircraft);
+DEF_COMMAND(CmdStartStopAircraft);
+DEF_COMMAND(CmdBuildAircraft);
+DEF_COMMAND(CmdSendAircraftToHangar);
+DEF_COMMAND(CmdRefitAircraft);
+
+DEF_COMMAND(CmdPlaceSign);
+DEF_COMMAND(CmdRenameSign);
+
+DEF_COMMAND(CmdBuildRoadVeh);
+DEF_COMMAND(CmdStartStopRoadVeh);
+DEF_COMMAND(CmdSellRoadVeh);
+DEF_COMMAND(CmdSendRoadVehToDepot);
+DEF_COMMAND(CmdTurnRoadVeh);
+DEF_COMMAND(CmdRefitRoadVeh);
+
+DEF_COMMAND(CmdPause);
+
+DEF_COMMAND(CmdBuyShareInCompany);
+DEF_COMMAND(CmdSellShareInCompany);
+DEF_COMMAND(CmdBuyCompany);
+
+DEF_COMMAND(CmdBuildTown);
+
+DEF_COMMAND(CmdRenameTown);
+DEF_COMMAND(CmdDoTownAction);
+
+DEF_COMMAND(CmdSetRoadDriveSide);
+
+DEF_COMMAND(CmdChangeDifficultyLevel);
+DEF_COMMAND(CmdChangePatchSetting);
+
+DEF_COMMAND(CmdStartStopShip);
+DEF_COMMAND(CmdSellShip);
+DEF_COMMAND(CmdBuildShip);
+DEF_COMMAND(CmdSendShipToDepot);
+DEF_COMMAND(CmdRefitShip);
+
+DEF_COMMAND(CmdOrderRefit);
+DEF_COMMAND(CmdCloneOrder);
+
+DEF_COMMAND(CmdClearArea);
+
+DEF_COMMAND(CmdGiveMoney);
+DEF_COMMAND(CmdMoneyCheat);
+DEF_COMMAND(CmdBuildCanal);
+DEF_COMMAND(CmdBuildLock);
+
+DEF_COMMAND(CmdPlayerCtrl);
+
+DEF_COMMAND(CmdLevelLand);
+
+DEF_COMMAND(CmdRefitRailVehicle);
+
+DEF_COMMAND(CmdBuildSignalTrack);
+DEF_COMMAND(CmdRemoveSignalTrack);
+
+DEF_COMMAND(CmdSetAutoReplace);
+
+DEF_COMMAND(CmdCloneVehicle);
+DEF_COMMAND(CmdMassStartStopVehicle);
+DEF_COMMAND(CmdDepotSellAllVehicles);
+DEF_COMMAND(CmdDepotMassAutoReplace);
+
+/* The master command table */
+static const Command _command_proc_table[] = {
+	{CmdBuildRailroadTrack,                  0}, /*   0 */
+	{CmdRemoveRailroadTrack,                 0}, /*   1 */
+	{CmdBuildSingleRail,                     0}, /*   2 */
+	{CmdRemoveSingleRail,                    0}, /*   3 */
+	{CmdLandscapeClear,                      0}, /*   4 */
+	{CmdBuildBridge,                         0}, /*   5 */
+	{CmdBuildRailroadStation,                0}, /*   6 */
+	{CmdBuildTrainDepot,                     0}, /*   7 */
+	{CmdBuildSingleSignal,                   0}, /*   8 */
+	{CmdRemoveSingleSignal,                  0}, /*   9 */
+	{CmdTerraformLand,                       0}, /*  10 */
+	{CmdPurchaseLandArea,                    0}, /*  11 */
+	{CmdSellLandArea,                        0}, /*  12 */
+	{CmdBuildTunnel,                         0}, /*  13 */
+	{CmdRemoveFromRailroadStation,           0}, /*  14 */
+	{CmdConvertRail,                         0}, /*  15 */
+	{CmdBuildTrainWaypoint,                  0}, /*  16 */
+	{CmdRenameWaypoint,                      0}, /*  17 */
+	{CmdRemoveTrainWaypoint,                 0}, /*  18 */
+	{NULL,                                   0}, /*  19 */
+	{NULL,                                   0}, /*  20 */
+	{CmdBuildRoadStop,                       0}, /*  21 */
+	{NULL,                                   0}, /*  22 */
+	{CmdBuildLongRoad,                       0}, /*  23 */
+	{CmdRemoveLongRoad,                      0}, /*  24 */
+	{CmdBuildRoad,                           0}, /*  25 */
+	{CmdRemoveRoad,                          0}, /*  26 */
+	{CmdBuildRoadDepot,                      0}, /*  27 */
+	{NULL,                                   0}, /*  28 */
+	{CmdBuildAirport,                        0}, /*  29 */
+	{CmdBuildDock,                           0}, /*  30 */
+	{CmdBuildShipDepot,                      0}, /*  31 */
+	{CmdBuildBuoy,                           0}, /*  32 */
+	{CmdPlantTree,                           0}, /*  33 */
+	{CmdBuildRailVehicle,                    0}, /*  34 */
+	{CmdMoveRailVehicle,                     0}, /*  35 */
+	{CmdStartStopTrain,                      0}, /*  36 */
+	{NULL,                                   0}, /*  37 */
+	{CmdSellRailWagon,                       0}, /*  38 */
+	{CmdSendTrainToDepot,                    0}, /*  39 */
+	{CmdForceTrainProceed,                   0}, /*  40 */
+	{CmdReverseTrainDirection,               0}, /*  41 */
+
+	{CmdModifyOrder,                         0}, /*  42 */
+	{CmdSkipOrder,                           0}, /*  43 */
+	{CmdDeleteOrder,                         0}, /*  44 */
+	{CmdInsertOrder,                         0}, /*  45 */
+
+	{CmdChangeServiceInt,                    0}, /*  46 */
+
+	{CmdBuildIndustry,                       0}, /*  47 */
+	{CmdBuildCompanyHQ,                      0}, /*  48 */
+	{CmdSetPlayerFace,                       0}, /*  49 */
+	{CmdSetPlayerColor,                      0}, /*  50 */
+
+	{CmdIncreaseLoan,                        0}, /*  51 */
+	{CmdDecreaseLoan,                        0}, /*  52 */
+
+	{CmdWantEnginePreview,                   0}, /*  53 */
+
+	{CmdNameVehicle,                         0}, /*  54 */
+	{CmdRenameEngine,                        0}, /*  55 */
+
+	{CmdChangeCompanyName,                   0}, /*  56 */
+	{CmdChangePresidentName,                 0}, /*  57 */
+
+	{CmdRenameStation,                       0}, /*  58 */
+
+	{CmdSellAircraft,                        0}, /*  59 */
+	{CmdStartStopAircraft,                   0}, /*  60 */
+
+	{CmdBuildAircraft,                       0}, /*  61 */
+	{CmdSendAircraftToHangar,                0}, /*  62 */
+	{NULL,                                   0}, /*  63 */
+	{CmdRefitAircraft,                       0}, /*  64 */
+
+	{CmdPlaceSign,                           0}, /*  65 */
+	{CmdRenameSign,                          0}, /*  66 */
+
+	{CmdBuildRoadVeh,                        0}, /*  67 */
+	{CmdStartStopRoadVeh,                    0}, /*  68 */
+	{CmdSellRoadVeh,                         0}, /*  69 */
+	{CmdSendRoadVehToDepot,                  0}, /*  70 */
+	{CmdTurnRoadVeh,                         0}, /*  71 */
+	{CmdRefitRoadVeh,                        0}, /*  72 */
+
+	{CmdPause,                      CMD_SERVER}, /*  73 */
+
+	{CmdBuyShareInCompany,                   0}, /*  74 */
+	{CmdSellShareInCompany,                  0}, /*  75 */
+	{CmdBuyCompany,                          0}, /*  76 */
+
+	{CmdBuildTown,                 CMD_OFFLINE}, /*  77 */
+	{NULL,                                   0}, /*  78 */
+	{NULL,                                   0}, /*  79 */
+	{CmdRenameTown,                 CMD_SERVER}, /*  80 */
+	{CmdDoTownAction,                        0}, /*  81 */
+
+	{CmdSetRoadDriveSide,           CMD_SERVER}, /*  82 */
+	{NULL,                                   0}, /*  83 */
+	{NULL,                                   0}, /*  84 */
+	{CmdChangeDifficultyLevel,      CMD_SERVER}, /*  85 */
+
+	{CmdStartStopShip,                       0}, /*  86 */
+	{CmdSellShip,                            0}, /*  87 */
+	{CmdBuildShip,                           0}, /*  88 */
+	{CmdSendShipToDepot,                     0}, /*  89 */
+	{NULL,                                   0}, /*  90 */
+	{CmdRefitShip,                           0}, /*  91 */
+
+	{NULL,                                   0}, /*  92 */
+	{NULL,                                   0}, /*  93 */
+	{NULL,                                   0}, /*  94 */
+	{NULL,                                   0}, /*  95 */
+	{NULL,                                   0}, /*  96 */
+	{NULL,                                   0}, /*  97 */
+
+	{CmdOrderRefit,                          0}, /*  98 */
+	{CmdCloneOrder,                          0}, /*  99 */
+
+	{CmdClearArea,                           0}, /* 100 */
+	{NULL,                                   0}, /* 101 */
+
+	{CmdMoneyCheat,                CMD_OFFLINE}, /* 102 */
+	{CmdBuildCanal,                          0}, /* 103 */
+	{CmdPlayerCtrl,                          0}, /* 104 */
+
+	{CmdLevelLand,                           0}, /* 105 */
+
+	{CmdRefitRailVehicle,                    0}, /* 106 */
+	{CmdRestoreOrderIndex,                   0}, /* 107 */
+	{CmdBuildLock,                           0}, /* 108 */
+	{NULL,                                   0}, /* 109 */
+	{CmdBuildSignalTrack,                    0}, /* 110 */
+	{CmdRemoveSignalTrack,                   0}, /* 111 */
+	{NULL,                                   0}, /* 112 */
+	{CmdGiveMoney,                           0}, /* 113 */
+	{CmdChangePatchSetting,         CMD_SERVER}, /* 114 */
+	{CmdSetAutoReplace,                      0}, /* 115 */
+	{CmdCloneVehicle,                        0}, /* 116 */
+	{CmdMassStartStopVehicle,                0}, /* 117 */
+	{CmdDepotSellAllVehicles,                0}, /* 118 */
+	{CmdDepotMassAutoReplace,                0}, /* 119 */
+};
+
+/* This function range-checks a cmd, and checks if the cmd is not NULL */
+bool IsValidCommand(uint cmd)
+{
+	cmd &= 0xFF;
+
+	return
+		cmd < lengthof(_command_proc_table) &&
+		_command_proc_table[cmd].proc != NULL;
+}
+
+byte GetCommandFlags(uint cmd)
+{
+	return _command_proc_table[cmd & 0xFF].flags;
+}
+
+
+static int _docommand_recursive;
+
+int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
+{
+	int32 res;
+	CommandProc *proc;
+
+	/* Do not even think about executing out-of-bounds tile-commands */
+	if (tile >= MapSize()) {
+		_cmd_text = NULL;
+		return CMD_ERROR;
+	}
+
+	proc = _command_proc_table[procc].proc;
+
+	if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
+
+	_docommand_recursive++;
+
+	// only execute the test call if it's toplevel, or we're not execing.
+	if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) {
+		res = proc(tile, flags & ~DC_EXEC, p1, p2);
+		if (CmdFailed(res)) {
+			if (res & 0xFFFF) _error_message = res & 0xFFFF;
+			goto error;
+		}
+
+		if (_docommand_recursive == 1 &&
+				!(flags & DC_QUERY_COST) &&
+				res != 0 &&
+				!CheckPlayerHasMoney(res)) {
+			goto error;
+		}
+
+		if (!(flags & DC_EXEC)) {
+			_docommand_recursive--;
+			_cmd_text = NULL;
+			return res;
+		}
+	}
+
+	/* Execute the command here. All cost-relevant functions set the expenses type
+	 * themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */
+	res = proc(tile, flags, p1, p2);
+	if (CmdFailed(res)) {
+		if (res & 0xFFFF) _error_message = res & 0xFFFF;
+error:
+		_docommand_recursive--;
+		_cmd_text = NULL;
+		return CMD_ERROR;
+	}
+
+	// if toplevel, subtract the money.
+	if (--_docommand_recursive == 0) {
+		SubtractMoneyFromPlayer(res);
+		// XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player
+		if (tile != 0 && IsValidPlayer(_current_player)) {
+			GetPlayer(_current_player)->last_build_coordinate = tile;
+		}
+	}
+
+	_cmd_text = NULL;
+	return res;
+}
+
+int32 GetAvailableMoneyForCommand(void)
+{
+	PlayerID pid = _current_player;
+	if (!IsValidPlayer(pid)) return 0x7FFFFFFF; // max int
+	return GetPlayer(pid)->player_money;
+}
+
+// toplevel network safe docommand function for the current player. must not be called recursively.
+// the callback is called when the command succeeded or failed.
+bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
+{
+	int32 res = 0,res2;
+	CommandProc *proc;
+	uint32 flags;
+	bool notest;
+	StringID error_part1;
+
+	int x = TileX(tile) * TILE_SIZE;
+	int y = TileY(tile) * TILE_SIZE;
+
+	/* Do not even think about executing out-of-bounds tile-commands */
+	if (tile >= MapSize()) {
+		_cmd_text = NULL;
+		return false;
+	}
+
+	assert(_docommand_recursive == 0);
+
+	_error_message = INVALID_STRING_ID;
+	error_part1 = GB(cmd, 16, 16);
+	_additional_cash_required = 0;
+
+	/** Spectator has no rights except for the (dedicated) server which
+	 * is/can be a spectator but as the server it can do anything */
+	if (_current_player == PLAYER_SPECTATOR && !_network_server) {
+		ShowErrorMessage(_error_message, error_part1, x, y);
+		_cmd_text = NULL;
+		return false;
+	}
+
+	flags = 0;
+	if (cmd & CMD_AUTO) flags |= DC_AUTO;
+	if (cmd & CMD_NO_WATER) flags |= DC_NO_WATER;
+
+	// get pointer to command handler
+	assert((cmd & 0xFF) < lengthof(_command_proc_table));
+	proc = _command_proc_table[cmd & 0xFF].proc;
+	if (proc == NULL) {
+		_cmd_text = NULL;
+		return false;
+	}
+
+	// Some commands have a different output in dryrun than the realrun
+	//  e.g.: if you demolish a whole town, the dryrun would say okay.
+	//  but by really destroying, your rating drops and at a certain point
+	//  it will fail. so res and res2 are different
+	// CMD_REMOVE_ROAD: This command has special local authority
+	// restrictions which may cause the test run to fail (the previous
+	// road fragments still stay there and the town won't let you
+	// disconnect the road system), but the exec will succeed and this
+	// fact will trigger an assertion failure. --pasky
+	notest =
+		(cmd & 0xFF) == CMD_CLEAR_AREA ||
+		(cmd & 0xFF) == CMD_CONVERT_RAIL ||
+		(cmd & 0xFF) == CMD_LEVEL_LAND ||
+		(cmd & 0xFF) == CMD_REMOVE_ROAD ||
+		(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD;
+
+	_docommand_recursive = 1;
+
+	// cost estimation only?
+	if (!IsGeneratingWorld() &&
+			_shift_pressed &&
+			IsLocalPlayer() &&
+			!(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR)) &&
+			(cmd & 0xFF) != CMD_PAUSE) {
+		// estimate the cost.
+		res = proc(tile, flags, p1, p2);
+		if (CmdFailed(res)) {
+			if (res & 0xFFFF) _error_message = res & 0xFFFF;
+			ShowErrorMessage(_error_message, error_part1, x, y);
+		} else {
+			ShowEstimatedCostOrIncome(res, x, y);
+		}
+
+		_docommand_recursive = 0;
+		_cmd_text = NULL;
+		return false;
+	}
+
+
+	if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
+		// first test if the command can be executed.
+		res = proc(tile, flags, p1, p2);
+		if (CmdFailed(res)) {
+			if (res & 0xFFFF) _error_message = res & 0xFFFF;
+			goto show_error;
+		}
+		// no money? Only check if notest is off
+		if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
+	}
+
+#ifdef ENABLE_NETWORK
+	/** If we are in network, and the command is not from the network
+	 * send it to the command-queue and abort execution
+	 * If we are a dedicated server temporarily switch local player, otherwise
+	 * the other parties won't be able to execute our command and will desync.
+	 * We also need to do this if the server's company has gone bankrupt
+	 * @todo Rewrite (dedicated) server to something more than a dirty hack!
+	 */
+	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
+		PlayerID pbck = _local_player;
+		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = 0;
+		NetworkSend_Command(tile, p1, p2, cmd, callback);
+		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck;
+		_docommand_recursive = 0;
+		_cmd_text = NULL;
+		return true;
+	}
+#endif /* ENABLE_NETWORK */
+
+	// update last build coordinate of player.
+	if (tile != 0 && IsValidPlayer(_current_player)) {
+		GetPlayer(_current_player)->last_build_coordinate = tile;
+	}
+
+	/* Actually try and execute the command. If no cost-type is given
+	 * use the construction one */
+	_yearly_expenses_type = EXPENSES_CONSTRUCTION;
+	res2 = proc(tile, flags | DC_EXEC, p1, p2);
+
+	// If notest is on, it means the result of the test can be different than
+	//   the real command.. so ignore the test
+	if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
+		assert(res == res2); // sanity check
+	} else {
+		if (CmdFailed(res2)) {
+			if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
+			goto show_error;
+		}
+	}
+
+	SubtractMoneyFromPlayer(res2);
+
+	if (IsLocalPlayer() && _game_mode != GM_EDITOR) {
+		if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
+		if (_additional_cash_required) {
+			SetDParam(0, _additional_cash_required);
+			ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y);
+			if (res2 == 0) goto callb_err;
+		}
+	}
+
+	_docommand_recursive = 0;
+
+	if (callback) callback(true, tile, p1, p2);
+	_cmd_text = NULL;
+	return true;
+
+show_error:
+	// show error message if the command fails?
+	if (IsLocalPlayer() && error_part1 != 0) {
+		ShowErrorMessage(_error_message, error_part1, x,y);
+	}
+
+callb_err:
+	_docommand_recursive = 0;
+
+	if (callback) callback(false, tile, p1, p2);
+	_cmd_text = NULL;
+	return false;
+}
deleted file mode 100644
--- a/src/console.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "player.h"
-#include "variables.h"
-#include "string.h"
-#include <stdarg.h>
-#include <string.h>
-#include "console.h"
-#include "network/network.h"
-#include "network/network_data.h"
-#include "network/network_server.h"
-
-#define ICON_BUFFER 79
-#define ICON_HISTORY_SIZE 20
-#define ICON_LINE_HEIGHT 12
-#define ICON_RIGHT_BORDERWIDTH 10
-#define ICON_BOTTOM_BORDERWIDTH 12
-#define ICON_MAX_ALIAS_LINES 40
-#define ICON_TOKEN_COUNT 20
-
-// ** main console ** //
-static char *_iconsole_buffer[ICON_BUFFER + 1];
-static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
-static Textbuf _iconsole_cmdline;
-
-// ** stdlib ** //
-byte _stdlib_developer = 1;
-bool _stdlib_con_developer = false;
-FILE *_iconsole_output_file;
-
-// ** main console cmd buffer
-static char *_iconsole_history[ICON_HISTORY_SIZE];
-static byte _iconsole_historypos;
-
-/* *************** */
-/*  end of header  */
-/* *************** */
-
-static void IConsoleClearCommand(void)
-{
-	memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
-	_iconsole_cmdline.length = 0;
-	_iconsole_cmdline.width = 0;
-	_iconsole_cmdline.caretpos = 0;
-	_iconsole_cmdline.caretxoffs = 0;
-	SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
-}
-
-static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
-
-
-static void IConsoleHistoryAdd(const char *cmd);
-static void IConsoleHistoryNavigate(int direction);
-
-// ** console window ** //
-static void IConsoleWndProc(Window *w, WindowEvent *e)
-{
-	static byte iconsole_scroll = ICON_BUFFER;
-
-	switch (e->event) {
-		case WE_PAINT: {
-			int i = iconsole_scroll;
-			int max = (w->height / ICON_LINE_HEIGHT) - 1;
-			int delta = 0;
-			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
-			while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
-				DoDrawString(_iconsole_buffer[i], 5,
-					w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
-				i--;
-			}
-			/* If the text is longer than the window, don't show the starting ']' */
-			delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
-			if (delta > 0) {
-				DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
-				delta = 0;
-			}
-
-			DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
-
-			if (_iconsole_cmdline.caret)
-				DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, 12);
-			break;
-		}
-		case WE_MOUSELOOP:
-			if (HandleCaret(&_iconsole_cmdline))
-				SetWindowDirty(w);
-			break;
-		case WE_DESTROY:
-			_iconsole_mode = ICONSOLE_CLOSED;
-			break;
-		case WE_KEYPRESS:
-			e->we.keypress.cont = false;
-			switch (e->we.keypress.keycode) {
-				case WKC_UP:
-					IConsoleHistoryNavigate(+1);
-					SetWindowDirty(w);
-					break;
-				case WKC_DOWN:
-					IConsoleHistoryNavigate(-1);
-					SetWindowDirty(w);
-					break;
-				case WKC_SHIFT | WKC_PAGEUP:
-					if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
-						iconsole_scroll = 0;
-					} else {
-						iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
-					}
-					SetWindowDirty(w);
-					break;
-				case WKC_SHIFT | WKC_PAGEDOWN:
-					if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
-						iconsole_scroll = ICON_BUFFER;
-					} else {
-						iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
-					}
-					SetWindowDirty(w);
-					break;
-				case WKC_SHIFT | WKC_UP:
-					if (iconsole_scroll <= 0) {
-						iconsole_scroll = 0;
-					} else {
-						--iconsole_scroll;
-					}
-					SetWindowDirty(w);
-					break;
-				case WKC_SHIFT | WKC_DOWN:
-					if (iconsole_scroll >= ICON_BUFFER) {
-						iconsole_scroll = ICON_BUFFER;
-					} else {
-						++iconsole_scroll;
-					}
-					SetWindowDirty(w);
-					break;
-				case WKC_BACKQUOTE:
-					IConsoleSwitch();
-					break;
-				case WKC_RETURN: case WKC_NUM_ENTER:
-					IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
-					IConsoleHistoryAdd(_iconsole_cmdline.buf);
-
-					IConsoleCmdExec(_iconsole_cmdline.buf);
-					IConsoleClearCommand();
-					break;
-				case WKC_CTRL | WKC_RETURN:
-					_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
-					IConsoleResize(w);
-					MarkWholeScreenDirty();
-					break;
-				case (WKC_CTRL | 'V'):
-					if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
-						IConsoleResetHistoryPos();
-						SetWindowDirty(w);
-					}
-					break;
-				case (WKC_CTRL | 'L'):
-					IConsoleCmdExec("clear");
-					break;
-				case (WKC_CTRL | 'U'):
-					DeleteTextBufferAll(&_iconsole_cmdline);
-					SetWindowDirty(w);
-					break;
-				case WKC_BACKSPACE: case WKC_DELETE:
-					if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
-						IConsoleResetHistoryPos();
-						SetWindowDirty(w);
-					}
-					break;
-				case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
-					if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
-						IConsoleResetHistoryPos();
-						SetWindowDirty(w);
-					}
-					break;
-				default:
-					if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
-						iconsole_scroll = ICON_BUFFER;
-						InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
-						IConsoleResetHistoryPos();
-						SetWindowDirty(w);
-					} else {
-						e->we.keypress.cont = true;
-					}
-			break;
-		}
-	}
-}
-
-static const Widget _iconsole_window_widgets[] = {
-	{WIDGETS_END}
-};
-
-static const WindowDesc _iconsole_window_desc = {
-	0, 0, 2, 2,
-	WC_CONSOLE, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_iconsole_window_widgets,
-	IConsoleWndProc,
-};
-
-void IConsoleInit(void)
-{
-	extern const char _openttd_revision[];
-	_iconsole_output_file = NULL;
-	_icolour_def  =  1;
-	_icolour_err  =  3;
-	_icolour_warn = 13;
-	_icolour_dbg  =  5;
-	_icolour_cmd  =  2;
-	_iconsole_historypos = ICON_HISTORY_SIZE - 1;
-	_iconsole_mode = ICONSOLE_CLOSED;
-
-#ifdef ENABLE_NETWORK /* Initialize network only variables */
-	_redirect_console_to_client = 0;
-#endif
-
-	memset(_iconsole_history, 0, sizeof(_iconsole_history));
-	memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
-	memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
-	_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
-	_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE;
-
-	IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
-	IConsolePrint(12,  "------------------------------------");
-	IConsolePrint(12,  "use \"help\" for more information");
-	IConsolePrint(12,  "");
-	IConsoleStdLibRegister();
-	IConsoleClearCommand();
-	IConsoleHistoryAdd("");
-}
-
-void IConsoleClearBuffer(void)
-{
-	uint i;
-	for (i = 0; i <= ICON_BUFFER; i++) {
-		free(_iconsole_buffer[i]);
-		_iconsole_buffer[i] = NULL;
-	}
-}
-
-static void IConsoleClear(void)
-{
-	free(_iconsole_cmdline.buf);
-	IConsoleClearBuffer();
-}
-
-static void IConsoleWriteToLogFile(const char *string)
-{
-	if (_iconsole_output_file != NULL) {
-		// if there is an console output file ... also print it there
-		fwrite(string, strlen(string), 1, _iconsole_output_file);
-		fwrite("\n", 1, 1, _iconsole_output_file);
-	}
-}
-
-bool CloseConsoleLogIfActive(void)
-{
-	if (_iconsole_output_file != NULL) {
-		IConsolePrintF(_icolour_def, "file output complete");
-		fclose(_iconsole_output_file);
-		_iconsole_output_file = NULL;
-		return true;
-	}
-
-	return false;
-}
-
-void IConsoleFree(void)
-{
-	IConsoleClear();
-	CloseConsoleLogIfActive();
-}
-
-void IConsoleResize(Window *w)
-{
-	switch (_iconsole_mode) {
-		case ICONSOLE_OPENED:
-			w->height = _screen.height / 3;
-			w->width = _screen.width;
-			break;
-		case ICONSOLE_FULL:
-			w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
-			w->width = _screen.width;
-			break;
-		default: return;
-	}
-
-	MarkWholeScreenDirty();
-}
-
-void IConsoleSwitch(void)
-{
-	switch (_iconsole_mode) {
-		case ICONSOLE_CLOSED: {
-			Window *w = AllocateWindowDesc(&_iconsole_window_desc);
-			w->height = _screen.height / 3;
-			w->width = _screen.width;
-			_iconsole_mode = ICONSOLE_OPENED;
-			SETBIT(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
-		} break;
-		case ICONSOLE_OPENED: case ICONSOLE_FULL:
-			DeleteWindowById(WC_CONSOLE, 0);
-			_iconsole_mode = ICONSOLE_CLOSED;
-			CLRBIT(_no_scroll, SCROLL_CON);
-			break;
-	}
-
-	MarkWholeScreenDirty();
-}
-
-void IConsoleClose(void) {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
-void IConsoleOpen(void)  {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
-
-/**
- * Add the entered line into the history so you can look it back
- * scroll, etc. Put it to the beginning as it is the latest text
- * @param cmd Text to be entered into the 'history'
- */
-static void IConsoleHistoryAdd(const char *cmd)
-{
-	free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
-
-	memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
-	_iconsole_history[0] = strdup(cmd);
-	IConsoleResetHistoryPos();
-}
-
-/**
- * Navigate Up/Down in the history of typed commands
- * @param direction Go further back in history (+1), go to recently typed commands (-1)
- */
-static void IConsoleHistoryNavigate(int direction)
-{
-	int i = _iconsole_historypos + direction;
-
-	// watch out for overflows, just wrap around
-	if (i < 0) i = ICON_HISTORY_SIZE - 1;
-	if (i >= ICON_HISTORY_SIZE) i = 0;
-
-	if (direction > 0)
-		if (_iconsole_history[i] == NULL) i = 0;
-
-	if (direction < 0) {
-		while (i > 0 && _iconsole_history[i] == NULL) i--;
-	}
-
-	_iconsole_historypos = i;
-	IConsoleClearCommand();
-	// copy history to 'command prompt / bash'
-	assert(_iconsole_history[i] != NULL && IS_INT_INSIDE(i, 0, ICON_HISTORY_SIZE));
-	ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength);
-	UpdateTextBufferSize(&_iconsole_cmdline);
-}
-
-/**
- * Handle the printing of text entered into the console or redirected there
- * by any other means. Text can be redirected to other players in a network game
- * as well as to a logfile. If the network server is a dedicated server, all activities
- * are also logged. All lines to print are added to a temporary buffer which can be
- * used as a history to print them onscreen
- * @param color_code the colour of the command. Red in case of errors, etc.
- * @param string the message entered or output on the console (notice, error, etc.)
- */
-void IConsolePrint(uint16 color_code, const char *string)
-{
-	char *str;
-#ifdef ENABLE_NETWORK
-	if (_redirect_console_to_client != 0) {
-		/* Redirect the string to the client */
-		SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(_redirect_console_to_client), color_code, string);
-		return;
-	}
-#endif
-
-	/* Create a copy of the string, strip if of colours and invalid
-	 * characters and (when applicable) assign it to the console buffer */
-	str = strdup(string);
-	str_strip_colours(str);
-	str_validate(str);
-
-	if (_network_dedicated) {
-		printf("%s\n", str);
-		IConsoleWriteToLogFile(str);
-		free(str); // free duplicated string since it's not used anymore
-		return;
-	}
-
-	/* move up all the strings in the buffer one place and do the same for colour
-	 * to accomodate for the new command/message */
-	free(_iconsole_buffer[0]);
-	memmove(&_iconsole_buffer[0], &_iconsole_buffer[1], sizeof(_iconsole_buffer[0]) * ICON_BUFFER);
-	_iconsole_buffer[ICON_BUFFER] = str;
-
-	memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER);
-	_iconsole_cbuffer[ICON_BUFFER] = color_code;
-
-	IConsoleWriteToLogFile(_iconsole_buffer[ICON_BUFFER]);
-
-	SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
-}
-
-/**
- * Handle the printing of text entered into the console or redirected there
- * by any other means. Uses printf() style format, for more information look
- * at @IConsolePrint()
- */
-void CDECL IConsolePrintF(uint16 color_code, const char *s, ...)
-{
-	va_list va;
-	char buf[ICON_MAX_STREAMSIZE];
-
-	va_start(va, s);
-	vsnprintf(buf, sizeof(buf), s, va);
-	va_end(va);
-
-	IConsolePrint(color_code, buf);
-}
-
-/**
- * It is possible to print debugging information to the console,
- * which is achieved by using this function. Can only be used by
- * @debug() in debug.c. You need at least a level 2 (developer) for debugging
- * messages to show up
- * @param dbg debugging category
- * @param string debugging message
- */
-void IConsoleDebug(const char *dbg, const char *string)
-{
-	if (_stdlib_developer > 1)
-		IConsolePrintF(_icolour_dbg, "dbg: [%s] %s", dbg, string);
-}
-
-/**
- * It is possible to print warnings to the console. These are mostly
- * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for
- * debugging messages to show up
- */
-void IConsoleWarning(const char *string)
-{
-	if (_stdlib_developer > 0)
-		IConsolePrintF(_icolour_warn, "WARNING: %s", string);
-}
-
-/**
- * It is possible to print error information to the console. This can include
- * game errors, or errors in general you would want the user to notice
- */
-void IConsoleError(const char *string)
-{
-	IConsolePrintF(_icolour_err, "ERROR: %s", string);
-}
-
-/**
- * Change a string into its number representation. Supports
- * decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false'
- * @param *value the variable a successfull conversion will be put in
- * @param *arg the string to be converted
- * @return Return true on success or false on failure
- */
-bool GetArgumentInteger(uint32 *value, const char *arg)
-{
-	char *endptr;
-
-	if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) {
-		*value = 1;
-		return true;
-	}
-	if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) {
-		*value = 0;
-		return true;
-	}
-
-	*value = strtoul(arg, &endptr, 0);
-	return arg != endptr;
-}
-
-// * ************************* * //
-// * hooking code              * //
-// * ************************* * //
-/**
- * General internal hooking code that is the same for both commands and variables
- * @param hooks @IConsoleHooks structure that will be set according to
- * @param type type access trigger
- * @param proc function called when the hook criteria is met
- */
-static void IConsoleHookAdd(IConsoleHooks *hooks, IConsoleHookTypes type, IConsoleHook *proc)
-{
-	if (hooks == NULL || proc == NULL) return;
-
-	switch (type) {
-		case ICONSOLE_HOOK_ACCESS:
-			hooks->access = proc;
-			break;
-		case ICONSOLE_HOOK_PRE_ACTION:
-			hooks->pre = proc;
-			break;
-		case ICONSOLE_HOOK_POST_ACTION:
-			hooks->post = proc;
-			break;
-		default: NOT_REACHED();
-	}
-}
-
-/**
- * Handle any special hook triggers. If the hook type is met check if
- * there is a function associated with that and if so, execute it
- * @param hooks @IConsoleHooks structure that will be checked
- * @param type type of hook, trigger that needs to be activated
- * @return true on a successfull execution of the hook command or if there
- * is no hook/trigger present at all. False otherwise
- */
-static bool IConsoleHookHandle(const IConsoleHooks *hooks, IConsoleHookTypes type)
-{
-	IConsoleHook *proc = NULL;
-	if (hooks == NULL) return false;
-
-	switch (type) {
-		case ICONSOLE_HOOK_ACCESS:
-			proc = hooks->access;
-			break;
-		case ICONSOLE_HOOK_PRE_ACTION:
-			proc = hooks->pre;
-			break;
-		case ICONSOLE_HOOK_POST_ACTION:
-			proc = hooks->post;
-			break;
-		default: NOT_REACHED();
-	}
-
-	return (proc == NULL) ? true : proc();
-}
-
-/**
- * Add a hook to a command that will be triggered at certain points
- * @param name name of the command that the hook is added to
- * @param type type of hook that is added (ACCESS, BEFORE and AFTER change)
- * @param proc function called when the hook criteria is met
- */
-void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
-{
-	IConsoleCmd *cmd = IConsoleCmdGet(name);
-	if (cmd == NULL) return;
-	IConsoleHookAdd(&cmd->hook, type, proc);
-}
-
-/**
- * Add a hook to a variable that will be triggered at certain points
- * @param name name of the variable that the hook is added to
- * @param type type of hook that is added (ACCESS, BEFORE and AFTER change)
- * @param proc function called when the hook criteria is met
- */
-void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
-{
-	IConsoleVar *var = IConsoleVarGet(name);
-	if (var == NULL) return;
-	IConsoleHookAdd(&var->hook, type, proc);
-}
-
-/**
- * Perhaps ugly macro, but this saves us the trouble of writing the same function
- * three types, just with different variables. Yes, templates would be handy. It was
- * either this define or an even more ugly void* magic function
- */
-#define IConsoleAddSorted(_base, item_new, IConsoleType, type)                 \
-{                                                                              \
-	IConsoleType *item, *item_before;                                            \
-	/* first command */                                                          \
-	if (_base == NULL) {                                                         \
-		_base = item_new;                                                          \
-		return;                                                                    \
-	}                                                                            \
-                                                                               \
-	item_before = NULL;                                                          \
-	item = _base;                                                                \
-                                                                               \
-	/* BEGIN - Alphabetically insert the commands into the linked list */        \
-	while (item != NULL) {                                                       \
-		int i = strcmp(item->name, item_new->name);                                \
-		if (i == 0) {                                                              \
-			IConsoleError(type " with this name already exists; insertion aborted"); \
-			free(item_new);                                                          \
-			return;                                                                  \
-		}                                                                          \
-                                                                               \
-		if (i > 0) break; /* insert at this position */                            \
-                                                                               \
-		item_before = item;                                                        \
-		item = item->next;                                                         \
-	}                                                                            \
-                                                                               \
-	if (item_before == NULL) {                                                   \
-		_base = item_new;                                                          \
-	} else {                                                                     \
-		item_before->next = item_new;                                              \
-  }                                                                            \
-                                                                               \
-	item_new->next = item;                                                       \
-	/* END - Alphabetical insert */                                              \
-}
-
-/**
- * Register a new command to be used in the console
- * @param name name of the command that will be used
- * @param proc function that will be called upon execution of command
- */
-void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc)
-{
-	char *new_cmd = strdup(name);
-	IConsoleCmd *item_new = malloc(sizeof(IConsoleCmd));
-
-	item_new->next = NULL;
-	item_new->proc = proc;
-	item_new->name = new_cmd;
-
-	item_new->hook.access = NULL;
-	item_new->hook.pre = NULL;
-	item_new->hook.post = NULL;
-
-	IConsoleAddSorted(_iconsole_cmds, item_new, IConsoleCmd, "a command");
-}
-
-/**
- * Find the command pointed to by its string
- * @param name command to be found
- * @return return Cmdstruct of the found command, or NULL on failure
- */
-IConsoleCmd *IConsoleCmdGet(const char *name)
-{
-	IConsoleCmd *item;
-
-	for (item = _iconsole_cmds; item != NULL; item = item->next) {
-		if (strcmp(item->name, name) == 0) return item;
-	}
-	return NULL;
-}
-
-/**
- * Register a an alias for an already existing command in the console
- * @param name name of the alias that will be used
- * @param cmd name of the command that 'name' will be alias of
- */
-void IConsoleAliasRegister(const char *name, const char *cmd)
-{
-	char *new_alias = strdup(name);
-	char *cmd_aliased = strdup(cmd);
-	IConsoleAlias *item_new = malloc(sizeof(IConsoleAlias));
-
-	item_new->next = NULL;
-	item_new->cmdline = cmd_aliased;
-	item_new->name = new_alias;
-
-	IConsoleAddSorted(_iconsole_aliases, item_new, IConsoleAlias, "an alias");
-}
-
-/**
- * Find the alias pointed to by its string
- * @param name alias to be found
- * @return return Aliasstruct of the found alias, or NULL on failure
- */
-IConsoleAlias *IConsoleAliasGet(const char *name)
-{
-	IConsoleAlias* item;
-
-	for (item = _iconsole_aliases; item != NULL; item = item->next) {
-		if (strcmp(item->name, name) == 0) return item;
-	}
-
-	return NULL;
-}
-
-/** copy in an argument into the aliasstream */
-static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
-{
-	int len = min(ICON_MAX_STREAMSIZE - bufpos, (uint)strlen(src));
-	strncpy(dst, src, len);
-
-	return len;
-}
-
-/**
- * An alias is just another name for a command, or for more commands
- * Execute it as well.
- * @param *alias is the alias of the command
- * @param tokencount the number of parameters passed
- * @param *tokens are the parameters given to the original command (0 is the first param)
- */
-static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
-{
-	const char *cmdptr;
-	char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
-	uint i;
-	uint a_index, astream_i;
-
-	memset(&aliases, 0, sizeof(aliases));
-	memset(&aliasstream, 0, sizeof(aliasstream));
-
-	if (_stdlib_con_developer)
-		IConsolePrintF(_icolour_dbg, "condbg: requested command is an alias; parsing...");
-
-	aliases[0] = aliasstream;
-	for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
-		if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
-
-		switch (*cmdptr) {
-		case '\'': /* ' will double for "" */
-			aliasstream[astream_i++] = '"';
-			break;
-		case ';': /* Cmd seperator, start new command */
-			aliasstream[astream_i] = '\0';
-			aliases[++a_index] = &aliasstream[++astream_i];
-			cmdptr++;
-			break;
-		case '%': /* Some or all parameters */
-			cmdptr++;
-			switch (*cmdptr) {
-			case '+': { /* All parameters seperated: "[param 1]" "[param 2]" */
-				for (i = 0; i != tokencount; i++) {
-					aliasstream[astream_i++] = '"';
-					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
-					aliasstream[astream_i++] = '"';
-					aliasstream[astream_i++] = ' ';
-				}
-			} break;
-			case '!': { /* Merge the parameters to one: "[param 1] [param 2] [param 3...]" */
-				aliasstream[astream_i++] = '"';
-				for (i = 0; i != tokencount; i++) {
-					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
-					aliasstream[astream_i++] = ' ';
-				}
-				aliasstream[astream_i++] = '"';
-
-			} break;
-				default: { /* One specific parameter: %A = [param 1] %B = [param 2] ... */
-				int param = *cmdptr - 'A';
-
-				if (param < 0 || param >= tokencount) {
-					IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
-					IConsolePrintF(_icolour_warn, "Usage of alias '%s': %s", alias->name, alias->cmdline);
-					return;
-				}
-
-				aliasstream[astream_i++] = '"';
-				astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
-				aliasstream[astream_i++] = '"';
-			} break;
-			} break;
-
-		default:
-			aliasstream[astream_i++] = *cmdptr;
-			break;
-		}
-	}
-
-	for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn
-}
-
-/**
- * Special function for adding string-type variables. They in addition
- * also need a 'size' value saying how long their string buffer is.
- * @param size the length of the string buffer
- * For more information see @IConsoleVarRegister()
- */
-void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help)
-{
-	IConsoleVar *var;
-	IConsoleVarRegister(name, addr, ICONSOLE_VAR_STRING, help);
-	var = IConsoleVarGet(name);
-	var->size = size;
-}
-
-/**
- * Register a new variable to be used in the console
- * @param name name of the variable that will be used
- * @param addr memory location the variable will point to
- * @param help the help string shown for the variable
- * @param type the type of the variable (simple atomic) so we know which values it can get
- */
-void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help)
-{
-	char *new_cmd = strdup(name);
-	IConsoleVar *item_new = malloc(sizeof(IConsoleVar));
-
-	item_new->help = (help != NULL) ? strdup(help) : NULL;
-
-	item_new->next = NULL;
-	item_new->name = new_cmd;
-	item_new->addr = addr;
-	item_new->proc = NULL;
-	item_new->type = type;
-
-	item_new->hook.access = NULL;
-	item_new->hook.pre = NULL;
-	item_new->hook.post = NULL;
-
-	IConsoleAddSorted(_iconsole_vars, item_new, IConsoleVar, "a variable");
-}
-
-/**
- * Find the variable pointed to by its string
- * @param name variable to be found
- * @return return Varstruct of the found variable, or NULL on failure
- */
-IConsoleVar *IConsoleVarGet(const char *name)
-{
-	IConsoleVar *item;
-	for (item = _iconsole_vars; item != NULL; item = item->next) {
-		if (strcmp(item->name, name) == 0) return item;
-	}
-
-	return NULL;
-}
-
-/**
- * Set a new value to a console variable
- * @param *var the variable being set/changed
- * @param value the new value given to the variable, cast properly
- */
-static void IConsoleVarSetValue(const IConsoleVar *var, uint32 value)
-{
-	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
-	switch (var->type) {
-		case ICONSOLE_VAR_BOOLEAN:
-			*(bool*)var->addr = (value != 0);
-			break;
-		case ICONSOLE_VAR_BYTE:
-			*(byte*)var->addr = (byte)value;
-			break;
-		case ICONSOLE_VAR_UINT16:
-			*(uint16*)var->addr = (uint16)value;
-			break;
-		case ICONSOLE_VAR_INT16:
-			*(int16*)var->addr = (int16)value;
-			break;
-		case ICONSOLE_VAR_UINT32:
-			*(uint32*)var->addr = (uint32)value;
-			break;
-		case ICONSOLE_VAR_INT32:
-			*(int32*)var->addr = (int32)value;
-			break;
-		default: NOT_REACHED();
-	}
-
-	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
-	IConsoleVarPrintSetValue(var);
-}
-
-/**
- * Set a new value to a string-type variable. Basically this
- * means to copy the new value over to the container.
- * @param *var the variable in question
- * @param *value the new value
- */
-static void IConsoleVarSetStringvalue(const IConsoleVar *var, const char *value)
-{
-	if (var->type != ICONSOLE_VAR_STRING || var->addr == NULL) return;
-
-	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
-	ttd_strlcpy(var->addr, value, var->size);
-	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
-	IConsoleVarPrintSetValue(var); // print out the new value, giving feedback
-	return;
-}
-
-/**
- * Query the current value of a variable and return it
- * @param *var the variable queried
- * @return current value of the variable
- */
-static uint32 IConsoleVarGetValue(const IConsoleVar *var)
-{
-	uint32 result = 0;
-
-	switch (var->type) {
-		case ICONSOLE_VAR_BOOLEAN:
-			result = *(bool*)var->addr;
-			break;
-		case ICONSOLE_VAR_BYTE:
-			result = *(byte*)var->addr;
-			break;
-		case ICONSOLE_VAR_UINT16:
-			result = *(uint16*)var->addr;
-			break;
-		case ICONSOLE_VAR_INT16:
-			result = *(int16*)var->addr;
-			break;
-		case ICONSOLE_VAR_UINT32:
-			result = *(uint32*)var->addr;
-			break;
-		case ICONSOLE_VAR_INT32:
-			result = *(int32*)var->addr;
-			break;
-		default: NOT_REACHED();
-	}
-	return result;
-}
-
-/**
- * Get the value of the variable and put it into a printable
- * string form so we can use it for printing
- */
-static char *IConsoleVarGetStringValue(const IConsoleVar *var)
-{
-	static char tempres[50];
-	char *value = tempres;
-
-	switch (var->type) {
-		case ICONSOLE_VAR_BOOLEAN:
-			snprintf(tempres, sizeof(tempres), "%s", (*(bool*)var->addr) ? "on" : "off");
-			break;
-		case ICONSOLE_VAR_BYTE:
-			snprintf(tempres, sizeof(tempres), "%u", *(byte*)var->addr);
-			break;
-		case ICONSOLE_VAR_UINT16:
-			snprintf(tempres, sizeof(tempres), "%u", *(uint16*)var->addr);
-			break;
-		case ICONSOLE_VAR_UINT32:
-			snprintf(tempres, sizeof(tempres), "%u",  *(uint32*)var->addr);
-			break;
-		case ICONSOLE_VAR_INT16:
-			snprintf(tempres, sizeof(tempres), "%i", *(int16*)var->addr);
-			break;
-		case ICONSOLE_VAR_INT32:
-			snprintf(tempres, sizeof(tempres), "%i",  *(int32*)var->addr);
-			break;
-		case ICONSOLE_VAR_STRING:
-			value = (char*)var->addr;
-			break;
-		default: NOT_REACHED();
-	}
-
-	return value;
-}
-
-/**
- * Print out the value of the variable when asked
- */
-void IConsoleVarPrintGetValue(const IConsoleVar *var)
-{
-	char *value;
-	/* Some variables need really specific handling, handle this in its
-	 * callback function */
-	if (var->proc != NULL) {
-		var->proc(0, NULL);
-		return;
-	}
-
-	value = IConsoleVarGetStringValue(var);
-	IConsolePrintF(_icolour_warn, "Current value for '%s' is:  %s", var->name, value);
-}
-
-/**
- * Print out the value of the variable after it has been assigned
- * a new value, thus giving us feedback on the action
- */
-void IConsoleVarPrintSetValue(const IConsoleVar *var)
-{
-	char *value = IConsoleVarGetStringValue(var);
-	IConsolePrintF(_icolour_warn, "'%s' changed to:  %s", var->name, value);
-}
-
-/**
- * Execute a variable command. Without any parameters, print out its value
- * with parameters it assigns a new value to the variable
- * @param *var the variable that we will be querying/changing
- * @param tokencount how many additional parameters have been given to the commandline
- * @param *token the actual parameters the variable was called with
- */
-void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[ICON_TOKEN_COUNT])
-{
-	const char *tokenptr = token[0];
-	byte t_index = tokencount;
-	uint32 value;
-
-	if (_stdlib_con_developer)
-		IConsolePrintF(_icolour_dbg, "condbg: requested command is a variable");
-
-	if (tokencount == 0) { /* Just print out value */
-		IConsoleVarPrintGetValue(var);
-		return;
-	}
-
-	/* Use of assignment sign is not mandatory but supported, so just 'ignore it appropiately' */
-	if (strcmp(tokenptr, "=") == 0) tokencount--;
-
-	if (tokencount == 1) {
-		/* Some variables need really special handling, handle it in their callback procedure */
-		if (var->proc != NULL) {
-			var->proc(tokencount, &token[t_index - tokencount]); // set the new value
-			return;
-		}
-		/* Strings need special processing. No need to convert the argument to
-		 * an integer value, just copy over the argument on a one-by-one basis */
-		if (var->type == ICONSOLE_VAR_STRING) {
-			IConsoleVarSetStringvalue(var, token[t_index - tokencount]);
-			return;
-		} else if (GetArgumentInteger(&value, token[t_index - tokencount])) {
-			IConsoleVarSetValue(var, value);
-			return;
-		}
-
-		/* Increase or decrease the value by one. This of course can only happen to 'number' types */
-		if (strcmp(tokenptr, "++") == 0 && var->type != ICONSOLE_VAR_STRING) {
-			IConsoleVarSetValue(var, IConsoleVarGetValue(var) + 1);
-			return;
-		}
-
-		if (strcmp(tokenptr, "--") == 0 && var->type != ICONSOLE_VAR_STRING) {
-			IConsoleVarSetValue(var, IConsoleVarGetValue(var) - 1);
-			return;
-		}
-	}
-
-	IConsoleError("invalid variable assignment");
-}
-
-/**
- * Add a callback function to the variable. Some variables need
- * very special processing, which can only be done with custom code
- * @param name name of the variable the callback function is added to
- * @param proc the function called
- */
-void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc)
-{
-	IConsoleVar *var = IConsoleVarGet(name);
-	if (var == NULL) return;
-	var->proc = proc;
-}
-
-/**
- * Execute a given command passed to us. First chop it up into
- * individual tokens (seperated by spaces), then execute it if possible
- * @param cmdstr string to be parsed and executed
- */
-void IConsoleCmdExec(const char *cmdstr)
-{
-	IConsoleCmd   *cmd    = NULL;
-	IConsoleAlias *alias  = NULL;
-	IConsoleVar   *var    = NULL;
-
-	const char *cmdptr;
-	char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
-	uint t_index, tstream_i;
-
-	bool longtoken = false;
-	bool foundtoken = false;
-
-	if (cmdstr[0] == '#') return; // comments
-
-	for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
-		if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
-			IConsoleError("command contains malformed characters, aborting");
-			IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
-			return;
-		}
-	}
-
-	if (_stdlib_con_developer)
-		IConsolePrintF(_icolour_dbg, "condbg: executing cmdline: '%s'", cmdstr);
-
-	memset(&tokens, 0, sizeof(tokens));
-	memset(&tokenstream, 0, sizeof(tokenstream));
-
-	/* 1. Split up commandline into tokens, seperated by spaces, commands
-	 * enclosed in "" are taken as one token. We can only go as far as the amount
-	 * of characters in our stream or the max amount of tokens we can handle */
-	for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) {
-		if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
-
-		switch (*cmdptr) {
-		case ' ': /* Token seperator */
-			if (!foundtoken) break;
-
-			if (longtoken) {
-				tokenstream[tstream_i] = *cmdptr;
-			} else {
-				tokenstream[tstream_i] = '\0';
-				foundtoken = false;
-			}
-
-			tstream_i++;
-			break;
-		case '"': /* Tokens enclosed in "" are one token */
-			longtoken = !longtoken;
-			break;
-		case '\\': /* Escape character for "" */
-			if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
-				tokenstream[tstream_i++] = *++cmdptr;
-				break;
-			}
-			/* fallthrough */
-		default: /* Normal character */
-			tokenstream[tstream_i++] = *cmdptr;
-
-			if (!foundtoken) {
-				tokens[t_index++] = &tokenstream[tstream_i - 1];
-				foundtoken = true;
-			}
-			break;
-		}
-	}
-
-	if (_stdlib_con_developer) {
-		uint i;
-
-		for (i = 0; tokens[i] != NULL; i++) {
-			IConsolePrintF(_icolour_dbg, "condbg: token %d is: '%s'", i, tokens[i]);
-		}
-	}
-
-	if (tokens[0] == '\0') return; // don't execute empty commands
-	/* 2. Determine type of command (cmd, alias or variable) and execute
-	 * First try commands, then aliases, and finally variables. Execute
-	 * the found action taking into account its hooking code
-	 */
-	cmd = IConsoleCmdGet(tokens[0]);
-	if (cmd != NULL) {
-		if (IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_ACCESS)) {
-			IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_PRE_ACTION);
-			if (cmd->proc(t_index, tokens)) { // index started with 0
-				IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_POST_ACTION);
-			} else {
-				cmd->proc(0, NULL); // if command failed, give help
-			}
-		}
-		return;
-	}
-
-	t_index--; // ignore the variable-name for comfort for both aliases and variaables
-	alias = IConsoleAliasGet(tokens[0]);
-	if (alias != NULL) {
-		IConsoleAliasExec(alias, t_index, &tokens[1]);
-		return;
-	}
-
-	var = IConsoleVarGet(tokens[0]);
-	if (var != NULL) {
-		if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS)) {
-			IConsoleVarExec(var, t_index, &tokens[1]);
-		}
-		return;
-	}
-
-	IConsoleError("command or variable not found");
-}
new file mode 100644
--- /dev/null
+++ b/src/console.cpp
@@ -0,0 +1,1150 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "player.h"
+#include "variables.h"
+#include "string.h"
+#include <stdarg.h>
+#include <string.h>
+#include "console.h"
+#include "network/network.h"
+#include "network/network_data.h"
+#include "network/network_server.h"
+
+#define ICON_BUFFER 79
+#define ICON_HISTORY_SIZE 20
+#define ICON_LINE_HEIGHT 12
+#define ICON_RIGHT_BORDERWIDTH 10
+#define ICON_BOTTOM_BORDERWIDTH 12
+#define ICON_MAX_ALIAS_LINES 40
+#define ICON_TOKEN_COUNT 20
+
+// ** main console ** //
+static char *_iconsole_buffer[ICON_BUFFER + 1];
+static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
+static Textbuf _iconsole_cmdline;
+
+// ** stdlib ** //
+byte _stdlib_developer = 1;
+bool _stdlib_con_developer = false;
+FILE *_iconsole_output_file;
+
+// ** main console cmd buffer
+static char *_iconsole_history[ICON_HISTORY_SIZE];
+static byte _iconsole_historypos;
+
+/* *************** */
+/*  end of header  */
+/* *************** */
+
+static void IConsoleClearCommand(void)
+{
+	memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
+	_iconsole_cmdline.length = 0;
+	_iconsole_cmdline.width = 0;
+	_iconsole_cmdline.caretpos = 0;
+	_iconsole_cmdline.caretxoffs = 0;
+	SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
+}
+
+static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
+
+
+static void IConsoleHistoryAdd(const char *cmd);
+static void IConsoleHistoryNavigate(int direction);
+
+// ** console window ** //
+static void IConsoleWndProc(Window *w, WindowEvent *e)
+{
+	static byte iconsole_scroll = ICON_BUFFER;
+
+	switch (e->event) {
+		case WE_PAINT: {
+			int i = iconsole_scroll;
+			int max = (w->height / ICON_LINE_HEIGHT) - 1;
+			int delta = 0;
+			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
+			while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
+				DoDrawString(_iconsole_buffer[i], 5,
+					w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
+				i--;
+			}
+			/* If the text is longer than the window, don't show the starting ']' */
+			delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
+			if (delta > 0) {
+				DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
+				delta = 0;
+			}
+
+			DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
+
+			if (_iconsole_cmdline.caret)
+				DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, 12);
+			break;
+		}
+		case WE_MOUSELOOP:
+			if (HandleCaret(&_iconsole_cmdline))
+				SetWindowDirty(w);
+			break;
+		case WE_DESTROY:
+			_iconsole_mode = ICONSOLE_CLOSED;
+			break;
+		case WE_KEYPRESS:
+			e->we.keypress.cont = false;
+			switch (e->we.keypress.keycode) {
+				case WKC_UP:
+					IConsoleHistoryNavigate(+1);
+					SetWindowDirty(w);
+					break;
+				case WKC_DOWN:
+					IConsoleHistoryNavigate(-1);
+					SetWindowDirty(w);
+					break;
+				case WKC_SHIFT | WKC_PAGEUP:
+					if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
+						iconsole_scroll = 0;
+					} else {
+						iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
+					}
+					SetWindowDirty(w);
+					break;
+				case WKC_SHIFT | WKC_PAGEDOWN:
+					if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
+						iconsole_scroll = ICON_BUFFER;
+					} else {
+						iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
+					}
+					SetWindowDirty(w);
+					break;
+				case WKC_SHIFT | WKC_UP:
+					if (iconsole_scroll <= 0) {
+						iconsole_scroll = 0;
+					} else {
+						--iconsole_scroll;
+					}
+					SetWindowDirty(w);
+					break;
+				case WKC_SHIFT | WKC_DOWN:
+					if (iconsole_scroll >= ICON_BUFFER) {
+						iconsole_scroll = ICON_BUFFER;
+					} else {
+						++iconsole_scroll;
+					}
+					SetWindowDirty(w);
+					break;
+				case WKC_BACKQUOTE:
+					IConsoleSwitch();
+					break;
+				case WKC_RETURN: case WKC_NUM_ENTER:
+					IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
+					IConsoleHistoryAdd(_iconsole_cmdline.buf);
+
+					IConsoleCmdExec(_iconsole_cmdline.buf);
+					IConsoleClearCommand();
+					break;
+				case WKC_CTRL | WKC_RETURN:
+					_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
+					IConsoleResize(w);
+					MarkWholeScreenDirty();
+					break;
+				case (WKC_CTRL | 'V'):
+					if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
+						IConsoleResetHistoryPos();
+						SetWindowDirty(w);
+					}
+					break;
+				case (WKC_CTRL | 'L'):
+					IConsoleCmdExec("clear");
+					break;
+				case (WKC_CTRL | 'U'):
+					DeleteTextBufferAll(&_iconsole_cmdline);
+					SetWindowDirty(w);
+					break;
+				case WKC_BACKSPACE: case WKC_DELETE:
+					if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
+						IConsoleResetHistoryPos();
+						SetWindowDirty(w);
+					}
+					break;
+				case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
+					if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
+						IConsoleResetHistoryPos();
+						SetWindowDirty(w);
+					}
+					break;
+				default:
+					if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
+						iconsole_scroll = ICON_BUFFER;
+						InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
+						IConsoleResetHistoryPos();
+						SetWindowDirty(w);
+					} else {
+						e->we.keypress.cont = true;
+					}
+			break;
+		}
+	}
+}
+
+static const Widget _iconsole_window_widgets[] = {
+	{WIDGETS_END}
+};
+
+static const WindowDesc _iconsole_window_desc = {
+	0, 0, 2, 2,
+	WC_CONSOLE, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_iconsole_window_widgets,
+	IConsoleWndProc,
+};
+
+void IConsoleInit(void)
+{
+	extern const char _openttd_revision[];
+	_iconsole_output_file = NULL;
+	_icolour_def  =  1;
+	_icolour_err  =  3;
+	_icolour_warn = 13;
+	_icolour_dbg  =  5;
+	_icolour_cmd  =  2;
+	_iconsole_historypos = ICON_HISTORY_SIZE - 1;
+	_iconsole_mode = ICONSOLE_CLOSED;
+
+#ifdef ENABLE_NETWORK /* Initialize network only variables */
+	_redirect_console_to_client = 0;
+#endif
+
+	memset(_iconsole_history, 0, sizeof(_iconsole_history));
+	memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
+	memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
+	_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
+	_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE;
+
+	IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
+	IConsolePrint(12,  "------------------------------------");
+	IConsolePrint(12,  "use \"help\" for more information");
+	IConsolePrint(12,  "");
+	IConsoleStdLibRegister();
+	IConsoleClearCommand();
+	IConsoleHistoryAdd("");
+}
+
+void IConsoleClearBuffer(void)
+{
+	uint i;
+	for (i = 0; i <= ICON_BUFFER; i++) {
+		free(_iconsole_buffer[i]);
+		_iconsole_buffer[i] = NULL;
+	}
+}
+
+static void IConsoleClear(void)
+{
+	free(_iconsole_cmdline.buf);
+	IConsoleClearBuffer();
+}
+
+static void IConsoleWriteToLogFile(const char *string)
+{
+	if (_iconsole_output_file != NULL) {
+		// if there is an console output file ... also print it there
+		fwrite(string, strlen(string), 1, _iconsole_output_file);
+		fwrite("\n", 1, 1, _iconsole_output_file);
+	}
+}
+
+bool CloseConsoleLogIfActive(void)
+{
+	if (_iconsole_output_file != NULL) {
+		IConsolePrintF(_icolour_def, "file output complete");
+		fclose(_iconsole_output_file);
+		_iconsole_output_file = NULL;
+		return true;
+	}
+
+	return false;
+}
+
+void IConsoleFree(void)
+{
+	IConsoleClear();
+	CloseConsoleLogIfActive();
+}
+
+void IConsoleResize(Window *w)
+{
+	switch (_iconsole_mode) {
+		case ICONSOLE_OPENED:
+			w->height = _screen.height / 3;
+			w->width = _screen.width;
+			break;
+		case ICONSOLE_FULL:
+			w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
+			w->width = _screen.width;
+			break;
+		default: return;
+	}
+
+	MarkWholeScreenDirty();
+}
+
+void IConsoleSwitch(void)
+{
+	switch (_iconsole_mode) {
+		case ICONSOLE_CLOSED: {
+			Window *w = AllocateWindowDesc(&_iconsole_window_desc);
+			w->height = _screen.height / 3;
+			w->width = _screen.width;
+			_iconsole_mode = ICONSOLE_OPENED;
+			SETBIT(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
+		} break;
+		case ICONSOLE_OPENED: case ICONSOLE_FULL:
+			DeleteWindowById(WC_CONSOLE, 0);
+			_iconsole_mode = ICONSOLE_CLOSED;
+			CLRBIT(_no_scroll, SCROLL_CON);
+			break;
+	}
+
+	MarkWholeScreenDirty();
+}
+
+void IConsoleClose(void) {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
+void IConsoleOpen(void)  {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
+
+/**
+ * Add the entered line into the history so you can look it back
+ * scroll, etc. Put it to the beginning as it is the latest text
+ * @param cmd Text to be entered into the 'history'
+ */
+static void IConsoleHistoryAdd(const char *cmd)
+{
+	free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
+
+	memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
+	_iconsole_history[0] = strdup(cmd);
+	IConsoleResetHistoryPos();
+}
+
+/**
+ * Navigate Up/Down in the history of typed commands
+ * @param direction Go further back in history (+1), go to recently typed commands (-1)
+ */
+static void IConsoleHistoryNavigate(int direction)
+{
+	int i = _iconsole_historypos + direction;
+
+	// watch out for overflows, just wrap around
+	if (i < 0) i = ICON_HISTORY_SIZE - 1;
+	if (i >= ICON_HISTORY_SIZE) i = 0;
+
+	if (direction > 0)
+		if (_iconsole_history[i] == NULL) i = 0;
+
+	if (direction < 0) {
+		while (i > 0 && _iconsole_history[i] == NULL) i--;
+	}
+
+	_iconsole_historypos = i;
+	IConsoleClearCommand();
+	// copy history to 'command prompt / bash'
+	assert(_iconsole_history[i] != NULL && IS_INT_INSIDE(i, 0, ICON_HISTORY_SIZE));
+	ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength);
+	UpdateTextBufferSize(&_iconsole_cmdline);
+}
+
+/**
+ * Handle the printing of text entered into the console or redirected there
+ * by any other means. Text can be redirected to other players in a network game
+ * as well as to a logfile. If the network server is a dedicated server, all activities
+ * are also logged. All lines to print are added to a temporary buffer which can be
+ * used as a history to print them onscreen
+ * @param color_code the colour of the command. Red in case of errors, etc.
+ * @param string the message entered or output on the console (notice, error, etc.)
+ */
+void IConsolePrint(uint16 color_code, const char *string)
+{
+	char *str;
+#ifdef ENABLE_NETWORK
+	if (_redirect_console_to_client != 0) {
+		/* Redirect the string to the client */
+		SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(_redirect_console_to_client), color_code, string);
+		return;
+	}
+#endif
+
+	/* Create a copy of the string, strip if of colours and invalid
+	 * characters and (when applicable) assign it to the console buffer */
+	str = strdup(string);
+	str_strip_colours(str);
+	str_validate(str);
+
+	if (_network_dedicated) {
+		printf("%s\n", str);
+		IConsoleWriteToLogFile(str);
+		free(str); // free duplicated string since it's not used anymore
+		return;
+	}
+
+	/* move up all the strings in the buffer one place and do the same for colour
+	 * to accomodate for the new command/message */
+	free(_iconsole_buffer[0]);
+	memmove(&_iconsole_buffer[0], &_iconsole_buffer[1], sizeof(_iconsole_buffer[0]) * ICON_BUFFER);
+	_iconsole_buffer[ICON_BUFFER] = str;
+
+	memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER);
+	_iconsole_cbuffer[ICON_BUFFER] = color_code;
+
+	IConsoleWriteToLogFile(_iconsole_buffer[ICON_BUFFER]);
+
+	SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
+}
+
+/**
+ * Handle the printing of text entered into the console or redirected there
+ * by any other means. Uses printf() style format, for more information look
+ * at @IConsolePrint()
+ */
+void CDECL IConsolePrintF(uint16 color_code, const char *s, ...)
+{
+	va_list va;
+	char buf[ICON_MAX_STREAMSIZE];
+
+	va_start(va, s);
+	vsnprintf(buf, sizeof(buf), s, va);
+	va_end(va);
+
+	IConsolePrint(color_code, buf);
+}
+
+/**
+ * It is possible to print debugging information to the console,
+ * which is achieved by using this function. Can only be used by
+ * @debug() in debug.c. You need at least a level 2 (developer) for debugging
+ * messages to show up
+ * @param dbg debugging category
+ * @param string debugging message
+ */
+void IConsoleDebug(const char *dbg, const char *string)
+{
+	if (_stdlib_developer > 1)
+		IConsolePrintF(_icolour_dbg, "dbg: [%s] %s", dbg, string);
+}
+
+/**
+ * It is possible to print warnings to the console. These are mostly
+ * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for
+ * debugging messages to show up
+ */
+void IConsoleWarning(const char *string)
+{
+	if (_stdlib_developer > 0)
+		IConsolePrintF(_icolour_warn, "WARNING: %s", string);
+}
+
+/**
+ * It is possible to print error information to the console. This can include
+ * game errors, or errors in general you would want the user to notice
+ */
+void IConsoleError(const char *string)
+{
+	IConsolePrintF(_icolour_err, "ERROR: %s", string);
+}
+
+/**
+ * Change a string into its number representation. Supports
+ * decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false'
+ * @param *value the variable a successfull conversion will be put in
+ * @param *arg the string to be converted
+ * @return Return true on success or false on failure
+ */
+bool GetArgumentInteger(uint32 *value, const char *arg)
+{
+	char *endptr;
+
+	if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) {
+		*value = 1;
+		return true;
+	}
+	if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) {
+		*value = 0;
+		return true;
+	}
+
+	*value = strtoul(arg, &endptr, 0);
+	return arg != endptr;
+}
+
+// * ************************* * //
+// * hooking code              * //
+// * ************************* * //
+/**
+ * General internal hooking code that is the same for both commands and variables
+ * @param hooks @IConsoleHooks structure that will be set according to
+ * @param type type access trigger
+ * @param proc function called when the hook criteria is met
+ */
+static void IConsoleHookAdd(IConsoleHooks *hooks, IConsoleHookTypes type, IConsoleHook *proc)
+{
+	if (hooks == NULL || proc == NULL) return;
+
+	switch (type) {
+		case ICONSOLE_HOOK_ACCESS:
+			hooks->access = proc;
+			break;
+		case ICONSOLE_HOOK_PRE_ACTION:
+			hooks->pre = proc;
+			break;
+		case ICONSOLE_HOOK_POST_ACTION:
+			hooks->post = proc;
+			break;
+		default: NOT_REACHED();
+	}
+}
+
+/**
+ * Handle any special hook triggers. If the hook type is met check if
+ * there is a function associated with that and if so, execute it
+ * @param hooks @IConsoleHooks structure that will be checked
+ * @param type type of hook, trigger that needs to be activated
+ * @return true on a successfull execution of the hook command or if there
+ * is no hook/trigger present at all. False otherwise
+ */
+static bool IConsoleHookHandle(const IConsoleHooks *hooks, IConsoleHookTypes type)
+{
+	IConsoleHook *proc = NULL;
+	if (hooks == NULL) return false;
+
+	switch (type) {
+		case ICONSOLE_HOOK_ACCESS:
+			proc = hooks->access;
+			break;
+		case ICONSOLE_HOOK_PRE_ACTION:
+			proc = hooks->pre;
+			break;
+		case ICONSOLE_HOOK_POST_ACTION:
+			proc = hooks->post;
+			break;
+		default: NOT_REACHED();
+	}
+
+	return (proc == NULL) ? true : proc();
+}
+
+/**
+ * Add a hook to a command that will be triggered at certain points
+ * @param name name of the command that the hook is added to
+ * @param type type of hook that is added (ACCESS, BEFORE and AFTER change)
+ * @param proc function called when the hook criteria is met
+ */
+void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
+{
+	IConsoleCmd *cmd = IConsoleCmdGet(name);
+	if (cmd == NULL) return;
+	IConsoleHookAdd(&cmd->hook, type, proc);
+}
+
+/**
+ * Add a hook to a variable that will be triggered at certain points
+ * @param name name of the variable that the hook is added to
+ * @param type type of hook that is added (ACCESS, BEFORE and AFTER change)
+ * @param proc function called when the hook criteria is met
+ */
+void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc)
+{
+	IConsoleVar *var = IConsoleVarGet(name);
+	if (var == NULL) return;
+	IConsoleHookAdd(&var->hook, type, proc);
+}
+
+/**
+ * Perhaps ugly macro, but this saves us the trouble of writing the same function
+ * three types, just with different variables. Yes, templates would be handy. It was
+ * either this define or an even more ugly void* magic function
+ */
+#define IConsoleAddSorted(_base, item_new, IConsoleType, type)                 \
+{                                                                              \
+	IConsoleType *item, *item_before;                                            \
+	/* first command */                                                          \
+	if (_base == NULL) {                                                         \
+		_base = item_new;                                                          \
+		return;                                                                    \
+	}                                                                            \
+                                                                               \
+	item_before = NULL;                                                          \
+	item = _base;                                                                \
+                                                                               \
+	/* BEGIN - Alphabetically insert the commands into the linked list */        \
+	while (item != NULL) {                                                       \
+		int i = strcmp(item->name, item_new->name);                                \
+		if (i == 0) {                                                              \
+			IConsoleError(type " with this name already exists; insertion aborted"); \
+			free(item_new);                                                          \
+			return;                                                                  \
+		}                                                                          \
+                                                                               \
+		if (i > 0) break; /* insert at this position */                            \
+                                                                               \
+		item_before = item;                                                        \
+		item = item->next;                                                         \
+	}                                                                            \
+                                                                               \
+	if (item_before == NULL) {                                                   \
+		_base = item_new;                                                          \
+	} else {                                                                     \
+		item_before->next = item_new;                                              \
+  }                                                                            \
+                                                                               \
+	item_new->next = item;                                                       \
+	/* END - Alphabetical insert */                                              \
+}
+
+/**
+ * Register a new command to be used in the console
+ * @param name name of the command that will be used
+ * @param proc function that will be called upon execution of command
+ */
+void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc)
+{
+	char *new_cmd = strdup(name);
+	IConsoleCmd *item_new = malloc(sizeof(IConsoleCmd));
+
+	item_new->next = NULL;
+	item_new->proc = proc;
+	item_new->name = new_cmd;
+
+	item_new->hook.access = NULL;
+	item_new->hook.pre = NULL;
+	item_new->hook.post = NULL;
+
+	IConsoleAddSorted(_iconsole_cmds, item_new, IConsoleCmd, "a command");
+}
+
+/**
+ * Find the command pointed to by its string
+ * @param name command to be found
+ * @return return Cmdstruct of the found command, or NULL on failure
+ */
+IConsoleCmd *IConsoleCmdGet(const char *name)
+{
+	IConsoleCmd *item;
+
+	for (item = _iconsole_cmds; item != NULL; item = item->next) {
+		if (strcmp(item->name, name) == 0) return item;
+	}
+	return NULL;
+}
+
+/**
+ * Register a an alias for an already existing command in the console
+ * @param name name of the alias that will be used
+ * @param cmd name of the command that 'name' will be alias of
+ */
+void IConsoleAliasRegister(const char *name, const char *cmd)
+{
+	char *new_alias = strdup(name);
+	char *cmd_aliased = strdup(cmd);
+	IConsoleAlias *item_new = malloc(sizeof(IConsoleAlias));
+
+	item_new->next = NULL;
+	item_new->cmdline = cmd_aliased;
+	item_new->name = new_alias;
+
+	IConsoleAddSorted(_iconsole_aliases, item_new, IConsoleAlias, "an alias");
+}
+
+/**
+ * Find the alias pointed to by its string
+ * @param name alias to be found
+ * @return return Aliasstruct of the found alias, or NULL on failure
+ */
+IConsoleAlias *IConsoleAliasGet(const char *name)
+{
+	IConsoleAlias* item;
+
+	for (item = _iconsole_aliases; item != NULL; item = item->next) {
+		if (strcmp(item->name, name) == 0) return item;
+	}
+
+	return NULL;
+}
+
+/** copy in an argument into the aliasstream */
+static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
+{
+	int len = min(ICON_MAX_STREAMSIZE - bufpos, (uint)strlen(src));
+	strncpy(dst, src, len);
+
+	return len;
+}
+
+/**
+ * An alias is just another name for a command, or for more commands
+ * Execute it as well.
+ * @param *alias is the alias of the command
+ * @param tokencount the number of parameters passed
+ * @param *tokens are the parameters given to the original command (0 is the first param)
+ */
+static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
+{
+	const char *cmdptr;
+	char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
+	uint i;
+	uint a_index, astream_i;
+
+	memset(&aliases, 0, sizeof(aliases));
+	memset(&aliasstream, 0, sizeof(aliasstream));
+
+	if (_stdlib_con_developer)
+		IConsolePrintF(_icolour_dbg, "condbg: requested command is an alias; parsing...");
+
+	aliases[0] = aliasstream;
+	for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
+		if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
+
+		switch (*cmdptr) {
+		case '\'': /* ' will double for "" */
+			aliasstream[astream_i++] = '"';
+			break;
+		case ';': /* Cmd seperator, start new command */
+			aliasstream[astream_i] = '\0';
+			aliases[++a_index] = &aliasstream[++astream_i];
+			cmdptr++;
+			break;
+		case '%': /* Some or all parameters */
+			cmdptr++;
+			switch (*cmdptr) {
+			case '+': { /* All parameters seperated: "[param 1]" "[param 2]" */
+				for (i = 0; i != tokencount; i++) {
+					aliasstream[astream_i++] = '"';
+					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
+					aliasstream[astream_i++] = '"';
+					aliasstream[astream_i++] = ' ';
+				}
+			} break;
+			case '!': { /* Merge the parameters to one: "[param 1] [param 2] [param 3...]" */
+				aliasstream[astream_i++] = '"';
+				for (i = 0; i != tokencount; i++) {
+					astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
+					aliasstream[astream_i++] = ' ';
+				}
+				aliasstream[astream_i++] = '"';
+
+			} break;
+				default: { /* One specific parameter: %A = [param 1] %B = [param 2] ... */
+				int param = *cmdptr - 'A';
+
+				if (param < 0 || param >= tokencount) {
+					IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
+					IConsolePrintF(_icolour_warn, "Usage of alias '%s': %s", alias->name, alias->cmdline);
+					return;
+				}
+
+				aliasstream[astream_i++] = '"';
+				astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i);
+				aliasstream[astream_i++] = '"';
+			} break;
+			} break;
+
+		default:
+			aliasstream[astream_i++] = *cmdptr;
+			break;
+		}
+	}
+
+	for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn
+}
+
+/**
+ * Special function for adding string-type variables. They in addition
+ * also need a 'size' value saying how long their string buffer is.
+ * @param size the length of the string buffer
+ * For more information see @IConsoleVarRegister()
+ */
+void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help)
+{
+	IConsoleVar *var;
+	IConsoleVarRegister(name, addr, ICONSOLE_VAR_STRING, help);
+	var = IConsoleVarGet(name);
+	var->size = size;
+}
+
+/**
+ * Register a new variable to be used in the console
+ * @param name name of the variable that will be used
+ * @param addr memory location the variable will point to
+ * @param help the help string shown for the variable
+ * @param type the type of the variable (simple atomic) so we know which values it can get
+ */
+void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help)
+{
+	char *new_cmd = strdup(name);
+	IConsoleVar *item_new = malloc(sizeof(IConsoleVar));
+
+	item_new->help = (help != NULL) ? strdup(help) : NULL;
+
+	item_new->next = NULL;
+	item_new->name = new_cmd;
+	item_new->addr = addr;
+	item_new->proc = NULL;
+	item_new->type = type;
+
+	item_new->hook.access = NULL;
+	item_new->hook.pre = NULL;
+	item_new->hook.post = NULL;
+
+	IConsoleAddSorted(_iconsole_vars, item_new, IConsoleVar, "a variable");
+}
+
+/**
+ * Find the variable pointed to by its string
+ * @param name variable to be found
+ * @return return Varstruct of the found variable, or NULL on failure
+ */
+IConsoleVar *IConsoleVarGet(const char *name)
+{
+	IConsoleVar *item;
+	for (item = _iconsole_vars; item != NULL; item = item->next) {
+		if (strcmp(item->name, name) == 0) return item;
+	}
+
+	return NULL;
+}
+
+/**
+ * Set a new value to a console variable
+ * @param *var the variable being set/changed
+ * @param value the new value given to the variable, cast properly
+ */
+static void IConsoleVarSetValue(const IConsoleVar *var, uint32 value)
+{
+	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
+	switch (var->type) {
+		case ICONSOLE_VAR_BOOLEAN:
+			*(bool*)var->addr = (value != 0);
+			break;
+		case ICONSOLE_VAR_BYTE:
+			*(byte*)var->addr = (byte)value;
+			break;
+		case ICONSOLE_VAR_UINT16:
+			*(uint16*)var->addr = (uint16)value;
+			break;
+		case ICONSOLE_VAR_INT16:
+			*(int16*)var->addr = (int16)value;
+			break;
+		case ICONSOLE_VAR_UINT32:
+			*(uint32*)var->addr = (uint32)value;
+			break;
+		case ICONSOLE_VAR_INT32:
+			*(int32*)var->addr = (int32)value;
+			break;
+		default: NOT_REACHED();
+	}
+
+	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
+	IConsoleVarPrintSetValue(var);
+}
+
+/**
+ * Set a new value to a string-type variable. Basically this
+ * means to copy the new value over to the container.
+ * @param *var the variable in question
+ * @param *value the new value
+ */
+static void IConsoleVarSetStringvalue(const IConsoleVar *var, const char *value)
+{
+	if (var->type != ICONSOLE_VAR_STRING || var->addr == NULL) return;
+
+	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
+	ttd_strlcpy(var->addr, value, var->size);
+	IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
+	IConsoleVarPrintSetValue(var); // print out the new value, giving feedback
+	return;
+}
+
+/**
+ * Query the current value of a variable and return it
+ * @param *var the variable queried
+ * @return current value of the variable
+ */
+static uint32 IConsoleVarGetValue(const IConsoleVar *var)
+{
+	uint32 result = 0;
+
+	switch (var->type) {
+		case ICONSOLE_VAR_BOOLEAN:
+			result = *(bool*)var->addr;
+			break;
+		case ICONSOLE_VAR_BYTE:
+			result = *(byte*)var->addr;
+			break;
+		case ICONSOLE_VAR_UINT16:
+			result = *(uint16*)var->addr;
+			break;
+		case ICONSOLE_VAR_INT16:
+			result = *(int16*)var->addr;
+			break;
+		case ICONSOLE_VAR_UINT32:
+			result = *(uint32*)var->addr;
+			break;
+		case ICONSOLE_VAR_INT32:
+			result = *(int32*)var->addr;
+			break;
+		default: NOT_REACHED();
+	}
+	return result;
+}
+
+/**
+ * Get the value of the variable and put it into a printable
+ * string form so we can use it for printing
+ */
+static char *IConsoleVarGetStringValue(const IConsoleVar *var)
+{
+	static char tempres[50];
+	char *value = tempres;
+
+	switch (var->type) {
+		case ICONSOLE_VAR_BOOLEAN:
+			snprintf(tempres, sizeof(tempres), "%s", (*(bool*)var->addr) ? "on" : "off");
+			break;
+		case ICONSOLE_VAR_BYTE:
+			snprintf(tempres, sizeof(tempres), "%u", *(byte*)var->addr);
+			break;
+		case ICONSOLE_VAR_UINT16:
+			snprintf(tempres, sizeof(tempres), "%u", *(uint16*)var->addr);
+			break;
+		case ICONSOLE_VAR_UINT32:
+			snprintf(tempres, sizeof(tempres), "%u",  *(uint32*)var->addr);
+			break;
+		case ICONSOLE_VAR_INT16:
+			snprintf(tempres, sizeof(tempres), "%i", *(int16*)var->addr);
+			break;
+		case ICONSOLE_VAR_INT32:
+			snprintf(tempres, sizeof(tempres), "%i",  *(int32*)var->addr);
+			break;
+		case ICONSOLE_VAR_STRING:
+			value = (char*)var->addr;
+			break;
+		default: NOT_REACHED();
+	}
+
+	return value;
+}
+
+/**
+ * Print out the value of the variable when asked
+ */
+void IConsoleVarPrintGetValue(const IConsoleVar *var)
+{
+	char *value;
+	/* Some variables need really specific handling, handle this in its
+	 * callback function */
+	if (var->proc != NULL) {
+		var->proc(0, NULL);
+		return;
+	}
+
+	value = IConsoleVarGetStringValue(var);
+	IConsolePrintF(_icolour_warn, "Current value for '%s' is:  %s", var->name, value);
+}
+
+/**
+ * Print out the value of the variable after it has been assigned
+ * a new value, thus giving us feedback on the action
+ */
+void IConsoleVarPrintSetValue(const IConsoleVar *var)
+{
+	char *value = IConsoleVarGetStringValue(var);
+	IConsolePrintF(_icolour_warn, "'%s' changed to:  %s", var->name, value);
+}
+
+/**
+ * Execute a variable command. Without any parameters, print out its value
+ * with parameters it assigns a new value to the variable
+ * @param *var the variable that we will be querying/changing
+ * @param tokencount how many additional parameters have been given to the commandline
+ * @param *token the actual parameters the variable was called with
+ */
+void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[ICON_TOKEN_COUNT])
+{
+	const char *tokenptr = token[0];
+	byte t_index = tokencount;
+	uint32 value;
+
+	if (_stdlib_con_developer)
+		IConsolePrintF(_icolour_dbg, "condbg: requested command is a variable");
+
+	if (tokencount == 0) { /* Just print out value */
+		IConsoleVarPrintGetValue(var);
+		return;
+	}
+
+	/* Use of assignment sign is not mandatory but supported, so just 'ignore it appropiately' */
+	if (strcmp(tokenptr, "=") == 0) tokencount--;
+
+	if (tokencount == 1) {
+		/* Some variables need really special handling, handle it in their callback procedure */
+		if (var->proc != NULL) {
+			var->proc(tokencount, &token[t_index - tokencount]); // set the new value
+			return;
+		}
+		/* Strings need special processing. No need to convert the argument to
+		 * an integer value, just copy over the argument on a one-by-one basis */
+		if (var->type == ICONSOLE_VAR_STRING) {
+			IConsoleVarSetStringvalue(var, token[t_index - tokencount]);
+			return;
+		} else if (GetArgumentInteger(&value, token[t_index - tokencount])) {
+			IConsoleVarSetValue(var, value);
+			return;
+		}
+
+		/* Increase or decrease the value by one. This of course can only happen to 'number' types */
+		if (strcmp(tokenptr, "++") == 0 && var->type != ICONSOLE_VAR_STRING) {
+			IConsoleVarSetValue(var, IConsoleVarGetValue(var) + 1);
+			return;
+		}
+
+		if (strcmp(tokenptr, "--") == 0 && var->type != ICONSOLE_VAR_STRING) {
+			IConsoleVarSetValue(var, IConsoleVarGetValue(var) - 1);
+			return;
+		}
+	}
+
+	IConsoleError("invalid variable assignment");
+}
+
+/**
+ * Add a callback function to the variable. Some variables need
+ * very special processing, which can only be done with custom code
+ * @param name name of the variable the callback function is added to
+ * @param proc the function called
+ */
+void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc)
+{
+	IConsoleVar *var = IConsoleVarGet(name);
+	if (var == NULL) return;
+	var->proc = proc;
+}
+
+/**
+ * Execute a given command passed to us. First chop it up into
+ * individual tokens (seperated by spaces), then execute it if possible
+ * @param cmdstr string to be parsed and executed
+ */
+void IConsoleCmdExec(const char *cmdstr)
+{
+	IConsoleCmd   *cmd    = NULL;
+	IConsoleAlias *alias  = NULL;
+	IConsoleVar   *var    = NULL;
+
+	const char *cmdptr;
+	char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
+	uint t_index, tstream_i;
+
+	bool longtoken = false;
+	bool foundtoken = false;
+
+	if (cmdstr[0] == '#') return; // comments
+
+	for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
+		if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
+			IConsoleError("command contains malformed characters, aborting");
+			IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
+			return;
+		}
+	}
+
+	if (_stdlib_con_developer)
+		IConsolePrintF(_icolour_dbg, "condbg: executing cmdline: '%s'", cmdstr);
+
+	memset(&tokens, 0, sizeof(tokens));
+	memset(&tokenstream, 0, sizeof(tokenstream));
+
+	/* 1. Split up commandline into tokens, seperated by spaces, commands
+	 * enclosed in "" are taken as one token. We can only go as far as the amount
+	 * of characters in our stream or the max amount of tokens we can handle */
+	for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) {
+		if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
+
+		switch (*cmdptr) {
+		case ' ': /* Token seperator */
+			if (!foundtoken) break;
+
+			if (longtoken) {
+				tokenstream[tstream_i] = *cmdptr;
+			} else {
+				tokenstream[tstream_i] = '\0';
+				foundtoken = false;
+			}
+
+			tstream_i++;
+			break;
+		case '"': /* Tokens enclosed in "" are one token */
+			longtoken = !longtoken;
+			break;
+		case '\\': /* Escape character for "" */
+			if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
+				tokenstream[tstream_i++] = *++cmdptr;
+				break;
+			}
+			/* fallthrough */
+		default: /* Normal character */
+			tokenstream[tstream_i++] = *cmdptr;
+
+			if (!foundtoken) {
+				tokens[t_index++] = &tokenstream[tstream_i - 1];
+				foundtoken = true;
+			}
+			break;
+		}
+	}
+
+	if (_stdlib_con_developer) {
+		uint i;
+
+		for (i = 0; tokens[i] != NULL; i++) {
+			IConsolePrintF(_icolour_dbg, "condbg: token %d is: '%s'", i, tokens[i]);
+		}
+	}
+
+	if (tokens[0] == '\0') return; // don't execute empty commands
+	/* 2. Determine type of command (cmd, alias or variable) and execute
+	 * First try commands, then aliases, and finally variables. Execute
+	 * the found action taking into account its hooking code
+	 */
+	cmd = IConsoleCmdGet(tokens[0]);
+	if (cmd != NULL) {
+		if (IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_ACCESS)) {
+			IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_PRE_ACTION);
+			if (cmd->proc(t_index, tokens)) { // index started with 0
+				IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_POST_ACTION);
+			} else {
+				cmd->proc(0, NULL); // if command failed, give help
+			}
+		}
+		return;
+	}
+
+	t_index--; // ignore the variable-name for comfort for both aliases and variaables
+	alias = IConsoleAliasGet(tokens[0]);
+	if (alias != NULL) {
+		IConsoleAliasExec(alias, t_index, &tokens[1]);
+		return;
+	}
+
+	var = IConsoleVarGet(tokens[0]);
+	if (var != NULL) {
+		if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS)) {
+			IConsoleVarExec(var, t_index, &tokens[1]);
+		}
+		return;
+	}
+
+	IConsoleError("command or variable not found");
+}
deleted file mode 100644
--- a/src/console_cmds.c
+++ /dev/null
@@ -1,1622 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "console.h"
-#include "debug.h"
-#include "engine.h"
-#include "functions.h"
-#include "saveload.h"
-#include "string.h"
-#include "variables.h"
-#include "network/network_data.h"
-#include "network/network_client.h"
-#include "network/network_server.h"
-#include "network/network_udp.h"
-#include "command.h"
-#include "settings.h"
-#include "fios.h"
-#include "vehicle.h"
-#include "station.h"
-#include "strings.h"
-#include "screenshot.h"
-#include "genworld.h"
-#include "date.h"
-#include "network/network.h"
-
-// ** scriptfile handling ** //
-static FILE *_script_file;
-static bool _script_running;
-
-// ** console command / variable defines ** //
-#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
-#define DEF_CONSOLE_HOOK(function) static bool function(void)
-
-
-/* **************************** */
-/* variable and command hooks   */
-/* **************************** */
-
-#ifdef ENABLE_NETWORK
-
-static inline bool NetworkAvailable(void)
-{
-	if (!_network_available) {
-		IConsoleError("You cannot use this command because there is no network available.");
-		return false;
-	}
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerOnly)
-{
-	if (!NetworkAvailable()) return false;
-
-	if (!_network_server) {
-		IConsoleError("This command/variable is only available to a network server.");
-		return false;
-	}
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookClientOnly)
-{
-	if (!NetworkAvailable()) return false;
-
-	if (_network_server) {
-		IConsoleError("This command/variable is not available to a network server.");
-		return false;
-	}
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookNeedNetwork)
-{
-	if (!NetworkAvailable()) return false;
-
-	if (!_networking) {
-		IConsoleError("Not connected. This command/variable is only available in multiplayer.");
-		return false;
-	}
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookNoNetwork)
-{
-	if (_networking) {
-		IConsoleError("This command/variable is forbidden in multiplayer.");
-		return false;
-	}
-	return true;
-}
-
-#endif /* ENABLE_NETWORK */
-
-static void IConsoleHelp(const char *str)
-{
-	IConsolePrintF(_icolour_warn, "- %s", str);
-}
-
-DEF_CONSOLE_CMD(ConResetEngines)
-{
-	if (argc == 0) {
-		IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'");
-		return true;
-	}
-
-	StartupEngines();
-	return true;
-}
-
-#ifdef _DEBUG
-DEF_CONSOLE_CMD(ConResetTile)
-{
-	if (argc == 0) {
-		IConsoleHelp("Reset a tile to bare land. Usage: 'resettile <tile>'");
-		IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
-		return true;
-	}
-
-	if (argc == 2) {
-		uint32 result;
-		if (GetArgumentInteger(&result, argv[1])) {
-			DoClearSquare((TileIndex)result);
-			return true;
-		}
-	}
-
-	return false;
-}
-
-DEF_CONSOLE_CMD(ConStopAllVehicles)
-{
-	Vehicle* v;
-	if (argc == 0) {
-		IConsoleHelp("Stops all vehicles in the game. For debugging only! Use at your own risk... Usage: 'stopall'");
-		return true;
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		/* Code ripped from CmdStartStopTrain. Can't call it, because of
-		 * ownership problems, so we'll duplicate some code, for now */
-		if (v->type == VEH_Train)
-			v->u.rail.days_since_order_progr = 0;
-		v->vehstatus |= VS_STOPPED;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-	}
-	return true;
-}
-#endif /* _DEBUG */
-
-DEF_CONSOLE_CMD(ConScrollToTile)
-{
-	if (argc == 0) {
-		IConsoleHelp("Center the screen on a given tile. Usage: 'scrollto <tile>'");
-		IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
-		return true;
-	}
-
-	if (argc == 2) {
-		uint32 result;
-		if (GetArgumentInteger(&result, argv[1])) {
-			if (result >= MapSize()) {
-				IConsolePrint(_icolour_err, "Tile does not exist");
-				return true;
-			}
-			ScrollMainWindowToTile((TileIndex)result);
-			return true;
-		}
-	}
-
-	return false;
-}
-
-extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
-extern void BuildFileList(void);
-extern void SetFiosType(const byte fiostype);
-
-/* Save the map to a file */
-DEF_CONSOLE_CMD(ConSave)
-{
-	if (argc == 0) {
-		IConsoleHelp("Save the current game. Usage: 'save <filename>'");
-		return true;
-	}
-
-	if (argc == 2) {
-		char buf[200];
-
-		snprintf(buf, lengthof(buf), "%s%s%s.sav", _paths.save_dir, PATHSEP, argv[1]);
-		IConsolePrint(_icolour_def, "Saving map...");
-
-		if (SaveOrLoad(buf, SL_SAVE) != SL_OK) {
-			IConsolePrint(_icolour_err, "SaveMap failed");
-		} else {
-			IConsolePrintF(_icolour_def, "Map sucessfully saved to %s", buf);
-		}
-		return true;
-	}
-
-	return false;
-}
-
-/* Explicitly save the configuration */
-DEF_CONSOLE_CMD(ConSaveConfig)
-{
-	if (argc == 0) {
-		IConsoleHelp("Saves the current config, typically to 'openttd.cfg'.");
-		return true;
-	}
-
-	SaveToConfig();
-	IConsolePrint(_icolour_def, "Saved config.");
-	return true;
-}
-
-static const FiosItem* GetFiosItem(const char* file)
-{
-	int i;
-
-	_saveload_mode = SLD_LOAD_GAME;
-	BuildFileList();
-
-	for (i = 0; i < _fios_num; i++) {
-		if (strcmp(file, _fios_list[i].name) == 0) break;
-		if (strcmp(file, _fios_list[i].title) == 0) break;
-	}
-
-	if (i == _fios_num) { /* If no name matches, try to parse it as number */
-		char* endptr;
-
-		i = strtol(file, &endptr, 10);
-		if (file == endptr || *endptr != '\0') i = -1;
-	}
-
-	return IS_INT_INSIDE(i, 0, _fios_num) ? &_fios_list[i] : NULL;
-}
-
-
-DEF_CONSOLE_CMD(ConLoad)
-{
-	const FiosItem *item;
-	const char *file;
-
-	if (argc == 0) {
-		IConsoleHelp("Load a game by name or index. Usage: 'load <file | number>'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	file = argv[1];
-	item = GetFiosItem(file);
-	if (item != NULL) {
-		switch (item->type) {
-			case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: {
-				_switch_mode = SM_LOAD;
-				SetFiosType(item->type);
-
-				ttd_strlcpy(_file_to_saveload.name, FiosBrowseTo(item), sizeof(_file_to_saveload.name));
-				ttd_strlcpy(_file_to_saveload.title, item->title, sizeof(_file_to_saveload.title));
-			} break;
-			default: IConsolePrintF(_icolour_err, "%s: Not a savegame.", file);
-		}
-	} else {
-		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
-	}
-
-	FiosFreeSavegameList();
-	return true;
-}
-
-
-DEF_CONSOLE_CMD(ConRemove)
-{
-	const FiosItem* item;
-	const char* file;
-
-	if (argc == 0) {
-		IConsoleHelp("Remove a savegame by name or index. Usage: 'rm <file | number>'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	file = argv[1];
-	item = GetFiosItem(file);
-	if (item != NULL) {
-		if (!FiosDelete(item->name))
-			IConsolePrintF(_icolour_err, "%s: Failed to delete file", file);
-	} else {
-		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
-	}
-
-	FiosFreeSavegameList();
-	return true;
-}
-
-
-/* List all the files in the current dir via console */
-DEF_CONSOLE_CMD(ConListFiles)
-{
-	int i;
-
-	if (argc == 0) {
-		IConsoleHelp("List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'");
-		return true;
-	}
-
-	BuildFileList();
-
-	for (i = 0; i < _fios_num; i++) {
-		const FiosItem *item = &_fios_list[i];
-		IConsolePrintF(_icolour_def, "%d) %s", i, item->title);
-	}
-
-	FiosFreeSavegameList();
-	return true;
-}
-
-/* Change the dir via console */
-DEF_CONSOLE_CMD(ConChangeDirectory)
-{
-	const FiosItem *item;
-	const char *file;
-
-	if (argc == 0) {
-		IConsoleHelp("Change the dir via console. Usage: 'cd <directory | number>'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	file = argv[1];
-	item = GetFiosItem(file);
-	if (item != NULL) {
-		switch (item->type) {
-			case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
-				FiosBrowseTo(item);
-				break;
-			default: IConsolePrintF(_icolour_err, "%s: Not a directory.", file);
-		}
-	} else {
-		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
-	}
-
-	FiosFreeSavegameList();
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
-{
-	const char *path;
-
-	if (argc == 0) {
-		IConsoleHelp("Print out the current working directory. Usage: 'pwd'");
-		return true;
-	}
-
-	// XXX - Workaround for broken file handling
-	FiosGetSavegameList(SLD_LOAD_GAME);
-	FiosFreeSavegameList();
-
-	FiosGetDescText(&path, NULL);
-	IConsolePrint(_icolour_def, path);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConClearBuffer)
-{
-	if (argc == 0) {
-		IConsoleHelp("Clear the console buffer. Usage: 'clear'");
-		return true;
-	}
-
-	IConsoleClearBuffer();
-	InvalidateWindow(WC_CONSOLE, 0);
-	return true;
-}
-
-
-// ********************************* //
-// * Network Core Console Commands * //
-// ********************************* //
-#ifdef ENABLE_NETWORK
-
-DEF_CONSOLE_CMD(ConBan)
-{
-	NetworkClientInfo *ci;
-	const char *banip = NULL;
-	uint32 index;
-
-	if (argc == 0) {
-		IConsoleHelp("Ban a player from a network game. Usage: 'ban <ip | client-id>'");
-		IConsoleHelp("For client-id's, see the command 'clients'");
-		IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	if (strchr(argv[1], '.') == NULL) { // banning with ID
-		index = atoi(argv[1]);
-		ci = NetworkFindClientInfoFromIndex(index);
-	} else { // banning IP
-		ci = NetworkFindClientInfoFromIP(argv[1]);
-		if (ci == NULL) {
-			banip = argv[1];
-			index = (uint32)-1;
-		} else {
-			index = ci->client_index;
-		}
-	}
-
-	if (index == NETWORK_SERVER_INDEX) {
-		IConsoleError("Silly boy, you can not ban yourself!");
-		return true;
-	}
-
-	if (index == 0 || (ci == NULL && index != (uint32)-1)) {
-		IConsoleError("Invalid client");
-		return true;
-	}
-
-	if (ci != NULL) {
-		banip = inet_ntoa(*(struct in_addr *)&ci->client_ip);
-		SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
-		IConsolePrint(_icolour_def, "Client banned");
-	} else {
-		IConsolePrint(_icolour_def, "Client not online, banned IP");
-	}
-
-	/* Add user to ban-list */
-	for (index = 0; index < lengthof(_network_ban_list); index++) {
-		if (_network_ban_list[index] == NULL) {
-			_network_ban_list[index] = strdup(banip);
-			break;
-		}
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConUnBan)
-{
-	uint i, index;
-
-	if (argc == 0) {
-		IConsoleHelp("Unban a player from a network game. Usage: 'unban <ip | client-id>'");
-		IConsoleHelp("For a list of banned IP's, see the command 'banlist'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	index = (strchr(argv[1], '.') == NULL) ? atoi(argv[1]) : 0;
-	index--;
-
-	for (i = 0; i < lengthof(_network_ban_list); i++) {
-		if (_network_ban_list[i] == NULL) continue;
-
-		if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) {
-			free(_network_ban_list[i]);
-			_network_ban_list[i] = NULL;
-			IConsolePrint(_icolour_def, "IP unbanned.");
-			return true;
-		}
-	}
-
-	IConsolePrint(_icolour_def, "IP not in ban-list.");
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConBanList)
-{
-	uint i;
-
-	if (argc == 0) {
-		IConsoleHelp("List the IP's of banned clients: Usage 'banlist'");
-		return true;
-	}
-
-	IConsolePrint(_icolour_def, "Banlist: ");
-
-	for (i = 0; i < lengthof(_network_ban_list); i++) {
-		if (_network_ban_list[i] != NULL)
-			IConsolePrintF(_icolour_def, "  %d) %s", i + 1, _network_ban_list[i]);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConPauseGame)
-{
-	if (argc == 0) {
-		IConsoleHelp("Pause a network game. Usage: 'pause'");
-		return true;
-	}
-
-	if (_pause == 0) {
-		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-		IConsolePrint(_icolour_def, "Game paused.");
-	} else {
-		IConsolePrint(_icolour_def, "Game is already paused.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConUnPauseGame)
-{
-	if (argc == 0) {
-		IConsoleHelp("Unpause a network game. Usage: 'unpause'");
-		return true;
-	}
-
-	if (_pause != 0) {
-		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
-		IConsolePrint(_icolour_def, "Game unpaused.");
-	} else {
-		IConsolePrint(_icolour_def, "Game is already unpaused.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConRcon)
-{
-	if (argc == 0) {
-		IConsoleHelp("Remote control the server from another client. Usage: 'rcon <password> <command>'");
-		IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent");
-		return true;
-	}
-
-	if (argc < 3) return false;
-
-	SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConStatus)
-{
-	static const char* const stat_str[] = {
-		"inactive",
-		"authorized",
-		"waiting",
-		"loading map",
-		"map done",
-		"ready",
-		"active"
-	};
-
-	const NetworkClientState *cs;
-
-	if (argc == 0) {
-		IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
-		return true;
-	}
-
-	FOR_ALL_CLIENTS(cs) {
-		int lag = NetworkCalculateLag(cs);
-		const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
-		const char* status;
-
-		status = (cs->status < lengthof(stat_str) ? stat_str[cs->status] : "unknown");
-		IConsolePrintF(8, "Client #%1d  name: '%s'  status: '%s'  frame-lag: %3d  company: %1d  IP: %s  unique-id: '%s'",
-			cs->index, ci->client_name, status, lag,
-			ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
-			GetPlayerIP(ci), ci->unique_id);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConServerInfo)
-{
-	const NetworkGameInfo *gi;
-
-	if (argc == 0) {
-		IConsoleHelp("List current and maximum client/player limits. Usage 'server_info'");
-		IConsoleHelp("You can change these values by setting the variables 'max_clients', 'max_companies' and 'max_spectators'");
-		return true;
-	}
-
-	gi = &_network_game_info;
-	IConsolePrintF(_icolour_def, "Current/maximum clients:    %2d/%2d", gi->clients_on, gi->clients_max);
-	IConsolePrintF(_icolour_def, "Current/maximum companies:  %2d/%2d", ActivePlayerCount(), gi->companies_max);
-	IConsolePrintF(_icolour_def, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), gi->spectators_max);
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount)
-{
-	/* XXX - hardcoded, string limiation -- TrueLight
-	 * XXX - also see network.c:NetworkStartup ~1356 */
-	if (_network_game_info.clients_max > 10) {
-		_network_game_info.clients_max = 10;
-		IConsoleError("Maximum clients out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount)
-{
-	if (_network_game_info.companies_max > MAX_PLAYERS) {
-		_network_game_info.companies_max = MAX_PLAYERS;
-		IConsoleError("Maximum companies out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount)
-{
-	/* XXX @see ConHookValidateMaxClientsCount */
-	if (_network_game_info.spectators_max > 10) {
-		_network_game_info.spectators_max = 10;
-		IConsoleError("Maximum spectators out of bounds, truncating to limit.");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookCheckMinPlayers)
-{
-	CheckMinPlayers();
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConKick)
-{
-	NetworkClientInfo *ci;
-	uint32 index;
-
-	if (argc == 0) {
-		IConsoleHelp("Kick a player from a network game. Usage: 'kick <ip | client-id>'");
-		IConsoleHelp("For client-id's, see the command 'clients'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	if (strchr(argv[1], '.') == NULL) {
-		index = atoi(argv[1]);
-		ci = NetworkFindClientInfoFromIndex(index);
-	} else {
-		ci = NetworkFindClientInfoFromIP(argv[1]);
-		index = (ci == NULL) ? 0 : ci->client_index;
-	}
-
-	if (index == NETWORK_SERVER_INDEX) {
-		IConsoleError("Silly boy, you can not kick yourself!");
-		return true;
-	}
-
-	if (index == 0) {
-		IConsoleError("Invalid client");
-		return true;
-	}
-
-	if (ci != NULL) {
-		SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
-	} else {
-		IConsoleError("Client not found");
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConResetCompany)
-{
-	const Player *p;
-	const NetworkClientState *cs;
-	const NetworkClientInfo *ci;
-	PlayerID index;
-
-	if (argc == 0) {
-		IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company <company-id>'");
-		IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Player 1 is 1, etc.");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	index = atoi(argv[1]) - 1;
-
-	/* Check valid range */
-	if (!IsValidPlayer(index)) {
-		IConsolePrintF(_icolour_err, "Company does not exist. Company-id must be between 1 and %d.", MAX_PLAYERS);
-		return true;
-	}
-
-	/* Check if company does exist */
-	p = GetPlayer(index);
-	if (!p->is_active) {
-		IConsoleError("Company does not exist.");
-		return true;
-	}
-
-	if (p->is_ai) {
-		IConsoleError("Company is owned by an AI.");
-		return true;
-	}
-
-	/* Check if the company has active players */
-	FOR_ALL_CLIENTS(cs) {
-		ci = DEREF_CLIENT_INFO(cs);
-		if (ci->client_playas == index) {
-			IConsoleError("Cannot remove company: a client is connected to that company.");
-			return true;
-		}
-	}
-	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-	if (ci->client_playas == index) {
-		IConsoleError("Cannot remove company: the server is connected to that company.");
-		return true;
-	}
-
-	/* It is safe to remove this company */
-	DoCommandP(0, 2, index, NULL, CMD_PLAYER_CTRL);
-	IConsolePrint(_icolour_def, "Company deleted.");
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConNetworkClients)
-{
-	NetworkClientInfo *ci;
-
-	if (argc == 0) {
-		IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'");
-		return true;
-	}
-
-	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-		IConsolePrintF(8, "Client #%1d  name: '%s'  company: %1d  IP: %s",
-		               ci->client_index, ci->client_name,
-		               ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
-		               GetPlayerIP(ci));
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConNetworkConnect)
-{
-	char *ip;
-	const char *port = NULL;
-	const char *player = NULL;
-	uint16 rport;
-
-	if (argc == 0) {
-		IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'");
-		IConsoleHelp("IP can contain port and player: 'IP[[#Player]:Port]', eg: 'server.ottd.org#2:443'");
-		IConsoleHelp("Player #255 is spectator all others are a certain company with Company 1 being #1");
-		return true;
-	}
-
-	if (argc < 2) return false;
-	if (_networking) NetworkDisconnect(); // we are in network-mode, first close it!
-
-	ip = argv[1];
-	/* Default settings: default port and new company */
-	rport = NETWORK_DEFAULT_PORT;
-	_network_playas = PLAYER_NEW_COMPANY;
-
-	ParseConnectionString(&player, &port, ip);
-
-	IConsolePrintF(_icolour_def, "Connecting to %s...", ip);
-	if (player != NULL) {
-		_network_playas = atoi(player);
-		IConsolePrintF(_icolour_def, "    player-no: %d", _network_playas);
-
-		/* From a user pov 0 is a new player, internally it's different and all
-		 * players are offset by one to ease up on users (eg players 1-8 not 0-7) */
-		if (_network_playas != PLAYER_SPECTATOR) {
-			_network_playas--;
-			if (!IsValidPlayer(_network_playas)) return false;
-		}
-	}
-	if (port != NULL) {
-		rport = atoi(port);
-		IConsolePrintF(_icolour_def, "    port: %s", port);
-	}
-
-	NetworkClientConnectGame(ip, rport);
-
-	return true;
-}
-
-#endif /* ENABLE_NETWORK */
-
-/* ******************************** */
-/*   script file console commands   */
-/* ******************************** */
-
-DEF_CONSOLE_CMD(ConExec)
-{
-	char cmdline[ICON_CMDLN_SIZE];
-	char *cmdptr;
-
-	if (argc == 0) {
-		IConsoleHelp("Execute a local script file. Usage: 'exec <script> <?>'");
-		return true;
-	}
-
-	if (argc < 2) return false;
-
-	_script_file = fopen(argv[1], "r");
-
-	if (_script_file == NULL) {
-		if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found");
-		return true;
-	}
-
-	_script_running = true;
-
-	while (_script_running && fgets(cmdline, sizeof(cmdline), _script_file) != NULL) {
-		/* Remove newline characters from the executing script */
-		for (cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) {
-			if (*cmdptr == '\n' || *cmdptr == '\r') {
-				*cmdptr = '\0';
-				break;
-			}
-		}
-		IConsoleCmdExec(cmdline);
-	}
-
-	if (ferror(_script_file))
-		IConsoleError("Encountered errror while trying to read from script file");
-
-	_script_running = false;
-	fclose(_script_file);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConReturn)
-{
-	if (argc == 0) {
-		IConsoleHelp("Stop executing a running script. Usage: 'return'");
-		return true;
-	}
-
-	_script_running = false;
-	return true;
-}
-
-/* **************************** */
-/*   default console commands   */
-/* **************************** */
-extern bool CloseConsoleLogIfActive(void);
-
-DEF_CONSOLE_CMD(ConScript)
-{
-	extern FILE* _iconsole_output_file;
-
-	if (argc == 0) {
-		IConsoleHelp("Start or stop logging console output to a file. Usage: 'script <filename>'");
-		IConsoleHelp("If filename is omitted, a running log is stopped if it is active");
-		return true;
-	}
-
-	if (!CloseConsoleLogIfActive()) {
-		if (argc < 2) return false;
-
-		IConsolePrintF(_icolour_def, "file output started to: %s", argv[1]);
-		_iconsole_output_file = fopen(argv[1], "ab");
-		if (_iconsole_output_file == NULL) IConsoleError("could not open file");
-	}
-
-	return true;
-}
-
-
-DEF_CONSOLE_CMD(ConEcho)
-{
-	if (argc == 0) {
-		IConsoleHelp("Print back the first argument to the console. Usage: 'echo <arg>'");
-		return true;
-	}
-
-	if (argc < 2) return false;
-	IConsolePrint(_icolour_def, argv[1]);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConEchoC)
-{
-	if (argc == 0) {
-		IConsoleHelp("Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'");
-		return true;
-	}
-
-	if (argc < 3) return false;
-	IConsolePrint(atoi(argv[1]), argv[2]);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConNewGame)
-{
-	if (argc == 0) {
-		IConsoleHelp("Start a new game. Usage: 'newgame [seed]'");
-		IConsoleHelp("The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
-		return true;
-	}
-
-	StartNewGameWithoutGUI((argc == 2) ? (uint)atoi(argv[1]) : GENERATE_NEW_SEED);
-	return true;
-}
-
-extern void SwitchMode(int new_mode);
-
-DEF_CONSOLE_CMD(ConRestart)
-{
-	if (argc == 0) {
-		IConsoleHelp("Restart game. Usage: 'restart'");
-		IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
-		return true;
-	}
-
-	/* Don't copy the _newgame pointers to the real pointers, so call SwitchMode directly */
-	_patches.map_x = MapLogX();
-	_patches.map_y = FindFirstBit(MapSizeY());
-	SwitchMode(SM_NEWGAME);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConGetSeed)
-{
-	if (argc == 0) {
-		IConsoleHelp("Returns the seed used to create this game. Usage: 'getseed'");
-		IConsoleHelp("The seed can be used to reproduce the exact same map as the game started with.");
-		return true;
-	}
-
-	IConsolePrintF(_icolour_def, "Generation Seed: %u", _patches.generation_seed);
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConAlias)
-{
-	IConsoleAlias *alias;
-
-	if (argc == 0) {
-		IConsoleHelp("Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'");
-		return true;
-	}
-
-	if (argc < 3) return false;
-
-	alias = IConsoleAliasGet(argv[1]);
-	if (alias == NULL) {
-		IConsoleAliasRegister(argv[1], argv[2]);
-	} else {
-		free(alias->cmdline);
-		alias->cmdline = strdup(argv[2]);
-	}
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConScreenShot)
-{
-	if (argc == 0) {
-		IConsoleHelp("Create a screenshot of the game. Usage: 'screenshot [big | no_con]'");
-		IConsoleHelp("'big' makes a screenshot of the whole map, 'no_con' hides the console to create the screenshot");
-		return true;
-	}
-
-	if (argc > 3) return false;
-
-	SetScreenshotType(SC_VIEWPORT);
-	if (argc > 1) {
-		if (strcmp(argv[1], "big") == 0 || (argc == 3 && strcmp(argv[2], "big") == 0))
-			SetScreenshotType(SC_WORLD);
-
-		if (strcmp(argv[1], "no_con") == 0 || (argc == 3 && strcmp(argv[2], "no_con") == 0))
-			IConsoleClose();
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConInfoVar)
-{
-	static const char *_icon_vartypes[] = {"boolean", "byte", "uint16", "uint32", "int16", "int32", "string"};
-	const IConsoleVar *var;
-
-	if (argc == 0) {
-		IConsoleHelp("Print out debugging information about a variable. Usage: 'info_var <var>'");
-		return true;
-	}
-
-	if (argc < 2) return false;
-
-	var = IConsoleVarGet(argv[1]);
-	if (var == NULL) {
-		IConsoleError("the given variable was not found");
-		return true;
-	}
-
-	IConsolePrintF(_icolour_def, "variable name: %s", var->name);
-	IConsolePrintF(_icolour_def, "variable type: %s", _icon_vartypes[var->type]);
-	IConsolePrintF(_icolour_def, "variable addr: 0x%X", var->addr);
-
-	if (var->hook.access) IConsoleWarning("variable is access hooked");
-	if (var->hook.pre) IConsoleWarning("variable is pre hooked");
-	if (var->hook.post) IConsoleWarning("variable is post hooked");
-	return true;
-}
-
-
-DEF_CONSOLE_CMD(ConInfoCmd)
-{
-	const IConsoleCmd *cmd;
-
-	if (argc == 0) {
-		IConsoleHelp("Print out debugging information about a command. Usage: 'info_cmd <cmd>'");
-		return true;
-	}
-
-	if (argc < 2) return false;
-
-	cmd = IConsoleCmdGet(argv[1]);
-	if (cmd == NULL) {
-		IConsoleError("the given command was not found");
-		return true;
-	}
-
-	IConsolePrintF(_icolour_def, "command name: %s", cmd->name);
-	IConsolePrintF(_icolour_def, "command proc: 0x%X", cmd->proc);
-
-	if (cmd->hook.access) IConsoleWarning("command is access hooked");
-	if (cmd->hook.pre) IConsoleWarning("command is pre hooked");
-	if (cmd->hook.post) IConsoleWarning("command is post hooked");
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConDebugLevel)
-{
-	if (argc == 0) {
-		IConsoleHelp("Get/set the default debugging level for the game. Usage: 'debug_level [<level>]'");
-		IConsoleHelp("Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'s");
-		return true;
-	}
-
-	if (argc > 2) return false;
-
-	if (argc == 1) {
-		IConsolePrintF(_icolour_def, "Current debug-level: '%s'", GetDebugString());
-	} else {
-		SetDebugString(argv[1]);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConExit)
-{
-	if (argc == 0) {
-		IConsoleHelp("Exit the game. Usage: 'exit'");
-		return true;
-	}
-
-	_exit_game = true;
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConPart)
-{
-	if (argc == 0) {
-		IConsoleHelp("Leave the currently joined/running game (only ingame). Usage: 'part'");
-		return true;
-	}
-
-	if (_game_mode != GM_NORMAL) return false;
-
-	_switch_mode = SM_MENU;
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConHelp)
-{
-	if (argc == 2) {
-		const IConsoleCmd *cmd;
-		const IConsoleVar *var;
-		const IConsoleAlias *alias;
-
-		cmd = IConsoleCmdGet(argv[1]);
-		if (cmd != NULL) {
-			cmd->proc(0, NULL);
-			return true;
-		}
-
-		alias = IConsoleAliasGet(argv[1]);
-		if (alias != NULL) {
-			cmd = IConsoleCmdGet(alias->cmdline);
-			if (cmd != NULL) {
-				cmd->proc(0, NULL);
-				return true;
-			}
-			IConsolePrintF(_icolour_err, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline);
-			return true;
-		}
-
-		var = IConsoleVarGet(argv[1]);
-		if (var != NULL && var->help != NULL) {
-			IConsoleHelp(var->help);
-			return true;
-		}
-
-		IConsoleError("command or variable not found");
-		return true;
-	}
-
-	IConsolePrint(13, " ---- OpenTTD Console Help ---- ");
-	IConsolePrint( 1, " - variables: [command to list all variables: list_vars]");
-	IConsolePrint( 1, " set value with '<var> = <value>', use '++/--' to in-or decrement");
-	IConsolePrint( 1, " or omit '=' and just '<var> <value>'. get value with typing '<var>'");
-	IConsolePrint( 1, " - commands: [command to list all commands: list_cmds]");
-	IConsolePrint( 1, " call commands with '<command> <arg2> <arg3>...'");
-	IConsolePrint( 1, " - to assign strings, or use them as arguments, enclose it within quotes");
-	IConsolePrint( 1, " like this: '<command> \"string argument with spaces\"'");
-	IConsolePrint( 1, " - use 'help <command> | <variable>' to get specific information");
-	IConsolePrint( 1, " - scroll console output with shift + (up | down) | (pageup | pagedown))");
-	IConsolePrint( 1, " - scroll console input history with the up | down arrows");
-	IConsolePrint( 1, "");
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConListCommands)
-{
-	const IConsoleCmd *cmd;
-	size_t l = 0;
-
-	if (argc == 0) {
-		IConsoleHelp("List all registered commands. Usage: 'list_cmds [<pre-filter>]'");
-		return true;
-	}
-
-	if (argv[1] != NULL) l = strlen(argv[1]);
-
-	for (cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) {
-		if (argv[1] == NULL || strncmp(cmd->name, argv[1], l) == 0) {
-				IConsolePrintF(_icolour_def, "%s", cmd->name);
-		}
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConListVariables)
-{
-	const IConsoleVar *var;
-	size_t l = 0;
-
-	if (argc == 0) {
-		IConsoleHelp("List all registered variables. Usage: 'list_vars [<pre-filter>]'");
-		return true;
-	}
-
-	if (argv[1] != NULL) l = strlen(argv[1]);
-
-	for (var = _iconsole_vars; var != NULL; var = var->next) {
-		if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0)
-			IConsolePrintF(_icolour_def, "%s", var->name);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConListAliases)
-{
-	const IConsoleAlias *alias;
-	size_t l = 0;
-
-	if (argc == 0) {
-		IConsoleHelp("List all registered aliases. Usage: 'list_aliases [<pre-filter>]'");
-		return true;
-	}
-
-	if (argv[1] != NULL) l = strlen(argv[1]);
-
-	for (alias = _iconsole_aliases; alias != NULL; alias = alias->next) {
-		if (argv[1] == NULL || strncmp(alias->name, argv[1], l) == 0)
-			IConsolePrintF(_icolour_def, "%s => %s", alias->name, alias->cmdline);
-	}
-
-	return true;
-}
-
-#ifdef ENABLE_NETWORK
-
-DEF_CONSOLE_CMD(ConSay)
-{
-	if (argc == 0) {
-		IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'");
-		return true;
-	}
-
-	if (argc != 2) return false;
-
-	if (!_network_server) {
-		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
-	} else {
-		NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX);
-	}
-
-	return true;
-}
-
-#ifdef ENABLE_NETWORK
-	#include "table/strings.h"
-#endif /* ENABLE_NETWORK */
-
-DEF_CONSOLE_CMD(ConPlayers)
-{
-	Player *p;
-
-	if (argc == 0) {
-		IConsoleHelp("List the in-game details of all clients connected to the server. Usage 'players'");
-		return true;
-	}
-	NetworkPopulateCompanyInfo();
-
-	FOR_ALL_PLAYERS(p) {
-		char buffer[512];
-
-		if (!p->is_active) continue;
-
-		GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index], lastof(buffer));
-		IConsolePrintF(8, "#:%d(%s) Company Name: '%s'  Year Founded: %d  Money: %d  Loan: %d  Value: %" OTTD_PRINTF64 "d  (T:%d, R:%d, P:%d, S:%d)",
-			p->index + 1, buffer, _network_player_info[p->index].company_name, p->inaugurated_year, p->player_money, p->current_loan, CalculateCompanyValue(p),
-			/* trains      */ _network_player_info[p->index].num_vehicle[0],
-			/* lorry + bus */ _network_player_info[p->index].num_vehicle[1] + _network_player_info[p->index].num_vehicle[2],
-			/* planes      */ _network_player_info[p->index].num_vehicle[3],
-			/* ships       */ _network_player_info[p->index].num_vehicle[4]);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConSayPlayer)
-{
-	if (argc == 0) {
-		IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_player <player-no> \"<msg>\"'");
-		IConsoleHelp("PlayerNo is the player that plays as company <playerno>, 1 through max_players");
-		return true;
-	}
-
-	if (argc != 3) return false;
-
-	if (atoi(argv[1]) < 1 || atoi(argv[1]) > MAX_PLAYERS) {
-		IConsolePrintF(_icolour_def, "Unknown player. Player range is between 1 and %d.", MAX_PLAYERS);
-		return true;
-	}
-
-	if (!_network_server) {
-		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2]);
-	} else {
-		NetworkServer_HandleChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConSayClient)
-{
-	if (argc == 0) {
-		IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'");
-		IConsoleHelp("For client-id's, see the command 'clients'");
-		return true;
-	}
-
-	if (argc != 3) return false;
-
-	if (!_network_server) {
-		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
-	} else {
-		NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerPW)
-{
-	if (strcmp(_network_server_password, "*") == 0) {
-		_network_server_password[0] = '\0';
-		_network_game_info.use_password = 0;
-	} else {
-		ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
-		_network_game_info.use_password = 1;
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookRconPW)
-{
-	if (strcmp(_network_rcon_password, "*") == 0)
-		_network_rcon_password[0] = '\0';
-
-	ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password));
-
-	return true;
-}
-
-/* Also use from within player_gui to change the password graphically */
-bool NetworkChangeCompanyPassword(byte argc, char *argv[])
-{
-	if (argc == 0) {
-		if (!IsValidPlayer(_local_player)) return true; // dedicated server
-		IConsolePrintF(_icolour_warn, "Current value for 'company_pw': %s", _network_player_info[_local_player].password);
-		return true;
-	}
-
-	if (!IsValidPlayer(_local_player)) {
-		IConsoleError("You have to own a company to make use of this command.");
-		return false;
-	}
-
-	if (argc != 1) return false;
-
-	if (strcmp(argv[0], "*") == 0) argv[0][0] = '\0';
-
-	ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password));
-
-	if (!_network_server)
-		SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
-
-	IConsolePrintF(_icolour_warn, "'company_pw' changed to:  %s", _network_player_info[_local_player].password);
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConProcPlayerName)
-{
-	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
-
-	if (ci == NULL) return false;
-
-	// Don't change the name if it is the same as the old name
-	if (strcmp(ci->client_name, _network_player_name) != 0) {
-		if (!_network_server) {
-			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_network_player_name);
-		} else {
-			if (NetworkFindName(_network_player_name)) {
-				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", _network_player_name);
-				ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
-				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
-			}
-		}
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerName)
-{
-	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
-	return true;
-}
-
-DEF_CONSOLE_HOOK(ConHookServerAdvertise)
-{
-	if (!_network_advertise) // remove us from advertising
-		NetworkUDPRemoveAdvertise();
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConProcServerIP)
-{
-	if (argc == 0) {
-		IConsolePrintF(_icolour_warn, "Current value for 'server_ip': %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-		return true;
-	}
-
-	if (argc != 1) return false;
-
-	_network_server_bind_ip = (strcmp(argv[0], "all") == 0) ? inet_addr("0.0.0.0") : inet_addr(argv[0]);
-	snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-	IConsolePrintF(_icolour_warn, "'server_ip' changed to:  %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-	return true;
-}
-#endif /* ENABLE_NETWORK */
-
-DEF_CONSOLE_CMD(ConPatch)
-{
-	if (argc == 0) {
-		IConsoleHelp("Change patch variables for all players. Usage: 'patch <name> [<value>]'");
-		IConsoleHelp("Omitting <value> will print out the current value of the patch-setting.");
-		return true;
-	}
-
-	if (argc == 1 || argc > 3) return false;
-
-	if (argc == 2) {
-		IConsoleGetPatchSetting(argv[1]);
-	} else {
-		uint32 val;
-
-		if (GetArgumentInteger(&val, argv[2])) {
-			if (!IConsoleSetPatchSetting(argv[1], val)) {
-				IConsoleError("This command/variable is only available to a network server.");
-			}
-		}
-	}
-
-	return true;
-}
-
-DEF_CONSOLE_CMD(ConListDumpVariables)
-{
-	const IConsoleVar *var;
-	size_t l = 0;
-
-	if (argc == 0) {
-		IConsoleHelp("List all variables with their value. Usage: 'dump_vars [<pre-filter>]'");
-		return true;
-	}
-
-	if (argv[1] != NULL) l = strlen(argv[1]);
-
-	for (var = _iconsole_vars; var != NULL; var = var->next) {
-		if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0)
-			IConsoleVarPrintGetValue(var);
-	}
-
-	return true;
-}
-
-
-#ifdef _DEBUG
-/* ****************************************** */
-/*  debug commands and variables */
-/* ****************************************** */
-
-static void IConsoleDebugLibRegister(void)
-{
-	// debugging variables and functions
-	extern bool _stdlib_con_developer; /* XXX extern in .c */
-
-	IConsoleVarRegister("con_developer",    &_stdlib_con_developer, ICONSOLE_VAR_BOOLEAN, "Enable/disable console debugging information (internal)");
-	IConsoleCmdRegister("resettile",        ConResetTile);
-	IConsoleCmdRegister("stopall",          ConStopAllVehicles);
-	IConsoleAliasRegister("dbg_echo",       "echo %A; echo %B");
-	IConsoleAliasRegister("dbg_echo2",      "echo %!");
-}
-#endif
-
-/* ****************************************** */
-/*  console command and variable registration */
-/* ****************************************** */
-
-void IConsoleStdLibRegister(void)
-{
-	// stdlib
-	extern byte _stdlib_developer; /* XXX extern in .c */
-
-	// default variables and functions
-	IConsoleCmdRegister("debug_level",  ConDebugLevel);
-	IConsoleCmdRegister("dump_vars",    ConListDumpVariables);
-	IConsoleCmdRegister("echo",         ConEcho);
-	IConsoleCmdRegister("echoc",        ConEchoC);
-	IConsoleCmdRegister("exec",         ConExec);
-	IConsoleCmdRegister("exit",         ConExit);
-	IConsoleCmdRegister("part",         ConPart);
-	IConsoleCmdRegister("help",         ConHelp);
-	IConsoleCmdRegister("info_cmd",     ConInfoCmd);
-	IConsoleCmdRegister("info_var",     ConInfoVar);
-	IConsoleCmdRegister("list_cmds",    ConListCommands);
-	IConsoleCmdRegister("list_vars",    ConListVariables);
-	IConsoleCmdRegister("list_aliases", ConListAliases);
-	IConsoleCmdRegister("newgame",      ConNewGame);
-	IConsoleCmdRegister("restart",      ConRestart);
-	IConsoleCmdRegister("getseed",      ConGetSeed);
-	IConsoleCmdRegister("quit",         ConExit);
-	IConsoleCmdRegister("resetengines", ConResetEngines);
-	IConsoleCmdRegister("return",       ConReturn);
-	IConsoleCmdRegister("screenshot",   ConScreenShot);
-	IConsoleCmdRegister("script",       ConScript);
-	IConsoleCmdRegister("scrollto",     ConScrollToTile);
-	IConsoleCmdRegister("alias",        ConAlias);
-	IConsoleCmdRegister("load",         ConLoad);
-	IConsoleCmdRegister("rm",           ConRemove);
-	IConsoleCmdRegister("save",         ConSave);
-	IConsoleCmdRegister("saveconfig",   ConSaveConfig);
-	IConsoleCmdRegister("ls",           ConListFiles);
-	IConsoleCmdRegister("cd",           ConChangeDirectory);
-	IConsoleCmdRegister("pwd",          ConPrintWorkingDirectory);
-	IConsoleCmdRegister("clear",        ConClearBuffer);
-	IConsoleCmdRegister("patch",        ConPatch);
-
-	IConsoleAliasRegister("dir",      "ls");
-	IConsoleAliasRegister("del",      "rm %+");
-	IConsoleAliasRegister("newmap",   "newgame");
-	IConsoleAliasRegister("new_map",  "newgame");
-	IConsoleAliasRegister("new_game", "newgame");
-
-
-	IConsoleVarRegister("developer", &_stdlib_developer, ICONSOLE_VAR_BYTE, "Redirect debugging output from the console/command line to the ingame console (value 2). Default value: 1");
-
-	/* networking variables and functions */
-#ifdef ENABLE_NETWORK
-	/* Network hooks; only active in network */
-	IConsoleCmdHookAdd ("resetengines", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork);
-
-	/*** Networking commands ***/
-	IConsoleCmdRegister("say",             ConSay);
-	IConsoleCmdHookAdd("say",              ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleCmdRegister("players",             ConPlayers);
-	IConsoleCmdHookAdd("players",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("say_player",      ConSayPlayer);
-	IConsoleCmdHookAdd("say_player",       ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleCmdRegister("say_client",      ConSayClient);
-	IConsoleCmdHookAdd("say_client",       ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-
-	IConsoleCmdRegister("connect",         ConNetworkConnect);
-	IConsoleCmdHookAdd("connect",          ICONSOLE_HOOK_ACCESS, ConHookClientOnly);
-	IConsoleAliasRegister("join",          "connect %A");
-	IConsoleCmdRegister("clients",         ConNetworkClients);
-	IConsoleCmdHookAdd("clients",          ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleCmdRegister("status",          ConStatus);
-	IConsoleCmdHookAdd("status",           ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("server_info",     ConServerInfo);
-	IConsoleCmdHookAdd("server_info",      ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleAliasRegister("info",          "server_info");
-	IConsoleCmdRegister("rcon",            ConRcon);
-	IConsoleCmdHookAdd("rcon",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-
-	IConsoleCmdRegister("reset_company",   ConResetCompany);
-	IConsoleCmdHookAdd("reset_company",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleAliasRegister("clean_company", "reset_company %A");
-	IConsoleCmdRegister("kick",            ConKick);
-	IConsoleCmdHookAdd("kick",             ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("ban",             ConBan);
-	IConsoleCmdHookAdd("ban",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("unban",           ConUnBan);
-	IConsoleCmdHookAdd("unban",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("banlist",         ConBanList);
-	IConsoleCmdHookAdd("banlist",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleCmdRegister("pause",           ConPauseGame);
-	IConsoleCmdHookAdd("pause",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleCmdRegister("unpause",         ConUnPauseGame);
-	IConsoleCmdHookAdd("unpause",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	/*** Networking variables ***/
-	IConsoleVarRegister("net_frame_freq",        &_network_frame_freq, ICONSOLE_VAR_BYTE, "The amount of frames before a command will be (visibly) executed. Default value: 1");
-	IConsoleVarHookAdd("net_frame_freq",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("net_sync_freq",         &_network_sync_freq,  ICONSOLE_VAR_UINT16, "The amount of frames to check if the game is still in sync. Default value: 100");
-	IConsoleVarHookAdd("net_sync_freq",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarStringRegister("server_pw",       &_network_server_password, sizeof(_network_server_password), "Set the server password to protect your server. Use '*' to clear the password");
-	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_POST_ACTION, ConHookServerPW);
-	IConsoleAliasRegister("server_password",     "server_pw %+");
-	IConsoleVarStringRegister("rcon_pw",         &_network_rcon_password, sizeof(_network_rcon_password), "Set the rcon-password to change server behaviour. Use '*' to disable rcon");
-	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_POST_ACTION, ConHookRconPW);
-	IConsoleAliasRegister("rcon_password",       "rcon_pw %+");
-	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");
-	IConsoleVarHookAdd("company_pw",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleVarProcAdd("company_pw",             NetworkChangeCompanyPassword);
-	IConsoleAliasRegister("company_password",    "company_pw %+");
-
-	IConsoleVarStringRegister("name",            &_network_player_name, sizeof(_network_player_name), "Set your name for multiplayer");
-	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
-	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_POST_ACTION, ConProcPlayerName);
-	IConsoleVarStringRegister("server_name",     &_network_server_name, sizeof(_network_server_name), "Set the name of the server for multiplayer");
-	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_POST_ACTION, ConHookServerName);
-
-	IConsoleVarRegister("server_port",           &_network_server_port, ICONSOLE_VAR_UINT32, "Set the server port. Changes take effect the next time you start a server");
-	IConsoleVarRegister("server_ip",             &_network_server_bind_ip, ICONSOLE_VAR_UINT32, "Set the IP the server binds to. Changes take effect the next time you start a server. Use 'all' to bind to any IP.");
-	IConsoleVarProcAdd("server_ip",              ConProcServerIP);
-	IConsoleAliasRegister("server_bind_ip",      "server_ip %+");
-	IConsoleAliasRegister("server_ip_bind",      "server_ip %+");
-	IConsoleAliasRegister("server_bind",         "server_ip %+");
-	IConsoleVarRegister("server_advertise",      &_network_advertise, ICONSOLE_VAR_BOOLEAN, "Set if the server will advertise to the master server and show up there");
-	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_POST_ACTION, ConHookServerAdvertise);
-
-	IConsoleVarRegister("max_clients",           &_network_game_info.clients_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of connected players during runtime. Default value: 10");
-	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxClientsCount);
-	IConsoleVarRegister("max_companies",         &_network_game_info.companies_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active companies during runtime. Default value: 8");
-	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxCompaniesCount);
-	IConsoleVarRegister("max_spectators",        &_network_game_info.spectators_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active spectators during runtime. Default value: 9");
-	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxSpectatorsCount);
-
-	IConsoleVarRegister("max_join_time",         &_network_max_join_time, ICONSOLE_VAR_UINT16, "Set the maximum amount of time (ticks) a client is allowed to join. Default value: 500");
-
-	IConsoleVarRegister("pause_on_join",         &_network_pause_on_join, ICONSOLE_VAR_BOOLEAN, "Set if the server should pause gameplay while a client is joining. This might help slow users");
-	IConsoleVarHookAdd("pause_on_join",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarRegister("autoclean_companies",   &_network_autoclean_companies, ICONSOLE_VAR_BOOLEAN, "Automatically shut down inactive companies to free them up for other players. Customize with 'autoclean_(un)protected'");
-	IConsoleVarHookAdd("autoclean_companies",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("autoclean_protected",   &_network_autoclean_protected, ICONSOLE_VAR_BYTE, "Automatically remove the password from an inactive company after the given amount of months");
-	IConsoleVarHookAdd("autoclean_protected",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("autoclean_unprotected", &_network_autoclean_unprotected, ICONSOLE_VAR_BYTE, "Automatically shut down inactive companies after the given amount of months");
-	IConsoleVarHookAdd("autoclean_unprotected",  ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarRegister("restart_game_year",     &_network_restart_game_year, ICONSOLE_VAR_UINT16, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this");
-	IConsoleVarHookAdd("restart_game_year",      ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-
-	IConsoleVarRegister("min_players",           &_network_min_players, ICONSOLE_VAR_BYTE, "Automatically pause the game when the number of active players passes below the given amount");
-	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
-	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_POST_ACTION, ConHookCheckMinPlayers);
-
-#endif /* ENABLE_NETWORK */
-
-	// debugging stuff
-#ifdef _DEBUG
-	IConsoleDebugLibRegister();
-#endif
-}
new file mode 100644
--- /dev/null
+++ b/src/console_cmds.cpp
@@ -0,0 +1,1622 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "console.h"
+#include "debug.h"
+#include "engine.h"
+#include "functions.h"
+#include "saveload.h"
+#include "string.h"
+#include "variables.h"
+#include "network/network_data.h"
+#include "network/network_client.h"
+#include "network/network_server.h"
+#include "network/network_udp.h"
+#include "command.h"
+#include "settings.h"
+#include "fios.h"
+#include "vehicle.h"
+#include "station.h"
+#include "strings.h"
+#include "screenshot.h"
+#include "genworld.h"
+#include "date.h"
+#include "network/network.h"
+
+// ** scriptfile handling ** //
+static FILE *_script_file;
+static bool _script_running;
+
+// ** console command / variable defines ** //
+#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
+#define DEF_CONSOLE_HOOK(function) static bool function(void)
+
+
+/* **************************** */
+/* variable and command hooks   */
+/* **************************** */
+
+#ifdef ENABLE_NETWORK
+
+static inline bool NetworkAvailable(void)
+{
+	if (!_network_available) {
+		IConsoleError("You cannot use this command because there is no network available.");
+		return false;
+	}
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookServerOnly)
+{
+	if (!NetworkAvailable()) return false;
+
+	if (!_network_server) {
+		IConsoleError("This command/variable is only available to a network server.");
+		return false;
+	}
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookClientOnly)
+{
+	if (!NetworkAvailable()) return false;
+
+	if (_network_server) {
+		IConsoleError("This command/variable is not available to a network server.");
+		return false;
+	}
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookNeedNetwork)
+{
+	if (!NetworkAvailable()) return false;
+
+	if (!_networking) {
+		IConsoleError("Not connected. This command/variable is only available in multiplayer.");
+		return false;
+	}
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookNoNetwork)
+{
+	if (_networking) {
+		IConsoleError("This command/variable is forbidden in multiplayer.");
+		return false;
+	}
+	return true;
+}
+
+#endif /* ENABLE_NETWORK */
+
+static void IConsoleHelp(const char *str)
+{
+	IConsolePrintF(_icolour_warn, "- %s", str);
+}
+
+DEF_CONSOLE_CMD(ConResetEngines)
+{
+	if (argc == 0) {
+		IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'");
+		return true;
+	}
+
+	StartupEngines();
+	return true;
+}
+
+#ifdef _DEBUG
+DEF_CONSOLE_CMD(ConResetTile)
+{
+	if (argc == 0) {
+		IConsoleHelp("Reset a tile to bare land. Usage: 'resettile <tile>'");
+		IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
+		return true;
+	}
+
+	if (argc == 2) {
+		uint32 result;
+		if (GetArgumentInteger(&result, argv[1])) {
+			DoClearSquare((TileIndex)result);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+DEF_CONSOLE_CMD(ConStopAllVehicles)
+{
+	Vehicle* v;
+	if (argc == 0) {
+		IConsoleHelp("Stops all vehicles in the game. For debugging only! Use at your own risk... Usage: 'stopall'");
+		return true;
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		/* Code ripped from CmdStartStopTrain. Can't call it, because of
+		 * ownership problems, so we'll duplicate some code, for now */
+		if (v->type == VEH_Train)
+			v->u.rail.days_since_order_progr = 0;
+		v->vehstatus |= VS_STOPPED;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+	}
+	return true;
+}
+#endif /* _DEBUG */
+
+DEF_CONSOLE_CMD(ConScrollToTile)
+{
+	if (argc == 0) {
+		IConsoleHelp("Center the screen on a given tile. Usage: 'scrollto <tile>'");
+		IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
+		return true;
+	}
+
+	if (argc == 2) {
+		uint32 result;
+		if (GetArgumentInteger(&result, argv[1])) {
+			if (result >= MapSize()) {
+				IConsolePrint(_icolour_err, "Tile does not exist");
+				return true;
+			}
+			ScrollMainWindowToTile((TileIndex)result);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
+extern void BuildFileList(void);
+extern void SetFiosType(const byte fiostype);
+
+/* Save the map to a file */
+DEF_CONSOLE_CMD(ConSave)
+{
+	if (argc == 0) {
+		IConsoleHelp("Save the current game. Usage: 'save <filename>'");
+		return true;
+	}
+
+	if (argc == 2) {
+		char buf[200];
+
+		snprintf(buf, lengthof(buf), "%s%s%s.sav", _paths.save_dir, PATHSEP, argv[1]);
+		IConsolePrint(_icolour_def, "Saving map...");
+
+		if (SaveOrLoad(buf, SL_SAVE) != SL_OK) {
+			IConsolePrint(_icolour_err, "SaveMap failed");
+		} else {
+			IConsolePrintF(_icolour_def, "Map sucessfully saved to %s", buf);
+		}
+		return true;
+	}
+
+	return false;
+}
+
+/* Explicitly save the configuration */
+DEF_CONSOLE_CMD(ConSaveConfig)
+{
+	if (argc == 0) {
+		IConsoleHelp("Saves the current config, typically to 'openttd.cfg'.");
+		return true;
+	}
+
+	SaveToConfig();
+	IConsolePrint(_icolour_def, "Saved config.");
+	return true;
+}
+
+static const FiosItem* GetFiosItem(const char* file)
+{
+	int i;
+
+	_saveload_mode = SLD_LOAD_GAME;
+	BuildFileList();
+
+	for (i = 0; i < _fios_num; i++) {
+		if (strcmp(file, _fios_list[i].name) == 0) break;
+		if (strcmp(file, _fios_list[i].title) == 0) break;
+	}
+
+	if (i == _fios_num) { /* If no name matches, try to parse it as number */
+		char* endptr;
+
+		i = strtol(file, &endptr, 10);
+		if (file == endptr || *endptr != '\0') i = -1;
+	}
+
+	return IS_INT_INSIDE(i, 0, _fios_num) ? &_fios_list[i] : NULL;
+}
+
+
+DEF_CONSOLE_CMD(ConLoad)
+{
+	const FiosItem *item;
+	const char *file;
+
+	if (argc == 0) {
+		IConsoleHelp("Load a game by name or index. Usage: 'load <file | number>'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	file = argv[1];
+	item = GetFiosItem(file);
+	if (item != NULL) {
+		switch (item->type) {
+			case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: {
+				_switch_mode = SM_LOAD;
+				SetFiosType(item->type);
+
+				ttd_strlcpy(_file_to_saveload.name, FiosBrowseTo(item), sizeof(_file_to_saveload.name));
+				ttd_strlcpy(_file_to_saveload.title, item->title, sizeof(_file_to_saveload.title));
+			} break;
+			default: IConsolePrintF(_icolour_err, "%s: Not a savegame.", file);
+		}
+	} else {
+		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
+	}
+
+	FiosFreeSavegameList();
+	return true;
+}
+
+
+DEF_CONSOLE_CMD(ConRemove)
+{
+	const FiosItem* item;
+	const char* file;
+
+	if (argc == 0) {
+		IConsoleHelp("Remove a savegame by name or index. Usage: 'rm <file | number>'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	file = argv[1];
+	item = GetFiosItem(file);
+	if (item != NULL) {
+		if (!FiosDelete(item->name))
+			IConsolePrintF(_icolour_err, "%s: Failed to delete file", file);
+	} else {
+		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
+	}
+
+	FiosFreeSavegameList();
+	return true;
+}
+
+
+/* List all the files in the current dir via console */
+DEF_CONSOLE_CMD(ConListFiles)
+{
+	int i;
+
+	if (argc == 0) {
+		IConsoleHelp("List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'");
+		return true;
+	}
+
+	BuildFileList();
+
+	for (i = 0; i < _fios_num; i++) {
+		const FiosItem *item = &_fios_list[i];
+		IConsolePrintF(_icolour_def, "%d) %s", i, item->title);
+	}
+
+	FiosFreeSavegameList();
+	return true;
+}
+
+/* Change the dir via console */
+DEF_CONSOLE_CMD(ConChangeDirectory)
+{
+	const FiosItem *item;
+	const char *file;
+
+	if (argc == 0) {
+		IConsoleHelp("Change the dir via console. Usage: 'cd <directory | number>'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	file = argv[1];
+	item = GetFiosItem(file);
+	if (item != NULL) {
+		switch (item->type) {
+			case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
+				FiosBrowseTo(item);
+				break;
+			default: IConsolePrintF(_icolour_err, "%s: Not a directory.", file);
+		}
+	} else {
+		IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
+	}
+
+	FiosFreeSavegameList();
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
+{
+	const char *path;
+
+	if (argc == 0) {
+		IConsoleHelp("Print out the current working directory. Usage: 'pwd'");
+		return true;
+	}
+
+	// XXX - Workaround for broken file handling
+	FiosGetSavegameList(SLD_LOAD_GAME);
+	FiosFreeSavegameList();
+
+	FiosGetDescText(&path, NULL);
+	IConsolePrint(_icolour_def, path);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConClearBuffer)
+{
+	if (argc == 0) {
+		IConsoleHelp("Clear the console buffer. Usage: 'clear'");
+		return true;
+	}
+
+	IConsoleClearBuffer();
+	InvalidateWindow(WC_CONSOLE, 0);
+	return true;
+}
+
+
+// ********************************* //
+// * Network Core Console Commands * //
+// ********************************* //
+#ifdef ENABLE_NETWORK
+
+DEF_CONSOLE_CMD(ConBan)
+{
+	NetworkClientInfo *ci;
+	const char *banip = NULL;
+	uint32 index;
+
+	if (argc == 0) {
+		IConsoleHelp("Ban a player from a network game. Usage: 'ban <ip | client-id>'");
+		IConsoleHelp("For client-id's, see the command 'clients'");
+		IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	if (strchr(argv[1], '.') == NULL) { // banning with ID
+		index = atoi(argv[1]);
+		ci = NetworkFindClientInfoFromIndex(index);
+	} else { // banning IP
+		ci = NetworkFindClientInfoFromIP(argv[1]);
+		if (ci == NULL) {
+			banip = argv[1];
+			index = (uint32)-1;
+		} else {
+			index = ci->client_index;
+		}
+	}
+
+	if (index == NETWORK_SERVER_INDEX) {
+		IConsoleError("Silly boy, you can not ban yourself!");
+		return true;
+	}
+
+	if (index == 0 || (ci == NULL && index != (uint32)-1)) {
+		IConsoleError("Invalid client");
+		return true;
+	}
+
+	if (ci != NULL) {
+		banip = inet_ntoa(*(struct in_addr *)&ci->client_ip);
+		SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
+		IConsolePrint(_icolour_def, "Client banned");
+	} else {
+		IConsolePrint(_icolour_def, "Client not online, banned IP");
+	}
+
+	/* Add user to ban-list */
+	for (index = 0; index < lengthof(_network_ban_list); index++) {
+		if (_network_ban_list[index] == NULL) {
+			_network_ban_list[index] = strdup(banip);
+			break;
+		}
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConUnBan)
+{
+	uint i, index;
+
+	if (argc == 0) {
+		IConsoleHelp("Unban a player from a network game. Usage: 'unban <ip | client-id>'");
+		IConsoleHelp("For a list of banned IP's, see the command 'banlist'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	index = (strchr(argv[1], '.') == NULL) ? atoi(argv[1]) : 0;
+	index--;
+
+	for (i = 0; i < lengthof(_network_ban_list); i++) {
+		if (_network_ban_list[i] == NULL) continue;
+
+		if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) {
+			free(_network_ban_list[i]);
+			_network_ban_list[i] = NULL;
+			IConsolePrint(_icolour_def, "IP unbanned.");
+			return true;
+		}
+	}
+
+	IConsolePrint(_icolour_def, "IP not in ban-list.");
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConBanList)
+{
+	uint i;
+
+	if (argc == 0) {
+		IConsoleHelp("List the IP's of banned clients: Usage 'banlist'");
+		return true;
+	}
+
+	IConsolePrint(_icolour_def, "Banlist: ");
+
+	for (i = 0; i < lengthof(_network_ban_list); i++) {
+		if (_network_ban_list[i] != NULL)
+			IConsolePrintF(_icolour_def, "  %d) %s", i + 1, _network_ban_list[i]);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConPauseGame)
+{
+	if (argc == 0) {
+		IConsoleHelp("Pause a network game. Usage: 'pause'");
+		return true;
+	}
+
+	if (_pause == 0) {
+		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+		IConsolePrint(_icolour_def, "Game paused.");
+	} else {
+		IConsolePrint(_icolour_def, "Game is already paused.");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConUnPauseGame)
+{
+	if (argc == 0) {
+		IConsoleHelp("Unpause a network game. Usage: 'unpause'");
+		return true;
+	}
+
+	if (_pause != 0) {
+		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+		IConsolePrint(_icolour_def, "Game unpaused.");
+	} else {
+		IConsolePrint(_icolour_def, "Game is already unpaused.");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConRcon)
+{
+	if (argc == 0) {
+		IConsoleHelp("Remote control the server from another client. Usage: 'rcon <password> <command>'");
+		IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent");
+		return true;
+	}
+
+	if (argc < 3) return false;
+
+	SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConStatus)
+{
+	static const char* const stat_str[] = {
+		"inactive",
+		"authorized",
+		"waiting",
+		"loading map",
+		"map done",
+		"ready",
+		"active"
+	};
+
+	const NetworkClientState *cs;
+
+	if (argc == 0) {
+		IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
+		return true;
+	}
+
+	FOR_ALL_CLIENTS(cs) {
+		int lag = NetworkCalculateLag(cs);
+		const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
+		const char* status;
+
+		status = (cs->status < lengthof(stat_str) ? stat_str[cs->status] : "unknown");
+		IConsolePrintF(8, "Client #%1d  name: '%s'  status: '%s'  frame-lag: %3d  company: %1d  IP: %s  unique-id: '%s'",
+			cs->index, ci->client_name, status, lag,
+			ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
+			GetPlayerIP(ci), ci->unique_id);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConServerInfo)
+{
+	const NetworkGameInfo *gi;
+
+	if (argc == 0) {
+		IConsoleHelp("List current and maximum client/player limits. Usage 'server_info'");
+		IConsoleHelp("You can change these values by setting the variables 'max_clients', 'max_companies' and 'max_spectators'");
+		return true;
+	}
+
+	gi = &_network_game_info;
+	IConsolePrintF(_icolour_def, "Current/maximum clients:    %2d/%2d", gi->clients_on, gi->clients_max);
+	IConsolePrintF(_icolour_def, "Current/maximum companies:  %2d/%2d", ActivePlayerCount(), gi->companies_max);
+	IConsolePrintF(_icolour_def, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), gi->spectators_max);
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount)
+{
+	/* XXX - hardcoded, string limiation -- TrueLight
+	 * XXX - also see network.c:NetworkStartup ~1356 */
+	if (_network_game_info.clients_max > 10) {
+		_network_game_info.clients_max = 10;
+		IConsoleError("Maximum clients out of bounds, truncating to limit.");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount)
+{
+	if (_network_game_info.companies_max > MAX_PLAYERS) {
+		_network_game_info.companies_max = MAX_PLAYERS;
+		IConsoleError("Maximum companies out of bounds, truncating to limit.");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount)
+{
+	/* XXX @see ConHookValidateMaxClientsCount */
+	if (_network_game_info.spectators_max > 10) {
+		_network_game_info.spectators_max = 10;
+		IConsoleError("Maximum spectators out of bounds, truncating to limit.");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookCheckMinPlayers)
+{
+	CheckMinPlayers();
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConKick)
+{
+	NetworkClientInfo *ci;
+	uint32 index;
+
+	if (argc == 0) {
+		IConsoleHelp("Kick a player from a network game. Usage: 'kick <ip | client-id>'");
+		IConsoleHelp("For client-id's, see the command 'clients'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	if (strchr(argv[1], '.') == NULL) {
+		index = atoi(argv[1]);
+		ci = NetworkFindClientInfoFromIndex(index);
+	} else {
+		ci = NetworkFindClientInfoFromIP(argv[1]);
+		index = (ci == NULL) ? 0 : ci->client_index;
+	}
+
+	if (index == NETWORK_SERVER_INDEX) {
+		IConsoleError("Silly boy, you can not kick yourself!");
+		return true;
+	}
+
+	if (index == 0) {
+		IConsoleError("Invalid client");
+		return true;
+	}
+
+	if (ci != NULL) {
+		SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
+	} else {
+		IConsoleError("Client not found");
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConResetCompany)
+{
+	const Player *p;
+	const NetworkClientState *cs;
+	const NetworkClientInfo *ci;
+	PlayerID index;
+
+	if (argc == 0) {
+		IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company <company-id>'");
+		IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Player 1 is 1, etc.");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	index = atoi(argv[1]) - 1;
+
+	/* Check valid range */
+	if (!IsValidPlayer(index)) {
+		IConsolePrintF(_icolour_err, "Company does not exist. Company-id must be between 1 and %d.", MAX_PLAYERS);
+		return true;
+	}
+
+	/* Check if company does exist */
+	p = GetPlayer(index);
+	if (!p->is_active) {
+		IConsoleError("Company does not exist.");
+		return true;
+	}
+
+	if (p->is_ai) {
+		IConsoleError("Company is owned by an AI.");
+		return true;
+	}
+
+	/* Check if the company has active players */
+	FOR_ALL_CLIENTS(cs) {
+		ci = DEREF_CLIENT_INFO(cs);
+		if (ci->client_playas == index) {
+			IConsoleError("Cannot remove company: a client is connected to that company.");
+			return true;
+		}
+	}
+	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+	if (ci->client_playas == index) {
+		IConsoleError("Cannot remove company: the server is connected to that company.");
+		return true;
+	}
+
+	/* It is safe to remove this company */
+	DoCommandP(0, 2, index, NULL, CMD_PLAYER_CTRL);
+	IConsolePrint(_icolour_def, "Company deleted.");
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConNetworkClients)
+{
+	NetworkClientInfo *ci;
+
+	if (argc == 0) {
+		IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'");
+		return true;
+	}
+
+	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+		IConsolePrintF(8, "Client #%1d  name: '%s'  company: %1d  IP: %s",
+		               ci->client_index, ci->client_name,
+		               ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
+		               GetPlayerIP(ci));
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConNetworkConnect)
+{
+	char *ip;
+	const char *port = NULL;
+	const char *player = NULL;
+	uint16 rport;
+
+	if (argc == 0) {
+		IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'");
+		IConsoleHelp("IP can contain port and player: 'IP[[#Player]:Port]', eg: 'server.ottd.org#2:443'");
+		IConsoleHelp("Player #255 is spectator all others are a certain company with Company 1 being #1");
+		return true;
+	}
+
+	if (argc < 2) return false;
+	if (_networking) NetworkDisconnect(); // we are in network-mode, first close it!
+
+	ip = argv[1];
+	/* Default settings: default port and new company */
+	rport = NETWORK_DEFAULT_PORT;
+	_network_playas = PLAYER_NEW_COMPANY;
+
+	ParseConnectionString(&player, &port, ip);
+
+	IConsolePrintF(_icolour_def, "Connecting to %s...", ip);
+	if (player != NULL) {
+		_network_playas = atoi(player);
+		IConsolePrintF(_icolour_def, "    player-no: %d", _network_playas);
+
+		/* From a user pov 0 is a new player, internally it's different and all
+		 * players are offset by one to ease up on users (eg players 1-8 not 0-7) */
+		if (_network_playas != PLAYER_SPECTATOR) {
+			_network_playas--;
+			if (!IsValidPlayer(_network_playas)) return false;
+		}
+	}
+	if (port != NULL) {
+		rport = atoi(port);
+		IConsolePrintF(_icolour_def, "    port: %s", port);
+	}
+
+	NetworkClientConnectGame(ip, rport);
+
+	return true;
+}
+
+#endif /* ENABLE_NETWORK */
+
+/* ******************************** */
+/*   script file console commands   */
+/* ******************************** */
+
+DEF_CONSOLE_CMD(ConExec)
+{
+	char cmdline[ICON_CMDLN_SIZE];
+	char *cmdptr;
+
+	if (argc == 0) {
+		IConsoleHelp("Execute a local script file. Usage: 'exec <script> <?>'");
+		return true;
+	}
+
+	if (argc < 2) return false;
+
+	_script_file = fopen(argv[1], "r");
+
+	if (_script_file == NULL) {
+		if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found");
+		return true;
+	}
+
+	_script_running = true;
+
+	while (_script_running && fgets(cmdline, sizeof(cmdline), _script_file) != NULL) {
+		/* Remove newline characters from the executing script */
+		for (cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) {
+			if (*cmdptr == '\n' || *cmdptr == '\r') {
+				*cmdptr = '\0';
+				break;
+			}
+		}
+		IConsoleCmdExec(cmdline);
+	}
+
+	if (ferror(_script_file))
+		IConsoleError("Encountered errror while trying to read from script file");
+
+	_script_running = false;
+	fclose(_script_file);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConReturn)
+{
+	if (argc == 0) {
+		IConsoleHelp("Stop executing a running script. Usage: 'return'");
+		return true;
+	}
+
+	_script_running = false;
+	return true;
+}
+
+/* **************************** */
+/*   default console commands   */
+/* **************************** */
+extern bool CloseConsoleLogIfActive(void);
+
+DEF_CONSOLE_CMD(ConScript)
+{
+	extern FILE* _iconsole_output_file;
+
+	if (argc == 0) {
+		IConsoleHelp("Start or stop logging console output to a file. Usage: 'script <filename>'");
+		IConsoleHelp("If filename is omitted, a running log is stopped if it is active");
+		return true;
+	}
+
+	if (!CloseConsoleLogIfActive()) {
+		if (argc < 2) return false;
+
+		IConsolePrintF(_icolour_def, "file output started to: %s", argv[1]);
+		_iconsole_output_file = fopen(argv[1], "ab");
+		if (_iconsole_output_file == NULL) IConsoleError("could not open file");
+	}
+
+	return true;
+}
+
+
+DEF_CONSOLE_CMD(ConEcho)
+{
+	if (argc == 0) {
+		IConsoleHelp("Print back the first argument to the console. Usage: 'echo <arg>'");
+		return true;
+	}
+
+	if (argc < 2) return false;
+	IConsolePrint(_icolour_def, argv[1]);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConEchoC)
+{
+	if (argc == 0) {
+		IConsoleHelp("Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'");
+		return true;
+	}
+
+	if (argc < 3) return false;
+	IConsolePrint(atoi(argv[1]), argv[2]);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConNewGame)
+{
+	if (argc == 0) {
+		IConsoleHelp("Start a new game. Usage: 'newgame [seed]'");
+		IConsoleHelp("The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
+		return true;
+	}
+
+	StartNewGameWithoutGUI((argc == 2) ? (uint)atoi(argv[1]) : GENERATE_NEW_SEED);
+	return true;
+}
+
+extern void SwitchMode(int new_mode);
+
+DEF_CONSOLE_CMD(ConRestart)
+{
+	if (argc == 0) {
+		IConsoleHelp("Restart game. Usage: 'restart'");
+		IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
+		return true;
+	}
+
+	/* Don't copy the _newgame pointers to the real pointers, so call SwitchMode directly */
+	_patches.map_x = MapLogX();
+	_patches.map_y = FindFirstBit(MapSizeY());
+	SwitchMode(SM_NEWGAME);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConGetSeed)
+{
+	if (argc == 0) {
+		IConsoleHelp("Returns the seed used to create this game. Usage: 'getseed'");
+		IConsoleHelp("The seed can be used to reproduce the exact same map as the game started with.");
+		return true;
+	}
+
+	IConsolePrintF(_icolour_def, "Generation Seed: %u", _patches.generation_seed);
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConAlias)
+{
+	IConsoleAlias *alias;
+
+	if (argc == 0) {
+		IConsoleHelp("Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'");
+		return true;
+	}
+
+	if (argc < 3) return false;
+
+	alias = IConsoleAliasGet(argv[1]);
+	if (alias == NULL) {
+		IConsoleAliasRegister(argv[1], argv[2]);
+	} else {
+		free(alias->cmdline);
+		alias->cmdline = strdup(argv[2]);
+	}
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConScreenShot)
+{
+	if (argc == 0) {
+		IConsoleHelp("Create a screenshot of the game. Usage: 'screenshot [big | no_con]'");
+		IConsoleHelp("'big' makes a screenshot of the whole map, 'no_con' hides the console to create the screenshot");
+		return true;
+	}
+
+	if (argc > 3) return false;
+
+	SetScreenshotType(SC_VIEWPORT);
+	if (argc > 1) {
+		if (strcmp(argv[1], "big") == 0 || (argc == 3 && strcmp(argv[2], "big") == 0))
+			SetScreenshotType(SC_WORLD);
+
+		if (strcmp(argv[1], "no_con") == 0 || (argc == 3 && strcmp(argv[2], "no_con") == 0))
+			IConsoleClose();
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConInfoVar)
+{
+	static const char *_icon_vartypes[] = {"boolean", "byte", "uint16", "uint32", "int16", "int32", "string"};
+	const IConsoleVar *var;
+
+	if (argc == 0) {
+		IConsoleHelp("Print out debugging information about a variable. Usage: 'info_var <var>'");
+		return true;
+	}
+
+	if (argc < 2) return false;
+
+	var = IConsoleVarGet(argv[1]);
+	if (var == NULL) {
+		IConsoleError("the given variable was not found");
+		return true;
+	}
+
+	IConsolePrintF(_icolour_def, "variable name: %s", var->name);
+	IConsolePrintF(_icolour_def, "variable type: %s", _icon_vartypes[var->type]);
+	IConsolePrintF(_icolour_def, "variable addr: 0x%X", var->addr);
+
+	if (var->hook.access) IConsoleWarning("variable is access hooked");
+	if (var->hook.pre) IConsoleWarning("variable is pre hooked");
+	if (var->hook.post) IConsoleWarning("variable is post hooked");
+	return true;
+}
+
+
+DEF_CONSOLE_CMD(ConInfoCmd)
+{
+	const IConsoleCmd *cmd;
+
+	if (argc == 0) {
+		IConsoleHelp("Print out debugging information about a command. Usage: 'info_cmd <cmd>'");
+		return true;
+	}
+
+	if (argc < 2) return false;
+
+	cmd = IConsoleCmdGet(argv[1]);
+	if (cmd == NULL) {
+		IConsoleError("the given command was not found");
+		return true;
+	}
+
+	IConsolePrintF(_icolour_def, "command name: %s", cmd->name);
+	IConsolePrintF(_icolour_def, "command proc: 0x%X", cmd->proc);
+
+	if (cmd->hook.access) IConsoleWarning("command is access hooked");
+	if (cmd->hook.pre) IConsoleWarning("command is pre hooked");
+	if (cmd->hook.post) IConsoleWarning("command is post hooked");
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConDebugLevel)
+{
+	if (argc == 0) {
+		IConsoleHelp("Get/set the default debugging level for the game. Usage: 'debug_level [<level>]'");
+		IConsoleHelp("Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'s");
+		return true;
+	}
+
+	if (argc > 2) return false;
+
+	if (argc == 1) {
+		IConsolePrintF(_icolour_def, "Current debug-level: '%s'", GetDebugString());
+	} else {
+		SetDebugString(argv[1]);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConExit)
+{
+	if (argc == 0) {
+		IConsoleHelp("Exit the game. Usage: 'exit'");
+		return true;
+	}
+
+	_exit_game = true;
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConPart)
+{
+	if (argc == 0) {
+		IConsoleHelp("Leave the currently joined/running game (only ingame). Usage: 'part'");
+		return true;
+	}
+
+	if (_game_mode != GM_NORMAL) return false;
+
+	_switch_mode = SM_MENU;
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConHelp)
+{
+	if (argc == 2) {
+		const IConsoleCmd *cmd;
+		const IConsoleVar *var;
+		const IConsoleAlias *alias;
+
+		cmd = IConsoleCmdGet(argv[1]);
+		if (cmd != NULL) {
+			cmd->proc(0, NULL);
+			return true;
+		}
+
+		alias = IConsoleAliasGet(argv[1]);
+		if (alias != NULL) {
+			cmd = IConsoleCmdGet(alias->cmdline);
+			if (cmd != NULL) {
+				cmd->proc(0, NULL);
+				return true;
+			}
+			IConsolePrintF(_icolour_err, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline);
+			return true;
+		}
+
+		var = IConsoleVarGet(argv[1]);
+		if (var != NULL && var->help != NULL) {
+			IConsoleHelp(var->help);
+			return true;
+		}
+
+		IConsoleError("command or variable not found");
+		return true;
+	}
+
+	IConsolePrint(13, " ---- OpenTTD Console Help ---- ");
+	IConsolePrint( 1, " - variables: [command to list all variables: list_vars]");
+	IConsolePrint( 1, " set value with '<var> = <value>', use '++/--' to in-or decrement");
+	IConsolePrint( 1, " or omit '=' and just '<var> <value>'. get value with typing '<var>'");
+	IConsolePrint( 1, " - commands: [command to list all commands: list_cmds]");
+	IConsolePrint( 1, " call commands with '<command> <arg2> <arg3>...'");
+	IConsolePrint( 1, " - to assign strings, or use them as arguments, enclose it within quotes");
+	IConsolePrint( 1, " like this: '<command> \"string argument with spaces\"'");
+	IConsolePrint( 1, " - use 'help <command> | <variable>' to get specific information");
+	IConsolePrint( 1, " - scroll console output with shift + (up | down) | (pageup | pagedown))");
+	IConsolePrint( 1, " - scroll console input history with the up | down arrows");
+	IConsolePrint( 1, "");
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConListCommands)
+{
+	const IConsoleCmd *cmd;
+	size_t l = 0;
+
+	if (argc == 0) {
+		IConsoleHelp("List all registered commands. Usage: 'list_cmds [<pre-filter>]'");
+		return true;
+	}
+
+	if (argv[1] != NULL) l = strlen(argv[1]);
+
+	for (cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) {
+		if (argv[1] == NULL || strncmp(cmd->name, argv[1], l) == 0) {
+				IConsolePrintF(_icolour_def, "%s", cmd->name);
+		}
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConListVariables)
+{
+	const IConsoleVar *var;
+	size_t l = 0;
+
+	if (argc == 0) {
+		IConsoleHelp("List all registered variables. Usage: 'list_vars [<pre-filter>]'");
+		return true;
+	}
+
+	if (argv[1] != NULL) l = strlen(argv[1]);
+
+	for (var = _iconsole_vars; var != NULL; var = var->next) {
+		if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0)
+			IConsolePrintF(_icolour_def, "%s", var->name);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConListAliases)
+{
+	const IConsoleAlias *alias;
+	size_t l = 0;
+
+	if (argc == 0) {
+		IConsoleHelp("List all registered aliases. Usage: 'list_aliases [<pre-filter>]'");
+		return true;
+	}
+
+	if (argv[1] != NULL) l = strlen(argv[1]);
+
+	for (alias = _iconsole_aliases; alias != NULL; alias = alias->next) {
+		if (argv[1] == NULL || strncmp(alias->name, argv[1], l) == 0)
+			IConsolePrintF(_icolour_def, "%s => %s", alias->name, alias->cmdline);
+	}
+
+	return true;
+}
+
+#ifdef ENABLE_NETWORK
+
+DEF_CONSOLE_CMD(ConSay)
+{
+	if (argc == 0) {
+		IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'");
+		return true;
+	}
+
+	if (argc != 2) return false;
+
+	if (!_network_server) {
+		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
+	} else {
+		NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX);
+	}
+
+	return true;
+}
+
+#ifdef ENABLE_NETWORK
+	#include "table/strings.h"
+#endif /* ENABLE_NETWORK */
+
+DEF_CONSOLE_CMD(ConPlayers)
+{
+	Player *p;
+
+	if (argc == 0) {
+		IConsoleHelp("List the in-game details of all clients connected to the server. Usage 'players'");
+		return true;
+	}
+	NetworkPopulateCompanyInfo();
+
+	FOR_ALL_PLAYERS(p) {
+		char buffer[512];
+
+		if (!p->is_active) continue;
+
+		GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index], lastof(buffer));
+		IConsolePrintF(8, "#:%d(%s) Company Name: '%s'  Year Founded: %d  Money: %d  Loan: %d  Value: %" OTTD_PRINTF64 "d  (T:%d, R:%d, P:%d, S:%d)",
+			p->index + 1, buffer, _network_player_info[p->index].company_name, p->inaugurated_year, p->player_money, p->current_loan, CalculateCompanyValue(p),
+			/* trains      */ _network_player_info[p->index].num_vehicle[0],
+			/* lorry + bus */ _network_player_info[p->index].num_vehicle[1] + _network_player_info[p->index].num_vehicle[2],
+			/* planes      */ _network_player_info[p->index].num_vehicle[3],
+			/* ships       */ _network_player_info[p->index].num_vehicle[4]);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConSayPlayer)
+{
+	if (argc == 0) {
+		IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_player <player-no> \"<msg>\"'");
+		IConsoleHelp("PlayerNo is the player that plays as company <playerno>, 1 through max_players");
+		return true;
+	}
+
+	if (argc != 3) return false;
+
+	if (atoi(argv[1]) < 1 || atoi(argv[1]) > MAX_PLAYERS) {
+		IConsolePrintF(_icolour_def, "Unknown player. Player range is between 1 and %d.", MAX_PLAYERS);
+		return true;
+	}
+
+	if (!_network_server) {
+		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2]);
+	} else {
+		NetworkServer_HandleChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConSayClient)
+{
+	if (argc == 0) {
+		IConsoleHelp("Chat to a certain player in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'");
+		IConsoleHelp("For client-id's, see the command 'clients'");
+		return true;
+	}
+
+	if (argc != 3) return false;
+
+	if (!_network_server) {
+		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
+	} else {
+		NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookServerPW)
+{
+	if (strcmp(_network_server_password, "*") == 0) {
+		_network_server_password[0] = '\0';
+		_network_game_info.use_password = 0;
+	} else {
+		ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
+		_network_game_info.use_password = 1;
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookRconPW)
+{
+	if (strcmp(_network_rcon_password, "*") == 0)
+		_network_rcon_password[0] = '\0';
+
+	ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password));
+
+	return true;
+}
+
+/* Also use from within player_gui to change the password graphically */
+bool NetworkChangeCompanyPassword(byte argc, char *argv[])
+{
+	if (argc == 0) {
+		if (!IsValidPlayer(_local_player)) return true; // dedicated server
+		IConsolePrintF(_icolour_warn, "Current value for 'company_pw': %s", _network_player_info[_local_player].password);
+		return true;
+	}
+
+	if (!IsValidPlayer(_local_player)) {
+		IConsoleError("You have to own a company to make use of this command.");
+		return false;
+	}
+
+	if (argc != 1) return false;
+
+	if (strcmp(argv[0], "*") == 0) argv[0][0] = '\0';
+
+	ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password));
+
+	if (!_network_server)
+		SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
+
+	IConsolePrintF(_icolour_warn, "'company_pw' changed to:  %s", _network_player_info[_local_player].password);
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConProcPlayerName)
+{
+	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
+
+	if (ci == NULL) return false;
+
+	// Don't change the name if it is the same as the old name
+	if (strcmp(ci->client_name, _network_player_name) != 0) {
+		if (!_network_server) {
+			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_network_player_name);
+		} else {
+			if (NetworkFindName(_network_player_name)) {
+				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", _network_player_name);
+				ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
+				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
+			}
+		}
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookServerName)
+{
+	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
+	return true;
+}
+
+DEF_CONSOLE_HOOK(ConHookServerAdvertise)
+{
+	if (!_network_advertise) // remove us from advertising
+		NetworkUDPRemoveAdvertise();
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConProcServerIP)
+{
+	if (argc == 0) {
+		IConsolePrintF(_icolour_warn, "Current value for 'server_ip': %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
+		return true;
+	}
+
+	if (argc != 1) return false;
+
+	_network_server_bind_ip = (strcmp(argv[0], "all") == 0) ? inet_addr("0.0.0.0") : inet_addr(argv[0]);
+	snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
+	IConsolePrintF(_icolour_warn, "'server_ip' changed to:  %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
+	return true;
+}
+#endif /* ENABLE_NETWORK */
+
+DEF_CONSOLE_CMD(ConPatch)
+{
+	if (argc == 0) {
+		IConsoleHelp("Change patch variables for all players. Usage: 'patch <name> [<value>]'");
+		IConsoleHelp("Omitting <value> will print out the current value of the patch-setting.");
+		return true;
+	}
+
+	if (argc == 1 || argc > 3) return false;
+
+	if (argc == 2) {
+		IConsoleGetPatchSetting(argv[1]);
+	} else {
+		uint32 val;
+
+		if (GetArgumentInteger(&val, argv[2])) {
+			if (!IConsoleSetPatchSetting(argv[1], val)) {
+				IConsoleError("This command/variable is only available to a network server.");
+			}
+		}
+	}
+
+	return true;
+}
+
+DEF_CONSOLE_CMD(ConListDumpVariables)
+{
+	const IConsoleVar *var;
+	size_t l = 0;
+
+	if (argc == 0) {
+		IConsoleHelp("List all variables with their value. Usage: 'dump_vars [<pre-filter>]'");
+		return true;
+	}
+
+	if (argv[1] != NULL) l = strlen(argv[1]);
+
+	for (var = _iconsole_vars; var != NULL; var = var->next) {
+		if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0)
+			IConsoleVarPrintGetValue(var);
+	}
+
+	return true;
+}
+
+
+#ifdef _DEBUG
+/* ****************************************** */
+/*  debug commands and variables */
+/* ****************************************** */
+
+static void IConsoleDebugLibRegister(void)
+{
+	// debugging variables and functions
+	extern bool _stdlib_con_developer; /* XXX extern in .c */
+
+	IConsoleVarRegister("con_developer",    &_stdlib_con_developer, ICONSOLE_VAR_BOOLEAN, "Enable/disable console debugging information (internal)");
+	IConsoleCmdRegister("resettile",        ConResetTile);
+	IConsoleCmdRegister("stopall",          ConStopAllVehicles);
+	IConsoleAliasRegister("dbg_echo",       "echo %A; echo %B");
+	IConsoleAliasRegister("dbg_echo2",      "echo %!");
+}
+#endif
+
+/* ****************************************** */
+/*  console command and variable registration */
+/* ****************************************** */
+
+void IConsoleStdLibRegister(void)
+{
+	// stdlib
+	extern byte _stdlib_developer; /* XXX extern in .c */
+
+	// default variables and functions
+	IConsoleCmdRegister("debug_level",  ConDebugLevel);
+	IConsoleCmdRegister("dump_vars",    ConListDumpVariables);
+	IConsoleCmdRegister("echo",         ConEcho);
+	IConsoleCmdRegister("echoc",        ConEchoC);
+	IConsoleCmdRegister("exec",         ConExec);
+	IConsoleCmdRegister("exit",         ConExit);
+	IConsoleCmdRegister("part",         ConPart);
+	IConsoleCmdRegister("help",         ConHelp);
+	IConsoleCmdRegister("info_cmd",     ConInfoCmd);
+	IConsoleCmdRegister("info_var",     ConInfoVar);
+	IConsoleCmdRegister("list_cmds",    ConListCommands);
+	IConsoleCmdRegister("list_vars",    ConListVariables);
+	IConsoleCmdRegister("list_aliases", ConListAliases);
+	IConsoleCmdRegister("newgame",      ConNewGame);
+	IConsoleCmdRegister("restart",      ConRestart);
+	IConsoleCmdRegister("getseed",      ConGetSeed);
+	IConsoleCmdRegister("quit",         ConExit);
+	IConsoleCmdRegister("resetengines", ConResetEngines);
+	IConsoleCmdRegister("return",       ConReturn);
+	IConsoleCmdRegister("screenshot",   ConScreenShot);
+	IConsoleCmdRegister("script",       ConScript);
+	IConsoleCmdRegister("scrollto",     ConScrollToTile);
+	IConsoleCmdRegister("alias",        ConAlias);
+	IConsoleCmdRegister("load",         ConLoad);
+	IConsoleCmdRegister("rm",           ConRemove);
+	IConsoleCmdRegister("save",         ConSave);
+	IConsoleCmdRegister("saveconfig",   ConSaveConfig);
+	IConsoleCmdRegister("ls",           ConListFiles);
+	IConsoleCmdRegister("cd",           ConChangeDirectory);
+	IConsoleCmdRegister("pwd",          ConPrintWorkingDirectory);
+	IConsoleCmdRegister("clear",        ConClearBuffer);
+	IConsoleCmdRegister("patch",        ConPatch);
+
+	IConsoleAliasRegister("dir",      "ls");
+	IConsoleAliasRegister("del",      "rm %+");
+	IConsoleAliasRegister("newmap",   "newgame");
+	IConsoleAliasRegister("new_map",  "newgame");
+	IConsoleAliasRegister("new_game", "newgame");
+
+
+	IConsoleVarRegister("developer", &_stdlib_developer, ICONSOLE_VAR_BYTE, "Redirect debugging output from the console/command line to the ingame console (value 2). Default value: 1");
+
+	/* networking variables and functions */
+#ifdef ENABLE_NETWORK
+	/* Network hooks; only active in network */
+	IConsoleCmdHookAdd ("resetengines", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork);
+
+	/*** Networking commands ***/
+	IConsoleCmdRegister("say",             ConSay);
+	IConsoleCmdHookAdd("say",              ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+	IConsoleCmdRegister("players",             ConPlayers);
+	IConsoleCmdHookAdd("players",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("say_player",      ConSayPlayer);
+	IConsoleCmdHookAdd("say_player",       ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+	IConsoleCmdRegister("say_client",      ConSayClient);
+	IConsoleCmdHookAdd("say_client",       ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+
+	IConsoleCmdRegister("connect",         ConNetworkConnect);
+	IConsoleCmdHookAdd("connect",          ICONSOLE_HOOK_ACCESS, ConHookClientOnly);
+	IConsoleAliasRegister("join",          "connect %A");
+	IConsoleCmdRegister("clients",         ConNetworkClients);
+	IConsoleCmdHookAdd("clients",          ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+	IConsoleCmdRegister("status",          ConStatus);
+	IConsoleCmdHookAdd("status",           ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("server_info",     ConServerInfo);
+	IConsoleCmdHookAdd("server_info",      ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleAliasRegister("info",          "server_info");
+	IConsoleCmdRegister("rcon",            ConRcon);
+	IConsoleCmdHookAdd("rcon",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+
+	IConsoleCmdRegister("reset_company",   ConResetCompany);
+	IConsoleCmdHookAdd("reset_company",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleAliasRegister("clean_company", "reset_company %A");
+	IConsoleCmdRegister("kick",            ConKick);
+	IConsoleCmdHookAdd("kick",             ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("ban",             ConBan);
+	IConsoleCmdHookAdd("ban",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("unban",           ConUnBan);
+	IConsoleCmdHookAdd("unban",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("banlist",         ConBanList);
+	IConsoleCmdHookAdd("banlist",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+
+	IConsoleCmdRegister("pause",           ConPauseGame);
+	IConsoleCmdHookAdd("pause",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("unpause",         ConUnPauseGame);
+	IConsoleCmdHookAdd("unpause",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+
+	/*** Networking variables ***/
+	IConsoleVarRegister("net_frame_freq",        &_network_frame_freq, ICONSOLE_VAR_BYTE, "The amount of frames before a command will be (visibly) executed. Default value: 1");
+	IConsoleVarHookAdd("net_frame_freq",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarRegister("net_sync_freq",         &_network_sync_freq,  ICONSOLE_VAR_UINT16, "The amount of frames to check if the game is still in sync. Default value: 100");
+	IConsoleVarHookAdd("net_sync_freq",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+
+	IConsoleVarStringRegister("server_pw",       &_network_server_password, sizeof(_network_server_password), "Set the server password to protect your server. Use '*' to clear the password");
+	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("server_pw",              ICONSOLE_HOOK_POST_ACTION, ConHookServerPW);
+	IConsoleAliasRegister("server_password",     "server_pw %+");
+	IConsoleVarStringRegister("rcon_pw",         &_network_rcon_password, sizeof(_network_rcon_password), "Set the rcon-password to change server behaviour. Use '*' to disable rcon");
+	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("rcon_pw",                ICONSOLE_HOOK_POST_ACTION, ConHookRconPW);
+	IConsoleAliasRegister("rcon_password",       "rcon_pw %+");
+	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");
+	IConsoleVarHookAdd("company_pw",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+	IConsoleVarProcAdd("company_pw",             NetworkChangeCompanyPassword);
+	IConsoleAliasRegister("company_password",    "company_pw %+");
+
+	IConsoleVarStringRegister("name",            &_network_player_name, sizeof(_network_player_name), "Set your name for multiplayer");
+	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
+	IConsoleVarHookAdd("name",                   ICONSOLE_HOOK_POST_ACTION, ConProcPlayerName);
+	IConsoleVarStringRegister("server_name",     &_network_server_name, sizeof(_network_server_name), "Set the name of the server for multiplayer");
+	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("server_name",            ICONSOLE_HOOK_POST_ACTION, ConHookServerName);
+
+	IConsoleVarRegister("server_port",           &_network_server_port, ICONSOLE_VAR_UINT32, "Set the server port. Changes take effect the next time you start a server");
+	IConsoleVarRegister("server_ip",             &_network_server_bind_ip, ICONSOLE_VAR_UINT32, "Set the IP the server binds to. Changes take effect the next time you start a server. Use 'all' to bind to any IP.");
+	IConsoleVarProcAdd("server_ip",              ConProcServerIP);
+	IConsoleAliasRegister("server_bind_ip",      "server_ip %+");
+	IConsoleAliasRegister("server_ip_bind",      "server_ip %+");
+	IConsoleAliasRegister("server_bind",         "server_ip %+");
+	IConsoleVarRegister("server_advertise",      &_network_advertise, ICONSOLE_VAR_BOOLEAN, "Set if the server will advertise to the master server and show up there");
+	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("server_advertise",       ICONSOLE_HOOK_POST_ACTION, ConHookServerAdvertise);
+
+	IConsoleVarRegister("max_clients",           &_network_game_info.clients_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of connected players during runtime. Default value: 10");
+	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("max_clients",            ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxClientsCount);
+	IConsoleVarRegister("max_companies",         &_network_game_info.companies_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active companies during runtime. Default value: 8");
+	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("max_companies",          ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxCompaniesCount);
+	IConsoleVarRegister("max_spectators",        &_network_game_info.spectators_max, ICONSOLE_VAR_BYTE, "Control the maximum amount of active spectators during runtime. Default value: 9");
+	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("max_spectators",         ICONSOLE_HOOK_POST_ACTION, ConHookValidateMaxSpectatorsCount);
+
+	IConsoleVarRegister("max_join_time",         &_network_max_join_time, ICONSOLE_VAR_UINT16, "Set the maximum amount of time (ticks) a client is allowed to join. Default value: 500");
+
+	IConsoleVarRegister("pause_on_join",         &_network_pause_on_join, ICONSOLE_VAR_BOOLEAN, "Set if the server should pause gameplay while a client is joining. This might help slow users");
+	IConsoleVarHookAdd("pause_on_join",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+
+	IConsoleVarRegister("autoclean_companies",   &_network_autoclean_companies, ICONSOLE_VAR_BOOLEAN, "Automatically shut down inactive companies to free them up for other players. Customize with 'autoclean_(un)protected'");
+	IConsoleVarHookAdd("autoclean_companies",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarRegister("autoclean_protected",   &_network_autoclean_protected, ICONSOLE_VAR_BYTE, "Automatically remove the password from an inactive company after the given amount of months");
+	IConsoleVarHookAdd("autoclean_protected",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarRegister("autoclean_unprotected", &_network_autoclean_unprotected, ICONSOLE_VAR_BYTE, "Automatically shut down inactive companies after the given amount of months");
+	IConsoleVarHookAdd("autoclean_unprotected",  ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarRegister("restart_game_year",     &_network_restart_game_year, ICONSOLE_VAR_UINT16, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this");
+	IConsoleVarHookAdd("restart_game_year",      ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+
+	IConsoleVarRegister("min_players",           &_network_min_players, ICONSOLE_VAR_BYTE, "Automatically pause the game when the number of active players passes below the given amount");
+	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleVarHookAdd("min_players",            ICONSOLE_HOOK_POST_ACTION, ConHookCheckMinPlayers);
+
+#endif /* ENABLE_NETWORK */
+
+	// debugging stuff
+#ifdef _DEBUG
+	IConsoleDebugLibRegister();
+#endif
+}
deleted file mode 100644
--- a/src/currency.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "news.h"
-#include "variables.h"
-#include "table/strings.h"
-#include "date.h"
-
-	//   exchange rate    prefix             symbol_pos
-	//   |  separator        |     postfix   |
-	//   |   |    Euro year  |       |       |    name
-	//   |   |    |          |       |       |    |
-static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
-	{    1, ',', CF_NOEURO, "£",    "",      0,  STR_CURR_GBP    }, // british pounds
-	{    2, ',', CF_NOEURO, "$",    "",      0,  STR_CURR_USD    }, // us dollars
-	{    2, ',', CF_ISEURO, "€",    "",      0,  STR_CURR_EUR    }, // Euro
-	{  220, ',', CF_NOEURO, "Â¥",    "",      0,  STR_CURR_YEN    }, // yen
-	{   20, ',', 2002,      "",     " S.",   1,  STR_CURR_ATS    }, // austrian schilling
-	{   59, ',', 2002,      "BEF ", "",      0,  STR_CURR_BEF    }, // belgian franc
-	{    2, ',', CF_NOEURO, "CHF ", "",      0,  STR_CURR_CHF    }, // swiss franc
-	{   41, ',', CF_NOEURO, "",     " KÄ",   1,  STR_CURR_CZK    }, // czech koruna
-	{    3, '.', 2002,      "DM ",  "",      0,  STR_CURR_DEM    }, // deutsche mark
-	{   11, '.', CF_NOEURO, "",     " kr",   1,  STR_CURR_DKK    }, // danish krone
-	{  245, '.', 2002,      "Pts ", "",      0,  STR_CURR_ESP    }, // spanish pesetas
-	{    9, ',', 2002,      "",     " mk",   1,  STR_CURR_FIM    }, // finnish markka
-	{   10, '.', 2002,      "FF ",  "",      0,  STR_CURR_FRF    }, // french francs
-	{  500, ',', 2002,      "",     "Dr.",   1,  STR_CURR_GRD    }, // greek drachma
-	{  378, ',', 2010,      "",     " Ft",   1,  STR_CURR_HUF    }, // hungarian forint
-	{  130, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_ISK    }, // icelandic krona
-	{ 2850, ',', 2002,      "",     " L.",   1,  STR_CURR_ITL    }, // italian lira
-	{    3, ',', 2002,      "NLG ", "",      0,  STR_CURR_NLG    }, // dutch gulden
-	{   12, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_NOK    }, // norwegian krone
-	{    6, ' ', CF_NOEURO, "",     " zl",   1,  STR_CURR_PLN    }, // polish zloty
-	{    5, '.', CF_NOEURO, "",     " Lei",  1,  STR_CURR_ROL    }, // romanian Lei
-	{   50, ' ', CF_NOEURO, "",     " p",    1,  STR_CURR_RUR    }, // russian rouble
-	{  352, '.', CF_NOEURO, "",     " SIT",  1,  STR_CURR_SIT    }, // slovenian tolar
-	{   13, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_SEK    }, // swedish krona
-	{    3, '.', CF_NOEURO, "",     " YTL",  1,  STR_CURR_YTL    }, // turkish lira
-	{   52, ',', CF_NOEURO, "",     " Sk",   1,  STR_CURR_SKK    }, // slovak koruna
-	{    4, ',', CF_NOEURO, "R$ ",  "",      0,  STR_CURR_BRR    }, // brazil real
-	{    1, ' ', CF_NOEURO, "",     "",      2,  STR_CURR_CUSTOM }, // custom currency
-};
-
-/* Array of currencies used by the system */
-CurrencySpec _currency_specs[NUM_CURRENCY];
-
-/**
- * These enums are only declared in order to make sens
- * out of the TTDPatch_To_OTTDIndex array that will follow
- * Every currency used by Ottd is there, just in case TTDPatch will
- * add those missing in its code
- **/
-enum {
-	CURR_GBP,
-	CURR_USD,
-	CURR_EUR,
-	CURR_YEN,
-	CURR_ATS,
-	CURR_BEF,
-	CURR_CHF,
-	CURR_CZK,
-	CURR_DEM,
-	CURR_DKK,
-	CURR_ESP,
-	CURR_FIM,
-	CURR_FRF,
-	CURR_GRD,
-	CURR_HUF,
-	CURR_ISK,
-	CURR_ITL,
-	CURR_NLG,
-	CURR_NOK,
-	CURR_PLN,
-	CURR_ROL,
-	CURR_RUR,
-	CURR_SIT,
-	CURR_SEK,
-	CURR_YTL,
-};
-
-/**
- * This array represent the position of OpenTTD's currencies,
- * compared to TTDPatch's ones.
- * When a grf sends currencies, they are based on the order defined by TTDPatch.
- * So, we must reindex them to our own order.
- **/
-const byte TTDPatch_To_OTTDIndex[] =
-{
-	CURR_GBP,
-	CURR_USD,
-	CURR_FRF,
-	CURR_DEM,
-	CURR_YEN,
-	CURR_ESP,
-	CURR_HUF,
-	CURR_PLN,
-	CURR_ATS,
-	CURR_BEF,
-	CURR_DKK,
-	CURR_FIM,
-	CURR_GRD,
-	CURR_CHF,
-	CURR_NLG,
-	CURR_ITL,
-	CURR_SEK,
-	CURR_RUR,
-	CURR_EUR,
-};
-
-/**
- * Will return the ottd's index correspondance to
- * the ttdpatch's id.  If the id is bigger then the array,
- * it is  a grf written for ottd, thus returning the same id.
- * Only called from newgrf.c
- * @param grfcurr_id currency id coming from newgrf
- * @return the corrected index
- **/
-byte GetNewgrfCurrencyIdConverted(byte grfcurr_id)
-{
-	return (grfcurr_id >= lengthof(TTDPatch_To_OTTDIndex)) ? grfcurr_id : TTDPatch_To_OTTDIndex[grfcurr_id];
-}
-
-/* get a mask of the allowed currencies depending on the year */
-uint GetMaskOfAllowedCurrencies(void)
-{
-	uint mask = 0;
-	uint i;
-
-	for (i = 0; i < NUM_CURRENCY; i++) {
-		Year to_euro = _currency_specs[i].to_euro;
-
-		if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue;
-		if (to_euro == CF_ISEURO && _cur_year < 2000) continue;
-		mask |= (1 << i);
-	}
-	mask |= (1 << CUSTOM_CURRENCY_ID); // always allow custom currency
-	return mask;
-}
-
-/**
- * Verify if the currency chosen by the user is about to be converted to Euro
- **/
-void CheckSwitchToEuro(void)
-{
-	if (_currency_specs[_opt.currency].to_euro != CF_NOEURO &&
-			_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
-			_cur_year >= _currency_specs[_opt.currency].to_euro) {
-		_opt.currency = 2; // this is the index of euro above.
-		AddNewsItem(STR_EURO_INTRODUCE, NEWS_FLAGS(NM_NORMAL, 0, NT_ECONOMY, 0), 0, 0);
-	}
-}
-
-/**
- * Called only from newgrf.c.  Will fill _currency_specs array with
- * default values from origin_currency_specs
- **/
-void ResetCurrencies(void)
-{
-	memcpy(&_currency_specs, &origin_currency_specs, sizeof(origin_currency_specs));
-}
-
-/**
- * Build a list of currency names StringIDs to use in a dropdown list
- * @return Pointer to a (static) array of StringIDs
- */
-StringID* BuildCurrencyDropdown(void)
-{
-	/* Allow room for all currencies, plus a terminator entry */
-	static StringID names[CUSTOM_CURRENCY_ID];
-	uint i;
-
-	/* Add each name */
-	for (i = 0; i < NUM_CURRENCY; i++) {
-		names[i] = _currency_specs[i].name;
-	}
-	/* Terminate the list */
-	names[i] = INVALID_STRING_ID;
-
-	return names;
-}
new file mode 100644
--- /dev/null
+++ b/src/currency.cpp
@@ -0,0 +1,182 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "news.h"
+#include "variables.h"
+#include "table/strings.h"
+#include "date.h"
+
+	//   exchange rate    prefix             symbol_pos
+	//   |  separator        |     postfix   |
+	//   |   |    Euro year  |       |       |    name
+	//   |   |    |          |       |       |    |
+static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
+	{    1, ',', CF_NOEURO, "£",    "",      0,  STR_CURR_GBP    }, // british pounds
+	{    2, ',', CF_NOEURO, "$",    "",      0,  STR_CURR_USD    }, // us dollars
+	{    2, ',', CF_ISEURO, "€",    "",      0,  STR_CURR_EUR    }, // Euro
+	{  220, ',', CF_NOEURO, "Â¥",    "",      0,  STR_CURR_YEN    }, // yen
+	{   20, ',', 2002,      "",     " S.",   1,  STR_CURR_ATS    }, // austrian schilling
+	{   59, ',', 2002,      "BEF ", "",      0,  STR_CURR_BEF    }, // belgian franc
+	{    2, ',', CF_NOEURO, "CHF ", "",      0,  STR_CURR_CHF    }, // swiss franc
+	{   41, ',', CF_NOEURO, "",     " KÄ",   1,  STR_CURR_CZK    }, // czech koruna
+	{    3, '.', 2002,      "DM ",  "",      0,  STR_CURR_DEM    }, // deutsche mark
+	{   11, '.', CF_NOEURO, "",     " kr",   1,  STR_CURR_DKK    }, // danish krone
+	{  245, '.', 2002,      "Pts ", "",      0,  STR_CURR_ESP    }, // spanish pesetas
+	{    9, ',', 2002,      "",     " mk",   1,  STR_CURR_FIM    }, // finnish markka
+	{   10, '.', 2002,      "FF ",  "",      0,  STR_CURR_FRF    }, // french francs
+	{  500, ',', 2002,      "",     "Dr.",   1,  STR_CURR_GRD    }, // greek drachma
+	{  378, ',', 2010,      "",     " Ft",   1,  STR_CURR_HUF    }, // hungarian forint
+	{  130, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_ISK    }, // icelandic krona
+	{ 2850, ',', 2002,      "",     " L.",   1,  STR_CURR_ITL    }, // italian lira
+	{    3, ',', 2002,      "NLG ", "",      0,  STR_CURR_NLG    }, // dutch gulden
+	{   12, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_NOK    }, // norwegian krone
+	{    6, ' ', CF_NOEURO, "",     " zl",   1,  STR_CURR_PLN    }, // polish zloty
+	{    5, '.', CF_NOEURO, "",     " Lei",  1,  STR_CURR_ROL    }, // romanian Lei
+	{   50, ' ', CF_NOEURO, "",     " p",    1,  STR_CURR_RUR    }, // russian rouble
+	{  352, '.', CF_NOEURO, "",     " SIT",  1,  STR_CURR_SIT    }, // slovenian tolar
+	{   13, '.', CF_NOEURO, "",     " Kr",   1,  STR_CURR_SEK    }, // swedish krona
+	{    3, '.', CF_NOEURO, "",     " YTL",  1,  STR_CURR_YTL    }, // turkish lira
+	{   52, ',', CF_NOEURO, "",     " Sk",   1,  STR_CURR_SKK    }, // slovak koruna
+	{    4, ',', CF_NOEURO, "R$ ",  "",      0,  STR_CURR_BRR    }, // brazil real
+	{    1, ' ', CF_NOEURO, "",     "",      2,  STR_CURR_CUSTOM }, // custom currency
+};
+
+/* Array of currencies used by the system */
+CurrencySpec _currency_specs[NUM_CURRENCY];
+
+/**
+ * These enums are only declared in order to make sens
+ * out of the TTDPatch_To_OTTDIndex array that will follow
+ * Every currency used by Ottd is there, just in case TTDPatch will
+ * add those missing in its code
+ **/
+enum {
+	CURR_GBP,
+	CURR_USD,
+	CURR_EUR,
+	CURR_YEN,
+	CURR_ATS,
+	CURR_BEF,
+	CURR_CHF,
+	CURR_CZK,
+	CURR_DEM,
+	CURR_DKK,
+	CURR_ESP,
+	CURR_FIM,
+	CURR_FRF,
+	CURR_GRD,
+	CURR_HUF,
+	CURR_ISK,
+	CURR_ITL,
+	CURR_NLG,
+	CURR_NOK,
+	CURR_PLN,
+	CURR_ROL,
+	CURR_RUR,
+	CURR_SIT,
+	CURR_SEK,
+	CURR_YTL,
+};
+
+/**
+ * This array represent the position of OpenTTD's currencies,
+ * compared to TTDPatch's ones.
+ * When a grf sends currencies, they are based on the order defined by TTDPatch.
+ * So, we must reindex them to our own order.
+ **/
+const byte TTDPatch_To_OTTDIndex[] =
+{
+	CURR_GBP,
+	CURR_USD,
+	CURR_FRF,
+	CURR_DEM,
+	CURR_YEN,
+	CURR_ESP,
+	CURR_HUF,
+	CURR_PLN,
+	CURR_ATS,
+	CURR_BEF,
+	CURR_DKK,
+	CURR_FIM,
+	CURR_GRD,
+	CURR_CHF,
+	CURR_NLG,
+	CURR_ITL,
+	CURR_SEK,
+	CURR_RUR,
+	CURR_EUR,
+};
+
+/**
+ * Will return the ottd's index correspondance to
+ * the ttdpatch's id.  If the id is bigger then the array,
+ * it is  a grf written for ottd, thus returning the same id.
+ * Only called from newgrf.c
+ * @param grfcurr_id currency id coming from newgrf
+ * @return the corrected index
+ **/
+byte GetNewgrfCurrencyIdConverted(byte grfcurr_id)
+{
+	return (grfcurr_id >= lengthof(TTDPatch_To_OTTDIndex)) ? grfcurr_id : TTDPatch_To_OTTDIndex[grfcurr_id];
+}
+
+/* get a mask of the allowed currencies depending on the year */
+uint GetMaskOfAllowedCurrencies(void)
+{
+	uint mask = 0;
+	uint i;
+
+	for (i = 0; i < NUM_CURRENCY; i++) {
+		Year to_euro = _currency_specs[i].to_euro;
+
+		if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue;
+		if (to_euro == CF_ISEURO && _cur_year < 2000) continue;
+		mask |= (1 << i);
+	}
+	mask |= (1 << CUSTOM_CURRENCY_ID); // always allow custom currency
+	return mask;
+}
+
+/**
+ * Verify if the currency chosen by the user is about to be converted to Euro
+ **/
+void CheckSwitchToEuro(void)
+{
+	if (_currency_specs[_opt.currency].to_euro != CF_NOEURO &&
+			_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
+			_cur_year >= _currency_specs[_opt.currency].to_euro) {
+		_opt.currency = 2; // this is the index of euro above.
+		AddNewsItem(STR_EURO_INTRODUCE, NEWS_FLAGS(NM_NORMAL, 0, NT_ECONOMY, 0), 0, 0);
+	}
+}
+
+/**
+ * Called only from newgrf.c.  Will fill _currency_specs array with
+ * default values from origin_currency_specs
+ **/
+void ResetCurrencies(void)
+{
+	memcpy(&_currency_specs, &origin_currency_specs, sizeof(origin_currency_specs));
+}
+
+/**
+ * Build a list of currency names StringIDs to use in a dropdown list
+ * @return Pointer to a (static) array of StringIDs
+ */
+StringID* BuildCurrencyDropdown(void)
+{
+	/* Allow room for all currencies, plus a terminator entry */
+	static StringID names[CUSTOM_CURRENCY_ID];
+	uint i;
+
+	/* Add each name */
+	for (i = 0; i < NUM_CURRENCY; i++) {
+		names[i] = _currency_specs[i].name;
+	}
+	/* Terminate the list */
+	names[i] = INVALID_STRING_ID;
+
+	return names;
+}
deleted file mode 100644
--- a/src/date.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "date.h"
-#include "variables.h"
-#include "macros.h"
-#include "vehicle.h"
-#include "network/network.h"
-#include "network/network_data.h"
-#include "network/network_server.h"
-#include "functions.h"
-#include "currency.h"
-
-Year      _cur_year;
-Month     _cur_month;
-Date      _date;
-DateFract _date_fract;
-
-
-void SetDate(Date date)
-{
-	YearMonthDay ymd;
-
-	_date = date;
-	ConvertDateToYMD(date, &ymd);
-	_cur_year = ymd.year;
-	_cur_month = ymd.month;
-#ifdef ENABLE_NETWORK
-	_network_last_advertise_frame = 0;
-	_network_need_advertise = true;
-#endif /* ENABLE_NETWORK */
-}
-
-#define M(a, b) ((a << 5) | b)
-static const uint16 _month_date_from_year_day[] = {
-	M( 0, 1), M( 0, 2), M( 0, 3), M( 0, 4), M( 0, 5), M( 0, 6), M( 0, 7), M( 0, 8), M( 0, 9), M( 0, 10), M( 0, 11), M( 0, 12), M( 0, 13), M( 0, 14), M( 0, 15), M( 0, 16), M( 0, 17), M( 0, 18), M( 0, 19), M( 0, 20), M( 0, 21), M( 0, 22), M( 0, 23), M( 0, 24), M( 0, 25), M( 0, 26), M( 0, 27), M( 0, 28), M( 0, 29), M( 0, 30), M( 0, 31),
-	M( 1, 1), M( 1, 2), M( 1, 3), M( 1, 4), M( 1, 5), M( 1, 6), M( 1, 7), M( 1, 8), M( 1, 9), M( 1, 10), M( 1, 11), M( 1, 12), M( 1, 13), M( 1, 14), M( 1, 15), M( 1, 16), M( 1, 17), M( 1, 18), M( 1, 19), M( 1, 20), M( 1, 21), M( 1, 22), M( 1, 23), M( 1, 24), M( 1, 25), M( 1, 26), M( 1, 27), M( 1, 28), M( 1, 29),
-	M( 2, 1), M( 2, 2), M( 2, 3), M( 2, 4), M( 2, 5), M( 2, 6), M( 2, 7), M( 2, 8), M( 2, 9), M( 2, 10), M( 2, 11), M( 2, 12), M( 2, 13), M( 2, 14), M( 2, 15), M( 2, 16), M( 2, 17), M( 2, 18), M( 2, 19), M( 2, 20), M( 2, 21), M( 2, 22), M( 2, 23), M( 2, 24), M( 2, 25), M( 2, 26), M( 2, 27), M( 2, 28), M( 2, 29), M( 2, 30), M( 2, 31),
-	M( 3, 1), M( 3, 2), M( 3, 3), M( 3, 4), M( 3, 5), M( 3, 6), M( 3, 7), M( 3, 8), M( 3, 9), M( 3, 10), M( 3, 11), M( 3, 12), M( 3, 13), M( 3, 14), M( 3, 15), M( 3, 16), M( 3, 17), M( 3, 18), M( 3, 19), M( 3, 20), M( 3, 21), M( 3, 22), M( 3, 23), M( 3, 24), M( 3, 25), M( 3, 26), M( 3, 27), M( 3, 28), M( 3, 29), M( 3, 30),
-	M( 4, 1), M( 4, 2), M( 4, 3), M( 4, 4), M( 4, 5), M( 4, 6), M( 4, 7), M( 4, 8), M( 4, 9), M( 4, 10), M( 4, 11), M( 4, 12), M( 4, 13), M( 4, 14), M( 4, 15), M( 4, 16), M( 4, 17), M( 4, 18), M( 4, 19), M( 4, 20), M( 4, 21), M( 4, 22), M( 4, 23), M( 4, 24), M( 4, 25), M( 4, 26), M( 4, 27), M( 4, 28), M( 4, 29), M( 4, 30), M( 4, 31),
-	M( 5, 1), M( 5, 2), M( 5, 3), M( 5, 4), M( 5, 5), M( 5, 6), M( 5, 7), M( 5, 8), M( 5, 9), M( 5, 10), M( 5, 11), M( 5, 12), M( 5, 13), M( 5, 14), M( 5, 15), M( 5, 16), M( 5, 17), M( 5, 18), M( 5, 19), M( 5, 20), M( 5, 21), M( 5, 22), M( 5, 23), M( 5, 24), M( 5, 25), M( 5, 26), M( 5, 27), M( 5, 28), M( 5, 29), M( 5, 30),
-	M( 6, 1), M( 6, 2), M( 6, 3), M( 6, 4), M( 6, 5), M( 6, 6), M( 6, 7), M( 6, 8), M( 6, 9), M( 6, 10), M( 6, 11), M( 6, 12), M( 6, 13), M( 6, 14), M( 6, 15), M( 6, 16), M( 6, 17), M( 6, 18), M( 6, 19), M( 6, 20), M( 6, 21), M( 6, 22), M( 6, 23), M( 6, 24), M( 6, 25), M( 6, 26), M( 6, 27), M( 6, 28), M( 6, 29), M( 6, 30), M( 6, 31),
-	M( 7, 1), M( 7, 2), M( 7, 3), M( 7, 4), M( 7, 5), M( 7, 6), M( 7, 7), M( 7, 8), M( 7, 9), M( 7, 10), M( 7, 11), M( 7, 12), M( 7, 13), M( 7, 14), M( 7, 15), M( 7, 16), M( 7, 17), M( 7, 18), M( 7, 19), M( 7, 20), M( 7, 21), M( 7, 22), M( 7, 23), M( 7, 24), M( 7, 25), M( 7, 26), M( 7, 27), M( 7, 28), M( 7, 29), M( 7, 30), M( 7, 31),
-	M( 8, 1), M( 8, 2), M( 8, 3), M( 8, 4), M( 8, 5), M( 8, 6), M( 8, 7), M( 8, 8), M( 8, 9), M( 8, 10), M( 8, 11), M( 8, 12), M( 8, 13), M( 8, 14), M( 8, 15), M( 8, 16), M( 8, 17), M( 8, 18), M( 8, 19), M( 8, 20), M( 8, 21), M( 8, 22), M( 8, 23), M( 8, 24), M( 8, 25), M( 8, 26), M( 8, 27), M( 8, 28), M( 8, 29), M( 8, 30),
-	M( 9, 1), M( 9, 2), M( 9, 3), M( 9, 4), M( 9, 5), M( 9, 6), M( 9, 7), M( 9, 8), M( 9, 9), M( 9, 10), M( 9, 11), M( 9, 12), M( 9, 13), M( 9, 14), M( 9, 15), M( 9, 16), M( 9, 17), M( 9, 18), M( 9, 19), M( 9, 20), M( 9, 21), M( 9, 22), M( 9, 23), M( 9, 24), M( 9, 25), M( 9, 26), M( 9, 27), M( 9, 28), M( 9, 29), M( 9, 30), M( 9, 31),
-	M(10, 1), M(10, 2), M(10, 3), M(10, 4), M(10, 5), M(10, 6), M(10, 7), M(10, 8), M(10, 9), M(10, 10), M(10, 11), M(10, 12), M(10, 13), M(10, 14), M(10, 15), M(10, 16), M(10, 17), M(10, 18), M(10, 19), M(10, 20), M(10, 21), M(10, 22), M(10, 23), M(10, 24), M(10, 25), M(10, 26), M(10, 27), M(10, 28), M(10, 29), M(10, 30),
-	M(11, 1), M(11, 2), M(11, 3), M(11, 4), M(11, 5), M(11, 6), M(11, 7), M(11, 8), M(11, 9), M(11, 10), M(11, 11), M(11, 12), M(11, 13), M(11, 14), M(11, 15), M(11, 16), M(11, 17), M(11, 18), M(11, 19), M(11, 20), M(11, 21), M(11, 22), M(11, 23), M(11, 24), M(11, 25), M(11, 26), M(11, 27), M(11, 28), M(11, 29), M(11, 30), M(11, 31),
-};
-#undef M
-
-enum {
-	ACCUM_JAN = 0,
-	ACCUM_FEB = ACCUM_JAN + 31,
-	ACCUM_MAR = ACCUM_FEB + 29,
-	ACCUM_APR = ACCUM_MAR + 31,
-	ACCUM_MAY = ACCUM_APR + 30,
-	ACCUM_JUN = ACCUM_MAY + 31,
-	ACCUM_JUL = ACCUM_JUN + 30,
-	ACCUM_AUG = ACCUM_JUL + 31,
-	ACCUM_SEP = ACCUM_AUG + 31,
-	ACCUM_OCT = ACCUM_SEP + 30,
-	ACCUM_NOV = ACCUM_OCT + 31,
-	ACCUM_DEC = ACCUM_NOV + 30,
-};
-
-static const uint16 _accum_days_for_month[] = {
-	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
-	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
-	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
-};
-
-static inline bool IsLeapYear(Year yr)
-{
-	return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
-}
-
-/**
- * Converts a Date to a Year, Month & Day.
- * @param date the date to convert from
- * @param ymd  the year, month and day to write to
- */
-void ConvertDateToYMD(Date date, YearMonthDay *ymd)
-{
-	/*
-	 * Year determination in multiple steps to account for leap
-	 * years. First do the large steps, then the smaller ones.
-	 */
-
-	/* There are 97 leap years in 400 years */
-	Year yr = 400 * (date / (365 * 400 + 97));
-	int rem = date % (365 * 400 + 97);
-	uint16 x;
-
-	if (rem >= 365 * 100 + 25) {
-		/* There are 25 leap years in the first 100 years after
-		 * every 400th year, as every 400th year is a leap year */
-		yr  += 100;
-		rem -= 365 * 100 + 25;
-
-		/* There are 24 leap years in the next couple of 100 years */
-		yr += 100 * (rem / (365 * 100 + 24));
-		rem = (rem % (365 * 100 + 24));
-	}
-
-	if (!IsLeapYear(yr) && rem >= 365 * 4) {
-		/* The first 4 year of the century are not always a leap year */
-		yr  += 4;
-		rem -= 365 * 4;
-	}
-
-	/* There is 1 leap year every 4 years */
-	yr += 4 * (rem / (365 * 4 + 1));
-	rem = rem % (365 * 4 + 1);
-
-	/* The last (max 3) years to account for; the first one
-	 * can be, but is not necessarily a leap year */
-	while (rem >= (IsLeapYear(yr) ? 366 : 365)) {
-		rem -= IsLeapYear(yr) ? 366 : 365;
-		yr++;
-	}
-
-	/* Skip the 29th of February in non-leap years */
-	if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
-
-	ymd->year = yr;
-
-	x = _month_date_from_year_day[rem];
-	ymd->month = x >> 5;
-	ymd->day = x & 0x1F;
-}
-
-/**
- * Converts a tupe of Year, Month and Day to a Date.
- * @param year  is a number between 0..MAX_YEAR
- * @param month is a number between 0..11
- * @param day   is a number between 1..31
- */
-Date ConvertYMDToDate(Year year, Month month, Day day)
-{
-	/*
-	 * Each passed leap year adds one day to the 'day count'.
-	 *
-	 * A special case for the year 0 as no year has been passed,
-	 * but '(year - 1) / 4' does not yield '-1' to counteract the
-	 * '+1' at the end of the formula as divisions round to zero.
-	 */
-	int nr_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1);
-
-	/* Day-offset in a leap year */
-	int days = _accum_days_for_month[month] + day - 1;
-
-	/* Account for the missing of the 29th of February in non-leap years */
-	if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
-
-	return year * 365 + nr_of_leap_years + days;
-}
-
-/** Functions used by the IncreaseDate function */
-
-extern void OnNewDay_Train(Vehicle *v);
-extern void OnNewDay_RoadVeh(Vehicle *v);
-extern void OnNewDay_Aircraft(Vehicle *v);
-extern void OnNewDay_Ship(Vehicle *v);
-static void OnNewDay_EffectVehicle(Vehicle *v) { /* empty */ }
-extern void OnNewDay_DisasterVehicle(Vehicle *v);
-
-typedef void OnNewVehicleDayProc(Vehicle *v);
-
-static OnNewVehicleDayProc * _on_new_vehicle_day_proc[] = {
-	OnNewDay_Train,
-	OnNewDay_RoadVeh,
-	OnNewDay_Ship,
-	OnNewDay_Aircraft,
-	OnNewDay_EffectVehicle,
-	OnNewDay_DisasterVehicle,
-};
-
-extern void WaypointsDailyLoop(void);
-extern void TextMessageDailyLoop(void);
-extern void EnginesDailyLoop(void);
-extern void DisasterDailyLoop(void);
-
-extern void PlayersMonthlyLoop(void);
-extern void EnginesMonthlyLoop(void);
-extern void TownsMonthlyLoop(void);
-extern void IndustryMonthlyLoop(void);
-extern void StationMonthlyLoop(void);
-
-extern void PlayersYearlyLoop(void);
-extern void TrainsYearlyLoop(void);
-extern void RoadVehiclesYearlyLoop(void);
-extern void AircraftYearlyLoop(void);
-extern void ShipsYearlyLoop(void);
-
-extern void ShowEndGameChart(void);
-
-
-static const Month _autosave_months[] = {
-	 0, // never
-	 1, // every month
-	 3, // every 3 months
-	 6, // every 6 months
-	12, // every 12 months
-};
-
-/**
- * Runs the day_proc for every DAY_TICKS vehicle starting at daytick.
- */
-static void RunVehicleDayProc(uint daytick)
-{
-	uint total = GetMaxVehicleIndex() + 1;
-	uint i;
-
-	for (i = daytick; i < total; i += DAY_TICKS) {
-		Vehicle *v = GetVehicle(i);
-
-		if (IsValidVehicle(v)) _on_new_vehicle_day_proc[v->type - 0x10](v);
-	}
-}
-
-void IncreaseDate(void)
-{
-	YearMonthDay ymd;
-
-	if (_game_mode == GM_MENU) {
-		_tick_counter++;
-		return;
-	}
-
-	RunVehicleDayProc(_date_fract);
-
-	/* increase day, and check if a new day is there? */
-	_tick_counter++;
-
-	_date_fract++;
-	if (_date_fract < DAY_TICKS) return;
-	_date_fract = 0;
-
-	/* yeah, increase day counter and call various daily loops */
-	_date++;
-
-	TextMessageDailyLoop();
-
-	DisasterDailyLoop();
-	WaypointsDailyLoop();
-
-	if (_game_mode != GM_MENU) {
-		InvalidateWindowWidget(WC_STATUS_BAR, 0, 0);
-		EnginesDailyLoop();
-	}
-
-	/* check if we entered a new month? */
-	ConvertDateToYMD(_date, &ymd);
-	if (ymd.month == _cur_month) return;
-	_cur_month = ymd.month;
-
-	/* yes, call various monthly loops */
-	if (_game_mode != GM_MENU) {
-		if (_opt.autosave != 0 && (_cur_month % _autosave_months[_opt.autosave]) == 0) {
-			_do_autosave = true;
-			RedrawAutosave();
-		}
-
-		PlayersMonthlyLoop();
-		EnginesMonthlyLoop();
-		TownsMonthlyLoop();
-		IndustryMonthlyLoop();
-		StationMonthlyLoop();
-		if (_network_server) NetworkServerMonthlyLoop();
-	}
-
-	/* check if we entered a new year? */
-	if (ymd.year == _cur_year) return;
-	_cur_year = ymd.year;
-
-	/* yes, call various yearly loops */
-	PlayersYearlyLoop();
-	TrainsYearlyLoop();
-	RoadVehiclesYearlyLoop();
-	AircraftYearlyLoop();
-	ShipsYearlyLoop();
-	if (_network_server) NetworkServerYearlyLoop();
-
-	/* check if we reached end of the game */
-	if (_cur_year == _patches.ending_year) {
-			ShowEndGameChart();
-	/* check if we reached the maximum year, decrement dates by a year */
-	} else if (_cur_year == MAX_YEAR + 1) {
-		Vehicle *v;
-		uint days_this_year;
-
-		_cur_year--;
-		days_this_year = IsLeapYear(_cur_year) ? 366 : 365;
-		_date -= days_this_year;
-		FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
-
-		/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
-		 *  all of them if the date is set back, else those messages will hang for ever */
-		InitTextMessage();
-	}
-
-	if (_patches.auto_euro) CheckSwitchToEuro();
-}
new file mode 100644
--- /dev/null
+++ b/src/date.cpp
@@ -0,0 +1,304 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "date.h"
+#include "variables.h"
+#include "macros.h"
+#include "vehicle.h"
+#include "network/network.h"
+#include "network/network_data.h"
+#include "network/network_server.h"
+#include "functions.h"
+#include "currency.h"
+
+Year      _cur_year;
+Month     _cur_month;
+Date      _date;
+DateFract _date_fract;
+
+
+void SetDate(Date date)
+{
+	YearMonthDay ymd;
+
+	_date = date;
+	ConvertDateToYMD(date, &ymd);
+	_cur_year = ymd.year;
+	_cur_month = ymd.month;
+#ifdef ENABLE_NETWORK
+	_network_last_advertise_frame = 0;
+	_network_need_advertise = true;
+#endif /* ENABLE_NETWORK */
+}
+
+#define M(a, b) ((a << 5) | b)
+static const uint16 _month_date_from_year_day[] = {
+	M( 0, 1), M( 0, 2), M( 0, 3), M( 0, 4), M( 0, 5), M( 0, 6), M( 0, 7), M( 0, 8), M( 0, 9), M( 0, 10), M( 0, 11), M( 0, 12), M( 0, 13), M( 0, 14), M( 0, 15), M( 0, 16), M( 0, 17), M( 0, 18), M( 0, 19), M( 0, 20), M( 0, 21), M( 0, 22), M( 0, 23), M( 0, 24), M( 0, 25), M( 0, 26), M( 0, 27), M( 0, 28), M( 0, 29), M( 0, 30), M( 0, 31),
+	M( 1, 1), M( 1, 2), M( 1, 3), M( 1, 4), M( 1, 5), M( 1, 6), M( 1, 7), M( 1, 8), M( 1, 9), M( 1, 10), M( 1, 11), M( 1, 12), M( 1, 13), M( 1, 14), M( 1, 15), M( 1, 16), M( 1, 17), M( 1, 18), M( 1, 19), M( 1, 20), M( 1, 21), M( 1, 22), M( 1, 23), M( 1, 24), M( 1, 25), M( 1, 26), M( 1, 27), M( 1, 28), M( 1, 29),
+	M( 2, 1), M( 2, 2), M( 2, 3), M( 2, 4), M( 2, 5), M( 2, 6), M( 2, 7), M( 2, 8), M( 2, 9), M( 2, 10), M( 2, 11), M( 2, 12), M( 2, 13), M( 2, 14), M( 2, 15), M( 2, 16), M( 2, 17), M( 2, 18), M( 2, 19), M( 2, 20), M( 2, 21), M( 2, 22), M( 2, 23), M( 2, 24), M( 2, 25), M( 2, 26), M( 2, 27), M( 2, 28), M( 2, 29), M( 2, 30), M( 2, 31),
+	M( 3, 1), M( 3, 2), M( 3, 3), M( 3, 4), M( 3, 5), M( 3, 6), M( 3, 7), M( 3, 8), M( 3, 9), M( 3, 10), M( 3, 11), M( 3, 12), M( 3, 13), M( 3, 14), M( 3, 15), M( 3, 16), M( 3, 17), M( 3, 18), M( 3, 19), M( 3, 20), M( 3, 21), M( 3, 22), M( 3, 23), M( 3, 24), M( 3, 25), M( 3, 26), M( 3, 27), M( 3, 28), M( 3, 29), M( 3, 30),
+	M( 4, 1), M( 4, 2), M( 4, 3), M( 4, 4), M( 4, 5), M( 4, 6), M( 4, 7), M( 4, 8), M( 4, 9), M( 4, 10), M( 4, 11), M( 4, 12), M( 4, 13), M( 4, 14), M( 4, 15), M( 4, 16), M( 4, 17), M( 4, 18), M( 4, 19), M( 4, 20), M( 4, 21), M( 4, 22), M( 4, 23), M( 4, 24), M( 4, 25), M( 4, 26), M( 4, 27), M( 4, 28), M( 4, 29), M( 4, 30), M( 4, 31),
+	M( 5, 1), M( 5, 2), M( 5, 3), M( 5, 4), M( 5, 5), M( 5, 6), M( 5, 7), M( 5, 8), M( 5, 9), M( 5, 10), M( 5, 11), M( 5, 12), M( 5, 13), M( 5, 14), M( 5, 15), M( 5, 16), M( 5, 17), M( 5, 18), M( 5, 19), M( 5, 20), M( 5, 21), M( 5, 22), M( 5, 23), M( 5, 24), M( 5, 25), M( 5, 26), M( 5, 27), M( 5, 28), M( 5, 29), M( 5, 30),
+	M( 6, 1), M( 6, 2), M( 6, 3), M( 6, 4), M( 6, 5), M( 6, 6), M( 6, 7), M( 6, 8), M( 6, 9), M( 6, 10), M( 6, 11), M( 6, 12), M( 6, 13), M( 6, 14), M( 6, 15), M( 6, 16), M( 6, 17), M( 6, 18), M( 6, 19), M( 6, 20), M( 6, 21), M( 6, 22), M( 6, 23), M( 6, 24), M( 6, 25), M( 6, 26), M( 6, 27), M( 6, 28), M( 6, 29), M( 6, 30), M( 6, 31),
+	M( 7, 1), M( 7, 2), M( 7, 3), M( 7, 4), M( 7, 5), M( 7, 6), M( 7, 7), M( 7, 8), M( 7, 9), M( 7, 10), M( 7, 11), M( 7, 12), M( 7, 13), M( 7, 14), M( 7, 15), M( 7, 16), M( 7, 17), M( 7, 18), M( 7, 19), M( 7, 20), M( 7, 21), M( 7, 22), M( 7, 23), M( 7, 24), M( 7, 25), M( 7, 26), M( 7, 27), M( 7, 28), M( 7, 29), M( 7, 30), M( 7, 31),
+	M( 8, 1), M( 8, 2), M( 8, 3), M( 8, 4), M( 8, 5), M( 8, 6), M( 8, 7), M( 8, 8), M( 8, 9), M( 8, 10), M( 8, 11), M( 8, 12), M( 8, 13), M( 8, 14), M( 8, 15), M( 8, 16), M( 8, 17), M( 8, 18), M( 8, 19), M( 8, 20), M( 8, 21), M( 8, 22), M( 8, 23), M( 8, 24), M( 8, 25), M( 8, 26), M( 8, 27), M( 8, 28), M( 8, 29), M( 8, 30),
+	M( 9, 1), M( 9, 2), M( 9, 3), M( 9, 4), M( 9, 5), M( 9, 6), M( 9, 7), M( 9, 8), M( 9, 9), M( 9, 10), M( 9, 11), M( 9, 12), M( 9, 13), M( 9, 14), M( 9, 15), M( 9, 16), M( 9, 17), M( 9, 18), M( 9, 19), M( 9, 20), M( 9, 21), M( 9, 22), M( 9, 23), M( 9, 24), M( 9, 25), M( 9, 26), M( 9, 27), M( 9, 28), M( 9, 29), M( 9, 30), M( 9, 31),
+	M(10, 1), M(10, 2), M(10, 3), M(10, 4), M(10, 5), M(10, 6), M(10, 7), M(10, 8), M(10, 9), M(10, 10), M(10, 11), M(10, 12), M(10, 13), M(10, 14), M(10, 15), M(10, 16), M(10, 17), M(10, 18), M(10, 19), M(10, 20), M(10, 21), M(10, 22), M(10, 23), M(10, 24), M(10, 25), M(10, 26), M(10, 27), M(10, 28), M(10, 29), M(10, 30),
+	M(11, 1), M(11, 2), M(11, 3), M(11, 4), M(11, 5), M(11, 6), M(11, 7), M(11, 8), M(11, 9), M(11, 10), M(11, 11), M(11, 12), M(11, 13), M(11, 14), M(11, 15), M(11, 16), M(11, 17), M(11, 18), M(11, 19), M(11, 20), M(11, 21), M(11, 22), M(11, 23), M(11, 24), M(11, 25), M(11, 26), M(11, 27), M(11, 28), M(11, 29), M(11, 30), M(11, 31),
+};
+#undef M
+
+enum {
+	ACCUM_JAN = 0,
+	ACCUM_FEB = ACCUM_JAN + 31,
+	ACCUM_MAR = ACCUM_FEB + 29,
+	ACCUM_APR = ACCUM_MAR + 31,
+	ACCUM_MAY = ACCUM_APR + 30,
+	ACCUM_JUN = ACCUM_MAY + 31,
+	ACCUM_JUL = ACCUM_JUN + 30,
+	ACCUM_AUG = ACCUM_JUL + 31,
+	ACCUM_SEP = ACCUM_AUG + 31,
+	ACCUM_OCT = ACCUM_SEP + 30,
+	ACCUM_NOV = ACCUM_OCT + 31,
+	ACCUM_DEC = ACCUM_NOV + 30,
+};
+
+static const uint16 _accum_days_for_month[] = {
+	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
+	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
+	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
+};
+
+static inline bool IsLeapYear(Year yr)
+{
+	return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
+}
+
+/**
+ * Converts a Date to a Year, Month & Day.
+ * @param date the date to convert from
+ * @param ymd  the year, month and day to write to
+ */
+void ConvertDateToYMD(Date date, YearMonthDay *ymd)
+{
+	/*
+	 * Year determination in multiple steps to account for leap
+	 * years. First do the large steps, then the smaller ones.
+	 */
+
+	/* There are 97 leap years in 400 years */
+	Year yr = 400 * (date / (365 * 400 + 97));
+	int rem = date % (365 * 400 + 97);
+	uint16 x;
+
+	if (rem >= 365 * 100 + 25) {
+		/* There are 25 leap years in the first 100 years after
+		 * every 400th year, as every 400th year is a leap year */
+		yr  += 100;
+		rem -= 365 * 100 + 25;
+
+		/* There are 24 leap years in the next couple of 100 years */
+		yr += 100 * (rem / (365 * 100 + 24));
+		rem = (rem % (365 * 100 + 24));
+	}
+
+	if (!IsLeapYear(yr) && rem >= 365 * 4) {
+		/* The first 4 year of the century are not always a leap year */
+		yr  += 4;
+		rem -= 365 * 4;
+	}
+
+	/* There is 1 leap year every 4 years */
+	yr += 4 * (rem / (365 * 4 + 1));
+	rem = rem % (365 * 4 + 1);
+
+	/* The last (max 3) years to account for; the first one
+	 * can be, but is not necessarily a leap year */
+	while (rem >= (IsLeapYear(yr) ? 366 : 365)) {
+		rem -= IsLeapYear(yr) ? 366 : 365;
+		yr++;
+	}
+
+	/* Skip the 29th of February in non-leap years */
+	if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
+
+	ymd->year = yr;
+
+	x = _month_date_from_year_day[rem];
+	ymd->month = x >> 5;
+	ymd->day = x & 0x1F;
+}
+
+/**
+ * Converts a tupe of Year, Month and Day to a Date.
+ * @param year  is a number between 0..MAX_YEAR
+ * @param month is a number between 0..11
+ * @param day   is a number between 1..31
+ */
+Date ConvertYMDToDate(Year year, Month month, Day day)
+{
+	/*
+	 * Each passed leap year adds one day to the 'day count'.
+	 *
+	 * A special case for the year 0 as no year has been passed,
+	 * but '(year - 1) / 4' does not yield '-1' to counteract the
+	 * '+1' at the end of the formula as divisions round to zero.
+	 */
+	int nr_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1);
+
+	/* Day-offset in a leap year */
+	int days = _accum_days_for_month[month] + day - 1;
+
+	/* Account for the missing of the 29th of February in non-leap years */
+	if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
+
+	return year * 365 + nr_of_leap_years + days;
+}
+
+/** Functions used by the IncreaseDate function */
+
+extern void OnNewDay_Train(Vehicle *v);
+extern void OnNewDay_RoadVeh(Vehicle *v);
+extern void OnNewDay_Aircraft(Vehicle *v);
+extern void OnNewDay_Ship(Vehicle *v);
+static void OnNewDay_EffectVehicle(Vehicle *v) { /* empty */ }
+extern void OnNewDay_DisasterVehicle(Vehicle *v);
+
+typedef void OnNewVehicleDayProc(Vehicle *v);
+
+static OnNewVehicleDayProc * _on_new_vehicle_day_proc[] = {
+	OnNewDay_Train,
+	OnNewDay_RoadVeh,
+	OnNewDay_Ship,
+	OnNewDay_Aircraft,
+	OnNewDay_EffectVehicle,
+	OnNewDay_DisasterVehicle,
+};
+
+extern void WaypointsDailyLoop(void);
+extern void TextMessageDailyLoop(void);
+extern void EnginesDailyLoop(void);
+extern void DisasterDailyLoop(void);
+
+extern void PlayersMonthlyLoop(void);
+extern void EnginesMonthlyLoop(void);
+extern void TownsMonthlyLoop(void);
+extern void IndustryMonthlyLoop(void);
+extern void StationMonthlyLoop(void);
+
+extern void PlayersYearlyLoop(void);
+extern void TrainsYearlyLoop(void);
+extern void RoadVehiclesYearlyLoop(void);
+extern void AircraftYearlyLoop(void);
+extern void ShipsYearlyLoop(void);
+
+extern void ShowEndGameChart(void);
+
+
+static const Month _autosave_months[] = {
+	 0, // never
+	 1, // every month
+	 3, // every 3 months
+	 6, // every 6 months
+	12, // every 12 months
+};
+
+/**
+ * Runs the day_proc for every DAY_TICKS vehicle starting at daytick.
+ */
+static void RunVehicleDayProc(uint daytick)
+{
+	uint total = GetMaxVehicleIndex() + 1;
+	uint i;
+
+	for (i = daytick; i < total; i += DAY_TICKS) {
+		Vehicle *v = GetVehicle(i);
+
+		if (IsValidVehicle(v)) _on_new_vehicle_day_proc[v->type - 0x10](v);
+	}
+}
+
+void IncreaseDate(void)
+{
+	YearMonthDay ymd;
+
+	if (_game_mode == GM_MENU) {
+		_tick_counter++;
+		return;
+	}
+
+	RunVehicleDayProc(_date_fract);
+
+	/* increase day, and check if a new day is there? */
+	_tick_counter++;
+
+	_date_fract++;
+	if (_date_fract < DAY_TICKS) return;
+	_date_fract = 0;
+
+	/* yeah, increase day counter and call various daily loops */
+	_date++;
+
+	TextMessageDailyLoop();
+
+	DisasterDailyLoop();
+	WaypointsDailyLoop();
+
+	if (_game_mode != GM_MENU) {
+		InvalidateWindowWidget(WC_STATUS_BAR, 0, 0);
+		EnginesDailyLoop();
+	}
+
+	/* check if we entered a new month? */
+	ConvertDateToYMD(_date, &ymd);
+	if (ymd.month == _cur_month) return;
+	_cur_month = ymd.month;
+
+	/* yes, call various monthly loops */
+	if (_game_mode != GM_MENU) {
+		if (_opt.autosave != 0 && (_cur_month % _autosave_months[_opt.autosave]) == 0) {
+			_do_autosave = true;
+			RedrawAutosave();
+		}
+
+		PlayersMonthlyLoop();
+		EnginesMonthlyLoop();
+		TownsMonthlyLoop();
+		IndustryMonthlyLoop();
+		StationMonthlyLoop();
+		if (_network_server) NetworkServerMonthlyLoop();
+	}
+
+	/* check if we entered a new year? */
+	if (ymd.year == _cur_year) return;
+	_cur_year = ymd.year;
+
+	/* yes, call various yearly loops */
+	PlayersYearlyLoop();
+	TrainsYearlyLoop();
+	RoadVehiclesYearlyLoop();
+	AircraftYearlyLoop();
+	ShipsYearlyLoop();
+	if (_network_server) NetworkServerYearlyLoop();
+
+	/* check if we reached end of the game */
+	if (_cur_year == _patches.ending_year) {
+			ShowEndGameChart();
+	/* check if we reached the maximum year, decrement dates by a year */
+	} else if (_cur_year == MAX_YEAR + 1) {
+		Vehicle *v;
+		uint days_this_year;
+
+		_cur_year--;
+		days_this_year = IsLeapYear(_cur_year) ? 366 : 365;
+		_date -= days_this_year;
+		FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
+
+		/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
+		 *  all of them if the date is set back, else those messages will hang for ever */
+		InitTextMessage();
+	}
+
+	if (_patches.auto_euro) CheckSwitchToEuro();
+}
deleted file mode 100644
--- a/src/debug.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include <stdio.h>
-#include <stdarg.h>
-#include "openttd.h"
-#include "console.h"
-#include "debug.h"
-#include "functions.h"
-#include "string.h"
-
-int _debug_ai_level;
-int _debug_driver_level;
-int _debug_grf_level;
-int _debug_map_level;
-int _debug_misc_level;
-int _debug_ms_level;
-int _debug_net_level;
-int _debug_sprite_level;
-int _debug_oldloader_level;
-int _debug_ntp_level;
-int _debug_npf_level;
-int _debug_yapf_level;
-int _debug_freetype_level;
-int _debug_sl_level;
-
-
-typedef struct DebugLevel {
-	const char *name;
-	int *level;
-} DebugLevel;
-
-#define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
-	static const DebugLevel debug_level[] = {
-	DEBUG_LEVEL(ai),
-	DEBUG_LEVEL(driver),
-	DEBUG_LEVEL(grf),
-	DEBUG_LEVEL(map),
-	DEBUG_LEVEL(misc),
-	DEBUG_LEVEL(ms),
-	DEBUG_LEVEL(net),
-	DEBUG_LEVEL(sprite),
-	DEBUG_LEVEL(oldloader),
-	DEBUG_LEVEL(ntp),
-	DEBUG_LEVEL(npf),
-	DEBUG_LEVEL(yapf),
-	DEBUG_LEVEL(freetype),
-	DEBUG_LEVEL(sl),
-	};
-#undef DEBUG_LEVEL
-
-#if !defined(NO_DEBUG_MESSAGES)
-
-/** Functionized DEBUG macro for compilers that don't support
- * variadic macros (__VA_ARGS__) such as...yes MSVC2003 and lower */
-#if defined(NO_VARARG_MACRO)
-void CDECL DEBUG(int name, int level, ...)
-{
-	va_list va;
-	const char *dbg;
-	const DebugLevel *dl = &debug_level[name];
-
-	if (level != 0 && *dl->level < level) return;
-	dbg = dl->name;
-	va_start(va, level);
-#else
-void CDECL debug(const char *dbg, ...)
-{
-	va_list va;
-	va_start(va, dbg);
-#endif /* NO_VARARG_MACRO */
-	{
-		const char *s;
-		char buf[1024];
-
-		s = va_arg(va, const char*);
-		vsnprintf(buf, lengthof(buf), s, va);
-		va_end(va);
-		fprintf(stderr, "dbg: [%s] %s\n", dbg, buf);
-		IConsoleDebug(dbg, buf);
-	}
-}
-#endif /* NO_DEBUG_MESSAGES */
-
-void SetDebugString(const char *s)
-{
-	int v;
-	char *end;
-	const char *t;
-
-	// global debugging level?
-	if (*s >= '0' && *s <= '9') {
-		const DebugLevel *i;
-
-		v = strtoul(s, &end, 0);
-		s = end;
-
-		for (i = debug_level; i != endof(debug_level); ++i) *i->level = v;
-	}
-
-	// individual levels
-	for (;;) {
-		const DebugLevel *i;
-		int *p;
-
-		// skip delimiters
-		while (*s == ' ' || *s == ',' || *s == '\t') s++;
-		if (*s == '\0') break;
-
-		t = s;
-		while (*s >= 'a' && *s <= 'z') s++;
-
-		// check debugging levels
-		p = NULL;
-		for (i = debug_level; i != endof(debug_level); ++i)
-			if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) {
-				p = i->level;
-				break;
-			}
-
-		if (*s == '=') s++;
-		v = strtoul(s, &end, 0);
-		s = end;
-		if (p != NULL) {
-			*p = v;
-		} else {
-			ShowInfoF("Unknown debug level '%.*s'", s - t, t);
-			return;
-		}
-	}
-}
-
-/** Print out the current debug-level
- * Just return a string with the values of all the debug categorites
- * @return string with debug-levels
- */
-const char *GetDebugString(void)
-{
-	const DebugLevel *i;
-	static char dbgstr[100];
-	char dbgval[20];
-
-	memset(dbgstr, 0, sizeof(dbgstr));
-	i = debug_level;
-	snprintf(dbgstr, sizeof(dbgstr), "%s=%d", i->name, *i->level);
-
-	for (i++; i != endof(debug_level); i++) {
-		snprintf(dbgval, sizeof(dbgval), ", %s=%d", i->name, *i->level);
-		ttd_strlcat(dbgstr, dbgval, sizeof(dbgstr));
-	}
-
-	return dbgstr;
-}
new file mode 100644
--- /dev/null
+++ b/src/debug.cpp
@@ -0,0 +1,153 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "openttd.h"
+#include "console.h"
+#include "debug.h"
+#include "functions.h"
+#include "string.h"
+
+int _debug_ai_level;
+int _debug_driver_level;
+int _debug_grf_level;
+int _debug_map_level;
+int _debug_misc_level;
+int _debug_ms_level;
+int _debug_net_level;
+int _debug_sprite_level;
+int _debug_oldloader_level;
+int _debug_ntp_level;
+int _debug_npf_level;
+int _debug_yapf_level;
+int _debug_freetype_level;
+int _debug_sl_level;
+
+
+typedef struct DebugLevel {
+	const char *name;
+	int *level;
+} DebugLevel;
+
+#define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
+	static const DebugLevel debug_level[] = {
+	DEBUG_LEVEL(ai),
+	DEBUG_LEVEL(driver),
+	DEBUG_LEVEL(grf),
+	DEBUG_LEVEL(map),
+	DEBUG_LEVEL(misc),
+	DEBUG_LEVEL(ms),
+	DEBUG_LEVEL(net),
+	DEBUG_LEVEL(sprite),
+	DEBUG_LEVEL(oldloader),
+	DEBUG_LEVEL(ntp),
+	DEBUG_LEVEL(npf),
+	DEBUG_LEVEL(yapf),
+	DEBUG_LEVEL(freetype),
+	DEBUG_LEVEL(sl),
+	};
+#undef DEBUG_LEVEL
+
+#if !defined(NO_DEBUG_MESSAGES)
+
+/** Functionized DEBUG macro for compilers that don't support
+ * variadic macros (__VA_ARGS__) such as...yes MSVC2003 and lower */
+#if defined(NO_VARARG_MACRO)
+void CDECL DEBUG(int name, int level, ...)
+{
+	va_list va;
+	const char *dbg;
+	const DebugLevel *dl = &debug_level[name];
+
+	if (level != 0 && *dl->level < level) return;
+	dbg = dl->name;
+	va_start(va, level);
+#else
+void CDECL debug(const char *dbg, ...)
+{
+	va_list va;
+	va_start(va, dbg);
+#endif /* NO_VARARG_MACRO */
+	{
+		const char *s;
+		char buf[1024];
+
+		s = va_arg(va, const char*);
+		vsnprintf(buf, lengthof(buf), s, va);
+		va_end(va);
+		fprintf(stderr, "dbg: [%s] %s\n", dbg, buf);
+		IConsoleDebug(dbg, buf);
+	}
+}
+#endif /* NO_DEBUG_MESSAGES */
+
+void SetDebugString(const char *s)
+{
+	int v;
+	char *end;
+	const char *t;
+
+	// global debugging level?
+	if (*s >= '0' && *s <= '9') {
+		const DebugLevel *i;
+
+		v = strtoul(s, &end, 0);
+		s = end;
+
+		for (i = debug_level; i != endof(debug_level); ++i) *i->level = v;
+	}
+
+	// individual levels
+	for (;;) {
+		const DebugLevel *i;
+		int *p;
+
+		// skip delimiters
+		while (*s == ' ' || *s == ',' || *s == '\t') s++;
+		if (*s == '\0') break;
+
+		t = s;
+		while (*s >= 'a' && *s <= 'z') s++;
+
+		// check debugging levels
+		p = NULL;
+		for (i = debug_level; i != endof(debug_level); ++i)
+			if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) {
+				p = i->level;
+				break;
+			}
+
+		if (*s == '=') s++;
+		v = strtoul(s, &end, 0);
+		s = end;
+		if (p != NULL) {
+			*p = v;
+		} else {
+			ShowInfoF("Unknown debug level '%.*s'", s - t, t);
+			return;
+		}
+	}
+}
+
+/** Print out the current debug-level
+ * Just return a string with the values of all the debug categorites
+ * @return string with debug-levels
+ */
+const char *GetDebugString(void)
+{
+	const DebugLevel *i;
+	static char dbgstr[100];
+	char dbgval[20];
+
+	memset(dbgstr, 0, sizeof(dbgstr));
+	i = debug_level;
+	snprintf(dbgstr, sizeof(dbgstr), "%s=%d", i->name, *i->level);
+
+	for (i++; i != endof(debug_level); i++) {
+		snprintf(dbgval, sizeof(dbgval), ", %s=%d", i->name, *i->level);
+		ttd_strlcat(dbgstr, dbgval, sizeof(dbgstr));
+	}
+
+	return dbgstr;
+}
deleted file mode 100644
--- a/src/dedicated.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-
-#ifdef ENABLE_NETWORK
-
-#if defined(UNIX) && !defined(__MORPHOS__)
-
-#include "openttd.h"
-#include "variables.h"
-
-#include <sys/types.h>
-#include <unistd.h>
-
-void DedicatedFork(void)
-{
-	/* Fork the program */
-	pid_t pid = fork();
-	switch (pid) {
-		case -1:
-			perror("Unable to fork");
-			exit(1);
-
-		case 0: { // We're the child
-			FILE* f;
-
-			/* Open the log-file to log all stuff too */
-			f = fopen(_log_file, "a");
-			if (f == NULL) {
-				perror("Unable to open logfile");
-				exit(1);
-			}
-			/* Redirect stdout and stderr to log-file */
-			if (dup2(fileno(f), fileno(stdout)) == -1) {
-				perror("Rerouting stdout");
-				exit(1);
-			}
-			if (dup2(fileno(f), fileno(stderr)) == -1) {
-				perror("Rerouting stderr");
-				exit(1);
-			}
-			break;
-		}
-
-		default:
-			// We're the parent
-			printf("Loading dedicated server...\n");
-			printf("  - Forked to background with pid %d\n", pid);
-			exit(0);
-	}
-}
-#endif
-
-#else
-
-void DedicatedFork(void) {}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/dedicated.cpp
@@ -0,0 +1,58 @@
+/* $Id$ */
+
+#include "stdafx.h"
+
+#ifdef ENABLE_NETWORK
+
+#if defined(UNIX) && !defined(__MORPHOS__)
+
+#include "openttd.h"
+#include "variables.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+void DedicatedFork(void)
+{
+	/* Fork the program */
+	pid_t pid = fork();
+	switch (pid) {
+		case -1:
+			perror("Unable to fork");
+			exit(1);
+
+		case 0: { // We're the child
+			FILE* f;
+
+			/* Open the log-file to log all stuff too */
+			f = fopen(_log_file, "a");
+			if (f == NULL) {
+				perror("Unable to open logfile");
+				exit(1);
+			}
+			/* Redirect stdout and stderr to log-file */
+			if (dup2(fileno(f), fileno(stdout)) == -1) {
+				perror("Rerouting stdout");
+				exit(1);
+			}
+			if (dup2(fileno(f), fileno(stderr)) == -1) {
+				perror("Rerouting stderr");
+				exit(1);
+			}
+			break;
+		}
+
+		default:
+			// We're the parent
+			printf("Loading dedicated server...\n");
+			printf("  - Forked to background with pid %d\n", pid);
+			exit(0);
+	}
+}
+#endif
+
+#else
+
+void DedicatedFork(void) {}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/depot.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "depot.h"
-#include "functions.h"
-#include "tile.h"
-#include "map.h"
-#include "table/strings.h"
-#include "saveload.h"
-#include "order.h"
-
-
-/**
- * Called if a new block is added to the depot-pool
- */
-static void DepotPoolNewBlock(uint start_item)
-{
-	Depot *d;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (d = GetDepot(start_item); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) d->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Depot, Depot, DepotPoolNewBlock, NULL)
-
-
-/**
- * Gets a depot from a tile
- *
- * @return Returns the depot if the tile had a depot, else it returns NULL
- */
-Depot *GetDepotByTile(TileIndex tile)
-{
-	Depot *depot;
-
-	FOR_ALL_DEPOTS(depot) {
-		if (depot->xy == tile) return depot;
-	}
-
-	return NULL;
-}
-
-/**
- * Allocate a new depot
- */
-Depot *AllocateDepot(void)
-{
-	Depot *d;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (d = GetDepot(0); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) {
-		if (!IsValidDepot(d)) {
-			DepotID index = d->index;
-
-			memset(d, 0, sizeof(Depot));
-			d->index = index;
-
-			return d;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Depot_pool)) return AllocateDepot();
-
-	return NULL;
-}
-
-/**
- * Clean up a depot
- */
-void DestroyDepot(Depot *depot)
-{
-	/* Clear the tile */
-	DoClearSquare(depot->xy);
-
-	/* Clear the depot from all order-lists */
-	RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, depot->index);
-
-	/* Delete the depot-window */
-	DeleteWindowById(WC_VEHICLE_DEPOT, depot->xy);
-}
-
-void InitializeDepots(void)
-{
-	CleanPool(&_Depot_pool);
-	AddBlockToPool(&_Depot_pool);
-}
-
-
-static const SaveLoad _depot_desc[] = {
-	SLE_CONDVAR(Depot, xy,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
-	SLE_CONDVAR(Depot, xy,         SLE_UINT32,                 6, SL_MAX_VERSION),
-	    SLE_VAR(Depot, town_index, SLE_UINT16),
-	SLE_END()
-};
-
-static void Save_DEPT(void)
-{
-	Depot *depot;
-
-	FOR_ALL_DEPOTS(depot) {
-		SlSetArrayIndex(depot->index);
-		SlObject(depot, _depot_desc);
-	}
-}
-
-static void Load_DEPT(void)
-{
-	int index;
-
-	while ((index = SlIterateArray()) != -1) {
-		Depot *depot;
-
-		if (!AddBlockIfNeeded(&_Depot_pool, index))
-			error("Depots: failed loading savegame: too many depots");
-
-		depot = GetDepot(index);
-		SlObject(depot, _depot_desc);
-	}
-}
-
-const ChunkHandler _depot_chunk_handlers[] = {
-	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/depot.cpp
@@ -0,0 +1,127 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "depot.h"
+#include "functions.h"
+#include "tile.h"
+#include "map.h"
+#include "table/strings.h"
+#include "saveload.h"
+#include "order.h"
+
+
+/**
+ * Called if a new block is added to the depot-pool
+ */
+static void DepotPoolNewBlock(uint start_item)
+{
+	Depot *d;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (d = GetDepot(start_item); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) d->index = start_item++;
+}
+
+DEFINE_OLD_POOL(Depot, Depot, DepotPoolNewBlock, NULL)
+
+
+/**
+ * Gets a depot from a tile
+ *
+ * @return Returns the depot if the tile had a depot, else it returns NULL
+ */
+Depot *GetDepotByTile(TileIndex tile)
+{
+	Depot *depot;
+
+	FOR_ALL_DEPOTS(depot) {
+		if (depot->xy == tile) return depot;
+	}
+
+	return NULL;
+}
+
+/**
+ * Allocate a new depot
+ */
+Depot *AllocateDepot(void)
+{
+	Depot *d;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (d = GetDepot(0); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) {
+		if (!IsValidDepot(d)) {
+			DepotID index = d->index;
+
+			memset(d, 0, sizeof(Depot));
+			d->index = index;
+
+			return d;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Depot_pool)) return AllocateDepot();
+
+	return NULL;
+}
+
+/**
+ * Clean up a depot
+ */
+void DestroyDepot(Depot *depot)
+{
+	/* Clear the tile */
+	DoClearSquare(depot->xy);
+
+	/* Clear the depot from all order-lists */
+	RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, depot->index);
+
+	/* Delete the depot-window */
+	DeleteWindowById(WC_VEHICLE_DEPOT, depot->xy);
+}
+
+void InitializeDepots(void)
+{
+	CleanPool(&_Depot_pool);
+	AddBlockToPool(&_Depot_pool);
+}
+
+
+static const SaveLoad _depot_desc[] = {
+	SLE_CONDVAR(Depot, xy,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+	SLE_CONDVAR(Depot, xy,         SLE_UINT32,                 6, SL_MAX_VERSION),
+	    SLE_VAR(Depot, town_index, SLE_UINT16),
+	SLE_END()
+};
+
+static void Save_DEPT(void)
+{
+	Depot *depot;
+
+	FOR_ALL_DEPOTS(depot) {
+		SlSetArrayIndex(depot->index);
+		SlObject(depot, _depot_desc);
+	}
+}
+
+static void Load_DEPT(void)
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		Depot *depot;
+
+		if (!AddBlockIfNeeded(&_Depot_pool, index))
+			error("Depots: failed loading savegame: too many depots");
+
+		depot = GetDepot(index);
+		SlObject(depot, _depot_desc);
+	}
+}
+
+const ChunkHandler _depot_chunk_handlers[] = {
+	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/depot_gui.c
+++ /dev/null
@@ -1,954 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "train.h"
-#include "roadveh.h"
-#include "ship.h"
-#include "aircraft.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "gui.h"
-#include "gfx.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "station_map.h"
-#include "newgrf_engine.h"
-
-/*
- * Since all depot window sizes aren't the same, we need to modify sizes a little.
- * It's done with the following arrays of widget indexes. Each of them tells if a widget side should be moved and in what direction.
- * How long they should be moved and for what window types are controlled in ShowDepotWindow()
- */
-
-/* Names of the widgets. Keep them in the same order as in the widget array */
-enum DepotWindowWidgets {
-	DEPOT_WIDGET_CLOSEBOX = 0,
-	DEPOT_WIDGET_CAPTION,
-	DEPOT_WIDGET_STICKY,
-	DEPOT_WIDGET_SELL,
-	DEPOT_WIDGET_SELL_CHAIN,
-	DEPOT_WIDGET_SELL_ALL,
-	DEPOT_WIDGET_AUTOREPLACE,
-	DEPOT_WIDGET_MATRIX,
-	DEPOT_WIDGET_V_SCROLL, // Vertical scrollbar
-	DEPOT_WIDGET_H_SCROLL, // Horizontal scrollbar
-	DEPOT_WIDGET_BUILD,
-	DEPOT_WIDGET_CLONE,
-	DEPOT_WIDGET_LOCATION,
-	DEPOT_WIDGET_VEHICLE_LIST,
-	DEPOT_WIDGET_STOP_ALL,
-	DEPOT_WIDGET_START_ALL,
-	DEPOT_WIDGET_RESIZE,
-};
-
-/* Widget array for all depot windows.
- * If a widget is needed in some windows only (like train specific), add it for all windows
- * and use HideWindowWidget in ShowDepotWindow() to remove it in the windows where it should not be
- * Keep the widget numbers in sync with the enum or really bad stuff will happen!!! */
-
-/* When adding widgets, place them as you would place them for the ship depot and define how you want it to move in widget_moves[]
- * If you want a widget for one window only, set it to be hidden in ShowDepotWindow() for the windows where you don't want it
- * NOTE: the train only widgets are moved/resized in ShowDepotWindow() so they follow certain other widgets if they are moved to ensure that they stick together.
- *    Changing the size of those here will not have an effect at all. It should be done in ShowDepotWindow()
- */
-static const Widget _depot_widgets[] = {
-	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},            // DEPOT_WIDGET_CLOSEBOX
-	{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   292,     0,    13, 0x0,                 STR_018C_WINDOW_TITLE_DRAG_THIS},  // DEPOT_WIDGET_CAPTION
-	{  WWT_STICKYBOX,     RESIZE_LR,    14,   293,   304,     0,    13, 0x0,                 STR_STICKY_BUTTON},                // DEPOT_WIDGET_STICKY
-
-	/* Widgets are set up run-time */
-	{     WWT_IMGBTN,    RESIZE_LRB,    14,   270,   292,    14,    37, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL
-	{     WWT_IMGBTN,   RESIZE_LRTB,    14,   270,   292,    14,    37, SPR_SELL_CHAIN_TRAIN,STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP}, // DEPOT_WIDGET_SELL_CHAIN, trains only
-	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   292,    38,    60, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL_ALL
-	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   292,    61,    83, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_AUTOREPLACE
-
-	{     WWT_MATRIX,     RESIZE_RB,    14,     0,   269,    14,    83, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_MATRIX
-	{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   293,   304,    14,    83, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_V_SCROLL
-
-	{ WWT_HSCROLLBAR,    RESIZE_RTB,    14,     0,   269,    72,    83, 0x0,                 STR_HSCROLL_BAR_SCROLLS_LIST},     // DEPOT_WIDGET_H_SCROLL, trains only
-
-	/* The buttons in the bottom of the window. left and right is not important as they are later resized to be equal in size
-	 * This calculation is based on right in DEPOT_WIDGET_LOCATION and it presumes left of DEPOT_WIDGET_BUILD is 0            */
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,    85,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_BUILD
-	{    WWT_TEXTBTN,     RESIZE_TB,    14,    86,   170,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_CLONE
-	{ WWT_PUSHTXTBTN,    RESIZE_RTB,    14,   171,   257,    84,    95, STR_00E4_LOCATION,   STR_NULL},                         // DEPOT_WIDGET_LOCATION
-	{ WWT_PUSHTXTBTN,   RESIZE_LRTB,    14,   258,   269,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_VEHICLE_LIST
-	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   280,    84,    95, SPR_FLAG_VEH_STOPPED,STR_NULL},                         // DEPOT_WIDGET_STOP_ALL
-	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   281,   292,    84,    95, SPR_FLAG_VEH_RUNNING,STR_NULL},                         // DEPOT_WIDGET_START_ALL
-	{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   293,   304,    84,    95, 0x0,                 STR_RESIZE_BUTTON},                // DEPOT_WIDGET_RESIZE
-	{   WIDGETS_END},
-};
-
-static void DepotWndProc(Window *w, WindowEvent *e);
-
-static const WindowDesc _train_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 305, 96,
-	WC_VEHICLE_DEPOT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_depot_widgets,
-	DepotWndProc
-};
-
-static const WindowDesc _road_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 305, 96,
-	WC_VEHICLE_DEPOT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_depot_widgets,
-	DepotWndProc
-};
-
-static const WindowDesc _ship_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 305, 96,
-	WC_VEHICLE_DEPOT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_depot_widgets,
-	DepotWndProc
-};
-
-static const WindowDesc _aircraft_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 305, 96,
-	WC_VEHICLE_DEPOT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_depot_widgets,
-	DepotWndProc
-};
-
-extern int WagonLengthToPixels(int len);
-
-void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (!success) return;
-	switch(GetVehicle(p1)->type) {
-		case VEH_Train:    CcCloneTrain(   true, tile, p1, p2); break;
-		case VEH_Road:     CcCloneRoadVeh( true, tile, p1, p2); break;
-		case VEH_Ship:     CcCloneShip(    true, tile, p1, p2); break;
-		case VEH_Aircraft: CcCloneAircraft(true, tile, p1, p2); break;
-	}
-}
-
-static inline void ShowVehicleViewWindow(const Vehicle *v)
-{
-	switch (v->type) {
-		case VEH_Train:    ShowTrainViewWindow(v);    break;
-		case VEH_Road:     ShowRoadVehViewWindow(v);  break;
-		case VEH_Ship:     ShowShipViewWindow(v);     break;
-		case VEH_Aircraft: ShowAircraftViewWindow(v); break;
-		default: NOT_REACHED();
-	}
-}
-
-static void DepotSellAllConfirmationCallback(Window *w, bool confirmed)
-{
-	if (confirmed) {
-		TileIndex tile = w->window_number;
-		byte vehtype = WP(w, depot_d).type;
-		DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
-	}
-}
-
-/** Draw a vehicle in the depot window in the box with the top left corner at x,y
- * @param *w Window to draw in
- * @param *v Vehicle to draw
- * @param x Left side of the box to draw in
- * @param y Top of the box to draw in
- */
-static void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
-{
-	byte diff_x = 0, diff_y = 0;
-
-	switch (v->type) {
-		case VEH_Train:
-			DrawTrainImage(v, x + 21, y, w->hscroll.cap + 4, w->hscroll.pos, WP(w,depot_d).sel);
-
-			/* Number of wagons relative to a standard length wagon (rounded up) */
-			SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
-			DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
-			break;
-
-		case VEH_Road:     DrawRoadVehImage( v, x + 24, y, WP(w, depot_d).sel); break;
-		case VEH_Ship:     DrawShipImage(    v, x + 19, y, WP(w, depot_d).sel); break;
-		case VEH_Aircraft: DrawAircraftImage(v, x + 12, y, WP(w, depot_d).sel); break;
-		default: NOT_REACHED();
-	}
-
-	if (w->resize.step_height == 14) {
-		/* VEH_Train and VEH_Road, which are low */
-		diff_x = 15;
-	} else {
-		/* VEH_Ship and VEH_Aircraft, which are tall */
-		diff_y = 12;
-	}
-
-	DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, x + diff_x, y + diff_y);
-
-	SetDParam(0, v->unitnumber);
-	DrawString(x, y + 2, (uint16)(v->max_age-366) >= v->age ? STR_00E2 : STR_00E3, 0);
-}
-
-static void DrawDepotWindow(Window *w)
-{
-	Vehicle **vl = WP(w, depot_d).vehicle_list;
-	TileIndex tile = w->window_number;
-	int x, y, i, hnum, max;
-	uint16 num = WP(w, depot_d).engine_count;
-
-	/* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
-	uint16 rows_in_display   = w->widget[DEPOT_WIDGET_MATRIX].data >> 8;
-	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
-	/* setup disabled buttons */
-	SetWindowWidgetsDisabledState(w, !IsTileOwner(tile, _local_player),
-		DEPOT_WIDGET_STOP_ALL,
-		DEPOT_WIDGET_START_ALL,
-		DEPOT_WIDGET_SELL,
-		DEPOT_WIDGET_SELL_CHAIN,
-		DEPOT_WIDGET_SELL_ALL,
-		DEPOT_WIDGET_BUILD,
-		DEPOT_WIDGET_CLONE,
-		DEPOT_WIDGET_AUTOREPLACE,
-		WIDGET_LIST_END);
-
-	/* determine amount of items for scroller */
-	if (WP(w, depot_d).type == VEH_Train) {
-		hnum = 8;
-		for (num = 0; num < WP(w, depot_d).engine_count; num++) {
-			const Vehicle *v = vl[num];
-			hnum = maxu(hnum, v->u.rail.cached_total_length);
-		}
-		/* Always have 1 empty row, so people can change the setting of the train */
-		SetVScrollCount(w, WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count + 1);
-		SetHScrollCount(w, WagonLengthToPixels(hnum));
-	} else {
-		SetVScrollCount(w, (num + w->hscroll.cap - 1) / w->hscroll.cap);
-	}
-
-	/* locate the depot struct */
-	if (WP(w, depot_d).type == VEH_Aircraft) {
-		SetDParam(0, GetStationIndex(tile)); // Airport name
-	} else {
-		Depot *depot = GetDepotByTile(tile);
-		assert(depot != NULL);
-
-		SetDParam(0, depot->town_index);
-	}
-
-	DrawWindowWidgets(w);
-
-	num = w->vscroll.pos * boxes_in_each_row;
-	max = min(WP(w, depot_d).engine_count, num + (rows_in_display * boxes_in_each_row));
-
-	for (x = 2, y = 15; num < max; y += w->resize.step_height, x = 2) { // Draw the rows
-		byte i;
-
-		for (i = 0; i < boxes_in_each_row && num < max; i++, num++, x += w->resize.step_width) {
-			/* Draw all vehicles in the current row */
-			const Vehicle *v = vl[num];
-			DrawVehicleInDepot(w, v, x, y);
-		}
-	}
-
-	max = min(WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count, (w->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
-
-	/* draw the train wagons, that do not have an engine in front */
-	for (; num < max; num++, y += 14) {
-		const Vehicle *v = WP(w, depot_d).wagon_list[num - WP(w, depot_d).engine_count];
-		const Vehicle *u;
-
-		DrawTrainImage(v, x + 50, y, w->hscroll.cap - 29, 0, WP(w,depot_d).sel);
-		DrawString(x, y + 2, STR_8816, 0);
-
-		/*Draw the train counter */
-		i = 0;
-		u = v;
-		do i++; while ( (u=u->next) != NULL); // Determine length of train
-		SetDParam(0, i);                      // Set the counter
-		DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
-	}
-}
-
-typedef struct GetDepotVehiclePtData {
-	Vehicle *head;
-	Vehicle *wagon;
-} GetDepotVehiclePtData;
-
-enum {
-	MODE_ERROR        =  1,
-	MODE_DRAG_VEHICLE =  0,
-	MODE_SHOW_VEHICLE = -1,
-	MODE_START_STOP   = -2,
-};
-
-static int GetVehicleFromDepotWndPt(const Window *w, int x, int y, Vehicle **veh, GetDepotVehiclePtData *d)
-{
-	Vehicle **vl = WP(w, depot_d).vehicle_list;
-	uint xt, row, xm = 0, ym = 0;
-	int pos, skip = 0;
-	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
-	if (WP(w, depot_d).type == VEH_Train) {
-		xt = 0;
-		x -= 23;
-	} else {
-		xt = x / w->resize.step_width;
-		xm = x % w->resize.step_width;
-		if (xt >= w->hscroll.cap) return MODE_ERROR;
-
-		ym = (y - 14) % w->resize.step_height;
-	}
-
-	row = (y - 14) / w->resize.step_height;
-	if (row >= w->vscroll.cap) return MODE_ERROR;
-
-	pos = ((row + w->vscroll.pos) * boxes_in_each_row) + xt;
-
-	if (WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count <= pos) {
-		if (WP(w, depot_d).type == VEH_Train) {
-			d->head  = NULL;
-			d->wagon = NULL;
-			return MODE_DRAG_VEHICLE;
-		} else {
-			return MODE_ERROR; // empty block, so no vehicle is selected
-		}
-	}
-
-	if (WP(w, depot_d).engine_count > pos) {
-		*veh = vl[pos];
-		skip = w->hscroll.pos;
-	} else {
-		vl = WP(w, depot_d).wagon_list;
-		pos -= WP(w, depot_d).engine_count;
-		*veh = vl[pos];
-		/* free wagons don't have an initial loco. */
-		x -= _traininfo_vehicle_width;
-	}
-
-	switch (WP(w, depot_d).type) {
-		case VEH_Train: {
-			Vehicle *v = *veh;
-			d->head = d->wagon = v;
-
-			/* either pressed the flag or the number, but only when it's a loco */
-			if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
-
-			skip = (skip * 8) / _traininfo_vehicle_width;
-			x = (x * 8) / _traininfo_vehicle_width;
-
-			/* Skip vehicles that are scrolled off the list */
-			x += skip;
-
-			/* find the vehicle in this row that was clicked */
-			while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->next;
-
-			/* if an articulated part was selected, find its parent */
-			while (v != NULL && IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
-
-			d->wagon = v;
-
-			return MODE_DRAG_VEHICLE;
-			}
-			break;
-
-		case VEH_Road:
-			if (xm >= 24) return MODE_DRAG_VEHICLE;
-			if (xm <= 16) return MODE_SHOW_VEHICLE;
-			break;
-
-		case VEH_Ship:
-			if (xm >= 19) return MODE_DRAG_VEHICLE;
-			if (ym <= 10) return MODE_SHOW_VEHICLE;
-			break;
-
-		case VEH_Aircraft:
-			if (xm >= 12) return MODE_DRAG_VEHICLE;
-			if (ym <= 12) return MODE_SHOW_VEHICLE;
-			break;
-
-		default: NOT_REACHED();
-	}
-	return MODE_START_STOP;
-}
-
-static void TrainDepotMoveVehicle(Vehicle *wagon, VehicleID sel, Vehicle *head)
-{
-	Vehicle *v;
-
-	v = GetVehicle(sel);
-
-	if (v == wagon) return;
-
-	if (wagon == NULL) {
-		if (head != NULL) wagon = GetLastVehicleInChain(head);
-	} else  {
-		wagon = GetPrevVehicleInChain(wagon);
-		if (wagon == NULL) return;
-	}
-
-	if (wagon == v) return;
-
-	DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, NULL, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
-}
-
-static void DepotClick(Window *w, int x, int y)
-{
-	GetDepotVehiclePtData gdvp;
-	Vehicle *v = NULL;
-	int mode = GetVehicleFromDepotWndPt(w, x, y, &v, &gdvp);
-
-	/* share / copy orders */
-	if (_thd.place_mode && mode <= 0) {
-		_place_clicked_vehicle = (WP(w, depot_d).type == VEH_Train ? gdvp.head : v);
-		return;
-	}
-
-	if (WP(w, depot_d).type == VEH_Train) v = gdvp.wagon;
-
-	switch (mode) {
-		case MODE_ERROR: // invalid
-			return;
-
-		case MODE_DRAG_VEHICLE: { // start dragging of vehicle
-			VehicleID sel = WP(w, depot_d).sel;
-
-			if (WP(w, depot_d).type == VEH_Train && sel != INVALID_VEHICLE) {
-				WP(w,depot_d).sel = INVALID_VEHICLE;
-				TrainDepotMoveVehicle(v, sel, gdvp.head);
-			} else if (v != NULL) {
-				int image;
-
-				switch (WP(w, depot_d).type) {
-					case VEH_Train:    image = GetTrainImage(v, DIR_W);    break;
-					case VEH_Road:     image = GetRoadVehImage(v, DIR_W);  break;
-					case VEH_Ship:     image = GetShipImage(v, DIR_W);     break;
-					case VEH_Aircraft: image = GetAircraftImage(v, DIR_W); break;
-					default: NOT_REACHED(); image = 0;
-				}
-
-				WP(w, depot_d).sel = v->index;
-				SetWindowDirty(w);
-				SetObjectToPlaceWnd(GetVehiclePalette(v) | image, 4, w);
-			}
-			}
-			break;
-
-		case MODE_SHOW_VEHICLE: // show info window
-			ShowVehicleViewWindow(v);
-			break;
-
-		case MODE_START_STOP: { // click start/stop flag
-			uint command;
-
-			switch (WP(w, depot_d).type) {
-				case VEH_Train:    command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN);          break;
-				case VEH_Road:     command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
-				case VEH_Ship:     command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP);            break;
-				case VEH_Aircraft: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT);    break;
-				default: NOT_REACHED(); command = 0;
-			}
-			DoCommandP(v->tile, v->index, 0, NULL, command);
-			}
-			break;
-
-		default: NOT_REACHED();
-	}
-}
-
-/**
- * Clones a vehicle
- * @param *v is the original vehicle to clone
- * @param *w is the window of the depot where the clone is build
- */
-static void HandleCloneVehClick(const Vehicle *v, const Window *w)
-{
-	uint error_str;
-
-	if (v == NULL) return;
-
-	if (v->type == VEH_Train && !IsFrontEngine(v)) {
-		v = GetFirstVehicleInChain(v);
-		/* Do nothing when clicking on a train in depot with no loc attached */
-		if (!IsFrontEngine(v)) return;
-	}
-
-	switch (v->type) {
-		case VEH_Train:    error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
-		case VEH_Road:     error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE);     break;
-		case VEH_Ship:     error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP);             break;
-		case VEH_Aircraft: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT);         break;
-		default: return;
-	}
-
-	DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
-
-	ResetObjectToPlace();
-}
-
-static void ClonePlaceObj(const Window *w)
-{
-	const Vehicle *v = CheckMouseOverVehicle();
-
-	if (v != NULL) HandleCloneVehClick(v, w);
-}
-
-static void ResizeDepotButtons(Window *w)
-{
-	/* We got the widget moved around. Now we will make some widgets to fill the gap between some widgets in equal sizes */
-
-	/* Make the buttons in the bottom equal in size */
-	w->widget[DEPOT_WIDGET_BUILD].right    = w->widget[DEPOT_WIDGET_LOCATION].right / 3;
-	w->widget[DEPOT_WIDGET_LOCATION].left  = w->widget[DEPOT_WIDGET_BUILD].right * 2;
-	w->widget[DEPOT_WIDGET_CLONE].left     = w->widget[DEPOT_WIDGET_BUILD].right + 1;
-	w->widget[DEPOT_WIDGET_CLONE].right    = w->widget[DEPOT_WIDGET_LOCATION].left - 1;
-
-	if (WP(w, depot_d).type == VEH_Train) {
-		/* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
-		* This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
-		w->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top;
-		w->widget[DEPOT_WIDGET_SELL].bottom     = w->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
-	}
-}
-
-/* Function to set up vehicle specific sprites and strings
- * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
- * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
- */
-static void SetupStringsForDepotWindow(Window *w, byte type)
-{
-	switch (type) {
-		case VEH_Train:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_8800_TRAIN_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_8815_NEW_VEHICLES;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_TRAIN;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_TRAIN_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_TRAIN;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_TRAIN;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
-			break;
-
-		case VEH_Road:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9003_ROAD_VEHICLE_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9004_NEW_VEHICLES;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9023_BUILD_NEW_ROAD_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_ROAD_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_ROADVEH;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_ROADVEH;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
-			break;
-
-		case VEH_Ship:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9803_SHIP_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9804_NEW_SHIPS;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9820_BUILD_NEW_SHIP;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_SHIP;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_SHIP_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_SHIP;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_SHIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
-			break;
-
-		case VEH_Aircraft:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_A002_AIRCRAFT_HANGAR;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_HANGAR_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_A003_NEW_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_A022_BUILD_NEW_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
-			break;
-	}
-}
-
-static void CreateDepotListWindow(Window *w, byte type)
-{
-	WP(w, depot_d).type = type;
-	_backup_orders_tile = 0;
-
-	/* Resize the window according to the vehicle type */
-	switch (type) {
-		default: NOT_REACHED();
-		case VEH_Train:
-			w->vscroll.cap = 6;
-			w->hscroll.cap = 10 * 29;
-			w->resize.step_width = 1;
-			ResizeWindow(w, 56, 26);
-			break;
-
-		case VEH_Road:
-			w->vscroll.cap = 5;
-			w->hscroll.cap = 5;
-			w->resize.step_width = 56;
-			ResizeWindow(w, 10, 0);
-			break;
-
-		case VEH_Ship:
-			w->vscroll.cap = 3;
-			w->hscroll.cap = 3;
-			w->resize.step_width = 90;
-			ResizeWindow(w, 0, 2);
-			break;
-
-		case VEH_Aircraft:
-			w->vscroll.cap = 3;
-			w->hscroll.cap = 4;
-			w->resize.step_width = 74;
-			ResizeWindow(w, 26, 2);
-			break;
-	}
-
-	/* Set the minimum window size to the current window size */
-	w->resize.width = w->width;
-	w->resize.height = w->height;
-	w->resize.step_height = GetVehicleListHeight(type);
-
-	SetupStringsForDepotWindow(w, type);
-
-	w->widget[DEPOT_WIDGET_MATRIX].data =
-		(w->vscroll.cap * 0x100) // number of rows to draw on the background
-		+ (type == VEH_Train ? 1 : w->hscroll.cap); // number of boxes in each row. Trains always have just one
-
-
-	SetWindowWidgetsHiddenState(w, type != VEH_Train,
-		DEPOT_WIDGET_H_SCROLL,
-		DEPOT_WIDGET_SELL_CHAIN,
-		WIDGET_LIST_END);
-
-	/* The train depot has a horizontal scroller, make the matrix that much shorter to fit */
-	if (type == VEH_Train) w->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
-	ResizeDepotButtons(w);
-}
-
-void DepotSortList(Vehicle **v, uint16 length);
-
-static void DepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			WP(w, depot_d).sel = INVALID_VEHICLE;
-			WP(w, depot_d).vehicle_list  = NULL;
-			WP(w, depot_d).wagon_list    = NULL;
-			WP(w, depot_d).engine_count  = 0;
-			WP(w, depot_d).wagon_count   = 0;
-			WP(w, depot_d).generate_list = true;
-			break;
-
-		case WE_INVALIDATE_DATA:
-			WP(w, depot_d).generate_list = true;
-			break;
-
-		case WE_PAINT:
-			if (WP(w, depot_d).generate_list) {
-				/* Generate the vehicle list
-				 * It's ok to use the wagon pointers for non-trains as they will be ignored */
-				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
-					&WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
-					&WP(w, depot_d).wagon_list,   &WP(w, depot_d).wagon_list_length,  &WP(w, depot_d).wagon_count);
-				WP(w, depot_d).generate_list = false;
-				DepotSortList(WP(w, depot_d).vehicle_list, WP(w, depot_d).engine_count);
-//#ifndef NDEBUG
-#if 0
-/* We disabled this check for now, but will keep it to quickly make this test again later (if we change some code) */
-			} else {
-				/* Here we got a piece of code, that only checks if we got a different number of vehicles in the depot list and the number of vehicles actually being in the depot.
-				 * IF they aren't the same, then WE_INVALIDATE_DATA should have been called somewhere, but it wasn't and we got a bug
-				 * Since this is a time consuming check and not nice to memory fragmentation, it may not stay for long, but it's a good way to check this
-				 * We can turn it on/off by switching between #ifndef NDEBUG and #if 0 */
-				Vehicle **engines = NULL, **wagons = NULL;
-				uint16 engine_count = 0, engine_length = 0;
-				uint16 wagon_count  = 0, wagon_length  = 0;
-				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number, &engines, &engine_length, &engine_count,
-									  &wagons,  &wagon_length,  &wagon_count);
-
-				assert(engine_count == WP(w, depot_d).engine_count);
-				assert(wagon_count == WP(w, depot_d).wagon_count);
-				free((void*)engines);
-				free((void*)wagons);
-#endif
-			}
-			DrawDepotWindow(w);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case DEPOT_WIDGET_MATRIX: // List
-					DepotClick(w, e->we.click.pt.x, e->we.click.pt.y);
-					break;
-
-				case DEPOT_WIDGET_BUILD: // Build vehicle
-					ResetObjectToPlace();
-					switch (WP(w, depot_d).type) {
-						case VEH_Train:    ShowBuildTrainWindow(w->window_number);    break;
-						case VEH_Road:     ShowBuildRoadVehWindow(w->window_number);  break;
-						case VEH_Ship:     ShowBuildShipWindow(w->window_number);     break;
-						case VEH_Aircraft:
-							ShowBuildVehicleWindow(w->window_number, WP(w, depot_d).type);
-							break;
-					default: NOT_REACHED();
-					}
-					break;
-
-				case DEPOT_WIDGET_CLONE: // Clone button
-					InvalidateWidget(w, DEPOT_WIDGET_CLONE);
-					ToggleWidgetLoweredState(w, DEPOT_WIDGET_CLONE);
-
-					if (IsWindowWidgetLowered(w, DEPOT_WIDGET_CLONE)) {
-						static const CursorID clone_icons[] = {
-							SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
-							SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
-						};
-
-						_place_clicked_vehicle = NULL;
-						SetObjectToPlaceWnd(clone_icons[WP(w, depot_d).type - VEH_Train], VHM_RECT, w);
-					} else {
-						ResetObjectToPlace();
-					}
-						break;
-
-				case DEPOT_WIDGET_LOCATION: ScrollMainWindowToTile(w->window_number); break;
-
-				case DEPOT_WIDGET_STOP_ALL:
-				case DEPOT_WIDGET_START_ALL:
-					DoCommandP(w->window_number, 0, WP(w, depot_d).type | (e->we.click.widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
-					break;
-
-				case DEPOT_WIDGET_SELL_ALL:
-					/* Only open the confimation window if there are anything to sell */
-					if (WP(w, depot_d).engine_count != 0 || WP(w, depot_d).wagon_count != 0) {
-						static const StringID confirm_captions[] = {
-							STR_8800_TRAIN_DEPOT,
-							STR_9003_ROAD_VEHICLE_DEPOT,
-							STR_9803_SHIP_DEPOT,
-							STR_A002_AIRCRAFT_HANGAR
-						};
-						TileIndex tile = w->window_number;
-						byte vehtype = WP(w, depot_d).type;
-
-						SetDParam(0, (vehtype == VEH_Aircraft) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
-						ShowQuery(
-							confirm_captions[vehtype - VEH_Train],
-							STR_DEPOT_SELL_CONFIRMATION_TEXT,
-							w,
-							DepotSellAllConfirmationCallback
-						);
-					}
-					break;
-
-				case DEPOT_WIDGET_VEHICLE_LIST:
-					ShowVehDepotOrders(GetTileOwner(w->window_number), WP(w, depot_d).type, w->window_number);
-					break;
-
-				case DEPOT_WIDGET_AUTOREPLACE:
-					DoCommandP(w->window_number, WP(w, depot_d).type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
-					break;
-
-			}
-			break;
-
-		case WE_PLACE_OBJ: {
-			ClonePlaceObj(w);
-		} break;
-
-		case WE_ABORT_PLACE_OBJ: {
-			RaiseWindowWidget(w, DEPOT_WIDGET_CLONE);
-			InvalidateWidget(w, DEPOT_WIDGET_CLONE);
-		} break;
-
-			/* check if a vehicle in a depot was clicked.. */
-		case WE_MOUSELOOP: {
-			const Vehicle *v = _place_clicked_vehicle;
-
-			/* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
-			if (v != NULL && IsWindowWidgetLowered(w, DEPOT_WIDGET_CLONE)) {
-				_place_clicked_vehicle = NULL;
-				HandleCloneVehClick(v, w);
-			}
-		} break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_BUILD_VEHICLE, w->window_number);
-			free((void*)WP(w, depot_d).vehicle_list);
-			free((void*)WP(w, depot_d).wagon_list);
-			break;
-
-		case WE_DRAGDROP:
-			switch (e->we.click.widget) {
-				case DEPOT_WIDGET_MATRIX: {
-					Vehicle *v;
-					VehicleID sel = WP(w, depot_d).sel;
-
-					WP(w, depot_d).sel = INVALID_VEHICLE;
-					SetWindowDirty(w);
-
-					if (WP(w, depot_d).type == VEH_Train) {
-						GetDepotVehiclePtData gdvp;
-
-						if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
-							sel != INVALID_VEHICLE) {
-							if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
-								DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
-							} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
-								TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
-							} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
-								ShowTrainViewWindow(gdvp.head);
-							}
-						}
-					} else if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
-						v != NULL &&
-						sel == v->index) {
-						ShowVehicleViewWindow(v);
-					}
-				} break;
-
-				case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
-					if (!IsWindowWidgetDisabled(w, DEPOT_WIDGET_SELL) &&
-						WP(w, depot_d).sel != INVALID_VEHICLE) {
-						Vehicle *v;
-						uint command;
-						int sell_cmd;
-						bool is_engine;
-
-						if (IsWindowWidgetDisabled(w, e->we.click.widget)) return;
-						if (WP(w, depot_d).sel == INVALID_VEHICLE) return;
-
-						HandleButtonClick(w, e->we.click.widget);
-
-						v = GetVehicle(WP(w, depot_d).sel);
-						WP(w, depot_d).sel = INVALID_VEHICLE;
-						SetWindowDirty(w);
-
-						sell_cmd = (v->type == VEH_Train && (e->we.click.widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
-
-						is_engine = (!(v->type == VEH_Train && !IsFrontEngine(v)));
-
-						if (is_engine) {
-							_backup_orders_tile = v->tile;
-							BackupVehicleOrders(v, _backup_orders_data);
-						}
-
-						switch (v->type) {
-							case VEH_Train:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
-							case VEH_Road:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE);       break;
-							case VEH_Ship:     command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP);                   break;
-							case VEH_Aircraft: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT);           break;
-							default: NOT_REACHED(); command = 0;
-						}
-
-						if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
-					}
-					break;
-				default:
-					WP(w, depot_d).sel = INVALID_VEHICLE;
-					SetWindowDirty(w);
-			}
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->hscroll.cap += e->we.sizing.diff.x / (int)w->resize.step_width;
-			w->widget[DEPOT_WIDGET_MATRIX].data = (w->vscroll.cap << 8) + (WP(w, depot_d).type == VEH_Train ? 1 : w->hscroll.cap);
-			ResizeDepotButtons(w);
-			break;
-	}
-}
-
-/** Opens a depot window
- * @param tile The tile where the depot/hangar is located
- * @param type The type of vehicles in the depot
- */
-void ShowDepotWindow(TileIndex tile, byte type)
-{
-	Window *w;
-
-	switch (type) {
-		default: NOT_REACHED();
-		case VEH_Train:
-			w = AllocateWindowDescFront(&_train_depot_desc, tile); break;
-		case VEH_Road:
-			w = AllocateWindowDescFront(&_road_depot_desc, tile); break;
-		case VEH_Ship:
-			w = AllocateWindowDescFront(&_ship_depot_desc, tile); break;
-		case VEH_Aircraft:
-			w = AllocateWindowDescFront(&_aircraft_depot_desc, tile); break;
-	}
-
-	if (w != NULL) {
-		w->caption_color = GetTileOwner(tile);
-		CreateDepotListWindow(w, type);
-	}
-}
-
-/** Removes the highlight of a vehicle in a depot window
- * @param *v Vehicle to remove all highlights from
- */
-void DeleteDepotHighlightOfVehicle(const Vehicle *v)
-{
-	Window *w;
-
-	/* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either
-	 * If that is the case, we can skip looping though the windows and save time                                */
-	if (_special_mouse_mode != WSM_DRAGDROP) return;
-
-	w = FindWindowById(WC_VEHICLE_DEPOT, v->tile);
-	if (w != NULL) {
-		WP(w, depot_d).sel = INVALID_VEHICLE;
-		ResetObjectToPlace();
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/depot_gui.cpp
@@ -0,0 +1,954 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "train.h"
+#include "roadveh.h"
+#include "ship.h"
+#include "aircraft.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "gui.h"
+#include "gfx.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "command.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "station_map.h"
+#include "newgrf_engine.h"
+
+/*
+ * Since all depot window sizes aren't the same, we need to modify sizes a little.
+ * It's done with the following arrays of widget indexes. Each of them tells if a widget side should be moved and in what direction.
+ * How long they should be moved and for what window types are controlled in ShowDepotWindow()
+ */
+
+/* Names of the widgets. Keep them in the same order as in the widget array */
+enum DepotWindowWidgets {
+	DEPOT_WIDGET_CLOSEBOX = 0,
+	DEPOT_WIDGET_CAPTION,
+	DEPOT_WIDGET_STICKY,
+	DEPOT_WIDGET_SELL,
+	DEPOT_WIDGET_SELL_CHAIN,
+	DEPOT_WIDGET_SELL_ALL,
+	DEPOT_WIDGET_AUTOREPLACE,
+	DEPOT_WIDGET_MATRIX,
+	DEPOT_WIDGET_V_SCROLL, // Vertical scrollbar
+	DEPOT_WIDGET_H_SCROLL, // Horizontal scrollbar
+	DEPOT_WIDGET_BUILD,
+	DEPOT_WIDGET_CLONE,
+	DEPOT_WIDGET_LOCATION,
+	DEPOT_WIDGET_VEHICLE_LIST,
+	DEPOT_WIDGET_STOP_ALL,
+	DEPOT_WIDGET_START_ALL,
+	DEPOT_WIDGET_RESIZE,
+};
+
+/* Widget array for all depot windows.
+ * If a widget is needed in some windows only (like train specific), add it for all windows
+ * and use HideWindowWidget in ShowDepotWindow() to remove it in the windows where it should not be
+ * Keep the widget numbers in sync with the enum or really bad stuff will happen!!! */
+
+/* When adding widgets, place them as you would place them for the ship depot and define how you want it to move in widget_moves[]
+ * If you want a widget for one window only, set it to be hidden in ShowDepotWindow() for the windows where you don't want it
+ * NOTE: the train only widgets are moved/resized in ShowDepotWindow() so they follow certain other widgets if they are moved to ensure that they stick together.
+ *    Changing the size of those here will not have an effect at all. It should be done in ShowDepotWindow()
+ */
+static const Widget _depot_widgets[] = {
+	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},            // DEPOT_WIDGET_CLOSEBOX
+	{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   292,     0,    13, 0x0,                 STR_018C_WINDOW_TITLE_DRAG_THIS},  // DEPOT_WIDGET_CAPTION
+	{  WWT_STICKYBOX,     RESIZE_LR,    14,   293,   304,     0,    13, 0x0,                 STR_STICKY_BUTTON},                // DEPOT_WIDGET_STICKY
+
+	/* Widgets are set up run-time */
+	{     WWT_IMGBTN,    RESIZE_LRB,    14,   270,   292,    14,    37, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL
+	{     WWT_IMGBTN,   RESIZE_LRTB,    14,   270,   292,    14,    37, SPR_SELL_CHAIN_TRAIN,STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP}, // DEPOT_WIDGET_SELL_CHAIN, trains only
+	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   292,    38,    60, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL_ALL
+	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   292,    61,    83, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_AUTOREPLACE
+
+	{     WWT_MATRIX,     RESIZE_RB,    14,     0,   269,    14,    83, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_MATRIX
+	{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   293,   304,    14,    83, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_V_SCROLL
+
+	{ WWT_HSCROLLBAR,    RESIZE_RTB,    14,     0,   269,    72,    83, 0x0,                 STR_HSCROLL_BAR_SCROLLS_LIST},     // DEPOT_WIDGET_H_SCROLL, trains only
+
+	/* The buttons in the bottom of the window. left and right is not important as they are later resized to be equal in size
+	 * This calculation is based on right in DEPOT_WIDGET_LOCATION and it presumes left of DEPOT_WIDGET_BUILD is 0            */
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,    85,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_BUILD
+	{    WWT_TEXTBTN,     RESIZE_TB,    14,    86,   170,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_CLONE
+	{ WWT_PUSHTXTBTN,    RESIZE_RTB,    14,   171,   257,    84,    95, STR_00E4_LOCATION,   STR_NULL},                         // DEPOT_WIDGET_LOCATION
+	{ WWT_PUSHTXTBTN,   RESIZE_LRTB,    14,   258,   269,    84,    95, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_VEHICLE_LIST
+	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   270,   280,    84,    95, SPR_FLAG_VEH_STOPPED,STR_NULL},                         // DEPOT_WIDGET_STOP_ALL
+	{ WWT_PUSHIMGBTN,   RESIZE_LRTB,    14,   281,   292,    84,    95, SPR_FLAG_VEH_RUNNING,STR_NULL},                         // DEPOT_WIDGET_START_ALL
+	{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   293,   304,    84,    95, 0x0,                 STR_RESIZE_BUTTON},                // DEPOT_WIDGET_RESIZE
+	{   WIDGETS_END},
+};
+
+static void DepotWndProc(Window *w, WindowEvent *e);
+
+static const WindowDesc _train_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 305, 96,
+	WC_VEHICLE_DEPOT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_depot_widgets,
+	DepotWndProc
+};
+
+static const WindowDesc _road_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 305, 96,
+	WC_VEHICLE_DEPOT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_depot_widgets,
+	DepotWndProc
+};
+
+static const WindowDesc _ship_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 305, 96,
+	WC_VEHICLE_DEPOT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_depot_widgets,
+	DepotWndProc
+};
+
+static const WindowDesc _aircraft_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 305, 96,
+	WC_VEHICLE_DEPOT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_depot_widgets,
+	DepotWndProc
+};
+
+extern int WagonLengthToPixels(int len);
+
+void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (!success) return;
+	switch(GetVehicle(p1)->type) {
+		case VEH_Train:    CcCloneTrain(   true, tile, p1, p2); break;
+		case VEH_Road:     CcCloneRoadVeh( true, tile, p1, p2); break;
+		case VEH_Ship:     CcCloneShip(    true, tile, p1, p2); break;
+		case VEH_Aircraft: CcCloneAircraft(true, tile, p1, p2); break;
+	}
+}
+
+static inline void ShowVehicleViewWindow(const Vehicle *v)
+{
+	switch (v->type) {
+		case VEH_Train:    ShowTrainViewWindow(v);    break;
+		case VEH_Road:     ShowRoadVehViewWindow(v);  break;
+		case VEH_Ship:     ShowShipViewWindow(v);     break;
+		case VEH_Aircraft: ShowAircraftViewWindow(v); break;
+		default: NOT_REACHED();
+	}
+}
+
+static void DepotSellAllConfirmationCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		TileIndex tile = w->window_number;
+		byte vehtype = WP(w, depot_d).type;
+		DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
+	}
+}
+
+/** Draw a vehicle in the depot window in the box with the top left corner at x,y
+ * @param *w Window to draw in
+ * @param *v Vehicle to draw
+ * @param x Left side of the box to draw in
+ * @param y Top of the box to draw in
+ */
+static void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
+{
+	byte diff_x = 0, diff_y = 0;
+
+	switch (v->type) {
+		case VEH_Train:
+			DrawTrainImage(v, x + 21, y, w->hscroll.cap + 4, w->hscroll.pos, WP(w,depot_d).sel);
+
+			/* Number of wagons relative to a standard length wagon (rounded up) */
+			SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
+			DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
+			break;
+
+		case VEH_Road:     DrawRoadVehImage( v, x + 24, y, WP(w, depot_d).sel); break;
+		case VEH_Ship:     DrawShipImage(    v, x + 19, y, WP(w, depot_d).sel); break;
+		case VEH_Aircraft: DrawAircraftImage(v, x + 12, y, WP(w, depot_d).sel); break;
+		default: NOT_REACHED();
+	}
+
+	if (w->resize.step_height == 14) {
+		/* VEH_Train and VEH_Road, which are low */
+		diff_x = 15;
+	} else {
+		/* VEH_Ship and VEH_Aircraft, which are tall */
+		diff_y = 12;
+	}
+
+	DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, x + diff_x, y + diff_y);
+
+	SetDParam(0, v->unitnumber);
+	DrawString(x, y + 2, (uint16)(v->max_age-366) >= v->age ? STR_00E2 : STR_00E3, 0);
+}
+
+static void DrawDepotWindow(Window *w)
+{
+	Vehicle **vl = WP(w, depot_d).vehicle_list;
+	TileIndex tile = w->window_number;
+	int x, y, i, hnum, max;
+	uint16 num = WP(w, depot_d).engine_count;
+
+	/* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
+	uint16 rows_in_display   = w->widget[DEPOT_WIDGET_MATRIX].data >> 8;
+	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+	/* setup disabled buttons */
+	SetWindowWidgetsDisabledState(w, !IsTileOwner(tile, _local_player),
+		DEPOT_WIDGET_STOP_ALL,
+		DEPOT_WIDGET_START_ALL,
+		DEPOT_WIDGET_SELL,
+		DEPOT_WIDGET_SELL_CHAIN,
+		DEPOT_WIDGET_SELL_ALL,
+		DEPOT_WIDGET_BUILD,
+		DEPOT_WIDGET_CLONE,
+		DEPOT_WIDGET_AUTOREPLACE,
+		WIDGET_LIST_END);
+
+	/* determine amount of items for scroller */
+	if (WP(w, depot_d).type == VEH_Train) {
+		hnum = 8;
+		for (num = 0; num < WP(w, depot_d).engine_count; num++) {
+			const Vehicle *v = vl[num];
+			hnum = maxu(hnum, v->u.rail.cached_total_length);
+		}
+		/* Always have 1 empty row, so people can change the setting of the train */
+		SetVScrollCount(w, WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count + 1);
+		SetHScrollCount(w, WagonLengthToPixels(hnum));
+	} else {
+		SetVScrollCount(w, (num + w->hscroll.cap - 1) / w->hscroll.cap);
+	}
+
+	/* locate the depot struct */
+	if (WP(w, depot_d).type == VEH_Aircraft) {
+		SetDParam(0, GetStationIndex(tile)); // Airport name
+	} else {
+		Depot *depot = GetDepotByTile(tile);
+		assert(depot != NULL);
+
+		SetDParam(0, depot->town_index);
+	}
+
+	DrawWindowWidgets(w);
+
+	num = w->vscroll.pos * boxes_in_each_row;
+	max = min(WP(w, depot_d).engine_count, num + (rows_in_display * boxes_in_each_row));
+
+	for (x = 2, y = 15; num < max; y += w->resize.step_height, x = 2) { // Draw the rows
+		byte i;
+
+		for (i = 0; i < boxes_in_each_row && num < max; i++, num++, x += w->resize.step_width) {
+			/* Draw all vehicles in the current row */
+			const Vehicle *v = vl[num];
+			DrawVehicleInDepot(w, v, x, y);
+		}
+	}
+
+	max = min(WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count, (w->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
+
+	/* draw the train wagons, that do not have an engine in front */
+	for (; num < max; num++, y += 14) {
+		const Vehicle *v = WP(w, depot_d).wagon_list[num - WP(w, depot_d).engine_count];
+		const Vehicle *u;
+
+		DrawTrainImage(v, x + 50, y, w->hscroll.cap - 29, 0, WP(w,depot_d).sel);
+		DrawString(x, y + 2, STR_8816, 0);
+
+		/*Draw the train counter */
+		i = 0;
+		u = v;
+		do i++; while ( (u=u->next) != NULL); // Determine length of train
+		SetDParam(0, i);                      // Set the counter
+		DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
+	}
+}
+
+typedef struct GetDepotVehiclePtData {
+	Vehicle *head;
+	Vehicle *wagon;
+} GetDepotVehiclePtData;
+
+enum {
+	MODE_ERROR        =  1,
+	MODE_DRAG_VEHICLE =  0,
+	MODE_SHOW_VEHICLE = -1,
+	MODE_START_STOP   = -2,
+};
+
+static int GetVehicleFromDepotWndPt(const Window *w, int x, int y, Vehicle **veh, GetDepotVehiclePtData *d)
+{
+	Vehicle **vl = WP(w, depot_d).vehicle_list;
+	uint xt, row, xm = 0, ym = 0;
+	int pos, skip = 0;
+	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+	if (WP(w, depot_d).type == VEH_Train) {
+		xt = 0;
+		x -= 23;
+	} else {
+		xt = x / w->resize.step_width;
+		xm = x % w->resize.step_width;
+		if (xt >= w->hscroll.cap) return MODE_ERROR;
+
+		ym = (y - 14) % w->resize.step_height;
+	}
+
+	row = (y - 14) / w->resize.step_height;
+	if (row >= w->vscroll.cap) return MODE_ERROR;
+
+	pos = ((row + w->vscroll.pos) * boxes_in_each_row) + xt;
+
+	if (WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count <= pos) {
+		if (WP(w, depot_d).type == VEH_Train) {
+			d->head  = NULL;
+			d->wagon = NULL;
+			return MODE_DRAG_VEHICLE;
+		} else {
+			return MODE_ERROR; // empty block, so no vehicle is selected
+		}
+	}
+
+	if (WP(w, depot_d).engine_count > pos) {
+		*veh = vl[pos];
+		skip = w->hscroll.pos;
+	} else {
+		vl = WP(w, depot_d).wagon_list;
+		pos -= WP(w, depot_d).engine_count;
+		*veh = vl[pos];
+		/* free wagons don't have an initial loco. */
+		x -= _traininfo_vehicle_width;
+	}
+
+	switch (WP(w, depot_d).type) {
+		case VEH_Train: {
+			Vehicle *v = *veh;
+			d->head = d->wagon = v;
+
+			/* either pressed the flag or the number, but only when it's a loco */
+			if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
+
+			skip = (skip * 8) / _traininfo_vehicle_width;
+			x = (x * 8) / _traininfo_vehicle_width;
+
+			/* Skip vehicles that are scrolled off the list */
+			x += skip;
+
+			/* find the vehicle in this row that was clicked */
+			while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->next;
+
+			/* if an articulated part was selected, find its parent */
+			while (v != NULL && IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
+
+			d->wagon = v;
+
+			return MODE_DRAG_VEHICLE;
+			}
+			break;
+
+		case VEH_Road:
+			if (xm >= 24) return MODE_DRAG_VEHICLE;
+			if (xm <= 16) return MODE_SHOW_VEHICLE;
+			break;
+
+		case VEH_Ship:
+			if (xm >= 19) return MODE_DRAG_VEHICLE;
+			if (ym <= 10) return MODE_SHOW_VEHICLE;
+			break;
+
+		case VEH_Aircraft:
+			if (xm >= 12) return MODE_DRAG_VEHICLE;
+			if (ym <= 12) return MODE_SHOW_VEHICLE;
+			break;
+
+		default: NOT_REACHED();
+	}
+	return MODE_START_STOP;
+}
+
+static void TrainDepotMoveVehicle(Vehicle *wagon, VehicleID sel, Vehicle *head)
+{
+	Vehicle *v;
+
+	v = GetVehicle(sel);
+
+	if (v == wagon) return;
+
+	if (wagon == NULL) {
+		if (head != NULL) wagon = GetLastVehicleInChain(head);
+	} else  {
+		wagon = GetPrevVehicleInChain(wagon);
+		if (wagon == NULL) return;
+	}
+
+	if (wagon == v) return;
+
+	DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, NULL, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
+}
+
+static void DepotClick(Window *w, int x, int y)
+{
+	GetDepotVehiclePtData gdvp;
+	Vehicle *v = NULL;
+	int mode = GetVehicleFromDepotWndPt(w, x, y, &v, &gdvp);
+
+	/* share / copy orders */
+	if (_thd.place_mode && mode <= 0) {
+		_place_clicked_vehicle = (WP(w, depot_d).type == VEH_Train ? gdvp.head : v);
+		return;
+	}
+
+	if (WP(w, depot_d).type == VEH_Train) v = gdvp.wagon;
+
+	switch (mode) {
+		case MODE_ERROR: // invalid
+			return;
+
+		case MODE_DRAG_VEHICLE: { // start dragging of vehicle
+			VehicleID sel = WP(w, depot_d).sel;
+
+			if (WP(w, depot_d).type == VEH_Train && sel != INVALID_VEHICLE) {
+				WP(w,depot_d).sel = INVALID_VEHICLE;
+				TrainDepotMoveVehicle(v, sel, gdvp.head);
+			} else if (v != NULL) {
+				int image;
+
+				switch (WP(w, depot_d).type) {
+					case VEH_Train:    image = GetTrainImage(v, DIR_W);    break;
+					case VEH_Road:     image = GetRoadVehImage(v, DIR_W);  break;
+					case VEH_Ship:     image = GetShipImage(v, DIR_W);     break;
+					case VEH_Aircraft: image = GetAircraftImage(v, DIR_W); break;
+					default: NOT_REACHED(); image = 0;
+				}
+
+				WP(w, depot_d).sel = v->index;
+				SetWindowDirty(w);
+				SetObjectToPlaceWnd(GetVehiclePalette(v) | image, 4, w);
+			}
+			}
+			break;
+
+		case MODE_SHOW_VEHICLE: // show info window
+			ShowVehicleViewWindow(v);
+			break;
+
+		case MODE_START_STOP: { // click start/stop flag
+			uint command;
+
+			switch (WP(w, depot_d).type) {
+				case VEH_Train:    command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN);          break;
+				case VEH_Road:     command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
+				case VEH_Ship:     command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP);            break;
+				case VEH_Aircraft: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT);    break;
+				default: NOT_REACHED(); command = 0;
+			}
+			DoCommandP(v->tile, v->index, 0, NULL, command);
+			}
+			break;
+
+		default: NOT_REACHED();
+	}
+}
+
+/**
+ * Clones a vehicle
+ * @param *v is the original vehicle to clone
+ * @param *w is the window of the depot where the clone is build
+ */
+static void HandleCloneVehClick(const Vehicle *v, const Window *w)
+{
+	uint error_str;
+
+	if (v == NULL) return;
+
+	if (v->type == VEH_Train && !IsFrontEngine(v)) {
+		v = GetFirstVehicleInChain(v);
+		/* Do nothing when clicking on a train in depot with no loc attached */
+		if (!IsFrontEngine(v)) return;
+	}
+
+	switch (v->type) {
+		case VEH_Train:    error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
+		case VEH_Road:     error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE);     break;
+		case VEH_Ship:     error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP);             break;
+		case VEH_Aircraft: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT);         break;
+		default: return;
+	}
+
+	DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
+
+	ResetObjectToPlace();
+}
+
+static void ClonePlaceObj(const Window *w)
+{
+	const Vehicle *v = CheckMouseOverVehicle();
+
+	if (v != NULL) HandleCloneVehClick(v, w);
+}
+
+static void ResizeDepotButtons(Window *w)
+{
+	/* We got the widget moved around. Now we will make some widgets to fill the gap between some widgets in equal sizes */
+
+	/* Make the buttons in the bottom equal in size */
+	w->widget[DEPOT_WIDGET_BUILD].right    = w->widget[DEPOT_WIDGET_LOCATION].right / 3;
+	w->widget[DEPOT_WIDGET_LOCATION].left  = w->widget[DEPOT_WIDGET_BUILD].right * 2;
+	w->widget[DEPOT_WIDGET_CLONE].left     = w->widget[DEPOT_WIDGET_BUILD].right + 1;
+	w->widget[DEPOT_WIDGET_CLONE].right    = w->widget[DEPOT_WIDGET_LOCATION].left - 1;
+
+	if (WP(w, depot_d).type == VEH_Train) {
+		/* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
+		* This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
+		w->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top;
+		w->widget[DEPOT_WIDGET_SELL].bottom     = w->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
+	}
+}
+
+/* Function to set up vehicle specific sprites and strings
+ * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
+ * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
+ */
+static void SetupStringsForDepotWindow(Window *w, byte type)
+{
+	switch (type) {
+		case VEH_Train:
+			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_8800_TRAIN_DEPOT;
+			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
+			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_TRAIN_TIP;
+			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
+			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
+			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
+
+			w->widget[DEPOT_WIDGET_BUILD].data        = STR_8815_NEW_VEHICLES;
+			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
+			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_TRAIN;
+			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_TRAIN_DEPOT_INFO;
+
+			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
+
+			/* Sprites */
+			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_TRAIN;
+			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_TRAIN;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
+			break;
+
+		case VEH_Road:
+			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9003_ROAD_VEHICLE_DEPOT;
+			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
+			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_ROADVEH_TIP;
+			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
+			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
+			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
+
+			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9004_NEW_VEHICLES;
+			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9023_BUILD_NEW_ROAD_VEHICLE;
+			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_ROAD_VEHICLE;
+			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
+
+			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
+
+			/* Sprites */
+			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_ROADVEH;
+			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_ROADVEH;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
+			break;
+
+		case VEH_Ship:
+			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9803_SHIP_DEPOT;
+			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
+			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_DEPOT_SHIP_TIP;
+			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
+			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
+			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
+
+			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9804_NEW_SHIPS;
+			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9820_BUILD_NEW_SHIP;
+			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_SHIP;
+			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_SHIP_DEPOT_INFO;
+
+			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
+
+			/* Sprites */
+			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_SHIP;
+			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_SHIP;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
+			break;
+
+		case VEH_Aircraft:
+			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_A002_AIRCRAFT_HANGAR;
+			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
+			w->widget[DEPOT_WIDGET_START_ALL].tooltips=	STR_MASS_START_HANGAR_TIP;
+			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
+			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips =	STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
+			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
+
+			w->widget[DEPOT_WIDGET_BUILD].data        = STR_A003_NEW_AIRCRAFT;
+			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_A022_BUILD_NEW_AIRCRAFT;
+			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_AIRCRAFT;
+			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
+
+			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
+			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
+
+			/* Sprites */
+			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_AIRCRAFT;
+			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_AIRCRAFT;
+			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
+			break;
+	}
+}
+
+static void CreateDepotListWindow(Window *w, byte type)
+{
+	WP(w, depot_d).type = type;
+	_backup_orders_tile = 0;
+
+	/* Resize the window according to the vehicle type */
+	switch (type) {
+		default: NOT_REACHED();
+		case VEH_Train:
+			w->vscroll.cap = 6;
+			w->hscroll.cap = 10 * 29;
+			w->resize.step_width = 1;
+			ResizeWindow(w, 56, 26);
+			break;
+
+		case VEH_Road:
+			w->vscroll.cap = 5;
+			w->hscroll.cap = 5;
+			w->resize.step_width = 56;
+			ResizeWindow(w, 10, 0);
+			break;
+
+		case VEH_Ship:
+			w->vscroll.cap = 3;
+			w->hscroll.cap = 3;
+			w->resize.step_width = 90;
+			ResizeWindow(w, 0, 2);
+			break;
+
+		case VEH_Aircraft:
+			w->vscroll.cap = 3;
+			w->hscroll.cap = 4;
+			w->resize.step_width = 74;
+			ResizeWindow(w, 26, 2);
+			break;
+	}
+
+	/* Set the minimum window size to the current window size */
+	w->resize.width = w->width;
+	w->resize.height = w->height;
+	w->resize.step_height = GetVehicleListHeight(type);
+
+	SetupStringsForDepotWindow(w, type);
+
+	w->widget[DEPOT_WIDGET_MATRIX].data =
+		(w->vscroll.cap * 0x100) // number of rows to draw on the background
+		+ (type == VEH_Train ? 1 : w->hscroll.cap); // number of boxes in each row. Trains always have just one
+
+
+	SetWindowWidgetsHiddenState(w, type != VEH_Train,
+		DEPOT_WIDGET_H_SCROLL,
+		DEPOT_WIDGET_SELL_CHAIN,
+		WIDGET_LIST_END);
+
+	/* The train depot has a horizontal scroller, make the matrix that much shorter to fit */
+	if (type == VEH_Train) w->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
+	ResizeDepotButtons(w);
+}
+
+void DepotSortList(Vehicle **v, uint16 length);
+
+static void DepotWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_CREATE:
+			WP(w, depot_d).sel = INVALID_VEHICLE;
+			WP(w, depot_d).vehicle_list  = NULL;
+			WP(w, depot_d).wagon_list    = NULL;
+			WP(w, depot_d).engine_count  = 0;
+			WP(w, depot_d).wagon_count   = 0;
+			WP(w, depot_d).generate_list = true;
+			break;
+
+		case WE_INVALIDATE_DATA:
+			WP(w, depot_d).generate_list = true;
+			break;
+
+		case WE_PAINT:
+			if (WP(w, depot_d).generate_list) {
+				/* Generate the vehicle list
+				 * It's ok to use the wagon pointers for non-trains as they will be ignored */
+				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
+					&WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
+					&WP(w, depot_d).wagon_list,   &WP(w, depot_d).wagon_list_length,  &WP(w, depot_d).wagon_count);
+				WP(w, depot_d).generate_list = false;
+				DepotSortList(WP(w, depot_d).vehicle_list, WP(w, depot_d).engine_count);
+//#ifndef NDEBUG
+#if 0
+/* We disabled this check for now, but will keep it to quickly make this test again later (if we change some code) */
+			} else {
+				/* Here we got a piece of code, that only checks if we got a different number of vehicles in the depot list and the number of vehicles actually being in the depot.
+				 * IF they aren't the same, then WE_INVALIDATE_DATA should have been called somewhere, but it wasn't and we got a bug
+				 * Since this is a time consuming check and not nice to memory fragmentation, it may not stay for long, but it's a good way to check this
+				 * We can turn it on/off by switching between #ifndef NDEBUG and #if 0 */
+				Vehicle **engines = NULL, **wagons = NULL;
+				uint16 engine_count = 0, engine_length = 0;
+				uint16 wagon_count  = 0, wagon_length  = 0;
+				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number, &engines, &engine_length, &engine_count,
+									  &wagons,  &wagon_length,  &wagon_count);
+
+				assert(engine_count == WP(w, depot_d).engine_count);
+				assert(wagon_count == WP(w, depot_d).wagon_count);
+				free((void*)engines);
+				free((void*)wagons);
+#endif
+			}
+			DrawDepotWindow(w);
+			break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case DEPOT_WIDGET_MATRIX: // List
+					DepotClick(w, e->we.click.pt.x, e->we.click.pt.y);
+					break;
+
+				case DEPOT_WIDGET_BUILD: // Build vehicle
+					ResetObjectToPlace();
+					switch (WP(w, depot_d).type) {
+						case VEH_Train:    ShowBuildTrainWindow(w->window_number);    break;
+						case VEH_Road:     ShowBuildRoadVehWindow(w->window_number);  break;
+						case VEH_Ship:     ShowBuildShipWindow(w->window_number);     break;
+						case VEH_Aircraft:
+							ShowBuildVehicleWindow(w->window_number, WP(w, depot_d).type);
+							break;
+					default: NOT_REACHED();
+					}
+					break;
+
+				case DEPOT_WIDGET_CLONE: // Clone button
+					InvalidateWidget(w, DEPOT_WIDGET_CLONE);
+					ToggleWidgetLoweredState(w, DEPOT_WIDGET_CLONE);
+
+					if (IsWindowWidgetLowered(w, DEPOT_WIDGET_CLONE)) {
+						static const CursorID clone_icons[] = {
+							SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
+							SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
+						};
+
+						_place_clicked_vehicle = NULL;
+						SetObjectToPlaceWnd(clone_icons[WP(w, depot_d).type - VEH_Train], VHM_RECT, w);
+					} else {
+						ResetObjectToPlace();
+					}
+						break;
+
+				case DEPOT_WIDGET_LOCATION: ScrollMainWindowToTile(w->window_number); break;
+
+				case DEPOT_WIDGET_STOP_ALL:
+				case DEPOT_WIDGET_START_ALL:
+					DoCommandP(w->window_number, 0, WP(w, depot_d).type | (e->we.click.widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
+					break;
+
+				case DEPOT_WIDGET_SELL_ALL:
+					/* Only open the confimation window if there are anything to sell */
+					if (WP(w, depot_d).engine_count != 0 || WP(w, depot_d).wagon_count != 0) {
+						static const StringID confirm_captions[] = {
+							STR_8800_TRAIN_DEPOT,
+							STR_9003_ROAD_VEHICLE_DEPOT,
+							STR_9803_SHIP_DEPOT,
+							STR_A002_AIRCRAFT_HANGAR
+						};
+						TileIndex tile = w->window_number;
+						byte vehtype = WP(w, depot_d).type;
+
+						SetDParam(0, (vehtype == VEH_Aircraft) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
+						ShowQuery(
+							confirm_captions[vehtype - VEH_Train],
+							STR_DEPOT_SELL_CONFIRMATION_TEXT,
+							w,
+							DepotSellAllConfirmationCallback
+						);
+					}
+					break;
+
+				case DEPOT_WIDGET_VEHICLE_LIST:
+					ShowVehDepotOrders(GetTileOwner(w->window_number), WP(w, depot_d).type, w->window_number);
+					break;
+
+				case DEPOT_WIDGET_AUTOREPLACE:
+					DoCommandP(w->window_number, WP(w, depot_d).type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
+					break;
+
+			}
+			break;
+
+		case WE_PLACE_OBJ: {
+			ClonePlaceObj(w);
+		} break;
+
+		case WE_ABORT_PLACE_OBJ: {
+			RaiseWindowWidget(w, DEPOT_WIDGET_CLONE);
+			InvalidateWidget(w, DEPOT_WIDGET_CLONE);
+		} break;
+
+			/* check if a vehicle in a depot was clicked.. */
+		case WE_MOUSELOOP: {
+			const Vehicle *v = _place_clicked_vehicle;
+
+			/* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
+			if (v != NULL && IsWindowWidgetLowered(w, DEPOT_WIDGET_CLONE)) {
+				_place_clicked_vehicle = NULL;
+				HandleCloneVehClick(v, w);
+			}
+		} break;
+
+		case WE_DESTROY:
+			DeleteWindowById(WC_BUILD_VEHICLE, w->window_number);
+			free((void*)WP(w, depot_d).vehicle_list);
+			free((void*)WP(w, depot_d).wagon_list);
+			break;
+
+		case WE_DRAGDROP:
+			switch (e->we.click.widget) {
+				case DEPOT_WIDGET_MATRIX: {
+					Vehicle *v;
+					VehicleID sel = WP(w, depot_d).sel;
+
+					WP(w, depot_d).sel = INVALID_VEHICLE;
+					SetWindowDirty(w);
+
+					if (WP(w, depot_d).type == VEH_Train) {
+						GetDepotVehiclePtData gdvp;
+
+						if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
+							sel != INVALID_VEHICLE) {
+							if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
+								DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
+							} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
+								TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
+							} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
+								ShowTrainViewWindow(gdvp.head);
+							}
+						}
+					} else if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
+						v != NULL &&
+						sel == v->index) {
+						ShowVehicleViewWindow(v);
+					}
+				} break;
+
+				case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
+					if (!IsWindowWidgetDisabled(w, DEPOT_WIDGET_SELL) &&
+						WP(w, depot_d).sel != INVALID_VEHICLE) {
+						Vehicle *v;
+						uint command;
+						int sell_cmd;
+						bool is_engine;
+
+						if (IsWindowWidgetDisabled(w, e->we.click.widget)) return;
+						if (WP(w, depot_d).sel == INVALID_VEHICLE) return;
+
+						HandleButtonClick(w, e->we.click.widget);
+
+						v = GetVehicle(WP(w, depot_d).sel);
+						WP(w, depot_d).sel = INVALID_VEHICLE;
+						SetWindowDirty(w);
+
+						sell_cmd = (v->type == VEH_Train && (e->we.click.widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
+
+						is_engine = (!(v->type == VEH_Train && !IsFrontEngine(v)));
+
+						if (is_engine) {
+							_backup_orders_tile = v->tile;
+							BackupVehicleOrders(v, _backup_orders_data);
+						}
+
+						switch (v->type) {
+							case VEH_Train:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
+							case VEH_Road:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE);       break;
+							case VEH_Ship:     command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP);                   break;
+							case VEH_Aircraft: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT);           break;
+							default: NOT_REACHED(); command = 0;
+						}
+
+						if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
+					}
+					break;
+				default:
+					WP(w, depot_d).sel = INVALID_VEHICLE;
+					SetWindowDirty(w);
+			}
+			break;
+
+		case WE_RESIZE:
+			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
+			w->hscroll.cap += e->we.sizing.diff.x / (int)w->resize.step_width;
+			w->widget[DEPOT_WIDGET_MATRIX].data = (w->vscroll.cap << 8) + (WP(w, depot_d).type == VEH_Train ? 1 : w->hscroll.cap);
+			ResizeDepotButtons(w);
+			break;
+	}
+}
+
+/** Opens a depot window
+ * @param tile The tile where the depot/hangar is located
+ * @param type The type of vehicles in the depot
+ */
+void ShowDepotWindow(TileIndex tile, byte type)
+{
+	Window *w;
+
+	switch (type) {
+		default: NOT_REACHED();
+		case VEH_Train:
+			w = AllocateWindowDescFront(&_train_depot_desc, tile); break;
+		case VEH_Road:
+			w = AllocateWindowDescFront(&_road_depot_desc, tile); break;
+		case VEH_Ship:
+			w = AllocateWindowDescFront(&_ship_depot_desc, tile); break;
+		case VEH_Aircraft:
+			w = AllocateWindowDescFront(&_aircraft_depot_desc, tile); break;
+	}
+
+	if (w != NULL) {
+		w->caption_color = GetTileOwner(tile);
+		CreateDepotListWindow(w, type);
+	}
+}
+
+/** Removes the highlight of a vehicle in a depot window
+ * @param *v Vehicle to remove all highlights from
+ */
+void DeleteDepotHighlightOfVehicle(const Vehicle *v)
+{
+	Window *w;
+
+	/* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either
+	 * If that is the case, we can skip looping though the windows and save time                                */
+	if (_special_mouse_mode != WSM_DRAGDROP) return;
+
+	w = FindWindowById(WC_VEHICLE_DEPOT, v->tile);
+	if (w != NULL) {
+		WP(w, depot_d).sel = INVALID_VEHICLE;
+		ResetObjectToPlace();
+	}
+}
deleted file mode 100644
--- a/src/disaster_cmd.c
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "industry_map.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
-#include "command.h"
-#include "news.h"
-#include "station.h"
-#include "waypoint.h"
-#include "town.h"
-#include "industry.h"
-#include "player.h"
-#include "airport.h"
-#include "sound.h"
-#include "variables.h"
-#include "table/sprites.h"
-#include "date.h"
-
-static void DisasterClearSquare(TileIndex tile)
-{
-	if (!EnsureNoVehicle(tile)) return;
-
-	switch (GetTileType(tile)) {
-		case MP_RAILWAY:
-			if (IsHumanPlayer(GetTileOwner(tile)) && !IsRailWaypoint(tile)) {
-				PlayerID p = _current_player;
-				_current_player = OWNER_WATER;
-				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-				_current_player = p;
-			}
-			break;
-
-		case MP_HOUSE: {
-			PlayerID p = _current_player;
-			_current_player = OWNER_NONE;
-			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-			_current_player = p;
-			break;
-		}
-
-		case MP_TREES:
-		case MP_CLEAR:
-			DoClearSquare(tile);
-			break;
-
-		default:
-			break;
-	}
-}
-
-static const SpriteID _disaster_images_1[] = {0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41};
-static const SpriteID _disaster_images_2[] = {0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44};
-static const SpriteID _disaster_images_3[] = {0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E};
-static const SpriteID _disaster_images_4[] = {0xF46, 0xF46, 0xF47, 0xF47, 0xF48, 0xF48, 0xF49, 0xF49};
-static const SpriteID _disaster_images_5[] = {0xF4A, 0xF4A, 0xF4B, 0xF4B, 0xF4C, 0xF4C, 0xF4D, 0xF4D};
-static const SpriteID _disaster_images_6[] = {0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50};
-static const SpriteID _disaster_images_7[] = {0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51};
-static const SpriteID _disaster_images_8[] = {0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52};
-static const SpriteID _disaster_images_9[] = {0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E};
-
-static const SpriteID * const _disaster_images[] = {
-	_disaster_images_1, _disaster_images_1,
-	_disaster_images_2, _disaster_images_2,
-	_disaster_images_3, _disaster_images_3,
-	_disaster_images_8, _disaster_images_8, _disaster_images_9,
-	_disaster_images_6, _disaster_images_6,
-	_disaster_images_7, _disaster_images_7,
-	_disaster_images_4, _disaster_images_5,
-};
-
-static void DisasterVehicleUpdateImage(Vehicle *v)
-{
-	int img = v->u.disaster.image_override;
-	if (img == 0)
-		img = _disaster_images[v->subtype][v->direction];
-	v->cur_image = img;
-}
-
-static void InitializeDisasterVehicle(Vehicle* v, int x, int y, byte z, Direction direction, byte subtype)
-{
-	v->type = VEH_Disaster;
-	v->x_pos = x;
-	v->y_pos = y;
-	v->z_pos = z;
-	v->tile = TileVirtXY(x, y);
-	v->direction = direction;
-	v->subtype = subtype;
-	v->x_offs = -1;
-	v->y_offs = -1;
-	v->sprite_width = 2;
-	v->sprite_height = 2;
-	v->z_height = 5;
-	v->owner = OWNER_NONE;
-	v->vehstatus = VS_UNCLICKABLE;
-	v->u.disaster.image_override = 0;
-	v->current_order.type = OT_NOTHING;
-	v->current_order.flags = 0;
-	v->current_order.dest = 0;
-
-	DisasterVehicleUpdateImage(v);
-	VehiclePositionChanged(v);
-	BeginVehicleMove(v);
-	EndVehicleMove(v);
-}
-
-static void DeleteDisasterVeh(Vehicle *v)
-{
-	DeleteVehicleChain(v);
-}
-
-static void SetDisasterVehiclePos(Vehicle *v, int x, int y, byte z)
-{
-	Vehicle *u;
-
-	BeginVehicleMove(v);
-	v->x_pos = x;
-	v->y_pos = y;
-	v->z_pos = z;
-	v->tile = TileVirtXY(x, y);
-
-	DisasterVehicleUpdateImage(v);
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-
-	if ( (u=v->next) != NULL) {
-		int safe_x = clamp(x, 0, MapMaxX() * TILE_SIZE);
-		int safe_y = clamp(y - 1, 0, MapMaxY() * TILE_SIZE);
-		BeginVehicleMove(u);
-
-		u->x_pos = x;
-		u->y_pos = y - 1 - (max(z - GetSlopeZ(safe_x, safe_y), 0) >> 3);
-		safe_y = clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
-		u->z_pos = GetSlopeZ(safe_x, safe_y);
-		u->direction = v->direction;
-
-		DisasterVehicleUpdateImage(u);
-		VehiclePositionChanged(u);
-		EndVehicleMove(u);
-
-		if ( (u=u->next) != NULL) {
-			BeginVehicleMove(u);
-			u->x_pos = x;
-			u->y_pos = y;
-			u->z_pos = z + 5;
-			VehiclePositionChanged(u);
-			EndVehicleMove(u);
-		}
-	}
-}
-
-
-static void DisasterTick_Zeppeliner(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-	Station *st;
-	int x,y;
-	byte z;
-	TileIndex tile;
-
-	++v->tick_counter;
-
-	if (v->current_order.dest < 2) {
-		if (v->tick_counter&1)
-			return;
-
-		GetNewVehiclePos(v, &gp);
-
-		SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-
-		if (v->current_order.dest == 1) {
-			if (++v->age == 38) {
-				v->current_order.dest = 2;
-				v->age = 0;
-			}
-
-			if ((v->tick_counter&7)==0) {
-				CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE);
-			}
-		} else if (v->current_order.dest == 0) {
-			tile = v->tile; /**/
-
-			if (IsValidTile(tile) &&
-					IsTileType(tile, MP_STATION) &&
-					IsAirport(tile) &&
-					IsHumanPlayer(GetTileOwner(tile))) {
-				v->current_order.dest = 1;
-				v->age = 0;
-
-				SetDParam(0, GetStationIndex(tile));
-				AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
-					NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
-					v->index,
-					0);
-			}
-		}
-		if (v->y_pos >= ((int)MapSizeY() + 9) * TILE_SIZE - 1)
-			DeleteDisasterVeh(v);
-		return;
-	}
-
-	if (v->current_order.dest > 2) {
-		if (++v->age <= 13320)
-			return;
-
-		tile = v->tile; /**/
-
-		if (IsValidTile(tile) &&
-				IsTileType(tile, MP_STATION) &&
-				IsAirport(tile) &&
-				IsHumanPlayer(GetTileOwner(tile))) {
-			st = GetStationByTile(tile);
-			CLRBITS(st->airport_flags, RUNWAY_IN_block);
-		}
-
-		SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos);
-		DeleteDisasterVeh(v);
-		return;
-	}
-
-	x = v->x_pos;
-	y = v->y_pos;
-	z = GetSlopeZ(x,y);
-	if (z < v->z_pos)
-		z = v->z_pos - 1;
-	SetDisasterVehiclePos(v, x, y, z);
-
-	if (++v->age == 1) {
-		CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
-		SndPlayVehicleFx(SND_12_EXPLOSION, v);
-		v->u.disaster.image_override = SPR_BLIMP_CRASHING;
-	} else if (v->age == 70) {
-		v->u.disaster.image_override = SPR_BLIMP_CRASHED;
-	} else if (v->age <= 300) {
-		if (!(v->tick_counter&7)) {
-			uint32 r = Random();
-
-			CreateEffectVehicleRel(v,
-				GB(r, 0, 4) - 7,
-				GB(r, 4, 4) - 7,
-				GB(r, 8, 3) + 5,
-				EV_EXPLOSION_SMALL);
-		}
-	} else if (v->age == 350) {
-		v->current_order.dest = 3;
-		v->age = 0;
-	}
-
-	tile = v->tile;/**/
-	if (IsValidTile(tile) &&
-			IsTileType(tile, MP_STATION) &&
-			IsAirport(tile) &&
-			IsHumanPlayer(GetTileOwner(tile))) {
-		st = GetStationByTile(tile);
-		SETBITS(st->airport_flags, RUNWAY_IN_block);
-	}
-}
-
-// UFO starts in the middle, and flies around a bit until it locates
-// a road vehicle which it targets.
-static void DisasterTick_UFO(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-	Vehicle *u;
-	uint dist;
-	byte z;
-
-	v->u.disaster.image_override = (++v->tick_counter & 8) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT;
-
-	if (v->current_order.dest == 0) {
-// fly around randomly
-		int x = TileX(v->dest_tile) * TILE_SIZE;
-		int y = TileY(v->dest_tile) * TILE_SIZE;
-		if (abs(x - v->x_pos) + abs(y - v->y_pos) >= TILE_SIZE) {
-			v->direction = GetDirectionTowards(v, x, y);
-			GetNewVehiclePos(v, &gp);
-			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-			return;
-		}
-		if (++v->age < 6) {
-			v->dest_tile = RandomTile();
-			return;
-		}
-		v->current_order.dest = 1;
-
-		FOR_ALL_VEHICLES(u) {
-			if (u->type == VEH_Road && IsHumanPlayer(u->owner)) {
-				v->dest_tile = u->index;
-				v->age = 0;
-				return;
-			}
-		}
-
-		DeleteDisasterVeh(v);
-	} else {
-// target a vehicle
-		u = GetVehicle(v->dest_tile);
-		if (u->type != VEH_Road) {
-			DeleteDisasterVeh(v);
-			return;
-		}
-
-		dist = abs(v->x_pos - u->x_pos) + abs(v->y_pos - u->y_pos);
-
-		if (dist < TILE_SIZE && !(u->vehstatus&VS_HIDDEN) && u->breakdown_ctr==0) {
-			u->breakdown_ctr = 3;
-			u->breakdown_delay = 140;
-		}
-
-		v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos);
-		GetNewVehiclePos(v, &gp);
-
-		z = v->z_pos;
-		if (dist <= TILE_SIZE && z > u->z_pos) z--;
-		SetDisasterVehiclePos(v, gp.x, gp.y, z);
-
-		if (z <= u->z_pos && (u->vehstatus&VS_HIDDEN)==0) {
-			v->age++;
-			if (u->u.road.crashed_ctr == 0) {
-				u->u.road.crashed_ctr++;
-				u->vehstatus |= VS_CRASHED;
-
-				AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED,
-					NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
-					u->index,
-					0);
-			}
-		}
-
-// destroy?
-		if (v->age > 50) {
-			CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
-			SndPlayVehicleFx(SND_12_EXPLOSION, v);
-			DeleteDisasterVeh(v);
-		}
-	}
-}
-
-static void DestructIndustry(Industry *i)
-{
-	TileIndex tile;
-
-	for (tile = 0; tile != MapSize(); tile++) {
-		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == i->index) {
-			ResetIndustryConstructionStage(tile);
-			MarkTileDirtyByTile(tile);
-		}
-	}
-}
-
-// Airplane which destroys an oil refinery
-static void DisasterTick_2(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-
-	v->tick_counter++;
-	v->u.disaster.image_override =
-		(v->current_order.dest == 1 && v->tick_counter & 4) ? SPR_F_15_FIRING : 0;
-
-	GetNewVehiclePos(v, &gp);
-	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-
-	if (gp.x < -160) {
-		DeleteDisasterVeh(v);
-		return;
-	}
-
-	if (v->current_order.dest == 2) {
-		if (!(v->tick_counter&3)) {
-			Industry *i = GetIndustry(v->dest_tile);
-			int x = TileX(i->xy) * TILE_SIZE;
-			int y = TileY(i->xy) * TILE_SIZE;
-			uint32 r = Random();
-
-			CreateEffectVehicleAbove(
-				GB(r,  0, 6) + x,
-				GB(r,  6, 6) + y,
-				GB(r, 12, 4),
-				EV_EXPLOSION_SMALL);
-
-			if (++v->age >= 55)
-				v->current_order.dest = 3;
-		}
-	} else if (v->current_order.dest == 1) {
-		if (++v->age == 112) {
-			Industry *i;
-
-			v->current_order.dest = 2;
-			v->age = 0;
-
-			i = GetIndustry(v->dest_tile);
-			DestructIndustry(i);
-
-			SetDParam(0, i->town->index);
-			AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
-			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
-		}
-	} else if (v->current_order.dest == 0) {
-		int x,y;
-		TileIndex tile;
-		uint ind;
-
-		x = v->x_pos - 15 * TILE_SIZE;
-		y = v->y_pos;
-
-		if ( (uint)x > MapMaxX() * TILE_SIZE - 1)
-			return;
-
-		tile = TileVirtXY(x, y);
-		if (!IsTileType(tile, MP_INDUSTRY))
-			return;
-
-		ind = GetIndustryIndex(tile);
-		v->dest_tile = ind;
-
-		if (GetIndustry(ind)->type == IT_OIL_REFINERY) {
-			v->current_order.dest = 1;
-			v->age = 0;
-		}
-	}
-}
-
-// Helicopter which destroys a factory
-static void DisasterTick_3(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-
-	v->tick_counter++;
-	v->u.disaster.image_override =
-		(v->current_order.dest == 1 && v->tick_counter & 4) ? SPR_AH_64A_FIRING : 0;
-
-	GetNewVehiclePos(v, &gp);
-	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-
-	if (gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1) {
-		DeleteDisasterVeh(v);
-		return;
-	}
-
-	if (v->current_order.dest == 2) {
-		if (!(v->tick_counter&3)) {
-			Industry *i = GetIndustry(v->dest_tile);
-			int x = TileX(i->xy) * TILE_SIZE;
-			int y = TileY(i->xy) * TILE_SIZE;
-			uint32 r = Random();
-
-			CreateEffectVehicleAbove(
-				GB(r,  0, 6) + x,
-				GB(r,  6, 6) + y,
-				GB(r, 12, 4),
-				EV_EXPLOSION_SMALL);
-
-			if (++v->age >= 55)
-				v->current_order.dest = 3;
-		}
-	} else if (v->current_order.dest == 1) {
-		if (++v->age == 112) {
-			Industry *i;
-
-			v->current_order.dest = 2;
-			v->age = 0;
-
-			i = GetIndustry(v->dest_tile);
-			DestructIndustry(i);
-
-			SetDParam(0, i->town->index);
-			AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
-			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
-		}
-	} else if (v->current_order.dest == 0) {
-		int x,y;
-		TileIndex tile;
-		uint ind;
-
-		x = v->x_pos - 15 * TILE_SIZE;
-		y = v->y_pos;
-
-		if ( (uint)x > MapMaxX() * TILE_SIZE - 1)
-			return;
-
-		tile = TileVirtXY(x, y);
-		if (!IsTileType(tile, MP_INDUSTRY))
-			return;
-
-		ind = GetIndustryIndex(tile);
-		v->dest_tile = ind;
-
-		if (GetIndustry(ind)->type == IT_FACTORY) {
-			v->current_order.dest = 1;
-			v->age = 0;
-		}
-	}
-}
-
-// Helicopter rotor blades
-static void DisasterTick_3b(Vehicle *v)
-{
-	if (++v->tick_counter & 1)
-		return;
-
-	if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1;
-
-	VehiclePositionChanged(v);
-	BeginVehicleMove(v);
-	EndVehicleMove(v);
-}
-
-// Big UFO which lands on a piece of rail.
-// Will be shot down by a plane
-static void DisasterTick_4(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-	byte z;
-	Vehicle *u,*w;
-	Town *t;
-	TileIndex tile;
-	TileIndex tile_org;
-
-	v->tick_counter++;
-
-	if (v->current_order.dest == 1) {
-		int x = TileX(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
-		int y = TileY(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
-		if (abs(v->x_pos - x) + abs(v->y_pos - y) >= 8) {
-			v->direction = GetDirectionTowards(v, x, y);
-
-			GetNewVehiclePos(v, &gp);
-			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-			return;
-		}
-
-		z = GetSlopeZ(v->x_pos, v->y_pos);
-		if (z < v->z_pos) {
-			SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos - 1);
-			return;
-		}
-
-		v->current_order.dest = 2;
-
-		FOR_ALL_VEHICLES(u) {
-			if (u->type == VEH_Train || u->type == VEH_Road) {
-				if (abs(u->x_pos - v->x_pos) + abs(u->y_pos - v->y_pos) <= 12 * TILE_SIZE) {
-					u->breakdown_ctr = 5;
-					u->breakdown_delay = 0xF0;
-				}
-			}
-		}
-
-		t = ClosestTownFromTile(v->dest_tile, (uint)-1);
-		SetDParam(0, t->index);
-		AddNewsItem(STR_B004_UFO_LANDS_NEAR,
-			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ACCIDENT, 0),
-			v->tile,
-			0);
-
-		u = ForceAllocateSpecialVehicle();
-		if (u == NULL) {
-			DeleteDisasterVeh(v);
-			return;
-		}
-
-		InitializeDisasterVehicle(u, -6 * TILE_SIZE, v->y_pos, 135, DIR_SW, 11);
-		u->u.disaster.unk2 = v->index;
-
-		w = ForceAllocateSpecialVehicle();
-		if (w == NULL)
-			return;
-
-		u->next = w;
-		InitializeDisasterVehicle(w, -6 * TILE_SIZE, v->y_pos, 0, DIR_SW, 12);
-		w->vehstatus |= VS_SHADOW;
-	} else if (v->current_order.dest < 1) {
-
-		int x = TileX(v->dest_tile) * TILE_SIZE;
-		int y = TileY(v->dest_tile) * TILE_SIZE;
-		if (abs(x - v->x_pos) + abs(y - v->y_pos) >= TILE_SIZE) {
-			v->direction = GetDirectionTowards(v, x, y);
-			GetNewVehiclePos(v, &gp);
-			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-			return;
-		}
-
-		if (++v->age < 6) {
-			v->dest_tile = RandomTile();
-			return;
-		}
-		v->current_order.dest = 1;
-
-		tile_org = tile = RandomTile();
-		do {
-			if (IsTileType(tile, MP_RAILWAY) &&
-					IsPlainRailTile(tile) &&
-					IsHumanPlayer(GetTileOwner(tile))) {
-				break;
-			}
-			tile = TILE_MASK(tile+1);
-		} while (tile != tile_org);
-		v->dest_tile = tile;
-		v->age = 0;
-	} else {
-		return;
-	}
-}
-
-// The plane which will shoot down the UFO
-static void DisasterTick_4b(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-	Vehicle *u;
-	int i;
-
-	v->tick_counter++;
-
-	GetNewVehiclePos(v, &gp);
-	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-
-	if (gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1) {
-		DeleteDisasterVeh(v);
-		return;
-	}
-
-	if (v->current_order.dest == 0) {
-		u = GetVehicle(v->u.disaster.unk2);
-		if (abs(v->x_pos - u->x_pos) > TILE_SIZE)
-			return;
-		v->current_order.dest = 1;
-
-		CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE);
-		SndPlayVehicleFx(SND_12_EXPLOSION, u);
-
-		DeleteDisasterVeh(u);
-
-		for (i = 0; i != 80; i++) {
-			uint32 r = Random();
-			CreateEffectVehicleAbove(
-				GB(r, 0, 6) + v->x_pos - 32,
-				GB(r, 5, 6) + v->y_pos - 32,
-				0,
-				EV_EXPLOSION_SMALL);
-		}
-
-		BEGIN_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
-			tile = TILE_MASK(tile);
-			DisasterClearSquare(tile);
-		END_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
-	}
-}
-
-// Submarine handler
-static void DisasterTick_5_and_6(Vehicle *v)
-{
-	uint32 r;
-	GetNewVehiclePosResult gp;
-	TileIndex tile;
-
-	v->tick_counter++;
-
-	if (++v->age > 8880) {
-		VehiclePositionChanged(v);
-		BeginVehicleMove(v);
-		EndVehicleMove(v);
-		DeleteVehicle(v);
-		return;
-	}
-
-	if (!(v->tick_counter & 1)) return;
-
-	tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
-	if (IsValidTile(tile) &&
-			(r=GetTileTrackStatus(tile,TRANSPORT_WATER),(byte)(r+(r >> 8)) == 0x3F) &&
-			!CHANCE16(1,90)) {
-		GetNewVehiclePos(v, &gp);
-		SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
-		return;
-	}
-
-	v->direction = ChangeDir(v->direction, GB(Random(), 0, 1) ? DIRDIFF_90RIGHT : DIRDIFF_90LEFT);
-}
-
-
-static void DisasterTick_NULL(Vehicle *v) {}
-typedef void DisasterVehicleTickProc(Vehicle *v);
-
-static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = {
-	DisasterTick_Zeppeliner,DisasterTick_NULL,
-	DisasterTick_UFO,DisasterTick_NULL,
-	DisasterTick_2,DisasterTick_NULL,
-	DisasterTick_3,DisasterTick_NULL,DisasterTick_3b,
-	DisasterTick_4,DisasterTick_NULL,
-	DisasterTick_4b,DisasterTick_NULL,
-	DisasterTick_5_and_6,
-	DisasterTick_5_and_6,
-};
-
-
-void DisasterVehicle_Tick(Vehicle *v)
-{
-	_disastervehicle_tick_procs[v->subtype](v);
-}
-
-
-void OnNewDay_DisasterVehicle(Vehicle *v)
-{
-	// not used
-}
-
-typedef void DisasterInitProc(void);
-
-// Zeppeliner which crashes on a small airport
-static void Disaster0_Init(void)
-{
-	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
-	Station *st;
-	int x;
-
-	if (v == NULL) return;
-
-	/* Pick a random place, unless we find a small airport */
-	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
-
-	FOR_ALL_STATIONS(st) {
-		if (st->airport_tile != 0 &&
-				st->airport_type <= 1 &&
-				IsHumanPlayer(st->owner)) {
-			x = (TileX(st->xy) + 2) * TILE_SIZE;
-			break;
-		}
-	}
-
-	InitializeDisasterVehicle(v, x, 0, 135, DIR_SE, 0);
-
-	// Allocate shadow too?
-	u = ForceAllocateSpecialVehicle();
-	if (u != NULL) {
-		v->next = u;
-		InitializeDisasterVehicle(u, x, 0, 0, DIR_SE, 1);
-		u->vehstatus |= VS_SHADOW;
-	}
-}
-
-static void Disaster1_Init(void)
-{
-	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
-	int x;
-
-	if (v == NULL) return;
-
-	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
-
-	InitializeDisasterVehicle(v, x, 0, 135, DIR_SE, 2);
-	v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
-	v->age = 0;
-
-	// Allocate shadow too?
-	u = ForceAllocateSpecialVehicle();
-	if (u != NULL) {
-		v->next = u;
-		InitializeDisasterVehicle(u, x, 0, 0, DIR_SE, 3);
-		u->vehstatus |= VS_SHADOW;
-	}
-}
-
-static void Disaster2_Init(void)
-{
-	Industry *i, *found;
-	Vehicle *v,*u;
-	int x,y;
-
-	found = NULL;
-
-	FOR_ALL_INDUSTRIES(i) {
-		if (i->type == IT_OIL_REFINERY &&
-				(found == NULL || CHANCE16(1, 2))) {
-			found = i;
-		}
-	}
-
-	if (found == NULL) return;
-
-	v = ForceAllocateSpecialVehicle();
-	if (v == NULL) return;
-
-	x = (MapSizeX() + 9) * TILE_SIZE - 1;
-	y = TileY(found->xy) * TILE_SIZE + 37;
-
-	InitializeDisasterVehicle(v, x, y, 135, DIR_NE, 4);
-
-	u = ForceAllocateSpecialVehicle();
-	if (u != NULL) {
-		v->next = u;
-		InitializeDisasterVehicle(u, x, y, 0, DIR_SE, 5);
-		u->vehstatus |= VS_SHADOW;
-	}
-}
-
-static void Disaster3_Init(void)
-{
-	Industry *i, *found;
-	Vehicle *v,*u,*w;
-	int x,y;
-
-	found = NULL;
-
-	FOR_ALL_INDUSTRIES(i) {
-		if (i->type == IT_FACTORY &&
-				(found==NULL || CHANCE16(1,2))) {
-			found = i;
-		}
-	}
-
-	if (found == NULL) return;
-
-	v = ForceAllocateSpecialVehicle();
-	if (v == NULL) return;
-
-	x = -16 * TILE_SIZE;
-	y = TileY(found->xy) * TILE_SIZE + 37;
-
-	InitializeDisasterVehicle(v, x, y, 135, DIR_SW, 6);
-
-	u = ForceAllocateSpecialVehicle();
-	if (u != NULL) {
-		v->next = u;
-		InitializeDisasterVehicle(u, x, y, 0, DIR_SW, 7);
-		u->vehstatus |= VS_SHADOW;
-
-		w = ForceAllocateSpecialVehicle();
-		if (w != NULL) {
-			u->next = w;
-			InitializeDisasterVehicle(w, x, y, 140, DIR_SW, 8);
-		}
-	}
-}
-
-static void Disaster4_Init(void)
-{
-	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
-	int x,y;
-
-	if (v == NULL) return;
-
-	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
-
-	y = MapMaxX() * TILE_SIZE - 1;
-	InitializeDisasterVehicle(v, x, y, 135, DIR_NW, 9);
-	v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
-	v->age = 0;
-
-	// Allocate shadow too?
-	u = ForceAllocateSpecialVehicle();
-	if (u != NULL) {
-		v->next = u;
-		InitializeDisasterVehicle(u, x, y, 0, DIR_NW, 10);
-		u->vehstatus |= VS_SHADOW;
-	}
-}
-
-// Submarine type 1
-static void Disaster5_Init(void)
-{
-	Vehicle *v = ForceAllocateSpecialVehicle();
-	int x,y;
-	Direction dir;
-	uint32 r;
-
-	if (v == NULL) return;
-
-	r = Random();
-	x = TileX(r) * TILE_SIZE + TILE_SIZE / 2;
-
-	if (r & 0x80000000) {
-		y = MapMaxX() * TILE_SIZE - TILE_SIZE / 2 - 1;
-		dir = DIR_NW;
-	} else {
-		y = TILE_SIZE / 2;
-		dir = DIR_SE;
-	}
-	InitializeDisasterVehicle(v, x, y, 0, dir, 13);
-	v->age = 0;
-}
-
-// Submarine type 2
-static void Disaster6_Init(void)
-{
-	Vehicle *v = ForceAllocateSpecialVehicle();
-	int x,y;
-	Direction dir;
-	uint32 r;
-
-	if (v == NULL) return;
-
-	r = Random();
-	x = TileX(r) * TILE_SIZE + TILE_SIZE / 2;
-
-	if (r & 0x80000000) {
-		y = MapMaxX() * TILE_SIZE - TILE_SIZE / 2 - 1;
-		dir = DIR_NW;
-	} else {
-		y = TILE_SIZE / 2;
-		dir = DIR_SE;
-	}
-	InitializeDisasterVehicle(v, x, y, 0, dir, 14);
-	v->age = 0;
-}
-
-static void Disaster7_Init(void)
-{
-	int index = GB(Random(), 0, 4);
-	uint m;
-
-	for (m = 0; m < 15; m++) {
-		const Industry* i;
-
-		FOR_ALL_INDUSTRIES(i) {
-			if (i->type == IT_COAL_MINE && --index < 0) {
-				SetDParam(0, i->town->index);
-				AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
-					NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TileDiffXY(1, 1), 0);
-
-				{
-					TileIndex tile = i->xy;
-					TileIndexDiff step = TileOffsByDiagDir(GB(Random(), 0, 2));
-					uint n;
-
-					for (n = 0; n < 30; n++) {
-						DisasterClearSquare(tile);
-						tile = TILE_MASK(tile + step);
-					}
-				}
-				return;
-			}
-		}
-	}
-}
-
-static DisasterInitProc * const _disaster_initprocs[] = {
-	Disaster0_Init,
-	Disaster1_Init,
-	Disaster2_Init,
-	Disaster3_Init,
-	Disaster4_Init,
-	Disaster5_Init,
-	Disaster6_Init,
-	Disaster7_Init,
-};
-
-static const struct {
-	Year min;
-	Year max;
-} _dis_years[] = {
-	{ 1930, 1955 },
-	{ 1940, 1970 },
-	{ 1960, 1990 },
-	{ 1970, 2000 },
-	{ 2000, 2100 },
-	{ 1940, 1965 },
-	{ 1975, 2010 },
-	{ 1950, 1985 }
-};
-
-
-static void DoDisaster(void)
-{
-	byte buf[lengthof(_dis_years)];
-	uint i;
-	uint j;
-
-	j = 0;
-	for (i = 0; i != lengthof(_dis_years); i++) {
-		if (_cur_year >= _dis_years[i].min && _cur_year < _dis_years[i].max) buf[j++] = i;
-	}
-
-	if (j == 0) return;
-
-	_disaster_initprocs[buf[RandomRange(j)]]();
-}
-
-
-static void ResetDisasterDelay(void)
-{
-	_disaster_delay = GB(Random(), 0, 9) + 730;
-}
-
-void DisasterDailyLoop(void)
-{
-	if (--_disaster_delay != 0) return;
-
-	ResetDisasterDelay();
-
-	if (_opt.diff.disasters != 0) DoDisaster();
-}
-
-void StartupDisasters(void)
-{
-	ResetDisasterDelay();
-}
new file mode 100644
--- /dev/null
+++ b/src/disaster_cmd.cpp
@@ -0,0 +1,1001 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "industry_map.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "vehicle.h"
+#include "command.h"
+#include "news.h"
+#include "station.h"
+#include "waypoint.h"
+#include "town.h"
+#include "industry.h"
+#include "player.h"
+#include "airport.h"
+#include "sound.h"
+#include "variables.h"
+#include "table/sprites.h"
+#include "date.h"
+
+static void DisasterClearSquare(TileIndex tile)
+{
+	if (!EnsureNoVehicle(tile)) return;
+
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			if (IsHumanPlayer(GetTileOwner(tile)) && !IsRailWaypoint(tile)) {
+				PlayerID p = _current_player;
+				_current_player = OWNER_WATER;
+				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+				_current_player = p;
+			}
+			break;
+
+		case MP_HOUSE: {
+			PlayerID p = _current_player;
+			_current_player = OWNER_NONE;
+			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+			_current_player = p;
+			break;
+		}
+
+		case MP_TREES:
+		case MP_CLEAR:
+			DoClearSquare(tile);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static const SpriteID _disaster_images_1[] = {0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41, 0xF41};
+static const SpriteID _disaster_images_2[] = {0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44, 0xF44};
+static const SpriteID _disaster_images_3[] = {0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E, 0xF4E};
+static const SpriteID _disaster_images_4[] = {0xF46, 0xF46, 0xF47, 0xF47, 0xF48, 0xF48, 0xF49, 0xF49};
+static const SpriteID _disaster_images_5[] = {0xF4A, 0xF4A, 0xF4B, 0xF4B, 0xF4C, 0xF4C, 0xF4D, 0xF4D};
+static const SpriteID _disaster_images_6[] = {0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50, 0xF50};
+static const SpriteID _disaster_images_7[] = {0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51, 0xF51};
+static const SpriteID _disaster_images_8[] = {0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52, 0xF52};
+static const SpriteID _disaster_images_9[] = {0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E, 0xF3E};
+
+static const SpriteID * const _disaster_images[] = {
+	_disaster_images_1, _disaster_images_1,
+	_disaster_images_2, _disaster_images_2,
+	_disaster_images_3, _disaster_images_3,
+	_disaster_images_8, _disaster_images_8, _disaster_images_9,
+	_disaster_images_6, _disaster_images_6,
+	_disaster_images_7, _disaster_images_7,
+	_disaster_images_4, _disaster_images_5,
+};
+
+static void DisasterVehicleUpdateImage(Vehicle *v)
+{
+	int img = v->u.disaster.image_override;
+	if (img == 0)
+		img = _disaster_images[v->subtype][v->direction];
+	v->cur_image = img;
+}
+
+static void InitializeDisasterVehicle(Vehicle* v, int x, int y, byte z, Direction direction, byte subtype)
+{
+	v->type = VEH_Disaster;
+	v->x_pos = x;
+	v->y_pos = y;
+	v->z_pos = z;
+	v->tile = TileVirtXY(x, y);
+	v->direction = direction;
+	v->subtype = subtype;
+	v->x_offs = -1;
+	v->y_offs = -1;
+	v->sprite_width = 2;
+	v->sprite_height = 2;
+	v->z_height = 5;
+	v->owner = OWNER_NONE;
+	v->vehstatus = VS_UNCLICKABLE;
+	v->u.disaster.image_override = 0;
+	v->current_order.type = OT_NOTHING;
+	v->current_order.flags = 0;
+	v->current_order.dest = 0;
+
+	DisasterVehicleUpdateImage(v);
+	VehiclePositionChanged(v);
+	BeginVehicleMove(v);
+	EndVehicleMove(v);
+}
+
+static void DeleteDisasterVeh(Vehicle *v)
+{
+	DeleteVehicleChain(v);
+}
+
+static void SetDisasterVehiclePos(Vehicle *v, int x, int y, byte z)
+{
+	Vehicle *u;
+
+	BeginVehicleMove(v);
+	v->x_pos = x;
+	v->y_pos = y;
+	v->z_pos = z;
+	v->tile = TileVirtXY(x, y);
+
+	DisasterVehicleUpdateImage(v);
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+
+	if ( (u=v->next) != NULL) {
+		int safe_x = clamp(x, 0, MapMaxX() * TILE_SIZE);
+		int safe_y = clamp(y - 1, 0, MapMaxY() * TILE_SIZE);
+		BeginVehicleMove(u);
+
+		u->x_pos = x;
+		u->y_pos = y - 1 - (max(z - GetSlopeZ(safe_x, safe_y), 0) >> 3);
+		safe_y = clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
+		u->z_pos = GetSlopeZ(safe_x, safe_y);
+		u->direction = v->direction;
+
+		DisasterVehicleUpdateImage(u);
+		VehiclePositionChanged(u);
+		EndVehicleMove(u);
+
+		if ( (u=u->next) != NULL) {
+			BeginVehicleMove(u);
+			u->x_pos = x;
+			u->y_pos = y;
+			u->z_pos = z + 5;
+			VehiclePositionChanged(u);
+			EndVehicleMove(u);
+		}
+	}
+}
+
+
+static void DisasterTick_Zeppeliner(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+	Station *st;
+	int x,y;
+	byte z;
+	TileIndex tile;
+
+	++v->tick_counter;
+
+	if (v->current_order.dest < 2) {
+		if (v->tick_counter&1)
+			return;
+
+		GetNewVehiclePos(v, &gp);
+
+		SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+
+		if (v->current_order.dest == 1) {
+			if (++v->age == 38) {
+				v->current_order.dest = 2;
+				v->age = 0;
+			}
+
+			if ((v->tick_counter&7)==0) {
+				CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE);
+			}
+		} else if (v->current_order.dest == 0) {
+			tile = v->tile; /**/
+
+			if (IsValidTile(tile) &&
+					IsTileType(tile, MP_STATION) &&
+					IsAirport(tile) &&
+					IsHumanPlayer(GetTileOwner(tile))) {
+				v->current_order.dest = 1;
+				v->age = 0;
+
+				SetDParam(0, GetStationIndex(tile));
+				AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
+					NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
+					v->index,
+					0);
+			}
+		}
+		if (v->y_pos >= ((int)MapSizeY() + 9) * TILE_SIZE - 1)
+			DeleteDisasterVeh(v);
+		return;
+	}
+
+	if (v->current_order.dest > 2) {
+		if (++v->age <= 13320)
+			return;
+
+		tile = v->tile; /**/
+
+		if (IsValidTile(tile) &&
+				IsTileType(tile, MP_STATION) &&
+				IsAirport(tile) &&
+				IsHumanPlayer(GetTileOwner(tile))) {
+			st = GetStationByTile(tile);
+			CLRBITS(st->airport_flags, RUNWAY_IN_block);
+		}
+
+		SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos);
+		DeleteDisasterVeh(v);
+		return;
+	}
+
+	x = v->x_pos;
+	y = v->y_pos;
+	z = GetSlopeZ(x,y);
+	if (z < v->z_pos)
+		z = v->z_pos - 1;
+	SetDisasterVehiclePos(v, x, y, z);
+
+	if (++v->age == 1) {
+		CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
+		SndPlayVehicleFx(SND_12_EXPLOSION, v);
+		v->u.disaster.image_override = SPR_BLIMP_CRASHING;
+	} else if (v->age == 70) {
+		v->u.disaster.image_override = SPR_BLIMP_CRASHED;
+	} else if (v->age <= 300) {
+		if (!(v->tick_counter&7)) {
+			uint32 r = Random();
+
+			CreateEffectVehicleRel(v,
+				GB(r, 0, 4) - 7,
+				GB(r, 4, 4) - 7,
+				GB(r, 8, 3) + 5,
+				EV_EXPLOSION_SMALL);
+		}
+	} else if (v->age == 350) {
+		v->current_order.dest = 3;
+		v->age = 0;
+	}
+
+	tile = v->tile;/**/
+	if (IsValidTile(tile) &&
+			IsTileType(tile, MP_STATION) &&
+			IsAirport(tile) &&
+			IsHumanPlayer(GetTileOwner(tile))) {
+		st = GetStationByTile(tile);
+		SETBITS(st->airport_flags, RUNWAY_IN_block);
+	}
+}
+
+// UFO starts in the middle, and flies around a bit until it locates
+// a road vehicle which it targets.
+static void DisasterTick_UFO(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+	Vehicle *u;
+	uint dist;
+	byte z;
+
+	v->u.disaster.image_override = (++v->tick_counter & 8) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT;
+
+	if (v->current_order.dest == 0) {
+// fly around randomly
+		int x = TileX(v->dest_tile) * TILE_SIZE;
+		int y = TileY(v->dest_tile) * TILE_SIZE;
+		if (abs(x - v->x_pos) + abs(y - v->y_pos) >= TILE_SIZE) {
+			v->direction = GetDirectionTowards(v, x, y);
+			GetNewVehiclePos(v, &gp);
+			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+			return;
+		}
+		if (++v->age < 6) {
+			v->dest_tile = RandomTile();
+			return;
+		}
+		v->current_order.dest = 1;
+
+		FOR_ALL_VEHICLES(u) {
+			if (u->type == VEH_Road && IsHumanPlayer(u->owner)) {
+				v->dest_tile = u->index;
+				v->age = 0;
+				return;
+			}
+		}
+
+		DeleteDisasterVeh(v);
+	} else {
+// target a vehicle
+		u = GetVehicle(v->dest_tile);
+		if (u->type != VEH_Road) {
+			DeleteDisasterVeh(v);
+			return;
+		}
+
+		dist = abs(v->x_pos - u->x_pos) + abs(v->y_pos - u->y_pos);
+
+		if (dist < TILE_SIZE && !(u->vehstatus&VS_HIDDEN) && u->breakdown_ctr==0) {
+			u->breakdown_ctr = 3;
+			u->breakdown_delay = 140;
+		}
+
+		v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos);
+		GetNewVehiclePos(v, &gp);
+
+		z = v->z_pos;
+		if (dist <= TILE_SIZE && z > u->z_pos) z--;
+		SetDisasterVehiclePos(v, gp.x, gp.y, z);
+
+		if (z <= u->z_pos && (u->vehstatus&VS_HIDDEN)==0) {
+			v->age++;
+			if (u->u.road.crashed_ctr == 0) {
+				u->u.road.crashed_ctr++;
+				u->vehstatus |= VS_CRASHED;
+
+				AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED,
+					NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
+					u->index,
+					0);
+			}
+		}
+
+// destroy?
+		if (v->age > 50) {
+			CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
+			SndPlayVehicleFx(SND_12_EXPLOSION, v);
+			DeleteDisasterVeh(v);
+		}
+	}
+}
+
+static void DestructIndustry(Industry *i)
+{
+	TileIndex tile;
+
+	for (tile = 0; tile != MapSize(); tile++) {
+		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == i->index) {
+			ResetIndustryConstructionStage(tile);
+			MarkTileDirtyByTile(tile);
+		}
+	}
+}
+
+// Airplane which destroys an oil refinery
+static void DisasterTick_2(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+
+	v->tick_counter++;
+	v->u.disaster.image_override =
+		(v->current_order.dest == 1 && v->tick_counter & 4) ? SPR_F_15_FIRING : 0;
+
+	GetNewVehiclePos(v, &gp);
+	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+
+	if (gp.x < -160) {
+		DeleteDisasterVeh(v);
+		return;
+	}
+
+	if (v->current_order.dest == 2) {
+		if (!(v->tick_counter&3)) {
+			Industry *i = GetIndustry(v->dest_tile);
+			int x = TileX(i->xy) * TILE_SIZE;
+			int y = TileY(i->xy) * TILE_SIZE;
+			uint32 r = Random();
+
+			CreateEffectVehicleAbove(
+				GB(r,  0, 6) + x,
+				GB(r,  6, 6) + y,
+				GB(r, 12, 4),
+				EV_EXPLOSION_SMALL);
+
+			if (++v->age >= 55)
+				v->current_order.dest = 3;
+		}
+	} else if (v->current_order.dest == 1) {
+		if (++v->age == 112) {
+			Industry *i;
+
+			v->current_order.dest = 2;
+			v->age = 0;
+
+			i = GetIndustry(v->dest_tile);
+			DestructIndustry(i);
+
+			SetDParam(0, i->town->index);
+			AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
+			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
+		}
+	} else if (v->current_order.dest == 0) {
+		int x,y;
+		TileIndex tile;
+		uint ind;
+
+		x = v->x_pos - 15 * TILE_SIZE;
+		y = v->y_pos;
+
+		if ( (uint)x > MapMaxX() * TILE_SIZE - 1)
+			return;
+
+		tile = TileVirtXY(x, y);
+		if (!IsTileType(tile, MP_INDUSTRY))
+			return;
+
+		ind = GetIndustryIndex(tile);
+		v->dest_tile = ind;
+
+		if (GetIndustry(ind)->type == IT_OIL_REFINERY) {
+			v->current_order.dest = 1;
+			v->age = 0;
+		}
+	}
+}
+
+// Helicopter which destroys a factory
+static void DisasterTick_3(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+
+	v->tick_counter++;
+	v->u.disaster.image_override =
+		(v->current_order.dest == 1 && v->tick_counter & 4) ? SPR_AH_64A_FIRING : 0;
+
+	GetNewVehiclePos(v, &gp);
+	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+
+	if (gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1) {
+		DeleteDisasterVeh(v);
+		return;
+	}
+
+	if (v->current_order.dest == 2) {
+		if (!(v->tick_counter&3)) {
+			Industry *i = GetIndustry(v->dest_tile);
+			int x = TileX(i->xy) * TILE_SIZE;
+			int y = TileY(i->xy) * TILE_SIZE;
+			uint32 r = Random();
+
+			CreateEffectVehicleAbove(
+				GB(r,  0, 6) + x,
+				GB(r,  6, 6) + y,
+				GB(r, 12, 4),
+				EV_EXPLOSION_SMALL);
+
+			if (++v->age >= 55)
+				v->current_order.dest = 3;
+		}
+	} else if (v->current_order.dest == 1) {
+		if (++v->age == 112) {
+			Industry *i;
+
+			v->current_order.dest = 2;
+			v->age = 0;
+
+			i = GetIndustry(v->dest_tile);
+			DestructIndustry(i);
+
+			SetDParam(0, i->town->index);
+			AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
+			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
+		}
+	} else if (v->current_order.dest == 0) {
+		int x,y;
+		TileIndex tile;
+		uint ind;
+
+		x = v->x_pos - 15 * TILE_SIZE;
+		y = v->y_pos;
+
+		if ( (uint)x > MapMaxX() * TILE_SIZE - 1)
+			return;
+
+		tile = TileVirtXY(x, y);
+		if (!IsTileType(tile, MP_INDUSTRY))
+			return;
+
+		ind = GetIndustryIndex(tile);
+		v->dest_tile = ind;
+
+		if (GetIndustry(ind)->type == IT_FACTORY) {
+			v->current_order.dest = 1;
+			v->age = 0;
+		}
+	}
+}
+
+// Helicopter rotor blades
+static void DisasterTick_3b(Vehicle *v)
+{
+	if (++v->tick_counter & 1)
+		return;
+
+	if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1;
+
+	VehiclePositionChanged(v);
+	BeginVehicleMove(v);
+	EndVehicleMove(v);
+}
+
+// Big UFO which lands on a piece of rail.
+// Will be shot down by a plane
+static void DisasterTick_4(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+	byte z;
+	Vehicle *u,*w;
+	Town *t;
+	TileIndex tile;
+	TileIndex tile_org;
+
+	v->tick_counter++;
+
+	if (v->current_order.dest == 1) {
+		int x = TileX(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
+		int y = TileY(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2;
+		if (abs(v->x_pos - x) + abs(v->y_pos - y) >= 8) {
+			v->direction = GetDirectionTowards(v, x, y);
+
+			GetNewVehiclePos(v, &gp);
+			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+			return;
+		}
+
+		z = GetSlopeZ(v->x_pos, v->y_pos);
+		if (z < v->z_pos) {
+			SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos - 1);
+			return;
+		}
+
+		v->current_order.dest = 2;
+
+		FOR_ALL_VEHICLES(u) {
+			if (u->type == VEH_Train || u->type == VEH_Road) {
+				if (abs(u->x_pos - v->x_pos) + abs(u->y_pos - v->y_pos) <= 12 * TILE_SIZE) {
+					u->breakdown_ctr = 5;
+					u->breakdown_delay = 0xF0;
+				}
+			}
+		}
+
+		t = ClosestTownFromTile(v->dest_tile, (uint)-1);
+		SetDParam(0, t->index);
+		AddNewsItem(STR_B004_UFO_LANDS_NEAR,
+			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ACCIDENT, 0),
+			v->tile,
+			0);
+
+		u = ForceAllocateSpecialVehicle();
+		if (u == NULL) {
+			DeleteDisasterVeh(v);
+			return;
+		}
+
+		InitializeDisasterVehicle(u, -6 * TILE_SIZE, v->y_pos, 135, DIR_SW, 11);
+		u->u.disaster.unk2 = v->index;
+
+		w = ForceAllocateSpecialVehicle();
+		if (w == NULL)
+			return;
+
+		u->next = w;
+		InitializeDisasterVehicle(w, -6 * TILE_SIZE, v->y_pos, 0, DIR_SW, 12);
+		w->vehstatus |= VS_SHADOW;
+	} else if (v->current_order.dest < 1) {
+
+		int x = TileX(v->dest_tile) * TILE_SIZE;
+		int y = TileY(v->dest_tile) * TILE_SIZE;
+		if (abs(x - v->x_pos) + abs(y - v->y_pos) >= TILE_SIZE) {
+			v->direction = GetDirectionTowards(v, x, y);
+			GetNewVehiclePos(v, &gp);
+			SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+			return;
+		}
+
+		if (++v->age < 6) {
+			v->dest_tile = RandomTile();
+			return;
+		}
+		v->current_order.dest = 1;
+
+		tile_org = tile = RandomTile();
+		do {
+			if (IsTileType(tile, MP_RAILWAY) &&
+					IsPlainRailTile(tile) &&
+					IsHumanPlayer(GetTileOwner(tile))) {
+				break;
+			}
+			tile = TILE_MASK(tile+1);
+		} while (tile != tile_org);
+		v->dest_tile = tile;
+		v->age = 0;
+	} else {
+		return;
+	}
+}
+
+// The plane which will shoot down the UFO
+static void DisasterTick_4b(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+	Vehicle *u;
+	int i;
+
+	v->tick_counter++;
+
+	GetNewVehiclePos(v, &gp);
+	SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+
+	if (gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1) {
+		DeleteDisasterVeh(v);
+		return;
+	}
+
+	if (v->current_order.dest == 0) {
+		u = GetVehicle(v->u.disaster.unk2);
+		if (abs(v->x_pos - u->x_pos) > TILE_SIZE)
+			return;
+		v->current_order.dest = 1;
+
+		CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE);
+		SndPlayVehicleFx(SND_12_EXPLOSION, u);
+
+		DeleteDisasterVeh(u);
+
+		for (i = 0; i != 80; i++) {
+			uint32 r = Random();
+			CreateEffectVehicleAbove(
+				GB(r, 0, 6) + v->x_pos - 32,
+				GB(r, 5, 6) + v->y_pos - 32,
+				0,
+				EV_EXPLOSION_SMALL);
+		}
+
+		BEGIN_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
+			tile = TILE_MASK(tile);
+			DisasterClearSquare(tile);
+		END_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
+	}
+}
+
+// Submarine handler
+static void DisasterTick_5_and_6(Vehicle *v)
+{
+	uint32 r;
+	GetNewVehiclePosResult gp;
+	TileIndex tile;
+
+	v->tick_counter++;
+
+	if (++v->age > 8880) {
+		VehiclePositionChanged(v);
+		BeginVehicleMove(v);
+		EndVehicleMove(v);
+		DeleteVehicle(v);
+		return;
+	}
+
+	if (!(v->tick_counter & 1)) return;
+
+	tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
+	if (IsValidTile(tile) &&
+			(r=GetTileTrackStatus(tile,TRANSPORT_WATER),(byte)(r+(r >> 8)) == 0x3F) &&
+			!CHANCE16(1,90)) {
+		GetNewVehiclePos(v, &gp);
+		SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
+		return;
+	}
+
+	v->direction = ChangeDir(v->direction, GB(Random(), 0, 1) ? DIRDIFF_90RIGHT : DIRDIFF_90LEFT);
+}
+
+
+static void DisasterTick_NULL(Vehicle *v) {}
+typedef void DisasterVehicleTickProc(Vehicle *v);
+
+static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = {
+	DisasterTick_Zeppeliner,DisasterTick_NULL,
+	DisasterTick_UFO,DisasterTick_NULL,
+	DisasterTick_2,DisasterTick_NULL,
+	DisasterTick_3,DisasterTick_NULL,DisasterTick_3b,
+	DisasterTick_4,DisasterTick_NULL,
+	DisasterTick_4b,DisasterTick_NULL,
+	DisasterTick_5_and_6,
+	DisasterTick_5_and_6,
+};
+
+
+void DisasterVehicle_Tick(Vehicle *v)
+{
+	_disastervehicle_tick_procs[v->subtype](v);
+}
+
+
+void OnNewDay_DisasterVehicle(Vehicle *v)
+{
+	// not used
+}
+
+typedef void DisasterInitProc(void);
+
+// Zeppeliner which crashes on a small airport
+static void Disaster0_Init(void)
+{
+	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
+	Station *st;
+	int x;
+
+	if (v == NULL) return;
+
+	/* Pick a random place, unless we find a small airport */
+	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
+
+	FOR_ALL_STATIONS(st) {
+		if (st->airport_tile != 0 &&
+				st->airport_type <= 1 &&
+				IsHumanPlayer(st->owner)) {
+			x = (TileX(st->xy) + 2) * TILE_SIZE;
+			break;
+		}
+	}
+
+	InitializeDisasterVehicle(v, x, 0, 135, DIR_SE, 0);
+
+	// Allocate shadow too?
+	u = ForceAllocateSpecialVehicle();
+	if (u != NULL) {
+		v->next = u;
+		InitializeDisasterVehicle(u, x, 0, 0, DIR_SE, 1);
+		u->vehstatus |= VS_SHADOW;
+	}
+}
+
+static void Disaster1_Init(void)
+{
+	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
+	int x;
+
+	if (v == NULL) return;
+
+	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
+
+	InitializeDisasterVehicle(v, x, 0, 135, DIR_SE, 2);
+	v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
+	v->age = 0;
+
+	// Allocate shadow too?
+	u = ForceAllocateSpecialVehicle();
+	if (u != NULL) {
+		v->next = u;
+		InitializeDisasterVehicle(u, x, 0, 0, DIR_SE, 3);
+		u->vehstatus |= VS_SHADOW;
+	}
+}
+
+static void Disaster2_Init(void)
+{
+	Industry *i, *found;
+	Vehicle *v,*u;
+	int x,y;
+
+	found = NULL;
+
+	FOR_ALL_INDUSTRIES(i) {
+		if (i->type == IT_OIL_REFINERY &&
+				(found == NULL || CHANCE16(1, 2))) {
+			found = i;
+		}
+	}
+
+	if (found == NULL) return;
+
+	v = ForceAllocateSpecialVehicle();
+	if (v == NULL) return;
+
+	x = (MapSizeX() + 9) * TILE_SIZE - 1;
+	y = TileY(found->xy) * TILE_SIZE + 37;
+
+	InitializeDisasterVehicle(v, x, y, 135, DIR_NE, 4);
+
+	u = ForceAllocateSpecialVehicle();
+	if (u != NULL) {
+		v->next = u;
+		InitializeDisasterVehicle(u, x, y, 0, DIR_SE, 5);
+		u->vehstatus |= VS_SHADOW;
+	}
+}
+
+static void Disaster3_Init(void)
+{
+	Industry *i, *found;
+	Vehicle *v,*u,*w;
+	int x,y;
+
+	found = NULL;
+
+	FOR_ALL_INDUSTRIES(i) {
+		if (i->type == IT_FACTORY &&
+				(found==NULL || CHANCE16(1,2))) {
+			found = i;
+		}
+	}
+
+	if (found == NULL) return;
+
+	v = ForceAllocateSpecialVehicle();
+	if (v == NULL) return;
+
+	x = -16 * TILE_SIZE;
+	y = TileY(found->xy) * TILE_SIZE + 37;
+
+	InitializeDisasterVehicle(v, x, y, 135, DIR_SW, 6);
+
+	u = ForceAllocateSpecialVehicle();
+	if (u != NULL) {
+		v->next = u;
+		InitializeDisasterVehicle(u, x, y, 0, DIR_SW, 7);
+		u->vehstatus |= VS_SHADOW;
+
+		w = ForceAllocateSpecialVehicle();
+		if (w != NULL) {
+			u->next = w;
+			InitializeDisasterVehicle(w, x, y, 140, DIR_SW, 8);
+		}
+	}
+}
+
+static void Disaster4_Init(void)
+{
+	Vehicle *v = ForceAllocateSpecialVehicle(), *u;
+	int x,y;
+
+	if (v == NULL) return;
+
+	x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2;
+
+	y = MapMaxX() * TILE_SIZE - 1;
+	InitializeDisasterVehicle(v, x, y, 135, DIR_NW, 9);
+	v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
+	v->age = 0;
+
+	// Allocate shadow too?
+	u = ForceAllocateSpecialVehicle();
+	if (u != NULL) {
+		v->next = u;
+		InitializeDisasterVehicle(u, x, y, 0, DIR_NW, 10);
+		u->vehstatus |= VS_SHADOW;
+	}
+}
+
+// Submarine type 1
+static void Disaster5_Init(void)
+{
+	Vehicle *v = ForceAllocateSpecialVehicle();
+	int x,y;
+	Direction dir;
+	uint32 r;
+
+	if (v == NULL) return;
+
+	r = Random();
+	x = TileX(r) * TILE_SIZE + TILE_SIZE / 2;
+
+	if (r & 0x80000000) {
+		y = MapMaxX() * TILE_SIZE - TILE_SIZE / 2 - 1;
+		dir = DIR_NW;
+	} else {
+		y = TILE_SIZE / 2;
+		dir = DIR_SE;
+	}
+	InitializeDisasterVehicle(v, x, y, 0, dir, 13);
+	v->age = 0;
+}
+
+// Submarine type 2
+static void Disaster6_Init(void)
+{
+	Vehicle *v = ForceAllocateSpecialVehicle();
+	int x,y;
+	Direction dir;
+	uint32 r;
+
+	if (v == NULL) return;
+
+	r = Random();
+	x = TileX(r) * TILE_SIZE + TILE_SIZE / 2;
+
+	if (r & 0x80000000) {
+		y = MapMaxX() * TILE_SIZE - TILE_SIZE / 2 - 1;
+		dir = DIR_NW;
+	} else {
+		y = TILE_SIZE / 2;
+		dir = DIR_SE;
+	}
+	InitializeDisasterVehicle(v, x, y, 0, dir, 14);
+	v->age = 0;
+}
+
+static void Disaster7_Init(void)
+{
+	int index = GB(Random(), 0, 4);
+	uint m;
+
+	for (m = 0; m < 15; m++) {
+		const Industry* i;
+
+		FOR_ALL_INDUSTRIES(i) {
+			if (i->type == IT_COAL_MINE && --index < 0) {
+				SetDParam(0, i->town->index);
+				AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
+					NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TileDiffXY(1, 1), 0);
+
+				{
+					TileIndex tile = i->xy;
+					TileIndexDiff step = TileOffsByDiagDir(GB(Random(), 0, 2));
+					uint n;
+
+					for (n = 0; n < 30; n++) {
+						DisasterClearSquare(tile);
+						tile = TILE_MASK(tile + step);
+					}
+				}
+				return;
+			}
+		}
+	}
+}
+
+static DisasterInitProc * const _disaster_initprocs[] = {
+	Disaster0_Init,
+	Disaster1_Init,
+	Disaster2_Init,
+	Disaster3_Init,
+	Disaster4_Init,
+	Disaster5_Init,
+	Disaster6_Init,
+	Disaster7_Init,
+};
+
+static const struct {
+	Year min;
+	Year max;
+} _dis_years[] = {
+	{ 1930, 1955 },
+	{ 1940, 1970 },
+	{ 1960, 1990 },
+	{ 1970, 2000 },
+	{ 2000, 2100 },
+	{ 1940, 1965 },
+	{ 1975, 2010 },
+	{ 1950, 1985 }
+};
+
+
+static void DoDisaster(void)
+{
+	byte buf[lengthof(_dis_years)];
+	uint i;
+	uint j;
+
+	j = 0;
+	for (i = 0; i != lengthof(_dis_years); i++) {
+		if (_cur_year >= _dis_years[i].min && _cur_year < _dis_years[i].max) buf[j++] = i;
+	}
+
+	if (j == 0) return;
+
+	_disaster_initprocs[buf[RandomRange(j)]]();
+}
+
+
+static void ResetDisasterDelay(void)
+{
+	_disaster_delay = GB(Random(), 0, 9) + 730;
+}
+
+void DisasterDailyLoop(void)
+{
+	if (--_disaster_delay != 0) return;
+
+	ResetDisasterDelay();
+
+	if (_opt.diff.disasters != 0) DoDisaster();
+}
+
+void StartupDisasters(void)
+{
+	ResetDisasterDelay();
+}
deleted file mode 100644
--- a/src/dock_gui.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "window.h"
-#include "station.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "sound.h"
-#include "command.h"
-#include "variables.h"
-
-static void ShowBuildDockStationPicker(void);
-static void ShowBuildDocksDepotPicker(void);
-
-static Axis _ship_depot_direction;
-
-void CcBuildDocks(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_02_SPLAT, tile);
-		ResetObjectToPlace();
-	}
-}
-
-void CcBuildCanal(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) SndPlayTileFx(SND_02_SPLAT, tile);
-}
-
-
-static void PlaceDocks_Dock(TileIndex tile)
-{
-	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_DOCK | CMD_AUTO | CMD_MSG(STR_9802_CAN_T_BUILD_DOCK_HERE));
-}
-
-static void PlaceDocks_Depot(TileIndex tile)
-{
-	DoCommandP(tile, _ship_depot_direction, 0, CcBuildDocks, CMD_BUILD_SHIP_DEPOT | CMD_AUTO | CMD_MSG(STR_3802_CAN_T_BUILD_SHIP_DEPOT));
-}
-
-static void PlaceDocks_Buoy(TileIndex tile)
-{
-	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_BUOY | CMD_AUTO | CMD_MSG(STR_9835_CAN_T_POSITION_BUOY_HERE));
-}
-
-static void PlaceDocks_DemolishArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea);
-}
-
-static void PlaceDocks_BuildCanal(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_OR_Y);
-}
-
-static void PlaceDocks_BuildLock(TileIndex tile)
-{
-	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS));
-}
-
-
-enum {
-	DTW_CANAL    = 3,
-	DTW_LOCK     = 4,
-	DTW_DEMOLISH = 6,
-	DTW_DEPOT    = 7,
-	DTW_STATION  = 8,
-	DTW_BUOY     = 9
-};
-
-
-static void BuildDocksClick_Canal(Window *w)
-{
-	HandlePlacePushButton(w, DTW_CANAL, SPR_CURSOR_CANAL, 1, PlaceDocks_BuildCanal);
-}
-
-static void BuildDocksClick_Lock(Window *w)
-{
-	HandlePlacePushButton(w, DTW_LOCK, SPR_CURSOR_LOCK, 1, PlaceDocks_BuildLock);
-}
-
-static void BuildDocksClick_Demolish(Window *w)
-{
-	HandlePlacePushButton(w, DTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceDocks_DemolishArea);
-}
-
-static void BuildDocksClick_Depot(Window *w)
-{
-	if (HandlePlacePushButton(w, DTW_DEPOT, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
-}
-
-static void BuildDocksClick_Dock(Window *w)
-{
-	if (HandlePlacePushButton(w, DTW_STATION, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
-}
-
-static void BuildDocksClick_Buoy(Window *w)
-{
-	HandlePlacePushButton(w, DTW_BUOY, SPR_CURSOR_BOUY, 1, PlaceDocks_Buoy);
-}
-
-static void BuildDocksClick_Landscaping(Window *w)
-{
-	ShowTerraformToolbar();
-}
-
-typedef void OnButtonClick(Window *w);
-static OnButtonClick * const _build_docks_button_proc[] = {
-	BuildDocksClick_Canal,
-	BuildDocksClick_Lock,
-	NULL,
-	BuildDocksClick_Demolish,
-	BuildDocksClick_Depot,
-	BuildDocksClick_Dock,
-	BuildDocksClick_Buoy,
-	BuildDocksClick_Landscaping,
-};
-
-static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK:
-		if (e->we.click.widget - 3 >= 0 && e->we.click.widget != 5) _build_docks_button_proc[e->we.click.widget - 3](w);
-		break;
-
-	case WE_KEYPRESS:
-		switch (e->we.keypress.keycode) {
-			case '1': BuildDocksClick_Canal(w); break;
-			case '2': BuildDocksClick_Lock(w); break;
-			case '3': BuildDocksClick_Demolish(w); break;
-			case '4': BuildDocksClick_Depot(w); break;
-			case '5': BuildDocksClick_Dock(w); break;
-			case '6': BuildDocksClick_Buoy(w); break;
-			case 'l': BuildDocksClick_Landscaping(w); break;
-			default:  return;
-		}
-		break;
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		break;
-
-	case WE_PLACE_DRAG: {
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
-		return;
-	}
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
-				GUIPlaceProcDragXY(e);
-			} else if (e->we.place.userdata == VPM_X_OR_Y) {
-				DoCommandP(e->we.place.tile, e->we.place.starttile, _ctrl_pressed, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
-			}
-		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-
-		w = FindWindowById(WC_BUILD_STATION, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-
-		w = FindWindowById(WC_BUILD_DEPOT, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		break;
-
-	case WE_PLACE_PRESIZE: {
-		TileIndex tile_from;
-		TileIndex tile_to;
-
-		tile_from = tile_to = e->we.place.tile;
-		switch (GetTileSlope(tile_from, NULL)) {
-			case SLOPE_SW: tile_to += TileDiffXY(-1,  0); break;
-			case SLOPE_SE: tile_to += TileDiffXY( 0, -1); break;
-			case SLOPE_NW: tile_to += TileDiffXY( 0,  1); break;
-			case SLOPE_NE: tile_to += TileDiffXY( 1,  0); break;
-			default: break;
-		}
-		VpSetPresizeRange(tile_from, tile_to);
-	} break;
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
-	}
-}
-
-static const Widget _build_docks_toolb_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   145,     0,    13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   146,   157,     0,    13, 0x0,                        STR_STICKY_BUTTON},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_BUILD_CANAL,        STR_BUILD_CANALS_TIP},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_BUILD_LOCK,         STR_BUILD_LOCKS_TIP},
-
-{      WWT_PANEL,   RESIZE_NONE,     7,    44,    47,    14,    35, 0x0,                        STR_NULL},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    48,    69,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    70,    91,    14,    35, SPR_IMG_SHIP_DEPOT,         STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    92,   113,    14,    35, SPR_IMG_SHIP_DOCK,          STR_981D_BUILD_SHIP_DOCK},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_BOUY,               STR_9834_POSITION_BUOY_WHICH_CAN},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   157,    14,    35, SPR_IMG_LANDSCAPING,        STR_LANDSCAPING_TOOLBAR_TIP},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_docks_toolbar_desc = {
-	WDP_ALIGN_TBR, 22, 158, 36,
-	WC_BUILD_TOOLBAR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_build_docks_toolb_widgets,
-	BuildDocksToolbWndProc
-};
-
-void ShowBuildDocksToolbar(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-
-	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
-	AllocateWindowDesc(&_build_docks_toolbar_desc);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
-}
-
-static void BuildDockStationWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _station_show_coverage + 3); break;
-
-	case WE_PAINT: {
-		int rad;
-
-		if (WP(w,def_d).close) return;
-		DrawWindowWidgets(w);
-
-		rad = (_patches.modified_catchment) ? CA_DOCK : 4;
-
-		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-
-		DrawStationCoverageAreaText(4, 50, (uint)-1, rad);
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 3:
-			case 4:
-				RaiseWindowWidget(w, _station_show_coverage + 3);
-				_station_show_coverage = e->we.click.widget - 3;
-				LowerWindowWidget(w, _station_show_coverage + 3);
-				SndPlayFx(SND_15_BEEP);
-				SetWindowDirty(w);
-				break;
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) {
-			DeleteWindow(w);
-			return;
-		}
-
-		CheckRedrawStationCoverage(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_dock_station_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3068_DOCK,                    STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    74, 0x0,                              STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,    30,    40, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,    30,    40, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    17,    30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_dock_station_desc = {
-	WDP_AUTO, WDP_AUTO, 148, 75,
-	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_dock_station_widgets,
-	BuildDockStationWndProc
-};
-
-static void ShowBuildDockStationPicker(void)
-{
-	AllocateWindowDesc(&_build_dock_station_desc);
-}
-
-static void UpdateDocksDirection(void)
-{
-	if (_ship_depot_direction != AXIS_X) {
-		SetTileSelectSize(1, 2);
-	} else {
-		SetTileSelectSize(2, 1);
-	}
-}
-
-static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _ship_depot_direction + 3); break;
-
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-
-		DrawShipDepotSprite(67, 35, 0);
-		DrawShipDepotSprite(35, 51, 1);
-		DrawShipDepotSprite(135, 35, 2);
-		DrawShipDepotSprite(167, 51, 3);
-		return;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3:
-		case 4:
-			RaiseWindowWidget(w, _ship_depot_direction + 3);
-			_ship_depot_direction = e->we.click.widget - 3;
-			LowerWindowWidget(w, _ship_depot_direction + 3);
-			SndPlayFx(SND_15_BEEP);
-			UpdateDocksDirection();
-			SetWindowDirty(w);
-			break;
-		}
-	} break;
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) DeleteWindow(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_docks_depot_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   203,     0,    13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   203,    14,    85, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,   100,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,   103,   200,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_docks_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 204, 86,
-	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_docks_depot_widgets,
-	BuildDocksDepotWndProc
-};
-
-
-static void ShowBuildDocksDepotPicker(void)
-{
-	AllocateWindowDesc(&_build_docks_depot_desc);
-	UpdateDocksDirection();
-}
-
-
-void InitializeDockGui(void)
-{
-	_ship_depot_direction = AXIS_X;
-}
new file mode 100644
--- /dev/null
+++ b/src/dock_gui.cpp
@@ -0,0 +1,378 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "window.h"
+#include "station.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "sound.h"
+#include "command.h"
+#include "variables.h"
+
+static void ShowBuildDockStationPicker(void);
+static void ShowBuildDocksDepotPicker(void);
+
+static Axis _ship_depot_direction;
+
+void CcBuildDocks(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_02_SPLAT, tile);
+		ResetObjectToPlace();
+	}
+}
+
+void CcBuildCanal(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) SndPlayTileFx(SND_02_SPLAT, tile);
+}
+
+
+static void PlaceDocks_Dock(TileIndex tile)
+{
+	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_DOCK | CMD_AUTO | CMD_MSG(STR_9802_CAN_T_BUILD_DOCK_HERE));
+}
+
+static void PlaceDocks_Depot(TileIndex tile)
+{
+	DoCommandP(tile, _ship_depot_direction, 0, CcBuildDocks, CMD_BUILD_SHIP_DEPOT | CMD_AUTO | CMD_MSG(STR_3802_CAN_T_BUILD_SHIP_DEPOT));
+}
+
+static void PlaceDocks_Buoy(TileIndex tile)
+{
+	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_BUOY | CMD_AUTO | CMD_MSG(STR_9835_CAN_T_POSITION_BUOY_HERE));
+}
+
+static void PlaceDocks_DemolishArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea);
+}
+
+static void PlaceDocks_BuildCanal(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_OR_Y);
+}
+
+static void PlaceDocks_BuildLock(TileIndex tile)
+{
+	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS));
+}
+
+
+enum {
+	DTW_CANAL    = 3,
+	DTW_LOCK     = 4,
+	DTW_DEMOLISH = 6,
+	DTW_DEPOT    = 7,
+	DTW_STATION  = 8,
+	DTW_BUOY     = 9
+};
+
+
+static void BuildDocksClick_Canal(Window *w)
+{
+	HandlePlacePushButton(w, DTW_CANAL, SPR_CURSOR_CANAL, 1, PlaceDocks_BuildCanal);
+}
+
+static void BuildDocksClick_Lock(Window *w)
+{
+	HandlePlacePushButton(w, DTW_LOCK, SPR_CURSOR_LOCK, 1, PlaceDocks_BuildLock);
+}
+
+static void BuildDocksClick_Demolish(Window *w)
+{
+	HandlePlacePushButton(w, DTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceDocks_DemolishArea);
+}
+
+static void BuildDocksClick_Depot(Window *w)
+{
+	if (HandlePlacePushButton(w, DTW_DEPOT, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
+}
+
+static void BuildDocksClick_Dock(Window *w)
+{
+	if (HandlePlacePushButton(w, DTW_STATION, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
+}
+
+static void BuildDocksClick_Buoy(Window *w)
+{
+	HandlePlacePushButton(w, DTW_BUOY, SPR_CURSOR_BOUY, 1, PlaceDocks_Buoy);
+}
+
+static void BuildDocksClick_Landscaping(Window *w)
+{
+	ShowTerraformToolbar();
+}
+
+typedef void OnButtonClick(Window *w);
+static OnButtonClick * const _build_docks_button_proc[] = {
+	BuildDocksClick_Canal,
+	BuildDocksClick_Lock,
+	NULL,
+	BuildDocksClick_Demolish,
+	BuildDocksClick_Depot,
+	BuildDocksClick_Dock,
+	BuildDocksClick_Buoy,
+	BuildDocksClick_Landscaping,
+};
+
+static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK:
+		if (e->we.click.widget - 3 >= 0 && e->we.click.widget != 5) _build_docks_button_proc[e->we.click.widget - 3](w);
+		break;
+
+	case WE_KEYPRESS:
+		switch (e->we.keypress.keycode) {
+			case '1': BuildDocksClick_Canal(w); break;
+			case '2': BuildDocksClick_Lock(w); break;
+			case '3': BuildDocksClick_Demolish(w); break;
+			case '4': BuildDocksClick_Depot(w); break;
+			case '5': BuildDocksClick_Dock(w); break;
+			case '6': BuildDocksClick_Buoy(w); break;
+			case 'l': BuildDocksClick_Landscaping(w); break;
+			default:  return;
+		}
+		break;
+
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		break;
+
+	case WE_PLACE_DRAG: {
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
+		return;
+	}
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
+				GUIPlaceProcDragXY(e);
+			} else if (e->we.place.userdata == VPM_X_OR_Y) {
+				DoCommandP(e->we.place.tile, e->we.place.starttile, _ctrl_pressed, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
+			}
+		}
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+
+		w = FindWindowById(WC_BUILD_STATION, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+
+		w = FindWindowById(WC_BUILD_DEPOT, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		break;
+
+	case WE_PLACE_PRESIZE: {
+		TileIndex tile_from;
+		TileIndex tile_to;
+
+		tile_from = tile_to = e->we.place.tile;
+		switch (GetTileSlope(tile_from, NULL)) {
+			case SLOPE_SW: tile_to += TileDiffXY(-1,  0); break;
+			case SLOPE_SE: tile_to += TileDiffXY( 0, -1); break;
+			case SLOPE_NW: tile_to += TileDiffXY( 0,  1); break;
+			case SLOPE_NE: tile_to += TileDiffXY( 1,  0); break;
+			default: break;
+		}
+		VpSetPresizeRange(tile_from, tile_to);
+	} break;
+
+	case WE_DESTROY:
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+		break;
+	}
+}
+
+static const Widget _build_docks_toolb_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   145,     0,    13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   146,   157,     0,    13, 0x0,                        STR_STICKY_BUTTON},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_BUILD_CANAL,        STR_BUILD_CANALS_TIP},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_BUILD_LOCK,         STR_BUILD_LOCKS_TIP},
+
+{      WWT_PANEL,   RESIZE_NONE,     7,    44,    47,    14,    35, 0x0,                        STR_NULL},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    48,    69,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    70,    91,    14,    35, SPR_IMG_SHIP_DEPOT,         STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    92,   113,    14,    35, SPR_IMG_SHIP_DOCK,          STR_981D_BUILD_SHIP_DOCK},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_BOUY,               STR_9834_POSITION_BUOY_WHICH_CAN},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   157,    14,    35, SPR_IMG_LANDSCAPING,        STR_LANDSCAPING_TOOLBAR_TIP},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_docks_toolbar_desc = {
+	WDP_ALIGN_TBR, 22, 158, 36,
+	WC_BUILD_TOOLBAR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_build_docks_toolb_widgets,
+	BuildDocksToolbWndProc
+};
+
+void ShowBuildDocksToolbar(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+
+	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
+	AllocateWindowDesc(&_build_docks_toolbar_desc);
+	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
+}
+
+static void BuildDockStationWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _station_show_coverage + 3); break;
+
+	case WE_PAINT: {
+		int rad;
+
+		if (WP(w,def_d).close) return;
+		DrawWindowWidgets(w);
+
+		rad = (_patches.modified_catchment) ? CA_DOCK : 4;
+
+		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+
+		DrawStationCoverageAreaText(4, 50, (uint)-1, rad);
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 3:
+			case 4:
+				RaiseWindowWidget(w, _station_show_coverage + 3);
+				_station_show_coverage = e->we.click.widget - 3;
+				LowerWindowWidget(w, _station_show_coverage + 3);
+				SndPlayFx(SND_15_BEEP);
+				SetWindowDirty(w);
+				break;
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) {
+			DeleteWindow(w);
+			return;
+		}
+
+		CheckRedrawStationCoverage(w);
+		break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_dock_station_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3068_DOCK,                    STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    74, 0x0,                              STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,    30,    40, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,    30,    40, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    17,    30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_dock_station_desc = {
+	WDP_AUTO, WDP_AUTO, 148, 75,
+	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_dock_station_widgets,
+	BuildDockStationWndProc
+};
+
+static void ShowBuildDockStationPicker(void)
+{
+	AllocateWindowDesc(&_build_dock_station_desc);
+}
+
+static void UpdateDocksDirection(void)
+{
+	if (_ship_depot_direction != AXIS_X) {
+		SetTileSelectSize(1, 2);
+	} else {
+		SetTileSelectSize(2, 1);
+	}
+}
+
+static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _ship_depot_direction + 3); break;
+
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+
+		DrawShipDepotSprite(67, 35, 0);
+		DrawShipDepotSprite(35, 51, 1);
+		DrawShipDepotSprite(135, 35, 2);
+		DrawShipDepotSprite(167, 51, 3);
+		return;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3:
+		case 4:
+			RaiseWindowWidget(w, _ship_depot_direction + 3);
+			_ship_depot_direction = e->we.click.widget - 3;
+			LowerWindowWidget(w, _ship_depot_direction + 3);
+			SndPlayFx(SND_15_BEEP);
+			UpdateDocksDirection();
+			SetWindowDirty(w);
+			break;
+		}
+	} break;
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) DeleteWindow(w);
+		break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_docks_depot_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   203,     0,    13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   203,    14,    85, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,   100,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,   103,   200,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_docks_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 204, 86,
+	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_docks_depot_widgets,
+	BuildDocksDepotWndProc
+};
+
+
+static void ShowBuildDocksDepotPicker(void)
+{
+	AllocateWindowDesc(&_build_docks_depot_desc);
+	UpdateDocksDirection();
+}
+
+
+void InitializeDockGui(void)
+{
+	_ship_depot_direction = AXIS_X;
+}
deleted file mode 100644
--- a/src/driver.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "driver.h"
-#include "functions.h"
-#include "hal.h"
-#include "string.h"
-
-#include "music/bemidi.h"
-#include "music/dmusic.h"
-#include "music/extmidi.h"
-#include "music/null_m.h"
-#include "music/os2_m.h"
-#include "music/win32_m.h"
-#include "music/qtmidi.h"
-
-#include "sound/null_s.h"
-#include "sound/sdl_s.h"
-#include "sound/cocoa_s.h"
-#include "sound/win32_s.h"
-
-#include "video/dedicated_v.h"
-#include "video/null_v.h"
-#include "video/sdl_v.h"
-#include "video/cocoa_v.h"
-#include "video/win32_v.h"
-
-typedef struct DriverDesc {
-	const char* name;
-	const char* longname;
-	const HalCommonDriver* drv;
-} DriverDesc;
-
-typedef struct DriverClass {
-	const DriverDesc *descs;
-	const char *name;
-	const HalCommonDriver** drv;
-} DriverClass;
-
-
-#define M(x, y, z) { x, y, (const HalCommonDriver *)(void *)z }
-static const DriverDesc _music_driver_descs[] = {
-#ifdef __BEOS__
-	M("bemidi",  "BeOS MIDI Driver",        &_bemidi_music_driver),
-#endif
-#if defined(__OS2__) && !defined(__INNOTEK_LIBC__)
-	M("os2",     "OS/2 Music Driver",       &_os2_music_driver),
-#endif
-#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
-	M("dmusic",  "DirectMusic MIDI Driver", &_dmusic_midi_driver),
-#endif
-#ifdef WIN32
-	M("win32",   "Win32 MIDI Driver",       &_win32_music_driver),
-#endif
-#if defined(__APPLE__) && !defined(DEDICATED)
-	M("qt",      "QuickTime MIDI Driver",   &_qtime_music_driver),
-#endif
-#ifdef UNIX
-#if !defined(__MORPHOS__) && !defined(__AMIGA__)
-	M("extmidi", "External MIDI Driver",    &_extmidi_music_driver),
-#endif
-#endif
-	M("null",    "Null Music Driver",       &_null_music_driver),
-	M(NULL, NULL, NULL)
-};
-
-static const DriverDesc _sound_driver_descs[] = {
-#ifdef WIN32
-	M("win32", "Win32 WaveOut Driver", &_win32_sound_driver),
-#endif
-#ifdef WITH_SDL
-	M("sdl",   "SDL Sound Driver",     &_sdl_sound_driver),
-#endif
-#ifdef WITH_COCOA
-	M("cocoa", "Cocoa Sound Driver",   &_cocoa_sound_driver),
-#endif
-	M("null",  "Null Sound Driver",    &_null_sound_driver),
-	M(NULL, NULL, NULL)
-};
-
-static const DriverDesc _video_driver_descs[] = {
-#ifdef WIN32
-	M("win32",      "Win32 GDI Video Driver", &_win32_video_driver),
-#endif
-#ifdef WITH_SDL
-	M("sdl",        "SDL Video Driver",       &_sdl_video_driver),
-#endif
-#ifdef WITH_COCOA
-	M("cocoa",      "Cocoa Video Driver",       &_cocoa_video_driver),
-#endif
-	M("null",       "Null Video Driver",      &_null_video_driver),
-#ifdef ENABLE_NETWORK
-	M("dedicated",  "Dedicated Video Driver", &_dedicated_video_driver),
-#endif
-	M(NULL, NULL, NULL)
-};
-#undef M
-
-
-#define M(x, y, z) { x, y, (const HalCommonDriver **)(void *)z }
-static const DriverClass _driver_classes[] = {
-	M(_video_driver_descs, "video", &_video_driver),
-	M(_sound_driver_descs, "sound", &_sound_driver),
-	M(_music_driver_descs, "music", &_music_driver)
-};
-#undef M
-
-static const DriverDesc* GetDriverByName(const DriverDesc* dd, const char* name)
-{
-	for (; dd->name != NULL; dd++) {
-		if (strcmp(dd->name, name) == 0) return dd;
-	}
-	return NULL;
-}
-
-void LoadDriver(int driver, const char *name)
-{
-	const DriverClass *dc = &_driver_classes[driver];
-	const DriverDesc *dd;
-	const char *err;
-
-	if (*name == '\0') {
-		for (dd = dc->descs; dd->name != NULL; dd++) {
-			err = dd->drv->start(NULL);
-			if (err == NULL) break;
-			DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s",
-				dc->name, dd->name, err
-			);
-		}
-		if (dd->name == NULL) error("Couldn't find any suitable %s driver", dc->name);
-
-		DEBUG(driver, 1, "Successfully probed %s driver '%s'", dc->name, dd->name);
-
-		*dc->drv = dd->drv;
-	} else {
-		char* parm;
-		char buffer[256];
-		const char* parms[32];
-
-		// Extract the driver name and put parameter list in parm
-		ttd_strlcpy(buffer, name, sizeof(buffer));
-		parm = strchr(buffer, ':');
-		parms[0] = NULL;
-		if (parm != NULL) {
-			uint np = 0;
-			// Tokenize the parm.
-			do {
-				*parm++ = '\0';
-				if (np < lengthof(parms) - 1)
-					parms[np++] = parm;
-				while (*parm != '\0' && *parm != ',')
-					parm++;
-			} while (*parm == ',');
-			parms[np] = NULL;
-		}
-		dd = GetDriverByName(dc->descs, buffer);
-		if (dd == NULL)
-			error("No such %s driver: %s\n", dc->name, buffer);
-
-		if (*dc->drv != NULL) (*dc->drv)->stop();
-		*dc->drv = NULL;
-
-		err = dd->drv->start(parms);
-		if (err != NULL) {
-			error("Unable to load driver %s(%s). The error was: %s\n",
-				dd->name, dd->longname, err
-			);
-		}
-		*dc->drv = dd->drv;
-	}
-}
-
-
-static const char* GetDriverParam(const char* const* parm, const char* name)
-{
-	size_t len;
-
-	if (parm == NULL) return NULL;
-
-	len = strlen(name);
-	for (; *parm != NULL; parm++) {
-		const char* p = *parm;
-
-		if (strncmp(p, name, len) == 0) {
-			if (p[len] == '=')  return p + len + 1;
-			if (p[len] == '\0') return p + len;
-		}
-	}
-	return NULL;
-}
-
-bool GetDriverParamBool(const char* const* parm, const char* name)
-{
-	return GetDriverParam(parm, name) != NULL;
-}
-
-int GetDriverParamInt(const char* const* parm, const char* name, int def)
-{
-	const char* p = GetDriverParam(parm, name);
-	return p != NULL ? atoi(p) : def;
-}
-
-
-char *GetDriverList(char* p, const char *last)
-{
-	const DriverClass* dc;
-
-	for (dc = _driver_classes; dc != endof(_driver_classes); dc++) {
-		const DriverDesc* dd;
-
-		p += snprintf(p, last - p, "List of %s drivers:\n", dc->name);
-		for (dd = dc->descs; dd->name != NULL; dd++) {
-			p += snprintf(p, last - p, "%10s: %s\n", dd->name, dd->longname);
-		}
-		p = strecpy(p, "\n", last);
-	}
-
-	return p;
-}
new file mode 100644
--- /dev/null
+++ b/src/driver.cpp
@@ -0,0 +1,221 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "driver.h"
+#include "functions.h"
+#include "hal.h"
+#include "string.h"
+
+#include "music/bemidi.h"
+#include "music/dmusic.h"
+#include "music/extmidi.h"
+#include "music/null_m.h"
+#include "music/os2_m.h"
+#include "music/win32_m.h"
+#include "music/qtmidi.h"
+
+#include "sound/null_s.h"
+#include "sound/sdl_s.h"
+#include "sound/cocoa_s.h"
+#include "sound/win32_s.h"
+
+#include "video/dedicated_v.h"
+#include "video/null_v.h"
+#include "video/sdl_v.h"
+#include "video/cocoa_v.h"
+#include "video/win32_v.h"
+
+typedef struct DriverDesc {
+	const char* name;
+	const char* longname;
+	const HalCommonDriver* drv;
+} DriverDesc;
+
+typedef struct DriverClass {
+	const DriverDesc *descs;
+	const char *name;
+	const HalCommonDriver** drv;
+} DriverClass;
+
+
+#define M(x, y, z) { x, y, (const HalCommonDriver *)(void *)z }
+static const DriverDesc _music_driver_descs[] = {
+#ifdef __BEOS__
+	M("bemidi",  "BeOS MIDI Driver",        &_bemidi_music_driver),
+#endif
+#if defined(__OS2__) && !defined(__INNOTEK_LIBC__)
+	M("os2",     "OS/2 Music Driver",       &_os2_music_driver),
+#endif
+#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
+	M("dmusic",  "DirectMusic MIDI Driver", &_dmusic_midi_driver),
+#endif
+#ifdef WIN32
+	M("win32",   "Win32 MIDI Driver",       &_win32_music_driver),
+#endif
+#if defined(__APPLE__) && !defined(DEDICATED)
+	M("qt",      "QuickTime MIDI Driver",   &_qtime_music_driver),
+#endif
+#ifdef UNIX
+#if !defined(__MORPHOS__) && !defined(__AMIGA__)
+	M("extmidi", "External MIDI Driver",    &_extmidi_music_driver),
+#endif
+#endif
+	M("null",    "Null Music Driver",       &_null_music_driver),
+	M(NULL, NULL, NULL)
+};
+
+static const DriverDesc _sound_driver_descs[] = {
+#ifdef WIN32
+	M("win32", "Win32 WaveOut Driver", &_win32_sound_driver),
+#endif
+#ifdef WITH_SDL
+	M("sdl",   "SDL Sound Driver",     &_sdl_sound_driver),
+#endif
+#ifdef WITH_COCOA
+	M("cocoa", "Cocoa Sound Driver",   &_cocoa_sound_driver),
+#endif
+	M("null",  "Null Sound Driver",    &_null_sound_driver),
+	M(NULL, NULL, NULL)
+};
+
+static const DriverDesc _video_driver_descs[] = {
+#ifdef WIN32
+	M("win32",      "Win32 GDI Video Driver", &_win32_video_driver),
+#endif
+#ifdef WITH_SDL
+	M("sdl",        "SDL Video Driver",       &_sdl_video_driver),
+#endif
+#ifdef WITH_COCOA
+	M("cocoa",      "Cocoa Video Driver",       &_cocoa_video_driver),
+#endif
+	M("null",       "Null Video Driver",      &_null_video_driver),
+#ifdef ENABLE_NETWORK
+	M("dedicated",  "Dedicated Video Driver", &_dedicated_video_driver),
+#endif
+	M(NULL, NULL, NULL)
+};
+#undef M
+
+
+#define M(x, y, z) { x, y, (const HalCommonDriver **)(void *)z }
+static const DriverClass _driver_classes[] = {
+	M(_video_driver_descs, "video", &_video_driver),
+	M(_sound_driver_descs, "sound", &_sound_driver),
+	M(_music_driver_descs, "music", &_music_driver)
+};
+#undef M
+
+static const DriverDesc* GetDriverByName(const DriverDesc* dd, const char* name)
+{
+	for (; dd->name != NULL; dd++) {
+		if (strcmp(dd->name, name) == 0) return dd;
+	}
+	return NULL;
+}
+
+void LoadDriver(int driver, const char *name)
+{
+	const DriverClass *dc = &_driver_classes[driver];
+	const DriverDesc *dd;
+	const char *err;
+
+	if (*name == '\0') {
+		for (dd = dc->descs; dd->name != NULL; dd++) {
+			err = dd->drv->start(NULL);
+			if (err == NULL) break;
+			DEBUG(driver, 1, "Probing %s driver '%s' failed with error: %s",
+				dc->name, dd->name, err
+			);
+		}
+		if (dd->name == NULL) error("Couldn't find any suitable %s driver", dc->name);
+
+		DEBUG(driver, 1, "Successfully probed %s driver '%s'", dc->name, dd->name);
+
+		*dc->drv = dd->drv;
+	} else {
+		char* parm;
+		char buffer[256];
+		const char* parms[32];
+
+		// Extract the driver name and put parameter list in parm
+		ttd_strlcpy(buffer, name, sizeof(buffer));
+		parm = strchr(buffer, ':');
+		parms[0] = NULL;
+		if (parm != NULL) {
+			uint np = 0;
+			// Tokenize the parm.
+			do {
+				*parm++ = '\0';
+				if (np < lengthof(parms) - 1)
+					parms[np++] = parm;
+				while (*parm != '\0' && *parm != ',')
+					parm++;
+			} while (*parm == ',');
+			parms[np] = NULL;
+		}
+		dd = GetDriverByName(dc->descs, buffer);
+		if (dd == NULL)
+			error("No such %s driver: %s\n", dc->name, buffer);
+
+		if (*dc->drv != NULL) (*dc->drv)->stop();
+		*dc->drv = NULL;
+
+		err = dd->drv->start(parms);
+		if (err != NULL) {
+			error("Unable to load driver %s(%s). The error was: %s\n",
+				dd->name, dd->longname, err
+			);
+		}
+		*dc->drv = dd->drv;
+	}
+}
+
+
+static const char* GetDriverParam(const char* const* parm, const char* name)
+{
+	size_t len;
+
+	if (parm == NULL) return NULL;
+
+	len = strlen(name);
+	for (; *parm != NULL; parm++) {
+		const char* p = *parm;
+
+		if (strncmp(p, name, len) == 0) {
+			if (p[len] == '=')  return p + len + 1;
+			if (p[len] == '\0') return p + len;
+		}
+	}
+	return NULL;
+}
+
+bool GetDriverParamBool(const char* const* parm, const char* name)
+{
+	return GetDriverParam(parm, name) != NULL;
+}
+
+int GetDriverParamInt(const char* const* parm, const char* name, int def)
+{
+	const char* p = GetDriverParam(parm, name);
+	return p != NULL ? atoi(p) : def;
+}
+
+
+char *GetDriverList(char* p, const char *last)
+{
+	const DriverClass* dc;
+
+	for (dc = _driver_classes; dc != endof(_driver_classes); dc++) {
+		const DriverDesc* dd;
+
+		p += snprintf(p, last - p, "List of %s drivers:\n", dc->name);
+		for (dd = dc->descs; dd->name != NULL; dd++) {
+			p += snprintf(p, last - p, "%10s: %s\n", dd->name, dd->longname);
+		}
+		p = strecpy(p, "\n", last);
+	}
+
+	return p;
+}
deleted file mode 100644
--- a/src/dummy_land.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "viewport.h"
-#include "command.h"
-#include "table/sprites.h"
-
-static void DrawTile_Dummy(TileInfo *ti)
-{
-	DrawGroundSpriteAt(SPR_SHADOW_CELL, ti->x, ti->y, ti->z);
-}
-
-
-static uint GetSlopeZ_Dummy(TileIndex tile, uint x, uint y)
-{
-	return 0;
-}
-
-static Slope GetSlopeTileh_Dummy(TileIndex tile, Slope tileh)
-{
-	return SLOPE_FLAT;
-}
-
-static int32 ClearTile_Dummy(TileIndex tile, byte flags)
-{
-	return_cmd_error(STR_0001_OFF_EDGE_OF_MAP);
-}
-
-
-static void GetAcceptedCargo_Dummy(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void GetTileDesc_Dummy(TileIndex tile, TileDesc *td)
-{
-	td->str = STR_EMPTY;
-	td->owner = OWNER_NONE;
-}
-
-static void AnimateTile_Dummy(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoop_Dummy(TileIndex tile)
-{
-	/* not used */
-}
-
-static void ClickTile_Dummy(TileIndex tile)
-{
-	/* not used */
-}
-
-static void ChangeTileOwner_Dummy(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	/* not used */
-}
-
-static uint32 GetTileTrackStatus_Dummy(TileIndex tile, TransportType mode)
-{
-	return 0;
-}
-
-const TileTypeProcs _tile_type_dummy_procs = {
-	DrawTile_Dummy,           /* draw_tile_proc */
-	GetSlopeZ_Dummy,          /* get_slope_z_proc */
-	ClearTile_Dummy,          /* clear_tile_proc */
-	GetAcceptedCargo_Dummy,   /* get_accepted_cargo_proc */
-	GetTileDesc_Dummy,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Dummy, /* get_tile_track_status_proc */
-	ClickTile_Dummy,          /* click_tile_proc */
-	AnimateTile_Dummy,        /* animate_tile_proc */
-	TileLoop_Dummy,           /* tile_loop_clear */
-	ChangeTileOwner_Dummy,    /* change_tile_owner_clear */
-	NULL,                     /* get_produced_cargo_proc */
-	NULL,                     /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Dummy,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/dummy_land.cpp
@@ -0,0 +1,83 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "viewport.h"
+#include "command.h"
+#include "table/sprites.h"
+
+static void DrawTile_Dummy(TileInfo *ti)
+{
+	DrawGroundSpriteAt(SPR_SHADOW_CELL, ti->x, ti->y, ti->z);
+}
+
+
+static uint GetSlopeZ_Dummy(TileIndex tile, uint x, uint y)
+{
+	return 0;
+}
+
+static Slope GetSlopeTileh_Dummy(TileIndex tile, Slope tileh)
+{
+	return SLOPE_FLAT;
+}
+
+static int32 ClearTile_Dummy(TileIndex tile, byte flags)
+{
+	return_cmd_error(STR_0001_OFF_EDGE_OF_MAP);
+}
+
+
+static void GetAcceptedCargo_Dummy(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void GetTileDesc_Dummy(TileIndex tile, TileDesc *td)
+{
+	td->str = STR_EMPTY;
+	td->owner = OWNER_NONE;
+}
+
+static void AnimateTile_Dummy(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoop_Dummy(TileIndex tile)
+{
+	/* not used */
+}
+
+static void ClickTile_Dummy(TileIndex tile)
+{
+	/* not used */
+}
+
+static void ChangeTileOwner_Dummy(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	/* not used */
+}
+
+static uint32 GetTileTrackStatus_Dummy(TileIndex tile, TransportType mode)
+{
+	return 0;
+}
+
+const TileTypeProcs _tile_type_dummy_procs = {
+	DrawTile_Dummy,           /* draw_tile_proc */
+	GetSlopeZ_Dummy,          /* get_slope_z_proc */
+	ClearTile_Dummy,          /* clear_tile_proc */
+	GetAcceptedCargo_Dummy,   /* get_accepted_cargo_proc */
+	GetTileDesc_Dummy,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Dummy, /* get_tile_track_status_proc */
+	ClickTile_Dummy,          /* click_tile_proc */
+	AnimateTile_Dummy,        /* animate_tile_proc */
+	TileLoop_Dummy,           /* tile_loop_clear */
+	ChangeTileOwner_Dummy,    /* change_tile_owner_clear */
+	NULL,                     /* get_produced_cargo_proc */
+	NULL,                     /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Dummy,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/economy.c
+++ /dev/null
@@ -1,1738 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "functions.h"
-#include "strings.h" // XXX InjectDParam()
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "news.h"
-#include "player.h"
-#include "station.h"
-#include "vehicle.h"
-#include "window.h"
-#include "gfx.h"
-#include "command.h"
-#include "saveload.h"
-#include "economy.h"
-#include "industry.h"
-#include "town.h"
-#include "network/network.h"
-#include "sound.h"
-#include "engine.h"
-#include "network/network_data.h"
-#include "variables.h"
-#include "vehicle_gui.h"
-#include "ai/ai.h"
-#include "train.h"
-#include "newgrf_engine.h"
-#include "newgrf_sound.h"
-#include "newgrf_callbacks.h"
-#include "unmovable.h"
-#include "date.h"
-
-// Score info
-const ScoreInfo _score_info[] = {
-	{ SCORE_VEHICLES,        120, 100 },
-	{ SCORE_STATIONS,         80, 100 },
-	{ SCORE_MIN_PROFIT,    10000, 100 },
-	{ SCORE_MIN_INCOME,    50000,  50 },
-	{ SCORE_MAX_INCOME,   100000, 100 },
-	{ SCORE_DELIVERED,     40000, 400 },
-	{ SCORE_CARGO,             8,  50 },
-	{ SCORE_MONEY,      10000000,  50 },
-	{ SCORE_LOAN,         250000,  50 },
-	{ SCORE_TOTAL,             0,   0 }
-};
-
-int _score_part[MAX_PLAYERS][NUM_SCORE];
-
-int64 CalculateCompanyValue(const Player* p)
-{
-	PlayerID owner = p->index;
-	int64 value;
-
-	{
-		Station *st;
-		uint num = 0;
-
-		FOR_ALL_STATIONS(st) {
-			if (st->owner == owner) {
-				uint facil = st->facilities;
-				do num += (facil&1); while (facil >>= 1);
-			}
-		}
-
-		value = num * _price.station_value * 25;
-	}
-
-	{
-		Vehicle *v;
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->owner != owner) continue;
-
-			if (v->type == VEH_Train ||
-					v->type == VEH_Road ||
-					(v->type == VEH_Aircraft && v->subtype<=2) ||
-					v->type == VEH_Ship) {
-				value += v->value * 3 >> 1;
-			}
-		}
-	}
-
-	value += p->money64 - p->current_loan; // add real money value
-
-	return max64(value, 1);
-}
-
-// if update is set to true, the economy is updated with this score
-//  (also the house is updated, should only be true in the on-tick event)
-int UpdateCompanyRatingAndValue(Player *p, bool update)
-{
-	byte owner = p->index;
-	int score = 0;
-
-	memset(_score_part[owner], 0, sizeof(_score_part[owner]));
-
-/* Count vehicles */
-	{
-		Vehicle *v;
-		int32 min_profit = 0;
-		bool min_profit_first = true;
-		uint num = 0;
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->owner != owner) continue;
-			if ((v->type == VEH_Train && IsFrontEngine(v)) ||
-					 v->type == VEH_Road ||
-					(v->type == VEH_Aircraft && v->subtype <= 2) ||
-					 v->type == VEH_Ship) {
-				num++;
-				if (v->age > 730) {
-					/* Find the vehicle with the lowest amount of profit */
-					if (min_profit_first == true) {
-						min_profit = v->profit_last_year;
-						min_profit_first = false;
-					} else if (min_profit > v->profit_last_year) {
-						min_profit = v->profit_last_year;
-					}
-				}
-			}
-		}
-
-		_score_part[owner][SCORE_VEHICLES] = num;
-		/* Don't allow negative min_profit to show */
-		if (min_profit > 0)
-			_score_part[owner][SCORE_MIN_PROFIT] = min_profit;
-	}
-
-/* Count stations */
-	{
-		uint num = 0;
-		const Station* st;
-
-		FOR_ALL_STATIONS(st) {
-			if (st->owner == owner) {
-				int facil = st->facilities;
-				do num += facil&1; while (facil>>=1);
-			}
-		}
-		_score_part[owner][SCORE_STATIONS] = num;
-	}
-
-/* Generate statistics depending on recent income statistics */
-	{
-		const PlayerEconomyEntry* pee;
-		int numec;
-		int32 min_income;
-		int32 max_income;
-
-		numec = min(p->num_valid_stat_ent, 12);
-		if (numec != 0) {
-			min_income = 0x7FFFFFFF;
-			max_income = 0;
-			pee = p->old_economy;
-			do {
-				min_income = min(min_income, pee->income + pee->expenses);
-				max_income = max(max_income, pee->income + pee->expenses);
-			} while (++pee,--numec);
-
-			if (min_income > 0)
-				_score_part[owner][SCORE_MIN_INCOME] = min_income;
-
-			_score_part[owner][SCORE_MAX_INCOME] = max_income;
-		}
-	}
-
-/* Generate score depending on amount of transported cargo */
-	{
-		const PlayerEconomyEntry* pee;
-		int numec;
-		uint32 total_delivered;
-
-		numec = min(p->num_valid_stat_ent, 4);
-		if (numec != 0) {
-			pee = p->old_economy;
-			total_delivered = 0;
-			do {
-				total_delivered += pee->delivered_cargo;
-			} while (++pee,--numec);
-
-			_score_part[owner][SCORE_DELIVERED] = total_delivered;
-		}
-	}
-
-/* Generate score for variety of cargo */
-	{
-		uint cargo = p->cargo_types;
-		uint num = 0;
-		do num += cargo&1; while (cargo>>=1);
-		_score_part[owner][SCORE_CARGO] = num;
-		if (update) p->cargo_types = 0;
-	}
-
-/* Generate score for player money */
-	{
-		int32 money = p->player_money;
-		if (money > 0) {
-			_score_part[owner][SCORE_MONEY] = money;
-		}
-	}
-
-/* Generate score for loan */
-	{
-		_score_part[owner][SCORE_LOAN] = _score_info[SCORE_LOAN].needed - p->current_loan;
-	}
-
-	// Now we calculate the score for each item..
-	{
-		int i;
-		int total_score = 0;
-		int s;
-		score = 0;
-		for (i = 0; i < NUM_SCORE; i++) {
-			// Skip the total
-			if (i == SCORE_TOTAL) continue;
-			// Check the score
-			s = (_score_part[owner][i] >= _score_info[i].needed) ?
-				_score_info[i].score :
-				_score_part[owner][i] * _score_info[i].score / _score_info[i].needed;
-			if (s < 0) s = 0;
-			score += s;
-			total_score += _score_info[i].score;
-		}
-
-		_score_part[owner][SCORE_TOTAL] = score;
-
-		// We always want the score scaled to SCORE_MAX (1000)
-		if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score;
-	}
-
-	if (update) {
-		p->old_economy[0].performance_history = score;
-		UpdateCompanyHQ(p, score);
-		p->old_economy[0].company_value = CalculateCompanyValue(p);
-	}
-
-	InvalidateWindow(WC_PERFORMANCE_DETAIL, 0);
-	return score;
-}
-
-// use PLAYER_SPECTATOR as new_player to delete the player.
-void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
-{
-	Town *t;
-	PlayerID old = _current_player;
-	_current_player = old_player;
-
-	/* Temporarily increase the player's money, to be sure that
-	 * removing his/her property doesn't fail because of lack of money.
-	 * Not too drastically though, because it could overflow */
-	if (new_player == PLAYER_SPECTATOR) {
-		GetPlayer(old_player)->money64 = MAX_UVALUE(uint64) >>2; // jackpot ;p
-		UpdatePlayerMoney32(GetPlayer(old_player));
-	}
-
-	if (new_player == PLAYER_SPECTATOR) {
-		Subsidy *s;
-
-		for (s = _subsidies; s != endof(_subsidies); s++) {
-			if (s->cargo_type != CT_INVALID && s->age >= 12) {
-				if (GetStation(s->to)->owner == old_player) s->cargo_type = CT_INVALID;
-			}
-		}
-	}
-
-	/* Take care of rating in towns */
-	FOR_ALL_TOWNS(t) {
-		/* If a player takes over, give the ratings to that player. */
-		if (new_player != PLAYER_SPECTATOR) {
-			if (HASBIT(t->have_ratings, old_player)) {
-				if (HASBIT(t->have_ratings, new_player)) {
-					// use max of the two ratings.
-					t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
-				} else {
-					SETBIT(t->have_ratings, new_player);
-					t->ratings[new_player] = t->ratings[old_player];
-				}
-			}
-		}
-
-		/* Reset the ratings for the old player */
-		t->ratings[old_player] = 500;
-		CLRBIT(t->have_ratings, old_player);
-	}
-
-	{
-		int num_train = 0;
-		int num_road = 0;
-		int num_ship = 0;
-		int num_aircraft = 0;
-		Vehicle *v;
-
-		// Determine Ids for the new vehicles
-		FOR_ALL_VEHICLES(v) {
-			if (v->owner == new_player) {
-				switch (v->type) {
-					case VEH_Train:    if (IsFrontEngine(v)) num_train++; break;
-					case VEH_Road:     num_road++; break;
-					case VEH_Ship:     num_ship++; break;
-					case VEH_Aircraft: if (v->subtype <= 2) num_aircraft++; break;
-					default: break;
-				}
-			}
-		}
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->owner == old_player && IS_BYTE_INSIDE(v->type, VEH_Train, VEH_Aircraft + 1)) {
-				if (new_player == PLAYER_SPECTATOR) {
-					DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-					DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
-					DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
-					DeleteVehicle(v);
-				} else {
-					v->owner = new_player;
-					if (IsEngineCountable(v)) GetPlayer(new_player)->num_engines[v->engine_type]++;
-					switch (v->type) {
-						case VEH_Train:    if (IsFrontEngine(v)) v->unitnumber = ++num_train; break;
-						case VEH_Road:     v->unitnumber = ++num_road; break;
-						case VEH_Ship:     v->unitnumber = ++num_ship; break;
-						case VEH_Aircraft: if (v->subtype <= 2) v->unitnumber = ++num_aircraft; break;
-					}
-				}
-			}
-		}
-	}
-
-	// Change ownership of tiles
-	{
-		TileIndex tile = 0;
-		do {
-			ChangeTileOwner(tile, old_player, new_player);
-		} while (++tile != MapSize());
-	}
-
-	/* Change color of existing windows */
-	if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);
-
-	{
-		Player *p;
-		uint i;
-
-		/* Check for shares */
-		FOR_ALL_PLAYERS(p) {
-			for (i = 0; i < 4; i++) {
-				/* 'Sell' the share if this player has any */
-				if (p->share_owners[i] == _current_player) {
-					p->share_owners[i] = PLAYER_SPECTATOR;
-				}
-			}
-		}
-		p = GetPlayer(_current_player);
-		/* Sell all the shares that people have on this company */
-		for (i = 0; i < 4; i++)
-			p->share_owners[i] = PLAYER_SPECTATOR;
-	}
-
-	_current_player = old;
-
-	MarkWholeScreenDirty();
-}
-
-static void PlayersCheckBankrupt(Player *p)
-{
-	PlayerID owner;
-	int64 val;
-
-	// If the player has money again, it does not go bankrupt
-	if (p->player_money >= 0) {
-		p->quarters_of_bankrupcy = 0;
-		return;
-	}
-
-	p->quarters_of_bankrupcy++;
-
-	owner = p->index;
-
-	switch (p->quarters_of_bankrupcy) {
-		case 2:
-			AddNewsItem( (StringID)(owner | NB_BTROUBLE),
-				NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
-			break;
-		case 3: {
-			/* XXX - In multiplayer, should we ask other players if it wants to take
-		          over when it is a human company? -- TrueLight */
-			if (IsHumanPlayer(owner)) {
-				AddNewsItem( (StringID)(owner | NB_BTROUBLE),
-					NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
-				break;
-			}
-
-			// Check if the company has any value.. if not, declare it bankrupt
-			//  right now
-			val = CalculateCompanyValue(p);
-			if (val > 0) {
-				p->bankrupt_value = val;
-				p->bankrupt_asked = 1 << owner; // Don't ask the owner
-				p->bankrupt_timeout = 0;
-				break;
-			}
-			// Else, falltrue to case 4...
-		}
-		case 4: {
-			// Close everything the owner has open
-			DeletePlayerWindows(owner);
-
-//		Show bankrupt news
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
-
-			if (IsHumanPlayer(owner)) {
-				/* XXX - If we are in offline mode, leave the player playing. Eg. there
-				 * is no THE-END, otherwise mark the player as spectator to make sure
-				 * he/she is no long in control of this company */
-				if (!_networking) {
-					p->bankrupt_asked = 0xFF;
-					p->bankrupt_timeout = 0x456;
-					break;
-				} else if (owner == _local_player) {
-					_network_playas = PLAYER_SPECTATOR;
-					SetLocalPlayer(PLAYER_SPECTATOR);
-				}
-
-#ifdef ENABLE_NETWORK
-				/* The server has to handle all administrative issues, for example
-				 * updating and notifying all clients of what has happened */
-				if (_network_server) {
-					const NetworkClientState *cs;
-					NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-
-					/* The server has just gone belly-up, mark it as spectator */
-					if (owner == ci->client_playas) {
-						ci->client_playas = PLAYER_SPECTATOR;
-						NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
-					}
-
-					/* Find all clients that were in control of this company,
-					 * and mark them as spectator; broadcast this message to everyone */
-					FOR_ALL_CLIENTS(cs) {
-						ci = DEREF_CLIENT_INFO(cs);
-						if (ci->client_playas == owner) {
-							ci->client_playas = PLAYER_SPECTATOR;
-							NetworkUpdateClientInfo(ci->client_index);
-						}
-					}
-				}
-#endif /* ENABLE_NETWORK */
-			}
-
-			/* Remove the player */
-			ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
-			/* Register the player as not-active */
-			p->is_active = false;
-
-			if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
-				AI_PlayerDied(owner);
-		}
-	}
-}
-
-void DrawNewsBankrupcy(Window *w)
-{
-	Player *p;
-
-	DrawNewsBorder(w);
-
-	p = GetPlayer(GB(WP(w,news_d).ni->string_id, 0, 4));
-	DrawPlayerFace(p->face, p->player_color, 2, 23);
-	GfxFillRect(3, 23, 3+91, 23+118, 0x323 | USE_COLORTABLE);
-
-	SetDParam(0, p->president_name_1);
-	SetDParam(1, p->president_name_2);
-
-	DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
-
-	switch (WP(w,news_d).ni->string_id & 0xF0) {
-	case NB_BTROUBLE:
-		DrawStringCentered(w->width>>1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, 0);
-
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
-			w->width - 101);
-		break;
-
-	case NB_BMERGER: {
-		int32 price;
-
-		DrawStringCentered(w->width>>1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, 0);
-		COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
-		SetDParam(2, p->name_1);
-		SetDParam(3, p->name_2);
-		price = WP(w,news_d).ni->params[2];
-		SetDParam(4, price);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			price==0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
-			w->width - 101);
-		break;
-	}
-
-	case NB_BBANKRUPT:
-		DrawStringCentered(w->width>>1, 1, STR_705C_BANKRUPT, 0);
-		COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
-			w->width - 101);
-		break;
-
-	case NB_BNEWCOMPANY:
-		DrawStringCentered(w->width>>1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, 0);
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		COPY_IN_DPARAM(2,WP(w,news_d).ni->params, 2);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_705F_STARTS_CONSTRUCTION_NEAR,
-			w->width - 101);
-		break;
-
-	default:
-		NOT_REACHED();
-	}
-}
-
-StringID GetNewsStringBankrupcy(const NewsItem *ni)
-{
-	const Player *p = GetPlayer(GB(ni->string_id, 0, 4));
-
-	switch (ni->string_id & 0xF0) {
-	case NB_BTROUBLE:
-		SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
-		SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
-		SetDParam(2, p->name_1);
-		SetDParam(3, p->name_2);
-		return STR_02B6;
-	case NB_BMERGER:
-		SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
-		SetDParam(1, STR_705A_HAS_BEEN_SOLD_TO_FOR);
-		COPY_IN_DPARAM(2,ni->params, 2);
-		SetDParam(4, p->name_1);
-		SetDParam(5, p->name_2);
-		COPY_IN_DPARAM(6,ni->params + 2, 1);
-		return STR_02B6;
-	case NB_BBANKRUPT:
-		SetDParam(0, STR_705C_BANKRUPT);
-		SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
-		COPY_IN_DPARAM(2,ni->params, 2);
-		return STR_02B6;
-	case NB_BNEWCOMPANY:
-		SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
-		SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
-		SetDParam(2, p->name_1);
-		SetDParam(3, p->name_2);
-		COPY_IN_DPARAM(4,ni->params, 2);
-		return STR_02B6;
-	default:
-		NOT_REACHED();
-	}
-
-	/* useless, but avoids compiler warning this way */
-	return 0;
-}
-
-static void PlayersGenStatistics(void)
-{
-	Station *st;
-	Player *p;
-
-	FOR_ALL_STATIONS(st) {
-		_current_player = st->owner;
-		SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
-		SubtractMoneyFromPlayer(_price.station_value >> 1);
-	}
-
-	if (!HASBIT(1<<0|1<<3|1<<6|1<<9, _cur_month))
-		return;
-
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) {
-			memmove(&p->old_economy[1], &p->old_economy[0], sizeof(p->old_economy) - sizeof(p->old_economy[0]));
-			p->old_economy[0] = p->cur_economy;
-			memset(&p->cur_economy, 0, sizeof(p->cur_economy));
-
-			if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++;
-
-			UpdateCompanyRatingAndValue(p, true);
-			PlayersCheckBankrupt(p);
-
-			if (p->block_preview != 0) p->block_preview--;
-		}
-	}
-
-	InvalidateWindow(WC_INCOME_GRAPH, 0);
-	InvalidateWindow(WC_OPERATING_PROFIT, 0);
-	InvalidateWindow(WC_DELIVERED_CARGO, 0);
-	InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
-	InvalidateWindow(WC_COMPANY_VALUE, 0);
-	InvalidateWindow(WC_COMPANY_LEAGUE, 0);
-}
-
-static void AddSingleInflation(int32 *value, uint16 *frac, int32 amt)
-{
-	int64 tmp;
-	int32 low;
-	tmp = BIGMULS(*value, amt);
-	*frac = (uint16)(low = (uint16)tmp + *frac);
-	*value += (int32)(tmp >> 16) + (low >> 16);
-}
-
-static void AddInflation(void)
-{
-	int i;
-	int32 inf = _economy.infl_amount * 54;
-
-	for (i = 0; i != NUM_PRICES; i++) {
-		AddSingleInflation((int32*)&_price + i, _price_frac + i, inf);
-	}
-
-	_economy.max_loan_unround += BIGMULUS(_economy.max_loan_unround, inf, 16);
-
-	if (_economy.max_loan + 50000 <= _economy.max_loan_unround)
-		_economy.max_loan += 50000;
-
-	inf = _economy.infl_amount_pr * 54;
-	for (i = 0; i != NUM_CARGO; i++) {
-		AddSingleInflation(
-			(int32*)_cargo_payment_rates + i,
-			_cargo_payment_rates_frac + i,
-			inf
-		);
-	}
-
-	InvalidateWindowClasses(WC_BUILD_VEHICLE);
-	InvalidateWindowClasses(WC_REPLACE_VEHICLE);
-	InvalidateWindowClasses(WC_VEHICLE_DETAILS);
-	InvalidateWindow(WC_PAYMENT_RATES, 0);
-}
-
-static void PlayersPayInterest(void)
-{
-	const Player* p;
-	int interest = _economy.interest_rate * 54;
-
-	FOR_ALL_PLAYERS(p) {
-		if (!p->is_active) continue;
-
-		_current_player = p->index;
-		SET_EXPENSES_TYPE(EXPENSES_LOAN_INT);
-
-		SubtractMoneyFromPlayer(BIGMULUS(p->current_loan, interest, 16));
-
-		SET_EXPENSES_TYPE(EXPENSES_OTHER);
-		SubtractMoneyFromPlayer(_price.station_value >> 2);
-	}
-}
-
-static void HandleEconomyFluctuations(void)
-{
-	if (_opt.diff.economy == 0) return;
-
-	if (--_economy.fluct == 0) {
-		_economy.fluct = -(int)GB(Random(), 0, 2);
-		AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
-	} else if (_economy.fluct == -12) {
-		_economy.fluct = GB(Random(), 0, 8) + 312;
-		AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
-	}
-}
-
-static byte _price_category[NUM_PRICES] = {
-	0, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 2, 2, 2, 2, 2, 2,
-	2, 2, 1, 1, 1, 1, 1, 1,
-	2,
-};
-
-static const int32 _price_base[NUM_PRICES] = {
-	    100, // station_value
-	    100, // build_rail
-	     95, // build_road
-	     65, // build_signals
-	    275, // build_bridge
-	    600, // build_train_depot
-	    500, // build_road_depot
-	    700, // build_ship_depot
-	    450, // build_tunnel
-	    200, // train_station_track
-	    180, // train_station_length
-	    600, // build_airport
-	    200, // build_bus_station
-	    200, // build_truck_station
-	    350, // build_dock
-	 400000, // build_railvehicle
-	   2000, // build_railwagon
-	 700000, // aircraft_base
-	  14000, // roadveh_base
-	  65000, // ship_base
-	     20, // build_trees
-	    250, // terraform
-	     20, // clear_1
-	     40, // purchase_land
-	    200, // clear_2
-	    500, // clear_3
-	     20, // remove_trees
-	    -70, // remove_rail
-	     10, // remove_signals
-	     50, // clear_bridge
-	     80, // remove_train_depot
-	     80, // remove_road_depot
-	     90, // remove_ship_depot
-	     30, // clear_tunnel
-	  10000, // clear_water
-	     50, // remove_rail_station
-	     30, // remove_airport
-	     50, // remove_bus_station
-	     50, // remove_truck_station
-	     55, // remove_dock
-	   1600, // remove_house
-	     40, // remove_road
-	   5600, // running_rail[0] railroad
-	   5200, // running_rail[1] monorail
-	   4800, // running_rail[2] maglev
-	   9600, // aircraft_running
-	   1600, // roadveh_running
-	   5600, // ship_running
-	1000000, // build_industry
-};
-
-static byte price_base_multiplier[NUM_PRICES];
-
-/**
- * Reset changes to the price base multipliers.
- */
-void ResetPriceBaseMultipliers(void)
-{
-	uint i;
-
-	// 8 means no multiplier.
-	for (i = 0; i < NUM_PRICES; i++)
-		price_base_multiplier[i] = 8;
-}
-
-/**
- * Change a price base by the given factor.
- * The price base is altered by factors of two, with an offset of 8.
- * NewBaseCost = OldBaseCost * 2^(n-8)
- * @param price Index of price base to change.
- * @param factor Amount to change by.
- */
-void SetPriceBaseMultiplier(uint price, byte factor)
-{
-	assert(price < NUM_PRICES);
-	price_base_multiplier[price] = factor;
-}
-
-void StartupEconomy(void)
-{
-	int i;
-
-	assert(sizeof(_price) == NUM_PRICES * sizeof(int32));
-
-	for (i = 0; i != NUM_PRICES; i++) {
-		int32 price = _price_base[i];
-		if (_price_category[i] != 0) {
-			uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
-			if (mod < 1) {
-				price = price * 3 >> 2;
-			} else if (mod > 1) {
-				price = price * 9 >> 3;
-			}
-		}
-		if (price_base_multiplier[i] > 8) {
-			price <<= price_base_multiplier[i] - 8;
-		} else {
-			price >>= 8 - price_base_multiplier[i];
-		}
-		((int32*)&_price)[i] = price;
-		_price_frac[i] = 0;
-	}
-
-	_economy.interest_rate = _opt.diff.initial_interest;
-	_economy.infl_amount = _opt.diff.initial_interest;
-	_economy.infl_amount_pr = max(0, _opt.diff.initial_interest - 1);
-	_economy.max_loan_unround = _economy.max_loan = _opt.diff.max_loan * 1000;
-	_economy.fluct = GB(Random(), 0, 8) + 168;
-}
-
-Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode)
-{
-	TileIndex tile;
-	TileIndex tile2;
-	Pair tp;
-
-	/* if mode is false, use the singular form */
-	SetDParam(0, _cargoc.names_s[s->cargo_type] + (mode ? 0 : 32));
-
-	if (s->age < 12) {
-		if (s->cargo_type != CT_PASSENGERS && s->cargo_type != CT_MAIL) {
-			SetDParam(1, STR_INDUSTRY);
-			SetDParam(2, s->from);
-			tile = GetIndustry(s->from)->xy;
-
-			if (s->cargo_type != CT_GOODS && s->cargo_type != CT_FOOD) {
-				SetDParam(4, STR_INDUSTRY);
-				SetDParam(5, s->to);
-				tile2 = GetIndustry(s->to)->xy;
-			} else {
-				SetDParam(4, STR_TOWN);
-				SetDParam(5, s->to);
-				tile2 = GetTown(s->to)->xy;
-			}
-		} else {
-			SetDParam(1, STR_TOWN);
-			SetDParam(2, s->from);
-			tile = GetTown(s->from)->xy;
-
-			SetDParam(4, STR_TOWN);
-			SetDParam(5, s->to);
-			tile2 = GetTown(s->to)->xy;
-		}
-	} else {
-		SetDParam(1, s->from);
-		tile = GetStation(s->from)->xy;
-
-		SetDParam(2, s->to);
-		tile2 = GetStation(s->to)->xy;
-	}
-
-	tp.a = tile;
-	tp.b = tile2;
-
-	return tp;
-}
-
-void DeleteSubsidyWithTown(TownID index)
-{
-	Subsidy *s;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12 &&
-				(((s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL) && (index == s->from || index == s->to)) ||
-				((s->cargo_type == CT_GOODS || s->cargo_type == CT_FOOD) && index == s->to))) {
-			s->cargo_type = CT_INVALID;
-		}
-	}
-}
-
-void DeleteSubsidyWithIndustry(IndustryID index)
-{
-	Subsidy *s;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12 &&
-				s->cargo_type != CT_PASSENGERS && s->cargo_type != CT_MAIL &&
-				(index == s->from || (s->cargo_type != CT_GOODS && s->cargo_type != CT_FOOD && index == s->to))) {
-			s->cargo_type = CT_INVALID;
-		}
-	}
-}
-
-void DeleteSubsidyWithStation(StationID index)
-{
-	Subsidy *s;
-	bool dirty = false;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age >= 12 &&
-				(s->from == index || s->to == index)) {
-			s->cargo_type = CT_INVALID;
-			dirty = true;
-		}
-	}
-
-	if (dirty)
-		InvalidateWindow(WC_SUBSIDIES_LIST, 0);
-}
-
-typedef struct FoundRoute {
-	uint distance;
-	CargoID cargo;
-	void *from;
-	void *to;
-} FoundRoute;
-
-static void FindSubsidyPassengerRoute(FoundRoute *fr)
-{
-	Town *from,*to;
-
-	fr->distance = (uint)-1;
-
-	fr->from = from = GetRandomTown();
-	if (from == NULL || from->population < 400) return;
-
-	fr->to = to = GetRandomTown();
-	if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
-		return;
-
-	fr->distance = DistanceManhattan(from->xy, to->xy);
-}
-
-static void FindSubsidyCargoRoute(FoundRoute *fr)
-{
-	Industry *i;
-	int trans, total;
-	CargoID cargo;
-
-	fr->distance = (uint)-1;
-
-	fr->from = i = GetRandomIndustry();
-	if (i == NULL) return;
-
-	// Randomize cargo type
-	if (Random()&1 && i->produced_cargo[1] != CT_INVALID) {
-		cargo = i->produced_cargo[1];
-		trans = i->pct_transported[1];
-		total = i->total_production[1];
-	} else {
-		cargo = i->produced_cargo[0];
-		trans = i->pct_transported[0];
-		total = i->total_production[0];
-	}
-
-	// Quit if no production in this industry
-	//  or if the cargo type is passengers
-	//  or if the pct transported is already large enough
-	if (total == 0 || trans > 42 || cargo == CT_INVALID || cargo == CT_PASSENGERS)
-		return;
-
-	fr->cargo = cargo;
-
-	if (cargo == CT_GOODS || cargo == CT_FOOD) {
-		// The destination is a town
-		Town *t = GetRandomTown();
-
-		// Only want big towns
-		if (t == NULL || t->population < 900) return;
-
-		fr->distance = DistanceManhattan(i->xy, t->xy);
-		fr->to = t;
-	} else {
-		// The destination is an industry
-		Industry *i2 = GetRandomIndustry();
-
-		// The industry must accept the cargo
-		if (i == i2 || i == NULL ||
-				(cargo != i2->accepts_cargo[0] &&
-				cargo != i2->accepts_cargo[1] &&
-				cargo != i2->accepts_cargo[2]))
-			return;
-		fr->distance = DistanceManhattan(i->xy, i2->xy);
-		fr->to = i2;
-	}
-}
-
-static bool CheckSubsidyDuplicate(Subsidy *s)
-{
-	const Subsidy* ss;
-
-	for (ss = _subsidies; ss != endof(_subsidies); ss++) {
-		if (s != ss &&
-				ss->from == s->from &&
-				ss->to == s->to &&
-				ss->cargo_type == s->cargo_type) {
-			s->cargo_type = CT_INVALID;
-			return true;
-		}
-	}
-	return false;
-}
-
-
-static void SubsidyMonthlyHandler(void)
-{
-	Subsidy *s;
-	Pair pair;
-	Station *st;
-	uint n;
-	FoundRoute fr;
-	bool modified = false;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type == CT_INVALID) continue;
-
-		if (s->age == 12-1) {
-			pair = SetupSubsidyDecodeParam(s, 1);
-			AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
-			s->cargo_type = CT_INVALID;
-			modified = true;
-		} else if (s->age == 2*12-1) {
-			st = GetStation(s->to);
-			if (st->owner == _local_player) {
-				pair = SetupSubsidyDecodeParam(s, 1);
-				AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
-			}
-			s->cargo_type = CT_INVALID;
-			modified = true;
-		} else {
-			s->age++;
-		}
-	}
-
-	// 25% chance to go on
-	if (CHANCE16(1,4)) {
-		// Find a free slot
-		s = _subsidies;
-		while (s->cargo_type != CT_INVALID) {
-			if (++s == endof(_subsidies))
-				goto no_add;
-		}
-
-		n = 1000;
-		do {
-			FindSubsidyPassengerRoute(&fr);
-			if (fr.distance <= 70) {
-				s->cargo_type = CT_PASSENGERS;
-				s->from = ((Town*)fr.from)->index;
-				s->to = ((Town*)fr.to)->index;
-				goto add_subsidy;
-			}
-			FindSubsidyCargoRoute(&fr);
-			if (fr.distance <= 70) {
-				s->cargo_type = fr.cargo;
-				s->from = ((Industry*)fr.from)->index;
-				s->to = (fr.cargo == CT_GOODS || fr.cargo == CT_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
-	add_subsidy:
-				if (!CheckSubsidyDuplicate(s)) {
-					s->age = 0;
-					pair = SetupSubsidyDecodeParam(s, 0);
-					AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
-					modified = true;
-					break;
-				}
-			}
-		} while (n--);
-	}
-no_add:;
-	if (modified)
-		InvalidateWindow(WC_SUBSIDIES_LIST, 0);
-}
-
-static const SaveLoad _subsidies_desc[] = {
-	    SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
-	    SLE_VAR(Subsidy, age,        SLE_UINT8),
-	SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
-	SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
-	SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
-	SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
-	SLE_END()
-};
-
-static void Save_SUBS(void)
-{
-	int i;
-	Subsidy *s;
-
-	for (i = 0; i != lengthof(_subsidies); i++) {
-		s = &_subsidies[i];
-		if (s->cargo_type != CT_INVALID) {
-			SlSetArrayIndex(i);
-			SlObject(s, _subsidies_desc);
-		}
-	}
-}
-
-static void Load_SUBS(void)
-{
-	int index;
-	while ((index = SlIterateArray()) != -1)
-		SlObject(&_subsidies[index], _subsidies_desc);
-}
-
-int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
-{
-	CargoID cargo = cargo_type;
-	byte f;
-
-	/* zero the distance if it's the bank and very short transport. */
-	if (_opt.landscape == LT_NORMAL && cargo == CT_VALUABLES && dist < 10)
-		dist = 0;
-
-	f = 255;
-	if (transit_days > _cargoc.transit_days_1[cargo]) {
-		transit_days -= _cargoc.transit_days_1[cargo];
-		f -= transit_days;
-
-		if (transit_days > _cargoc.transit_days_2[cargo]) {
-			transit_days -= _cargoc.transit_days_2[cargo];
-
-			if (f < transit_days) {
-				f = 0;
-			} else {
-				f -= transit_days;
-			}
-		}
-	}
-	if (f < 31) f = 31;
-
-	return BIGMULSS(dist * f * num_pieces, _cargo_payment_rates[cargo], 21);
-}
-
-static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
-{
-	Industry* best = NULL;
-	Industry* ind;
-	uint u;
-
-	// Check if there's an industry close to the station that accepts the cargo
-	// XXX - Think of something better to
-	//       1) Only deliver to industries which are withing the catchment radius
-	//       2) Distribute between industries if more then one is present
-	u = (_patches.station_spread + 8) * 2;
-	FOR_ALL_INDUSTRIES(ind) {
-		uint t;
-
-		if (( cargo_type == ind->accepts_cargo[0] ||
-					cargo_type == ind->accepts_cargo[1] ||
-					cargo_type == ind->accepts_cargo[2]
-				) &&
-				ind->produced_cargo[0] != CT_INVALID &&
-				ind->produced_cargo[0] != cargo_type &&
-				(t = DistanceManhattan(ind->xy, xy)) < u) {
-			u = t;
-			best = ind;
-		}
-	}
-
-	/* Found one? */
-	if (best != NULL) {
-		best->was_cargo_delivered = true;
-		best->cargo_waiting[0] = min(best->cargo_waiting[0] + num_pieces, 0xFFFF);
-	}
-}
-
-static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
-{
-	Subsidy *s;
-	TileIndex xy;
-	Pair pair;
-	Player *p;
-
-	// check if there is an already existing subsidy that applies to us
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type == cargo_type &&
-				s->age >= 12 &&
-				s->from == from->index &&
-				s->to == to->index) {
-			return true;
-		}
-	}
-
-	/* check if there's a new subsidy that applies.. */
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type == cargo_type && s->age < 12) {
-			/* Check distance from source */
-			if (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL) {
-				xy = GetTown(s->from)->xy;
-			} else {
-				xy = (GetIndustry(s->from))->xy;
-			}
-			if (DistanceMax(xy, from->xy) > 9) continue;
-
-			/* Check distance from dest */
-			switch (cargo_type) {
-				case CT_PASSENGERS:
-				case CT_MAIL:
-				case CT_GOODS:
-				case CT_FOOD:
-					xy = GetTown(s->to)->xy;
-					break;
-
-				default:
-					xy = GetIndustry(s->to)->xy;
-					break;
-			}
-			if (DistanceMax(xy, to->xy) > 9) continue;
-
-			/* Found a subsidy, change the values to indicate that it's in use */
-			s->age = 12;
-			s->from = from->index;
-			s->to = to->index;
-
-			/* Add a news item */
-			pair = SetupSubsidyDecodeParam(s, 0);
-			InjectDParam(2);
-
-			p = GetPlayer(_current_player);
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			AddNewsItem(
-				STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
-				NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
-				pair.a, pair.b
-			);
-
-			InvalidateWindow(WC_SUBSIDIES_LIST, 0);
-			return true;
-		}
-	}
-	return false;
-}
-
-static int32 DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, byte days_in_transit)
-{
-	bool subsidised;
-	Station *s_from, *s_to;
-	int32 profit;
-
-	assert(num_pieces > 0);
-
-	// Update player statistics
-	{
-		Player *p = GetPlayer(_current_player);
-		p->cur_economy.delivered_cargo += num_pieces;
-		SETBIT(p->cargo_types, cargo_type);
-	}
-
-	// Get station pointers.
-	s_from = GetStation(source);
-	s_to = GetStation(dest);
-
-	// Check if a subsidy applies.
-	subsidised = CheckSubsidised(s_from, s_to, cargo_type);
-
-	// Increase town's counter for some special goods types
-	if (cargo_type == CT_FOOD) s_to->town->new_act_food += num_pieces;
-	if (cargo_type == CT_WATER)  s_to->town->new_act_water += num_pieces;
-
-	// Give the goods to the industry.
-	DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
-
-	// Determine profit
-	profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(s_from->xy, s_to->xy), days_in_transit, cargo_type);
-
-	// Modify profit if a subsidy is in effect
-	if (subsidised) {
-		switch (_opt.diff.subsidy_multiplier) {
-			case 0:  profit += profit >> 1; break;
-			case 1:  profit *= 2; break;
-			case 2:  profit *= 3; break;
-			default: profit *= 4; break;
-		}
-	}
-
-	return profit;
-}
-
-/*
- * Returns true if Vehicle v should wait loading because other vehicle is
- * already loading the same cargo type
- * v = vehicle to load, u = GetFirstInChain(v)
- */
-static bool LoadWait(const Vehicle* v, const Vehicle* u)
-{
-	const Vehicle *w;
-	const Vehicle *x;
-	bool has_any_cargo = false;
-
-	if (!(u->current_order.flags & OF_FULL_LOAD)) return false;
-
-	for (w = u; w != NULL; w = w->next) {
-		if (w->cargo_count != 0) {
-			if (v->cargo_type == w->cargo_type &&
-					u->last_station_visited == w->cargo_source) {
-				return false;
-			}
-			has_any_cargo = true;
-		}
-	}
-
-	FOR_ALL_VEHICLES(x) {
-		if ((x->type != VEH_Train || IsFrontEngine(x)) && // for all locs
-				u->last_station_visited == x->last_station_visited && // at the same station
-				!(x->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed
-				x->current_order.type == OT_LOADING && // loading
-				u != x) { // not itself
-			bool other_has_any_cargo = false;
-			bool has_space_for_same_type = false;
-			bool other_has_same_type = false;
-
-			for (w = x; w != NULL; w = w->next) {
-				if (w->cargo_count < w->cargo_cap && v->cargo_type == w->cargo_type) {
-					has_space_for_same_type = true;
-				}
-
-				if (w->cargo_count != 0) {
-					if (v->cargo_type == w->cargo_type &&
-							u->last_station_visited == w->cargo_source) {
-						other_has_same_type = true;
-					}
-					other_has_any_cargo = true;
-				}
-			}
-
-			if (has_space_for_same_type) {
-				if (other_has_same_type) return true;
-				if (other_has_any_cargo && !has_any_cargo) return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-int LoadUnloadVehicle(Vehicle *v, bool just_arrived)
-{
-	int profit = 0;
-	int v_profit = 0; //virtual profit for feeder systems
-	int v_profit_total = 0;
-	int unloading_time = 20;
-	Vehicle *u = v;
-	int result = 0;
-	StationID last_visited;
-	Station *st;
-	int t;
-	uint count, cap;
-	PlayerID old_player;
-	bool completely_empty = true;
-	byte load_amount;
-	bool anything_loaded = false;
-
-	assert(v->current_order.type == OT_LOADING);
-
-	v->cur_speed = 0;
-
-	/* Loading can only have finished when all the cargo has been unloaded, and
-	 * there is nothing left to load. It's easier to clear this if the
-	 * conditions haven't been met than attempting to check them all before
-	 * enabling though. */
-	SETBIT(v->load_status, LS_LOADING_FINISHED);
-
-	old_player = _current_player;
-	_current_player = v->owner;
-
-	last_visited = v->last_station_visited;
-	st = GetStation(last_visited);
-
-	for (; v != NULL; v = v->next) {
-		GoodsEntry* ge;
-		load_amount = EngInfo(v->engine_type)->load_amount;
-		if (_patches.gradual_loading) {
-			uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
-			if (cb_load_amount != CALLBACK_FAILED) load_amount = cb_load_amount & 0xFF;
-		}
-
-		if (v->cargo_cap == 0) continue;
-
-		/* If the vehicle has just arrived, set it to unload. */
-		if (just_arrived) SETBIT(v->load_status, LS_CARGO_UNLOADING);
-
-		ge = &st->goods[v->cargo_type];
-		count = GB(ge->waiting_acceptance, 0, 12);
-
-		/* unload? */
-		if (v->cargo_count != 0 && HASBIT(v->load_status, LS_CARGO_UNLOADING)) {
-			uint16 amount_unloaded = _patches.gradual_loading ? min(v->cargo_count, load_amount) : v->cargo_count;
-
-			CLRBIT(u->load_status, LS_LOADING_FINISHED);
-
-			if (v->cargo_source != last_visited && ge->waiting_acceptance & 0x8000 && !(u->current_order.flags & OF_TRANSFER)) {
-				// deliver goods to the station
-				st->time_since_unload = 0;
-
-				unloading_time += v->cargo_count; /* TTDBUG: bug in original TTD */
-				if (just_arrived && !HASBIT(v->load_status, LS_CARGO_PAID_FOR)) {
-					profit += DeliverGoods(v->cargo_count, v->cargo_type, v->cargo_source, last_visited, v->cargo_days);
-					SETBIT(v->load_status, LS_CARGO_PAID_FOR);
-				}
-				result |= 1;
-				v->cargo_count -= amount_unloaded;
-				if (_patches.gradual_loading) continue;
-			} else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
-				/* unload goods and let it wait at the station */
-				st->time_since_unload = 0;
-				if (just_arrived && (u->current_order.flags & OF_TRANSFER) && !HASBIT(v->load_status, LS_CARGO_PAID_FOR)) {
-					v_profit = GetTransportedGoodsIncome(
-						v->cargo_count,
-						DistanceManhattan(GetStation(v->cargo_source)->xy, GetStation(last_visited)->xy),
-						v->cargo_days,
-						v->cargo_type) * 3 / 2;
-
-					v_profit_total += v_profit;
-					SETBIT(v->load_status, LS_CARGO_PAID_FOR);
-				}
-
-				unloading_time += v->cargo_count;
-				t = GB(ge->waiting_acceptance, 0, 12);
-				if (t == 0) {
-					// No goods waiting at station
-					ge->enroute_time = v->cargo_days;
-					ge->enroute_from = v->cargo_source;
-				} else {
-					// Goods already waiting at station. Set counters to the worst value.
-					if (v->cargo_days >= ge->enroute_time)
-						ge->enroute_time = v->cargo_days;
-					if (last_visited != ge->enroute_from)
-						ge->enroute_from = v->cargo_source;
-				}
-				// Update amount of waiting cargo
-				SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + t, 0xFFF));
-
-				if (u->current_order.flags & OF_TRANSFER) {
-					ge->feeder_profit += v_profit;
-					u->profit_this_year += v_profit;
-				}
-				result |= 2;
-				v->cargo_count -= amount_unloaded;
-				if (_patches.gradual_loading) continue;
-			}
-
-			if (v->cargo_count != 0) completely_empty = false;
-		}
-
-		/* The vehicle must have been unloaded because it is either empty, or
-		 * the UNLOADING bit is already clear in v->load_status. */
-		CLRBIT(v->load_status, LS_CARGO_UNLOADING);
-		CLRBIT(v->load_status, LS_CARGO_PAID_FOR);
-
-		/* don't pick up goods that we unloaded */
-		if (u->current_order.flags & OF_UNLOAD) continue;
-
-		/* update stats */
-		ge->days_since_pickup = 0;
-		switch (u->type) {
-			case VEH_Train: t = u->u.rail.cached_max_speed; break;
-			case VEH_Road:  t = u->max_speed / 2;           break;
-			default:        t = u->max_speed;               break;
-		}
-
-		// if last speed is 0, we treat that as if no vehicle has ever visited the station.
-		ge->last_speed = min(t, 255);
-		ge->last_age = _cur_year - v->build_year;
-
-		// If there's goods waiting at the station, and the vehicle
-		//  has capacity for it, load it on the vehicle.
-		if (count != 0 &&
-				(cap = v->cargo_cap - v->cargo_count) != 0) {
-			int cargoshare;
-			int feeder_profit_share;
-
-			if (v->cargo_count == 0)
-				TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
-
-			/* Skip loading this vehicle if another train/vehicle is already handling
-			 * the same cargo type at this station */
-			if (_patches.improved_load && (u->current_order.flags & OF_FULL_LOAD) && LoadWait(v,u)) continue;
-
-			/* TODO: Regarding this, when we do gradual loading, we
-			 * should first unload all vehicles and then start
-			 * loading them. Since this will cause
-			 * VEHICLE_TRIGGER_EMPTY to be called at the time when
-			 * the whole vehicle chain is really totally empty, the
-			 * @completely_empty assignment can then be safely
-			 * removed; that's how TTDPatch behaves too. --pasky */
-			completely_empty = false;
-			anything_loaded = true;
-
-			if (cap > count) cap = count;
-			if (_patches.gradual_loading) cap = min(cap, load_amount);
-			if (cap < count) CLRBIT(u->load_status, LS_LOADING_FINISHED);
-			cargoshare = cap * 10000 / ge->waiting_acceptance;
-			feeder_profit_share = ge->feeder_profit * cargoshare / 10000;
-			v->cargo_count += cap;
-			ge->waiting_acceptance -= cap;
-			u->profit_this_year -= feeder_profit_share;
-			ge->feeder_profit -= feeder_profit_share;
-			unloading_time += cap;
-			st->time_since_load = 0;
-
-			// And record the source of the cargo, and the days in travel.
-			v->cargo_source = ge->enroute_from;
-			v->cargo_days = ge->enroute_time;
-			result |= 2;
-			st->last_vehicle_type = v->type;
-		}
-	}
-
-	v = u;
-
-	if (_patches.gradual_loading) {
-		/* The time it takes to load one 'slice' of cargo or passengers depends
-		 * on the vehicle type - the values here are those found in TTDPatch */
-		uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
-
-		unloading_time = gradual_loading_wait_time[v->type - VEH_Train];
-		if (HASBIT(v->load_status, LS_LOADING_FINISHED)) {
-			if (anything_loaded) {
-				unloading_time += 20;
-			} else {
-				unloading_time = 20;
-			}
-		}
-	}
-
-	if (v_profit_total > 0) {
-		ShowFeederIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, v_profit_total);
-	}
-
-	if (v->type == VEH_Train) {
-		// Each platform tile is worth 2 rail vehicles.
-		int overhang = v->u.rail.cached_total_length - GetStationPlatforms(st, v->tile) * TILE_SIZE;
-		if (overhang > 0) {
-			unloading_time <<= 1;
-			unloading_time += (overhang * unloading_time) / 8;
-		}
-	}
-
-	v->load_unload_time_rem = unloading_time;
-
-	if (completely_empty) {
-		TriggerVehicle(v, VEHICLE_TRIGGER_EMPTY);
-	}
-
-	if (result != 0) {
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		MarkStationTilesDirty(st);
-
-		if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited);
-
-		if (profit != 0) {
-			v->profit_this_year += profit;
-			SubtractMoneyFromPlayer(-profit);
-
-			if (IsLocalPlayer() && !PlayVehicleSound(v, VSE_LOAD_UNLOAD)) {
-				SndPlayVehicleFx(SND_14_CASHTILL, v);
-			}
-
-			ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, -profit);
-		}
-	}
-
-	_current_player = old_player;
-	return result;
-}
-
-void PlayersMonthlyLoop(void)
-{
-	PlayersGenStatistics();
-	if (_patches.inflation && _cur_year < MAX_YEAR)
-		AddInflation();
-	PlayersPayInterest();
-	// Reset the _current_player flag
-	_current_player = OWNER_NONE;
-	HandleEconomyFluctuations();
-	SubsidyMonthlyHandler();
-}
-
-static void DoAcquireCompany(Player *p)
-{
-	Player *owner;
-	int i,pi;
-	int64 value;
-
-	SetDParam(0, p->name_1);
-	SetDParam(1, p->name_2);
-	SetDParam(2, p->bankrupt_value);
-	AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
-
-	// original code does this a little bit differently
-	pi = p->index;
-	ChangeOwnershipOfPlayerItems(pi, _current_player);
-
-	if (p->bankrupt_value == 0) {
-		owner = GetPlayer(_current_player);
-		owner->current_loan += p->current_loan;
-	}
-
-	value = CalculateCompanyValue(p) >> 2;
-	for (i = 0; i != 4; i++) {
-		if (p->share_owners[i] != PLAYER_SPECTATOR) {
-			owner = GetPlayer(p->share_owners[i]);
-			owner->money64 += value;
-			owner->yearly_expenses[0][EXPENSES_OTHER] += value;
-			UpdatePlayerMoney32(owner);
-		}
-	}
-
-	p->is_active = false;
-
-	DeletePlayerWindows(pi);
-	RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
-}
-
-extern int GetAmountOwnedBy(Player *p, byte owner);
-
-/** Acquire shares in an opposing company.
- * @param tile unused
- * @param p1 player to buy the shares from
- * @param p2 unused
- */
-int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-	int64 cost;
-
-	/* Check if buying shares is allowed (protection against modified clients */
-	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-	p = GetPlayer(p1);
-
-	/* Protect new companies from hostile takeovers */
-	if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED);
-
-	/* Those lines are here for network-protection (clients can be slow) */
-	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return 0;
-
-	/* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
-	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return 0;
-
-	cost = CalculateCompanyValue(p) >> 2;
-	if (flags & DC_EXEC) {
-		PlayerID* b = p->share_owners;
-		int i;
-
-		while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
-		*b = _current_player;
-
-		for (i = 0; p->share_owners[i] == _current_player;) {
-			if (++i == 4) {
-				p->bankrupt_value = 0;
-				DoAcquireCompany(p);
-				break;
-			}
-		}
-		InvalidateWindow(WC_COMPANY, p1);
-	}
-	return cost;
-}
-
-/** Sell shares in an opposing company.
- * @param tile unused
- * @param p1 player to sell the shares from
- * @param p2 unused
- */
-int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-	int64 cost;
-
-	/* Check if buying shares is allowed (protection against modified clients */
-	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-	p = GetPlayer(p1);
-
-	/* Those lines are here for network-protection (clients can be slow) */
-	if (GetAmountOwnedBy(p, _current_player) == 0) return 0;
-
-	/* adjust it a little to make it less profitable to sell and buy */
-	cost = CalculateCompanyValue(p) >> 2;
-	cost = -(cost - (cost >> 7));
-
-	if (flags & DC_EXEC) {
-		PlayerID* b = p->share_owners;
-		while (*b != _current_player) b++; /* share owners is guaranteed to contain player */
-		*b = PLAYER_SPECTATOR;
-		InvalidateWindow(WC_COMPANY, p1);
-	}
-	return cost;
-}
-
-/** Buy up another company.
- * When a competing company is gone bankrupt you get the chance to purchase
- * that company.
- * @todo currently this only works for AI players
- * @param tile unused
- * @param p1 player/company to buy up
- * @param p2 unused
- */
-int32 CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-
-	/* Disable takeovers in multiplayer games */
-	if (!IsValidPlayer((PlayerID)p1) || _networking) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-	p = GetPlayer(p1);
-
-	if (!p->is_ai) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		DoAcquireCompany(p);
-	}
-	return p->bankrupt_value;
-}
-
-// Prices
-static void SaveLoad_PRIC(void)
-{
-	SlArray(&_price,      NUM_PRICES, SLE_INT32);
-	SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
-}
-
-// Cargo payment rates
-static void SaveLoad_CAPR(void)
-{
-	SlArray(&_cargo_payment_rates,      NUM_CARGO, SLE_INT32);
-	SlArray(&_cargo_payment_rates_frac, NUM_CARGO, SLE_UINT16);
-}
-
-static const SaveLoad _economy_desc[] = {
-	SLE_VAR(Economy, max_loan,         SLE_INT32),
-	SLE_VAR(Economy, max_loan_unround, SLE_INT32),
-	SLE_VAR(Economy, fluct,            SLE_FILE_I16 | SLE_VAR_I32),
-	SLE_VAR(Economy, interest_rate,    SLE_UINT8),
-	SLE_VAR(Economy, infl_amount,      SLE_UINT8),
-	SLE_VAR(Economy, infl_amount_pr,   SLE_UINT8),
-	SLE_END()
-};
-
-// Economy variables
-static void SaveLoad_ECMY(void)
-{
-	SlObject(&_economy, _economy_desc);
-}
-
-const ChunkHandler _economy_chunk_handlers[] = {
-	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
-	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
-	{ 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
-	{ 'ECMY', SaveLoad_ECMY, SaveLoad_ECMY, CH_RIFF | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/economy.cpp
@@ -0,0 +1,1738 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "functions.h"
+#include "strings.h" // XXX InjectDParam()
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "news.h"
+#include "player.h"
+#include "station.h"
+#include "vehicle.h"
+#include "window.h"
+#include "gfx.h"
+#include "command.h"
+#include "saveload.h"
+#include "economy.h"
+#include "industry.h"
+#include "town.h"
+#include "network/network.h"
+#include "sound.h"
+#include "engine.h"
+#include "network/network_data.h"
+#include "variables.h"
+#include "vehicle_gui.h"
+#include "ai/ai.h"
+#include "train.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+#include "newgrf_callbacks.h"
+#include "unmovable.h"
+#include "date.h"
+
+// Score info
+const ScoreInfo _score_info[] = {
+	{ SCORE_VEHICLES,        120, 100 },
+	{ SCORE_STATIONS,         80, 100 },
+	{ SCORE_MIN_PROFIT,    10000, 100 },
+	{ SCORE_MIN_INCOME,    50000,  50 },
+	{ SCORE_MAX_INCOME,   100000, 100 },
+	{ SCORE_DELIVERED,     40000, 400 },
+	{ SCORE_CARGO,             8,  50 },
+	{ SCORE_MONEY,      10000000,  50 },
+	{ SCORE_LOAN,         250000,  50 },
+	{ SCORE_TOTAL,             0,   0 }
+};
+
+int _score_part[MAX_PLAYERS][NUM_SCORE];
+
+int64 CalculateCompanyValue(const Player* p)
+{
+	PlayerID owner = p->index;
+	int64 value;
+
+	{
+		Station *st;
+		uint num = 0;
+
+		FOR_ALL_STATIONS(st) {
+			if (st->owner == owner) {
+				uint facil = st->facilities;
+				do num += (facil&1); while (facil >>= 1);
+			}
+		}
+
+		value = num * _price.station_value * 25;
+	}
+
+	{
+		Vehicle *v;
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->owner != owner) continue;
+
+			if (v->type == VEH_Train ||
+					v->type == VEH_Road ||
+					(v->type == VEH_Aircraft && v->subtype<=2) ||
+					v->type == VEH_Ship) {
+				value += v->value * 3 >> 1;
+			}
+		}
+	}
+
+	value += p->money64 - p->current_loan; // add real money value
+
+	return max64(value, 1);
+}
+
+// if update is set to true, the economy is updated with this score
+//  (also the house is updated, should only be true in the on-tick event)
+int UpdateCompanyRatingAndValue(Player *p, bool update)
+{
+	byte owner = p->index;
+	int score = 0;
+
+	memset(_score_part[owner], 0, sizeof(_score_part[owner]));
+
+/* Count vehicles */
+	{
+		Vehicle *v;
+		int32 min_profit = 0;
+		bool min_profit_first = true;
+		uint num = 0;
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->owner != owner) continue;
+			if ((v->type == VEH_Train && IsFrontEngine(v)) ||
+					 v->type == VEH_Road ||
+					(v->type == VEH_Aircraft && v->subtype <= 2) ||
+					 v->type == VEH_Ship) {
+				num++;
+				if (v->age > 730) {
+					/* Find the vehicle with the lowest amount of profit */
+					if (min_profit_first == true) {
+						min_profit = v->profit_last_year;
+						min_profit_first = false;
+					} else if (min_profit > v->profit_last_year) {
+						min_profit = v->profit_last_year;
+					}
+				}
+			}
+		}
+
+		_score_part[owner][SCORE_VEHICLES] = num;
+		/* Don't allow negative min_profit to show */
+		if (min_profit > 0)
+			_score_part[owner][SCORE_MIN_PROFIT] = min_profit;
+	}
+
+/* Count stations */
+	{
+		uint num = 0;
+		const Station* st;
+
+		FOR_ALL_STATIONS(st) {
+			if (st->owner == owner) {
+				int facil = st->facilities;
+				do num += facil&1; while (facil>>=1);
+			}
+		}
+		_score_part[owner][SCORE_STATIONS] = num;
+	}
+
+/* Generate statistics depending on recent income statistics */
+	{
+		const PlayerEconomyEntry* pee;
+		int numec;
+		int32 min_income;
+		int32 max_income;
+
+		numec = min(p->num_valid_stat_ent, 12);
+		if (numec != 0) {
+			min_income = 0x7FFFFFFF;
+			max_income = 0;
+			pee = p->old_economy;
+			do {
+				min_income = min(min_income, pee->income + pee->expenses);
+				max_income = max(max_income, pee->income + pee->expenses);
+			} while (++pee,--numec);
+
+			if (min_income > 0)
+				_score_part[owner][SCORE_MIN_INCOME] = min_income;
+
+			_score_part[owner][SCORE_MAX_INCOME] = max_income;
+		}
+	}
+
+/* Generate score depending on amount of transported cargo */
+	{
+		const PlayerEconomyEntry* pee;
+		int numec;
+		uint32 total_delivered;
+
+		numec = min(p->num_valid_stat_ent, 4);
+		if (numec != 0) {
+			pee = p->old_economy;
+			total_delivered = 0;
+			do {
+				total_delivered += pee->delivered_cargo;
+			} while (++pee,--numec);
+
+			_score_part[owner][SCORE_DELIVERED] = total_delivered;
+		}
+	}
+
+/* Generate score for variety of cargo */
+	{
+		uint cargo = p->cargo_types;
+		uint num = 0;
+		do num += cargo&1; while (cargo>>=1);
+		_score_part[owner][SCORE_CARGO] = num;
+		if (update) p->cargo_types = 0;
+	}
+
+/* Generate score for player money */
+	{
+		int32 money = p->player_money;
+		if (money > 0) {
+			_score_part[owner][SCORE_MONEY] = money;
+		}
+	}
+
+/* Generate score for loan */
+	{
+		_score_part[owner][SCORE_LOAN] = _score_info[SCORE_LOAN].needed - p->current_loan;
+	}
+
+	// Now we calculate the score for each item..
+	{
+		int i;
+		int total_score = 0;
+		int s;
+		score = 0;
+		for (i = 0; i < NUM_SCORE; i++) {
+			// Skip the total
+			if (i == SCORE_TOTAL) continue;
+			// Check the score
+			s = (_score_part[owner][i] >= _score_info[i].needed) ?
+				_score_info[i].score :
+				_score_part[owner][i] * _score_info[i].score / _score_info[i].needed;
+			if (s < 0) s = 0;
+			score += s;
+			total_score += _score_info[i].score;
+		}
+
+		_score_part[owner][SCORE_TOTAL] = score;
+
+		// We always want the score scaled to SCORE_MAX (1000)
+		if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score;
+	}
+
+	if (update) {
+		p->old_economy[0].performance_history = score;
+		UpdateCompanyHQ(p, score);
+		p->old_economy[0].company_value = CalculateCompanyValue(p);
+	}
+
+	InvalidateWindow(WC_PERFORMANCE_DETAIL, 0);
+	return score;
+}
+
+// use PLAYER_SPECTATOR as new_player to delete the player.
+void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
+{
+	Town *t;
+	PlayerID old = _current_player;
+	_current_player = old_player;
+
+	/* Temporarily increase the player's money, to be sure that
+	 * removing his/her property doesn't fail because of lack of money.
+	 * Not too drastically though, because it could overflow */
+	if (new_player == PLAYER_SPECTATOR) {
+		GetPlayer(old_player)->money64 = MAX_UVALUE(uint64) >>2; // jackpot ;p
+		UpdatePlayerMoney32(GetPlayer(old_player));
+	}
+
+	if (new_player == PLAYER_SPECTATOR) {
+		Subsidy *s;
+
+		for (s = _subsidies; s != endof(_subsidies); s++) {
+			if (s->cargo_type != CT_INVALID && s->age >= 12) {
+				if (GetStation(s->to)->owner == old_player) s->cargo_type = CT_INVALID;
+			}
+		}
+	}
+
+	/* Take care of rating in towns */
+	FOR_ALL_TOWNS(t) {
+		/* If a player takes over, give the ratings to that player. */
+		if (new_player != PLAYER_SPECTATOR) {
+			if (HASBIT(t->have_ratings, old_player)) {
+				if (HASBIT(t->have_ratings, new_player)) {
+					// use max of the two ratings.
+					t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
+				} else {
+					SETBIT(t->have_ratings, new_player);
+					t->ratings[new_player] = t->ratings[old_player];
+				}
+			}
+		}
+
+		/* Reset the ratings for the old player */
+		t->ratings[old_player] = 500;
+		CLRBIT(t->have_ratings, old_player);
+	}
+
+	{
+		int num_train = 0;
+		int num_road = 0;
+		int num_ship = 0;
+		int num_aircraft = 0;
+		Vehicle *v;
+
+		// Determine Ids for the new vehicles
+		FOR_ALL_VEHICLES(v) {
+			if (v->owner == new_player) {
+				switch (v->type) {
+					case VEH_Train:    if (IsFrontEngine(v)) num_train++; break;
+					case VEH_Road:     num_road++; break;
+					case VEH_Ship:     num_ship++; break;
+					case VEH_Aircraft: if (v->subtype <= 2) num_aircraft++; break;
+					default: break;
+				}
+			}
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->owner == old_player && IS_BYTE_INSIDE(v->type, VEH_Train, VEH_Aircraft + 1)) {
+				if (new_player == PLAYER_SPECTATOR) {
+					DeleteWindowById(WC_VEHICLE_VIEW, v->index);
+					DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
+					DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
+					DeleteVehicle(v);
+				} else {
+					v->owner = new_player;
+					if (IsEngineCountable(v)) GetPlayer(new_player)->num_engines[v->engine_type]++;
+					switch (v->type) {
+						case VEH_Train:    if (IsFrontEngine(v)) v->unitnumber = ++num_train; break;
+						case VEH_Road:     v->unitnumber = ++num_road; break;
+						case VEH_Ship:     v->unitnumber = ++num_ship; break;
+						case VEH_Aircraft: if (v->subtype <= 2) v->unitnumber = ++num_aircraft; break;
+					}
+				}
+			}
+		}
+	}
+
+	// Change ownership of tiles
+	{
+		TileIndex tile = 0;
+		do {
+			ChangeTileOwner(tile, old_player, new_player);
+		} while (++tile != MapSize());
+	}
+
+	/* Change color of existing windows */
+	if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);
+
+	{
+		Player *p;
+		uint i;
+
+		/* Check for shares */
+		FOR_ALL_PLAYERS(p) {
+			for (i = 0; i < 4; i++) {
+				/* 'Sell' the share if this player has any */
+				if (p->share_owners[i] == _current_player) {
+					p->share_owners[i] = PLAYER_SPECTATOR;
+				}
+			}
+		}
+		p = GetPlayer(_current_player);
+		/* Sell all the shares that people have on this company */
+		for (i = 0; i < 4; i++)
+			p->share_owners[i] = PLAYER_SPECTATOR;
+	}
+
+	_current_player = old;
+
+	MarkWholeScreenDirty();
+}
+
+static void PlayersCheckBankrupt(Player *p)
+{
+	PlayerID owner;
+	int64 val;
+
+	// If the player has money again, it does not go bankrupt
+	if (p->player_money >= 0) {
+		p->quarters_of_bankrupcy = 0;
+		return;
+	}
+
+	p->quarters_of_bankrupcy++;
+
+	owner = p->index;
+
+	switch (p->quarters_of_bankrupcy) {
+		case 2:
+			AddNewsItem( (StringID)(owner | NB_BTROUBLE),
+				NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
+			break;
+		case 3: {
+			/* XXX - In multiplayer, should we ask other players if it wants to take
+		          over when it is a human company? -- TrueLight */
+			if (IsHumanPlayer(owner)) {
+				AddNewsItem( (StringID)(owner | NB_BTROUBLE),
+					NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
+				break;
+			}
+
+			// Check if the company has any value.. if not, declare it bankrupt
+			//  right now
+			val = CalculateCompanyValue(p);
+			if (val > 0) {
+				p->bankrupt_value = val;
+				p->bankrupt_asked = 1 << owner; // Don't ask the owner
+				p->bankrupt_timeout = 0;
+				break;
+			}
+			// Else, falltrue to case 4...
+		}
+		case 4: {
+			// Close everything the owner has open
+			DeletePlayerWindows(owner);
+
+//		Show bankrupt news
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
+
+			if (IsHumanPlayer(owner)) {
+				/* XXX - If we are in offline mode, leave the player playing. Eg. there
+				 * is no THE-END, otherwise mark the player as spectator to make sure
+				 * he/she is no long in control of this company */
+				if (!_networking) {
+					p->bankrupt_asked = 0xFF;
+					p->bankrupt_timeout = 0x456;
+					break;
+				} else if (owner == _local_player) {
+					_network_playas = PLAYER_SPECTATOR;
+					SetLocalPlayer(PLAYER_SPECTATOR);
+				}
+
+#ifdef ENABLE_NETWORK
+				/* The server has to handle all administrative issues, for example
+				 * updating and notifying all clients of what has happened */
+				if (_network_server) {
+					const NetworkClientState *cs;
+					NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+
+					/* The server has just gone belly-up, mark it as spectator */
+					if (owner == ci->client_playas) {
+						ci->client_playas = PLAYER_SPECTATOR;
+						NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
+					}
+
+					/* Find all clients that were in control of this company,
+					 * and mark them as spectator; broadcast this message to everyone */
+					FOR_ALL_CLIENTS(cs) {
+						ci = DEREF_CLIENT_INFO(cs);
+						if (ci->client_playas == owner) {
+							ci->client_playas = PLAYER_SPECTATOR;
+							NetworkUpdateClientInfo(ci->client_index);
+						}
+					}
+				}
+#endif /* ENABLE_NETWORK */
+			}
+
+			/* Remove the player */
+			ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
+			/* Register the player as not-active */
+			p->is_active = false;
+
+			if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
+				AI_PlayerDied(owner);
+		}
+	}
+}
+
+void DrawNewsBankrupcy(Window *w)
+{
+	Player *p;
+
+	DrawNewsBorder(w);
+
+	p = GetPlayer(GB(WP(w,news_d).ni->string_id, 0, 4));
+	DrawPlayerFace(p->face, p->player_color, 2, 23);
+	GfxFillRect(3, 23, 3+91, 23+118, 0x323 | USE_COLORTABLE);
+
+	SetDParam(0, p->president_name_1);
+	SetDParam(1, p->president_name_2);
+
+	DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
+
+	switch (WP(w,news_d).ni->string_id & 0xF0) {
+	case NB_BTROUBLE:
+		DrawStringCentered(w->width>>1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, 0);
+
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+
+		DrawStringMultiCenter(
+			((w->width - 101) >> 1) + 98,
+			90,
+			STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
+			w->width - 101);
+		break;
+
+	case NB_BMERGER: {
+		int32 price;
+
+		DrawStringCentered(w->width>>1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, 0);
+		COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
+		SetDParam(2, p->name_1);
+		SetDParam(3, p->name_2);
+		price = WP(w,news_d).ni->params[2];
+		SetDParam(4, price);
+		DrawStringMultiCenter(
+			((w->width - 101) >> 1) + 98,
+			90,
+			price==0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
+			w->width - 101);
+		break;
+	}
+
+	case NB_BBANKRUPT:
+		DrawStringCentered(w->width>>1, 1, STR_705C_BANKRUPT, 0);
+		COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
+		DrawStringMultiCenter(
+			((w->width - 101) >> 1) + 98,
+			90,
+			STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
+			w->width - 101);
+		break;
+
+	case NB_BNEWCOMPANY:
+		DrawStringCentered(w->width>>1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, 0);
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		COPY_IN_DPARAM(2,WP(w,news_d).ni->params, 2);
+		DrawStringMultiCenter(
+			((w->width - 101) >> 1) + 98,
+			90,
+			STR_705F_STARTS_CONSTRUCTION_NEAR,
+			w->width - 101);
+		break;
+
+	default:
+		NOT_REACHED();
+	}
+}
+
+StringID GetNewsStringBankrupcy(const NewsItem *ni)
+{
+	const Player *p = GetPlayer(GB(ni->string_id, 0, 4));
+
+	switch (ni->string_id & 0xF0) {
+	case NB_BTROUBLE:
+		SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
+		SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
+		SetDParam(2, p->name_1);
+		SetDParam(3, p->name_2);
+		return STR_02B6;
+	case NB_BMERGER:
+		SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
+		SetDParam(1, STR_705A_HAS_BEEN_SOLD_TO_FOR);
+		COPY_IN_DPARAM(2,ni->params, 2);
+		SetDParam(4, p->name_1);
+		SetDParam(5, p->name_2);
+		COPY_IN_DPARAM(6,ni->params + 2, 1);
+		return STR_02B6;
+	case NB_BBANKRUPT:
+		SetDParam(0, STR_705C_BANKRUPT);
+		SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
+		COPY_IN_DPARAM(2,ni->params, 2);
+		return STR_02B6;
+	case NB_BNEWCOMPANY:
+		SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
+		SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
+		SetDParam(2, p->name_1);
+		SetDParam(3, p->name_2);
+		COPY_IN_DPARAM(4,ni->params, 2);
+		return STR_02B6;
+	default:
+		NOT_REACHED();
+	}
+
+	/* useless, but avoids compiler warning this way */
+	return 0;
+}
+
+static void PlayersGenStatistics(void)
+{
+	Station *st;
+	Player *p;
+
+	FOR_ALL_STATIONS(st) {
+		_current_player = st->owner;
+		SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
+		SubtractMoneyFromPlayer(_price.station_value >> 1);
+	}
+
+	if (!HASBIT(1<<0|1<<3|1<<6|1<<9, _cur_month))
+		return;
+
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active) {
+			memmove(&p->old_economy[1], &p->old_economy[0], sizeof(p->old_economy) - sizeof(p->old_economy[0]));
+			p->old_economy[0] = p->cur_economy;
+			memset(&p->cur_economy, 0, sizeof(p->cur_economy));
+
+			if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++;
+
+			UpdateCompanyRatingAndValue(p, true);
+			PlayersCheckBankrupt(p);
+
+			if (p->block_preview != 0) p->block_preview--;
+		}
+	}
+
+	InvalidateWindow(WC_INCOME_GRAPH, 0);
+	InvalidateWindow(WC_OPERATING_PROFIT, 0);
+	InvalidateWindow(WC_DELIVERED_CARGO, 0);
+	InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
+	InvalidateWindow(WC_COMPANY_VALUE, 0);
+	InvalidateWindow(WC_COMPANY_LEAGUE, 0);
+}
+
+static void AddSingleInflation(int32 *value, uint16 *frac, int32 amt)
+{
+	int64 tmp;
+	int32 low;
+	tmp = BIGMULS(*value, amt);
+	*frac = (uint16)(low = (uint16)tmp + *frac);
+	*value += (int32)(tmp >> 16) + (low >> 16);
+}
+
+static void AddInflation(void)
+{
+	int i;
+	int32 inf = _economy.infl_amount * 54;
+
+	for (i = 0; i != NUM_PRICES; i++) {
+		AddSingleInflation((int32*)&_price + i, _price_frac + i, inf);
+	}
+
+	_economy.max_loan_unround += BIGMULUS(_economy.max_loan_unround, inf, 16);
+
+	if (_economy.max_loan + 50000 <= _economy.max_loan_unround)
+		_economy.max_loan += 50000;
+
+	inf = _economy.infl_amount_pr * 54;
+	for (i = 0; i != NUM_CARGO; i++) {
+		AddSingleInflation(
+			(int32*)_cargo_payment_rates + i,
+			_cargo_payment_rates_frac + i,
+			inf
+		);
+	}
+
+	InvalidateWindowClasses(WC_BUILD_VEHICLE);
+	InvalidateWindowClasses(WC_REPLACE_VEHICLE);
+	InvalidateWindowClasses(WC_VEHICLE_DETAILS);
+	InvalidateWindow(WC_PAYMENT_RATES, 0);
+}
+
+static void PlayersPayInterest(void)
+{
+	const Player* p;
+	int interest = _economy.interest_rate * 54;
+
+	FOR_ALL_PLAYERS(p) {
+		if (!p->is_active) continue;
+
+		_current_player = p->index;
+		SET_EXPENSES_TYPE(EXPENSES_LOAN_INT);
+
+		SubtractMoneyFromPlayer(BIGMULUS(p->current_loan, interest, 16));
+
+		SET_EXPENSES_TYPE(EXPENSES_OTHER);
+		SubtractMoneyFromPlayer(_price.station_value >> 2);
+	}
+}
+
+static void HandleEconomyFluctuations(void)
+{
+	if (_opt.diff.economy == 0) return;
+
+	if (--_economy.fluct == 0) {
+		_economy.fluct = -(int)GB(Random(), 0, 2);
+		AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
+	} else if (_economy.fluct == -12) {
+		_economy.fluct = GB(Random(), 0, 8) + 312;
+		AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
+	}
+}
+
+static byte _price_category[NUM_PRICES] = {
+	0, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 1, 1, 1, 1, 1, 1,
+	2,
+};
+
+static const int32 _price_base[NUM_PRICES] = {
+	    100, // station_value
+	    100, // build_rail
+	     95, // build_road
+	     65, // build_signals
+	    275, // build_bridge
+	    600, // build_train_depot
+	    500, // build_road_depot
+	    700, // build_ship_depot
+	    450, // build_tunnel
+	    200, // train_station_track
+	    180, // train_station_length
+	    600, // build_airport
+	    200, // build_bus_station
+	    200, // build_truck_station
+	    350, // build_dock
+	 400000, // build_railvehicle
+	   2000, // build_railwagon
+	 700000, // aircraft_base
+	  14000, // roadveh_base
+	  65000, // ship_base
+	     20, // build_trees
+	    250, // terraform
+	     20, // clear_1
+	     40, // purchase_land
+	    200, // clear_2
+	    500, // clear_3
+	     20, // remove_trees
+	    -70, // remove_rail
+	     10, // remove_signals
+	     50, // clear_bridge
+	     80, // remove_train_depot
+	     80, // remove_road_depot
+	     90, // remove_ship_depot
+	     30, // clear_tunnel
+	  10000, // clear_water
+	     50, // remove_rail_station
+	     30, // remove_airport
+	     50, // remove_bus_station
+	     50, // remove_truck_station
+	     55, // remove_dock
+	   1600, // remove_house
+	     40, // remove_road
+	   5600, // running_rail[0] railroad
+	   5200, // running_rail[1] monorail
+	   4800, // running_rail[2] maglev
+	   9600, // aircraft_running
+	   1600, // roadveh_running
+	   5600, // ship_running
+	1000000, // build_industry
+};
+
+static byte price_base_multiplier[NUM_PRICES];
+
+/**
+ * Reset changes to the price base multipliers.
+ */
+void ResetPriceBaseMultipliers(void)
+{
+	uint i;
+
+	// 8 means no multiplier.
+	for (i = 0; i < NUM_PRICES; i++)
+		price_base_multiplier[i] = 8;
+}
+
+/**
+ * Change a price base by the given factor.
+ * The price base is altered by factors of two, with an offset of 8.
+ * NewBaseCost = OldBaseCost * 2^(n-8)
+ * @param price Index of price base to change.
+ * @param factor Amount to change by.
+ */
+void SetPriceBaseMultiplier(uint price, byte factor)
+{
+	assert(price < NUM_PRICES);
+	price_base_multiplier[price] = factor;
+}
+
+void StartupEconomy(void)
+{
+	int i;
+
+	assert(sizeof(_price) == NUM_PRICES * sizeof(int32));
+
+	for (i = 0; i != NUM_PRICES; i++) {
+		int32 price = _price_base[i];
+		if (_price_category[i] != 0) {
+			uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
+			if (mod < 1) {
+				price = price * 3 >> 2;
+			} else if (mod > 1) {
+				price = price * 9 >> 3;
+			}
+		}
+		if (price_base_multiplier[i] > 8) {
+			price <<= price_base_multiplier[i] - 8;
+		} else {
+			price >>= 8 - price_base_multiplier[i];
+		}
+		((int32*)&_price)[i] = price;
+		_price_frac[i] = 0;
+	}
+
+	_economy.interest_rate = _opt.diff.initial_interest;
+	_economy.infl_amount = _opt.diff.initial_interest;
+	_economy.infl_amount_pr = max(0, _opt.diff.initial_interest - 1);
+	_economy.max_loan_unround = _economy.max_loan = _opt.diff.max_loan * 1000;
+	_economy.fluct = GB(Random(), 0, 8) + 168;
+}
+
+Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode)
+{
+	TileIndex tile;
+	TileIndex tile2;
+	Pair tp;
+
+	/* if mode is false, use the singular form */
+	SetDParam(0, _cargoc.names_s[s->cargo_type] + (mode ? 0 : 32));
+
+	if (s->age < 12) {
+		if (s->cargo_type != CT_PASSENGERS && s->cargo_type != CT_MAIL) {
+			SetDParam(1, STR_INDUSTRY);
+			SetDParam(2, s->from);
+			tile = GetIndustry(s->from)->xy;
+
+			if (s->cargo_type != CT_GOODS && s->cargo_type != CT_FOOD) {
+				SetDParam(4, STR_INDUSTRY);
+				SetDParam(5, s->to);
+				tile2 = GetIndustry(s->to)->xy;
+			} else {
+				SetDParam(4, STR_TOWN);
+				SetDParam(5, s->to);
+				tile2 = GetTown(s->to)->xy;
+			}
+		} else {
+			SetDParam(1, STR_TOWN);
+			SetDParam(2, s->from);
+			tile = GetTown(s->from)->xy;
+
+			SetDParam(4, STR_TOWN);
+			SetDParam(5, s->to);
+			tile2 = GetTown(s->to)->xy;
+		}
+	} else {
+		SetDParam(1, s->from);
+		tile = GetStation(s->from)->xy;
+
+		SetDParam(2, s->to);
+		tile2 = GetStation(s->to)->xy;
+	}
+
+	tp.a = tile;
+	tp.b = tile2;
+
+	return tp;
+}
+
+void DeleteSubsidyWithTown(TownID index)
+{
+	Subsidy *s;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age < 12 &&
+				(((s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL) && (index == s->from || index == s->to)) ||
+				((s->cargo_type == CT_GOODS || s->cargo_type == CT_FOOD) && index == s->to))) {
+			s->cargo_type = CT_INVALID;
+		}
+	}
+}
+
+void DeleteSubsidyWithIndustry(IndustryID index)
+{
+	Subsidy *s;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age < 12 &&
+				s->cargo_type != CT_PASSENGERS && s->cargo_type != CT_MAIL &&
+				(index == s->from || (s->cargo_type != CT_GOODS && s->cargo_type != CT_FOOD && index == s->to))) {
+			s->cargo_type = CT_INVALID;
+		}
+	}
+}
+
+void DeleteSubsidyWithStation(StationID index)
+{
+	Subsidy *s;
+	bool dirty = false;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age >= 12 &&
+				(s->from == index || s->to == index)) {
+			s->cargo_type = CT_INVALID;
+			dirty = true;
+		}
+	}
+
+	if (dirty)
+		InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+}
+
+typedef struct FoundRoute {
+	uint distance;
+	CargoID cargo;
+	void *from;
+	void *to;
+} FoundRoute;
+
+static void FindSubsidyPassengerRoute(FoundRoute *fr)
+{
+	Town *from,*to;
+
+	fr->distance = (uint)-1;
+
+	fr->from = from = GetRandomTown();
+	if (from == NULL || from->population < 400) return;
+
+	fr->to = to = GetRandomTown();
+	if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
+		return;
+
+	fr->distance = DistanceManhattan(from->xy, to->xy);
+}
+
+static void FindSubsidyCargoRoute(FoundRoute *fr)
+{
+	Industry *i;
+	int trans, total;
+	CargoID cargo;
+
+	fr->distance = (uint)-1;
+
+	fr->from = i = GetRandomIndustry();
+	if (i == NULL) return;
+
+	// Randomize cargo type
+	if (Random()&1 && i->produced_cargo[1] != CT_INVALID) {
+		cargo = i->produced_cargo[1];
+		trans = i->pct_transported[1];
+		total = i->total_production[1];
+	} else {
+		cargo = i->produced_cargo[0];
+		trans = i->pct_transported[0];
+		total = i->total_production[0];
+	}
+
+	// Quit if no production in this industry
+	//  or if the cargo type is passengers
+	//  or if the pct transported is already large enough
+	if (total == 0 || trans > 42 || cargo == CT_INVALID || cargo == CT_PASSENGERS)
+		return;
+
+	fr->cargo = cargo;
+
+	if (cargo == CT_GOODS || cargo == CT_FOOD) {
+		// The destination is a town
+		Town *t = GetRandomTown();
+
+		// Only want big towns
+		if (t == NULL || t->population < 900) return;
+
+		fr->distance = DistanceManhattan(i->xy, t->xy);
+		fr->to = t;
+	} else {
+		// The destination is an industry
+		Industry *i2 = GetRandomIndustry();
+
+		// The industry must accept the cargo
+		if (i == i2 || i == NULL ||
+				(cargo != i2->accepts_cargo[0] &&
+				cargo != i2->accepts_cargo[1] &&
+				cargo != i2->accepts_cargo[2]))
+			return;
+		fr->distance = DistanceManhattan(i->xy, i2->xy);
+		fr->to = i2;
+	}
+}
+
+static bool CheckSubsidyDuplicate(Subsidy *s)
+{
+	const Subsidy* ss;
+
+	for (ss = _subsidies; ss != endof(_subsidies); ss++) {
+		if (s != ss &&
+				ss->from == s->from &&
+				ss->to == s->to &&
+				ss->cargo_type == s->cargo_type) {
+			s->cargo_type = CT_INVALID;
+			return true;
+		}
+	}
+	return false;
+}
+
+
+static void SubsidyMonthlyHandler(void)
+{
+	Subsidy *s;
+	Pair pair;
+	Station *st;
+	uint n;
+	FoundRoute fr;
+	bool modified = false;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type == CT_INVALID) continue;
+
+		if (s->age == 12-1) {
+			pair = SetupSubsidyDecodeParam(s, 1);
+			AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
+			s->cargo_type = CT_INVALID;
+			modified = true;
+		} else if (s->age == 2*12-1) {
+			st = GetStation(s->to);
+			if (st->owner == _local_player) {
+				pair = SetupSubsidyDecodeParam(s, 1);
+				AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
+			}
+			s->cargo_type = CT_INVALID;
+			modified = true;
+		} else {
+			s->age++;
+		}
+	}
+
+	// 25% chance to go on
+	if (CHANCE16(1,4)) {
+		// Find a free slot
+		s = _subsidies;
+		while (s->cargo_type != CT_INVALID) {
+			if (++s == endof(_subsidies))
+				goto no_add;
+		}
+
+		n = 1000;
+		do {
+			FindSubsidyPassengerRoute(&fr);
+			if (fr.distance <= 70) {
+				s->cargo_type = CT_PASSENGERS;
+				s->from = ((Town*)fr.from)->index;
+				s->to = ((Town*)fr.to)->index;
+				goto add_subsidy;
+			}
+			FindSubsidyCargoRoute(&fr);
+			if (fr.distance <= 70) {
+				s->cargo_type = fr.cargo;
+				s->from = ((Industry*)fr.from)->index;
+				s->to = (fr.cargo == CT_GOODS || fr.cargo == CT_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
+	add_subsidy:
+				if (!CheckSubsidyDuplicate(s)) {
+					s->age = 0;
+					pair = SetupSubsidyDecodeParam(s, 0);
+					AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
+					modified = true;
+					break;
+				}
+			}
+		} while (n--);
+	}
+no_add:;
+	if (modified)
+		InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+}
+
+static const SaveLoad _subsidies_desc[] = {
+	    SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
+	    SLE_VAR(Subsidy, age,        SLE_UINT8),
+	SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+	SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
+	SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+	SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
+	SLE_END()
+};
+
+static void Save_SUBS(void)
+{
+	int i;
+	Subsidy *s;
+
+	for (i = 0; i != lengthof(_subsidies); i++) {
+		s = &_subsidies[i];
+		if (s->cargo_type != CT_INVALID) {
+			SlSetArrayIndex(i);
+			SlObject(s, _subsidies_desc);
+		}
+	}
+}
+
+static void Load_SUBS(void)
+{
+	int index;
+	while ((index = SlIterateArray()) != -1)
+		SlObject(&_subsidies[index], _subsidies_desc);
+}
+
+int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
+{
+	CargoID cargo = cargo_type;
+	byte f;
+
+	/* zero the distance if it's the bank and very short transport. */
+	if (_opt.landscape == LT_NORMAL && cargo == CT_VALUABLES && dist < 10)
+		dist = 0;
+
+	f = 255;
+	if (transit_days > _cargoc.transit_days_1[cargo]) {
+		transit_days -= _cargoc.transit_days_1[cargo];
+		f -= transit_days;
+
+		if (transit_days > _cargoc.transit_days_2[cargo]) {
+			transit_days -= _cargoc.transit_days_2[cargo];
+
+			if (f < transit_days) {
+				f = 0;
+			} else {
+				f -= transit_days;
+			}
+		}
+	}
+	if (f < 31) f = 31;
+
+	return BIGMULSS(dist * f * num_pieces, _cargo_payment_rates[cargo], 21);
+}
+
+static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
+{
+	Industry* best = NULL;
+	Industry* ind;
+	uint u;
+
+	// Check if there's an industry close to the station that accepts the cargo
+	// XXX - Think of something better to
+	//       1) Only deliver to industries which are withing the catchment radius
+	//       2) Distribute between industries if more then one is present
+	u = (_patches.station_spread + 8) * 2;
+	FOR_ALL_INDUSTRIES(ind) {
+		uint t;
+
+		if (( cargo_type == ind->accepts_cargo[0] ||
+					cargo_type == ind->accepts_cargo[1] ||
+					cargo_type == ind->accepts_cargo[2]
+				) &&
+				ind->produced_cargo[0] != CT_INVALID &&
+				ind->produced_cargo[0] != cargo_type &&
+				(t = DistanceManhattan(ind->xy, xy)) < u) {
+			u = t;
+			best = ind;
+		}
+	}
+
+	/* Found one? */
+	if (best != NULL) {
+		best->was_cargo_delivered = true;
+		best->cargo_waiting[0] = min(best->cargo_waiting[0] + num_pieces, 0xFFFF);
+	}
+}
+
+static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
+{
+	Subsidy *s;
+	TileIndex xy;
+	Pair pair;
+	Player *p;
+
+	// check if there is an already existing subsidy that applies to us
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type == cargo_type &&
+				s->age >= 12 &&
+				s->from == from->index &&
+				s->to == to->index) {
+			return true;
+		}
+	}
+
+	/* check if there's a new subsidy that applies.. */
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type == cargo_type && s->age < 12) {
+			/* Check distance from source */
+			if (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL) {
+				xy = GetTown(s->from)->xy;
+			} else {
+				xy = (GetIndustry(s->from))->xy;
+			}
+			if (DistanceMax(xy, from->xy) > 9) continue;
+
+			/* Check distance from dest */
+			switch (cargo_type) {
+				case CT_PASSENGERS:
+				case CT_MAIL:
+				case CT_GOODS:
+				case CT_FOOD:
+					xy = GetTown(s->to)->xy;
+					break;
+
+				default:
+					xy = GetIndustry(s->to)->xy;
+					break;
+			}
+			if (DistanceMax(xy, to->xy) > 9) continue;
+
+			/* Found a subsidy, change the values to indicate that it's in use */
+			s->age = 12;
+			s->from = from->index;
+			s->to = to->index;
+
+			/* Add a news item */
+			pair = SetupSubsidyDecodeParam(s, 0);
+			InjectDParam(2);
+
+			p = GetPlayer(_current_player);
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			AddNewsItem(
+				STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
+				NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
+				pair.a, pair.b
+			);
+
+			InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+			return true;
+		}
+	}
+	return false;
+}
+
+static int32 DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, byte days_in_transit)
+{
+	bool subsidised;
+	Station *s_from, *s_to;
+	int32 profit;
+
+	assert(num_pieces > 0);
+
+	// Update player statistics
+	{
+		Player *p = GetPlayer(_current_player);
+		p->cur_economy.delivered_cargo += num_pieces;
+		SETBIT(p->cargo_types, cargo_type);
+	}
+
+	// Get station pointers.
+	s_from = GetStation(source);
+	s_to = GetStation(dest);
+
+	// Check if a subsidy applies.
+	subsidised = CheckSubsidised(s_from, s_to, cargo_type);
+
+	// Increase town's counter for some special goods types
+	if (cargo_type == CT_FOOD) s_to->town->new_act_food += num_pieces;
+	if (cargo_type == CT_WATER)  s_to->town->new_act_water += num_pieces;
+
+	// Give the goods to the industry.
+	DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
+
+	// Determine profit
+	profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(s_from->xy, s_to->xy), days_in_transit, cargo_type);
+
+	// Modify profit if a subsidy is in effect
+	if (subsidised) {
+		switch (_opt.diff.subsidy_multiplier) {
+			case 0:  profit += profit >> 1; break;
+			case 1:  profit *= 2; break;
+			case 2:  profit *= 3; break;
+			default: profit *= 4; break;
+		}
+	}
+
+	return profit;
+}
+
+/*
+ * Returns true if Vehicle v should wait loading because other vehicle is
+ * already loading the same cargo type
+ * v = vehicle to load, u = GetFirstInChain(v)
+ */
+static bool LoadWait(const Vehicle* v, const Vehicle* u)
+{
+	const Vehicle *w;
+	const Vehicle *x;
+	bool has_any_cargo = false;
+
+	if (!(u->current_order.flags & OF_FULL_LOAD)) return false;
+
+	for (w = u; w != NULL; w = w->next) {
+		if (w->cargo_count != 0) {
+			if (v->cargo_type == w->cargo_type &&
+					u->last_station_visited == w->cargo_source) {
+				return false;
+			}
+			has_any_cargo = true;
+		}
+	}
+
+	FOR_ALL_VEHICLES(x) {
+		if ((x->type != VEH_Train || IsFrontEngine(x)) && // for all locs
+				u->last_station_visited == x->last_station_visited && // at the same station
+				!(x->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed
+				x->current_order.type == OT_LOADING && // loading
+				u != x) { // not itself
+			bool other_has_any_cargo = false;
+			bool has_space_for_same_type = false;
+			bool other_has_same_type = false;
+
+			for (w = x; w != NULL; w = w->next) {
+				if (w->cargo_count < w->cargo_cap && v->cargo_type == w->cargo_type) {
+					has_space_for_same_type = true;
+				}
+
+				if (w->cargo_count != 0) {
+					if (v->cargo_type == w->cargo_type &&
+							u->last_station_visited == w->cargo_source) {
+						other_has_same_type = true;
+					}
+					other_has_any_cargo = true;
+				}
+			}
+
+			if (has_space_for_same_type) {
+				if (other_has_same_type) return true;
+				if (other_has_any_cargo && !has_any_cargo) return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+int LoadUnloadVehicle(Vehicle *v, bool just_arrived)
+{
+	int profit = 0;
+	int v_profit = 0; //virtual profit for feeder systems
+	int v_profit_total = 0;
+	int unloading_time = 20;
+	Vehicle *u = v;
+	int result = 0;
+	StationID last_visited;
+	Station *st;
+	int t;
+	uint count, cap;
+	PlayerID old_player;
+	bool completely_empty = true;
+	byte load_amount;
+	bool anything_loaded = false;
+
+	assert(v->current_order.type == OT_LOADING);
+
+	v->cur_speed = 0;
+
+	/* Loading can only have finished when all the cargo has been unloaded, and
+	 * there is nothing left to load. It's easier to clear this if the
+	 * conditions haven't been met than attempting to check them all before
+	 * enabling though. */
+	SETBIT(v->load_status, LS_LOADING_FINISHED);
+
+	old_player = _current_player;
+	_current_player = v->owner;
+
+	last_visited = v->last_station_visited;
+	st = GetStation(last_visited);
+
+	for (; v != NULL; v = v->next) {
+		GoodsEntry* ge;
+		load_amount = EngInfo(v->engine_type)->load_amount;
+		if (_patches.gradual_loading) {
+			uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
+			if (cb_load_amount != CALLBACK_FAILED) load_amount = cb_load_amount & 0xFF;
+		}
+
+		if (v->cargo_cap == 0) continue;
+
+		/* If the vehicle has just arrived, set it to unload. */
+		if (just_arrived) SETBIT(v->load_status, LS_CARGO_UNLOADING);
+
+		ge = &st->goods[v->cargo_type];
+		count = GB(ge->waiting_acceptance, 0, 12);
+
+		/* unload? */
+		if (v->cargo_count != 0 && HASBIT(v->load_status, LS_CARGO_UNLOADING)) {
+			uint16 amount_unloaded = _patches.gradual_loading ? min(v->cargo_count, load_amount) : v->cargo_count;
+
+			CLRBIT(u->load_status, LS_LOADING_FINISHED);
+
+			if (v->cargo_source != last_visited && ge->waiting_acceptance & 0x8000 && !(u->current_order.flags & OF_TRANSFER)) {
+				// deliver goods to the station
+				st->time_since_unload = 0;
+
+				unloading_time += v->cargo_count; /* TTDBUG: bug in original TTD */
+				if (just_arrived && !HASBIT(v->load_status, LS_CARGO_PAID_FOR)) {
+					profit += DeliverGoods(v->cargo_count, v->cargo_type, v->cargo_source, last_visited, v->cargo_days);
+					SETBIT(v->load_status, LS_CARGO_PAID_FOR);
+				}
+				result |= 1;
+				v->cargo_count -= amount_unloaded;
+				if (_patches.gradual_loading) continue;
+			} else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
+				/* unload goods and let it wait at the station */
+				st->time_since_unload = 0;
+				if (just_arrived && (u->current_order.flags & OF_TRANSFER) && !HASBIT(v->load_status, LS_CARGO_PAID_FOR)) {
+					v_profit = GetTransportedGoodsIncome(
+						v->cargo_count,
+						DistanceManhattan(GetStation(v->cargo_source)->xy, GetStation(last_visited)->xy),
+						v->cargo_days,
+						v->cargo_type) * 3 / 2;
+
+					v_profit_total += v_profit;
+					SETBIT(v->load_status, LS_CARGO_PAID_FOR);
+				}
+
+				unloading_time += v->cargo_count;
+				t = GB(ge->waiting_acceptance, 0, 12);
+				if (t == 0) {
+					// No goods waiting at station
+					ge->enroute_time = v->cargo_days;
+					ge->enroute_from = v->cargo_source;
+				} else {
+					// Goods already waiting at station. Set counters to the worst value.
+					if (v->cargo_days >= ge->enroute_time)
+						ge->enroute_time = v->cargo_days;
+					if (last_visited != ge->enroute_from)
+						ge->enroute_from = v->cargo_source;
+				}
+				// Update amount of waiting cargo
+				SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + t, 0xFFF));
+
+				if (u->current_order.flags & OF_TRANSFER) {
+					ge->feeder_profit += v_profit;
+					u->profit_this_year += v_profit;
+				}
+				result |= 2;
+				v->cargo_count -= amount_unloaded;
+				if (_patches.gradual_loading) continue;
+			}
+
+			if (v->cargo_count != 0) completely_empty = false;
+		}
+
+		/* The vehicle must have been unloaded because it is either empty, or
+		 * the UNLOADING bit is already clear in v->load_status. */
+		CLRBIT(v->load_status, LS_CARGO_UNLOADING);
+		CLRBIT(v->load_status, LS_CARGO_PAID_FOR);
+
+		/* don't pick up goods that we unloaded */
+		if (u->current_order.flags & OF_UNLOAD) continue;
+
+		/* update stats */
+		ge->days_since_pickup = 0;
+		switch (u->type) {
+			case VEH_Train: t = u->u.rail.cached_max_speed; break;
+			case VEH_Road:  t = u->max_speed / 2;           break;
+			default:        t = u->max_speed;               break;
+		}
+
+		// if last speed is 0, we treat that as if no vehicle has ever visited the station.
+		ge->last_speed = min(t, 255);
+		ge->last_age = _cur_year - v->build_year;
+
+		// If there's goods waiting at the station, and the vehicle
+		//  has capacity for it, load it on the vehicle.
+		if (count != 0 &&
+				(cap = v->cargo_cap - v->cargo_count) != 0) {
+			int cargoshare;
+			int feeder_profit_share;
+
+			if (v->cargo_count == 0)
+				TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
+
+			/* Skip loading this vehicle if another train/vehicle is already handling
+			 * the same cargo type at this station */
+			if (_patches.improved_load && (u->current_order.flags & OF_FULL_LOAD) && LoadWait(v,u)) continue;
+
+			/* TODO: Regarding this, when we do gradual loading, we
+			 * should first unload all vehicles and then start
+			 * loading them. Since this will cause
+			 * VEHICLE_TRIGGER_EMPTY to be called at the time when
+			 * the whole vehicle chain is really totally empty, the
+			 * @completely_empty assignment can then be safely
+			 * removed; that's how TTDPatch behaves too. --pasky */
+			completely_empty = false;
+			anything_loaded = true;
+
+			if (cap > count) cap = count;
+			if (_patches.gradual_loading) cap = min(cap, load_amount);
+			if (cap < count) CLRBIT(u->load_status, LS_LOADING_FINISHED);
+			cargoshare = cap * 10000 / ge->waiting_acceptance;
+			feeder_profit_share = ge->feeder_profit * cargoshare / 10000;
+			v->cargo_count += cap;
+			ge->waiting_acceptance -= cap;
+			u->profit_this_year -= feeder_profit_share;
+			ge->feeder_profit -= feeder_profit_share;
+			unloading_time += cap;
+			st->time_since_load = 0;
+
+			// And record the source of the cargo, and the days in travel.
+			v->cargo_source = ge->enroute_from;
+			v->cargo_days = ge->enroute_time;
+			result |= 2;
+			st->last_vehicle_type = v->type;
+		}
+	}
+
+	v = u;
+
+	if (_patches.gradual_loading) {
+		/* The time it takes to load one 'slice' of cargo or passengers depends
+		 * on the vehicle type - the values here are those found in TTDPatch */
+		uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
+
+		unloading_time = gradual_loading_wait_time[v->type - VEH_Train];
+		if (HASBIT(v->load_status, LS_LOADING_FINISHED)) {
+			if (anything_loaded) {
+				unloading_time += 20;
+			} else {
+				unloading_time = 20;
+			}
+		}
+	}
+
+	if (v_profit_total > 0) {
+		ShowFeederIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, v_profit_total);
+	}
+
+	if (v->type == VEH_Train) {
+		// Each platform tile is worth 2 rail vehicles.
+		int overhang = v->u.rail.cached_total_length - GetStationPlatforms(st, v->tile) * TILE_SIZE;
+		if (overhang > 0) {
+			unloading_time <<= 1;
+			unloading_time += (overhang * unloading_time) / 8;
+		}
+	}
+
+	v->load_unload_time_rem = unloading_time;
+
+	if (completely_empty) {
+		TriggerVehicle(v, VEHICLE_TRIGGER_EMPTY);
+	}
+
+	if (result != 0) {
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		MarkStationTilesDirty(st);
+
+		if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited);
+
+		if (profit != 0) {
+			v->profit_this_year += profit;
+			SubtractMoneyFromPlayer(-profit);
+
+			if (IsLocalPlayer() && !PlayVehicleSound(v, VSE_LOAD_UNLOAD)) {
+				SndPlayVehicleFx(SND_14_CASHTILL, v);
+			}
+
+			ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, -profit);
+		}
+	}
+
+	_current_player = old_player;
+	return result;
+}
+
+void PlayersMonthlyLoop(void)
+{
+	PlayersGenStatistics();
+	if (_patches.inflation && _cur_year < MAX_YEAR)
+		AddInflation();
+	PlayersPayInterest();
+	// Reset the _current_player flag
+	_current_player = OWNER_NONE;
+	HandleEconomyFluctuations();
+	SubsidyMonthlyHandler();
+}
+
+static void DoAcquireCompany(Player *p)
+{
+	Player *owner;
+	int i,pi;
+	int64 value;
+
+	SetDParam(0, p->name_1);
+	SetDParam(1, p->name_2);
+	SetDParam(2, p->bankrupt_value);
+	AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
+
+	// original code does this a little bit differently
+	pi = p->index;
+	ChangeOwnershipOfPlayerItems(pi, _current_player);
+
+	if (p->bankrupt_value == 0) {
+		owner = GetPlayer(_current_player);
+		owner->current_loan += p->current_loan;
+	}
+
+	value = CalculateCompanyValue(p) >> 2;
+	for (i = 0; i != 4; i++) {
+		if (p->share_owners[i] != PLAYER_SPECTATOR) {
+			owner = GetPlayer(p->share_owners[i]);
+			owner->money64 += value;
+			owner->yearly_expenses[0][EXPENSES_OTHER] += value;
+			UpdatePlayerMoney32(owner);
+		}
+	}
+
+	p->is_active = false;
+
+	DeletePlayerWindows(pi);
+	RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
+}
+
+extern int GetAmountOwnedBy(Player *p, byte owner);
+
+/** Acquire shares in an opposing company.
+ * @param tile unused
+ * @param p1 player to buy the shares from
+ * @param p2 unused
+ */
+int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+	int64 cost;
+
+	/* Check if buying shares is allowed (protection against modified clients */
+	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+	p = GetPlayer(p1);
+
+	/* Protect new companies from hostile takeovers */
+	if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED);
+
+	/* Those lines are here for network-protection (clients can be slow) */
+	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return 0;
+
+	/* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
+	if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return 0;
+
+	cost = CalculateCompanyValue(p) >> 2;
+	if (flags & DC_EXEC) {
+		PlayerID* b = p->share_owners;
+		int i;
+
+		while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
+		*b = _current_player;
+
+		for (i = 0; p->share_owners[i] == _current_player;) {
+			if (++i == 4) {
+				p->bankrupt_value = 0;
+				DoAcquireCompany(p);
+				break;
+			}
+		}
+		InvalidateWindow(WC_COMPANY, p1);
+	}
+	return cost;
+}
+
+/** Sell shares in an opposing company.
+ * @param tile unused
+ * @param p1 player to sell the shares from
+ * @param p2 unused
+ */
+int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+	int64 cost;
+
+	/* Check if buying shares is allowed (protection against modified clients */
+	if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+	p = GetPlayer(p1);
+
+	/* Those lines are here for network-protection (clients can be slow) */
+	if (GetAmountOwnedBy(p, _current_player) == 0) return 0;
+
+	/* adjust it a little to make it less profitable to sell and buy */
+	cost = CalculateCompanyValue(p) >> 2;
+	cost = -(cost - (cost >> 7));
+
+	if (flags & DC_EXEC) {
+		PlayerID* b = p->share_owners;
+		while (*b != _current_player) b++; /* share owners is guaranteed to contain player */
+		*b = PLAYER_SPECTATOR;
+		InvalidateWindow(WC_COMPANY, p1);
+	}
+	return cost;
+}
+
+/** Buy up another company.
+ * When a competing company is gone bankrupt you get the chance to purchase
+ * that company.
+ * @todo currently this only works for AI players
+ * @param tile unused
+ * @param p1 player/company to buy up
+ * @param p2 unused
+ */
+int32 CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+
+	/* Disable takeovers in multiplayer games */
+	if (!IsValidPlayer((PlayerID)p1) || _networking) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+	p = GetPlayer(p1);
+
+	if (!p->is_ai) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		DoAcquireCompany(p);
+	}
+	return p->bankrupt_value;
+}
+
+// Prices
+static void SaveLoad_PRIC(void)
+{
+	SlArray(&_price,      NUM_PRICES, SLE_INT32);
+	SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
+}
+
+// Cargo payment rates
+static void SaveLoad_CAPR(void)
+{
+	SlArray(&_cargo_payment_rates,      NUM_CARGO, SLE_INT32);
+	SlArray(&_cargo_payment_rates_frac, NUM_CARGO, SLE_UINT16);
+}
+
+static const SaveLoad _economy_desc[] = {
+	SLE_VAR(Economy, max_loan,         SLE_INT32),
+	SLE_VAR(Economy, max_loan_unround, SLE_INT32),
+	SLE_VAR(Economy, fluct,            SLE_FILE_I16 | SLE_VAR_I32),
+	SLE_VAR(Economy, interest_rate,    SLE_UINT8),
+	SLE_VAR(Economy, infl_amount,      SLE_UINT8),
+	SLE_VAR(Economy, infl_amount_pr,   SLE_UINT8),
+	SLE_END()
+};
+
+// Economy variables
+static void SaveLoad_ECMY(void)
+{
+	SlObject(&_economy, _economy_desc);
+}
+
+const ChunkHandler _economy_chunk_handlers[] = {
+	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
+	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
+	{ 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
+	{ 'ECMY', SaveLoad_ECMY, SaveLoad_ECMY, CH_RIFF | CH_LAST},
+};
deleted file mode 100644
--- a/src/elrail.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/* $Id$ */
-/** @file elrail.c
- * This file deals with displaying wires and pylons for electric railways.
- * <h2>Basics</h2>
- *
- * <h3>Tile Types</h3>
- *
- * We have two different types of tiles in the drawing code:
- * Normal Railway Tiles (NRTs) which can have more than one track on it, and
- * Special Railways tiles (SRTs) which have only one track (like crossings, depots
- * stations, etc).
- *
- * <h3>Location Categories</h3>
- *
- * All tiles are categorized into three location groups (TLG):
- * Group 0: Tiles with both an even X coordinate and an even Y coordinate
- * Group 1: Tiles with an even X and an odd Y coordinate
- * Group 2: Tiles with an odd X and an even Y coordinate
- * Group 3: Tiles with both an odd X and Y coordnate.
- *
- * <h3>Pylon Points</h3>
- * <h4>Control Points</h4>
- * A Pylon Control Point (PCP) is a position where a wire (or rather two)
- * is mounted onto a pylon.
- * Each NRT does contain 4 PCPs which are bitmapped to a byte
- * variable and are represented by the DiagDirection enum
- *
- * Each track ends on two PCPs and thus requires one pylon on each end. However,
- * there is one exception: Straight-and-level tracks only have one pylon every
- * other tile.
- *
- * Now on each edge there are two PCPs: One from each adjacent tile. Both PCPs
- * are merged using an OR operation (i. e. if one tile needs a PCP at the postion
- * in question, both tiles get it).
- *
- * <h4>Position Points</h4>
- * A Pylon Position Point (PPP) is a position where a pylon is located on the
- * ground.  Each PCP owns 8 in (45 degree steps) PPPs that are located around
- * it. PPPs are represented using the Direction enum. Each track bit has PPPs
- * that are impossible (because the pylon would be situated on the track) and
- * some that are preferred (because the pylon would be rectangular to the track).
- *
- * <img src="../../elrail_tile.png">
- * <img src="../../elrail_track.png">
- *
- */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "station_map.h"
-#include "tile.h"
-#include "viewport.h"
-#include "functions.h" /* We should REALLY get rid of this goddamn file, as it is butt-ugly */
-#include "variables.h" /* ... same here */
-#include "rail.h"
-#include "debug.h"
-#include "tunnel_map.h"
-#include "road_map.h"
-#include "bridge_map.h"
-#include "bridge.h"
-#include "rail_map.h"
-#include "table/sprites.h"
-#include "table/elrail_data.h"
-#include "vehicle.h"
-#include "train.h"
-#include "gui.h"
-
-static inline TLG GetTLG(TileIndex t)
-{
-	return (HASBIT(TileX(t), 0) << 1) + HASBIT(TileY(t), 0);
-}
-
-/** Finds which Rail Bits are present on a given tile. For bridge tiles,
- * returns track bits under the bridge
- */
-static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
-{
-	switch (GetTileType(t)) {
-		case MP_RAILWAY:
-			if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
-			switch (GetRailTileType(t)) {
-				case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS:
-					return GetTrackBits(t);
-				case RAIL_TILE_DEPOT_WAYPOINT:
-					if (GetRailTileSubtype(t) == RAIL_SUBTYPE_WAYPOINT) return GetRailWaypointBits(t);
-				default:
-					return 0;
-			}
-			break;
-
-		case MP_TUNNELBRIDGE:
-			if (IsTunnel(t)) {
-				if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
-				if (override != NULL) *override = 1 << GetTunnelDirection(t);
-				return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(t)));
-			} else {
-				if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
-				if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) {
-					*override = 1 << GetBridgeRampDirection(t);
-				}
-				return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(t)));
-			}
-
-		case MP_STREET:
-			if (GetRoadTileType(t) != ROAD_TILE_CROSSING) return 0;
-			if (GetRailTypeCrossing(t) != RAILTYPE_ELECTRIC) return 0;
-			return GetCrossingRailBits(t);
-
-		case MP_STATION:
-			if (!IsRailwayStation(t)) return 0;
-			if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
-			if (!IsStationTileElectrifiable(t)) return 0;
-			return TrackToTrackBits(GetRailStationTrack(t));
-
-		default:
-			return 0;
-	}
-}
-
-/** Corrects the tileh for certain tile types. Returns an effective tileh for the track on the tile.
- * @param tile The tile to analyse
- * @param *tileh the tileh
- */
-static void AdjustTileh(TileIndex tile, Slope *tileh)
-{
-	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		if (IsTunnel(tile)) {
-			*tileh = SLOPE_FLAT;
-		} else {
-			if (*tileh != SLOPE_FLAT) {
-				*tileh = SLOPE_FLAT;
-			} else {
-				switch (GetBridgeRampDirection(tile)) {
-					case DIAGDIR_NE: *tileh = SLOPE_NE; break;
-					case DIAGDIR_SE: *tileh = SLOPE_SE; break;
-					case DIAGDIR_SW: *tileh = SLOPE_SW; break;
-					case DIAGDIR_NW: *tileh = SLOPE_NW; break;
-					default: NOT_REACHED();
-				}
-			}
-		}
-	}
-}
-
-/** Draws wires and, if required, pylons on a given tile
- * @param ti The Tileinfo to draw the tile for
- */
-static void DrawCatenaryRailway(const TileInfo *ti)
-{
-	/* Pylons are placed on a tile edge, so we need to take into account
-	 * the track configuration of 2 adjacent tiles. trackconfig[0] stores the
-	 * current tile (home tile) while [1] holds the neighbour */
-	TrackBits trackconfig[TS_END];
-	bool isflat[TS_END];
-	/* Note that ti->tileh has already been adjusted for Foundations */
-	Slope tileh[TS_END] = { ti->tileh, SLOPE_FLAT };
-
-	TLG tlg = GetTLG(ti->tile);
-	byte PCPstatus = 0;
-	byte OverridePCP = 0;
-	byte PPPpreferred[DIAGDIR_END];
-	byte PPPallowed[DIAGDIR_END];
-	DiagDirection i;
-	Track t;
-
-	/* Find which rail bits are present, and select the override points.
-	 * We don't draw a pylon:
-	 * 1) INSIDE a tunnel (we wouldn't see it anyway)
-	 * 2) on the "far" end of a bridge head (the one that connects to bridge middle),
-	 *    because that one is drawn on the bridge. Exception is for length 0 bridges
-	 *    which have no middle tiles */
-	trackconfig[TS_HOME] = GetRailTrackBitsUniversal(ti->tile, &OverridePCP);
-	/* If a track bit is present that is not in the main direction, the track is level */
-	isflat[TS_HOME] = trackconfig[TS_HOME] & (TRACK_BIT_HORZ | TRACK_BIT_VERT);
-
-	AdjustTileh(ti->tile, &tileh[TS_HOME]);
-
-	for (i = DIAGDIR_NE; i < DIAGDIR_END; i++) {
-		TileIndex neighbour = ti->tile + TileOffsByDiagDir(i);
-		uint foundation = 0;
-		int k;
-
-		/* Here's one of the main headaches. GetTileSlope does not correct for possibly
-		 * existing foundataions, so we do have to do that manually later on.*/
-		tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour, NULL);
-		trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL);
-		if (IsTunnelTile(neighbour) && i != GetTunnelDirection(neighbour)) trackconfig[TS_NEIGHBOUR] = 0;
-		isflat[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] & (TRACK_BIT_HORZ | TRACK_BIT_VERT);
-
-		PPPpreferred[i] = 0xFF; /* We start with preferring everything (end-of-line in any direction) */
-		PPPallowed[i] = AllowedPPPonPCP[i];
-
-		/* We cycle through all the existing tracks at a PCP and see what
-		 * PPPs we want to have, or may not have at all */
-		for (k = 0; k < NUM_TRACKS_AT_PCP; k++) {
-			/* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */
-			if (TrackSourceTile[i][k] == TS_NEIGHBOUR &&
-			    IsBridgeTile(neighbour) &&
-			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)) {
-				continue;
-			}
-
-			/* We check whether the track in question (k) is present in the tile
-			 * (TrackSourceTile) */
-			if (HASBIT(trackconfig[TrackSourceTile[i][k]], TracksAtPCP[i][k])) {
-				/* track found, if track is in the neighbour tile, adjust the number
-				 * of the PCP for preferred/allowed determination*/
-				DiagDirection PCPpos = (TrackSourceTile[i][k] == TS_HOME) ? i : ReverseDiagDir(i);
-				SETBIT(PCPstatus, i); /* This PCP is in use */
-
-				PPPpreferred[i] &= PreferredPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
-				PPPallowed[i] &= ~DisallowedPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
-			}
-		}
-
-		/* Deactivate all PPPs if PCP is not used */
-		PPPpreferred[i] *= HASBIT(PCPstatus, i);
-		PPPallowed[i] *= HASBIT(PCPstatus, i);
-
-		/* A station is always "flat", so adjust the tileh accordingly */
-		if (IsTileType(neighbour, MP_STATION)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
-
-		/* Read the foundataions if they are present, and adjust the tileh */
-		if (IsTileType(neighbour, MP_RAILWAY) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
-		if (IsBridgeTile(neighbour)) {
-			foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour)));
-		}
-
-		if (foundation != 0) {
-			if (foundation < 15) {
-				tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
-			} else {
-				tileh[TS_NEIGHBOUR] = _inclined_tileh[foundation - 15];
-			}
-		}
-
-		AdjustTileh(neighbour, &tileh[TS_NEIGHBOUR]);
-
-		/* If we have a straight (and level) track, we want a pylon only every 2 tiles
-		 * Delete the PCP if this is the case. */
-		/* Level means that the slope is the same, or the track is flat */
-		if (tileh[TS_HOME] == tileh[TS_NEIGHBOUR] || (isflat[TS_HOME] && isflat[TS_NEIGHBOUR])) {
-			for (k = 0; k < NUM_IGNORE_GROUPS; k++)
-				if (PPPpreferred[i] == IgnoredPCP[k][tlg][i]) CLRBIT(PCPstatus, i);
-		}
-
-		/* Now decide where we draw our pylons. First try the preferred PPPs, but they may not exist.
-		 * In that case, we try the any of the allowed ones. if they don't exist either, don't draw
-		 * anything. Note that the preferred PPPs still contain the end-of-line markers.
-		 * Remove those (simply by ANDing with allowed, since these markers are never allowed) */
-		if ((PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i];
-
-		if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
-			Track bridgetrack = GetBridgeAxis(ti->tile) == AXIS_X ? TRACK_X : TRACK_Y;
-			uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
-
-			if ((height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) &&
-			(i == PCPpositions[bridgetrack][0] || i == PCPpositions[bridgetrack][1])) SETBIT(OverridePCP, i);
-		}
-
-		if (PPPallowed[i] != 0 && HASBIT(PCPstatus, i) && !HASBIT(OverridePCP, i)) {
-			for (k = 0; k < DIR_END; k++) {
-				byte temp = PPPorder[i][GetTLG(ti->tile)][k];
-
-				if (HASBIT(PPPallowed[i], temp)) {
-					uint x  = ti->x + x_pcp_offsets[i] + x_ppp_offsets[temp];
-					uint y  = ti->y + y_pcp_offsets[i] + y_ppp_offsets[temp];
-
-					/* Don't build the pylon if it would be outside the tile */
-					if (!HASBIT(OwnedPPPonPCP[i], temp)) {
-						/* We have a neighour that will draw it, bail out */
-						if (trackconfig[TS_NEIGHBOUR] != 0) break;
-						continue; /* No neighbour, go looking for a better position */
-					}
-
-					AddSortableSpriteToDraw(pylons_normal[temp], x, y, 1, 1, 10,
-							GetSlopeZ(ti->x + x_pcp_offsets[i], ti->y + y_pcp_offsets[i]));
-					break; /* We already have drawn a pylon, bail out */
-				}
-			}
-		}
-	}
-
-	/* Don't draw a wire under a low bridge */
-	if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !(_display_opt & DO_TRANS_BUILDINGS)) {
-		uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
-
-		if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
-	}
-
-	/* Drawing of pylons is finished, now draw the wires */
-	for (t = 0; t < TRACK_END; t++) {
-		if (HASBIT(trackconfig[TS_HOME], t)) {
-
-			byte PCPconfig = HASBIT(PCPstatus, PCPpositions[t][0]) +
-				(HASBIT(PCPstatus, PCPpositions[t][1]) << 1);
-
-			const SortableSpriteStruct *sss;
-			int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; /* tileh for the slopes, 0 otherwise */
-
-			assert(PCPconfig != 0); /* We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) */
-			assert(!IsSteepSlope(tileh[TS_HOME]));
-			sss = &CatenarySpriteData[Wires[tileh_selector][t][PCPconfig]];
-
-			AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
-				sss->x_size, sss->y_size, sss->z_size, GetSlopeZ(ti->x + min(sss->x_offset, TILE_SIZE - 1), ti->y + min(sss->y_offset, TILE_SIZE - 1)) + sss->z_offset);
-		}
-	}
-}
-
-static void DrawCatenaryOnBridge(const TileInfo *ti)
-{
-	TileIndex end = GetSouthernBridgeEnd(ti->tile);
-	TileIndex start = GetOtherBridgeEnd(end);
-
-	uint length = GetBridgeLength(start, end);
-	uint num = DistanceMax(ti->tile, start);
-	uint height;
-
-	const SortableSpriteStruct *sss;
-	Axis axis = GetBridgeAxis(ti->tile);
-	TLG tlg = GetTLG(ti->tile);
-
-	CatenarySprite offset = axis == AXIS_X ? 0 : WIRE_Y_FLAT_BOTH - WIRE_X_FLAT_BOTH;
-
-	if ((length % 2) && num == length) {
-		/* Draw the "short" wire on the southern end of the bridge
-		 * only needed if the length of the bridge is odd */
-		sss = &CatenarySpriteData[WIRE_X_FLAT_BOTH + offset];
-	} else {
-		/* Draw "long" wires on all other tiles of the bridge (one pylon every two tiles) */
-		sss = &CatenarySpriteData[WIRE_X_FLAT_SW + (num % 2) + offset];
-	}
-
-	height = GetBridgeHeight(end);
-
-	AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
-		sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset
-	);
-
-	/* Finished with wires, draw pylons */
-	/* every other tile needs a pylon on the northern end */
-	if (num % 2) {
-		if (axis == AXIS_X) {
-			AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height);
-		} else {
-			AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, height);
-		}
-	}
-
-	/* need a pylon on the southern end of the bridge */
-	if (DistanceMax(ti->tile, start) == length) {
-		if (axis == AXIS_X) {
-			AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height);
-		} else {
-			AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, height);
-		}
-	}
-}
-
-void DrawCatenary(const TileInfo *ti)
-{
-	if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
-		TileIndex head = GetNorthernBridgeEnd(ti->tile);
-
-		if (GetBridgeTransportType(head) == TRANSPORT_RAIL && GetRailType(head) == RAILTYPE_ELECTRIC) {
-			DrawCatenaryOnBridge(ti);
-		}
-	}
-	if (_patches.disable_elrails) return;
-
-	switch (GetTileType(ti->tile)) {
-		case MP_RAILWAY:
-			if (IsRailDepot(ti->tile)) {
-				const SortableSpriteStruct* sss = &CatenarySpriteData_Depot[GetRailDepotDirection(ti->tile)];
-
-				AddSortableSpriteToDraw(
-					sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
-					sss->x_size, sss->y_size, sss->z_size,
-					GetTileMaxZ(ti->tile) + sss->z_offset
-				);
-				return;
-			}
-			break;
-
-		case MP_TUNNELBRIDGE:
-		case MP_STREET:
-		case MP_STATION:
-			break;
-
-		default: return;
-	}
-	DrawCatenaryRailway(ti);
-}
-
-int32 SettingsDisableElrail(int32 p1)
-{
-	EngineID e_id;
-	Vehicle* v;
-	Player *p;
-	bool disable = (p1 != 0);
-
-	/* we will now walk through all electric train engines and change their railtypes if it is the wrong one*/
-	const RailType old_railtype = disable ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL;
-	const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC;
-
-	/* walk through all train engines */
-	for (e_id = 0; e_id < NUM_TRAIN_ENGINES; e_id++) {
-		const RailVehicleInfo *rv_info = RailVehInfo(e_id);
-		Engine *e = GetEngine(e_id);
-		/* if it is an electric rail engine and its railtype is the wrong one */
-		if (rv_info->engclass == 2 && e->railtype == old_railtype) {
-			/* change it to the proper one */
-			e->railtype = new_railtype;
-		}
-	}
-
-	/* when disabling elrails, make sure that all existing trains can run on
-	*  normal rail too */
-	if (disable) {
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_Train && v->u.rail.railtype == RAILTYPE_ELECTRIC) {
-				/* this railroad vehicle is now compatible only with elrail,
-				*  so add there also normal rail compatibility */
-				v->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
-				v->u.rail.railtype = RAILTYPE_RAIL;
-				SETBIT(v->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL);
-			}
-		}
-	}
-
-	/* setup total power for trains */
-	FOR_ALL_VEHICLES(v) {
-		/* power is cached only for front engines */
-		if (v->type == VEH_Train && IsFrontEngine(v)) TrainPowerChanged(v);
-	}
-
-	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
-
-	/* This resets the _last_built_railtype, which will be invalid for electric
-	* rails. It may have unintended consequences if that function is ever
-	* extended, though. */
-	ReinitGuiAfterToggleElrail(disable);
-	return 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/elrail.cpp
@@ -0,0 +1,445 @@
+/* $Id$ */
+/** @file elrail.c
+ * This file deals with displaying wires and pylons for electric railways.
+ * <h2>Basics</h2>
+ *
+ * <h3>Tile Types</h3>
+ *
+ * We have two different types of tiles in the drawing code:
+ * Normal Railway Tiles (NRTs) which can have more than one track on it, and
+ * Special Railways tiles (SRTs) which have only one track (like crossings, depots
+ * stations, etc).
+ *
+ * <h3>Location Categories</h3>
+ *
+ * All tiles are categorized into three location groups (TLG):
+ * Group 0: Tiles with both an even X coordinate and an even Y coordinate
+ * Group 1: Tiles with an even X and an odd Y coordinate
+ * Group 2: Tiles with an odd X and an even Y coordinate
+ * Group 3: Tiles with both an odd X and Y coordnate.
+ *
+ * <h3>Pylon Points</h3>
+ * <h4>Control Points</h4>
+ * A Pylon Control Point (PCP) is a position where a wire (or rather two)
+ * is mounted onto a pylon.
+ * Each NRT does contain 4 PCPs which are bitmapped to a byte
+ * variable and are represented by the DiagDirection enum
+ *
+ * Each track ends on two PCPs and thus requires one pylon on each end. However,
+ * there is one exception: Straight-and-level tracks only have one pylon every
+ * other tile.
+ *
+ * Now on each edge there are two PCPs: One from each adjacent tile. Both PCPs
+ * are merged using an OR operation (i. e. if one tile needs a PCP at the postion
+ * in question, both tiles get it).
+ *
+ * <h4>Position Points</h4>
+ * A Pylon Position Point (PPP) is a position where a pylon is located on the
+ * ground.  Each PCP owns 8 in (45 degree steps) PPPs that are located around
+ * it. PPPs are represented using the Direction enum. Each track bit has PPPs
+ * that are impossible (because the pylon would be situated on the track) and
+ * some that are preferred (because the pylon would be rectangular to the track).
+ *
+ * <img src="../../elrail_tile.png">
+ * <img src="../../elrail_track.png">
+ *
+ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "station_map.h"
+#include "tile.h"
+#include "viewport.h"
+#include "functions.h" /* We should REALLY get rid of this goddamn file, as it is butt-ugly */
+#include "variables.h" /* ... same here */
+#include "rail.h"
+#include "debug.h"
+#include "tunnel_map.h"
+#include "road_map.h"
+#include "bridge_map.h"
+#include "bridge.h"
+#include "rail_map.h"
+#include "table/sprites.h"
+#include "table/elrail_data.h"
+#include "vehicle.h"
+#include "train.h"
+#include "gui.h"
+
+static inline TLG GetTLG(TileIndex t)
+{
+	return (HASBIT(TileX(t), 0) << 1) + HASBIT(TileY(t), 0);
+}
+
+/** Finds which Rail Bits are present on a given tile. For bridge tiles,
+ * returns track bits under the bridge
+ */
+static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
+{
+	switch (GetTileType(t)) {
+		case MP_RAILWAY:
+			if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
+			switch (GetRailTileType(t)) {
+				case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS:
+					return GetTrackBits(t);
+				case RAIL_TILE_DEPOT_WAYPOINT:
+					if (GetRailTileSubtype(t) == RAIL_SUBTYPE_WAYPOINT) return GetRailWaypointBits(t);
+				default:
+					return 0;
+			}
+			break;
+
+		case MP_TUNNELBRIDGE:
+			if (IsTunnel(t)) {
+				if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
+				if (override != NULL) *override = 1 << GetTunnelDirection(t);
+				return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(t)));
+			} else {
+				if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
+				if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) {
+					*override = 1 << GetBridgeRampDirection(t);
+				}
+				return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(t)));
+			}
+
+		case MP_STREET:
+			if (GetRoadTileType(t) != ROAD_TILE_CROSSING) return 0;
+			if (GetRailTypeCrossing(t) != RAILTYPE_ELECTRIC) return 0;
+			return GetCrossingRailBits(t);
+
+		case MP_STATION:
+			if (!IsRailwayStation(t)) return 0;
+			if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
+			if (!IsStationTileElectrifiable(t)) return 0;
+			return TrackToTrackBits(GetRailStationTrack(t));
+
+		default:
+			return 0;
+	}
+}
+
+/** Corrects the tileh for certain tile types. Returns an effective tileh for the track on the tile.
+ * @param tile The tile to analyse
+ * @param *tileh the tileh
+ */
+static void AdjustTileh(TileIndex tile, Slope *tileh)
+{
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (IsTunnel(tile)) {
+			*tileh = SLOPE_FLAT;
+		} else {
+			if (*tileh != SLOPE_FLAT) {
+				*tileh = SLOPE_FLAT;
+			} else {
+				switch (GetBridgeRampDirection(tile)) {
+					case DIAGDIR_NE: *tileh = SLOPE_NE; break;
+					case DIAGDIR_SE: *tileh = SLOPE_SE; break;
+					case DIAGDIR_SW: *tileh = SLOPE_SW; break;
+					case DIAGDIR_NW: *tileh = SLOPE_NW; break;
+					default: NOT_REACHED();
+				}
+			}
+		}
+	}
+}
+
+/** Draws wires and, if required, pylons on a given tile
+ * @param ti The Tileinfo to draw the tile for
+ */
+static void DrawCatenaryRailway(const TileInfo *ti)
+{
+	/* Pylons are placed on a tile edge, so we need to take into account
+	 * the track configuration of 2 adjacent tiles. trackconfig[0] stores the
+	 * current tile (home tile) while [1] holds the neighbour */
+	TrackBits trackconfig[TS_END];
+	bool isflat[TS_END];
+	/* Note that ti->tileh has already been adjusted for Foundations */
+	Slope tileh[TS_END] = { ti->tileh, SLOPE_FLAT };
+
+	TLG tlg = GetTLG(ti->tile);
+	byte PCPstatus = 0;
+	byte OverridePCP = 0;
+	byte PPPpreferred[DIAGDIR_END];
+	byte PPPallowed[DIAGDIR_END];
+	DiagDirection i;
+	Track t;
+
+	/* Find which rail bits are present, and select the override points.
+	 * We don't draw a pylon:
+	 * 1) INSIDE a tunnel (we wouldn't see it anyway)
+	 * 2) on the "far" end of a bridge head (the one that connects to bridge middle),
+	 *    because that one is drawn on the bridge. Exception is for length 0 bridges
+	 *    which have no middle tiles */
+	trackconfig[TS_HOME] = GetRailTrackBitsUniversal(ti->tile, &OverridePCP);
+	/* If a track bit is present that is not in the main direction, the track is level */
+	isflat[TS_HOME] = trackconfig[TS_HOME] & (TRACK_BIT_HORZ | TRACK_BIT_VERT);
+
+	AdjustTileh(ti->tile, &tileh[TS_HOME]);
+
+	for (i = DIAGDIR_NE; i < DIAGDIR_END; i++) {
+		TileIndex neighbour = ti->tile + TileOffsByDiagDir(i);
+		uint foundation = 0;
+		int k;
+
+		/* Here's one of the main headaches. GetTileSlope does not correct for possibly
+		 * existing foundataions, so we do have to do that manually later on.*/
+		tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour, NULL);
+		trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL);
+		if (IsTunnelTile(neighbour) && i != GetTunnelDirection(neighbour)) trackconfig[TS_NEIGHBOUR] = 0;
+		isflat[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] & (TRACK_BIT_HORZ | TRACK_BIT_VERT);
+
+		PPPpreferred[i] = 0xFF; /* We start with preferring everything (end-of-line in any direction) */
+		PPPallowed[i] = AllowedPPPonPCP[i];
+
+		/* We cycle through all the existing tracks at a PCP and see what
+		 * PPPs we want to have, or may not have at all */
+		for (k = 0; k < NUM_TRACKS_AT_PCP; k++) {
+			/* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */
+			if (TrackSourceTile[i][k] == TS_NEIGHBOUR &&
+			    IsBridgeTile(neighbour) &&
+			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)) {
+				continue;
+			}
+
+			/* We check whether the track in question (k) is present in the tile
+			 * (TrackSourceTile) */
+			if (HASBIT(trackconfig[TrackSourceTile[i][k]], TracksAtPCP[i][k])) {
+				/* track found, if track is in the neighbour tile, adjust the number
+				 * of the PCP for preferred/allowed determination*/
+				DiagDirection PCPpos = (TrackSourceTile[i][k] == TS_HOME) ? i : ReverseDiagDir(i);
+				SETBIT(PCPstatus, i); /* This PCP is in use */
+
+				PPPpreferred[i] &= PreferredPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
+				PPPallowed[i] &= ~DisallowedPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos];
+			}
+		}
+
+		/* Deactivate all PPPs if PCP is not used */
+		PPPpreferred[i] *= HASBIT(PCPstatus, i);
+		PPPallowed[i] *= HASBIT(PCPstatus, i);
+
+		/* A station is always "flat", so adjust the tileh accordingly */
+		if (IsTileType(neighbour, MP_STATION)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
+
+		/* Read the foundataions if they are present, and adjust the tileh */
+		if (IsTileType(neighbour, MP_RAILWAY) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
+		if (IsBridgeTile(neighbour)) {
+			foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour)));
+		}
+
+		if (foundation != 0) {
+			if (foundation < 15) {
+				tileh[TS_NEIGHBOUR] = SLOPE_FLAT;
+			} else {
+				tileh[TS_NEIGHBOUR] = _inclined_tileh[foundation - 15];
+			}
+		}
+
+		AdjustTileh(neighbour, &tileh[TS_NEIGHBOUR]);
+
+		/* If we have a straight (and level) track, we want a pylon only every 2 tiles
+		 * Delete the PCP if this is the case. */
+		/* Level means that the slope is the same, or the track is flat */
+		if (tileh[TS_HOME] == tileh[TS_NEIGHBOUR] || (isflat[TS_HOME] && isflat[TS_NEIGHBOUR])) {
+			for (k = 0; k < NUM_IGNORE_GROUPS; k++)
+				if (PPPpreferred[i] == IgnoredPCP[k][tlg][i]) CLRBIT(PCPstatus, i);
+		}
+
+		/* Now decide where we draw our pylons. First try the preferred PPPs, but they may not exist.
+		 * In that case, we try the any of the allowed ones. if they don't exist either, don't draw
+		 * anything. Note that the preferred PPPs still contain the end-of-line markers.
+		 * Remove those (simply by ANDing with allowed, since these markers are never allowed) */
+		if ((PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i];
+
+		if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
+			Track bridgetrack = GetBridgeAxis(ti->tile) == AXIS_X ? TRACK_X : TRACK_Y;
+			uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
+
+			if ((height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) &&
+			(i == PCPpositions[bridgetrack][0] || i == PCPpositions[bridgetrack][1])) SETBIT(OverridePCP, i);
+		}
+
+		if (PPPallowed[i] != 0 && HASBIT(PCPstatus, i) && !HASBIT(OverridePCP, i)) {
+			for (k = 0; k < DIR_END; k++) {
+				byte temp = PPPorder[i][GetTLG(ti->tile)][k];
+
+				if (HASBIT(PPPallowed[i], temp)) {
+					uint x  = ti->x + x_pcp_offsets[i] + x_ppp_offsets[temp];
+					uint y  = ti->y + y_pcp_offsets[i] + y_ppp_offsets[temp];
+
+					/* Don't build the pylon if it would be outside the tile */
+					if (!HASBIT(OwnedPPPonPCP[i], temp)) {
+						/* We have a neighour that will draw it, bail out */
+						if (trackconfig[TS_NEIGHBOUR] != 0) break;
+						continue; /* No neighbour, go looking for a better position */
+					}
+
+					AddSortableSpriteToDraw(pylons_normal[temp], x, y, 1, 1, 10,
+							GetSlopeZ(ti->x + x_pcp_offsets[i], ti->y + y_pcp_offsets[i]));
+					break; /* We already have drawn a pylon, bail out */
+				}
+			}
+		}
+	}
+
+	/* Don't draw a wire under a low bridge */
+	if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !(_display_opt & DO_TRANS_BUILDINGS)) {
+		uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
+
+		if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
+	}
+
+	/* Drawing of pylons is finished, now draw the wires */
+	for (t = 0; t < TRACK_END; t++) {
+		if (HASBIT(trackconfig[TS_HOME], t)) {
+
+			byte PCPconfig = HASBIT(PCPstatus, PCPpositions[t][0]) +
+				(HASBIT(PCPstatus, PCPpositions[t][1]) << 1);
+
+			const SortableSpriteStruct *sss;
+			int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; /* tileh for the slopes, 0 otherwise */
+
+			assert(PCPconfig != 0); /* We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) */
+			assert(!IsSteepSlope(tileh[TS_HOME]));
+			sss = &CatenarySpriteData[Wires[tileh_selector][t][PCPconfig]];
+
+			AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
+				sss->x_size, sss->y_size, sss->z_size, GetSlopeZ(ti->x + min(sss->x_offset, TILE_SIZE - 1), ti->y + min(sss->y_offset, TILE_SIZE - 1)) + sss->z_offset);
+		}
+	}
+}
+
+static void DrawCatenaryOnBridge(const TileInfo *ti)
+{
+	TileIndex end = GetSouthernBridgeEnd(ti->tile);
+	TileIndex start = GetOtherBridgeEnd(end);
+
+	uint length = GetBridgeLength(start, end);
+	uint num = DistanceMax(ti->tile, start);
+	uint height;
+
+	const SortableSpriteStruct *sss;
+	Axis axis = GetBridgeAxis(ti->tile);
+	TLG tlg = GetTLG(ti->tile);
+
+	CatenarySprite offset = axis == AXIS_X ? 0 : WIRE_Y_FLAT_BOTH - WIRE_X_FLAT_BOTH;
+
+	if ((length % 2) && num == length) {
+		/* Draw the "short" wire on the southern end of the bridge
+		 * only needed if the length of the bridge is odd */
+		sss = &CatenarySpriteData[WIRE_X_FLAT_BOTH + offset];
+	} else {
+		/* Draw "long" wires on all other tiles of the bridge (one pylon every two tiles) */
+		sss = &CatenarySpriteData[WIRE_X_FLAT_SW + (num % 2) + offset];
+	}
+
+	height = GetBridgeHeight(end);
+
+	AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
+		sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset
+	);
+
+	/* Finished with wires, draw pylons */
+	/* every other tile needs a pylon on the northern end */
+	if (num % 2) {
+		if (axis == AXIS_X) {
+			AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height);
+		} else {
+			AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, height);
+		}
+	}
+
+	/* need a pylon on the southern end of the bridge */
+	if (DistanceMax(ti->tile, start) == length) {
+		if (axis == AXIS_X) {
+			AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height);
+		} else {
+			AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, height);
+		}
+	}
+}
+
+void DrawCatenary(const TileInfo *ti)
+{
+	if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
+		TileIndex head = GetNorthernBridgeEnd(ti->tile);
+
+		if (GetBridgeTransportType(head) == TRANSPORT_RAIL && GetRailType(head) == RAILTYPE_ELECTRIC) {
+			DrawCatenaryOnBridge(ti);
+		}
+	}
+	if (_patches.disable_elrails) return;
+
+	switch (GetTileType(ti->tile)) {
+		case MP_RAILWAY:
+			if (IsRailDepot(ti->tile)) {
+				const SortableSpriteStruct* sss = &CatenarySpriteData_Depot[GetRailDepotDirection(ti->tile)];
+
+				AddSortableSpriteToDraw(
+					sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
+					sss->x_size, sss->y_size, sss->z_size,
+					GetTileMaxZ(ti->tile) + sss->z_offset
+				);
+				return;
+			}
+			break;
+
+		case MP_TUNNELBRIDGE:
+		case MP_STREET:
+		case MP_STATION:
+			break;
+
+		default: return;
+	}
+	DrawCatenaryRailway(ti);
+}
+
+int32 SettingsDisableElrail(int32 p1)
+{
+	EngineID e_id;
+	Vehicle* v;
+	Player *p;
+	bool disable = (p1 != 0);
+
+	/* we will now walk through all electric train engines and change their railtypes if it is the wrong one*/
+	const RailType old_railtype = disable ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL;
+	const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC;
+
+	/* walk through all train engines */
+	for (e_id = 0; e_id < NUM_TRAIN_ENGINES; e_id++) {
+		const RailVehicleInfo *rv_info = RailVehInfo(e_id);
+		Engine *e = GetEngine(e_id);
+		/* if it is an electric rail engine and its railtype is the wrong one */
+		if (rv_info->engclass == 2 && e->railtype == old_railtype) {
+			/* change it to the proper one */
+			e->railtype = new_railtype;
+		}
+	}
+
+	/* when disabling elrails, make sure that all existing trains can run on
+	*  normal rail too */
+	if (disable) {
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Train && v->u.rail.railtype == RAILTYPE_ELECTRIC) {
+				/* this railroad vehicle is now compatible only with elrail,
+				*  so add there also normal rail compatibility */
+				v->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
+				v->u.rail.railtype = RAILTYPE_RAIL;
+				SETBIT(v->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL);
+			}
+		}
+	}
+
+	/* setup total power for trains */
+	FOR_ALL_VEHICLES(v) {
+		/* power is cached only for front engines */
+		if (v->type == VEH_Train && IsFrontEngine(v)) TrainPowerChanged(v);
+	}
+
+	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
+
+	/* This resets the _last_built_railtype, which will be invalid for electric
+	* rails. It may have unintended consequences if that function is ever
+	* extended, though. */
+	ReinitGuiAfterToggleElrail(disable);
+	return 0;
+}
deleted file mode 100644
--- a/src/endian_check.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/* $Id$ */
-
-#include <stdio.h>
-
-// This pretty simple file checks if the system is LITTLE_ENDIAN or BIG_ENDIAN
-//  it does that by putting a 1 and a 0 in an array, and read it out as one
-//  number. If it is 1, it is LITTLE_ENDIAN, if it is 256, it is BIG_ENDIAN
-//
-// After that it outputs the contents of an include files (endian.h)
-//  that says or TTD_LITTLE_ENDIAN, or TTD_BIG_ENDIAN. Makefile takes
-//  care of the real writing to the file.
-
-int main (int argc, char *argv[]) {
-	unsigned char EndianTest[2] = { 1, 0 };
-	int force_BE = 0, force_LE = 0, force_PREPROCESSOR = 0;
-
-	if (argc > 1 && strcmp(argv[1], "BE") == 0)
-		force_BE = 1;
-	if (argc > 1 && strcmp(argv[1], "LE") == 0)
-		force_LE = 1;
-	if (argc > 1 && strcmp(argv[1], "PREPROCESSOR") == 0)
-		force_PREPROCESSOR = 1;
-
-	printf("#ifndef ENDIAN_H\n#define ENDIAN_H\n");
-
-	if (force_LE == 1) {
-		printf("#define TTD_LITTLE_ENDIAN\n");
-	} else {
-		if (force_BE == 1) {
-			printf("#define TTD_BIG_ENDIAN\n");
-		} else {
-			if (force_PREPROCESSOR == 1) {
-				// adding support for universal binaries on OSX
-				// Universal binaries supports both PPC and x86
-				// If a compiler for OSX gets this setting, it will always pick the correct endian and no test is needed
-				printf("#ifdef __BIG_ENDIAN__\n");
-				printf("#define TTD_BIG_ENDIAN\n");
-				printf("#else\n");
-				printf("#define TTD_LITTLE_ENDIAN\n");
-				printf("#endif\n");
-			} else {
-				if ( *(short *) EndianTest == 1 )
-					printf("#define TTD_LITTLE_ENDIAN\n");
-				else
-					printf("#define TTD_BIG_ENDIAN\n");
-			}
-		}
-	}
-	printf("#endif\n");
-
-	return 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/endian_check.cpp
@@ -0,0 +1,52 @@
+/* $Id$ */
+
+#include <stdio.h>
+
+// This pretty simple file checks if the system is LITTLE_ENDIAN or BIG_ENDIAN
+//  it does that by putting a 1 and a 0 in an array, and read it out as one
+//  number. If it is 1, it is LITTLE_ENDIAN, if it is 256, it is BIG_ENDIAN
+//
+// After that it outputs the contents of an include files (endian.h)
+//  that says or TTD_LITTLE_ENDIAN, or TTD_BIG_ENDIAN. Makefile takes
+//  care of the real writing to the file.
+
+int main (int argc, char *argv[]) {
+	unsigned char EndianTest[2] = { 1, 0 };
+	int force_BE = 0, force_LE = 0, force_PREPROCESSOR = 0;
+
+	if (argc > 1 && strcmp(argv[1], "BE") == 0)
+		force_BE = 1;
+	if (argc > 1 && strcmp(argv[1], "LE") == 0)
+		force_LE = 1;
+	if (argc > 1 && strcmp(argv[1], "PREPROCESSOR") == 0)
+		force_PREPROCESSOR = 1;
+
+	printf("#ifndef ENDIAN_H\n#define ENDIAN_H\n");
+
+	if (force_LE == 1) {
+		printf("#define TTD_LITTLE_ENDIAN\n");
+	} else {
+		if (force_BE == 1) {
+			printf("#define TTD_BIG_ENDIAN\n");
+		} else {
+			if (force_PREPROCESSOR == 1) {
+				// adding support for universal binaries on OSX
+				// Universal binaries supports both PPC and x86
+				// If a compiler for OSX gets this setting, it will always pick the correct endian and no test is needed
+				printf("#ifdef __BIG_ENDIAN__\n");
+				printf("#define TTD_BIG_ENDIAN\n");
+				printf("#else\n");
+				printf("#define TTD_LITTLE_ENDIAN\n");
+				printf("#endif\n");
+			} else {
+				if ( *(short *) EndianTest == 1 )
+					printf("#define TTD_LITTLE_ENDIAN\n");
+				else
+					printf("#define TTD_BIG_ENDIAN\n");
+			}
+		}
+	}
+	printf("#endif\n");
+
+	return 0;
+}
deleted file mode 100644
--- a/src/engine.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "table/strings.h"
-#include "engine.h"
-#include "gfx.h"
-#include "player.h"
-#include "command.h"
-#include "vehicle.h"
-#include "news.h"
-#include "saveload.h"
-#include "variables.h"
-#include "train.h"
-#include "newgrf_cargo.h"
-#include "date.h"
-#include "table/engines.h"
-
-EngineInfo _engine_info[TOTAL_NUM_ENGINES];
-RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
-ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
-AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
-RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
-
-enum {
-	ENGINE_AVAILABLE   = 1,
-	ENGINE_INTRODUCING = 2,
-	ENGINE_PREVIEWING  = 4,
-};
-
-enum {
-	YEAR_ENGINE_AGING_STOPS = 2050,
-};
-
-
-void ShowEnginePreviewWindow(EngineID engine);
-
-void DeleteCustomEngineNames(void)
-{
-	uint i;
-	StringID old;
-
-	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
-		old = _engine_name_strings[i];
-		_engine_name_strings[i] = i + STR_8000_KIRBY_PAUL_TANK_STEAM;
-		DeleteName(old);
-	}
-
-	_vehicle_design_names &= ~1;
-}
-
-void LoadCustomEngineNames(void)
-{
-	/* XXX: not done */
-	DEBUG(misc, 1, "LoadCustomEngineNames: not done");
-}
-
-static void SetupEngineNames(void)
-{
-	StringID *name;
-
-	for (name = _engine_name_strings; name != endof(_engine_name_strings); name++)
-		*name = STR_SV_EMPTY;
-
-	DeleteCustomEngineNames();
-	LoadCustomEngineNames();
-}
-
-static void AdjustAvailAircraft(void)
-{
-	byte avail = 0;
-	if (_cur_year >= 1955) avail |= 2; // big airport
-	if (_cur_year <  1960 || _patches.always_small_airport) avail |= 1;  // small airport
-	if (_cur_year >= 1963) avail |= 4; // enable heliport
-
-	if (avail != _avail_aircraft) {
-		_avail_aircraft = avail;
-		InvalidateWindow(WC_BUILD_STATION, 0);
-	}
-}
-
-static void CalcEngineReliability(Engine *e)
-{
-	uint age = e->age;
-
-	if (age < e->duration_phase_1) {
-		uint start = e->reliability_start;
-		e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
-	} else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _patches.never_expire_vehicles) {
-		/* We are at the peak of this engines life. It will have max reliability.
-		 * This is also true if the engines never expire. They will not go bad over time */
-		e->reliability = e->reliability_max;
-	} else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
-		uint max = e->reliability_max;
-		e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
-	} else {
-		/* time's up for this engine.
-		 * We will now completely retire this design */
-		e->player_avail = 0;
-		e->reliability = e->reliability_final;
-		InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Kick this engine out of the lists
-	}
-	InvalidateWindowClasses(WC_BUILD_VEHICLE); // Update to show the new reliability
-}
-
-void AddTypeToEngines(void)
-{
-	Engine* e = _engines;
-
-	do e->type = VEH_Train;    while (++e < &_engines[ROAD_ENGINES_INDEX]);
-	do e->type = VEH_Road;     while (++e < &_engines[SHIP_ENGINES_INDEX]);
-	do e->type = VEH_Ship;     while (++e < &_engines[AIRCRAFT_ENGINES_INDEX]);
-	do e->type = VEH_Aircraft; while (++e < &_engines[TOTAL_NUM_ENGINES]);
-	do e->type = VEH_Special;  while (++e < endof(_engines));
-}
-
-void StartupEngines(void)
-{
-	Engine *e;
-	const EngineInfo *ei;
-	/* Aging of vehicles stops, so account for that when starting late */
-	const Date aging_date = min(_date, ConvertYMDToDate(YEAR_ENGINE_AGING_STOPS, 0, 1));
-
-	SetupEngineNames();
-
-	for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
-		uint32 r;
-
-		e->age = 0;
-		e->railtype = ei->railtype;
-		e->flags = 0;
-		e->player_avail = 0;
-
-		// The magic value of 729 days below comes from the NewGRF spec. If the
-		// base intro date is before 1922 then the random number of days is not
-		// added.
-		r = Random();
-		e->intro_date = ei->base_intro <= ConvertYMDToDate(1922, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
-		if (e->intro_date <= _date) {
-			e->age = (aging_date - e->intro_date) >> 5;
-			e->player_avail = (byte)-1;
-			e->flags |= ENGINE_AVAILABLE;
-		}
-
-		e->reliability_start = GB(r, 16, 14) + 0x7AE0;
-		r = Random();
-		e->reliability_max   = GB(r,  0, 14) + 0xBFFF;
-		e->reliability_final = GB(r, 16, 14) + 0x3FFF;
-
-		r = Random();
-		e->duration_phase_1 = GB(r, 0, 5) + 7;
-		e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
-		e->duration_phase_3 = GB(r, 9, 7) + 120;
-
-		e->reliability_spd_dec = (ei->unk2&0x7F) << 2;
-
-		/* my invented flag for something that is a wagon */
-		if (ei->unk2 & 0x80) {
-			e->age = 0xFFFF;
-		} else {
-			CalcEngineReliability(e);
-		}
-
-		e->lifelength = ei->lifelength + _patches.extend_vehicle_life;
-
-		// prevent certain engines from ever appearing.
-		if (!HASBIT(ei->climates, _opt.landscape)) {
-			e->flags |= ENGINE_AVAILABLE;
-			e->player_avail = 0;
-		}
-
-		/* This sets up type for the engine
-		 * It is needed if you want to ask the engine what type it is
-		 * It should hopefully be the same as when you ask a vehicle what it is
-		 * but using this, you can ask what type an engine number is
-		 * even if it is not a vehicle (yet)*/
-	}
-
-	AdjustAvailAircraft();
-}
-
-static void AcceptEnginePreview(Engine *e, PlayerID player)
-{
-	Player *p = GetPlayer(player);
-
-	assert(e->railtype < RAILTYPE_END);
-	SETBIT(e->player_avail, player);
-	SETBIT(p->avail_railtypes, e->railtype);
-
-	e->preview_player = 0xFF;
-	if (player == _local_player) {
-		InvalidateWindowClassesData(WC_BUILD_VEHICLE);
-		InvalidateWindowClasses(WC_REPLACE_VEHICLE);
-	}
-}
-
-static PlayerID GetBestPlayer(PlayerID pp)
-{
-	const Player *p;
-	int32 best_hist;
-	PlayerID best_player;
-	uint mask = 0;
-
-	do {
-		best_hist = -1;
-		best_player = PLAYER_SPECTATOR;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && p->block_preview == 0 && !HASBIT(mask, p->index) &&
-					p->old_economy[0].performance_history > best_hist) {
-				best_hist = p->old_economy[0].performance_history;
-				best_player = p->index;
-			}
-		}
-
-		if (best_player == PLAYER_SPECTATOR) return PLAYER_SPECTATOR;
-
-		SETBIT(mask, best_player);
-	} while (--pp != 0);
-
-	return best_player;
-}
-
-void EnginesDailyLoop(void)
-{
-	EngineID i;
-
-	if (_cur_year >= YEAR_ENGINE_AGING_STOPS) return;
-
-	for (i = 0; i != lengthof(_engines); i++) {
-		Engine *e = &_engines[i];
-
-		if (e->flags & ENGINE_INTRODUCING) {
-			if (e->flags & ENGINE_PREVIEWING) {
-				if (e->preview_player != 0xFF && !--e->preview_wait) {
-					e->flags &= ~ENGINE_PREVIEWING;
-					DeleteWindowById(WC_ENGINE_PREVIEW, i);
-					e->preview_player++;
-				}
-			} else if (e->preview_player != 0xFF) {
-				PlayerID best_player = GetBestPlayer(e->preview_player);
-
-				if (best_player == PLAYER_SPECTATOR) {
-					e->preview_player = 0xFF;
-					continue;
-				}
-
-				if (!IsHumanPlayer(best_player)) {
-					/* XXX - TTDBUG: TTD has a bug here ???? */
-					AcceptEnginePreview(e, best_player);
-				} else {
-					e->flags |= ENGINE_PREVIEWING;
-					e->preview_wait = 20;
-					if (IsInteractivePlayer(best_player)) ShowEnginePreviewWindow(i);
-				}
-			}
-		}
-	}
-}
-
-/** Accept an engine prototype. XXX - it is possible that the top-player
- * changes while you are waiting to accept the offer? Then it becomes invalid
- * @param tile unused
- * @param p1 engine-prototype offered
- * @param p2 unused
- */
-int32 CmdWantEnginePreview(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Engine *e;
-
-	if (!IsEngineIndex(p1)) return CMD_ERROR;
-	e = GetEngine(p1);
-	if (GetBestPlayer(e->preview_player) != _current_player) return CMD_ERROR;
-
-	if (flags & DC_EXEC) AcceptEnginePreview(e, _current_player);
-
-	return 0;
-}
-
-// Determine if an engine type is a wagon (and not a loco)
-static bool IsWagon(EngineID index)
-{
-	return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->flags & RVI_WAGON;
-}
-
-static void NewVehicleAvailable(Engine *e)
-{
-	Vehicle *v;
-	Player *p;
-	EngineID index = e - _engines;
-
-	// In case the player didn't build the vehicle during the intro period,
-	// prevent that player from getting future intro periods for a while.
-	if (e->flags & ENGINE_INTRODUCING) {
-		FOR_ALL_PLAYERS(p) {
-			uint block_preview = p->block_preview;
-
-			if (!HASBIT(e->player_avail, p->index)) continue;
-
-			/* We assume the user did NOT build it.. prove me wrong ;) */
-			p->block_preview = 20;
-
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship ||
-						(v->type == VEH_Aircraft && v->subtype <= 2)) {
-					if (v->owner == p->index && v->engine_type == index) {
-						/* The user did prove me wrong, so restore old value */
-						p->block_preview = block_preview;
-						break;
-					}
-				}
-			}
-		}
-	}
-
-	e->flags = (e->flags & ~ENGINE_INTRODUCING) | ENGINE_AVAILABLE;
-	InvalidateWindowClassesData(WC_BUILD_VEHICLE);
-	InvalidateWindowClasses(WC_REPLACE_VEHICLE);
-
-	// Now available for all players
-	e->player_avail = (byte)-1;
-
-	// Do not introduce new rail wagons
-	if (IsWagon(index)) return;
-
-	// make maglev / monorail available
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) {
-			assert(e->railtype < RAILTYPE_END);
-			SETBIT(p->avail_railtypes, e->railtype);
-		}
-	}
-
-	if (index < NUM_TRAIN_ENGINES) {
-		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_TRAINAVAIL), 0, 0);
-	} else if (index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) {
-		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_ROADAVAIL), 0, 0);
-	} else if (index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) {
-		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_SHIPAVAIL), 0, 0);
-	} else {
-		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_AIRCRAFTAVAIL), 0, 0);
-	}
-}
-
-void EnginesMonthlyLoop(void)
-{
-	Engine *e;
-
-	if (_cur_year < YEAR_ENGINE_AGING_STOPS) {
-		for (e = _engines; e != endof(_engines); e++) {
-			// Age the vehicle
-			if (e->flags & ENGINE_AVAILABLE && e->age != 0xFFFF) {
-				e->age++;
-				CalcEngineReliability(e);
-			}
-
-			if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + 365)) {
-				// Introduce it to all players
-				NewVehicleAvailable(e);
-			} else if (!(e->flags & (ENGINE_AVAILABLE|ENGINE_INTRODUCING)) && _date >= e->intro_date) {
-				// Introduction date has passed.. show introducing dialog to one player.
-				e->flags |= ENGINE_INTRODUCING;
-
-				// Do not introduce new rail wagons
-				if (!IsWagon(e - _engines))
-					e->preview_player = 1; // Give to the player with the highest rating.
-			}
-		}
-	}
-	AdjustAvailAircraft();
-}
-
-/** Rename an engine.
- * @param tile unused
- * @param p1 engine ID to rename
- * @param p2 unused
- */
-int32 CmdRenameEngine(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID str;
-
-	if (!IsEngineIndex(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
-
-	str = AllocateNameUnique(_cmd_text, 0);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		StringID old_str = _engine_name_strings[p1];
-		_engine_name_strings[p1] = str;
-		DeleteName(old_str);
-		_vehicle_design_names |= 3;
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-
-	return 0;
-}
-
-
-/*
- * returns true if an engine is valid, of the specified type, and buildable by
- * the given player, false otherwise
- *
- * engine = index of the engine to check
- * type   = the type the engine should be of (VEH_xxx)
- * player = index of the player
- */
-bool IsEngineBuildable(EngineID engine, byte type, PlayerID player)
-{
-	const Engine *e;
-
-	// check if it's an engine that is in the engine array
-	if (!IsEngineIndex(engine)) return false;
-
-	e = GetEngine(engine);
-
-	// check if it's an engine of specified type
-	if (e->type != type) return false;
-
-	// check if it's available
-	if (!HASBIT(e->player_avail, player)) return false;
-
-	return true;
-}
-
-/************************************************************************
- * Engine Replacement stuff
- ************************************************************************/
-
-static void EngineRenewPoolNewBlock(uint start_item);
-
-DEFINE_OLD_POOL(EngineRenew, EngineRenew, EngineRenewPoolNewBlock, NULL)
-
-static void EngineRenewPoolNewBlock(uint start_item)
-{
-	EngineRenew *er;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 *  TODO - This is just a temporary stage, this will be removed. */
-	for (er = GetEngineRenew(start_item); er != NULL; er = (er->index + 1U < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1U) : NULL) {
-		er->index = start_item++;
-		er->from = INVALID_ENGINE;
-	}
-}
-
-
-static EngineRenew *AllocateEngineRenew(void)
-{
-	EngineRenew *er;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 *  TODO - This is just a temporary stage, this will be removed. */
-	for (er = GetEngineRenew(0); er != NULL; er = (er->index + 1U < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1U) : NULL) {
-		if (IsValidEngineRenew(er)) continue;
-
-		er->to = INVALID_ENGINE;
-		er->next = NULL;
-		return er;
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_EngineRenew_pool)) return AllocateEngineRenew();
-
-	return NULL;
-}
-
-/**
- * Retrieves the EngineRenew that specifies the replacement of the given
- * engine type from the given renewlist */
-static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine)
-{
-	EngineRenew *er = (EngineRenew *)erl;
-
-	while (er) {
-		if (er->from == engine) return er;
-		er = er->next;
-	}
-	return NULL;
-}
-
-void RemoveAllEngineReplacement(EngineRenewList *erl)
-{
-	EngineRenew *er = (EngineRenew *)(*erl);
-	EngineRenew *next;
-
-	while (er) {
-		next = er->next;
-		DeleteEngineRenew(er);
-		er = next;
-	}
-	*erl = NULL; // Empty list
-}
-
-EngineID EngineReplacement(EngineRenewList erl, EngineID engine)
-{
-	const EngineRenew *er = GetEngineReplacement(erl, engine);
-	return er == NULL ? INVALID_ENGINE : er->to;
-}
-
-int32 AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, uint32 flags)
-{
-	EngineRenew *er;
-
-	/* Check if the old vehicle is already in the list */
-	er = GetEngineReplacement(*erl, old_engine);
-	if (er != NULL) {
-		if (flags & DC_EXEC) er->to = new_engine;
-		return 0;
-	}
-
-	er = AllocateEngineRenew();
-	if (er == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		er->from = old_engine;
-		er->to = new_engine;
-
-		/* Insert before the first element */
-		er->next = (EngineRenew *)(*erl);
-		*erl = (EngineRenewList)er;
-	}
-
-	return 0;
-}
-
-int32 RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, uint32 flags)
-{
-	EngineRenew *er = (EngineRenew *)(*erl);
-	EngineRenew *prev = NULL;
-
-	while (er)
-	{
-		if (er->from == engine) {
-			if (flags & DC_EXEC) {
-				if (prev == NULL) { // First element
-					/* The second becomes the new first element */
-					*erl = (EngineRenewList)er->next;
-				} else {
-					/* Cut this element out */
-					prev->next = er->next;
-				}
-				DeleteEngineRenew(er);
-			}
-			return 0;
-		}
-		prev = er;
-		er = er->next;
-	}
-
-	return CMD_ERROR;
-}
-
-static const SaveLoad _engine_renew_desc[] = {
-	SLE_VAR(EngineRenew, from, SLE_UINT16),
-	SLE_VAR(EngineRenew, to,   SLE_UINT16),
-
-	SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS),
-
-	SLE_END()
-};
-
-static void Save_ERNW(void)
-{
-	EngineRenew *er;
-
-	FOR_ALL_ENGINE_RENEWS(er) {
-		SlSetArrayIndex(er->index);
-		SlObject(er, _engine_renew_desc);
-	}
-}
-
-static void Load_ERNW(void)
-{
-	int index;
-
-	while ((index = SlIterateArray()) != -1) {
-		EngineRenew *er;
-
-		if (!AddBlockIfNeeded(&_EngineRenew_pool, index))
-			error("EngineRenews: failed loading savegame: too many EngineRenews");
-
-		er = GetEngineRenew(index);
-		SlObject(er, _engine_renew_desc);
-	}
-}
-
-static const SaveLoad _engine_desc[] = {
-	SLE_CONDVAR(Engine, intro_date,          SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
-	SLE_CONDVAR(Engine, intro_date,          SLE_INT32,                  31, SL_MAX_VERSION),
-	SLE_CONDVAR(Engine, age,                 SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
-	SLE_CONDVAR(Engine, age,                 SLE_INT32,                  31, SL_MAX_VERSION),
-	    SLE_VAR(Engine, reliability,         SLE_UINT16),
-	    SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
-	    SLE_VAR(Engine, reliability_start,   SLE_UINT16),
-	    SLE_VAR(Engine, reliability_max,     SLE_UINT16),
-	    SLE_VAR(Engine, reliability_final,   SLE_UINT16),
-	    SLE_VAR(Engine, duration_phase_1,    SLE_UINT16),
-	    SLE_VAR(Engine, duration_phase_2,    SLE_UINT16),
-	    SLE_VAR(Engine, duration_phase_3,    SLE_UINT16),
-
-	    SLE_VAR(Engine, lifelength,          SLE_UINT8),
-	    SLE_VAR(Engine, flags,               SLE_UINT8),
-	    SLE_VAR(Engine, preview_player,      SLE_UINT8),
-	    SLE_VAR(Engine, preview_wait,        SLE_UINT8),
-	    SLE_VAR(Engine, railtype,            SLE_UINT8),
-	    SLE_VAR(Engine, player_avail,        SLE_UINT8),
-
-	// reserve extra space in savegame here. (currently 16 bytes)
-	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static void Save_ENGN(void)
-{
-	uint i;
-
-	for (i = 0; i != lengthof(_engines); i++) {
-		SlSetArrayIndex(i);
-		SlObject(&_engines[i], _engine_desc);
-	}
-}
-
-static void Load_ENGN(void)
-{
-	int index;
-	while ((index = SlIterateArray()) != -1) {
-		SlObject(GetEngine(index), _engine_desc);
-	}
-}
-
-static void LoadSave_ENGS(void)
-{
-	SlArray(_engine_name_strings, lengthof(_engine_name_strings), SLE_STRINGID);
-}
-
-const ChunkHandler _engine_chunk_handlers[] = {
-	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
-	{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF           },
-	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
-};
-
-void InitializeEngines(void)
-{
-	/* Clean the engine renew pool and create 1 block in it */
-	CleanPool(&_EngineRenew_pool);
-	AddBlockToPool(&_EngineRenew_pool);
-}
new file mode 100644
--- /dev/null
+++ b/src/engine.cpp
@@ -0,0 +1,650 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "table/strings.h"
+#include "engine.h"
+#include "gfx.h"
+#include "player.h"
+#include "command.h"
+#include "vehicle.h"
+#include "news.h"
+#include "saveload.h"
+#include "variables.h"
+#include "train.h"
+#include "newgrf_cargo.h"
+#include "date.h"
+#include "table/engines.h"
+
+EngineInfo _engine_info[TOTAL_NUM_ENGINES];
+RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
+ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
+AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
+RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
+
+enum {
+	ENGINE_AVAILABLE   = 1,
+	ENGINE_INTRODUCING = 2,
+	ENGINE_PREVIEWING  = 4,
+};
+
+enum {
+	YEAR_ENGINE_AGING_STOPS = 2050,
+};
+
+
+void ShowEnginePreviewWindow(EngineID engine);
+
+void DeleteCustomEngineNames(void)
+{
+	uint i;
+	StringID old;
+
+	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
+		old = _engine_name_strings[i];
+		_engine_name_strings[i] = i + STR_8000_KIRBY_PAUL_TANK_STEAM;
+		DeleteName(old);
+	}
+
+	_vehicle_design_names &= ~1;
+}
+
+void LoadCustomEngineNames(void)
+{
+	/* XXX: not done */
+	DEBUG(misc, 1, "LoadCustomEngineNames: not done");
+}
+
+static void SetupEngineNames(void)
+{
+	StringID *name;
+
+	for (name = _engine_name_strings; name != endof(_engine_name_strings); name++)
+		*name = STR_SV_EMPTY;
+
+	DeleteCustomEngineNames();
+	LoadCustomEngineNames();
+}
+
+static void AdjustAvailAircraft(void)
+{
+	byte avail = 0;
+	if (_cur_year >= 1955) avail |= 2; // big airport
+	if (_cur_year <  1960 || _patches.always_small_airport) avail |= 1;  // small airport
+	if (_cur_year >= 1963) avail |= 4; // enable heliport
+
+	if (avail != _avail_aircraft) {
+		_avail_aircraft = avail;
+		InvalidateWindow(WC_BUILD_STATION, 0);
+	}
+}
+
+static void CalcEngineReliability(Engine *e)
+{
+	uint age = e->age;
+
+	if (age < e->duration_phase_1) {
+		uint start = e->reliability_start;
+		e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
+	} else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _patches.never_expire_vehicles) {
+		/* We are at the peak of this engines life. It will have max reliability.
+		 * This is also true if the engines never expire. They will not go bad over time */
+		e->reliability = e->reliability_max;
+	} else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
+		uint max = e->reliability_max;
+		e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
+	} else {
+		/* time's up for this engine.
+		 * We will now completely retire this design */
+		e->player_avail = 0;
+		e->reliability = e->reliability_final;
+		InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Kick this engine out of the lists
+	}
+	InvalidateWindowClasses(WC_BUILD_VEHICLE); // Update to show the new reliability
+}
+
+void AddTypeToEngines(void)
+{
+	Engine* e = _engines;
+
+	do e->type = VEH_Train;    while (++e < &_engines[ROAD_ENGINES_INDEX]);
+	do e->type = VEH_Road;     while (++e < &_engines[SHIP_ENGINES_INDEX]);
+	do e->type = VEH_Ship;     while (++e < &_engines[AIRCRAFT_ENGINES_INDEX]);
+	do e->type = VEH_Aircraft; while (++e < &_engines[TOTAL_NUM_ENGINES]);
+	do e->type = VEH_Special;  while (++e < endof(_engines));
+}
+
+void StartupEngines(void)
+{
+	Engine *e;
+	const EngineInfo *ei;
+	/* Aging of vehicles stops, so account for that when starting late */
+	const Date aging_date = min(_date, ConvertYMDToDate(YEAR_ENGINE_AGING_STOPS, 0, 1));
+
+	SetupEngineNames();
+
+	for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
+		uint32 r;
+
+		e->age = 0;
+		e->railtype = ei->railtype;
+		e->flags = 0;
+		e->player_avail = 0;
+
+		// The magic value of 729 days below comes from the NewGRF spec. If the
+		// base intro date is before 1922 then the random number of days is not
+		// added.
+		r = Random();
+		e->intro_date = ei->base_intro <= ConvertYMDToDate(1922, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
+		if (e->intro_date <= _date) {
+			e->age = (aging_date - e->intro_date) >> 5;
+			e->player_avail = (byte)-1;
+			e->flags |= ENGINE_AVAILABLE;
+		}
+
+		e->reliability_start = GB(r, 16, 14) + 0x7AE0;
+		r = Random();
+		e->reliability_max   = GB(r,  0, 14) + 0xBFFF;
+		e->reliability_final = GB(r, 16, 14) + 0x3FFF;
+
+		r = Random();
+		e->duration_phase_1 = GB(r, 0, 5) + 7;
+		e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
+		e->duration_phase_3 = GB(r, 9, 7) + 120;
+
+		e->reliability_spd_dec = (ei->unk2&0x7F) << 2;
+
+		/* my invented flag for something that is a wagon */
+		if (ei->unk2 & 0x80) {
+			e->age = 0xFFFF;
+		} else {
+			CalcEngineReliability(e);
+		}
+
+		e->lifelength = ei->lifelength + _patches.extend_vehicle_life;
+
+		// prevent certain engines from ever appearing.
+		if (!HASBIT(ei->climates, _opt.landscape)) {
+			e->flags |= ENGINE_AVAILABLE;
+			e->player_avail = 0;
+		}
+
+		/* This sets up type for the engine
+		 * It is needed if you want to ask the engine what type it is
+		 * It should hopefully be the same as when you ask a vehicle what it is
+		 * but using this, you can ask what type an engine number is
+		 * even if it is not a vehicle (yet)*/
+	}
+
+	AdjustAvailAircraft();
+}
+
+static void AcceptEnginePreview(Engine *e, PlayerID player)
+{
+	Player *p = GetPlayer(player);
+
+	assert(e->railtype < RAILTYPE_END);
+	SETBIT(e->player_avail, player);
+	SETBIT(p->avail_railtypes, e->railtype);
+
+	e->preview_player = 0xFF;
+	if (player == _local_player) {
+		InvalidateWindowClassesData(WC_BUILD_VEHICLE);
+		InvalidateWindowClasses(WC_REPLACE_VEHICLE);
+	}
+}
+
+static PlayerID GetBestPlayer(PlayerID pp)
+{
+	const Player *p;
+	int32 best_hist;
+	PlayerID best_player;
+	uint mask = 0;
+
+	do {
+		best_hist = -1;
+		best_player = PLAYER_SPECTATOR;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && p->block_preview == 0 && !HASBIT(mask, p->index) &&
+					p->old_economy[0].performance_history > best_hist) {
+				best_hist = p->old_economy[0].performance_history;
+				best_player = p->index;
+			}
+		}
+
+		if (best_player == PLAYER_SPECTATOR) return PLAYER_SPECTATOR;
+
+		SETBIT(mask, best_player);
+	} while (--pp != 0);
+
+	return best_player;
+}
+
+void EnginesDailyLoop(void)
+{
+	EngineID i;
+
+	if (_cur_year >= YEAR_ENGINE_AGING_STOPS) return;
+
+	for (i = 0; i != lengthof(_engines); i++) {
+		Engine *e = &_engines[i];
+
+		if (e->flags & ENGINE_INTRODUCING) {
+			if (e->flags & ENGINE_PREVIEWING) {
+				if (e->preview_player != 0xFF && !--e->preview_wait) {
+					e->flags &= ~ENGINE_PREVIEWING;
+					DeleteWindowById(WC_ENGINE_PREVIEW, i);
+					e->preview_player++;
+				}
+			} else if (e->preview_player != 0xFF) {
+				PlayerID best_player = GetBestPlayer(e->preview_player);
+
+				if (best_player == PLAYER_SPECTATOR) {
+					e->preview_player = 0xFF;
+					continue;
+				}
+
+				if (!IsHumanPlayer(best_player)) {
+					/* XXX - TTDBUG: TTD has a bug here ???? */
+					AcceptEnginePreview(e, best_player);
+				} else {
+					e->flags |= ENGINE_PREVIEWING;
+					e->preview_wait = 20;
+					if (IsInteractivePlayer(best_player)) ShowEnginePreviewWindow(i);
+				}
+			}
+		}
+	}
+}
+
+/** Accept an engine prototype. XXX - it is possible that the top-player
+ * changes while you are waiting to accept the offer? Then it becomes invalid
+ * @param tile unused
+ * @param p1 engine-prototype offered
+ * @param p2 unused
+ */
+int32 CmdWantEnginePreview(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Engine *e;
+
+	if (!IsEngineIndex(p1)) return CMD_ERROR;
+	e = GetEngine(p1);
+	if (GetBestPlayer(e->preview_player) != _current_player) return CMD_ERROR;
+
+	if (flags & DC_EXEC) AcceptEnginePreview(e, _current_player);
+
+	return 0;
+}
+
+// Determine if an engine type is a wagon (and not a loco)
+static bool IsWagon(EngineID index)
+{
+	return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->flags & RVI_WAGON;
+}
+
+static void NewVehicleAvailable(Engine *e)
+{
+	Vehicle *v;
+	Player *p;
+	EngineID index = e - _engines;
+
+	// In case the player didn't build the vehicle during the intro period,
+	// prevent that player from getting future intro periods for a while.
+	if (e->flags & ENGINE_INTRODUCING) {
+		FOR_ALL_PLAYERS(p) {
+			uint block_preview = p->block_preview;
+
+			if (!HASBIT(e->player_avail, p->index)) continue;
+
+			/* We assume the user did NOT build it.. prove me wrong ;) */
+			p->block_preview = 20;
+
+			FOR_ALL_VEHICLES(v) {
+				if (v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship ||
+						(v->type == VEH_Aircraft && v->subtype <= 2)) {
+					if (v->owner == p->index && v->engine_type == index) {
+						/* The user did prove me wrong, so restore old value */
+						p->block_preview = block_preview;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	e->flags = (e->flags & ~ENGINE_INTRODUCING) | ENGINE_AVAILABLE;
+	InvalidateWindowClassesData(WC_BUILD_VEHICLE);
+	InvalidateWindowClasses(WC_REPLACE_VEHICLE);
+
+	// Now available for all players
+	e->player_avail = (byte)-1;
+
+	// Do not introduce new rail wagons
+	if (IsWagon(index)) return;
+
+	// make maglev / monorail available
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active) {
+			assert(e->railtype < RAILTYPE_END);
+			SETBIT(p->avail_railtypes, e->railtype);
+		}
+	}
+
+	if (index < NUM_TRAIN_ENGINES) {
+		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_TRAINAVAIL), 0, 0);
+	} else if (index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) {
+		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_ROADAVAIL), 0, 0);
+	} else if (index < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) {
+		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_SHIPAVAIL), 0, 0);
+	} else {
+		AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_AIRCRAFTAVAIL), 0, 0);
+	}
+}
+
+void EnginesMonthlyLoop(void)
+{
+	Engine *e;
+
+	if (_cur_year < YEAR_ENGINE_AGING_STOPS) {
+		for (e = _engines; e != endof(_engines); e++) {
+			// Age the vehicle
+			if (e->flags & ENGINE_AVAILABLE && e->age != 0xFFFF) {
+				e->age++;
+				CalcEngineReliability(e);
+			}
+
+			if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + 365)) {
+				// Introduce it to all players
+				NewVehicleAvailable(e);
+			} else if (!(e->flags & (ENGINE_AVAILABLE|ENGINE_INTRODUCING)) && _date >= e->intro_date) {
+				// Introduction date has passed.. show introducing dialog to one player.
+				e->flags |= ENGINE_INTRODUCING;
+
+				// Do not introduce new rail wagons
+				if (!IsWagon(e - _engines))
+					e->preview_player = 1; // Give to the player with the highest rating.
+			}
+		}
+	}
+	AdjustAvailAircraft();
+}
+
+/** Rename an engine.
+ * @param tile unused
+ * @param p1 engine ID to rename
+ * @param p2 unused
+ */
+int32 CmdRenameEngine(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID str;
+
+	if (!IsEngineIndex(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+
+	str = AllocateNameUnique(_cmd_text, 0);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		StringID old_str = _engine_name_strings[p1];
+		_engine_name_strings[p1] = str;
+		DeleteName(old_str);
+		_vehicle_design_names |= 3;
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+
+	return 0;
+}
+
+
+/*
+ * returns true if an engine is valid, of the specified type, and buildable by
+ * the given player, false otherwise
+ *
+ * engine = index of the engine to check
+ * type   = the type the engine should be of (VEH_xxx)
+ * player = index of the player
+ */
+bool IsEngineBuildable(EngineID engine, byte type, PlayerID player)
+{
+	const Engine *e;
+
+	// check if it's an engine that is in the engine array
+	if (!IsEngineIndex(engine)) return false;
+
+	e = GetEngine(engine);
+
+	// check if it's an engine of specified type
+	if (e->type != type) return false;
+
+	// check if it's available
+	if (!HASBIT(e->player_avail, player)) return false;
+
+	return true;
+}
+
+/************************************************************************
+ * Engine Replacement stuff
+ ************************************************************************/
+
+static void EngineRenewPoolNewBlock(uint start_item);
+
+DEFINE_OLD_POOL(EngineRenew, EngineRenew, EngineRenewPoolNewBlock, NULL)
+
+static void EngineRenewPoolNewBlock(uint start_item)
+{
+	EngineRenew *er;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 *  TODO - This is just a temporary stage, this will be removed. */
+	for (er = GetEngineRenew(start_item); er != NULL; er = (er->index + 1U < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1U) : NULL) {
+		er->index = start_item++;
+		er->from = INVALID_ENGINE;
+	}
+}
+
+
+static EngineRenew *AllocateEngineRenew(void)
+{
+	EngineRenew *er;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 *  TODO - This is just a temporary stage, this will be removed. */
+	for (er = GetEngineRenew(0); er != NULL; er = (er->index + 1U < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1U) : NULL) {
+		if (IsValidEngineRenew(er)) continue;
+
+		er->to = INVALID_ENGINE;
+		er->next = NULL;
+		return er;
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_EngineRenew_pool)) return AllocateEngineRenew();
+
+	return NULL;
+}
+
+/**
+ * Retrieves the EngineRenew that specifies the replacement of the given
+ * engine type from the given renewlist */
+static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine)
+{
+	EngineRenew *er = (EngineRenew *)erl;
+
+	while (er) {
+		if (er->from == engine) return er;
+		er = er->next;
+	}
+	return NULL;
+}
+
+void RemoveAllEngineReplacement(EngineRenewList *erl)
+{
+	EngineRenew *er = (EngineRenew *)(*erl);
+	EngineRenew *next;
+
+	while (er) {
+		next = er->next;
+		DeleteEngineRenew(er);
+		er = next;
+	}
+	*erl = NULL; // Empty list
+}
+
+EngineID EngineReplacement(EngineRenewList erl, EngineID engine)
+{
+	const EngineRenew *er = GetEngineReplacement(erl, engine);
+	return er == NULL ? INVALID_ENGINE : er->to;
+}
+
+int32 AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, uint32 flags)
+{
+	EngineRenew *er;
+
+	/* Check if the old vehicle is already in the list */
+	er = GetEngineReplacement(*erl, old_engine);
+	if (er != NULL) {
+		if (flags & DC_EXEC) er->to = new_engine;
+		return 0;
+	}
+
+	er = AllocateEngineRenew();
+	if (er == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		er->from = old_engine;
+		er->to = new_engine;
+
+		/* Insert before the first element */
+		er->next = (EngineRenew *)(*erl);
+		*erl = (EngineRenewList)er;
+	}
+
+	return 0;
+}
+
+int32 RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, uint32 flags)
+{
+	EngineRenew *er = (EngineRenew *)(*erl);
+	EngineRenew *prev = NULL;
+
+	while (er)
+	{
+		if (er->from == engine) {
+			if (flags & DC_EXEC) {
+				if (prev == NULL) { // First element
+					/* The second becomes the new first element */
+					*erl = (EngineRenewList)er->next;
+				} else {
+					/* Cut this element out */
+					prev->next = er->next;
+				}
+				DeleteEngineRenew(er);
+			}
+			return 0;
+		}
+		prev = er;
+		er = er->next;
+	}
+
+	return CMD_ERROR;
+}
+
+static const SaveLoad _engine_renew_desc[] = {
+	SLE_VAR(EngineRenew, from, SLE_UINT16),
+	SLE_VAR(EngineRenew, to,   SLE_UINT16),
+
+	SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS),
+
+	SLE_END()
+};
+
+static void Save_ERNW(void)
+{
+	EngineRenew *er;
+
+	FOR_ALL_ENGINE_RENEWS(er) {
+		SlSetArrayIndex(er->index);
+		SlObject(er, _engine_renew_desc);
+	}
+}
+
+static void Load_ERNW(void)
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		EngineRenew *er;
+
+		if (!AddBlockIfNeeded(&_EngineRenew_pool, index))
+			error("EngineRenews: failed loading savegame: too many EngineRenews");
+
+		er = GetEngineRenew(index);
+		SlObject(er, _engine_renew_desc);
+	}
+}
+
+static const SaveLoad _engine_desc[] = {
+	SLE_CONDVAR(Engine, intro_date,          SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
+	SLE_CONDVAR(Engine, intro_date,          SLE_INT32,                  31, SL_MAX_VERSION),
+	SLE_CONDVAR(Engine, age,                 SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
+	SLE_CONDVAR(Engine, age,                 SLE_INT32,                  31, SL_MAX_VERSION),
+	    SLE_VAR(Engine, reliability,         SLE_UINT16),
+	    SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
+	    SLE_VAR(Engine, reliability_start,   SLE_UINT16),
+	    SLE_VAR(Engine, reliability_max,     SLE_UINT16),
+	    SLE_VAR(Engine, reliability_final,   SLE_UINT16),
+	    SLE_VAR(Engine, duration_phase_1,    SLE_UINT16),
+	    SLE_VAR(Engine, duration_phase_2,    SLE_UINT16),
+	    SLE_VAR(Engine, duration_phase_3,    SLE_UINT16),
+
+	    SLE_VAR(Engine, lifelength,          SLE_UINT8),
+	    SLE_VAR(Engine, flags,               SLE_UINT8),
+	    SLE_VAR(Engine, preview_player,      SLE_UINT8),
+	    SLE_VAR(Engine, preview_wait,        SLE_UINT8),
+	    SLE_VAR(Engine, railtype,            SLE_UINT8),
+	    SLE_VAR(Engine, player_avail,        SLE_UINT8),
+
+	// reserve extra space in savegame here. (currently 16 bytes)
+	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static void Save_ENGN(void)
+{
+	uint i;
+
+	for (i = 0; i != lengthof(_engines); i++) {
+		SlSetArrayIndex(i);
+		SlObject(&_engines[i], _engine_desc);
+	}
+}
+
+static void Load_ENGN(void)
+{
+	int index;
+	while ((index = SlIterateArray()) != -1) {
+		SlObject(GetEngine(index), _engine_desc);
+	}
+}
+
+static void LoadSave_ENGS(void)
+{
+	SlArray(_engine_name_strings, lengthof(_engine_name_strings), SLE_STRINGID);
+}
+
+const ChunkHandler _engine_chunk_handlers[] = {
+	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
+	{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF           },
+	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
+};
+
+void InitializeEngines(void)
+{
+	/* Clean the engine renew pool and create 1 block in it */
+	CleanPool(&_EngineRenew_pool);
+	AddBlockToPool(&_EngineRenew_pool);
+}
deleted file mode 100644
--- a/src/engine_gui.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "functions.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "engine.h"
-#include "command.h"
-#include "news.h"
-#include "variables.h"
-#include "newgrf_engine.h"
-
-
-static StringID GetEngineCategoryName(EngineID engine)
-{
-	if (engine < NUM_TRAIN_ENGINES) {
-		switch (GetEngine(engine)->railtype) {
-			case RAILTYPE_RAIL:     return STR_8102_RAILROAD_LOCOMOTIVE;
-			case RAILTYPE_ELECTRIC: return STR_8102_RAILROAD_LOCOMOTIVE;
-			case RAILTYPE_MONO:     return STR_8106_MONORAIL_LOCOMOTIVE;
-			case RAILTYPE_MAGLEV:   return STR_8107_MAGLEV_LOCOMOTIVE;
-		}
-	}
-
-	if (engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES)
-		return STR_8103_ROAD_VEHICLE;
-
-	if (engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES)
-		return STR_8105_SHIP;
-
-	return STR_8104_AIRCRAFT;
-}
-
-static const Widget _engine_preview_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,                                  STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   299,     0,    13, STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     5,     0,   299,    14,   191, 0x0,                                       STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     5,    85,   144,   172,   183, STR_00C9_NO,                               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     5,   155,   214,   172,   183, STR_00C8_YES,                              STR_NULL},
-{   WIDGETS_END},
-};
-
-typedef void DrawEngineProc(int x, int y, EngineID engine, uint32 image_ormod);
-typedef void DrawEngineInfoProc(EngineID, int x, int y, int maxw);
-
-typedef struct DrawEngineInfo {
-	DrawEngineProc *engine_proc;
-	DrawEngineInfoProc *info_proc;
-} DrawEngineInfo;
-
-static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw);
-static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw);
-static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw);
-static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw);
-
-static const DrawEngineInfo _draw_engine_list[4] = {
-	{DrawTrainEngine,DrawTrainEngineInfo},
-	{DrawRoadVehEngine,DrawRoadVehEngineInfo},
-	{DrawShipEngine,DrawShipEngineInfo},
-	{DrawAircraftEngine,DrawAircraftEngineInfo},
-};
-
-static void EnginePreviewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		EngineID engine = w->window_number;
-		const DrawEngineInfo* dei;
-		int width;
-
-		DrawWindowWidgets(w);
-
-		SetDParam(0, GetEngineCategoryName(engine));
-		DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
-
-		DrawStringCentered(w->width >> 1, 80, GetCustomEngineName(engine), 0x10);
-
-		(dei = _draw_engine_list,engine < NUM_TRAIN_ENGINES) ||
-		(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) ||
-		(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) ||
-		(dei++, true);
-
-		width = w->width;
-		dei->engine_proc(width >> 1, 100, engine, 0);
-		dei->info_proc(engine, width >> 1, 130, width - 52);
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 4:
-				DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
-				/* Fallthrough */
-			case 3:
-				DeleteWindow(w);
-				break;
-		}
-		break;
-	}
-}
-
-static const WindowDesc _engine_preview_desc = {
-	WDP_CENTER, WDP_CENTER, 300, 192,
-	WC_ENGINE_PREVIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_engine_preview_widgets,
-	EnginePreviewWndProc
-};
-
-
-void ShowEnginePreviewWindow(EngineID engine)
-{
-	AllocateWindowDescFront(&_engine_preview_desc, engine);
-}
-
-static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
-{
-	const RailVehicleInfo *rvi = RailVehInfo(engine);
-	uint multihead = (rvi->flags & RVI_MULTIHEAD) ? 1 : 0;
-
-	SetDParam(0, (_price.build_railvehicle >> 3) * rvi->base_cost >> 5);
-	SetDParam(2, rvi->max_speed);
-	SetDParam(3, rvi->power << multihead);
-	SetDParam(1, rvi->weight << multihead);
-
-	SetDParam(4, rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8 << multihead);
-
-	if (rvi->capacity != 0) {
-		SetDParam(5, rvi->cargo_type);
-		SetDParam(6, rvi->capacity << multihead);
-	} else {
-		SetDParam(5, CT_INVALID);
-	}
-	DrawStringMultiCenter(x, y, STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER, maxw);
-}
-
-void DrawNewsNewTrainAvail(Window *w)
-{
-	EngineID engine;
-
-	DrawNewsBorder(w);
-
-	engine = WP(w,news_d).ni->string_id;
-	SetDParam(0, GetEngineCategoryName(engine));
-	DrawStringMultiCenter(w->width >> 1, 20, STR_8859_NEW_NOW_AVAILABLE, w->width - 2);
-
-	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
-
-	SetDParam(0, GetCustomEngineName(engine));
-	DrawStringMultiCenter(w->width >> 1, 57, STR_885A, w->width - 2);
-
-	DrawTrainEngine(w->width >> 1, 88, engine, 0);
-	GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE);
-	DrawTrainEngineInfo(engine, w->width >> 1, 129, w->width - 52);
-}
-
-StringID GetNewsStringNewTrainAvail(const NewsItem *ni)
-{
-	EngineID engine = ni->string_id;
-	SetDParam(0, STR_8859_NEW_NOW_AVAILABLE);
-	SetDParam(1, GetEngineCategoryName(engine));
-	SetDParam(2, GetCustomEngineName(engine));
-	return STR_02B6;
-}
-
-static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw)
-{
-	const AircraftVehicleInfo *avi = AircraftVehInfo(engine);
-	SetDParam(0, (_price.aircraft_base >> 3) * avi->base_cost >> 5);
-	SetDParam(1, avi->max_speed * 128 / 10);
-	SetDParam(2, avi->passenger_capacity);
-	SetDParam(3, avi->mail_capacity);
-	SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
-
-	DrawStringMultiCenter(x, y, STR_A02E_COST_MAX_SPEED_CAPACITY, maxw);
-}
-
-void DrawNewsNewAircraftAvail(Window *w)
-{
-	EngineID engine;
-
-	DrawNewsBorder(w);
-
-	engine = WP(w,news_d).ni->string_id;
-
-	DrawStringMultiCenter(w->width >> 1, 20, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE, w->width - 2);
-	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
-
-	SetDParam(0, GetCustomEngineName(engine));
-	DrawStringMultiCenter(w->width >> 1, 57, STR_A02D, w->width - 2);
-
-	DrawAircraftEngine(w->width >> 1, 93, engine, 0);
-	GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE);
-	DrawAircraftEngineInfo(engine, w->width >> 1, 131, w->width - 52);
-}
-
-StringID GetNewsStringNewAircraftAvail(const NewsItem *ni)
-{
-	EngineID engine = ni->string_id;
-	SetDParam(0, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE);
-	SetDParam(1, GetCustomEngineName(engine));
-	return STR_02B6;
-}
-
-static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw)
-{
-	const RoadVehicleInfo *rvi = RoadVehInfo(engine);
-
-	SetDParam(0, (_price.roadveh_base >> 3) * rvi->base_cost >> 5);
-	SetDParam(1, rvi->max_speed / 2);
-	SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8);
-	SetDParam(3, rvi->cargo_type);
-	SetDParam(4, rvi->capacity);
-
-	DrawStringMultiCenter(x, y, STR_902A_COST_SPEED_RUNNING_COST, maxw);
-}
-
-void DrawNewsNewRoadVehAvail(Window *w)
-{
-	EngineID engine;
-
-	DrawNewsBorder(w);
-
-	engine = WP(w,news_d).ni->string_id;
-	DrawStringMultiCenter(w->width >> 1, 20, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE, w->width - 2);
-	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
-
-	SetDParam(0, GetCustomEngineName(engine));
-	DrawStringMultiCenter(w->width >> 1, 57, STR_9029, w->width - 2);
-
-	DrawRoadVehEngine(w->width >> 1, 88, engine, 0);
-	GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE);
-	DrawRoadVehEngineInfo(engine, w->width >> 1, 129, w->width - 52);
-}
-
-StringID GetNewsStringNewRoadVehAvail(const NewsItem *ni)
-{
-	EngineID engine = ni->string_id;
-	SetDParam(0, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE);
-	SetDParam(1, GetCustomEngineName(engine));
-	return STR_02B6;
-}
-
-static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw)
-{
-	const ShipVehicleInfo *svi = ShipVehInfo(engine);
-	SetDParam(0, svi->base_cost * (_price.ship_base >> 3) >> 5);
-	SetDParam(1, svi->max_speed / 2);
-	SetDParam(2, svi->cargo_type);
-	SetDParam(3, svi->capacity);
-	SetDParam(4, svi->running_cost * _price.ship_running >> 8);
-	DrawStringMultiCenter(x, y, STR_982E_COST_MAX_SPEED_CAPACITY, maxw);
-}
-
-void DrawNewsNewShipAvail(Window *w)
-{
-	EngineID engine;
-
-	DrawNewsBorder(w);
-
-	engine = WP(w,news_d).ni->string_id;
-
-	DrawStringMultiCenter(w->width >> 1, 20, STR_982C_NEW_SHIP_NOW_AVAILABLE, w->width - 2);
-	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
-
-	SetDParam(0, GetCustomEngineName(engine));
-	DrawStringMultiCenter(w->width >> 1, 57, STR_982D, w->width - 2);
-
-	DrawShipEngine(w->width >> 1, 93, engine, 0);
-	GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE);
-	DrawShipEngineInfo(engine, w->width >> 1, 131, w->width - 52);
-}
-
-StringID GetNewsStringNewShipAvail(const NewsItem *ni)
-{
-	EngineID engine = ni->string_id;
-	SetDParam(0, STR_982C_NEW_SHIP_NOW_AVAILABLE);
-	SetDParam(1, GetCustomEngineName(engine));
-	return STR_02B6;
-}
new file mode 100644
--- /dev/null
+++ b/src/engine_gui.cpp
@@ -0,0 +1,285 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "functions.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "engine.h"
+#include "command.h"
+#include "news.h"
+#include "variables.h"
+#include "newgrf_engine.h"
+
+
+static StringID GetEngineCategoryName(EngineID engine)
+{
+	if (engine < NUM_TRAIN_ENGINES) {
+		switch (GetEngine(engine)->railtype) {
+			case RAILTYPE_RAIL:     return STR_8102_RAILROAD_LOCOMOTIVE;
+			case RAILTYPE_ELECTRIC: return STR_8102_RAILROAD_LOCOMOTIVE;
+			case RAILTYPE_MONO:     return STR_8106_MONORAIL_LOCOMOTIVE;
+			case RAILTYPE_MAGLEV:   return STR_8107_MAGLEV_LOCOMOTIVE;
+		}
+	}
+
+	if (engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES)
+		return STR_8103_ROAD_VEHICLE;
+
+	if (engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES)
+		return STR_8105_SHIP;
+
+	return STR_8104_AIRCRAFT;
+}
+
+static const Widget _engine_preview_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,                                  STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   299,     0,    13, STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     5,     0,   299,    14,   191, 0x0,                                       STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     5,    85,   144,   172,   183, STR_00C9_NO,                               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     5,   155,   214,   172,   183, STR_00C8_YES,                              STR_NULL},
+{   WIDGETS_END},
+};
+
+typedef void DrawEngineProc(int x, int y, EngineID engine, uint32 image_ormod);
+typedef void DrawEngineInfoProc(EngineID, int x, int y, int maxw);
+
+typedef struct DrawEngineInfo {
+	DrawEngineProc *engine_proc;
+	DrawEngineInfoProc *info_proc;
+} DrawEngineInfo;
+
+static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw);
+static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw);
+static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw);
+static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw);
+
+static const DrawEngineInfo _draw_engine_list[4] = {
+	{DrawTrainEngine,DrawTrainEngineInfo},
+	{DrawRoadVehEngine,DrawRoadVehEngineInfo},
+	{DrawShipEngine,DrawShipEngineInfo},
+	{DrawAircraftEngine,DrawAircraftEngineInfo},
+};
+
+static void EnginePreviewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		EngineID engine = w->window_number;
+		const DrawEngineInfo* dei;
+		int width;
+
+		DrawWindowWidgets(w);
+
+		SetDParam(0, GetEngineCategoryName(engine));
+		DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
+
+		DrawStringCentered(w->width >> 1, 80, GetCustomEngineName(engine), 0x10);
+
+		(dei = _draw_engine_list,engine < NUM_TRAIN_ENGINES) ||
+		(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) ||
+		(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) ||
+		(dei++, true);
+
+		width = w->width;
+		dei->engine_proc(width >> 1, 100, engine, 0);
+		dei->info_proc(engine, width >> 1, 130, width - 52);
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 4:
+				DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
+				/* Fallthrough */
+			case 3:
+				DeleteWindow(w);
+				break;
+		}
+		break;
+	}
+}
+
+static const WindowDesc _engine_preview_desc = {
+	WDP_CENTER, WDP_CENTER, 300, 192,
+	WC_ENGINE_PREVIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_engine_preview_widgets,
+	EnginePreviewWndProc
+};
+
+
+void ShowEnginePreviewWindow(EngineID engine)
+{
+	AllocateWindowDescFront(&_engine_preview_desc, engine);
+}
+
+static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
+{
+	const RailVehicleInfo *rvi = RailVehInfo(engine);
+	uint multihead = (rvi->flags & RVI_MULTIHEAD) ? 1 : 0;
+
+	SetDParam(0, (_price.build_railvehicle >> 3) * rvi->base_cost >> 5);
+	SetDParam(2, rvi->max_speed);
+	SetDParam(3, rvi->power << multihead);
+	SetDParam(1, rvi->weight << multihead);
+
+	SetDParam(4, rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8 << multihead);
+
+	if (rvi->capacity != 0) {
+		SetDParam(5, rvi->cargo_type);
+		SetDParam(6, rvi->capacity << multihead);
+	} else {
+		SetDParam(5, CT_INVALID);
+	}
+	DrawStringMultiCenter(x, y, STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER, maxw);
+}
+
+void DrawNewsNewTrainAvail(Window *w)
+{
+	EngineID engine;
+
+	DrawNewsBorder(w);
+
+	engine = WP(w,news_d).ni->string_id;
+	SetDParam(0, GetEngineCategoryName(engine));
+	DrawStringMultiCenter(w->width >> 1, 20, STR_8859_NEW_NOW_AVAILABLE, w->width - 2);
+
+	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
+
+	SetDParam(0, GetCustomEngineName(engine));
+	DrawStringMultiCenter(w->width >> 1, 57, STR_885A, w->width - 2);
+
+	DrawTrainEngine(w->width >> 1, 88, engine, 0);
+	GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE);
+	DrawTrainEngineInfo(engine, w->width >> 1, 129, w->width - 52);
+}
+
+StringID GetNewsStringNewTrainAvail(const NewsItem *ni)
+{
+	EngineID engine = ni->string_id;
+	SetDParam(0, STR_8859_NEW_NOW_AVAILABLE);
+	SetDParam(1, GetEngineCategoryName(engine));
+	SetDParam(2, GetCustomEngineName(engine));
+	return STR_02B6;
+}
+
+static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw)
+{
+	const AircraftVehicleInfo *avi = AircraftVehInfo(engine);
+	SetDParam(0, (_price.aircraft_base >> 3) * avi->base_cost >> 5);
+	SetDParam(1, avi->max_speed * 128 / 10);
+	SetDParam(2, avi->passenger_capacity);
+	SetDParam(3, avi->mail_capacity);
+	SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
+
+	DrawStringMultiCenter(x, y, STR_A02E_COST_MAX_SPEED_CAPACITY, maxw);
+}
+
+void DrawNewsNewAircraftAvail(Window *w)
+{
+	EngineID engine;
+
+	DrawNewsBorder(w);
+
+	engine = WP(w,news_d).ni->string_id;
+
+	DrawStringMultiCenter(w->width >> 1, 20, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE, w->width - 2);
+	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
+
+	SetDParam(0, GetCustomEngineName(engine));
+	DrawStringMultiCenter(w->width >> 1, 57, STR_A02D, w->width - 2);
+
+	DrawAircraftEngine(w->width >> 1, 93, engine, 0);
+	GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE);
+	DrawAircraftEngineInfo(engine, w->width >> 1, 131, w->width - 52);
+}
+
+StringID GetNewsStringNewAircraftAvail(const NewsItem *ni)
+{
+	EngineID engine = ni->string_id;
+	SetDParam(0, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE);
+	SetDParam(1, GetCustomEngineName(engine));
+	return STR_02B6;
+}
+
+static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw)
+{
+	const RoadVehicleInfo *rvi = RoadVehInfo(engine);
+
+	SetDParam(0, (_price.roadveh_base >> 3) * rvi->base_cost >> 5);
+	SetDParam(1, rvi->max_speed / 2);
+	SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8);
+	SetDParam(3, rvi->cargo_type);
+	SetDParam(4, rvi->capacity);
+
+	DrawStringMultiCenter(x, y, STR_902A_COST_SPEED_RUNNING_COST, maxw);
+}
+
+void DrawNewsNewRoadVehAvail(Window *w)
+{
+	EngineID engine;
+
+	DrawNewsBorder(w);
+
+	engine = WP(w,news_d).ni->string_id;
+	DrawStringMultiCenter(w->width >> 1, 20, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE, w->width - 2);
+	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
+
+	SetDParam(0, GetCustomEngineName(engine));
+	DrawStringMultiCenter(w->width >> 1, 57, STR_9029, w->width - 2);
+
+	DrawRoadVehEngine(w->width >> 1, 88, engine, 0);
+	GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE);
+	DrawRoadVehEngineInfo(engine, w->width >> 1, 129, w->width - 52);
+}
+
+StringID GetNewsStringNewRoadVehAvail(const NewsItem *ni)
+{
+	EngineID engine = ni->string_id;
+	SetDParam(0, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE);
+	SetDParam(1, GetCustomEngineName(engine));
+	return STR_02B6;
+}
+
+static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw)
+{
+	const ShipVehicleInfo *svi = ShipVehInfo(engine);
+	SetDParam(0, svi->base_cost * (_price.ship_base >> 3) >> 5);
+	SetDParam(1, svi->max_speed / 2);
+	SetDParam(2, svi->cargo_type);
+	SetDParam(3, svi->capacity);
+	SetDParam(4, svi->running_cost * _price.ship_running >> 8);
+	DrawStringMultiCenter(x, y, STR_982E_COST_MAX_SPEED_CAPACITY, maxw);
+}
+
+void DrawNewsNewShipAvail(Window *w)
+{
+	EngineID engine;
+
+	DrawNewsBorder(w);
+
+	engine = WP(w,news_d).ni->string_id;
+
+	DrawStringMultiCenter(w->width >> 1, 20, STR_982C_NEW_SHIP_NOW_AVAILABLE, w->width - 2);
+	GfxFillRect(25, 56, w->width - 25, w->height - 2, 10);
+
+	SetDParam(0, GetCustomEngineName(engine));
+	DrawStringMultiCenter(w->width >> 1, 57, STR_982D, w->width - 2);
+
+	DrawShipEngine(w->width >> 1, 93, engine, 0);
+	GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE);
+	DrawShipEngineInfo(engine, w->width >> 1, 131, w->width - 52);
+}
+
+StringID GetNewsStringNewShipAvail(const NewsItem *ni)
+{
+	EngineID engine = ni->string_id;
+	SetDParam(0, STR_982C_NEW_SHIP_NOW_AVAILABLE);
+	SetDParam(1, GetCustomEngineName(engine));
+	return STR_02B6;
+}
deleted file mode 100644
--- a/src/fileio.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "fileio.h"
-#include "functions.h"
-#include "string.h"
-#include "macros.h"
-#include "variables.h"
-
-/*************************************************/
-/* FILE IO ROUTINES ******************************/
-/*************************************************/
-
-#define FIO_BUFFER_SIZE 512
-
-typedef struct {
-	byte *buffer, *buffer_end;          ///< position pointer in local buffer and last valid byte of buffer
-	uint32 pos;                         ///< current (system) position in file
-	FILE *cur_fh;                       ///< current file handle
-	FILE *handles[64];                  ///< array of file handles we can have open
-	byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file
-} Fio;
-
-static Fio _fio;
-
-// Get current position in file
-uint32 FioGetPos(void)
-{
-	return _fio.pos + (_fio.buffer - _fio.buffer_start) - FIO_BUFFER_SIZE;
-}
-
-void FioSeekTo(uint32 pos, int mode)
-{
-	if (mode == SEEK_CUR) pos += FioGetPos();
-	_fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE;
-	_fio.pos = pos;
-	fseek(_fio.cur_fh, _fio.pos, SEEK_SET);
-}
-
-// Seek to a file and a position
-void FioSeekToFile(uint32 pos)
-{
-	FILE *f = _fio.handles[pos >> 24];
-	assert(f != NULL);
-	_fio.cur_fh = f;
-	FioSeekTo(GB(pos, 0, 24), SEEK_SET);
-}
-
-byte FioReadByte(void)
-{
-	if (_fio.buffer == _fio.buffer_end) {
-		_fio.pos += FIO_BUFFER_SIZE;
-		fread(_fio.buffer = _fio.buffer_start, 1, FIO_BUFFER_SIZE, _fio.cur_fh);
-	}
-	return *_fio.buffer++;
-}
-
-void FioSkipBytes(int n)
-{
-	for (;;) {
-		int m = min(_fio.buffer_end - _fio.buffer, n);
-		_fio.buffer += m;
-		n -= m;
-		if (n == 0) break;
-		FioReadByte();
-		n--;
-	}
-}
-
-uint16 FioReadWord(void)
-{
-	byte b = FioReadByte();
-	return (FioReadByte() << 8) | b;
-}
-
-uint32 FioReadDword(void)
-{
-	uint b = FioReadWord();
-	return (FioReadWord() << 16) | b;
-}
-
-void FioReadBlock(void *ptr, uint size)
-{
-	FioSeekTo(FioGetPos(), SEEK_SET);
-	_fio.pos += size;
-	fread(ptr, 1, size, _fio.cur_fh);
-}
-
-static inline void FioCloseFile(int slot)
-{
-	if (_fio.handles[slot] != NULL) {
-		fclose(_fio.handles[slot]);
-		_fio.handles[slot] = NULL;
-	}
-}
-
-void FioCloseAll(void)
-{
-	int i;
-
-	for (i = 0; i != lengthof(_fio.handles); i++)
-		FioCloseFile(i);
-}
-
-bool FioCheckFileExists(const char *filename)
-{
-	FILE *f = FioFOpenFile(filename);
-	if (f == NULL) return false;
-
-	fclose(f);
-	return true;
-}
-
-FILE *FioFOpenFile(const char *filename)
-{
-	FILE *f;
-	char buf[MAX_PATH];
-
-	snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, filename);
-
-	f = fopen(buf, "rb");
-#if !defined(WIN32)
-	if (f == NULL) {
-		strtolower(buf + strlen(_paths.data_dir) - 1);
-		f = fopen(buf, "rb");
-
-#if defined SECOND_DATA_DIR
-		// tries in the 2nd data directory
-		if (f == NULL) {
-			snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, filename);
-			strtolower(buf + strlen(_paths.second_data_dir) - 1);
-			f = fopen(buf, "rb");
-		}
-#endif
-	}
-#endif
-
-	return f;
-}
-
-void FioOpenFile(int slot, const char *filename)
-{
-	FILE *f = FioFOpenFile(filename);
-
-	if (f == NULL) error("Cannot open file '%s%s'", _paths.data_dir, filename);
-
-	FioCloseFile(slot); // if file was opened before, close it
-	_fio.handles[slot] = f;
-	FioSeekToFile(slot << 24);
-}
new file mode 100644
--- /dev/null
+++ b/src/fileio.cpp
@@ -0,0 +1,151 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "fileio.h"
+#include "functions.h"
+#include "string.h"
+#include "macros.h"
+#include "variables.h"
+
+/*************************************************/
+/* FILE IO ROUTINES ******************************/
+/*************************************************/
+
+#define FIO_BUFFER_SIZE 512
+
+typedef struct {
+	byte *buffer, *buffer_end;          ///< position pointer in local buffer and last valid byte of buffer
+	uint32 pos;                         ///< current (system) position in file
+	FILE *cur_fh;                       ///< current file handle
+	FILE *handles[64];                  ///< array of file handles we can have open
+	byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file
+} Fio;
+
+static Fio _fio;
+
+// Get current position in file
+uint32 FioGetPos(void)
+{
+	return _fio.pos + (_fio.buffer - _fio.buffer_start) - FIO_BUFFER_SIZE;
+}
+
+void FioSeekTo(uint32 pos, int mode)
+{
+	if (mode == SEEK_CUR) pos += FioGetPos();
+	_fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE;
+	_fio.pos = pos;
+	fseek(_fio.cur_fh, _fio.pos, SEEK_SET);
+}
+
+// Seek to a file and a position
+void FioSeekToFile(uint32 pos)
+{
+	FILE *f = _fio.handles[pos >> 24];
+	assert(f != NULL);
+	_fio.cur_fh = f;
+	FioSeekTo(GB(pos, 0, 24), SEEK_SET);
+}
+
+byte FioReadByte(void)
+{
+	if (_fio.buffer == _fio.buffer_end) {
+		_fio.pos += FIO_BUFFER_SIZE;
+		fread(_fio.buffer = _fio.buffer_start, 1, FIO_BUFFER_SIZE, _fio.cur_fh);
+	}
+	return *_fio.buffer++;
+}
+
+void FioSkipBytes(int n)
+{
+	for (;;) {
+		int m = min(_fio.buffer_end - _fio.buffer, n);
+		_fio.buffer += m;
+		n -= m;
+		if (n == 0) break;
+		FioReadByte();
+		n--;
+	}
+}
+
+uint16 FioReadWord(void)
+{
+	byte b = FioReadByte();
+	return (FioReadByte() << 8) | b;
+}
+
+uint32 FioReadDword(void)
+{
+	uint b = FioReadWord();
+	return (FioReadWord() << 16) | b;
+}
+
+void FioReadBlock(void *ptr, uint size)
+{
+	FioSeekTo(FioGetPos(), SEEK_SET);
+	_fio.pos += size;
+	fread(ptr, 1, size, _fio.cur_fh);
+}
+
+static inline void FioCloseFile(int slot)
+{
+	if (_fio.handles[slot] != NULL) {
+		fclose(_fio.handles[slot]);
+		_fio.handles[slot] = NULL;
+	}
+}
+
+void FioCloseAll(void)
+{
+	int i;
+
+	for (i = 0; i != lengthof(_fio.handles); i++)
+		FioCloseFile(i);
+}
+
+bool FioCheckFileExists(const char *filename)
+{
+	FILE *f = FioFOpenFile(filename);
+	if (f == NULL) return false;
+
+	fclose(f);
+	return true;
+}
+
+FILE *FioFOpenFile(const char *filename)
+{
+	FILE *f;
+	char buf[MAX_PATH];
+
+	snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, filename);
+
+	f = fopen(buf, "rb");
+#if !defined(WIN32)
+	if (f == NULL) {
+		strtolower(buf + strlen(_paths.data_dir) - 1);
+		f = fopen(buf, "rb");
+
+#if defined SECOND_DATA_DIR
+		// tries in the 2nd data directory
+		if (f == NULL) {
+			snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, filename);
+			strtolower(buf + strlen(_paths.second_data_dir) - 1);
+			f = fopen(buf, "rb");
+		}
+#endif
+	}
+#endif
+
+	return f;
+}
+
+void FioOpenFile(int slot, const char *filename)
+{
+	FILE *f = FioFOpenFile(filename);
+
+	if (f == NULL) error("Cannot open file '%s%s'", _paths.data_dir, filename);
+
+	FioCloseFile(slot); // if file was opened before, close it
+	_fio.handles[slot] = f;
+	FioSeekToFile(slot << 24);
+}
deleted file mode 100644
--- a/src/fios.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/* $Id$ */
-
-/** @file fios.c
- * This file contains functions for building file lists for the save/load dialogs.
- */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "hal.h"
-#include "string.h"
-#include "variables.h"
-#include "functions.h"
-#include "heightmap.h"
-#include "table/strings.h"
-#include "fios.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef WIN32
-# include <io.h>
-#else
-# include <unistd.h>
-# include <dirent.h>
-#endif /* WIN32 */
-
-/* Variables to display file lists */
-int _fios_num;
-
-static char *_fios_path;
-static FiosItem *_fios_items;
-static int _fios_count, _fios_alloc;
-
-/* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
-extern bool FiosIsRoot(const char *path);
-extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
-extern void FiosGetDrives(void);
-extern bool FiosGetDiskFreeSpace(const char *path, uint32 *tot);
-
-/* get the name of an oldstyle savegame */
-extern void GetOldSaveGameName(char *title, const char *path, const char *file);
-
-/**
- * Allocate a new FiosItem.
- * @return A pointer to the newly allocated FiosItem.
- */
-FiosItem *FiosAlloc(void)
-{
-	if (_fios_count == _fios_alloc) {
-		_fios_alloc += 256;
-		_fios_items = realloc(_fios_items, _fios_alloc * sizeof(FiosItem));
-	}
-	return &_fios_items[_fios_count++];
-}
-
-/**
- * Compare two FiosItem's. Used with qsort when sorting the file list.
- * @param a A pointer to the first FiosItem to compare.
- * @param a A pointer to the second FiosItem to compare.
- * @return -1, 0 or 1, depending on how the two items should be sorted.
- */
-int CDECL compare_FiosItems(const void *a, const void *b)
-{
-	const FiosItem *da = (const FiosItem *)a;
-	const FiosItem *db = (const FiosItem *)b;
-	int r;
-
-	if (_savegame_sort_order & SORT_BY_NAME) {
-		r = strcasecmp(da->title, db->title);
-	} else {
-		r = da->mtime < db->mtime ? -1 : 1;
-	}
-
-	if (_savegame_sort_order & SORT_DESCENDING) r = -r;
-	return r;
-}
-
-/**
- * Free the list of savegames
- */
-void FiosFreeSavegameList(void)
-{
-	free(_fios_items);
-	_fios_items = NULL;
-	_fios_alloc = _fios_count = 0;
-}
-
-/**
- * Get descriptive texts. Returns the path and free space
- * left on the device
- * @param path string describing the path
- * @param total_free total free space in megabytes, optional (can be NULL)
- * @return StringID describing the path (free space or failure)
- */
-StringID FiosGetDescText(const char **path, uint32 *total_free)
-{
-	*path = _fios_path;
-	return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
-}
-
-/* Browse to a new path based on the passed FiosItem struct
- * @param *item FiosItem object telling us what to do
- * @return a string if we have given a file as a target, otherwise NULL */
-char *FiosBrowseTo(const FiosItem *item)
-{
-	char *s;
-	char *path = _fios_path;
-
-	switch (item->type) {
-#if defined(WIN32) || defined(__OS2__)
-	case FIOS_TYPE_DRIVE: sprintf(path, "%c:" PATHSEP, item->title[0]); break;
-#endif
-
-	case FIOS_TYPE_PARENT:
-		/* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */
-		if ((s = strrchr(path, PATHSEPCHAR)) != NULL) {
-			s[1] = '\0'; // go up a directory
-			if (!FiosIsRoot(path)) s[0] = '\0';
-		}
-#if defined(__MORPHOS__) || defined(__AMIGAOS__)
-		/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
-		else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
-#endif
-		break;
-
-	case FIOS_TYPE_DIR:
-		if (!FiosIsRoot(path)) strcat(path, PATHSEP);
-		strcat(path, item->name);
-		break;
-
-	case FIOS_TYPE_DIRECT:
-		sprintf(path, "%s" PATHSEP, item->name);
-		s = strrchr(path, PATHSEPCHAR);
-		if (s != NULL && s[1] == '\0') s[0] = '\0'; // strip trailing slash
-		break;
-
-	case FIOS_TYPE_FILE:
-	case FIOS_TYPE_OLDFILE:
-	case FIOS_TYPE_SCENARIO:
-	case FIOS_TYPE_OLD_SCENARIO:
-	case FIOS_TYPE_PNG:
-	case FIOS_TYPE_BMP:
-	{
-		static char str_buffr[512];
-
-#if defined(__MORPHOS__) || defined(__AMIGAOS__)
-		/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
-		if (FiosIsRoot(path)) {
-			snprintf(str_buffr, lengthof(str_buffr), "%s:%s", path, item->name);
-		} else // XXX - only next line!
-#endif
-		snprintf(str_buffr, lengthof(str_buffr), "%s" PATHSEP "%s", path, item->name);
-
-		return str_buffr;
-	}
-	}
-
-	return NULL;
-}
-
-void FiosMakeSavegameName(char *buf, const char *name, size_t size)
-{
-	const char *extension, *period;
-
-	extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
-
-	/* Don't append the extension if it is already there */
-	period = strrchr(name, '.');
-	if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
-
-	snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
-}
-
-#if defined(WIN32) || defined(WIN64)
-# define unlink _wunlink
-#endif
-
-bool FiosDelete(const char *name)
-{
-	char filename[512];
-
-	FiosMakeSavegameName(filename, name, lengthof(filename));
-	return unlink(OTTD2FS(filename)) == 0;
-}
-
-bool FileExists(const char *filename)
-{
-	return access(filename, 0) == 0;
-}
-
-typedef byte fios_getlist_callback_proc(int mode, const char *filename, const char *ext, char *title);
-
-/** Create a list of the files in a directory, according to some arbitrary rule.
- *  @param num Will be filled with the amount of items.
- *  @param mode The mode we are in. Some modes don't allow 'parent'.
- *  @param callback The function that is called where you need to do the filtering.
- *  @return Return the list of files. */
-static FiosItem *FiosGetFileList(int mode, fios_getlist_callback_proc *callback_proc)
-{
-	struct stat sb;
-	struct dirent *dirent;
-	DIR *dir;
-	FiosItem *fios;
-	int sort_start;
-
-	/* A parent directory link exists if we are not in the root directory */
-	if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
-		fios = FiosAlloc();
-		fios->type = FIOS_TYPE_PARENT;
-		fios->mtime = 0;
-		ttd_strlcpy(fios->name, "..", lengthof(fios->name));
-		ttd_strlcpy(fios->title, ".. (Parent directory)", lengthof(fios->title));
-	}
-
-	/* Show subdirectories */
-	if (mode != SLD_NEW_GAME && (dir = opendir(_fios_path)) != NULL) {
-		while ((dirent = readdir(dir)) != NULL) {
-			const char *d_name = FS2OTTD(dirent->d_name);
-
-			/* found file must be directory, but not '.' or '..' */
-			if (FiosIsValidFile(_fios_path, dirent, &sb) && (sb.st_mode & S_IFDIR) &&
-				strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
-				fios = FiosAlloc();
-				fios->type = FIOS_TYPE_DIR;
-				fios->mtime = 0;
-				ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
-				snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
-				str_validate(fios->title);
-			}
-		}
-		closedir(dir);
-	}
-
-	/* Sort the subdirs always by name, ascending, remember user-sorting order */
-	{
-		byte order = _savegame_sort_order;
-		_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
-		qsort(_fios_items, _fios_count, sizeof(FiosItem), compare_FiosItems);
-		_savegame_sort_order = order;
-	}
-
-	/* This is where to start sorting for the filenames */
-	sort_start = _fios_count;
-
-	/* Show files */
-	dir = opendir(_fios_path);
-	if (dir != NULL) {
-		while ((dirent = readdir(dir)) != NULL) {
-			char fios_title[64];
-			char *t;
-			char *d_name = (char*)FS2OTTD(dirent->d_name);
-			byte type;
-
-			if (!FiosIsValidFile(_fios_path, dirent, &sb) || !(sb.st_mode & S_IFREG)) continue;
-
-			/* File has no extension, skip it */
-			if ((t = strrchr(d_name, '.')) == NULL) continue;
-			fios_title[0] = '\0'; // reset the title;
-
-			type = callback_proc(mode, d_name, t, fios_title);
-			if (type != FIOS_TYPE_INVALID) {
-				fios = FiosAlloc();
-				fios->mtime = sb.st_mtime;
-				fios->type = type;
-				ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
-
-				/* Some callbacks want to lookup the title of the file. Allow that.
-				 * If we just copy the title from the filename, strip the extension */
-				t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
-				ttd_strlcpy(fios->title, t, lengthof(fios->title));
-				str_validate(fios->title);
-			}
-		}
-		closedir(dir);
-	}
-
-	qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
-
-	/* Show drives */
-	if (mode != SLD_NEW_GAME) FiosGetDrives();
-
-	_fios_num = _fios_count;
-	return _fios_items;
-}
-
-/**
- * Callback for FiosGetFileList. It tells if a file is a savegame or not.
- * @param mode Save/load mode.
- * @param file Name of the file to check.
- * @param ext A pointer to the extension identifier inside file
- * @param title Buffer if a callback wants to lookup the title of the file
- * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame
- * @see FiosGetFileList
- * @see FiosGetSavegameList
- */
-static byte FiosGetSavegameListCallback(int mode, const char *file, const char *ext, char *title)
-{
-	/* Show savegame files
-	 * .SAV OpenTTD saved game
-	 * .SS1 Transport Tycoon Deluxe preset game
-	 * .SV1 Transport Tycoon Deluxe (Patch) saved game
-	 * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
-	if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
-
-	if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
-		if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
-				strcasecmp(ext, ".sv2") == 0) {
-			GetOldSaveGameName(title, _fios_path, file);
-			return FIOS_TYPE_OLDFILE;
-		}
-	}
-
-	return FIOS_TYPE_INVALID;
-}
-
-/**
- * Get a list of savegames.
- * @param mode Save/load mode.
- * @return A pointer to an array of FiosItem representing all the files to be shown in the save/load dialog.
- * @see FiosGetFileList
- */
-FiosItem *FiosGetSavegameList(int mode)
-{
-	static char *_fios_save_path = NULL;
-
-	if (_fios_save_path == NULL) {
-		_fios_save_path = malloc(MAX_PATH);
-		ttd_strlcpy(_fios_save_path, _paths.save_dir, MAX_PATH);
-	}
-
-	_fios_path = _fios_save_path;
-
-	return FiosGetFileList(mode, &FiosGetSavegameListCallback);
-}
-
-/**
- * Callback for FiosGetFileList. It tells if a file is a scenario or not.
- * @param mode Save/load mode.
- * @param file Name of the file to check.
- * @param ext A pointer to the extension identifier inside file
- * @param title Buffer if a callback wants to lookup the title of the file
- * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a scenario
- * @see FiosGetFileList
- * @see FiosGetScenarioList
- */
-static byte FiosGetScenarioListCallback(int mode, const char *file, const char *ext, char *title)
-{
-	/* Show scenario files
-	 * .SCN OpenTTD style scenario file
-	 * .SV0 Transport Tycoon Deluxe (Patch) scenario
-	 * .SS0 Transport Tycoon Deluxe preset scenario */
-	if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
-
-	if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
-		if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
-			GetOldSaveGameName(title, _fios_path, file);
-			return FIOS_TYPE_OLD_SCENARIO;
-		}
-	}
-
-	return FIOS_TYPE_INVALID;
-}
-
-/**
- * Get a list of scenarios.
- * @param mode Save/load mode.
- * @return A pointer to an array of FiosItem representing all the files to be shown in the save/load dialog.
- * @see FiosGetFileList
- */
-FiosItem *FiosGetScenarioList(int mode)
-{
-	static char *_fios_scn_path = NULL;
-
-	if (_fios_scn_path == NULL) {
-		_fios_scn_path = malloc(MAX_PATH);
-		ttd_strlcpy(_fios_scn_path, _paths.scenario_dir, MAX_PATH);
-	}
-
-	_fios_path = _fios_scn_path;
-
-	return FiosGetFileList(mode, &FiosGetScenarioListCallback);
-}
-
-static byte FiosGetHeightmapListCallback(int mode, const char *file, const char *ext, char *title)
-{
-	/* Show heightmap files
-	 * .PNG PNG Based heightmap files
-	 * .BMP BMP Based heightmap files
-	 */
-
-#ifdef WITH_PNG
-	if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
-#endif /* WITH_PNG */
-
-	if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
-
-	return FIOS_TYPE_INVALID;
-}
-
-// Get a list of Heightmaps
-FiosItem *FiosGetHeightmapList(int mode)
-{
-	static char *_fios_hmap_path = NULL;
-
-	if (_fios_hmap_path == NULL) {
-		_fios_hmap_path = malloc(MAX_PATH);
-		strcpy(_fios_hmap_path, _paths.heightmap_dir);
-	}
-
-	_fios_path = _fios_hmap_path;
-
-	return FiosGetFileList(mode, &FiosGetHeightmapListCallback);
-}
new file mode 100644
--- /dev/null
+++ b/src/fios.cpp
@@ -0,0 +1,412 @@
+/* $Id$ */
+
+/** @file fios.c
+ * This file contains functions for building file lists for the save/load dialogs.
+ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "hal.h"
+#include "string.h"
+#include "variables.h"
+#include "functions.h"
+#include "heightmap.h"
+#include "table/strings.h"
+#include "fios.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <dirent.h>
+#endif /* WIN32 */
+
+/* Variables to display file lists */
+int _fios_num;
+
+static char *_fios_path;
+static FiosItem *_fios_items;
+static int _fios_count, _fios_alloc;
+
+/* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
+extern bool FiosIsRoot(const char *path);
+extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
+extern void FiosGetDrives(void);
+extern bool FiosGetDiskFreeSpace(const char *path, uint32 *tot);
+
+/* get the name of an oldstyle savegame */
+extern void GetOldSaveGameName(char *title, const char *path, const char *file);
+
+/**
+ * Allocate a new FiosItem.
+ * @return A pointer to the newly allocated FiosItem.
+ */
+FiosItem *FiosAlloc(void)
+{
+	if (_fios_count == _fios_alloc) {
+		_fios_alloc += 256;
+		_fios_items = realloc(_fios_items, _fios_alloc * sizeof(FiosItem));
+	}
+	return &_fios_items[_fios_count++];
+}
+
+/**
+ * Compare two FiosItem's. Used with qsort when sorting the file list.
+ * @param a A pointer to the first FiosItem to compare.
+ * @param a A pointer to the second FiosItem to compare.
+ * @return -1, 0 or 1, depending on how the two items should be sorted.
+ */
+int CDECL compare_FiosItems(const void *a, const void *b)
+{
+	const FiosItem *da = (const FiosItem *)a;
+	const FiosItem *db = (const FiosItem *)b;
+	int r;
+
+	if (_savegame_sort_order & SORT_BY_NAME) {
+		r = strcasecmp(da->title, db->title);
+	} else {
+		r = da->mtime < db->mtime ? -1 : 1;
+	}
+
+	if (_savegame_sort_order & SORT_DESCENDING) r = -r;
+	return r;
+}
+
+/**
+ * Free the list of savegames
+ */
+void FiosFreeSavegameList(void)
+{
+	free(_fios_items);
+	_fios_items = NULL;
+	_fios_alloc = _fios_count = 0;
+}
+
+/**
+ * Get descriptive texts. Returns the path and free space
+ * left on the device
+ * @param path string describing the path
+ * @param total_free total free space in megabytes, optional (can be NULL)
+ * @return StringID describing the path (free space or failure)
+ */
+StringID FiosGetDescText(const char **path, uint32 *total_free)
+{
+	*path = _fios_path;
+	return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
+}
+
+/* Browse to a new path based on the passed FiosItem struct
+ * @param *item FiosItem object telling us what to do
+ * @return a string if we have given a file as a target, otherwise NULL */
+char *FiosBrowseTo(const FiosItem *item)
+{
+	char *s;
+	char *path = _fios_path;
+
+	switch (item->type) {
+#if defined(WIN32) || defined(__OS2__)
+	case FIOS_TYPE_DRIVE: sprintf(path, "%c:" PATHSEP, item->title[0]); break;
+#endif
+
+	case FIOS_TYPE_PARENT:
+		/* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */
+		if ((s = strrchr(path, PATHSEPCHAR)) != NULL) {
+			s[1] = '\0'; // go up a directory
+			if (!FiosIsRoot(path)) s[0] = '\0';
+		}
+#if defined(__MORPHOS__) || defined(__AMIGAOS__)
+		/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
+		else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
+#endif
+		break;
+
+	case FIOS_TYPE_DIR:
+		if (!FiosIsRoot(path)) strcat(path, PATHSEP);
+		strcat(path, item->name);
+		break;
+
+	case FIOS_TYPE_DIRECT:
+		sprintf(path, "%s" PATHSEP, item->name);
+		s = strrchr(path, PATHSEPCHAR);
+		if (s != NULL && s[1] == '\0') s[0] = '\0'; // strip trailing slash
+		break;
+
+	case FIOS_TYPE_FILE:
+	case FIOS_TYPE_OLDFILE:
+	case FIOS_TYPE_SCENARIO:
+	case FIOS_TYPE_OLD_SCENARIO:
+	case FIOS_TYPE_PNG:
+	case FIOS_TYPE_BMP:
+	{
+		static char str_buffr[512];
+
+#if defined(__MORPHOS__) || defined(__AMIGAOS__)
+		/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
+		if (FiosIsRoot(path)) {
+			snprintf(str_buffr, lengthof(str_buffr), "%s:%s", path, item->name);
+		} else // XXX - only next line!
+#endif
+		snprintf(str_buffr, lengthof(str_buffr), "%s" PATHSEP "%s", path, item->name);
+
+		return str_buffr;
+	}
+	}
+
+	return NULL;
+}
+
+void FiosMakeSavegameName(char *buf, const char *name, size_t size)
+{
+	const char *extension, *period;
+
+	extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
+
+	/* Don't append the extension if it is already there */
+	period = strrchr(name, '.');
+	if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
+
+	snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
+}
+
+#if defined(WIN32) || defined(WIN64)
+# define unlink _wunlink
+#endif
+
+bool FiosDelete(const char *name)
+{
+	char filename[512];
+
+	FiosMakeSavegameName(filename, name, lengthof(filename));
+	return unlink(OTTD2FS(filename)) == 0;
+}
+
+bool FileExists(const char *filename)
+{
+	return access(filename, 0) == 0;
+}
+
+typedef byte fios_getlist_callback_proc(int mode, const char *filename, const char *ext, char *title);
+
+/** Create a list of the files in a directory, according to some arbitrary rule.
+ *  @param num Will be filled with the amount of items.
+ *  @param mode The mode we are in. Some modes don't allow 'parent'.
+ *  @param callback The function that is called where you need to do the filtering.
+ *  @return Return the list of files. */
+static FiosItem *FiosGetFileList(int mode, fios_getlist_callback_proc *callback_proc)
+{
+	struct stat sb;
+	struct dirent *dirent;
+	DIR *dir;
+	FiosItem *fios;
+	int sort_start;
+
+	/* A parent directory link exists if we are not in the root directory */
+	if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
+		fios = FiosAlloc();
+		fios->type = FIOS_TYPE_PARENT;
+		fios->mtime = 0;
+		ttd_strlcpy(fios->name, "..", lengthof(fios->name));
+		ttd_strlcpy(fios->title, ".. (Parent directory)", lengthof(fios->title));
+	}
+
+	/* Show subdirectories */
+	if (mode != SLD_NEW_GAME && (dir = opendir(_fios_path)) != NULL) {
+		while ((dirent = readdir(dir)) != NULL) {
+			const char *d_name = FS2OTTD(dirent->d_name);
+
+			/* found file must be directory, but not '.' or '..' */
+			if (FiosIsValidFile(_fios_path, dirent, &sb) && (sb.st_mode & S_IFDIR) &&
+				strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
+				fios = FiosAlloc();
+				fios->type = FIOS_TYPE_DIR;
+				fios->mtime = 0;
+				ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
+				snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
+				str_validate(fios->title);
+			}
+		}
+		closedir(dir);
+	}
+
+	/* Sort the subdirs always by name, ascending, remember user-sorting order */
+	{
+		byte order = _savegame_sort_order;
+		_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
+		qsort(_fios_items, _fios_count, sizeof(FiosItem), compare_FiosItems);
+		_savegame_sort_order = order;
+	}
+
+	/* This is where to start sorting for the filenames */
+	sort_start = _fios_count;
+
+	/* Show files */
+	dir = opendir(_fios_path);
+	if (dir != NULL) {
+		while ((dirent = readdir(dir)) != NULL) {
+			char fios_title[64];
+			char *t;
+			char *d_name = (char*)FS2OTTD(dirent->d_name);
+			byte type;
+
+			if (!FiosIsValidFile(_fios_path, dirent, &sb) || !(sb.st_mode & S_IFREG)) continue;
+
+			/* File has no extension, skip it */
+			if ((t = strrchr(d_name, '.')) == NULL) continue;
+			fios_title[0] = '\0'; // reset the title;
+
+			type = callback_proc(mode, d_name, t, fios_title);
+			if (type != FIOS_TYPE_INVALID) {
+				fios = FiosAlloc();
+				fios->mtime = sb.st_mtime;
+				fios->type = type;
+				ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
+
+				/* Some callbacks want to lookup the title of the file. Allow that.
+				 * If we just copy the title from the filename, strip the extension */
+				t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
+				ttd_strlcpy(fios->title, t, lengthof(fios->title));
+				str_validate(fios->title);
+			}
+		}
+		closedir(dir);
+	}
+
+	qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
+
+	/* Show drives */
+	if (mode != SLD_NEW_GAME) FiosGetDrives();
+
+	_fios_num = _fios_count;
+	return _fios_items;
+}
+
+/**
+ * Callback for FiosGetFileList. It tells if a file is a savegame or not.
+ * @param mode Save/load mode.
+ * @param file Name of the file to check.
+ * @param ext A pointer to the extension identifier inside file
+ * @param title Buffer if a callback wants to lookup the title of the file
+ * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame
+ * @see FiosGetFileList
+ * @see FiosGetSavegameList
+ */
+static byte FiosGetSavegameListCallback(int mode, const char *file, const char *ext, char *title)
+{
+	/* Show savegame files
+	 * .SAV OpenTTD saved game
+	 * .SS1 Transport Tycoon Deluxe preset game
+	 * .SV1 Transport Tycoon Deluxe (Patch) saved game
+	 * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
+	if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
+
+	if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
+		if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
+				strcasecmp(ext, ".sv2") == 0) {
+			GetOldSaveGameName(title, _fios_path, file);
+			return FIOS_TYPE_OLDFILE;
+		}
+	}
+
+	return FIOS_TYPE_INVALID;
+}
+
+/**
+ * Get a list of savegames.
+ * @param mode Save/load mode.
+ * @return A pointer to an array of FiosItem representing all the files to be shown in the save/load dialog.
+ * @see FiosGetFileList
+ */
+FiosItem *FiosGetSavegameList(int mode)
+{
+	static char *_fios_save_path = NULL;
+
+	if (_fios_save_path == NULL) {
+		_fios_save_path = malloc(MAX_PATH);
+		ttd_strlcpy(_fios_save_path, _paths.save_dir, MAX_PATH);
+	}
+
+	_fios_path = _fios_save_path;
+
+	return FiosGetFileList(mode, &FiosGetSavegameListCallback);
+}
+
+/**
+ * Callback for FiosGetFileList. It tells if a file is a scenario or not.
+ * @param mode Save/load mode.
+ * @param file Name of the file to check.
+ * @param ext A pointer to the extension identifier inside file
+ * @param title Buffer if a callback wants to lookup the title of the file
+ * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a scenario
+ * @see FiosGetFileList
+ * @see FiosGetScenarioList
+ */
+static byte FiosGetScenarioListCallback(int mode, const char *file, const char *ext, char *title)
+{
+	/* Show scenario files
+	 * .SCN OpenTTD style scenario file
+	 * .SV0 Transport Tycoon Deluxe (Patch) scenario
+	 * .SS0 Transport Tycoon Deluxe preset scenario */
+	if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
+
+	if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
+		if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
+			GetOldSaveGameName(title, _fios_path, file);
+			return FIOS_TYPE_OLD_SCENARIO;
+		}
+	}
+
+	return FIOS_TYPE_INVALID;
+}
+
+/**
+ * Get a list of scenarios.
+ * @param mode Save/load mode.
+ * @return A pointer to an array of FiosItem representing all the files to be shown in the save/load dialog.
+ * @see FiosGetFileList
+ */
+FiosItem *FiosGetScenarioList(int mode)
+{
+	static char *_fios_scn_path = NULL;
+
+	if (_fios_scn_path == NULL) {
+		_fios_scn_path = malloc(MAX_PATH);
+		ttd_strlcpy(_fios_scn_path, _paths.scenario_dir, MAX_PATH);
+	}
+
+	_fios_path = _fios_scn_path;
+
+	return FiosGetFileList(mode, &FiosGetScenarioListCallback);
+}
+
+static byte FiosGetHeightmapListCallback(int mode, const char *file, const char *ext, char *title)
+{
+	/* Show heightmap files
+	 * .PNG PNG Based heightmap files
+	 * .BMP BMP Based heightmap files
+	 */
+
+#ifdef WITH_PNG
+	if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
+#endif /* WITH_PNG */
+
+	if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
+
+	return FIOS_TYPE_INVALID;
+}
+
+// Get a list of Heightmaps
+FiosItem *FiosGetHeightmapList(int mode)
+{
+	static char *_fios_hmap_path = NULL;
+
+	if (_fios_hmap_path == NULL) {
+		_fios_hmap_path = malloc(MAX_PATH);
+		strcpy(_fios_hmap_path, _paths.heightmap_dir);
+	}
+
+	_fios_path = _fios_hmap_path;
+
+	return FiosGetFileList(mode, &FiosGetHeightmapListCallback);
+}
deleted file mode 100644
--- a/src/fontcache.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "macros.h"
-#include "debug.h"
-#include "table/sprites.h"
-#include "table/control_codes.h"
-#include "spritecache.h"
-#include "gfx.h"
-#include "string.h"
-#include "fontcache.h"
-
-#ifdef WITH_FREETYPE
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-
-#ifdef WITH_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#endif
-
-static FT_Library _library = NULL;
-static FT_Face _face_small = NULL;
-static FT_Face _face_medium = NULL;
-static FT_Face _face_large = NULL;
-
-FreeTypeSettings _freetype;
-
-enum {
-	FACE_COLOUR = 1,
-	SHADOW_COLOUR = 2,
-};
-
-/** Get the font loaded into a Freetype face by using a font-name.
- * If no appropiate font is found, the function returns an error */
-#ifdef WIN32
-#include <windows.h>
-#include <tchar.h>
-#include <shlobj.h> // SHGetFolderPath
-#include "win32.h"
-
-/* Get the font file to be loaded into Freetype by looping the registry
- * location where windows lists all installed fonts. Not very nice, will
- * surely break if the registry path changes, but it works. Much better
- * solution would be to use CreateFont, and extract the font data from it
- * by GetFontData. The problem with this is that the font file needs to be
- * kept in memory then until the font is no longer needed. This could mean
- * an additional memory usage of 30MB (just for fonts!) when using an eastern
- * font for all font sizes */
-#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
-#define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
-static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
-{
-	FT_Error err = FT_Err_Cannot_Open_Resource;
-	HKEY hKey;
-	LONG ret;
-	TCHAR vbuffer[MAX_PATH], dbuffer[256];
-	TCHAR *font_namep;
-	char *font_path;
-	uint index;
-
-	/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
-	 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
-	 * to retrieve the windows version, we'll just query both */
-	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
-	if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
-
-	if (ret != ERROR_SUCCESS) {
-		DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
-		return err;
-	}
-
-	/* For Unicode we need some conversion between widechar and
-	 * normal char to match the data returned by RegEnumValue,
-	 * otherwise just use parameter */
-#if defined(UNICODE)
-	font_namep = malloc(MAX_PATH * sizeof(TCHAR));
-	MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
-#else
-	font_namep = (char*)font_name; // only cast because in unicode pointer is not const
-#endif
-
-	for (index = 0;; index++) {
-		TCHAR *s;
-		DWORD vbuflen = lengthof(vbuffer);
-		DWORD dbuflen = lengthof(dbuffer);
-
-		ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
-		if (ret != ERROR_SUCCESS) goto registry_no_font_found;
-
-		/* The font names in the registry are of the following 3 forms:
-		 * - ADMUI3.fon
-		 * - Book Antiqua Bold (TrueType)
-		 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
-		 * We will strip the font-type '()' if any and work with the font name
-		 * itself, which must match exactly; if...
-		 * TTC files, font files which contain more than one font are seperated
-		 * byt '&'. Our best bet will be to do substr match for the fontname
-		 * and then let FreeType figure out which index to load */
-		s = _tcschr(vbuffer, _T('('));
-		if (s != NULL) s[-1] = '\0';
-
-		if (_tcschr(vbuffer, _T('&')) == NULL) {
-			if (_tcsicmp(vbuffer, font_namep) == 0) break;
-		} else {
-			if (_tcsstr(vbuffer, font_namep) != NULL) break;
-		}
-	}
-
-	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
-		DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
-		goto folder_error;
-	}
-
-	/* Some fonts are contained in .ttc files, TrueType Collection fonts. These
-	 * contain multiple fonts inside this single file. GetFontData however
-	 * returns the whole file, so we need to check each font inside to get the
-	 * proper font.
-	 * Also note that FreeType does not support UNICODE filesnames! */
-#if defined(UNICODE)
-	/* We need a cast here back from wide because FreeType doesn't support
-	 * widechar filenames. Just use the buffer we allocated before for the
-	 * font_name search */
-	font_path = (char*)font_namep;
-	WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
-#else
-	font_path = vbuffer;
-#endif
-
-	ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
-	ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
-	index = 0;
-	do {
-		err = FT_New_Face(_library, font_path, index, face);
-		if (err != FT_Err_Ok) break;
-
-		if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
-		err = FT_Err_Cannot_Open_Resource;
-
-	} while ((FT_Long)++index != (*face)->num_faces);
-
-
-folder_error:
-#if defined(UNICODE)
-	free(font_path);
-#endif
-registry_no_font_found:
-	RegCloseKey(hKey);
-	return err;
-}
-#else
-# ifdef WITH_FONTCONFIG
-static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
-{
-	FT_Error err = FT_Err_Cannot_Open_Resource;
-
-	if (!FcInit()) {
-		ShowInfoF("Unable to load font configuration");
-	} else {
-		FcPattern *match;
-		FcPattern *pat;
-		FcFontSet *fs;
-		FcResult  result;
-		char *font_style;
-		char *font_family;
-
-		/* Split & strip the font's style */
-		font_family = strdup(font_name);
-		font_style = strchr(font_family, ',');
-		if (font_style != NULL) {
-			font_style[0] = '\0';
-			font_style++;
-			while (*font_style == ' ' || *font_style == '\t') font_style++;
-		}
-
-		/* Resolve the name and populate the information structure */
-		pat = FcNameParse((FcChar8*)font_family);
-		if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
-		FcConfigSubstitute(0, pat, FcMatchPattern);
-		FcDefaultSubstitute(pat);
-		fs = FcFontSetCreate();
-		match = FcFontMatch(0, pat, &result);
-
-		if (fs != NULL && match != NULL) {
-			int i;
-			FcChar8 *family;
-			FcChar8 *style;
-			FcChar8 *file;
-			FcFontSetAdd(fs, match);
-
-			for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
-				/* Try the new filename */
-				if (FcPatternGetString(fs->fonts[i], FC_FILE,   0, &file)   == FcResultMatch &&
-						FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
-						FcPatternGetString(fs->fonts[i], FC_STYLE,  0, &style)  == FcResultMatch) {
-
-					/* The correct style? */
-					if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
-
-					/* Font config takes the best shot, which, if the family name is spelled
-					* wrongly a 'random' font, so check whether the family name is the
-					* same as the supplied name */
-					if (strcasecmp(font_family, (char*)family) == 0) {
-						err = FT_New_Face(_library, (char *)file, 0, face);
-					}
-				}
-			}
-		}
-
-		free(font_family);
-		FcPatternDestroy(pat);
-		FcFontSetDestroy(fs);
-		FcFini();
-	}
-
-	return err;
-}
-# else
-FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
-# endif /* WITH_FONTCONFIG */
-
-#endif
-
-/**
- * Loads the freetype font.
- * First type to load the fontname as if it were a path. If that fails,
- * try to resolve the filename of the font using fontconfig, where the
- * format is 'font family name' or 'font family name, font style'.
- */
-static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
-{
-	FT_Error error;
-
-	if (strlen(font_name) == 0) return;
-
-	error = FT_New_Face(_library, font_name, 0, face);
-
-	if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, face);
-
-	if (error == FT_Err_Ok) {
-		DEBUG(freetype, 2, "Requested '%s', using '%s %s'", font_name, (*face)->family_name, (*face)->style_name);
-
-		/* Attempt to select the unicode character map */
-		error = FT_Select_Charmap(*face, ft_encoding_unicode);
-		if (error == FT_Err_Ok) return; // Success
-
-		if (error == FT_Err_Invalid_CharMap_Handle) {
-			/* Try to pick a different character map instead. We default to
-			 * the first map, but platform_id 0 encoding_id 0 should also
-			 * be unicode (strange system...) */
-			FT_CharMap found = (*face)->charmaps[0];
-			int i;
-
-			for (i = 0; i < (*face)->num_charmaps; i++) {
-				FT_CharMap charmap = (*face)->charmaps[i];
-				if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
-					found = charmap;
-				}
-			}
-
-			if (found != NULL) {
-				error = FT_Set_Charmap(*face, found);
-				if (error == FT_Err_Ok) return;
-			}
-		}
-	}
-
-	FT_Done_Face(*face);
-	*face = NULL;
-
-	ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
-}
-
-
-void InitFreeType(void)
-{
-	if (strlen(_freetype.small_font) == 0 && strlen(_freetype.medium_font) == 0 && strlen(_freetype.large_font) == 0) {
-		DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
-		return;
-	}
-
-	if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
-		ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
-		return;
-	}
-
-	DEBUG(freetype, 2, "Initialized");
-
-	/* Load each font */
-	LoadFreeTypeFont(_freetype.small_font,  &_face_small,  "small");
-	LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
-	LoadFreeTypeFont(_freetype.large_font,  &_face_large,  "large");
-
-	/* Set each font size */
-	if (_face_small  != NULL) FT_Set_Pixel_Sizes(_face_small,  0, _freetype.small_size);
-	if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
-	if (_face_large  != NULL) FT_Set_Pixel_Sizes(_face_large,  0, _freetype.large_size);
-}
-
-
-static FT_Face GetFontFace(FontSize size)
-{
-	switch (size) {
-		default: NOT_REACHED();
-		case FS_NORMAL: return _face_medium;
-		case FS_SMALL:  return _face_small;
-		case FS_LARGE:  return _face_large;
-	}
-}
-
-
-typedef struct GlyphEntry {
-	Sprite *sprite;
-	byte width;
-} GlyphEntry;
-
-
-/* The glyph cache. This is structured to reduce memory consumption.
- * 1) There is a 'segment' table for each font size.
- * 2) Each segment table is a discrete block of characters.
- * 3) Each block contains 256 (aligned) characters sequential characters.
- *
- * The cache is accessed in the following way:
- * For character 0x0041  ('A'): _glyph_ptr[FS_NORMAL][0x00][0x41]
- * For character 0x20AC (Euro): _glyph_ptr[FS_NORMAL][0x20][0xAC]
- *
- * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
- * This can be simply changed in the two functions Get & SetGlyphPtr.
- */
-static GlyphEntry **_glyph_ptr[FS_END];
-
-
-static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
-{
-	if (_glyph_ptr[size] == NULL) return NULL;
-	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
-	return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
-}
-
-
-static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
-{
-	if (_glyph_ptr[size] == NULL) {
-		DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
-		_glyph_ptr[size] = calloc(256, sizeof(**_glyph_ptr));
-	}
-
-	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
-		DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
-		_glyph_ptr[size][GB(key, 8, 8)] = calloc(256, sizeof(***_glyph_ptr));
-	}
-
-	DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
-	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
-	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width  = glyph->width;
-}
-
-
-const Sprite *GetGlyph(FontSize size, WChar key)
-{
-	FT_Face face = GetFontFace(size);
-	FT_GlyphSlot slot;
-	GlyphEntry new_glyph;
-	GlyphEntry *glyph;
-	Sprite *sprite;
-	int width;
-	int height;
-	int x;
-	int y;
-	int y_adj;
-
-	assert(IsPrintable(key));
-
-	/* Bail out if no face loaded, or for our special characters */
-	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
-		SpriteID sprite = GetUnicodeGlyph(size, key);
-		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
-		return GetSprite(sprite);
-	}
-
-	/* Check for the glyph in our cache */
-	glyph = GetGlyphPtr(size, key);
-	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
-
-	slot = face->glyph;
-
-	FT_Load_Char(face, key, FT_LOAD_DEFAULT);
-	FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
-
-	/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
-	width  = max(1, slot->bitmap.width + (size == FS_NORMAL));
-	height = max(1, slot->bitmap.rows  + (size == FS_NORMAL));
-
-	/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
-	sprite = calloc(width * height + 8, 1);
-	sprite->info   = 1;
-	sprite->width  = width;
-	sprite->height = height;
-	sprite->x_offs = slot->bitmap_left;
-	// XXX 2 should be determined somehow... it's right for the normal face
-	y_adj = (size == FS_NORMAL) ? 2 : 0;
-	sprite->y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
-
-	/* Draw shadow for medium size */
-	if (size == FS_NORMAL) {
-		for (y = 0; y < slot->bitmap.rows; y++) {
-			for (x = 0; x < slot->bitmap.width; x++) {
-				if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
-					sprite->data[1 + x + (1 + y) * sprite->width] = SHADOW_COLOUR;
-				}
-			}
-		}
-	}
-
-	for (y = 0; y < slot->bitmap.rows; y++) {
-		for (x = 0; x < slot->bitmap.width; x++) {
-			if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
-				sprite->data[x + y * sprite->width] = FACE_COLOUR;
-			}
-		}
-	}
-
-	new_glyph.sprite = sprite;
-	new_glyph.width  = (slot->advance.x >> 6) + (size != FS_NORMAL);
-
-	SetGlyphPtr(size, key, &new_glyph);
-
-	return sprite;
-}
-
-
-uint GetGlyphWidth(FontSize size, WChar key)
-{
-	FT_Face face = GetFontFace(size);
-	GlyphEntry *glyph;
-
-	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
-		SpriteID sprite = GetUnicodeGlyph(size, key);
-		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
-		return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
-	}
-
-	glyph = GetGlyphPtr(size, key);
-	if (glyph == NULL || glyph->sprite == NULL) {
-		GetGlyph(size, key);
-		glyph = GetGlyphPtr(size, key);
-	}
-
-	return glyph->width;
-}
-
-
-#endif /* WITH_FREETYPE */
-
-/* Sprite based glyph mapping */
-
-#include "table/unicode.h"
-
-static SpriteID **_unicode_glyph_map[FS_END];
-
-
-/** Get the SpriteID of the first glyph for the given font size */
-static SpriteID GetFontBase(FontSize size)
-{
-	switch (size) {
-		default: NOT_REACHED();
-		case FS_NORMAL: return SPR_ASCII_SPACE;
-		case FS_SMALL:  return SPR_ASCII_SPACE_SMALL;
-		case FS_LARGE:  return SPR_ASCII_SPACE_BIG;
-	}
-}
-
-
-SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
-{
-	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
-	return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
-}
-
-
-void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
-{
-	if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = calloc(256, sizeof(*_unicode_glyph_map[size]));
-	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = calloc(256, sizeof(**_unicode_glyph_map[size]));
-	_unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
-}
-
-
-void InitializeUnicodeGlyphMap(void)
-{
-	FontSize size;
-	SpriteID base;
-	SpriteID sprite;
-	uint i;
-
-	for (size = FS_NORMAL; size != FS_END; size++) {
-		/* Clear out existing glyph map if it exists */
-		if (_unicode_glyph_map[size] != NULL) {
-			for (i = 0; i < 256; i++) {
-				if (_unicode_glyph_map[size][i] != NULL) free(_unicode_glyph_map[size][i]);
-			}
-			free(_unicode_glyph_map[size]);
-			_unicode_glyph_map[size] = NULL;
-		}
-
-		base = GetFontBase(size);
-		for (i = ASCII_LETTERSTART; i < 256; i++) {
-			sprite = base + i - ASCII_LETTERSTART;
-			if (!SpriteExists(sprite)) continue;
-			SetUnicodeGlyph(size, i, sprite);
-			SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
-		}
-		for (i = 0; i < lengthof(_default_unicode_map); i++) {
-			sprite = base + _default_unicode_map[i].key - ASCII_LETTERSTART;
-			SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
-		}
-	}
-}
-
-
-
new file mode 100644
--- /dev/null
+++ b/src/fontcache.cpp
@@ -0,0 +1,524 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "macros.h"
+#include "debug.h"
+#include "table/sprites.h"
+#include "table/control_codes.h"
+#include "spritecache.h"
+#include "gfx.h"
+#include "string.h"
+#include "fontcache.h"
+
+#ifdef WITH_FREETYPE
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#ifdef WITH_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
+
+static FT_Library _library = NULL;
+static FT_Face _face_small = NULL;
+static FT_Face _face_medium = NULL;
+static FT_Face _face_large = NULL;
+
+FreeTypeSettings _freetype;
+
+enum {
+	FACE_COLOUR = 1,
+	SHADOW_COLOUR = 2,
+};
+
+/** Get the font loaded into a Freetype face by using a font-name.
+ * If no appropiate font is found, the function returns an error */
+#ifdef WIN32
+#include <windows.h>
+#include <tchar.h>
+#include <shlobj.h> // SHGetFolderPath
+#include "win32.h"
+
+/* Get the font file to be loaded into Freetype by looping the registry
+ * location where windows lists all installed fonts. Not very nice, will
+ * surely break if the registry path changes, but it works. Much better
+ * solution would be to use CreateFont, and extract the font data from it
+ * by GetFontData. The problem with this is that the font file needs to be
+ * kept in memory then until the font is no longer needed. This could mean
+ * an additional memory usage of 30MB (just for fonts!) when using an eastern
+ * font for all font sizes */
+#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
+#define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
+static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
+{
+	FT_Error err = FT_Err_Cannot_Open_Resource;
+	HKEY hKey;
+	LONG ret;
+	TCHAR vbuffer[MAX_PATH], dbuffer[256];
+	TCHAR *font_namep;
+	char *font_path;
+	uint index;
+
+	/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
+	 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
+	 * to retrieve the windows version, we'll just query both */
+	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
+	if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
+
+	if (ret != ERROR_SUCCESS) {
+		DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
+		return err;
+	}
+
+	/* For Unicode we need some conversion between widechar and
+	 * normal char to match the data returned by RegEnumValue,
+	 * otherwise just use parameter */
+#if defined(UNICODE)
+	font_namep = malloc(MAX_PATH * sizeof(TCHAR));
+	MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
+#else
+	font_namep = (char*)font_name; // only cast because in unicode pointer is not const
+#endif
+
+	for (index = 0;; index++) {
+		TCHAR *s;
+		DWORD vbuflen = lengthof(vbuffer);
+		DWORD dbuflen = lengthof(dbuffer);
+
+		ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
+		if (ret != ERROR_SUCCESS) goto registry_no_font_found;
+
+		/* The font names in the registry are of the following 3 forms:
+		 * - ADMUI3.fon
+		 * - Book Antiqua Bold (TrueType)
+		 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
+		 * We will strip the font-type '()' if any and work with the font name
+		 * itself, which must match exactly; if...
+		 * TTC files, font files which contain more than one font are seperated
+		 * byt '&'. Our best bet will be to do substr match for the fontname
+		 * and then let FreeType figure out which index to load */
+		s = _tcschr(vbuffer, _T('('));
+		if (s != NULL) s[-1] = '\0';
+
+		if (_tcschr(vbuffer, _T('&')) == NULL) {
+			if (_tcsicmp(vbuffer, font_namep) == 0) break;
+		} else {
+			if (_tcsstr(vbuffer, font_namep) != NULL) break;
+		}
+	}
+
+	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
+		DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
+		goto folder_error;
+	}
+
+	/* Some fonts are contained in .ttc files, TrueType Collection fonts. These
+	 * contain multiple fonts inside this single file. GetFontData however
+	 * returns the whole file, so we need to check each font inside to get the
+	 * proper font.
+	 * Also note that FreeType does not support UNICODE filesnames! */
+#if defined(UNICODE)
+	/* We need a cast here back from wide because FreeType doesn't support
+	 * widechar filenames. Just use the buffer we allocated before for the
+	 * font_name search */
+	font_path = (char*)font_namep;
+	WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
+#else
+	font_path = vbuffer;
+#endif
+
+	ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
+	ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
+	index = 0;
+	do {
+		err = FT_New_Face(_library, font_path, index, face);
+		if (err != FT_Err_Ok) break;
+
+		if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
+		err = FT_Err_Cannot_Open_Resource;
+
+	} while ((FT_Long)++index != (*face)->num_faces);
+
+
+folder_error:
+#if defined(UNICODE)
+	free(font_path);
+#endif
+registry_no_font_found:
+	RegCloseKey(hKey);
+	return err;
+}
+#else
+# ifdef WITH_FONTCONFIG
+static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
+{
+	FT_Error err = FT_Err_Cannot_Open_Resource;
+
+	if (!FcInit()) {
+		ShowInfoF("Unable to load font configuration");
+	} else {
+		FcPattern *match;
+		FcPattern *pat;
+		FcFontSet *fs;
+		FcResult  result;
+		char *font_style;
+		char *font_family;
+
+		/* Split & strip the font's style */
+		font_family = strdup(font_name);
+		font_style = strchr(font_family, ',');
+		if (font_style != NULL) {
+			font_style[0] = '\0';
+			font_style++;
+			while (*font_style == ' ' || *font_style == '\t') font_style++;
+		}
+
+		/* Resolve the name and populate the information structure */
+		pat = FcNameParse((FcChar8*)font_family);
+		if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
+		FcConfigSubstitute(0, pat, FcMatchPattern);
+		FcDefaultSubstitute(pat);
+		fs = FcFontSetCreate();
+		match = FcFontMatch(0, pat, &result);
+
+		if (fs != NULL && match != NULL) {
+			int i;
+			FcChar8 *family;
+			FcChar8 *style;
+			FcChar8 *file;
+			FcFontSetAdd(fs, match);
+
+			for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
+				/* Try the new filename */
+				if (FcPatternGetString(fs->fonts[i], FC_FILE,   0, &file)   == FcResultMatch &&
+						FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
+						FcPatternGetString(fs->fonts[i], FC_STYLE,  0, &style)  == FcResultMatch) {
+
+					/* The correct style? */
+					if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
+
+					/* Font config takes the best shot, which, if the family name is spelled
+					* wrongly a 'random' font, so check whether the family name is the
+					* same as the supplied name */
+					if (strcasecmp(font_family, (char*)family) == 0) {
+						err = FT_New_Face(_library, (char *)file, 0, face);
+					}
+				}
+			}
+		}
+
+		free(font_family);
+		FcPatternDestroy(pat);
+		FcFontSetDestroy(fs);
+		FcFini();
+	}
+
+	return err;
+}
+# else
+FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
+# endif /* WITH_FONTCONFIG */
+
+#endif
+
+/**
+ * Loads the freetype font.
+ * First type to load the fontname as if it were a path. If that fails,
+ * try to resolve the filename of the font using fontconfig, where the
+ * format is 'font family name' or 'font family name, font style'.
+ */
+static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
+{
+	FT_Error error;
+
+	if (strlen(font_name) == 0) return;
+
+	error = FT_New_Face(_library, font_name, 0, face);
+
+	if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, face);
+
+	if (error == FT_Err_Ok) {
+		DEBUG(freetype, 2, "Requested '%s', using '%s %s'", font_name, (*face)->family_name, (*face)->style_name);
+
+		/* Attempt to select the unicode character map */
+		error = FT_Select_Charmap(*face, ft_encoding_unicode);
+		if (error == FT_Err_Ok) return; // Success
+
+		if (error == FT_Err_Invalid_CharMap_Handle) {
+			/* Try to pick a different character map instead. We default to
+			 * the first map, but platform_id 0 encoding_id 0 should also
+			 * be unicode (strange system...) */
+			FT_CharMap found = (*face)->charmaps[0];
+			int i;
+
+			for (i = 0; i < (*face)->num_charmaps; i++) {
+				FT_CharMap charmap = (*face)->charmaps[i];
+				if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
+					found = charmap;
+				}
+			}
+
+			if (found != NULL) {
+				error = FT_Set_Charmap(*face, found);
+				if (error == FT_Err_Ok) return;
+			}
+		}
+	}
+
+	FT_Done_Face(*face);
+	*face = NULL;
+
+	ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
+}
+
+
+void InitFreeType(void)
+{
+	if (strlen(_freetype.small_font) == 0 && strlen(_freetype.medium_font) == 0 && strlen(_freetype.large_font) == 0) {
+		DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
+		return;
+	}
+
+	if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
+		ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
+		return;
+	}
+
+	DEBUG(freetype, 2, "Initialized");
+
+	/* Load each font */
+	LoadFreeTypeFont(_freetype.small_font,  &_face_small,  "small");
+	LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
+	LoadFreeTypeFont(_freetype.large_font,  &_face_large,  "large");
+
+	/* Set each font size */
+	if (_face_small  != NULL) FT_Set_Pixel_Sizes(_face_small,  0, _freetype.small_size);
+	if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
+	if (_face_large  != NULL) FT_Set_Pixel_Sizes(_face_large,  0, _freetype.large_size);
+}
+
+
+static FT_Face GetFontFace(FontSize size)
+{
+	switch (size) {
+		default: NOT_REACHED();
+		case FS_NORMAL: return _face_medium;
+		case FS_SMALL:  return _face_small;
+		case FS_LARGE:  return _face_large;
+	}
+}
+
+
+typedef struct GlyphEntry {
+	Sprite *sprite;
+	byte width;
+} GlyphEntry;
+
+
+/* The glyph cache. This is structured to reduce memory consumption.
+ * 1) There is a 'segment' table for each font size.
+ * 2) Each segment table is a discrete block of characters.
+ * 3) Each block contains 256 (aligned) characters sequential characters.
+ *
+ * The cache is accessed in the following way:
+ * For character 0x0041  ('A'): _glyph_ptr[FS_NORMAL][0x00][0x41]
+ * For character 0x20AC (Euro): _glyph_ptr[FS_NORMAL][0x20][0xAC]
+ *
+ * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
+ * This can be simply changed in the two functions Get & SetGlyphPtr.
+ */
+static GlyphEntry **_glyph_ptr[FS_END];
+
+
+static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
+{
+	if (_glyph_ptr[size] == NULL) return NULL;
+	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
+	return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
+}
+
+
+static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
+{
+	if (_glyph_ptr[size] == NULL) {
+		DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
+		_glyph_ptr[size] = calloc(256, sizeof(**_glyph_ptr));
+	}
+
+	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
+		DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
+		_glyph_ptr[size][GB(key, 8, 8)] = calloc(256, sizeof(***_glyph_ptr));
+	}
+
+	DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
+	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
+	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width  = glyph->width;
+}
+
+
+const Sprite *GetGlyph(FontSize size, WChar key)
+{
+	FT_Face face = GetFontFace(size);
+	FT_GlyphSlot slot;
+	GlyphEntry new_glyph;
+	GlyphEntry *glyph;
+	Sprite *sprite;
+	int width;
+	int height;
+	int x;
+	int y;
+	int y_adj;
+
+	assert(IsPrintable(key));
+
+	/* Bail out if no face loaded, or for our special characters */
+	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
+		SpriteID sprite = GetUnicodeGlyph(size, key);
+		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
+		return GetSprite(sprite);
+	}
+
+	/* Check for the glyph in our cache */
+	glyph = GetGlyphPtr(size, key);
+	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
+
+	slot = face->glyph;
+
+	FT_Load_Char(face, key, FT_LOAD_DEFAULT);
+	FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
+
+	/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
+	width  = max(1, slot->bitmap.width + (size == FS_NORMAL));
+	height = max(1, slot->bitmap.rows  + (size == FS_NORMAL));
+
+	/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
+	sprite = calloc(width * height + 8, 1);
+	sprite->info   = 1;
+	sprite->width  = width;
+	sprite->height = height;
+	sprite->x_offs = slot->bitmap_left;
+	// XXX 2 should be determined somehow... it's right for the normal face
+	y_adj = (size == FS_NORMAL) ? 2 : 0;
+	sprite->y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
+
+	/* Draw shadow for medium size */
+	if (size == FS_NORMAL) {
+		for (y = 0; y < slot->bitmap.rows; y++) {
+			for (x = 0; x < slot->bitmap.width; x++) {
+				if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
+					sprite->data[1 + x + (1 + y) * sprite->width] = SHADOW_COLOUR;
+				}
+			}
+		}
+	}
+
+	for (y = 0; y < slot->bitmap.rows; y++) {
+		for (x = 0; x < slot->bitmap.width; x++) {
+			if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
+				sprite->data[x + y * sprite->width] = FACE_COLOUR;
+			}
+		}
+	}
+
+	new_glyph.sprite = sprite;
+	new_glyph.width  = (slot->advance.x >> 6) + (size != FS_NORMAL);
+
+	SetGlyphPtr(size, key, &new_glyph);
+
+	return sprite;
+}
+
+
+uint GetGlyphWidth(FontSize size, WChar key)
+{
+	FT_Face face = GetFontFace(size);
+	GlyphEntry *glyph;
+
+	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
+		SpriteID sprite = GetUnicodeGlyph(size, key);
+		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
+		return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
+	}
+
+	glyph = GetGlyphPtr(size, key);
+	if (glyph == NULL || glyph->sprite == NULL) {
+		GetGlyph(size, key);
+		glyph = GetGlyphPtr(size, key);
+	}
+
+	return glyph->width;
+}
+
+
+#endif /* WITH_FREETYPE */
+
+/* Sprite based glyph mapping */
+
+#include "table/unicode.h"
+
+static SpriteID **_unicode_glyph_map[FS_END];
+
+
+/** Get the SpriteID of the first glyph for the given font size */
+static SpriteID GetFontBase(FontSize size)
+{
+	switch (size) {
+		default: NOT_REACHED();
+		case FS_NORMAL: return SPR_ASCII_SPACE;
+		case FS_SMALL:  return SPR_ASCII_SPACE_SMALL;
+		case FS_LARGE:  return SPR_ASCII_SPACE_BIG;
+	}
+}
+
+
+SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
+{
+	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
+	return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
+}
+
+
+void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
+{
+	if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = calloc(256, sizeof(*_unicode_glyph_map[size]));
+	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = calloc(256, sizeof(**_unicode_glyph_map[size]));
+	_unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
+}
+
+
+void InitializeUnicodeGlyphMap(void)
+{
+	FontSize size;
+	SpriteID base;
+	SpriteID sprite;
+	uint i;
+
+	for (size = FS_NORMAL; size != FS_END; size++) {
+		/* Clear out existing glyph map if it exists */
+		if (_unicode_glyph_map[size] != NULL) {
+			for (i = 0; i < 256; i++) {
+				if (_unicode_glyph_map[size][i] != NULL) free(_unicode_glyph_map[size][i]);
+			}
+			free(_unicode_glyph_map[size]);
+			_unicode_glyph_map[size] = NULL;
+		}
+
+		base = GetFontBase(size);
+		for (i = ASCII_LETTERSTART; i < 256; i++) {
+			sprite = base + i - ASCII_LETTERSTART;
+			if (!SpriteExists(sprite)) continue;
+			SetUnicodeGlyph(size, i, sprite);
+			SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
+		}
+		for (i = 0; i < lengthof(_default_unicode_map); i++) {
+			sprite = base + _default_unicode_map[i].key - ASCII_LETTERSTART;
+			SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
+		}
+	}
+}
+
+
+
deleted file mode 100644
--- a/src/genworld.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "player.h"
-#include "table/sprites.h"
-#include "variables.h"
-#include "thread.h"
-#include "genworld.h"
-#include "gfx.h"
-#include "gfxinit.h"
-#include "gui.h"
-#include "network/network.h"
-#include "debug.h"
-#include "settings.h"
-#include "heightmap.h"
-#include "date.h"
-
-void GenerateLandscape(byte mode);
-void GenerateClearTile(void);
-void GenerateIndustries(void);
-void GenerateUnmovables(void);
-bool GenerateTowns(void);
-void GenerateTrees(void);
-
-void StartupEconomy(void);
-void StartupPlayers(void);
-void StartupDisasters(void);
-
-void InitializeGame(int mode, uint size_x, uint size_y);
-
-void ConvertGroundTilesIntoWaterTiles(void);
-
-/* Please only use this variable in genworld.h and genworld.c and
- *  nowhere else. For speed improvements we need it to be global, but
- *  in no way the meaning of it is to use it anywhere else besides
- *  in the genworld.h and genworld.c! -- TrueLight */
-gw_info _gw;
-
-/**
- * Set the status of the Paint flag.
- *  If it is true, the thread will hold with any futher generating till
- *  the drawing of the screen is done. This is handled by
- *  SetGeneratingWorldProgress(), so calling that function will stall
- *  from time to time.
- */
-void SetGeneratingWorldPaintStatus(bool status)
-{
-	_gw.wait_for_draw = status;
-}
-
-/**
- * Returns true if the thread wants the main program to do a (full) paint.
- *  If this returns false, please do not update the screen. Because we are
- *  writing in a thread, it can cause damaged data (reading and writing the
- *  same tile at the same time).
- */
-bool IsGeneratingWorldReadyForPaint(void)
-{
-	/* If we are in quit_thread mode, ignore this and always return false. This
-	 *  forces the screen to not be drawn, and the GUI not to wait for a draw. */
-	if (!_gw.active || _gw.quit_thread || !_gw.threaded) return false;
-
-	return _gw.wait_for_draw;
-}
-
-/**
- * Tells if the world generation is done in a thread or not.
- */
-bool IsGenerateWorldThreaded(void)
-{
-	return _gw.threaded && !_gw.quit_thread;
-}
-
-/**
- * The internal, real, generate function.
- */
-static void *_GenerateWorld(void *arg)
-{
-	_generating_world = true;
-	if (_network_dedicated) DEBUG(net, 0, "Generating map, please wait...");
-	/* Set the Random() seed to generation_seed so we produce the same map with the same seed */
-	if (_patches.generation_seed == GENERATE_NEW_SEED) _patches.generation_seed = _patches_newgame.generation_seed = InteractiveRandom();
-	_random_seeds[0][0] = _random_seeds[0][1] = _patches.generation_seed;
-	SetGeneratingWorldProgress(GWP_MAP_INIT, 2);
-	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
-
-	IncreaseGeneratingWorldProgress(GWP_MAP_INIT);
-	// Must start economy early because of the costs.
-	StartupEconomy();
-
-	// Don't generate landscape items when in the scenario editor.
-	if (_gw.mode == GW_EMPTY) {
-		SetGeneratingWorldProgress(GWP_UNMOVABLE, 1);
-
-		/* Make the map the height of the patch setting */
-		if (_game_mode != GM_MENU) FlatEmptyWorld(_patches.se_flat_world_height);
-
-		ConvertGroundTilesIntoWaterTiles();
-		IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
-	} else {
-		GenerateLandscape(_gw.mode);
-		GenerateClearTile();
-
-		// only generate towns, tree and industries in newgame mode.
-		if (_game_mode != GM_EDITOR) {
-			GenerateTowns();
-			GenerateIndustries();
-			GenerateUnmovables();
-			GenerateTrees();
-		}
-	}
-
-	// These are probably pointless when inside the scenario editor.
-	SetGeneratingWorldProgress(GWP_GAME_INIT, 3);
-	StartupPlayers();
-	IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
-	StartupEngines();
-	IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
-	StartupDisasters();
-	_generating_world = false;
-
-	// No need to run the tile loop in the scenario editor.
-	if (_gw.mode != GW_EMPTY) {
-		uint i;
-
-		SetGeneratingWorldProgress(GWP_RUNTILELOOP, 0x500);
-		for (i = 0; i < 0x500; i++) {
-			RunTileLoop();
-			IncreaseGeneratingWorldProgress(GWP_RUNTILELOOP);
-		}
-	}
-
-	ResetObjectToPlace();
-	SetLocalPlayer(_gw.lp);
-
-	SetGeneratingWorldProgress(GWP_GAME_START, 1);
-	/* Call any callback */
-	if (_gw.proc != NULL) _gw.proc();
-	IncreaseGeneratingWorldProgress(GWP_GAME_START);
-
-	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
-	/* Show all vital windows again, because we have hidden them */
-	if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
-	_gw.active   = false;
-	_gw.thread   = NULL;
-	_gw.proc     = NULL;
-	_gw.threaded = false;
-
-	DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0);
-	MarkWholeScreenDirty();
-
-	if (_network_dedicated) DEBUG(net, 0, "Map generated, starting game");
-
-	return NULL;
-}
-
-/**
- * Set here the function, if any, that you want to be called when landscape
- *  generation is done.
- */
-void GenerateWorldSetCallback(gw_done_proc *proc)
-{
-	_gw.proc = proc;
-}
-
-/**
- * Set here the function, if any, that you want to be called when landscape
- *  generation is aborted.
- */
-void GenerateWorldSetAbortCallback(gw_abort_proc *proc)
-{
-	_gw.abortp = proc;
-}
-
-/**
- * This will wait for the thread to finish up his work. It will not continue
- *  till the work is done.
- */
-void WaitTillGeneratedWorld(void)
-{
-	if (_gw.thread == NULL) return;
-	_gw.quit_thread = true;
-	OTTDJoinThread(_gw.thread);
-	_gw.thread   = NULL;
-	_gw.threaded = false;
-}
-
-/**
- * Initializes the abortion process
- */
-void AbortGeneratingWorld(void)
-{
-	_gw.abort = true;
-}
-
-/**
- * Is the generation being aborted?
- */
-bool IsGeneratingWorldAborted(void)
-{
-	return _gw.abort;
-}
-
-/**
- * Really handle the abortion, i.e. clean up some of the mess
- */
-void HandleGeneratingWorldAbortion(void)
-{
-	/* Clean up - in SE create an empty map, otherwise, go to intro menu */
-	_switch_mode = (_game_mode == GM_EDITOR) ? SM_EDITOR : SM_MENU;
-
-	if (_gw.abortp != NULL) _gw.abortp();
-
-	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
-	/* Show all vital windows again, because we have hidden them */
-	if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
-	_gw.active   = false;
-	_gw.thread   = NULL;
-	_gw.proc     = NULL;
-	_gw.abortp   = NULL;
-	_gw.threaded = false;
-
-	DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0);
-	MarkWholeScreenDirty();
-
-	OTTDExitThread();
-}
-
-/**
- * Generate a world.
- * @param mode The mode of world generation (@see GenerateWorldModes).
- * @param size_x The X-size of the map.
- * @param size_y The Y-size of the map.
- */
-void GenerateWorld(int mode, uint size_x, uint size_y)
-{
-	if (_gw.active) return;
-	_gw.mode   = mode;
-	_gw.size_x = size_x;
-	_gw.size_y = size_y;
-	_gw.active = true;
-	_gw.abort  = false;
-	_gw.abortp = NULL;
-	_gw.lp     = _local_player;
-	_gw.wait_for_draw = false;
-	_gw.quit_thread   = false;
-	_gw.threaded      = true;
-
-	/* This disables some commands and stuff */
-	SetLocalPlayer(PLAYER_SPECTATOR);
-	/* Make sure everything is done via OWNER_NONE */
-	_current_player = OWNER_NONE;
-
-	/* Set the date before loading sprites as some newgrfs check it */
-	SetDate(ConvertYMDToDate(_patches.starting_year, 0, 1));
-
-	/* Load the right landscape stuff */
-	GfxLoadSprites();
-	LoadStringWidthTable();
-
-	InitializeGame(IG_NONE, _gw.size_x, _gw.size_y);
-	PrepareGenerateWorldProgress();
-
-	/* Re-init the windowing system */
-	ResetWindowSystem();
-
-	/* Create toolbars */
-	SetupColorsAndInitialWindow();
-
-	if (_network_dedicated ||
-	    (_gw.thread = OTTDCreateThread(&_GenerateWorld, NULL)) == NULL) {
-		DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
-		_gw.threaded = false;
-		_GenerateWorld(NULL);
-		return;
-	}
-
-	/* Remove any open window */
-	DeleteAllNonVitalWindows();
-	/* Hide vital windows, because we don't allow to use them */
-	HideVitalWindows();
-
-	/* Don't show the dialog if we don't have a thread */
-	ShowGenerateWorldProgress();
-
-	/* Centre the view on the map */
-	if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) {
-		ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2));
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/genworld.cpp
@@ -0,0 +1,292 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "player.h"
+#include "table/sprites.h"
+#include "variables.h"
+#include "thread.h"
+#include "genworld.h"
+#include "gfx.h"
+#include "gfxinit.h"
+#include "gui.h"
+#include "network/network.h"
+#include "debug.h"
+#include "settings.h"
+#include "heightmap.h"
+#include "date.h"
+
+void GenerateLandscape(byte mode);
+void GenerateClearTile(void);
+void GenerateIndustries(void);
+void GenerateUnmovables(void);
+bool GenerateTowns(void);
+void GenerateTrees(void);
+
+void StartupEconomy(void);
+void StartupPlayers(void);
+void StartupDisasters(void);
+
+void InitializeGame(int mode, uint size_x, uint size_y);
+
+void ConvertGroundTilesIntoWaterTiles(void);
+
+/* Please only use this variable in genworld.h and genworld.c and
+ *  nowhere else. For speed improvements we need it to be global, but
+ *  in no way the meaning of it is to use it anywhere else besides
+ *  in the genworld.h and genworld.c! -- TrueLight */
+gw_info _gw;
+
+/**
+ * Set the status of the Paint flag.
+ *  If it is true, the thread will hold with any futher generating till
+ *  the drawing of the screen is done. This is handled by
+ *  SetGeneratingWorldProgress(), so calling that function will stall
+ *  from time to time.
+ */
+void SetGeneratingWorldPaintStatus(bool status)
+{
+	_gw.wait_for_draw = status;
+}
+
+/**
+ * Returns true if the thread wants the main program to do a (full) paint.
+ *  If this returns false, please do not update the screen. Because we are
+ *  writing in a thread, it can cause damaged data (reading and writing the
+ *  same tile at the same time).
+ */
+bool IsGeneratingWorldReadyForPaint(void)
+{
+	/* If we are in quit_thread mode, ignore this and always return false. This
+	 *  forces the screen to not be drawn, and the GUI not to wait for a draw. */
+	if (!_gw.active || _gw.quit_thread || !_gw.threaded) return false;
+
+	return _gw.wait_for_draw;
+}
+
+/**
+ * Tells if the world generation is done in a thread or not.
+ */
+bool IsGenerateWorldThreaded(void)
+{
+	return _gw.threaded && !_gw.quit_thread;
+}
+
+/**
+ * The internal, real, generate function.
+ */
+static void *_GenerateWorld(void *arg)
+{
+	_generating_world = true;
+	if (_network_dedicated) DEBUG(net, 0, "Generating map, please wait...");
+	/* Set the Random() seed to generation_seed so we produce the same map with the same seed */
+	if (_patches.generation_seed == GENERATE_NEW_SEED) _patches.generation_seed = _patches_newgame.generation_seed = InteractiveRandom();
+	_random_seeds[0][0] = _random_seeds[0][1] = _patches.generation_seed;
+	SetGeneratingWorldProgress(GWP_MAP_INIT, 2);
+	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
+
+	IncreaseGeneratingWorldProgress(GWP_MAP_INIT);
+	// Must start economy early because of the costs.
+	StartupEconomy();
+
+	// Don't generate landscape items when in the scenario editor.
+	if (_gw.mode == GW_EMPTY) {
+		SetGeneratingWorldProgress(GWP_UNMOVABLE, 1);
+
+		/* Make the map the height of the patch setting */
+		if (_game_mode != GM_MENU) FlatEmptyWorld(_patches.se_flat_world_height);
+
+		ConvertGroundTilesIntoWaterTiles();
+		IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
+	} else {
+		GenerateLandscape(_gw.mode);
+		GenerateClearTile();
+
+		// only generate towns, tree and industries in newgame mode.
+		if (_game_mode != GM_EDITOR) {
+			GenerateTowns();
+			GenerateIndustries();
+			GenerateUnmovables();
+			GenerateTrees();
+		}
+	}
+
+	// These are probably pointless when inside the scenario editor.
+	SetGeneratingWorldProgress(GWP_GAME_INIT, 3);
+	StartupPlayers();
+	IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
+	StartupEngines();
+	IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
+	StartupDisasters();
+	_generating_world = false;
+
+	// No need to run the tile loop in the scenario editor.
+	if (_gw.mode != GW_EMPTY) {
+		uint i;
+
+		SetGeneratingWorldProgress(GWP_RUNTILELOOP, 0x500);
+		for (i = 0; i < 0x500; i++) {
+			RunTileLoop();
+			IncreaseGeneratingWorldProgress(GWP_RUNTILELOOP);
+		}
+	}
+
+	ResetObjectToPlace();
+	SetLocalPlayer(_gw.lp);
+
+	SetGeneratingWorldProgress(GWP_GAME_START, 1);
+	/* Call any callback */
+	if (_gw.proc != NULL) _gw.proc();
+	IncreaseGeneratingWorldProgress(GWP_GAME_START);
+
+	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
+	/* Show all vital windows again, because we have hidden them */
+	if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
+	_gw.active   = false;
+	_gw.thread   = NULL;
+	_gw.proc     = NULL;
+	_gw.threaded = false;
+
+	DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0);
+	MarkWholeScreenDirty();
+
+	if (_network_dedicated) DEBUG(net, 0, "Map generated, starting game");
+
+	return NULL;
+}
+
+/**
+ * Set here the function, if any, that you want to be called when landscape
+ *  generation is done.
+ */
+void GenerateWorldSetCallback(gw_done_proc *proc)
+{
+	_gw.proc = proc;
+}
+
+/**
+ * Set here the function, if any, that you want to be called when landscape
+ *  generation is aborted.
+ */
+void GenerateWorldSetAbortCallback(gw_abort_proc *proc)
+{
+	_gw.abortp = proc;
+}
+
+/**
+ * This will wait for the thread to finish up his work. It will not continue
+ *  till the work is done.
+ */
+void WaitTillGeneratedWorld(void)
+{
+	if (_gw.thread == NULL) return;
+	_gw.quit_thread = true;
+	OTTDJoinThread(_gw.thread);
+	_gw.thread   = NULL;
+	_gw.threaded = false;
+}
+
+/**
+ * Initializes the abortion process
+ */
+void AbortGeneratingWorld(void)
+{
+	_gw.abort = true;
+}
+
+/**
+ * Is the generation being aborted?
+ */
+bool IsGeneratingWorldAborted(void)
+{
+	return _gw.abort;
+}
+
+/**
+ * Really handle the abortion, i.e. clean up some of the mess
+ */
+void HandleGeneratingWorldAbortion(void)
+{
+	/* Clean up - in SE create an empty map, otherwise, go to intro menu */
+	_switch_mode = (_game_mode == GM_EDITOR) ? SM_EDITOR : SM_MENU;
+
+	if (_gw.abortp != NULL) _gw.abortp();
+
+	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
+	/* Show all vital windows again, because we have hidden them */
+	if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
+	_gw.active   = false;
+	_gw.thread   = NULL;
+	_gw.proc     = NULL;
+	_gw.abortp   = NULL;
+	_gw.threaded = false;
+
+	DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0);
+	MarkWholeScreenDirty();
+
+	OTTDExitThread();
+}
+
+/**
+ * Generate a world.
+ * @param mode The mode of world generation (@see GenerateWorldModes).
+ * @param size_x The X-size of the map.
+ * @param size_y The Y-size of the map.
+ */
+void GenerateWorld(int mode, uint size_x, uint size_y)
+{
+	if (_gw.active) return;
+	_gw.mode   = mode;
+	_gw.size_x = size_x;
+	_gw.size_y = size_y;
+	_gw.active = true;
+	_gw.abort  = false;
+	_gw.abortp = NULL;
+	_gw.lp     = _local_player;
+	_gw.wait_for_draw = false;
+	_gw.quit_thread   = false;
+	_gw.threaded      = true;
+
+	/* This disables some commands and stuff */
+	SetLocalPlayer(PLAYER_SPECTATOR);
+	/* Make sure everything is done via OWNER_NONE */
+	_current_player = OWNER_NONE;
+
+	/* Set the date before loading sprites as some newgrfs check it */
+	SetDate(ConvertYMDToDate(_patches.starting_year, 0, 1));
+
+	/* Load the right landscape stuff */
+	GfxLoadSprites();
+	LoadStringWidthTable();
+
+	InitializeGame(IG_NONE, _gw.size_x, _gw.size_y);
+	PrepareGenerateWorldProgress();
+
+	/* Re-init the windowing system */
+	ResetWindowSystem();
+
+	/* Create toolbars */
+	SetupColorsAndInitialWindow();
+
+	if (_network_dedicated ||
+	    (_gw.thread = OTTDCreateThread(&_GenerateWorld, NULL)) == NULL) {
+		DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
+		_gw.threaded = false;
+		_GenerateWorld(NULL);
+		return;
+	}
+
+	/* Remove any open window */
+	DeleteAllNonVitalWindows();
+	/* Hide vital windows, because we don't allow to use them */
+	HideVitalWindows();
+
+	/* Don't show the dialog if we don't have a thread */
+	ShowGenerateWorldProgress();
+
+	/* Centre the view on the map */
+	if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) {
+		ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2));
+	}
+}
deleted file mode 100644
--- a/src/genworld_gui.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "heightmap.h"
-#include "functions.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "strings.h"
-#include "gfxinit.h"
-#include "player.h"
-#include "command.h"
-#include "sound.h"
-#include "variables.h"
-#include "string.h"
-#include "settings.h"
-#include "debug.h"
-#include "genworld.h"
-#include "network/network.h"
-#include "thread.h"
-#include "date.h"
-#include "newgrf_config.h"
-
-enum {
-	START_DATE_QUERY,
-	SNOW_LINE_QUERY,
-	FLAT_WORLD_HEIGHT_QUERY,
-
-	LEN_RND_SEED = 11,
-	SEED_EDIT    = 15,
-};
-
-/**
- * In what 'mode' the GenerateLandscapeWindowProc is.
- */
-typedef enum glwp_modes {
-	GLWP_GENERATE,
-	GLWP_HEIGHTMAP,
-	GLWP_SCENARIO,
-	GLWP_END
-} glwp_modes;
-
-static uint _heightmap_x = 0;
-static uint _heightmap_y = 0;
-static StringID _heightmap_str = STR_NULL;
-static bool _goto_editor = false;
-
-extern void SwitchMode(int new_mode);
-
-static inline void SetNewLandscapeType(byte landscape)
-{
-	_opt_newgame.landscape = landscape;
-	InvalidateWindowClasses(WC_SELECT_GAME);
-	InvalidateWindowClasses(WC_GENERATE_LANDSCAPE);
-}
-
-// no longer static to allow calling from outside module
-const Widget _generate_landscape_widgets[] = {
-{  WWT_CLOSEBOX,  RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
-{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 267, 0x0,                          STR_NULL},
-
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,         STR_030E_SELECT_TEMPERATE_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,        STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL,      STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,           STR_0311_SELECT_TOYLAND_LANDSCAPE},
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 149,  90, 101, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 150, 161,  90, 101, STR_0225,                     STR_NULL}, // Mapsize X
-{      WWT_PANEL, RESIZE_NONE, 12, 180, 215,  90, 101, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 227,  90, 101, STR_0225,                     STR_NULL}, // Mapsize Y
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 112, 123, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 112, 123, STR_0225,                     STR_NULL}, // Number of towns
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 130, 141, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 130, 141, STR_0225,                     STR_NULL}, // Number of industries
-
-{      WWT_PANEL, RESIZE_NONE, 15, 114, 207, 152, 163, 0x0,                          STR_RANDOM_SEED_HELP}, // Edit box for seed
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 326, 152, 163, STR_RANDOM,                   STR_RANDOM_HELP},
-
-{    WWT_TEXTBTN, RESIZE_NONE,  6, 243, 326, 228, 257, STR_GENERATE,                 STR_NULL}, // Generate button
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 112, 123, SPR_ARROW_DOWN,               STR_029E_MOVE_THE_STARTING_DATE},
-{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 112, 123, 0x0,                          STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 112, 123, SPR_ARROW_UP,                 STR_029F_MOVE_THE_STARTING_DATE},
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 130, 141, SPR_ARROW_DOWN,               STR_SNOW_LINE_DOWN},
-{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 130, 141, 0x0,                          STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 130, 141, SPR_ARROW_UP,                 STR_SNOW_LINE_UP},
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 192, 203, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 192, 203, STR_0225,                     STR_NULL}, // Tree placer
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 174, 185, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 174, 185, STR_0225,                     STR_NULL}, // Landscape generator
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 210, 221, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 210, 221, STR_0225,                     STR_NULL}, // Terrain type
-{      WWT_PANEL, RESIZE_NONE, 12, 113, 219, 228, 239, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 228, 239, STR_0225,                     STR_NULL}, // Water quantity
-{      WWT_PANEL, RESIZE_NONE, 12, 113, 219, 246, 257, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 246, 257, STR_0225,                     STR_NULL}, // Map smoothness
-{   WIDGETS_END},
-};
-
-const Widget _heightmap_load_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
-{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 235, 0x0,                          STR_NULL},
-
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,        STR_030E_SELECT_TEMPERATE_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,       STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL,     STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,          STR_0311_SELECT_TOYLAND_LANDSCAPE},
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 149, 112, 123, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 150, 161, 112, 123, STR_0225,                     STR_NULL}, // Mapsize X
-{      WWT_PANEL, RESIZE_NONE, 12, 180, 215, 112, 123, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 227, 112, 123, STR_0225,                     STR_NULL}, // Mapsize Y
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 134, 145, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 134, 145, STR_0225,                     STR_NULL}, // Number of towns
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 152, 163, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 152, 163, STR_0225,                     STR_NULL}, // Number of industries
-
-{      WWT_PANEL, RESIZE_NONE, 15, 114, 194, 174, 185, 0x0,                          STR_RANDOM_SEED_HELP}, // Edit box for seed
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 203, 285, 174, 185, STR_RANDOM,                   STR_RANDOM_HELP},
-
-{    WWT_TEXTBTN, RESIZE_NONE,  6, 243, 326, 196, 225, STR_GENERATE,                 STR_NULL}, // Generate button
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 134, 145, SPR_ARROW_DOWN,               STR_029E_MOVE_THE_STARTING_DATE},
-{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 134, 145, 0x0,                          STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 134, 145, SPR_ARROW_UP,                 STR_029F_MOVE_THE_STARTING_DATE},
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 152, 163, SPR_ARROW_DOWN,               STR_SNOW_LINE_DOWN},
-{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 152, 163, 0x0,                          STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 152, 163, SPR_ARROW_UP,                 STR_SNOW_LINE_UP},
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 196, 207, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 196, 207, STR_0225,                     STR_NULL}, // Tree placer
-
-{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 214, 225, 0x0,                          STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 214, 225, STR_0225,                     STR_NULL}, // Heightmap rotation
-{   WIDGETS_END},
-};
-
-static void StartGeneratingLandscape(glwp_modes mode)
-{
-	/* If we want to go to the editor, and aren't yet, we need to delay
-	 *  it as long as possible, else it gives nasty side-effects (aborting
-	 *  results in ending up in the SE, which you don't want. Therefor we
-	 *  use this switch to do it at the very end.
-	 */
-	if (_goto_editor) _game_mode = GM_EDITOR;
-
-	DeleteWindowByClass(WC_GENERATE_LANDSCAPE);
-	DeleteWindowByClass(WC_INDUSTRY_VIEW);
-	DeleteWindowByClass(WC_TOWN_VIEW);
-	DeleteWindowByClass(WC_LAND_INFO);
-
-	/* Copy all XXX_newgame to XXX */
-	UpdatePatches();
-	_opt_ptr = &_opt;
-	*_opt_ptr = _opt_newgame;
-	ResetGRFConfig(true);
-
-	SndPlayFx(SND_15_BEEP);
-	switch (mode) {
-	case GLWP_GENERATE:  _switch_mode = (_game_mode == GM_EDITOR) ? SM_GENRANDLAND    : SM_NEWGAME;         break;
-	case GLWP_HEIGHTMAP: _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP; break;
-	case GLWP_SCENARIO:  _switch_mode = SM_EDITOR; break;
-	default: NOT_REACHED(); return;
-	}
-}
-
-static void HeightmapScaledTooMuchCallback(Window *w, bool confirmed)
-{
-	if (confirmed) StartGeneratingLandscape((glwp_modes)w->window_number);
-}
-
-void GenerateLandscapeWndProc(Window *w, WindowEvent *e)
-{
-	static const StringID mapsizes[]    = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
-	static const StringID elevations[]  = {STR_682A_VERY_FLAT, STR_682B_FLAT, STR_682C_HILLY, STR_682D_MOUNTAINOUS, INVALID_STRING_ID};
-	static const StringID sea_lakes[]   = {STR_VERY_LOW, STR_6820_LOW, STR_6821_MEDIUM, STR_6822_HIGH, INVALID_STRING_ID};
-	static const StringID smoothness[]  = {STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_ROUGH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_ROUGH, INVALID_STRING_ID};
-	static const StringID tree_placer[] = {STR_CONFIG_PATCHES_TREE_PLACER_NONE, STR_CONFIG_PATCHES_TREE_PLACER_ORIGINAL, STR_CONFIG_PATCHES_TREE_PLACER_IMPROVED, INVALID_STRING_ID};
-	static const StringID rotation[]    = {STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE, INVALID_STRING_ID};
-	static const StringID landscape[]   = {STR_CONFIG_PATCHES_LAND_GENERATOR_ORIGINAL, STR_CONFIG_PATCHES_LAND_GENERATOR_TERRA_GENESIS, INVALID_STRING_ID};
-	static const StringID num_towns[]   = {STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
-	static const StringID num_inds[]    = {STR_26816_NONE, STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
-
-	/* Data used for the generate seed edit box */
-	static querystr_d _genseed_query;
-	static char _genseed_buffer[LEN_RND_SEED];
-
-	uint mode = w->window_number;
-	uint y;
-
-	switch (e->event) {
-	case WE_CREATE:
-		LowerWindowWidget(w, _opt_newgame.landscape + 3);
-
-		snprintf(_genseed_buffer, sizeof(_genseed_buffer), "%u", _patches_newgame.generation_seed);
-		InitializeTextBuffer(&_genseed_query.text, _genseed_buffer, lengthof(_genseed_buffer), 120);
-		_genseed_query.caption = STR_NULL;
-		_genseed_query.afilter = CS_NUMERAL;
-		break;
-
-	case WE_PAINT:
-		/* You can't select smoothness if not terragenesis */
-		if (mode == GLWP_GENERATE) {
-			SetWindowWidgetDisabledState(w, 32, _patches_newgame.land_generator == 0);
-			SetWindowWidgetDisabledState(w, 33, _patches_newgame.land_generator == 0);
-		}
-		/* Disable snowline if not hilly */
-		SetWindowWidgetDisabledState(w, 22, _opt_newgame.landscape != LT_HILLY);
-		/* Disable town and industry in SE */
-		SetWindowWidgetDisabledState(w, 11, _game_mode == GM_EDITOR);
-		SetWindowWidgetDisabledState(w, 12, _game_mode == GM_EDITOR);
-		SetWindowWidgetDisabledState(w, 13, _game_mode == GM_EDITOR);
-		SetWindowWidgetDisabledState(w, 14, _game_mode == GM_EDITOR);
-		SetWindowWidgetDisabledState(w, 24, _game_mode == GM_EDITOR);
-		SetWindowWidgetDisabledState(w, 25, _game_mode == GM_EDITOR);
-
-		SetWindowWidgetDisabledState(w, 18, _patches_newgame.starting_year <= MIN_YEAR);
-		SetWindowWidgetDisabledState(w, 20, _patches_newgame.starting_year >= MAX_YEAR);
-		SetWindowWidgetDisabledState(w, 21, _patches_newgame.snow_line_height <= 2 || _opt_newgame.landscape != LT_HILLY);
-		SetWindowWidgetDisabledState(w, 23, _patches_newgame.snow_line_height >= 13 || _opt_newgame.landscape != LT_HILLY);
-
-		SetWindowWidgetLoweredState(w, 3, _opt_newgame.landscape == LT_NORMAL);
-		SetWindowWidgetLoweredState(w, 4, _opt_newgame.landscape == LT_HILLY);
-		SetWindowWidgetLoweredState(w, 5, _opt_newgame.landscape == LT_DESERT);
-		SetWindowWidgetLoweredState(w, 6, _opt_newgame.landscape == LT_CANDY);
-		DrawWindowWidgets(w);
-
-		y = (mode == GLWP_HEIGHTMAP) ? 22 : 0;
-
-		DrawString( 12,  91 + y, STR_MAPSIZE, 0);
-		DrawString(119,  91 + y, mapsizes[_patches_newgame.map_x - 6], 0x10);
-		DrawString(168,  91 + y, STR_BY, 0);
-		DrawString(182,  91 + y, mapsizes[_patches_newgame.map_y - 6], 0x10);
-
-		DrawString( 12, 113 + y, STR_NUMBER_OF_TOWNS, 0);
-		DrawString( 12, 131 + y, STR_NUMBER_OF_INDUSTRIES, 0);
-		if (_game_mode == GM_EDITOR) {
-			DrawString(118, 113 + y, STR_6836_OFF, 0x10);
-			DrawString(118, 131 + y, STR_6836_OFF, 0x10);
-		} else {
-			DrawString(118, 113 + y, num_towns[_opt_newgame.diff.number_towns], 0x10);
-			DrawString(118, 131 + y, num_inds[_opt_newgame.diff.number_industries], 0x10);
-		}
-
-		DrawString( 12, 153 + y, STR_RANDOM_SEED, 0);
-		DrawEditBox(w, &_genseed_query, SEED_EDIT);
-
-		DrawString(182, 113 + y, STR_DATE, 0);
-		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-		DrawStringCentered(271, 113 + y, STR_GENERATE_DATE, 0);
-
-		DrawString(182, 131 + y, STR_SNOW_LINE_HEIGHT, 0);
-		SetDParam(0, _patches_newgame.snow_line_height);
-		DrawStringCentered(303, 131 + y, STR_SNOW_LINE_HEIGHT_NUM, 0x10);
-
-		if (mode == GLWP_GENERATE) {
-			DrawString( 12, 175, STR_LAND_GENERATOR, 0);
-			DrawString(118, 175, landscape[_patches_newgame.land_generator], 0x10);
-
-			DrawString( 12, 193, STR_TREE_PLACER, 0);
-			DrawString(118, 193, tree_placer[_patches_newgame.tree_placer], 0x10);
-
-			DrawString( 12, 211, STR_TERRAIN_TYPE, 0);
-			DrawString(118, 211, elevations[_opt_newgame.diff.terrain_type], 0x10);
-
-			DrawString( 12, 229, STR_QUANTITY_OF_SEA_LAKES, 0);
-			DrawString(118, 229, sea_lakes[_opt_newgame.diff.quantity_sea_lakes], 0x10);
-
-			DrawString( 12, 247, STR_SMOOTHNESS, 0);
-			DrawString(118, 247, smoothness[_patches_newgame.tgen_smoothness], 0x10);
-		} else {
-			char buffer[512];
-
-			if (_patches_newgame.heightmap_rotation == HM_CLOCKWISE) {
-				SetDParam(0, _heightmap_y);
-				SetDParam(1, _heightmap_x);
-			} else {
-				SetDParam(0, _heightmap_x);
-				SetDParam(1, _heightmap_y);
-			}
-			GetString(buffer, STR_HEIGHTMAP_SIZE, lastof(buffer));
-			DrawStringRightAligned(326, 91, STR_HEIGHTMAP_SIZE, 0x10);
-
-			DrawString( 12,  91, STR_HEIGHTMAP_NAME, 0x10);
-			SetDParam(0, _heightmap_str);
-			DrawStringTruncated(114,  91, STR_ORANGE, 0x10, 326 - 114 - GetStringBoundingBox(buffer).width - 5);
-
-			DrawString( 12, 197, STR_TREE_PLACER, 0);
-			DrawString(118, 197, tree_placer[_patches_newgame.tree_placer], 0x10);
-
-			DrawString( 12, 215, STR_HEIGHTMAP_ROTATION, 0);
-			DrawString(118, 215, rotation[_patches_newgame.heightmap_rotation], 0x10);
-		}
-
-		break;
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 0: DeleteWindow(w); break;
-		case 3: case 4: case 5: case 6:
-			RaiseWindowWidget(w, _opt_newgame.landscape + 3);
-			SetNewLandscapeType(e->we.click.widget - 3);
-			break;
-		case 7: case 8: // Mapsize X
-			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_x - 6, 8, 0, 0);
-			break;
-		case 9: case 10: // Mapsize Y
-			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_y - 6, 10, 0, 0);
-			break;
-		case 11: case 12: // Number of towns
-			ShowDropDownMenu(w, num_towns, _opt_newgame.diff.number_towns, 12, 0, 0);
-			break;
-		case 13: case 14: // Number of industries
-			ShowDropDownMenu(w, num_inds, _opt_newgame.diff.number_industries, 14, 0, 0);
-			break;
-		case 16: // Random seed
-			_patches_newgame.generation_seed = InteractiveRandom();
-			snprintf(_genseed_buffer, lengthof(_genseed_buffer), "%u", _patches_newgame.generation_seed);
-			UpdateTextBufferSize(&_genseed_query.text);
-			SetWindowDirty(w);
-			break;
-		case 17: // Generate
-			if (mode == GLWP_HEIGHTMAP && (
-					_heightmap_x * 2 < (1U << _patches_newgame.map_x) || _heightmap_x / 2 > (1U << _patches_newgame.map_x) ||
-					_heightmap_y * 2 < (1U << _patches_newgame.map_y) || _heightmap_y / 2 > (1U << _patches_newgame.map_y))) {
-				ShowQuery(
-					STR_HEIGHTMAP_SCALE_WARNING_CAPTION,
-					STR_HEIGHTMAP_SCALE_WARNING_MESSAGE,
-					w,
-					HeightmapScaledTooMuchCallback);
-			} else {
-				StartGeneratingLandscape(mode);
-			}
-			break;
-		case 18: case 20: // Year buttons
-			/* Don't allow too fast scrolling */
-			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-				HandleButtonClick(w, e->we.click.widget);
-				SetWindowDirty(w);
-
-				_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + e->we.click.widget - 19, MIN_YEAR, MAX_YEAR);
-			}
-			_left_button_clicked = false;
-			break;
-		case 19: // Year text
-			WP(w, def_d).data_3 = START_DATE_QUERY;
-			SetDParam(0, _patches_newgame.starting_year);
-			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_START_DATE_QUERY_CAPT, 8, 100, w, CS_NUMERAL);
-			break;
-		case 21: case 23: // Snow line buttons
-			/* Don't allow too fast scrolling */
-			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-				HandleButtonClick(w, e->we.click.widget);
-				SetWindowDirty(w);
-
-				_patches_newgame.snow_line_height = clamp(_patches_newgame.snow_line_height + e->we.click.widget - 22, 2, 13);
-			}
-			_left_button_clicked = false;
-			break;
-		case 22: // Snow line text
-			WP(w, def_d).data_3 = SNOW_LINE_QUERY;
-			SetDParam(0, _patches_newgame.snow_line_height);
-			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_SNOW_LINE_QUERY_CAPT, 3, 100, w, CS_NUMERAL);
-			break;
-		case 24: case 25: // Tree placer
-			ShowDropDownMenu(w, tree_placer, _patches_newgame.tree_placer, 25, 0, 0);
-			break;
-		case 26: case 27: // Landscape generator OR Heightmap rotation
-			if (mode == GLWP_HEIGHTMAP) {
-				ShowDropDownMenu(w, rotation, _patches_newgame.heightmap_rotation, 27, 0, 0);
-			} else {
-				ShowDropDownMenu(w, landscape, _patches_newgame.land_generator, 27, 0, 0);
-			}
-			break;
-		case 28: case 29: // Terrain type
-			ShowDropDownMenu(w, elevations, _opt_newgame.diff.terrain_type, 29, 0, 0);
-			break;
-		case 30: case 31: // Water quantity
-			ShowDropDownMenu(w, sea_lakes, _opt_newgame.diff.quantity_sea_lakes, 31, 0, 0);
-			break;
-		case 32: case 33: // Map smoothness
-			ShowDropDownMenu(w, smoothness, _patches_newgame.tgen_smoothness, 33, 0, 0);
-			break;
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		HandleEditBox(w, &_genseed_query, SEED_EDIT);
-		break;
-
-	case WE_KEYPRESS:
-		HandleEditBoxKey(w, &_genseed_query, SEED_EDIT, e);
-		/* the seed is unsigned, therefore atoi cannot be used.
-		 * As 2^32 - 1 (MAX_UVALUE(uint32)) is a 'magic' value
-		 * (use random seed) it should not be possible to be
-		 * entered into the input field; the generate seed
-		 * button can be used instead. */
-		_patches_newgame.generation_seed = minu(strtoul(_genseed_buffer, NULL, sizeof(_genseed_buffer) - 1), MAX_UVALUE(uint32) - 1);
-		break;
-
-	case WE_DROPDOWN_SELECT:
-		switch (e->we.dropdown.button) {
-			case 8:  _patches_newgame.map_x = e->we.dropdown.index + 6; break;
-			case 10: _patches_newgame.map_y = e->we.dropdown.index + 6; break;
-			case 12:
-				_opt_newgame.diff.number_towns = e->we.dropdown.index;
-				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
-				DoCommandP(0, 2, _opt_newgame.diff.number_towns, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-				break;
-			case 14:
-				_opt_newgame.diff.number_industries = e->we.dropdown.index;
-				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
-				DoCommandP(0, 3, _opt_newgame.diff.number_industries, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-				break;
-			case 25:
-				_patches_newgame.tree_placer = e->we.dropdown.index;
-				break;
-			case 27:
-				if (mode == GLWP_HEIGHTMAP) {
-					_patches_newgame.heightmap_rotation = e->we.dropdown.index;
-				} else {
-					_patches_newgame.land_generator = e->we.dropdown.index;
-				}
-				break;
-			case 29:
-				_opt_newgame.diff.terrain_type = e->we.dropdown.index;
-				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
-				DoCommandP(0, 12, _opt_newgame.diff.terrain_type, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-				break;
-			case 31:
-				_opt_newgame.diff.quantity_sea_lakes = e->we.dropdown.index;
-				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
-				DoCommandP(0, 13, _opt_newgame.diff.quantity_sea_lakes, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-				break;
-			case 33:
-				_patches_newgame.tgen_smoothness = e->we.dropdown.index;
-				break;
-		}
-		SetWindowDirty(w);
-		break;
-
-	case WE_ON_EDIT_TEXT: {
-		if (e->we.edittext.str != NULL) {
-			int32 value = atoi(e->we.edittext.str);
-
-			switch (WP(w, def_d).data_3) {
-			case START_DATE_QUERY:
-				InvalidateWidget(w, 19);
-				_patches_newgame.starting_year = clamp(value, MIN_YEAR, MAX_YEAR);
-				break;
-			case SNOW_LINE_QUERY:
-				InvalidateWidget(w, 22);
-				_patches_newgame.snow_line_height = clamp(value, 2, 13);
-				break;
-			}
-
-			SetWindowDirty(w);
-		}
-		break;
-	}
-	}
-}
-
-const WindowDesc _generate_landscape_desc = {
-	WDP_CENTER, WDP_CENTER, 338, 268,
-	WC_GENERATE_LANDSCAPE, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_generate_landscape_widgets,
-	GenerateLandscapeWndProc,
-};
-
-const WindowDesc _heightmap_load_desc = {
-	WDP_CENTER, WDP_CENTER, 338, 236,
-	WC_GENERATE_LANDSCAPE, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_heightmap_load_widgets,
-	GenerateLandscapeWndProc,
-};
-
-static void _ShowGenerateLandscape(glwp_modes mode)
-{
-	Window *w;
-
-	/* Don't kill WC_GENERATE_LANDSCAPE:GLWP_SCENARIO, because it resets
-	 *  _goto_editor, which we maybe need later on. */
-	DeleteWindowById(WC_GENERATE_LANDSCAPE, GLWP_GENERATE);
-	DeleteWindowById(WC_GENERATE_LANDSCAPE, GLWP_HEIGHTMAP);
-
-	/* Always give a new seed if not editor */
-	if (_game_mode != GM_EDITOR) _patches_newgame.generation_seed = InteractiveRandom();
-
-	if (mode == GLWP_HEIGHTMAP) {
-		if (_heightmap_str != STR_NULL) DeleteName(_heightmap_str);
-
-		_heightmap_x = 0;
-		_heightmap_y = 0;
-		_heightmap_str = AllocateName(_file_to_saveload.title, 0);
-		/* If the function returns negative, it means there was a problem loading the heightmap */
-		if (!GetHeightmapDimensions(_file_to_saveload.name, &_heightmap_x, &_heightmap_y))
-			return;
-	}
-
-	w = AllocateWindowDescFront((mode == GLWP_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc, mode);
-
-	if (w != NULL) {
-
-		InvalidateWindow(WC_GENERATE_LANDSCAPE, mode);
-	}
-}
-
-void ShowGenerateLandscape(void)
-{
-	_ShowGenerateLandscape(GLWP_GENERATE);
-}
-
-void ShowHeightmapLoad(void)
-{
-	_ShowGenerateLandscape(GLWP_HEIGHTMAP);
-}
-
-void StartNewGameWithoutGUI(uint seed)
-{
-	/* GenerateWorld takes care of the possible GENERATE_NEW_SEED value in 'seed' */
-	_patches_newgame.generation_seed = seed;
-
-	StartGeneratingLandscape(GLWP_GENERATE);
-}
-
-
-void CreateScenarioWndProc(Window *w, WindowEvent *e)
-{
-	static const StringID mapsizes[] = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
-
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _opt_newgame.landscape + 3); break;
-
-	case WE_PAINT:
-		SetWindowWidgetDisabledState(w, 14, _patches_newgame.starting_year <= MIN_YEAR);
-		SetWindowWidgetDisabledState(w, 16, _patches_newgame.starting_year >= MAX_YEAR);
-		SetWindowWidgetDisabledState(w, 17, _patches_newgame.se_flat_world_height <= 0);
-		SetWindowWidgetDisabledState(w, 19, _patches_newgame.se_flat_world_height >= 15);
-
-		SetWindowWidgetLoweredState(w, 3, _opt_newgame.landscape == LT_NORMAL);
-		SetWindowWidgetLoweredState(w, 4, _opt_newgame.landscape == LT_HILLY);
-		SetWindowWidgetLoweredState(w, 5, _opt_newgame.landscape == LT_DESERT);
-		SetWindowWidgetLoweredState(w, 6, _opt_newgame.landscape == LT_CANDY);
-		DrawWindowWidgets(w);
-
-		DrawString( 12,  96, STR_MAPSIZE, 0);
-		DrawString(167,  96, mapsizes[_patches_newgame.map_x - 6], 0x10);
-		DrawString(216,  96, STR_BY, 0);
-		DrawString(230,  96, mapsizes[_patches_newgame.map_y - 6], 0x10);
-
-		DrawString(162, 118, STR_DATE, 0);
-		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-		DrawStringCentered(271, 118, STR_GENERATE_DATE, 0);
-
-		DrawString(162, 136, STR_FLAT_WORLD_HEIGHT, 0);
-		SetDParam(0, _patches_newgame.se_flat_world_height);
-		DrawStringCentered(303, 136, STR_FLAT_WORLD_HEIGHT_NUM, 0x10);
-
-		break;
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 0: DeleteWindow(w); break;
-		case 3: case 4: case 5: case 6:
-			RaiseWindowWidget(w, _opt_newgame.landscape + 3);
-			SetNewLandscapeType(e->we.click.widget - 3);
-			break;
-		case 7: case 8: // Mapsize X
-			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_x - 6, 8, 0, 0);
-			break;
-		case 9: case 10: // Mapsize Y
-			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_y - 6, 10, 0, 0);
-			break;
-		case 11: // Empty world / flat world
-			StartGeneratingLandscape(GLWP_SCENARIO);
-			break;
-		case 12: // Generate
-			_goto_editor = true;
-			ShowGenerateLandscape();
-			break;
-		case 13: // Heightmap
-			_goto_editor = true;
-			ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP);
-			break;
-		case 14: case 16: // Year buttons
-			/* Don't allow too fast scrolling */
-			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-				HandleButtonClick(w, e->we.click.widget);
-				SetWindowDirty(w);
-
-				_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + e->we.click.widget - 15, MIN_YEAR, MAX_YEAR);
-			}
-			_left_button_clicked = false;
-			break;
-		case 15: // Year text
-			WP(w, def_d).data_3 = START_DATE_QUERY;
-			SetDParam(0, _patches_newgame.starting_year);
-			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_START_DATE_QUERY_CAPT, 8, 100, w, CS_NUMERAL);
-			break;
-		case 17: case 19: // Height level buttons
-			/* Don't allow too fast scrolling */
-			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-				HandleButtonClick(w, e->we.click.widget);
-				SetWindowDirty(w);
-
-				_patches_newgame.se_flat_world_height = clamp(_patches_newgame.se_flat_world_height + e->we.click.widget - 18, 0, 15);
-			}
-			_left_button_clicked = false;
-			break;
-		case 18: // Height level text
-			WP(w, def_d).data_3 = FLAT_WORLD_HEIGHT_QUERY;
-			SetDParam(0, _patches_newgame.se_flat_world_height);
-			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_FLAT_WORLD_HEIGHT_QUERY_CAPT, 3, 100, w, CS_NUMERAL);
-			break;
-		}
-		break;
-
-	case WE_DROPDOWN_SELECT:
-		switch (e->we.dropdown.button) {
-			case 8:  _patches_newgame.map_x = e->we.dropdown.index + 6; break;
-			case 10: _patches_newgame.map_y = e->we.dropdown.index + 6; break;
-		}
-		SetWindowDirty(w);
-		break;
-
-	case WE_DESTROY:
-		_goto_editor = false;
-		break;
-
-	case WE_ON_EDIT_TEXT: {
-		if (e->we.edittext.str != NULL) {
-			int32 value = atoi(e->we.edittext.str);
-
-			switch (WP(w, def_d).data_3) {
-			case START_DATE_QUERY:
-				InvalidateWidget(w, 15);
-				_patches_newgame.starting_year = clamp(value, MIN_YEAR, MAX_YEAR);
-				break;
-			case FLAT_WORLD_HEIGHT_QUERY:
-				InvalidateWidget(w, 18);
-				_patches_newgame.se_flat_world_height = clamp(value, 0, 15);
-				break;
-			}
-
-			SetWindowDirty(w);
-		}
-		break;
-	}
-	}
-}
-
-const Widget _create_scenario_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_SE_CAPTION,          STR_NULL},
-{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 179, 0x0,                     STR_NULL},
-
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,    STR_030E_SELECT_TEMPERATE_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,   STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,      STR_0311_SELECT_TOYLAND_LANDSCAPE},
-
-{      WWT_PANEL, RESIZE_NONE, 12, 162, 197,  95, 106, 0x0,                     STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 198, 209,  95, 106, STR_0225,                STR_NULL}, // Mapsize X
-{      WWT_PANEL, RESIZE_NONE, 12, 228, 263,  95, 106, 0x0,                     STR_NULL},
-{    WWT_TEXTBTN, RESIZE_NONE, 12, 264, 275,  95, 106, STR_0225,                STR_NULL}, // Mapsize Y
-
-{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 117, 128, STR_SE_FLAT_WORLD,       STR_SE_FLAT_WORLD_TIP},                      // Empty (sea-level) map
-{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 135, 146, STR_SE_RANDOM_LAND,      STR_022A_GENERATE_RANDOM_LAND}, // Generate
-{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 153, 164, STR_LOAD_GAME_HEIGHTMAP, STR_LOAD_SCEN_HEIGHTMAP},       // Heightmap
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 117, 128, SPR_ARROW_DOWN,          STR_029E_MOVE_THE_STARTING_DATE},
-{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 117, 128, 0x0,                     STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 117, 128, SPR_ARROW_UP,            STR_029F_MOVE_THE_STARTING_DATE},
-
-{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 135, 146, SPR_ARROW_DOWN,          STR_FLAT_WORLD_HEIGHT_DOWN},
-{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 135, 146, 0x0,                     STR_NULL},
-{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 135, 146, SPR_ARROW_UP,            STR_FLAT_WORLD_HEIGHT_UP},
-{   WIDGETS_END},
-};
-
-const WindowDesc _create_scenario_desc = {
-	WDP_CENTER, WDP_CENTER, 338, 180,
-	WC_GENERATE_LANDSCAPE, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_create_scenario_widgets,
-	CreateScenarioWndProc,
-};
-
-void ShowCreateScenario(void)
-{
-	DeleteWindowByClass(WC_GENERATE_LANDSCAPE);
-	AllocateWindowDescFront(&_create_scenario_desc, GLWP_SCENARIO);
-}
-
-
-static const Widget _show_terrain_progress_widgets[] = {
-{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   180,     0,    13, STR_GENERATION_WORLD,   STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   180,    14,    96, 0x0,                    STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    15,    20,   161,    74,    85, STR_GENERATION_ABORT,   STR_NULL}, // Abort button
-{   WIDGETS_END},
-};
-
-typedef struct tp_info {
-	uint percent;
-	StringID class;
-	uint current;
-	uint total;
-	int timer;
-} tp_info;
-
-static tp_info _tp;
-
-static void AbortGeneratingWorldCallback(Window *w, bool confirmed)
-{
-	if (confirmed) {
-		AbortGeneratingWorld();
-	} else if (IsGeneratingWorld() && !IsGeneratingWorldAborted()) {
-		SetMouseCursor(SPR_CURSOR_ZZZ);
-	}
-}
-
-static void ShowTerrainProgressProc(Window* w, WindowEvent* e)
-{
-	switch (e->event) {
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2:
-			if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
-			ShowQuery(
-				STR_GENERATION_ABORT_CAPTION,
-				STR_GENERATION_ABORT_MESSAGE,
-				w,
-				AbortGeneratingWorldCallback
-			);
-			break;
-		}
-		break;
-
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-
-		/* Draw the % complete with a bar and a text */
-		DrawFrameRect(19, 20, (w->width - 18), 37, 14, FR_BORDERONLY);
-		DrawFrameRect(20, 21, (int)((w->width - 40) * _tp.percent / 100) + 20, 36, 10, 0);
-		SetDParam(0, _tp.percent);
-		DrawStringCentered(90, 25, STR_PROGRESS, 0);
-
-		/* Tell which class we are generating */
-		DrawStringCentered(90, 46, _tp.class, 0);
-
-		/* And say where we are in that class */
-		SetDParam(0, _tp.current);
-		SetDParam(1, _tp.total);
-		DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, 0);
-
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const WindowDesc _show_terrain_progress_desc = {
-	WDP_CENTER, WDP_CENTER, 181, 97,
-	WC_GENERATE_PROGRESS_WINDOW, 0,
-	WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_show_terrain_progress_widgets,
-	ShowTerrainProgressProc
-};
-
-/**
- * Initializes the progress counters to the starting point.
- */
-void PrepareGenerateWorldProgress(void)
-{
-	_tp.class   = STR_WORLD_GENERATION;
-	_tp.current = 0;
-	_tp.total   = 0;
-	_tp.percent = 0;
-	_tp.timer   = 0; // Forces to paint the progress window immediatelly
-}
-
-/**
- * Show the window where a user can follow the process of the map generation.
- */
-void ShowGenerateWorldProgress(void)
-{
-	AllocateWindowDescFront(&_show_terrain_progress_desc, 0);
-}
-
-static void _SetGeneratingWorldProgress(gwp_class class, uint progress, uint total)
-{
-	static const int percent_table[GWP_CLASS_COUNT + 1] = {0, 5, 15, 20, 40, 60, 65, 80, 85, 99, 100 };
-	static const StringID class_table[GWP_CLASS_COUNT]  = {
-		STR_WORLD_GENERATION,
-		STR_022E_LANDSCAPE_GENERATION,
-		STR_CLEARING_TILES,
-		STR_022F_TOWN_GENERATION,
-		STR_0230_INDUSTRY_GENERATION,
-		STR_UNMOVABLE_GENERATION,
-		STR_TREE_GENERATION,
-		STR_SETTINGUP_GAME,
-		STR_PREPARING_TILELOOP,
-		STR_PREPARING_GAME
-	};
-
-	assert(class < GWP_CLASS_COUNT);
-
-	/* Do not run this function if we aren't in a thread */
-	if (!IsGenerateWorldThreaded() && !_network_dedicated) return;
-
-	if (IsGeneratingWorldAborted()) HandleGeneratingWorldAbortion();
-
-	if (total == 0) {
-		assert(_tp.class == class_table[class]);
-		_tp.current += progress;
-	} else {
-		_tp.class   = class_table[class];
-		_tp.current = progress;
-		_tp.total   = total;
-		_tp.percent = percent_table[class];
-	}
-
-	/* Don't update the screen too often. So update it once in every 200ms.
-	 * However, the _tick_counter increases by 8 every 30ms, so compensate
-	 * for that. */
-	if (!_network_dedicated && _tp.timer != 0 && _timer_counter - _tp.timer < (200 * 8 / 30)) return;
-
-	/* Percentage is about the number of completed tasks, so 'current - 1' */
-	_tp.percent = percent_table[class] + (percent_table[class + 1] - percent_table[class]) * (_tp.current == 0 ? 0 : _tp.current - 1) / _tp.total;
-	_tp.timer = _timer_counter;
-
-	if (_network_dedicated) {
-		static uint last_percent = 0;
-
-		/* Never display 0% */
-		if (_tp.percent == 0) return;
-		/* Reset if percent is lower then the last recorded */
-		if (_tp.percent < last_percent) last_percent = 0;
-		/* Display every 5%, but 6% is also very valid.. just not smaller steps then 5% */
-		if (_tp.percent % 5 != 0 && _tp.percent <= last_percent + 5) return;
-		/* Never show steps smaller then 2%, even if it is a mod 5% */
-		if (_tp.percent <= last_percent + 2) return;
-
-		DEBUG(net, 1, "Map generation percentage complete: %d", _tp.percent);
-		last_percent = _tp.percent;
-
-		/* Don't continue as dedicated never has a thread running */
-		return;
-	}
-
-	InvalidateWindow(WC_GENERATE_PROGRESS_WINDOW, 0);
-	MarkWholeScreenDirty();
-	SetGeneratingWorldPaintStatus(true);
-
-	/* We wait here till the paint is done, so we don't read and write
-	 *  on the same tile at the same moment. Nasty hack, but that happens
-	 *  if you implement threading afterwards */
-	while (IsGeneratingWorldReadyForPaint()) { CSleep(10); }
-}
-
-/**
- * Set the total of a stage of the world generation.
- * @param class the current class we are in.
- * @param total Set the total expected items for this class.
- *
- * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
- *  Also, progress works if total is zero, total works if progress is zero.
- */
-void SetGeneratingWorldProgress(gwp_class class, uint total)
-{
-	if (total == 0) return;
-
-	_SetGeneratingWorldProgress(class, 0, total);
-}
-
-/**
- * Increases the current stage of the world generation with one.
- * @param class the current class we are in.
- *
- * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
- *  Also, progress works if total is zero, total works if progress is zero.
- */
-void IncreaseGeneratingWorldProgress(gwp_class class)
-{
-	/* In fact the param 'class' isn't needed.. but for some security reasons, we want it around */
-	_SetGeneratingWorldProgress(class, 1, 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/genworld_gui.cpp
@@ -0,0 +1,898 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "heightmap.h"
+#include "functions.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "strings.h"
+#include "gfxinit.h"
+#include "player.h"
+#include "command.h"
+#include "sound.h"
+#include "variables.h"
+#include "string.h"
+#include "settings.h"
+#include "debug.h"
+#include "genworld.h"
+#include "network/network.h"
+#include "thread.h"
+#include "date.h"
+#include "newgrf_config.h"
+
+enum {
+	START_DATE_QUERY,
+	SNOW_LINE_QUERY,
+	FLAT_WORLD_HEIGHT_QUERY,
+
+	LEN_RND_SEED = 11,
+	SEED_EDIT    = 15,
+};
+
+/**
+ * In what 'mode' the GenerateLandscapeWindowProc is.
+ */
+typedef enum glwp_modes {
+	GLWP_GENERATE,
+	GLWP_HEIGHTMAP,
+	GLWP_SCENARIO,
+	GLWP_END
+} glwp_modes;
+
+static uint _heightmap_x = 0;
+static uint _heightmap_y = 0;
+static StringID _heightmap_str = STR_NULL;
+static bool _goto_editor = false;
+
+extern void SwitchMode(int new_mode);
+
+static inline void SetNewLandscapeType(byte landscape)
+{
+	_opt_newgame.landscape = landscape;
+	InvalidateWindowClasses(WC_SELECT_GAME);
+	InvalidateWindowClasses(WC_GENERATE_LANDSCAPE);
+}
+
+// no longer static to allow calling from outside module
+const Widget _generate_landscape_widgets[] = {
+{  WWT_CLOSEBOX,  RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
+{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 267, 0x0,                          STR_NULL},
+
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,         STR_030E_SELECT_TEMPERATE_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,        STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL,      STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,           STR_0311_SELECT_TOYLAND_LANDSCAPE},
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 149,  90, 101, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 150, 161,  90, 101, STR_0225,                     STR_NULL}, // Mapsize X
+{      WWT_PANEL, RESIZE_NONE, 12, 180, 215,  90, 101, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 227,  90, 101, STR_0225,                     STR_NULL}, // Mapsize Y
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 112, 123, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 112, 123, STR_0225,                     STR_NULL}, // Number of towns
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 130, 141, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 130, 141, STR_0225,                     STR_NULL}, // Number of industries
+
+{      WWT_PANEL, RESIZE_NONE, 15, 114, 207, 152, 163, 0x0,                          STR_RANDOM_SEED_HELP}, // Edit box for seed
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 326, 152, 163, STR_RANDOM,                   STR_RANDOM_HELP},
+
+{    WWT_TEXTBTN, RESIZE_NONE,  6, 243, 326, 228, 257, STR_GENERATE,                 STR_NULL}, // Generate button
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 112, 123, SPR_ARROW_DOWN,               STR_029E_MOVE_THE_STARTING_DATE},
+{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 112, 123, 0x0,                          STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 112, 123, SPR_ARROW_UP,                 STR_029F_MOVE_THE_STARTING_DATE},
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 130, 141, SPR_ARROW_DOWN,               STR_SNOW_LINE_DOWN},
+{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 130, 141, 0x0,                          STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 130, 141, SPR_ARROW_UP,                 STR_SNOW_LINE_UP},
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 192, 203, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 192, 203, STR_0225,                     STR_NULL}, // Tree placer
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 174, 185, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 174, 185, STR_0225,                     STR_NULL}, // Landscape generator
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 210, 221, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 210, 221, STR_0225,                     STR_NULL}, // Terrain type
+{      WWT_PANEL, RESIZE_NONE, 12, 113, 219, 228, 239, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 228, 239, STR_0225,                     STR_NULL}, // Water quantity
+{      WWT_PANEL, RESIZE_NONE, 12, 113, 219, 246, 257, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 246, 257, STR_0225,                     STR_NULL}, // Map smoothness
+{   WIDGETS_END},
+};
+
+const Widget _heightmap_load_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
+{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 235, 0x0,                          STR_NULL},
+
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,        STR_030E_SELECT_TEMPERATE_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,       STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL,     STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,          STR_0311_SELECT_TOYLAND_LANDSCAPE},
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 149, 112, 123, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 150, 161, 112, 123, STR_0225,                     STR_NULL}, // Mapsize X
+{      WWT_PANEL, RESIZE_NONE, 12, 180, 215, 112, 123, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 216, 227, 112, 123, STR_0225,                     STR_NULL}, // Mapsize Y
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 134, 145, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 134, 145, STR_0225,                     STR_NULL}, // Number of towns
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 163, 152, 163, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 164, 175, 152, 163, STR_0225,                     STR_NULL}, // Number of industries
+
+{      WWT_PANEL, RESIZE_NONE, 15, 114, 194, 174, 185, 0x0,                          STR_RANDOM_SEED_HELP}, // Edit box for seed
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 203, 285, 174, 185, STR_RANDOM,                   STR_RANDOM_HELP},
+
+{    WWT_TEXTBTN, RESIZE_NONE,  6, 243, 326, 196, 225, STR_GENERATE,                 STR_NULL}, // Generate button
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 134, 145, SPR_ARROW_DOWN,               STR_029E_MOVE_THE_STARTING_DATE},
+{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 134, 145, 0x0,                          STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 134, 145, SPR_ARROW_UP,                 STR_029F_MOVE_THE_STARTING_DATE},
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 152, 163, SPR_ARROW_DOWN,               STR_SNOW_LINE_DOWN},
+{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 152, 163, 0x0,                          STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 152, 163, SPR_ARROW_UP,                 STR_SNOW_LINE_UP},
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 196, 207, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 196, 207, STR_0225,                     STR_NULL}, // Tree placer
+
+{      WWT_PANEL, RESIZE_NONE, 12, 114, 219, 214, 225, 0x0,                          STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 220, 231, 214, 225, STR_0225,                     STR_NULL}, // Heightmap rotation
+{   WIDGETS_END},
+};
+
+static void StartGeneratingLandscape(glwp_modes mode)
+{
+	/* If we want to go to the editor, and aren't yet, we need to delay
+	 *  it as long as possible, else it gives nasty side-effects (aborting
+	 *  results in ending up in the SE, which you don't want. Therefor we
+	 *  use this switch to do it at the very end.
+	 */
+	if (_goto_editor) _game_mode = GM_EDITOR;
+
+	DeleteWindowByClass(WC_GENERATE_LANDSCAPE);
+	DeleteWindowByClass(WC_INDUSTRY_VIEW);
+	DeleteWindowByClass(WC_TOWN_VIEW);
+	DeleteWindowByClass(WC_LAND_INFO);
+
+	/* Copy all XXX_newgame to XXX */
+	UpdatePatches();
+	_opt_ptr = &_opt;
+	*_opt_ptr = _opt_newgame;
+	ResetGRFConfig(true);
+
+	SndPlayFx(SND_15_BEEP);
+	switch (mode) {
+	case GLWP_GENERATE:  _switch_mode = (_game_mode == GM_EDITOR) ? SM_GENRANDLAND    : SM_NEWGAME;         break;
+	case GLWP_HEIGHTMAP: _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP; break;
+	case GLWP_SCENARIO:  _switch_mode = SM_EDITOR; break;
+	default: NOT_REACHED(); return;
+	}
+}
+
+static void HeightmapScaledTooMuchCallback(Window *w, bool confirmed)
+{
+	if (confirmed) StartGeneratingLandscape((glwp_modes)w->window_number);
+}
+
+void GenerateLandscapeWndProc(Window *w, WindowEvent *e)
+{
+	static const StringID mapsizes[]    = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
+	static const StringID elevations[]  = {STR_682A_VERY_FLAT, STR_682B_FLAT, STR_682C_HILLY, STR_682D_MOUNTAINOUS, INVALID_STRING_ID};
+	static const StringID sea_lakes[]   = {STR_VERY_LOW, STR_6820_LOW, STR_6821_MEDIUM, STR_6822_HIGH, INVALID_STRING_ID};
+	static const StringID smoothness[]  = {STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_ROUGH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_ROUGH, INVALID_STRING_ID};
+	static const StringID tree_placer[] = {STR_CONFIG_PATCHES_TREE_PLACER_NONE, STR_CONFIG_PATCHES_TREE_PLACER_ORIGINAL, STR_CONFIG_PATCHES_TREE_PLACER_IMPROVED, INVALID_STRING_ID};
+	static const StringID rotation[]    = {STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE, INVALID_STRING_ID};
+	static const StringID landscape[]   = {STR_CONFIG_PATCHES_LAND_GENERATOR_ORIGINAL, STR_CONFIG_PATCHES_LAND_GENERATOR_TERRA_GENESIS, INVALID_STRING_ID};
+	static const StringID num_towns[]   = {STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
+	static const StringID num_inds[]    = {STR_26816_NONE, STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
+
+	/* Data used for the generate seed edit box */
+	static querystr_d _genseed_query;
+	static char _genseed_buffer[LEN_RND_SEED];
+
+	uint mode = w->window_number;
+	uint y;
+
+	switch (e->event) {
+	case WE_CREATE:
+		LowerWindowWidget(w, _opt_newgame.landscape + 3);
+
+		snprintf(_genseed_buffer, sizeof(_genseed_buffer), "%u", _patches_newgame.generation_seed);
+		InitializeTextBuffer(&_genseed_query.text, _genseed_buffer, lengthof(_genseed_buffer), 120);
+		_genseed_query.caption = STR_NULL;
+		_genseed_query.afilter = CS_NUMERAL;
+		break;
+
+	case WE_PAINT:
+		/* You can't select smoothness if not terragenesis */
+		if (mode == GLWP_GENERATE) {
+			SetWindowWidgetDisabledState(w, 32, _patches_newgame.land_generator == 0);
+			SetWindowWidgetDisabledState(w, 33, _patches_newgame.land_generator == 0);
+		}
+		/* Disable snowline if not hilly */
+		SetWindowWidgetDisabledState(w, 22, _opt_newgame.landscape != LT_HILLY);
+		/* Disable town and industry in SE */
+		SetWindowWidgetDisabledState(w, 11, _game_mode == GM_EDITOR);
+		SetWindowWidgetDisabledState(w, 12, _game_mode == GM_EDITOR);
+		SetWindowWidgetDisabledState(w, 13, _game_mode == GM_EDITOR);
+		SetWindowWidgetDisabledState(w, 14, _game_mode == GM_EDITOR);
+		SetWindowWidgetDisabledState(w, 24, _game_mode == GM_EDITOR);
+		SetWindowWidgetDisabledState(w, 25, _game_mode == GM_EDITOR);
+
+		SetWindowWidgetDisabledState(w, 18, _patches_newgame.starting_year <= MIN_YEAR);
+		SetWindowWidgetDisabledState(w, 20, _patches_newgame.starting_year >= MAX_YEAR);
+		SetWindowWidgetDisabledState(w, 21, _patches_newgame.snow_line_height <= 2 || _opt_newgame.landscape != LT_HILLY);
+		SetWindowWidgetDisabledState(w, 23, _patches_newgame.snow_line_height >= 13 || _opt_newgame.landscape != LT_HILLY);
+
+		SetWindowWidgetLoweredState(w, 3, _opt_newgame.landscape == LT_NORMAL);
+		SetWindowWidgetLoweredState(w, 4, _opt_newgame.landscape == LT_HILLY);
+		SetWindowWidgetLoweredState(w, 5, _opt_newgame.landscape == LT_DESERT);
+		SetWindowWidgetLoweredState(w, 6, _opt_newgame.landscape == LT_CANDY);
+		DrawWindowWidgets(w);
+
+		y = (mode == GLWP_HEIGHTMAP) ? 22 : 0;
+
+		DrawString( 12,  91 + y, STR_MAPSIZE, 0);
+		DrawString(119,  91 + y, mapsizes[_patches_newgame.map_x - 6], 0x10);
+		DrawString(168,  91 + y, STR_BY, 0);
+		DrawString(182,  91 + y, mapsizes[_patches_newgame.map_y - 6], 0x10);
+
+		DrawString( 12, 113 + y, STR_NUMBER_OF_TOWNS, 0);
+		DrawString( 12, 131 + y, STR_NUMBER_OF_INDUSTRIES, 0);
+		if (_game_mode == GM_EDITOR) {
+			DrawString(118, 113 + y, STR_6836_OFF, 0x10);
+			DrawString(118, 131 + y, STR_6836_OFF, 0x10);
+		} else {
+			DrawString(118, 113 + y, num_towns[_opt_newgame.diff.number_towns], 0x10);
+			DrawString(118, 131 + y, num_inds[_opt_newgame.diff.number_industries], 0x10);
+		}
+
+		DrawString( 12, 153 + y, STR_RANDOM_SEED, 0);
+		DrawEditBox(w, &_genseed_query, SEED_EDIT);
+
+		DrawString(182, 113 + y, STR_DATE, 0);
+		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+		DrawStringCentered(271, 113 + y, STR_GENERATE_DATE, 0);
+
+		DrawString(182, 131 + y, STR_SNOW_LINE_HEIGHT, 0);
+		SetDParam(0, _patches_newgame.snow_line_height);
+		DrawStringCentered(303, 131 + y, STR_SNOW_LINE_HEIGHT_NUM, 0x10);
+
+		if (mode == GLWP_GENERATE) {
+			DrawString( 12, 175, STR_LAND_GENERATOR, 0);
+			DrawString(118, 175, landscape[_patches_newgame.land_generator], 0x10);
+
+			DrawString( 12, 193, STR_TREE_PLACER, 0);
+			DrawString(118, 193, tree_placer[_patches_newgame.tree_placer], 0x10);
+
+			DrawString( 12, 211, STR_TERRAIN_TYPE, 0);
+			DrawString(118, 211, elevations[_opt_newgame.diff.terrain_type], 0x10);
+
+			DrawString( 12, 229, STR_QUANTITY_OF_SEA_LAKES, 0);
+			DrawString(118, 229, sea_lakes[_opt_newgame.diff.quantity_sea_lakes], 0x10);
+
+			DrawString( 12, 247, STR_SMOOTHNESS, 0);
+			DrawString(118, 247, smoothness[_patches_newgame.tgen_smoothness], 0x10);
+		} else {
+			char buffer[512];
+
+			if (_patches_newgame.heightmap_rotation == HM_CLOCKWISE) {
+				SetDParam(0, _heightmap_y);
+				SetDParam(1, _heightmap_x);
+			} else {
+				SetDParam(0, _heightmap_x);
+				SetDParam(1, _heightmap_y);
+			}
+			GetString(buffer, STR_HEIGHTMAP_SIZE, lastof(buffer));
+			DrawStringRightAligned(326, 91, STR_HEIGHTMAP_SIZE, 0x10);
+
+			DrawString( 12,  91, STR_HEIGHTMAP_NAME, 0x10);
+			SetDParam(0, _heightmap_str);
+			DrawStringTruncated(114,  91, STR_ORANGE, 0x10, 326 - 114 - GetStringBoundingBox(buffer).width - 5);
+
+			DrawString( 12, 197, STR_TREE_PLACER, 0);
+			DrawString(118, 197, tree_placer[_patches_newgame.tree_placer], 0x10);
+
+			DrawString( 12, 215, STR_HEIGHTMAP_ROTATION, 0);
+			DrawString(118, 215, rotation[_patches_newgame.heightmap_rotation], 0x10);
+		}
+
+		break;
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 0: DeleteWindow(w); break;
+		case 3: case 4: case 5: case 6:
+			RaiseWindowWidget(w, _opt_newgame.landscape + 3);
+			SetNewLandscapeType(e->we.click.widget - 3);
+			break;
+		case 7: case 8: // Mapsize X
+			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_x - 6, 8, 0, 0);
+			break;
+		case 9: case 10: // Mapsize Y
+			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_y - 6, 10, 0, 0);
+			break;
+		case 11: case 12: // Number of towns
+			ShowDropDownMenu(w, num_towns, _opt_newgame.diff.number_towns, 12, 0, 0);
+			break;
+		case 13: case 14: // Number of industries
+			ShowDropDownMenu(w, num_inds, _opt_newgame.diff.number_industries, 14, 0, 0);
+			break;
+		case 16: // Random seed
+			_patches_newgame.generation_seed = InteractiveRandom();
+			snprintf(_genseed_buffer, lengthof(_genseed_buffer), "%u", _patches_newgame.generation_seed);
+			UpdateTextBufferSize(&_genseed_query.text);
+			SetWindowDirty(w);
+			break;
+		case 17: // Generate
+			if (mode == GLWP_HEIGHTMAP && (
+					_heightmap_x * 2 < (1U << _patches_newgame.map_x) || _heightmap_x / 2 > (1U << _patches_newgame.map_x) ||
+					_heightmap_y * 2 < (1U << _patches_newgame.map_y) || _heightmap_y / 2 > (1U << _patches_newgame.map_y))) {
+				ShowQuery(
+					STR_HEIGHTMAP_SCALE_WARNING_CAPTION,
+					STR_HEIGHTMAP_SCALE_WARNING_MESSAGE,
+					w,
+					HeightmapScaledTooMuchCallback);
+			} else {
+				StartGeneratingLandscape(mode);
+			}
+			break;
+		case 18: case 20: // Year buttons
+			/* Don't allow too fast scrolling */
+			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+				HandleButtonClick(w, e->we.click.widget);
+				SetWindowDirty(w);
+
+				_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + e->we.click.widget - 19, MIN_YEAR, MAX_YEAR);
+			}
+			_left_button_clicked = false;
+			break;
+		case 19: // Year text
+			WP(w, def_d).data_3 = START_DATE_QUERY;
+			SetDParam(0, _patches_newgame.starting_year);
+			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_START_DATE_QUERY_CAPT, 8, 100, w, CS_NUMERAL);
+			break;
+		case 21: case 23: // Snow line buttons
+			/* Don't allow too fast scrolling */
+			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+				HandleButtonClick(w, e->we.click.widget);
+				SetWindowDirty(w);
+
+				_patches_newgame.snow_line_height = clamp(_patches_newgame.snow_line_height + e->we.click.widget - 22, 2, 13);
+			}
+			_left_button_clicked = false;
+			break;
+		case 22: // Snow line text
+			WP(w, def_d).data_3 = SNOW_LINE_QUERY;
+			SetDParam(0, _patches_newgame.snow_line_height);
+			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_SNOW_LINE_QUERY_CAPT, 3, 100, w, CS_NUMERAL);
+			break;
+		case 24: case 25: // Tree placer
+			ShowDropDownMenu(w, tree_placer, _patches_newgame.tree_placer, 25, 0, 0);
+			break;
+		case 26: case 27: // Landscape generator OR Heightmap rotation
+			if (mode == GLWP_HEIGHTMAP) {
+				ShowDropDownMenu(w, rotation, _patches_newgame.heightmap_rotation, 27, 0, 0);
+			} else {
+				ShowDropDownMenu(w, landscape, _patches_newgame.land_generator, 27, 0, 0);
+			}
+			break;
+		case 28: case 29: // Terrain type
+			ShowDropDownMenu(w, elevations, _opt_newgame.diff.terrain_type, 29, 0, 0);
+			break;
+		case 30: case 31: // Water quantity
+			ShowDropDownMenu(w, sea_lakes, _opt_newgame.diff.quantity_sea_lakes, 31, 0, 0);
+			break;
+		case 32: case 33: // Map smoothness
+			ShowDropDownMenu(w, smoothness, _patches_newgame.tgen_smoothness, 33, 0, 0);
+			break;
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		HandleEditBox(w, &_genseed_query, SEED_EDIT);
+		break;
+
+	case WE_KEYPRESS:
+		HandleEditBoxKey(w, &_genseed_query, SEED_EDIT, e);
+		/* the seed is unsigned, therefore atoi cannot be used.
+		 * As 2^32 - 1 (MAX_UVALUE(uint32)) is a 'magic' value
+		 * (use random seed) it should not be possible to be
+		 * entered into the input field; the generate seed
+		 * button can be used instead. */
+		_patches_newgame.generation_seed = minu(strtoul(_genseed_buffer, NULL, sizeof(_genseed_buffer) - 1), MAX_UVALUE(uint32) - 1);
+		break;
+
+	case WE_DROPDOWN_SELECT:
+		switch (e->we.dropdown.button) {
+			case 8:  _patches_newgame.map_x = e->we.dropdown.index + 6; break;
+			case 10: _patches_newgame.map_y = e->we.dropdown.index + 6; break;
+			case 12:
+				_opt_newgame.diff.number_towns = e->we.dropdown.index;
+				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
+				DoCommandP(0, 2, _opt_newgame.diff.number_towns, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				break;
+			case 14:
+				_opt_newgame.diff.number_industries = e->we.dropdown.index;
+				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
+				DoCommandP(0, 3, _opt_newgame.diff.number_industries, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				break;
+			case 25:
+				_patches_newgame.tree_placer = e->we.dropdown.index;
+				break;
+			case 27:
+				if (mode == GLWP_HEIGHTMAP) {
+					_patches_newgame.heightmap_rotation = e->we.dropdown.index;
+				} else {
+					_patches_newgame.land_generator = e->we.dropdown.index;
+				}
+				break;
+			case 29:
+				_opt_newgame.diff.terrain_type = e->we.dropdown.index;
+				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
+				DoCommandP(0, 12, _opt_newgame.diff.terrain_type, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				break;
+			case 31:
+				_opt_newgame.diff.quantity_sea_lakes = e->we.dropdown.index;
+				if (_opt_newgame.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
+				DoCommandP(0, 13, _opt_newgame.diff.quantity_sea_lakes, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				break;
+			case 33:
+				_patches_newgame.tgen_smoothness = e->we.dropdown.index;
+				break;
+		}
+		SetWindowDirty(w);
+		break;
+
+	case WE_ON_EDIT_TEXT: {
+		if (e->we.edittext.str != NULL) {
+			int32 value = atoi(e->we.edittext.str);
+
+			switch (WP(w, def_d).data_3) {
+			case START_DATE_QUERY:
+				InvalidateWidget(w, 19);
+				_patches_newgame.starting_year = clamp(value, MIN_YEAR, MAX_YEAR);
+				break;
+			case SNOW_LINE_QUERY:
+				InvalidateWidget(w, 22);
+				_patches_newgame.snow_line_height = clamp(value, 2, 13);
+				break;
+			}
+
+			SetWindowDirty(w);
+		}
+		break;
+	}
+	}
+}
+
+const WindowDesc _generate_landscape_desc = {
+	WDP_CENTER, WDP_CENTER, 338, 268,
+	WC_GENERATE_LANDSCAPE, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_generate_landscape_widgets,
+	GenerateLandscapeWndProc,
+};
+
+const WindowDesc _heightmap_load_desc = {
+	WDP_CENTER, WDP_CENTER, 338, 236,
+	WC_GENERATE_LANDSCAPE, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_heightmap_load_widgets,
+	GenerateLandscapeWndProc,
+};
+
+static void _ShowGenerateLandscape(glwp_modes mode)
+{
+	Window *w;
+
+	/* Don't kill WC_GENERATE_LANDSCAPE:GLWP_SCENARIO, because it resets
+	 *  _goto_editor, which we maybe need later on. */
+	DeleteWindowById(WC_GENERATE_LANDSCAPE, GLWP_GENERATE);
+	DeleteWindowById(WC_GENERATE_LANDSCAPE, GLWP_HEIGHTMAP);
+
+	/* Always give a new seed if not editor */
+	if (_game_mode != GM_EDITOR) _patches_newgame.generation_seed = InteractiveRandom();
+
+	if (mode == GLWP_HEIGHTMAP) {
+		if (_heightmap_str != STR_NULL) DeleteName(_heightmap_str);
+
+		_heightmap_x = 0;
+		_heightmap_y = 0;
+		_heightmap_str = AllocateName(_file_to_saveload.title, 0);
+		/* If the function returns negative, it means there was a problem loading the heightmap */
+		if (!GetHeightmapDimensions(_file_to_saveload.name, &_heightmap_x, &_heightmap_y))
+			return;
+	}
+
+	w = AllocateWindowDescFront((mode == GLWP_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc, mode);
+
+	if (w != NULL) {
+
+		InvalidateWindow(WC_GENERATE_LANDSCAPE, mode);
+	}
+}
+
+void ShowGenerateLandscape(void)
+{
+	_ShowGenerateLandscape(GLWP_GENERATE);
+}
+
+void ShowHeightmapLoad(void)
+{
+	_ShowGenerateLandscape(GLWP_HEIGHTMAP);
+}
+
+void StartNewGameWithoutGUI(uint seed)
+{
+	/* GenerateWorld takes care of the possible GENERATE_NEW_SEED value in 'seed' */
+	_patches_newgame.generation_seed = seed;
+
+	StartGeneratingLandscape(GLWP_GENERATE);
+}
+
+
+void CreateScenarioWndProc(Window *w, WindowEvent *e)
+{
+	static const StringID mapsizes[] = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
+
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _opt_newgame.landscape + 3); break;
+
+	case WE_PAINT:
+		SetWindowWidgetDisabledState(w, 14, _patches_newgame.starting_year <= MIN_YEAR);
+		SetWindowWidgetDisabledState(w, 16, _patches_newgame.starting_year >= MAX_YEAR);
+		SetWindowWidgetDisabledState(w, 17, _patches_newgame.se_flat_world_height <= 0);
+		SetWindowWidgetDisabledState(w, 19, _patches_newgame.se_flat_world_height >= 15);
+
+		SetWindowWidgetLoweredState(w, 3, _opt_newgame.landscape == LT_NORMAL);
+		SetWindowWidgetLoweredState(w, 4, _opt_newgame.landscape == LT_HILLY);
+		SetWindowWidgetLoweredState(w, 5, _opt_newgame.landscape == LT_DESERT);
+		SetWindowWidgetLoweredState(w, 6, _opt_newgame.landscape == LT_CANDY);
+		DrawWindowWidgets(w);
+
+		DrawString( 12,  96, STR_MAPSIZE, 0);
+		DrawString(167,  96, mapsizes[_patches_newgame.map_x - 6], 0x10);
+		DrawString(216,  96, STR_BY, 0);
+		DrawString(230,  96, mapsizes[_patches_newgame.map_y - 6], 0x10);
+
+		DrawString(162, 118, STR_DATE, 0);
+		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+		DrawStringCentered(271, 118, STR_GENERATE_DATE, 0);
+
+		DrawString(162, 136, STR_FLAT_WORLD_HEIGHT, 0);
+		SetDParam(0, _patches_newgame.se_flat_world_height);
+		DrawStringCentered(303, 136, STR_FLAT_WORLD_HEIGHT_NUM, 0x10);
+
+		break;
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 0: DeleteWindow(w); break;
+		case 3: case 4: case 5: case 6:
+			RaiseWindowWidget(w, _opt_newgame.landscape + 3);
+			SetNewLandscapeType(e->we.click.widget - 3);
+			break;
+		case 7: case 8: // Mapsize X
+			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_x - 6, 8, 0, 0);
+			break;
+		case 9: case 10: // Mapsize Y
+			ShowDropDownMenu(w, mapsizes, _patches_newgame.map_y - 6, 10, 0, 0);
+			break;
+		case 11: // Empty world / flat world
+			StartGeneratingLandscape(GLWP_SCENARIO);
+			break;
+		case 12: // Generate
+			_goto_editor = true;
+			ShowGenerateLandscape();
+			break;
+		case 13: // Heightmap
+			_goto_editor = true;
+			ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP);
+			break;
+		case 14: case 16: // Year buttons
+			/* Don't allow too fast scrolling */
+			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+				HandleButtonClick(w, e->we.click.widget);
+				SetWindowDirty(w);
+
+				_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + e->we.click.widget - 15, MIN_YEAR, MAX_YEAR);
+			}
+			_left_button_clicked = false;
+			break;
+		case 15: // Year text
+			WP(w, def_d).data_3 = START_DATE_QUERY;
+			SetDParam(0, _patches_newgame.starting_year);
+			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_START_DATE_QUERY_CAPT, 8, 100, w, CS_NUMERAL);
+			break;
+		case 17: case 19: // Height level buttons
+			/* Don't allow too fast scrolling */
+			if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+				HandleButtonClick(w, e->we.click.widget);
+				SetWindowDirty(w);
+
+				_patches_newgame.se_flat_world_height = clamp(_patches_newgame.se_flat_world_height + e->we.click.widget - 18, 0, 15);
+			}
+			_left_button_clicked = false;
+			break;
+		case 18: // Height level text
+			WP(w, def_d).data_3 = FLAT_WORLD_HEIGHT_QUERY;
+			SetDParam(0, _patches_newgame.se_flat_world_height);
+			ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_FLAT_WORLD_HEIGHT_QUERY_CAPT, 3, 100, w, CS_NUMERAL);
+			break;
+		}
+		break;
+
+	case WE_DROPDOWN_SELECT:
+		switch (e->we.dropdown.button) {
+			case 8:  _patches_newgame.map_x = e->we.dropdown.index + 6; break;
+			case 10: _patches_newgame.map_y = e->we.dropdown.index + 6; break;
+		}
+		SetWindowDirty(w);
+		break;
+
+	case WE_DESTROY:
+		_goto_editor = false;
+		break;
+
+	case WE_ON_EDIT_TEXT: {
+		if (e->we.edittext.str != NULL) {
+			int32 value = atoi(e->we.edittext.str);
+
+			switch (WP(w, def_d).data_3) {
+			case START_DATE_QUERY:
+				InvalidateWidget(w, 15);
+				_patches_newgame.starting_year = clamp(value, MIN_YEAR, MAX_YEAR);
+				break;
+			case FLAT_WORLD_HEIGHT_QUERY:
+				InvalidateWidget(w, 18);
+				_patches_newgame.se_flat_world_height = clamp(value, 0, 15);
+				break;
+			}
+
+			SetWindowDirty(w);
+		}
+		break;
+	}
+	}
+}
+
+const Widget _create_scenario_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_NONE, 13,  11, 337,   0,  13, STR_SE_CAPTION,          STR_NULL},
+{      WWT_PANEL, RESIZE_NONE, 13,   0, 337,  14, 179, 0x0,                     STR_NULL},
+
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,    STR_030E_SELECT_TEMPERATE_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,   STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  24,  78, SPR_SELECT_TOYLAND,      STR_0311_SELECT_TOYLAND_LANDSCAPE},
+
+{      WWT_PANEL, RESIZE_NONE, 12, 162, 197,  95, 106, 0x0,                     STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 198, 209,  95, 106, STR_0225,                STR_NULL}, // Mapsize X
+{      WWT_PANEL, RESIZE_NONE, 12, 228, 263,  95, 106, 0x0,                     STR_NULL},
+{    WWT_TEXTBTN, RESIZE_NONE, 12, 264, 275,  95, 106, STR_0225,                STR_NULL}, // Mapsize Y
+
+{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 117, 128, STR_SE_FLAT_WORLD,       STR_SE_FLAT_WORLD_TIP},                      // Empty (sea-level) map
+{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 135, 146, STR_SE_RANDOM_LAND,      STR_022A_GENERATE_RANDOM_LAND}, // Generate
+{    WWT_TEXTBTN, RESIZE_NONE,  6,  12, 145, 153, 164, STR_LOAD_GAME_HEIGHTMAP, STR_LOAD_SCEN_HEIGHTMAP},       // Heightmap
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 216, 227, 117, 128, SPR_ARROW_DOWN,          STR_029E_MOVE_THE_STARTING_DATE},
+{      WWT_PANEL, RESIZE_NONE, 12, 228, 314, 117, 128, 0x0,                     STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 117, 128, SPR_ARROW_UP,            STR_029F_MOVE_THE_STARTING_DATE},
+
+{     WWT_IMGBTN, RESIZE_NONE, 12, 282, 293, 135, 146, SPR_ARROW_DOWN,          STR_FLAT_WORLD_HEIGHT_DOWN},
+{      WWT_PANEL, RESIZE_NONE, 12, 294, 314, 135, 146, 0x0,                     STR_NULL},
+{     WWT_IMGBTN, RESIZE_NONE, 12, 315, 326, 135, 146, SPR_ARROW_UP,            STR_FLAT_WORLD_HEIGHT_UP},
+{   WIDGETS_END},
+};
+
+const WindowDesc _create_scenario_desc = {
+	WDP_CENTER, WDP_CENTER, 338, 180,
+	WC_GENERATE_LANDSCAPE, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_create_scenario_widgets,
+	CreateScenarioWndProc,
+};
+
+void ShowCreateScenario(void)
+{
+	DeleteWindowByClass(WC_GENERATE_LANDSCAPE);
+	AllocateWindowDescFront(&_create_scenario_desc, GLWP_SCENARIO);
+}
+
+
+static const Widget _show_terrain_progress_widgets[] = {
+{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   180,     0,    13, STR_GENERATION_WORLD,   STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   180,    14,    96, 0x0,                    STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    15,    20,   161,    74,    85, STR_GENERATION_ABORT,   STR_NULL}, // Abort button
+{   WIDGETS_END},
+};
+
+typedef struct tp_info {
+	uint percent;
+	StringID class;
+	uint current;
+	uint total;
+	int timer;
+} tp_info;
+
+static tp_info _tp;
+
+static void AbortGeneratingWorldCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		AbortGeneratingWorld();
+	} else if (IsGeneratingWorld() && !IsGeneratingWorldAborted()) {
+		SetMouseCursor(SPR_CURSOR_ZZZ);
+	}
+}
+
+static void ShowTerrainProgressProc(Window* w, WindowEvent* e)
+{
+	switch (e->event) {
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2:
+			if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
+			ShowQuery(
+				STR_GENERATION_ABORT_CAPTION,
+				STR_GENERATION_ABORT_MESSAGE,
+				w,
+				AbortGeneratingWorldCallback
+			);
+			break;
+		}
+		break;
+
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+
+		/* Draw the % complete with a bar and a text */
+		DrawFrameRect(19, 20, (w->width - 18), 37, 14, FR_BORDERONLY);
+		DrawFrameRect(20, 21, (int)((w->width - 40) * _tp.percent / 100) + 20, 36, 10, 0);
+		SetDParam(0, _tp.percent);
+		DrawStringCentered(90, 25, STR_PROGRESS, 0);
+
+		/* Tell which class we are generating */
+		DrawStringCentered(90, 46, _tp.class, 0);
+
+		/* And say where we are in that class */
+		SetDParam(0, _tp.current);
+		SetDParam(1, _tp.total);
+		DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, 0);
+
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const WindowDesc _show_terrain_progress_desc = {
+	WDP_CENTER, WDP_CENTER, 181, 97,
+	WC_GENERATE_PROGRESS_WINDOW, 0,
+	WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_show_terrain_progress_widgets,
+	ShowTerrainProgressProc
+};
+
+/**
+ * Initializes the progress counters to the starting point.
+ */
+void PrepareGenerateWorldProgress(void)
+{
+	_tp.class   = STR_WORLD_GENERATION;
+	_tp.current = 0;
+	_tp.total   = 0;
+	_tp.percent = 0;
+	_tp.timer   = 0; // Forces to paint the progress window immediatelly
+}
+
+/**
+ * Show the window where a user can follow the process of the map generation.
+ */
+void ShowGenerateWorldProgress(void)
+{
+	AllocateWindowDescFront(&_show_terrain_progress_desc, 0);
+}
+
+static void _SetGeneratingWorldProgress(gwp_class class, uint progress, uint total)
+{
+	static const int percent_table[GWP_CLASS_COUNT + 1] = {0, 5, 15, 20, 40, 60, 65, 80, 85, 99, 100 };
+	static const StringID class_table[GWP_CLASS_COUNT]  = {
+		STR_WORLD_GENERATION,
+		STR_022E_LANDSCAPE_GENERATION,
+		STR_CLEARING_TILES,
+		STR_022F_TOWN_GENERATION,
+		STR_0230_INDUSTRY_GENERATION,
+		STR_UNMOVABLE_GENERATION,
+		STR_TREE_GENERATION,
+		STR_SETTINGUP_GAME,
+		STR_PREPARING_TILELOOP,
+		STR_PREPARING_GAME
+	};
+
+	assert(class < GWP_CLASS_COUNT);
+
+	/* Do not run this function if we aren't in a thread */
+	if (!IsGenerateWorldThreaded() && !_network_dedicated) return;
+
+	if (IsGeneratingWorldAborted()) HandleGeneratingWorldAbortion();
+
+	if (total == 0) {
+		assert(_tp.class == class_table[class]);
+		_tp.current += progress;
+	} else {
+		_tp.class   = class_table[class];
+		_tp.current = progress;
+		_tp.total   = total;
+		_tp.percent = percent_table[class];
+	}
+
+	/* Don't update the screen too often. So update it once in every 200ms.
+	 * However, the _tick_counter increases by 8 every 30ms, so compensate
+	 * for that. */
+	if (!_network_dedicated && _tp.timer != 0 && _timer_counter - _tp.timer < (200 * 8 / 30)) return;
+
+	/* Percentage is about the number of completed tasks, so 'current - 1' */
+	_tp.percent = percent_table[class] + (percent_table[class + 1] - percent_table[class]) * (_tp.current == 0 ? 0 : _tp.current - 1) / _tp.total;
+	_tp.timer = _timer_counter;
+
+	if (_network_dedicated) {
+		static uint last_percent = 0;
+
+		/* Never display 0% */
+		if (_tp.percent == 0) return;
+		/* Reset if percent is lower then the last recorded */
+		if (_tp.percent < last_percent) last_percent = 0;
+		/* Display every 5%, but 6% is also very valid.. just not smaller steps then 5% */
+		if (_tp.percent % 5 != 0 && _tp.percent <= last_percent + 5) return;
+		/* Never show steps smaller then 2%, even if it is a mod 5% */
+		if (_tp.percent <= last_percent + 2) return;
+
+		DEBUG(net, 1, "Map generation percentage complete: %d", _tp.percent);
+		last_percent = _tp.percent;
+
+		/* Don't continue as dedicated never has a thread running */
+		return;
+	}
+
+	InvalidateWindow(WC_GENERATE_PROGRESS_WINDOW, 0);
+	MarkWholeScreenDirty();
+	SetGeneratingWorldPaintStatus(true);
+
+	/* We wait here till the paint is done, so we don't read and write
+	 *  on the same tile at the same moment. Nasty hack, but that happens
+	 *  if you implement threading afterwards */
+	while (IsGeneratingWorldReadyForPaint()) { CSleep(10); }
+}
+
+/**
+ * Set the total of a stage of the world generation.
+ * @param class the current class we are in.
+ * @param total Set the total expected items for this class.
+ *
+ * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
+ *  Also, progress works if total is zero, total works if progress is zero.
+ */
+void SetGeneratingWorldProgress(gwp_class class, uint total)
+{
+	if (total == 0) return;
+
+	_SetGeneratingWorldProgress(class, 0, total);
+}
+
+/**
+ * Increases the current stage of the world generation with one.
+ * @param class the current class we are in.
+ *
+ * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
+ *  Also, progress works if total is zero, total works if progress is zero.
+ */
+void IncreaseGeneratingWorldProgress(gwp_class class)
+{
+	/* In fact the param 'class' isn't needed.. but for some security reasons, we want it around */
+	_SetGeneratingWorldProgress(class, 1, 0);
+}
deleted file mode 100644
--- a/src/gfx.c
+++ /dev/null
@@ -1,2031 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "macros.h"
-#include "spritecache.h"
-#include "strings.h"
-#include "string.h"
-#include "gfx.h"
-#include "table/palettes.h"
-#include "table/sprites.h"
-#include "hal.h"
-#include "variables.h"
-#include "table/control_codes.h"
-#include "fontcache.h"
-#include "genworld.h"
-#include "debug.h"
-
-#ifdef _DEBUG
-bool _dbg_screen_rect;
-#endif
-
-Colour _cur_palette[256];
-byte _stringwidth_table[FS_END][224];
-
-typedef enum BlitterModes {
-	BM_NORMAL,
-	BM_COLOUR_REMAP,
-	BM_TRANSPARENT,
-} BlitterMode;
-
-static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode);
-
-FontSize _cur_fontsize;
-static FontSize _last_fontsize;
-static Pixel _cursor_backup[64 * 64];
-static Rect _invalid_rect;
-static const byte *_color_remap_ptr;
-static byte _string_colorremap[3];
-
-#define DIRTY_BYTES_PER_LINE (MAX_SCREEN_WIDTH / 64)
-static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8];
-
-void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch)
-{
-	byte *dstp = (byte*)dst;
-	byte *srcp = (byte*)src;
-
-	assert(h >= 0);
-	for (; h != 0; --h) {
-		memcpy(dstp, srcp, w);
-		dstp += dstpitch;
-		srcp += srcpitch;
-	}
-}
-
-void GfxScroll(int left, int top, int width, int height, int xo, int yo)
-{
-	const Pixel *src;
-	Pixel *dst;
-	int p;
-	int ht;
-
-	if (xo == 0 && yo == 0) return;
-
-	if (_cursor.visible) UndrawMouseCursor();
-	UndrawTextMessage();
-
-	p = _screen.pitch;
-
-	if (yo > 0) {
-		// Calculate pointers
-		dst = _screen.dst_ptr + (top + height - 1) * p + left;
-		src = dst - yo * p;
-
-		// Decrease height and increase top
-		top += yo;
-		height -= yo;
-		assert(height > 0);
-
-		// Adjust left & width
-		if (xo >= 0) {
-			dst += xo;
-			left += xo;
-			width -= xo;
-		} else {
-			src -= xo;
-			width += xo;
-		}
-
-		for (ht = height; ht > 0; --ht) {
-			memcpy(dst, src, width);
-			src -= p;
-			dst -= p;
-		}
-	} else {
-		// Calculate pointers
-		dst = _screen.dst_ptr + top * p + left;
-		src = dst - yo * p;
-
-		// Decrese height. (yo is <=0).
-		height += yo;
-		assert(height > 0);
-
-		// Adjust left & width
-		if (xo >= 0) {
-			dst += xo;
-			left += xo;
-			width -= xo;
-		} else {
-			src -= xo;
-			width += xo;
-		}
-
-		// the y-displacement may be 0 therefore we have to use memmove,
-		// because source and destination may overlap
-		for (ht = height; ht > 0; --ht) {
-			memmove(dst, src, width);
-			src += p;
-			dst += p;
-		}
-	}
-	// This part of the screen is now dirty.
-	_video_driver->make_dirty(left, top, width, height);
-}
-
-
-void GfxFillRect(int left, int top, int right, int bottom, int color)
-{
-	const DrawPixelInfo* dpi = _cur_dpi;
-	Pixel *dst;
-	const int otop = top;
-	const int oleft = left;
-
-	if (dpi->zoom != 0) return;
-	if (left > right || top > bottom) return;
-	if (right < dpi->left || left >= dpi->left + dpi->width) return;
-	if (bottom < dpi->top || top >= dpi->top + dpi->height) return;
-
-	if ( (left -= dpi->left) < 0) left = 0;
-	right = right - dpi->left + 1;
-	if (right > dpi->width) right = dpi->width;
-	right -= left;
-	assert(right > 0);
-
-	if ( (top -= dpi->top) < 0) top = 0;
-	bottom = bottom - dpi->top + 1;
-	if (bottom > dpi->height) bottom = dpi->height;
-	bottom -= top;
-	assert(bottom > 0);
-
-	dst = dpi->dst_ptr + top * dpi->pitch + left;
-
-	if (!(color & PALETTE_MODIFIER_GREYOUT)) {
-		if (!(color & USE_COLORTABLE)) {
-			do {
-				memset(dst, color, right);
-				dst += dpi->pitch;
-			} while (--bottom);
-		} else {
-			/* use colortable mode */
-			const byte* ctab = GetNonSprite(color & COLORTABLE_MASK) + 1;
-
-			do {
-				int i;
-				for (i = 0; i != right; i++) dst[i] = ctab[dst[i]];
-				dst += dpi->pitch;
-			} while (--bottom);
-		}
-	} else {
-		byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
-		do {
-			int i;
-			for (i = (bo ^= 1); i < right; i += 2) dst[i] = (byte)color;
-			dst += dpi->pitch;
-		} while (--bottom > 0);
-	}
-}
-
-static void GfxSetPixel(int x, int y, int color)
-{
-	const DrawPixelInfo* dpi = _cur_dpi;
-	if ((x-=dpi->left) < 0 || x>=dpi->width || (y-=dpi->top)<0 || y>=dpi->height)
-		return;
-	dpi->dst_ptr[y * dpi->pitch + x] = color;
-}
-
-void GfxDrawLine(int x, int y, int x2, int y2, int color)
-{
-	int dy;
-	int dx;
-	int stepx;
-	int stepy;
-	int frac;
-
-	// Check clipping first
-	{
-		DrawPixelInfo *dpi = _cur_dpi;
-		int t;
-
-		if (x < dpi->left && x2 < dpi->left) return;
-
-		if (y < dpi->top && y2 < dpi->top) return;
-
-		t = dpi->left + dpi->width;
-		if (x > t && x2 > t) return;
-
-		t = dpi->top + dpi->height;
-		if (y > t && y2 > t) return;
-	}
-
-	dy = (y2 - y) * 2;
-	if (dy < 0) {
-		dy = -dy;
-		stepy = -1;
-	} else {
-		stepy = 1;
-	}
-
-	dx = (x2 - x) * 2;
-	if (dx < 0) {
-		dx = -dx;
-		stepx = -1;
-	} else {
-		stepx = 1;
-	}
-
-	GfxSetPixel(x, y, color);
-	if (dx > dy) {
-		frac = dy - (dx >> 1);
-		while (x != x2) {
-			if (frac >= 0) {
-				y += stepy;
-				frac -= dx;
-			}
-			x += stepx;
-			frac += dy;
-			GfxSetPixel(x, y, color);
-		}
-	} else {
-		frac = dx - (dy >> 1);
-		while (y != y2) {
-			if (frac >= 0) {
-				x += stepx;
-				frac -= dy;
-			}
-			y += stepy;
-			frac += dx;
-			GfxSetPixel(x, y, color);
-		}
-	}
-}
-
-
-/** Truncate a given string to a maximum width if neccessary.
- * If the string is truncated, add three dots ('...') to show this.
- * @param *dest string that is checked and possibly truncated
- * @param maxw maximum width in pixels of the string
- * @return new width of (truncated) string */
-static int TruncateString(char *str, int maxw)
-{
-	int w = 0;
-	FontSize size = _cur_fontsize;
-	int ddd, ddd_w;
-
-	WChar c;
-	char *ddd_pos;
-
-	ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
-
-	for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
-		if (IsPrintable(c)) {
-			w += GetCharacterWidth(size, c);
-
-			if (w >= maxw) {
-				// string got too big... insert dotdotdot
-				ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.';
-				ddd_pos[3] = 0;
-				return ddd_w;
-			}
-		} else {
-			if (c == SCC_SETX) str++;
-			else if (c == SCC_SETXY) str += 2;
-			else if (c == SCC_TINYFONT) {
-				size = FS_SMALL;
-				ddd = GetCharacterWidth(size, '.') * 3;
-			} else if (c == SCC_BIGFONT) {
-				size = FS_LARGE;
-				ddd = GetCharacterWidth(size, '.') * 3;
-			}
-		}
-
-		// Remember the last position where three dots fit.
-		if (w + ddd < maxw) {
-			ddd_w = w + ddd;
-			ddd_pos = str;
-		}
-	}
-
-	return w;
-}
-
-static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last)
-{
-	GetString(dest, src, last);
-	return TruncateString(dest, maxw);
-}
-
-/* returns right coordinate */
-int DrawString(int x, int y, StringID str, uint16 color)
-{
-	char buffer[512];
-
-	GetString(buffer, str, lastof(buffer));
-	return DoDrawString(buffer, x, y, color);
-}
-
-int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw)
-{
-	char buffer[512];
-	TruncateStringID(str, buffer, maxw, lastof(buffer));
-	return DoDrawString(buffer, x, y, color);
-}
-
-
-int DrawStringRightAligned(int x, int y, StringID str, uint16 color)
-{
-	char buffer[512];
-	int w;
-
-	GetString(buffer, str, lastof(buffer));
-	w = GetStringBoundingBox(buffer).width;
-	DoDrawString(buffer, x - w, y, color);
-
-	return w;
-}
-
-void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw)
-{
-	char buffer[512];
-
-	TruncateStringID(str, buffer, maxw, lastof(buffer));
-	DoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color);
-}
-
-void DrawStringRightAlignedUnderline(int x, int y, StringID str, uint16 color)
-{
-	int w = DrawStringRightAligned(x, y, str, color);
-	GfxFillRect(x - w, y + 10, x, y + 10, _string_colorremap[1]);
-}
-
-
-int DrawStringCentered(int x, int y, StringID str, uint16 color)
-{
-	char buffer[512];
-	int w;
-
-	GetString(buffer, str, lastof(buffer));
-
-	w = GetStringBoundingBox(buffer).width;
-	DoDrawString(buffer, x - w / 2, y, color);
-
-	return w;
-}
-
-int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color)
-{
-	char buffer[512];
-	int w = TruncateStringID(str, buffer, xr - xl, lastof(buffer));
-	return DoDrawString(buffer, (xl + xr - w) / 2, y, color);
-}
-
-int DoDrawStringCentered(int x, int y, const char *str, uint16 color)
-{
-	int w = GetStringBoundingBox(str).width;
-	DoDrawString(str, x - w / 2, y, color);
-	return w;
-}
-
-void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color)
-{
-	int w = DrawStringCentered(x, y, str, color);
-	GfxFillRect(x - (w >> 1), y + 10, x - (w >> 1) + w, y + 10, _string_colorremap[1]);
-}
-
-void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color)
-{
-	int w = DrawStringCenteredTruncated(xl, xr, y, str, color);
-	GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]);
-}
-
-/** 'Correct' a string to a maximum length. Longer strings will be cut into
- * additional lines at whitespace characters if possible. The string parameter
- * is modified with terminating characters mid-string which are the
- * placeholders for the newlines.<br/>
- * The string WILL be truncated if there was no whitespace for the current
- * line's maximum width.
- *
- * @note To know if the the terminating '\0' is the string end or just a
- * newline, the returned 'num' value should be consulted. The num'th '\0',
- * starting with index 0 is the real string end.
- *
- * @param str string to check and correct for length restrictions
- * @param maxw the maximum width the string can have on one line
- * @return return a 32bit wide number consisting of 2 packed values:
- *  0 - 15 the number of lines ADDED to the string
- * 16 - 31 the fontsize in which the length calculation was done at */
-uint32 FormatStringLinebreaks(char *str, int maxw)
-{
-	FontSize size = _cur_fontsize;
-	int num = 0;
-
-	assert(maxw > 0);
-
-	for (;;) {
-		char *last_space = NULL;
-		int w = 0;
-
-		for (;;) {
-			WChar c = Utf8Consume((const char **)&str);
-			/* whitespace is where we will insert the line-break */
-			if (c == ' ') last_space = str;
-
-			if (IsPrintable(c)) {
-				w += GetCharacterWidth(size, c);
-				/* string is longer than maximum width so we need to decide what to
-				 * do. We can do two things:
-				 * 1. If no whitespace was found at all up until now (on this line) then
-				 *    we will truncate the string and bail out.
-				 * 2. In all other cases force a linebreak at the last seen whitespace */
-				if (w > maxw) {
-					if (last_space == NULL) {
-						str[-1] = '\0';
-						return num + (size << 16);
-					}
-					str = last_space;
-					break;
-				}
-			} else {
-				switch (c) {
-					case '\0': return num + (size << 16); break;
-					case SCC_SETX:  str++; break;
-					case SCC_SETXY: str +=2; break;
-					case SCC_TINYFONT: size = FS_SMALL; break;
-					case SCC_BIGFONT:  size = FS_LARGE; break;
-					case '\n': goto end_of_inner_loop;
-				}
-			}
-		}
-end_of_inner_loop:
-		/* string didn't fit on line, so 'dummy' terminate and increase linecount */
-		num++;
-		str[-1] = '\0';
-	}
-}
-
-/** Draw a given string with the centre around the given x coordinates
- * @param x Centre the string around this pixel width
- * @param y Draw the string at this pixel height (first line's bottom)
- * @param str String to draw
- * @param max Maximum width the string can have before it is wrapped */
-void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
-{
-	char buffer[512];
-	uint32 tmp;
-	int num, w, mt;
-	const char *src;
-	WChar c;
-
-	GetString(buffer, str, lastof(buffer));
-
-	tmp = FormatStringLinebreaks(buffer, maxw);
-	num = GB(tmp, 0, 16);
-
-	mt = GetCharacterHeight(GB(tmp, 16, 16));
-
-	y -= (mt >> 1) * num;
-
-	src = buffer;
-
-	for (;;) {
-		w = GetStringBoundingBox(src).width;
-		DoDrawString(src, x - (w>>1), y, 0xFE);
-		_cur_fontsize = _last_fontsize;
-
-		for (;;) {
-			c = Utf8Consume(&src);
-			if (c == 0) {
-				y += mt;
-				if (--num < 0) {
-					_cur_fontsize = FS_NORMAL;
-					return;
-				}
-				break;
-			} else if (c == SCC_SETX) {
-				src++;
-			} else if (c == SCC_SETXY) {
-				src+=2;
-			}
-		}
-	}
-}
-
-
-uint DrawStringMultiLine(int x, int y, StringID str, int maxw)
-{
-	char buffer[512];
-	uint32 tmp;
-	int num, mt;
-	uint total_height;
-	const char *src;
-	WChar c;
-
-	GetString(buffer, str, lastof(buffer));
-
-	tmp = FormatStringLinebreaks(buffer, maxw);
-	num = GB(tmp, 0, 16);
-
-	mt = GetCharacterHeight(GB(tmp, 16, 16));
-	total_height = (num + 1) * mt;
-
-	src = buffer;
-
-	for (;;) {
-		DoDrawString(src, x, y, 0xFE);
-		_cur_fontsize = _last_fontsize;
-
-		for (;;) {
-			c = Utf8Consume(&src);
-			if (c == 0) {
-				y += mt;
-				if (--num < 0) {
-					_cur_fontsize = FS_NORMAL;
-					return total_height;
-				}
-				break;
-			} else if (c == SCC_SETX) {
-				src++;
-			} else if (c == SCC_SETXY) {
-				src+=2;
-			}
-		}
-	}
-}
-
-/** Return the string dimension in pixels. The height and width are returned
- * in a single BoundingRect value. TINYFONT, BIGFONT modifiers are only
- * supported as the first character of the string. The returned dimensions
- * are therefore a rough estimation correct for all the current strings
- * but not every possible combination
- * @param str string to calculate pixel-width
- * @return string width and height in pixels */
-BoundingRect GetStringBoundingBox(const char *str)
-{
-	FontSize size = _cur_fontsize;
-	BoundingRect br;
-	int max_width;
-	WChar c;
-
-	br.width = br.height = max_width = 0;
-	for (;;) {
-		c = Utf8Consume(&str);
-		if (c == 0) break;
-		if (IsPrintable(c)) {
-			br.width += GetCharacterWidth(size, c);
-		} else {
-			switch (c) {
-				case SCC_SETX: br.width += (byte)*str++; break;
-				case SCC_SETXY:
-					br.width += (byte)*str++;
-					br.height += (byte)*str++;
-					break;
-				case SCC_TINYFONT: size = FS_SMALL; break;
-				case SCC_BIGFONT:  size = FS_LARGE; break;
-				case '\n':
-					br.height += GetCharacterHeight(size);
-					if (br.width > max_width) max_width = br.width;
-					br.width = 0;
-					break;
-			}
-		}
-	}
-	br.height += GetCharacterHeight(size);
-
-	br.width  = max(br.width, max_width);
-	return br;
-}
-
-/** Draw a string at the given coordinates with the given colour
- * @param string the string to draw
- * @param x offset from left side of the screen, if negative offset from the right side
- * @param x offset from top side of the screen, if negative offset from the bottom
- * @param real_color colour of the string, see _string_colormap in
- * table/palettes.h or docs/ottd-colourtext-palette.png
- * @return the x-coordinates where the drawing has finished. If nothing is drawn
- * the originally passed x-coordinate is returned */
-int DoDrawString(const char *string, int x, int y, uint16 real_color)
-{
-	DrawPixelInfo *dpi = _cur_dpi;
-	FontSize size = _cur_fontsize;
-	WChar c;
-	byte color;
-	int xo = x, yo = y;
-
-	color = real_color & 0xFF;
-
-	if (color != 0xFE) {
-		if (x >= dpi->left + dpi->width ||
-				x + _screen.width*2 <= dpi->left ||
-				y >= dpi->top + dpi->height ||
-				y + _screen.height <= dpi->top)
-					return x;
-
-		if (color != 0xFF) {
-switch_color:;
-			if (real_color & IS_PALETTE_COLOR) {
-				_string_colorremap[1] = color;
-				_string_colorremap[2] = 215;
-			} else {
-				_string_colorremap[1] = _string_colormap[color].text;
-				_string_colorremap[2] = _string_colormap[color].shadow;
-			}
-			_color_remap_ptr = _string_colorremap;
-		}
-	}
-
-check_bounds:
-	if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
-skip_char:;
-		for (;;) {
-			c = Utf8Consume(&string);
-			if (!IsPrintable(c)) goto skip_cont;
-		}
-	}
-
-	for (;;) {
-		c = Utf8Consume(&string);
-skip_cont:;
-		if (c == 0) {
-			_last_fontsize = size;
-			return x;
-		}
-		if (IsPrintable(c)) {
-			if (x >= dpi->left + dpi->width) goto skip_char;
-			if (x + 26 >= dpi->left) {
-				GfxMainBlitter(GetGlyph(size, c), x, y, BM_COLOUR_REMAP);
-			}
-			x += GetCharacterWidth(size, c);
-		} else if (c == '\n') { // newline = {}
-			x = xo;
-			y += GetCharacterHeight(size);
-			goto check_bounds;
-		} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change color?
-			color = (byte)(c - SCC_BLUE);
-			goto switch_color;
-		} else if (c == SCC_SETX) { // {SETX}
-			x = xo + (byte)*string++;
-		} else if (c == SCC_SETXY) {// {SETXY}
-			x = xo + (byte)*string++;
-			y = yo + (byte)*string++;
-		} else if (c == SCC_TINYFONT) { // {TINYFONT}
-			size = FS_SMALL;
-		} else if (c == SCC_BIGFONT) { // {BIGFONT}
-			size = FS_LARGE;
-		} else {
-			DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
-		}
-	}
-}
-
-int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw)
-{
-	char buffer[512];
-	ttd_strlcpy(buffer, str, sizeof(buffer));
-	TruncateString(buffer, maxw);
-	return DoDrawString(buffer, x, y, color);
-}
-
-void DrawSprite(uint32 img, int x, int y)
-{
-	if (img & PALETTE_MODIFIER_COLOR) {
-		_color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1;
-		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_COLOUR_REMAP);
-	} else if (img & PALETTE_MODIFIER_TRANSPARENT) {
-		_color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1;
-		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_TRANSPARENT);
-	} else {
-		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_NORMAL);
-	}
-}
-
-typedef struct BlitterParams {
-	int start_x, start_y;
-	const byte *sprite;
-	Pixel *dst;
-	BlitterMode mode;
-	int width, height;
-	int width_org;
-	int pitch;
-} BlitterParams;
-
-static void GfxBlitTileZoomIn(BlitterParams *bp)
-{
-	const byte *src_o = bp->sprite;
-	const byte *src;
-	int num, skip;
-	byte done;
-	Pixel *dst;
-	const byte *ctab;
-
-	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-
-					for (; num >= 4; num -=4) {
-						dst[3] = ctab[src[3]];
-						dst[2] = ctab[src[2]];
-						dst[1] = ctab[src[1]];
-						dst[0] = ctab[src[0]];
-						dst += 4;
-						src += 4;
-					}
-					for (; num != 0; num--) *dst++ = ctab[*src++];
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-
-		case BM_TRANSPARENT:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					for (; num != 0; num--) {
-						*dst = ctab[*dst];
-						dst++;
-					}
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-
-		default:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-#if defined(_WIN32)
-					if (num & 1) *dst++ = *src++;
-					if (num & 2) { *(uint16*)dst = *(uint16*)src; dst += 2; src += 2; }
-					if (num >>= 2) {
-						do {
-							*(uint32*)dst = *(uint32*)src;
-							dst += 4;
-							src += 4;
-						} while (--num != 0);
-					}
-#else
-					memcpy(dst, src, num);
-#endif
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-	}
-}
-
-static void GfxBlitZoomInUncomp(BlitterParams *bp)
-{
-	const byte *src = bp->sprite;
-	Pixel *dst = bp->dst;
-	int height = bp->height;
-	int width = bp->width;
-	int i;
-
-	assert(height > 0);
-	assert(width > 0);
-
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP: {
-			const byte *ctab = _color_remap_ptr;
-
-			do {
-				for (i = 0; i != width; i++) {
-					byte b = ctab[src[i]];
-
-					if (b != 0) dst[i] = b;
-				}
-				src += bp->width_org;
-				dst += bp->pitch;
-			} while (--height != 0);
-			break;
-		}
-
-		case BM_TRANSPARENT: {
-			const byte *ctab = _color_remap_ptr;
-
-			do {
-				for (i = 0; i != width; i++)
-					if (src[i] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org;
-				dst += bp->pitch;
-			} while (--height != 0);
-			break;
-		}
-
-		default:
-			do {
-				int n = width;
-
-				for (; n >= 4; n -= 4) {
-					if (src[0] != 0) dst[0] = src[0];
-					if (src[1] != 0) dst[1] = src[1];
-					if (src[2] != 0) dst[2] = src[2];
-					if (src[3] != 0) dst[3] = src[3];
-
-					dst += 4;
-					src += 4;
-				}
-
-				for (; n != 0; n--) {
-					if (src[0] != 0) dst[0] = src[0];
-					src++;
-					dst++;
-				}
-
-				src += bp->width_org - width;
-				dst += bp->pitch - width;
-			} while (--height != 0);
-			break;
-	}
-}
-
-static void GfxBlitTileZoomMedium(BlitterParams *bp)
-{
-	const byte *src_o = bp->sprite;
-	const byte *src;
-	int num, skip;
-	byte done;
-	Pixel *dst;
-	const byte *ctab;
-
-	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 1) >> 1;
-					for (; num != 0; num--) {
-							*dst = ctab[*src];
-							dst++;
-							src += 2;
-					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-
-		case BM_TRANSPARENT:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						if (--num == 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 1) >> 1;
-					for (; num != 0; num--) {
-							*dst = ctab[*dst];
-							dst++;
-					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-
-		default:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					num = (num + 1) >> 1;
-
-					for (; num != 0; num--) {
-							*dst = *src;
-							dst++;
-							src += 2;
-					}
-
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-	}
-}
-
-static void GfxBlitZoomMediumUncomp(BlitterParams *bp)
-{
-	const byte *src = bp->sprite;
-	Pixel *dst = bp->dst;
-	int height = bp->height;
-	int width = bp->width;
-	int i;
-
-	assert(height > 0);
-	assert(width > 0);
-
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++) {
-					byte b = ctab[src[i * 2]];
-
-					if (b != 0) dst[i] = b;
-				}
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		case BM_TRANSPARENT: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++)
-					if (src[i * 2] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		default:
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++)
-					if (src[i * 2] != 0) dst[i] = src[i * 2];
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
-	}
-}
-
-static void GfxBlitTileZoomOut(BlitterParams *bp)
-{
-	const byte *src_o = bp->sprite;
-	const byte *src;
-	int num, skip;
-	byte done;
-	Pixel *dst;
-	const byte *ctab;
-
-	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						src += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 3) >> 2;
-					for (; num != 0; num--) {
-							*dst = ctab[*src];
-							dst++;
-							src += 4;
-					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-
-		case BM_TRANSPARENT:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 3) >> 2;
-					for (; num != 0; num--) {
-							*dst = ctab[*dst];
-							dst++;
-					}
-
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-
-		default:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						src += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					num = (num + 3) >> 2;
-
-					for (; num != 0; num--) {
-							*dst = *src;
-							dst++;
-							src += 4;
-					}
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-	}
-}
-
-static void GfxBlitZoomOutUncomp(BlitterParams *bp)
-{
-	const byte *src = bp->sprite;
-	Pixel *dst = bp->dst;
-	int height = bp->height;
-	int width = bp->width;
-	int i;
-
-	assert(height > 0);
-	assert(width > 0);
-
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++) {
-					byte b = ctab[src[i * 4]];
-
-					if (b != 0) dst[i] = b;
-				}
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		case BM_TRANSPARENT: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++)
-					if (src[i * 4] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		default:
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++)
-					if (src[i * 4] != 0) dst[i] = src[i * 4];
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-	}
-}
-
-
-static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode)
-{
-	const DrawPixelInfo *dpi = _cur_dpi;
-	int start_x, start_y;
-	BlitterParams bp;
-	int zoom_mask = ~((1 << dpi->zoom) - 1);
-
-	/* decode sprite header */
-	x += sprite->x_offs;
-	y += sprite->y_offs;
-	bp.width_org = bp.width = sprite->width;
-	bp.height = sprite->height;
-	bp.sprite = sprite->data;
-	bp.dst = dpi->dst_ptr;
-	bp.mode = mode;
-	bp.pitch = dpi->pitch;
-
-	assert(bp.height > 0);
-	assert(bp.width > 0);
-
-	if (sprite->info & 8) {
-		/* tile blit */
-		start_y = 0;
-
-		if (dpi->zoom > 0) {
-			start_y += bp.height & ~zoom_mask;
-			bp.height &= zoom_mask;
-			if (bp.height == 0) return;
-			y &= zoom_mask;
-		}
-
-		if ( (y -= dpi->top) < 0) {
-			bp.height += y;
-			if (bp.height <= 0) return;
-			start_y -= y;
-			y = 0;
-		} else {
-			bp.dst += bp.pitch * (y >> dpi->zoom);
-		}
-		bp.start_y = start_y;
-
-		if ( (y = y + bp.height - dpi->height) > 0) {
-			bp.height -= y;
-			if (bp.height <= 0) return;
-		}
-
-		start_x = 0;
-		x &= zoom_mask;
-		if ( (x -= dpi->left) < 0) {
-			bp.width += x;
-			if (bp.width <= 0) return;
-			start_x -= x;
-			x = 0;
-		}
-		bp.start_x = start_x;
-		bp.dst += x >> dpi->zoom;
-
-		if ( (x = x + bp.width - dpi->width) > 0) {
-			bp.width -= x;
-			if (bp.width <= 0) return;
-		}
-
-		switch (dpi->zoom) {
-			default: NOT_REACHED();
-			case 0: GfxBlitTileZoomIn(&bp);     break;
-			case 1: GfxBlitTileZoomMedium(&bp); break;
-			case 2: GfxBlitTileZoomOut(&bp);    break;
-		}
-	} else {
-		bp.sprite += bp.width * (bp.height & ~zoom_mask);
-		bp.height &= zoom_mask;
-		if (bp.height == 0) return;
-
-		y &= zoom_mask;
-
-		if ( (y -= dpi->top) < 0) {
-			bp.height += y;
-			if (bp.height <= 0) return;
-			bp.sprite -= bp.width * y;
-			y = 0;
-		} else {
-			bp.dst += bp.pitch * (y >> dpi->zoom);
-		}
-
-		if (bp.height > dpi->height - y) {
-			bp.height = dpi->height - y;
-			if (bp.height <= 0) return;
-		}
-
-		x &= zoom_mask;
-
-		if ( (x -= dpi->left) < 0) {
-			bp.width += x;
-			if (bp.width <= 0) return;
-			bp.sprite -= x;
-			x = 0;
-		}
-		bp.dst += x >> dpi->zoom;
-
-		if (bp.width > dpi->width - x) {
-			bp.width = dpi->width - x;
-			if (bp.width <= 0) return;
-		}
-
-		switch (dpi->zoom) {
-			default: NOT_REACHED();
-			case 0: GfxBlitZoomInUncomp(&bp);     break;
-			case 1: GfxBlitZoomMediumUncomp(&bp); break;
-			case 2: GfxBlitZoomOutUncomp(&bp);    break;
-		}
-	}
-}
-
-void DoPaletteAnimations(void);
-
-void GfxInitPalettes(void)
-{
-	memcpy(_cur_palette, _palettes[_use_dos_palette ? 1 : 0], sizeof(_cur_palette));
-
-	_pal_first_dirty = 0;
-	_pal_last_dirty = 255;
-	DoPaletteAnimations();
-}
-
-#define EXTR(p, q) (((uint16)(_timer_counter * (p)) * (q)) >> 16)
-#define EXTR2(p, q) (((uint16)(~_timer_counter * (p)) * (q)) >> 16)
-
-void DoPaletteAnimations(void)
-{
-	const Colour *s;
-	Colour *d;
-	/* Amount of colors to be rotated.
-	 * A few more for the DOS palette, because the water colors are
-	 * 245-254 for DOS and 217-226 for Windows.  */
-	const ExtraPaletteValues *ev = &_extra_palette_values;
-	int c = _use_dos_palette ? 38 : 28;
-	Colour old_val[38]; // max(38, 28)
-	uint i;
-	uint j;
-
-	d = &_cur_palette[217];
-	memcpy(old_val, d, c * sizeof(*old_val));
-
-	// Dark blue water
-	s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
-	j = EXTR(320, 5);
-	for (i = 0; i != 5; i++) {
-		*d++ = s[j];
-		j++;
-		if (j == 5) j = 0;
-	}
-
-	// Glittery water
-	s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
-	j = EXTR(128, 15);
-	for (i = 0; i != 5; i++) {
-		*d++ = s[j];
-		j += 3;
-		if (j >= 15) j -= 15;
-	}
-
-	s = ev->e;
-	j = EXTR2(512, 5);
-	for (i = 0; i != 5; i++) {
-		*d++ = s[j];
-		j++;
-		if (j == 5) j = 0;
-	}
-
-	// Oil refinery fire animation
-	s = ev->oil_ref;
-	j = EXTR2(512, 7);
-	for (i = 0; i != 7; i++) {
-		*d++ = s[j];
-		j++;
-		if (j == 7) j = 0;
-	}
-
-	// Radio tower blinking
-	{
-		byte i = (_timer_counter >> 1) & 0x7F;
-		byte v;
-
-		(v = 255, i < 0x3f) ||
-		(v = 128, i < 0x4A || i >= 0x75) ||
-		(v = 20);
-		d->r = v;
-		d->g = 0;
-		d->b = 0;
-		d++;
-
-		i ^= 0x40;
-		(v = 255, i < 0x3f) ||
-		(v = 128, i < 0x4A || i >= 0x75) ||
-		(v = 20);
-		d->r = v;
-		d->g = 0;
-		d->b = 0;
-		d++;
-	}
-
-	// Handle lighthouse and stadium animation
-	s = ev->lighthouse;
-	j = EXTR(256, 4);
-	for (i = 0; i != 4; i++) {
-		*d++ = s[j];
-		j++;
-		if (j == 4) j = 0;
-	}
-
-	// Animate water for old DOS graphics
-	if (_use_dos_palette) {
-		// Dark blue water DOS
-		s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
-		j = EXTR(320, 5);
-		for (i = 0; i != 5; i++) {
-			*d++ = s[j];
-			j++;
-			if (j == 5) j = 0;
-		}
-
-		// Glittery water DOS
-		s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
-		j = EXTR(128, 15);
-		for (i = 0; i != 5; i++) {
-			*d++ = s[j];
-			j += 3;
-			if (j >= 15) j -= 15;
-		}
-	}
-
-	if (memcmp(old_val, &_cur_palette[217], c * sizeof(*old_val)) != 0) {
-		if (_pal_first_dirty > 217) _pal_first_dirty = 217;
-		if (_pal_last_dirty < 217 + c) _pal_last_dirty = 217 + c;
-	}
-}
-
-
-void LoadStringWidthTable(void)
-{
-	uint i;
-
-	/* Normal font */
-	for (i = 0; i != 224; i++) {
-		_stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32);
-	}
-
-	/* Small font */
-	for (i = 0; i != 224; i++) {
-		_stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32);
-	}
-
-	/* Large font */
-	for (i = 0; i != 224; i++) {
-		_stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32);
-	}
-}
-
-
-byte GetCharacterWidth(FontSize size, WChar key)
-{
-	if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
-
-	return GetGlyphWidth(size, key);
-}
-
-
-void ScreenSizeChanged(void)
-{
-	// check the dirty rect
-	if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
-	if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
-
-	// screen size changed and the old bitmap is invalid now, so we don't want to undraw it
-	_cursor.visible = false;
-}
-
-void UndrawMouseCursor(void)
-{
-	if (_cursor.visible) {
-		_cursor.visible = false;
-		memcpy_pitch(
-			_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
-			_cursor_backup,
-			_cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x, _screen.pitch);
-
-		_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
-	}
-}
-
-void DrawMouseCursor(void)
-{
-	int x;
-	int y;
-	int w;
-	int h;
-
-	/* Redraw mouse cursor but only when it's inside the window */
-	if (!_cursor.in_window) return;
-
-	// Don't draw the mouse cursor if it's already drawn
-	if (_cursor.visible) {
-		if (!_cursor.dirty) return;
-		UndrawMouseCursor();
-	}
-
-	w = _cursor.size.x;
-	x = _cursor.pos.x + _cursor.offs.x;
-	if (x < 0) {
-		w += x;
-		x = 0;
-	}
-	if (w > _screen.width - x) w = _screen.width - x;
-	if (w <= 0) return;
-	_cursor.draw_pos.x = x;
-	_cursor.draw_size.x = w;
-
-	h = _cursor.size.y;
-	y = _cursor.pos.y + _cursor.offs.y;
-	if (y < 0) {
-		h += y;
-		y = 0;
-	}
-	if (h > _screen.height - y) h = _screen.height - y;
-	if (h <= 0) return;
-	_cursor.draw_pos.y = y;
-	_cursor.draw_size.y = h;
-
-	assert(w * h < (int)sizeof(_cursor_backup));
-
-	// Make backup of stuff below cursor
-	memcpy_pitch(
-		_cursor_backup,
-		_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
-		_cursor.draw_size.x, _cursor.draw_size.y, _screen.pitch, _cursor.draw_size.x);
-
-	// Draw cursor on screen
-	_cur_dpi = &_screen;
-	DrawSprite(_cursor.sprite, _cursor.pos.x, _cursor.pos.y);
-
-	_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
-
-	_cursor.visible = true;
-	_cursor.dirty = false;
-}
-
-#if defined(_DEBUG)
-static void DbgScreenRect(int left, int top, int right, int bottom)
-{
-	DrawPixelInfo dp;
-	DrawPixelInfo *old;
-
-	old = _cur_dpi;
-	_cur_dpi = &dp;
-	dp = _screen;
-	GfxFillRect(left, top, right - 1, bottom - 1, rand() & 255);
-	_cur_dpi = old;
-}
-#endif
-
-void RedrawScreenRect(int left, int top, int right, int bottom)
-{
-	assert(right <= _screen.width && bottom <= _screen.height);
-	if (_cursor.visible) {
-		if (right > _cursor.draw_pos.x &&
-				left < _cursor.draw_pos.x + _cursor.draw_size.x &&
-				bottom > _cursor.draw_pos.y &&
-				top < _cursor.draw_pos.y + _cursor.draw_size.y) {
-			UndrawMouseCursor();
-		}
-	}
-	UndrawTextMessage();
-
-#if defined(_DEBUG)
-	if (_dbg_screen_rect)
-		DbgScreenRect(left, top, right, bottom);
-	else
-#endif
-		DrawOverlappedWindowForAll(left, top, right, bottom);
-
-	_video_driver->make_dirty(left, top, right - left, bottom - top);
-}
-
-void DrawDirtyBlocks(void)
-{
-	byte *b = _dirty_blocks;
-	const int w = ALIGN(_screen.width, 64);
-	const int h = ALIGN(_screen.height, 8);
-	int x;
-	int y;
-
-	if (IsGeneratingWorld() && !IsGeneratingWorldReadyForPaint()) return;
-
-	y = 0;
-	do {
-		x = 0;
-		do {
-			if (*b != 0) {
-				int left;
-				int top;
-				int right = x + 64;
-				int bottom = y;
-				byte *p = b;
-				int h2;
-
-				// First try coalescing downwards
-				do {
-					*p = 0;
-					p += DIRTY_BYTES_PER_LINE;
-					bottom += 8;
-				} while (bottom != h && *p != 0);
-
-				// Try coalescing to the right too.
-				h2 = (bottom - y) >> 3;
-				assert(h2 > 0);
-				p = b;
-
-				while (right != w) {
-					byte *p2 = ++p;
-					int h = h2;
-					// Check if a full line of dirty flags is set.
-					do {
-						if (!*p2) goto no_more_coalesc;
-						p2 += DIRTY_BYTES_PER_LINE;
-					} while (--h != 0);
-
-					// Wohoo, can combine it one step to the right!
-					// Do that, and clear the bits.
-					right += 64;
-
-					h = h2;
-					p2 = p;
-					do {
-						*p2 = 0;
-						p2 += DIRTY_BYTES_PER_LINE;
-					} while (--h != 0);
-				}
-				no_more_coalesc:
-
-				left = x;
-				top = y;
-
-				if (left   < _invalid_rect.left  ) left   = _invalid_rect.left;
-				if (top    < _invalid_rect.top   ) top    = _invalid_rect.top;
-				if (right  > _invalid_rect.right ) right  = _invalid_rect.right;
-				if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom;
-
-				if (left < right && top < bottom) {
-					RedrawScreenRect(left, top, right, bottom);
-				}
-
-			}
-		} while (b++, (x += 64) != w);
-	} while (b += -(w >> 6) + DIRTY_BYTES_PER_LINE, (y += 8) != h);
-
-	_invalid_rect.left = w;
-	_invalid_rect.top = h;
-	_invalid_rect.right = 0;
-	_invalid_rect.bottom = 0;
-
-	/* If we are generating a world, and waiting for a paint run, mark it here
-	 *  as done painting, so we can continue generating. */
-	if (IsGeneratingWorld() && IsGeneratingWorldReadyForPaint()) {
-		SetGeneratingWorldPaintStatus(false);
-	}
-}
-
-
-void SetDirtyBlocks(int left, int top, int right, int bottom)
-{
-	byte *b;
-	int width;
-	int height;
-
-	if (left < 0) left = 0;
-	if (top < 0) top = 0;
-	if (right > _screen.width) right = _screen.width;
-	if (bottom > _screen.height) bottom = _screen.height;
-
-	if (left >= right || top >= bottom) return;
-
-	if (left   < _invalid_rect.left  ) _invalid_rect.left   = left;
-	if (top    < _invalid_rect.top   ) _invalid_rect.top    = top;
-	if (right  > _invalid_rect.right ) _invalid_rect.right  = right;
-	if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom;
-
-	left >>= 6;
-	top  >>= 3;
-
-	b = _dirty_blocks + top * DIRTY_BYTES_PER_LINE + left;
-
-	width  = ((right  - 1) >> 6) - left + 1;
-	height = ((bottom - 1) >> 3) - top  + 1;
-
-	assert(width > 0 && height > 0);
-
-	do {
-		int i = width;
-
-		do b[--i] = 0xFF; while (i);
-
-		b += DIRTY_BYTES_PER_LINE;
-	} while (--height != 0);
-}
-
-void MarkWholeScreenDirty(void)
-{
-	SetDirtyBlocks(0, 0, _screen.width, _screen.height);
-}
-
-/** Set up a clipping area for only drawing into a certain area. To do this,
- * Fill a DrawPixelInfo object with the supplied relative rectangle, backup
- * the original (calling) _cur_dpi and assign the just returned DrawPixelInfo
- * _cur_dpi. When you are done, give restore _cur_dpi's original value
- * @param *n the DrawPixelInfo that will be the clipping rectangle box allowed
- * for drawing
- * @param left,top,width,height the relative coordinates of the clipping
- * rectangle relative to the current _cur_dpi. This will most likely be the
- * offset from the calling window coordinates
- * @return return false if the requested rectangle is not possible with the
- * current dpi pointer. Only continue of the return value is true, or you'll
- * get some nasty results */
-bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
-{
-	const DrawPixelInfo *o = _cur_dpi;
-
-	n->zoom = 0;
-
-	assert(width > 0);
-	assert(height > 0);
-
-	if ((left -= o->left) < 0) {
-		width += left;
-		if (width <= 0) return false;
-		n->left = -left;
-		left = 0;
-	} else {
-		n->left = 0;
-	}
-
-	if (width > o->width - left) {
-		width = o->width - left;
-		if (width <= 0) return false;
-	}
-	n->width = width;
-
-	if ((top -= o->top) < 0) {
-		height += top;
-		if (height <= 0) return false;
-		n->top = -top;
-		top = 0;
-	} else {
-		n->top = 0;
-	}
-
-	n->dst_ptr = o->dst_ptr + left + top * (n->pitch = o->pitch);
-
-	if (height > o->height - top) {
-		height = o->height - top;
-		if (height <= 0) return false;
-	}
-	n->height = height;
-
-	return true;
-}
-
-static void SetCursorSprite(CursorID cursor)
-{
-	CursorVars *cv = &_cursor;
-	const Sprite *p;
-
-	if (cv->sprite == cursor) return;
-
-	p = GetSprite(cursor & SPRITE_MASK);
-	cv->sprite = cursor;
-	cv->size.y = p->height;
-	cv->size.x = p->width;
-	cv->offs.x = p->x_offs;
-	cv->offs.y = p->y_offs;
-
-	cv->dirty = true;
-}
-
-static void SwitchAnimatedCursor(void)
-{
-	CursorVars *cv = &_cursor;
-	const CursorID *cur = cv->animate_cur;
-	CursorID sprite;
-
-	// ANIM_CURSOR_END is 0xFFFF in table/animcursors.h
-	if (cur == NULL || *cur == 0xFFFF) cur = cv->animate_list;
-
-	sprite = cur[0];
-	cv->animate_timeout = cur[1];
-	cv->animate_cur = cur + 2;
-
-	SetCursorSprite(sprite);
-}
-
-void CursorTick(void)
-{
-	if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0)
-		SwitchAnimatedCursor();
-}
-
-void SetMouseCursor(CursorID cursor)
-{
-	// Turn off animation
-	_cursor.animate_timeout = 0;
-	// Set cursor
-	SetCursorSprite(cursor);
-}
-
-void SetAnimatedMouseCursor(const CursorID *table)
-{
-	_cursor.animate_list = table;
-	_cursor.animate_cur = NULL;
-	SwitchAnimatedCursor();
-}
-
-bool ChangeResInGame(int w, int h)
-{
-	return
-		(_screen.width == w && _screen.height == h) ||
-		_video_driver->change_resolution(w, h);
-}
-
-void ToggleFullScreen(bool fs)
-{
-	_video_driver->toggle_fullscreen(fs);
-	if (_fullscreen != fs && _num_resolutions == 0) {
-		DEBUG(driver, 0, "Could not find a suitable fullscreen resolution");
-	}
-}
-
-static int CDECL compare_res(const void *pa, const void *pb)
-{
-	int x = ((const uint16*)pa)[0] - ((const uint16*)pb)[0];
-	if (x != 0) return x;
-	return ((const uint16*)pa)[1] - ((const uint16*)pb)[1];
-}
-
-void SortResolutions(int count)
-{
-	qsort(_resolutions, count, sizeof(_resolutions[0]), compare_res);
-}
new file mode 100644
--- /dev/null
+++ b/src/gfx.cpp
@@ -0,0 +1,2031 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "macros.h"
+#include "spritecache.h"
+#include "strings.h"
+#include "string.h"
+#include "gfx.h"
+#include "table/palettes.h"
+#include "table/sprites.h"
+#include "hal.h"
+#include "variables.h"
+#include "table/control_codes.h"
+#include "fontcache.h"
+#include "genworld.h"
+#include "debug.h"
+
+#ifdef _DEBUG
+bool _dbg_screen_rect;
+#endif
+
+Colour _cur_palette[256];
+byte _stringwidth_table[FS_END][224];
+
+typedef enum BlitterModes {
+	BM_NORMAL,
+	BM_COLOUR_REMAP,
+	BM_TRANSPARENT,
+} BlitterMode;
+
+static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode);
+
+FontSize _cur_fontsize;
+static FontSize _last_fontsize;
+static Pixel _cursor_backup[64 * 64];
+static Rect _invalid_rect;
+static const byte *_color_remap_ptr;
+static byte _string_colorremap[3];
+
+#define DIRTY_BYTES_PER_LINE (MAX_SCREEN_WIDTH / 64)
+static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8];
+
+void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch)
+{
+	byte *dstp = (byte*)dst;
+	byte *srcp = (byte*)src;
+
+	assert(h >= 0);
+	for (; h != 0; --h) {
+		memcpy(dstp, srcp, w);
+		dstp += dstpitch;
+		srcp += srcpitch;
+	}
+}
+
+void GfxScroll(int left, int top, int width, int height, int xo, int yo)
+{
+	const Pixel *src;
+	Pixel *dst;
+	int p;
+	int ht;
+
+	if (xo == 0 && yo == 0) return;
+
+	if (_cursor.visible) UndrawMouseCursor();
+	UndrawTextMessage();
+
+	p = _screen.pitch;
+
+	if (yo > 0) {
+		// Calculate pointers
+		dst = _screen.dst_ptr + (top + height - 1) * p + left;
+		src = dst - yo * p;
+
+		// Decrease height and increase top
+		top += yo;
+		height -= yo;
+		assert(height > 0);
+
+		// Adjust left & width
+		if (xo >= 0) {
+			dst += xo;
+			left += xo;
+			width -= xo;
+		} else {
+			src -= xo;
+			width += xo;
+		}
+
+		for (ht = height; ht > 0; --ht) {
+			memcpy(dst, src, width);
+			src -= p;
+			dst -= p;
+		}
+	} else {
+		// Calculate pointers
+		dst = _screen.dst_ptr + top * p + left;
+		src = dst - yo * p;
+
+		// Decrese height. (yo is <=0).
+		height += yo;
+		assert(height > 0);
+
+		// Adjust left & width
+		if (xo >= 0) {
+			dst += xo;
+			left += xo;
+			width -= xo;
+		} else {
+			src -= xo;
+			width += xo;
+		}
+
+		// the y-displacement may be 0 therefore we have to use memmove,
+		// because source and destination may overlap
+		for (ht = height; ht > 0; --ht) {
+			memmove(dst, src, width);
+			src += p;
+			dst += p;
+		}
+	}
+	// This part of the screen is now dirty.
+	_video_driver->make_dirty(left, top, width, height);
+}
+
+
+void GfxFillRect(int left, int top, int right, int bottom, int color)
+{
+	const DrawPixelInfo* dpi = _cur_dpi;
+	Pixel *dst;
+	const int otop = top;
+	const int oleft = left;
+
+	if (dpi->zoom != 0) return;
+	if (left > right || top > bottom) return;
+	if (right < dpi->left || left >= dpi->left + dpi->width) return;
+	if (bottom < dpi->top || top >= dpi->top + dpi->height) return;
+
+	if ( (left -= dpi->left) < 0) left = 0;
+	right = right - dpi->left + 1;
+	if (right > dpi->width) right = dpi->width;
+	right -= left;
+	assert(right > 0);
+
+	if ( (top -= dpi->top) < 0) top = 0;
+	bottom = bottom - dpi->top + 1;
+	if (bottom > dpi->height) bottom = dpi->height;
+	bottom -= top;
+	assert(bottom > 0);
+
+	dst = dpi->dst_ptr + top * dpi->pitch + left;
+
+	if (!(color & PALETTE_MODIFIER_GREYOUT)) {
+		if (!(color & USE_COLORTABLE)) {
+			do {
+				memset(dst, color, right);
+				dst += dpi->pitch;
+			} while (--bottom);
+		} else {
+			/* use colortable mode */
+			const byte* ctab = GetNonSprite(color & COLORTABLE_MASK) + 1;
+
+			do {
+				int i;
+				for (i = 0; i != right; i++) dst[i] = ctab[dst[i]];
+				dst += dpi->pitch;
+			} while (--bottom);
+		}
+	} else {
+		byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
+		do {
+			int i;
+			for (i = (bo ^= 1); i < right; i += 2) dst[i] = (byte)color;
+			dst += dpi->pitch;
+		} while (--bottom > 0);
+	}
+}
+
+static void GfxSetPixel(int x, int y, int color)
+{
+	const DrawPixelInfo* dpi = _cur_dpi;
+	if ((x-=dpi->left) < 0 || x>=dpi->width || (y-=dpi->top)<0 || y>=dpi->height)
+		return;
+	dpi->dst_ptr[y * dpi->pitch + x] = color;
+}
+
+void GfxDrawLine(int x, int y, int x2, int y2, int color)
+{
+	int dy;
+	int dx;
+	int stepx;
+	int stepy;
+	int frac;
+
+	// Check clipping first
+	{
+		DrawPixelInfo *dpi = _cur_dpi;
+		int t;
+
+		if (x < dpi->left && x2 < dpi->left) return;
+
+		if (y < dpi->top && y2 < dpi->top) return;
+
+		t = dpi->left + dpi->width;
+		if (x > t && x2 > t) return;
+
+		t = dpi->top + dpi->height;
+		if (y > t && y2 > t) return;
+	}
+
+	dy = (y2 - y) * 2;
+	if (dy < 0) {
+		dy = -dy;
+		stepy = -1;
+	} else {
+		stepy = 1;
+	}
+
+	dx = (x2 - x) * 2;
+	if (dx < 0) {
+		dx = -dx;
+		stepx = -1;
+	} else {
+		stepx = 1;
+	}
+
+	GfxSetPixel(x, y, color);
+	if (dx > dy) {
+		frac = dy - (dx >> 1);
+		while (x != x2) {
+			if (frac >= 0) {
+				y += stepy;
+				frac -= dx;
+			}
+			x += stepx;
+			frac += dy;
+			GfxSetPixel(x, y, color);
+		}
+	} else {
+		frac = dx - (dy >> 1);
+		while (y != y2) {
+			if (frac >= 0) {
+				x += stepx;
+				frac -= dy;
+			}
+			y += stepy;
+			frac += dx;
+			GfxSetPixel(x, y, color);
+		}
+	}
+}
+
+
+/** Truncate a given string to a maximum width if neccessary.
+ * If the string is truncated, add three dots ('...') to show this.
+ * @param *dest string that is checked and possibly truncated
+ * @param maxw maximum width in pixels of the string
+ * @return new width of (truncated) string */
+static int TruncateString(char *str, int maxw)
+{
+	int w = 0;
+	FontSize size = _cur_fontsize;
+	int ddd, ddd_w;
+
+	WChar c;
+	char *ddd_pos;
+
+	ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
+
+	for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
+		if (IsPrintable(c)) {
+			w += GetCharacterWidth(size, c);
+
+			if (w >= maxw) {
+				// string got too big... insert dotdotdot
+				ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.';
+				ddd_pos[3] = 0;
+				return ddd_w;
+			}
+		} else {
+			if (c == SCC_SETX) str++;
+			else if (c == SCC_SETXY) str += 2;
+			else if (c == SCC_TINYFONT) {
+				size = FS_SMALL;
+				ddd = GetCharacterWidth(size, '.') * 3;
+			} else if (c == SCC_BIGFONT) {
+				size = FS_LARGE;
+				ddd = GetCharacterWidth(size, '.') * 3;
+			}
+		}
+
+		// Remember the last position where three dots fit.
+		if (w + ddd < maxw) {
+			ddd_w = w + ddd;
+			ddd_pos = str;
+		}
+	}
+
+	return w;
+}
+
+static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last)
+{
+	GetString(dest, src, last);
+	return TruncateString(dest, maxw);
+}
+
+/* returns right coordinate */
+int DrawString(int x, int y, StringID str, uint16 color)
+{
+	char buffer[512];
+
+	GetString(buffer, str, lastof(buffer));
+	return DoDrawString(buffer, x, y, color);
+}
+
+int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw)
+{
+	char buffer[512];
+	TruncateStringID(str, buffer, maxw, lastof(buffer));
+	return DoDrawString(buffer, x, y, color);
+}
+
+
+int DrawStringRightAligned(int x, int y, StringID str, uint16 color)
+{
+	char buffer[512];
+	int w;
+
+	GetString(buffer, str, lastof(buffer));
+	w = GetStringBoundingBox(buffer).width;
+	DoDrawString(buffer, x - w, y, color);
+
+	return w;
+}
+
+void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw)
+{
+	char buffer[512];
+
+	TruncateStringID(str, buffer, maxw, lastof(buffer));
+	DoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color);
+}
+
+void DrawStringRightAlignedUnderline(int x, int y, StringID str, uint16 color)
+{
+	int w = DrawStringRightAligned(x, y, str, color);
+	GfxFillRect(x - w, y + 10, x, y + 10, _string_colorremap[1]);
+}
+
+
+int DrawStringCentered(int x, int y, StringID str, uint16 color)
+{
+	char buffer[512];
+	int w;
+
+	GetString(buffer, str, lastof(buffer));
+
+	w = GetStringBoundingBox(buffer).width;
+	DoDrawString(buffer, x - w / 2, y, color);
+
+	return w;
+}
+
+int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color)
+{
+	char buffer[512];
+	int w = TruncateStringID(str, buffer, xr - xl, lastof(buffer));
+	return DoDrawString(buffer, (xl + xr - w) / 2, y, color);
+}
+
+int DoDrawStringCentered(int x, int y, const char *str, uint16 color)
+{
+	int w = GetStringBoundingBox(str).width;
+	DoDrawString(str, x - w / 2, y, color);
+	return w;
+}
+
+void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color)
+{
+	int w = DrawStringCentered(x, y, str, color);
+	GfxFillRect(x - (w >> 1), y + 10, x - (w >> 1) + w, y + 10, _string_colorremap[1]);
+}
+
+void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color)
+{
+	int w = DrawStringCenteredTruncated(xl, xr, y, str, color);
+	GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]);
+}
+
+/** 'Correct' a string to a maximum length. Longer strings will be cut into
+ * additional lines at whitespace characters if possible. The string parameter
+ * is modified with terminating characters mid-string which are the
+ * placeholders for the newlines.<br/>
+ * The string WILL be truncated if there was no whitespace for the current
+ * line's maximum width.
+ *
+ * @note To know if the the terminating '\0' is the string end or just a
+ * newline, the returned 'num' value should be consulted. The num'th '\0',
+ * starting with index 0 is the real string end.
+ *
+ * @param str string to check and correct for length restrictions
+ * @param maxw the maximum width the string can have on one line
+ * @return return a 32bit wide number consisting of 2 packed values:
+ *  0 - 15 the number of lines ADDED to the string
+ * 16 - 31 the fontsize in which the length calculation was done at */
+uint32 FormatStringLinebreaks(char *str, int maxw)
+{
+	FontSize size = _cur_fontsize;
+	int num = 0;
+
+	assert(maxw > 0);
+
+	for (;;) {
+		char *last_space = NULL;
+		int w = 0;
+
+		for (;;) {
+			WChar c = Utf8Consume((const char **)&str);
+			/* whitespace is where we will insert the line-break */
+			if (c == ' ') last_space = str;
+
+			if (IsPrintable(c)) {
+				w += GetCharacterWidth(size, c);
+				/* string is longer than maximum width so we need to decide what to
+				 * do. We can do two things:
+				 * 1. If no whitespace was found at all up until now (on this line) then
+				 *    we will truncate the string and bail out.
+				 * 2. In all other cases force a linebreak at the last seen whitespace */
+				if (w > maxw) {
+					if (last_space == NULL) {
+						str[-1] = '\0';
+						return num + (size << 16);
+					}
+					str = last_space;
+					break;
+				}
+			} else {
+				switch (c) {
+					case '\0': return num + (size << 16); break;
+					case SCC_SETX:  str++; break;
+					case SCC_SETXY: str +=2; break;
+					case SCC_TINYFONT: size = FS_SMALL; break;
+					case SCC_BIGFONT:  size = FS_LARGE; break;
+					case '\n': goto end_of_inner_loop;
+				}
+			}
+		}
+end_of_inner_loop:
+		/* string didn't fit on line, so 'dummy' terminate and increase linecount */
+		num++;
+		str[-1] = '\0';
+	}
+}
+
+/** Draw a given string with the centre around the given x coordinates
+ * @param x Centre the string around this pixel width
+ * @param y Draw the string at this pixel height (first line's bottom)
+ * @param str String to draw
+ * @param max Maximum width the string can have before it is wrapped */
+void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
+{
+	char buffer[512];
+	uint32 tmp;
+	int num, w, mt;
+	const char *src;
+	WChar c;
+
+	GetString(buffer, str, lastof(buffer));
+
+	tmp = FormatStringLinebreaks(buffer, maxw);
+	num = GB(tmp, 0, 16);
+
+	mt = GetCharacterHeight(GB(tmp, 16, 16));
+
+	y -= (mt >> 1) * num;
+
+	src = buffer;
+
+	for (;;) {
+		w = GetStringBoundingBox(src).width;
+		DoDrawString(src, x - (w>>1), y, 0xFE);
+		_cur_fontsize = _last_fontsize;
+
+		for (;;) {
+			c = Utf8Consume(&src);
+			if (c == 0) {
+				y += mt;
+				if (--num < 0) {
+					_cur_fontsize = FS_NORMAL;
+					return;
+				}
+				break;
+			} else if (c == SCC_SETX) {
+				src++;
+			} else if (c == SCC_SETXY) {
+				src+=2;
+			}
+		}
+	}
+}
+
+
+uint DrawStringMultiLine(int x, int y, StringID str, int maxw)
+{
+	char buffer[512];
+	uint32 tmp;
+	int num, mt;
+	uint total_height;
+	const char *src;
+	WChar c;
+
+	GetString(buffer, str, lastof(buffer));
+
+	tmp = FormatStringLinebreaks(buffer, maxw);
+	num = GB(tmp, 0, 16);
+
+	mt = GetCharacterHeight(GB(tmp, 16, 16));
+	total_height = (num + 1) * mt;
+
+	src = buffer;
+
+	for (;;) {
+		DoDrawString(src, x, y, 0xFE);
+		_cur_fontsize = _last_fontsize;
+
+		for (;;) {
+			c = Utf8Consume(&src);
+			if (c == 0) {
+				y += mt;
+				if (--num < 0) {
+					_cur_fontsize = FS_NORMAL;
+					return total_height;
+				}
+				break;
+			} else if (c == SCC_SETX) {
+				src++;
+			} else if (c == SCC_SETXY) {
+				src+=2;
+			}
+		}
+	}
+}
+
+/** Return the string dimension in pixels. The height and width are returned
+ * in a single BoundingRect value. TINYFONT, BIGFONT modifiers are only
+ * supported as the first character of the string. The returned dimensions
+ * are therefore a rough estimation correct for all the current strings
+ * but not every possible combination
+ * @param str string to calculate pixel-width
+ * @return string width and height in pixels */
+BoundingRect GetStringBoundingBox(const char *str)
+{
+	FontSize size = _cur_fontsize;
+	BoundingRect br;
+	int max_width;
+	WChar c;
+
+	br.width = br.height = max_width = 0;
+	for (;;) {
+		c = Utf8Consume(&str);
+		if (c == 0) break;
+		if (IsPrintable(c)) {
+			br.width += GetCharacterWidth(size, c);
+		} else {
+			switch (c) {
+				case SCC_SETX: br.width += (byte)*str++; break;
+				case SCC_SETXY:
+					br.width += (byte)*str++;
+					br.height += (byte)*str++;
+					break;
+				case SCC_TINYFONT: size = FS_SMALL; break;
+				case SCC_BIGFONT:  size = FS_LARGE; break;
+				case '\n':
+					br.height += GetCharacterHeight(size);
+					if (br.width > max_width) max_width = br.width;
+					br.width = 0;
+					break;
+			}
+		}
+	}
+	br.height += GetCharacterHeight(size);
+
+	br.width  = max(br.width, max_width);
+	return br;
+}
+
+/** Draw a string at the given coordinates with the given colour
+ * @param string the string to draw
+ * @param x offset from left side of the screen, if negative offset from the right side
+ * @param x offset from top side of the screen, if negative offset from the bottom
+ * @param real_color colour of the string, see _string_colormap in
+ * table/palettes.h or docs/ottd-colourtext-palette.png
+ * @return the x-coordinates where the drawing has finished. If nothing is drawn
+ * the originally passed x-coordinate is returned */
+int DoDrawString(const char *string, int x, int y, uint16 real_color)
+{
+	DrawPixelInfo *dpi = _cur_dpi;
+	FontSize size = _cur_fontsize;
+	WChar c;
+	byte color;
+	int xo = x, yo = y;
+
+	color = real_color & 0xFF;
+
+	if (color != 0xFE) {
+		if (x >= dpi->left + dpi->width ||
+				x + _screen.width*2 <= dpi->left ||
+				y >= dpi->top + dpi->height ||
+				y + _screen.height <= dpi->top)
+					return x;
+
+		if (color != 0xFF) {
+switch_color:;
+			if (real_color & IS_PALETTE_COLOR) {
+				_string_colorremap[1] = color;
+				_string_colorremap[2] = 215;
+			} else {
+				_string_colorremap[1] = _string_colormap[color].text;
+				_string_colorremap[2] = _string_colormap[color].shadow;
+			}
+			_color_remap_ptr = _string_colorremap;
+		}
+	}
+
+check_bounds:
+	if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
+skip_char:;
+		for (;;) {
+			c = Utf8Consume(&string);
+			if (!IsPrintable(c)) goto skip_cont;
+		}
+	}
+
+	for (;;) {
+		c = Utf8Consume(&string);
+skip_cont:;
+		if (c == 0) {
+			_last_fontsize = size;
+			return x;
+		}
+		if (IsPrintable(c)) {
+			if (x >= dpi->left + dpi->width) goto skip_char;
+			if (x + 26 >= dpi->left) {
+				GfxMainBlitter(GetGlyph(size, c), x, y, BM_COLOUR_REMAP);
+			}
+			x += GetCharacterWidth(size, c);
+		} else if (c == '\n') { // newline = {}
+			x = xo;
+			y += GetCharacterHeight(size);
+			goto check_bounds;
+		} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change color?
+			color = (byte)(c - SCC_BLUE);
+			goto switch_color;
+		} else if (c == SCC_SETX) { // {SETX}
+			x = xo + (byte)*string++;
+		} else if (c == SCC_SETXY) {// {SETXY}
+			x = xo + (byte)*string++;
+			y = yo + (byte)*string++;
+		} else if (c == SCC_TINYFONT) { // {TINYFONT}
+			size = FS_SMALL;
+		} else if (c == SCC_BIGFONT) { // {BIGFONT}
+			size = FS_LARGE;
+		} else {
+			DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
+		}
+	}
+}
+
+int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw)
+{
+	char buffer[512];
+	ttd_strlcpy(buffer, str, sizeof(buffer));
+	TruncateString(buffer, maxw);
+	return DoDrawString(buffer, x, y, color);
+}
+
+void DrawSprite(uint32 img, int x, int y)
+{
+	if (img & PALETTE_MODIFIER_COLOR) {
+		_color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1;
+		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_COLOUR_REMAP);
+	} else if (img & PALETTE_MODIFIER_TRANSPARENT) {
+		_color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1;
+		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_TRANSPARENT);
+	} else {
+		GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, BM_NORMAL);
+	}
+}
+
+typedef struct BlitterParams {
+	int start_x, start_y;
+	const byte *sprite;
+	Pixel *dst;
+	BlitterMode mode;
+	int width, height;
+	int width_org;
+	int pitch;
+} BlitterParams;
+
+static void GfxBlitTileZoomIn(BlitterParams *bp)
+{
+	const byte *src_o = bp->sprite;
+	const byte *src;
+	int num, skip;
+	byte done;
+	Pixel *dst;
+	const byte *ctab;
+
+	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+
+					for (; num >= 4; num -=4) {
+						dst[3] = ctab[src[3]];
+						dst[2] = ctab[src[2]];
+						dst[1] = ctab[src[1]];
+						dst[0] = ctab[src[0]];
+						dst += 4;
+						src += 4;
+					}
+					for (; num != 0; num--) *dst++ = ctab[*src++];
+				} while (!(done & 0x80));
+
+				bp->dst += bp->pitch;
+			} while (--bp->height != 0);
+			break;
+
+		case BM_TRANSPARENT:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip;
+					} else {
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+					for (; num != 0; num--) {
+						*dst = ctab[*dst];
+						dst++;
+					}
+				} while (!(done & 0x80));
+
+				bp->dst += bp->pitch;
+			} while (--bp->height != 0);
+			break;
+
+		default:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+#if defined(_WIN32)
+					if (num & 1) *dst++ = *src++;
+					if (num & 2) { *(uint16*)dst = *(uint16*)src; dst += 2; src += 2; }
+					if (num >>= 2) {
+						do {
+							*(uint32*)dst = *(uint32*)src;
+							dst += 4;
+							src += 4;
+						} while (--num != 0);
+					}
+#else
+					memcpy(dst, src, num);
+#endif
+				} while (!(done & 0x80));
+
+				bp->dst += bp->pitch;
+			} while (--bp->height != 0);
+			break;
+	}
+}
+
+static void GfxBlitZoomInUncomp(BlitterParams *bp)
+{
+	const byte *src = bp->sprite;
+	Pixel *dst = bp->dst;
+	int height = bp->height;
+	int width = bp->width;
+	int i;
+
+	assert(height > 0);
+	assert(width > 0);
+
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP: {
+			const byte *ctab = _color_remap_ptr;
+
+			do {
+				for (i = 0; i != width; i++) {
+					byte b = ctab[src[i]];
+
+					if (b != 0) dst[i] = b;
+				}
+				src += bp->width_org;
+				dst += bp->pitch;
+			} while (--height != 0);
+			break;
+		}
+
+		case BM_TRANSPARENT: {
+			const byte *ctab = _color_remap_ptr;
+
+			do {
+				for (i = 0; i != width; i++)
+					if (src[i] != 0) dst[i] = ctab[dst[i]];
+				src += bp->width_org;
+				dst += bp->pitch;
+			} while (--height != 0);
+			break;
+		}
+
+		default:
+			do {
+				int n = width;
+
+				for (; n >= 4; n -= 4) {
+					if (src[0] != 0) dst[0] = src[0];
+					if (src[1] != 0) dst[1] = src[1];
+					if (src[2] != 0) dst[2] = src[2];
+					if (src[3] != 0) dst[3] = src[3];
+
+					dst += 4;
+					src += 4;
+				}
+
+				for (; n != 0; n--) {
+					if (src[0] != 0) dst[0] = src[0];
+					src++;
+					dst++;
+				}
+
+				src += bp->width_org - width;
+				dst += bp->pitch - width;
+			} while (--height != 0);
+			break;
+	}
+}
+
+static void GfxBlitTileZoomMedium(BlitterParams *bp)
+{
+	const byte *src_o = bp->sprite;
+	const byte *src;
+	int num, skip;
+	byte done;
+	Pixel *dst;
+	const byte *ctab;
+
+	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						src++;
+						if (--num == 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 1;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+					num = (num + 1) >> 1;
+					for (; num != 0; num--) {
+							*dst = ctab[*src];
+							dst++;
+							src += 2;
+					}
+				} while (!(done & 0x80));
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+			} while (--bp->height != 0);
+			break;
+
+		case BM_TRANSPARENT:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						if (--num == 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 1;
+					} else {
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+					num = (num + 1) >> 1;
+					for (; num != 0; num--) {
+							*dst = ctab[*dst];
+							dst++;
+					}
+				} while (!(done & 0x80));
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+			} while (--bp->height != 0);
+			break;
+
+		default:
+			do {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						src++;
+						if (--num == 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 1;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					num = (num + 1) >> 1;
+
+					for (; num != 0; num--) {
+							*dst = *src;
+							dst++;
+							src += 2;
+					}
+
+				} while (!(done & 0x80));
+
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+			} while (--bp->height != 0);
+			break;
+	}
+}
+
+static void GfxBlitZoomMediumUncomp(BlitterParams *bp)
+{
+	const byte *src = bp->sprite;
+	Pixel *dst = bp->dst;
+	int height = bp->height;
+	int width = bp->width;
+	int i;
+
+	assert(height > 0);
+	assert(width > 0);
+
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP: {
+			const byte *ctab = _color_remap_ptr;
+
+			for (height >>= 1; height != 0; height--) {
+				for (i = 0; i != width >> 1; i++) {
+					byte b = ctab[src[i * 2]];
+
+					if (b != 0) dst[i] = b;
+				}
+				src += bp->width_org * 2;
+				dst += bp->pitch;
+			}
+			break;
+		}
+
+		case BM_TRANSPARENT: {
+			const byte *ctab = _color_remap_ptr;
+
+			for (height >>= 1; height != 0; height--) {
+				for (i = 0; i != width >> 1; i++)
+					if (src[i * 2] != 0) dst[i] = ctab[dst[i]];
+				src += bp->width_org * 2;
+				dst += bp->pitch;
+			}
+			break;
+		}
+
+		default:
+			for (height >>= 1; height != 0; height--) {
+				for (i = 0; i != width >> 1; i++)
+					if (src[i * 2] != 0) dst[i] = src[i * 2];
+				src += bp->width_org * 2;
+				dst += bp->pitch;
+			}
+			break;
+	}
+}
+
+static void GfxBlitTileZoomOut(BlitterParams *bp)
+{
+	const byte *src_o = bp->sprite;
+	const byte *src;
+	int num, skip;
+	byte done;
+	Pixel *dst;
+	const byte *ctab;
+
+	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP:
+			for (;;) {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						src++;
+						if (--num == 0) continue;
+					}
+
+					if (skip & 2) {
+						skip += 2;
+						src += 2;
+						num -= 2;
+						if (num <= 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 2;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+					num = (num + 3) >> 2;
+					for (; num != 0; num--) {
+							*dst = ctab[*src];
+							dst++;
+							src += 4;
+					}
+				} while (!(done & 0x80));
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+			}
+			break;
+
+		case BM_TRANSPARENT:
+			for (;;) {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						if (--num == 0) continue;
+					}
+
+					if (skip & 2) {
+						skip += 2;
+						num -= 2;
+						if (num <= 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 2;
+					} else {
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					ctab = _color_remap_ptr;
+					num = (num + 3) >> 2;
+					for (; num != 0; num--) {
+							*dst = ctab[*dst];
+							dst++;
+					}
+
+				} while (!(done & 0x80));
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+			}
+			break;
+
+		default:
+			for (;;) {
+				do {
+					done = src_o[0];
+					num = done & 0x7F;
+					skip = src_o[1];
+					src = src_o + 2;
+					src_o += num + 2;
+
+					dst = bp->dst;
+
+					if (skip & 1) {
+						skip++;
+						src++;
+						if (--num == 0) continue;
+					}
+
+					if (skip & 2) {
+						skip += 2;
+						src += 2;
+						num -= 2;
+						if (num <= 0) continue;
+					}
+
+					if ( (skip -= bp->start_x) > 0) {
+						dst += skip >> 2;
+					} else {
+						src -= skip;
+						num += skip;
+						if (num <= 0) continue;
+						skip = 0;
+					}
+
+					skip = skip + num - bp->width;
+					if (skip > 0) {
+						num -= skip;
+						if (num <= 0) continue;
+					}
+
+					num = (num + 3) >> 2;
+
+					for (; num != 0; num--) {
+							*dst = *src;
+							dst++;
+							src += 4;
+					}
+				} while (!(done & 0x80));
+
+				bp->dst += bp->pitch;
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+
+				do {
+					done = src_o[0];
+					src_o += (done & 0x7F) + 2;
+				} while (!(done & 0x80));
+				if (--bp->height == 0) return;
+			}
+			break;
+	}
+}
+
+static void GfxBlitZoomOutUncomp(BlitterParams *bp)
+{
+	const byte *src = bp->sprite;
+	Pixel *dst = bp->dst;
+	int height = bp->height;
+	int width = bp->width;
+	int i;
+
+	assert(height > 0);
+	assert(width > 0);
+
+	switch (bp->mode) {
+		case BM_COLOUR_REMAP: {
+			const byte *ctab = _color_remap_ptr;
+
+			for (height >>= 2; height != 0; height--) {
+				for (i = 0; i != width >> 2; i++) {
+					byte b = ctab[src[i * 4]];
+
+					if (b != 0) dst[i] = b;
+				}
+				src += bp->width_org * 4;
+				dst += bp->pitch;
+			}
+			break;
+		}
+
+		case BM_TRANSPARENT: {
+			const byte *ctab = _color_remap_ptr;
+
+			for (height >>= 2; height != 0; height--) {
+				for (i = 0; i != width >> 2; i++)
+					if (src[i * 4] != 0) dst[i] = ctab[dst[i]];
+				src += bp->width_org * 4;
+				dst += bp->pitch;
+			}
+			break;
+		}
+
+		default:
+			for (height >>= 2; height != 0; height--) {
+				for (i = 0; i != width >> 2; i++)
+					if (src[i * 4] != 0) dst[i] = src[i * 4];
+				src += bp->width_org * 4;
+				dst += bp->pitch;
+			}
+			break;
+	}
+}
+
+
+static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode)
+{
+	const DrawPixelInfo *dpi = _cur_dpi;
+	int start_x, start_y;
+	BlitterParams bp;
+	int zoom_mask = ~((1 << dpi->zoom) - 1);
+
+	/* decode sprite header */
+	x += sprite->x_offs;
+	y += sprite->y_offs;
+	bp.width_org = bp.width = sprite->width;
+	bp.height = sprite->height;
+	bp.sprite = sprite->data;
+	bp.dst = dpi->dst_ptr;
+	bp.mode = mode;
+	bp.pitch = dpi->pitch;
+
+	assert(bp.height > 0);
+	assert(bp.width > 0);
+
+	if (sprite->info & 8) {
+		/* tile blit */
+		start_y = 0;
+
+		if (dpi->zoom > 0) {
+			start_y += bp.height & ~zoom_mask;
+			bp.height &= zoom_mask;
+			if (bp.height == 0) return;
+			y &= zoom_mask;
+		}
+
+		if ( (y -= dpi->top) < 0) {
+			bp.height += y;
+			if (bp.height <= 0) return;
+			start_y -= y;
+			y = 0;
+		} else {
+			bp.dst += bp.pitch * (y >> dpi->zoom);
+		}
+		bp.start_y = start_y;
+
+		if ( (y = y + bp.height - dpi->height) > 0) {
+			bp.height -= y;
+			if (bp.height <= 0) return;
+		}
+
+		start_x = 0;
+		x &= zoom_mask;
+		if ( (x -= dpi->left) < 0) {
+			bp.width += x;
+			if (bp.width <= 0) return;
+			start_x -= x;
+			x = 0;
+		}
+		bp.start_x = start_x;
+		bp.dst += x >> dpi->zoom;
+
+		if ( (x = x + bp.width - dpi->width) > 0) {
+			bp.width -= x;
+			if (bp.width <= 0) return;
+		}
+
+		switch (dpi->zoom) {
+			default: NOT_REACHED();
+			case 0: GfxBlitTileZoomIn(&bp);     break;
+			case 1: GfxBlitTileZoomMedium(&bp); break;
+			case 2: GfxBlitTileZoomOut(&bp);    break;
+		}
+	} else {
+		bp.sprite += bp.width * (bp.height & ~zoom_mask);
+		bp.height &= zoom_mask;
+		if (bp.height == 0) return;
+
+		y &= zoom_mask;
+
+		if ( (y -= dpi->top) < 0) {
+			bp.height += y;
+			if (bp.height <= 0) return;
+			bp.sprite -= bp.width * y;
+			y = 0;
+		} else {
+			bp.dst += bp.pitch * (y >> dpi->zoom);
+		}
+
+		if (bp.height > dpi->height - y) {
+			bp.height = dpi->height - y;
+			if (bp.height <= 0) return;
+		}
+
+		x &= zoom_mask;
+
+		if ( (x -= dpi->left) < 0) {
+			bp.width += x;
+			if (bp.width <= 0) return;
+			bp.sprite -= x;
+			x = 0;
+		}
+		bp.dst += x >> dpi->zoom;
+
+		if (bp.width > dpi->width - x) {
+			bp.width = dpi->width - x;
+			if (bp.width <= 0) return;
+		}
+
+		switch (dpi->zoom) {
+			default: NOT_REACHED();
+			case 0: GfxBlitZoomInUncomp(&bp);     break;
+			case 1: GfxBlitZoomMediumUncomp(&bp); break;
+			case 2: GfxBlitZoomOutUncomp(&bp);    break;
+		}
+	}
+}
+
+void DoPaletteAnimations(void);
+
+void GfxInitPalettes(void)
+{
+	memcpy(_cur_palette, _palettes[_use_dos_palette ? 1 : 0], sizeof(_cur_palette));
+
+	_pal_first_dirty = 0;
+	_pal_last_dirty = 255;
+	DoPaletteAnimations();
+}
+
+#define EXTR(p, q) (((uint16)(_timer_counter * (p)) * (q)) >> 16)
+#define EXTR2(p, q) (((uint16)(~_timer_counter * (p)) * (q)) >> 16)
+
+void DoPaletteAnimations(void)
+{
+	const Colour *s;
+	Colour *d;
+	/* Amount of colors to be rotated.
+	 * A few more for the DOS palette, because the water colors are
+	 * 245-254 for DOS and 217-226 for Windows.  */
+	const ExtraPaletteValues *ev = &_extra_palette_values;
+	int c = _use_dos_palette ? 38 : 28;
+	Colour old_val[38]; // max(38, 28)
+	uint i;
+	uint j;
+
+	d = &_cur_palette[217];
+	memcpy(old_val, d, c * sizeof(*old_val));
+
+	// Dark blue water
+	s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
+	j = EXTR(320, 5);
+	for (i = 0; i != 5; i++) {
+		*d++ = s[j];
+		j++;
+		if (j == 5) j = 0;
+	}
+
+	// Glittery water
+	s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
+	j = EXTR(128, 15);
+	for (i = 0; i != 5; i++) {
+		*d++ = s[j];
+		j += 3;
+		if (j >= 15) j -= 15;
+	}
+
+	s = ev->e;
+	j = EXTR2(512, 5);
+	for (i = 0; i != 5; i++) {
+		*d++ = s[j];
+		j++;
+		if (j == 5) j = 0;
+	}
+
+	// Oil refinery fire animation
+	s = ev->oil_ref;
+	j = EXTR2(512, 7);
+	for (i = 0; i != 7; i++) {
+		*d++ = s[j];
+		j++;
+		if (j == 7) j = 0;
+	}
+
+	// Radio tower blinking
+	{
+		byte i = (_timer_counter >> 1) & 0x7F;
+		byte v;
+
+		(v = 255, i < 0x3f) ||
+		(v = 128, i < 0x4A || i >= 0x75) ||
+		(v = 20);
+		d->r = v;
+		d->g = 0;
+		d->b = 0;
+		d++;
+
+		i ^= 0x40;
+		(v = 255, i < 0x3f) ||
+		(v = 128, i < 0x4A || i >= 0x75) ||
+		(v = 20);
+		d->r = v;
+		d->g = 0;
+		d->b = 0;
+		d++;
+	}
+
+	// Handle lighthouse and stadium animation
+	s = ev->lighthouse;
+	j = EXTR(256, 4);
+	for (i = 0; i != 4; i++) {
+		*d++ = s[j];
+		j++;
+		if (j == 4) j = 0;
+	}
+
+	// Animate water for old DOS graphics
+	if (_use_dos_palette) {
+		// Dark blue water DOS
+		s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a;
+		j = EXTR(320, 5);
+		for (i = 0; i != 5; i++) {
+			*d++ = s[j];
+			j++;
+			if (j == 5) j = 0;
+		}
+
+		// Glittery water DOS
+		s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b;
+		j = EXTR(128, 15);
+		for (i = 0; i != 5; i++) {
+			*d++ = s[j];
+			j += 3;
+			if (j >= 15) j -= 15;
+		}
+	}
+
+	if (memcmp(old_val, &_cur_palette[217], c * sizeof(*old_val)) != 0) {
+		if (_pal_first_dirty > 217) _pal_first_dirty = 217;
+		if (_pal_last_dirty < 217 + c) _pal_last_dirty = 217 + c;
+	}
+}
+
+
+void LoadStringWidthTable(void)
+{
+	uint i;
+
+	/* Normal font */
+	for (i = 0; i != 224; i++) {
+		_stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32);
+	}
+
+	/* Small font */
+	for (i = 0; i != 224; i++) {
+		_stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32);
+	}
+
+	/* Large font */
+	for (i = 0; i != 224; i++) {
+		_stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32);
+	}
+}
+
+
+byte GetCharacterWidth(FontSize size, WChar key)
+{
+	if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
+
+	return GetGlyphWidth(size, key);
+}
+
+
+void ScreenSizeChanged(void)
+{
+	// check the dirty rect
+	if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
+	if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
+
+	// screen size changed and the old bitmap is invalid now, so we don't want to undraw it
+	_cursor.visible = false;
+}
+
+void UndrawMouseCursor(void)
+{
+	if (_cursor.visible) {
+		_cursor.visible = false;
+		memcpy_pitch(
+			_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
+			_cursor_backup,
+			_cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x, _screen.pitch);
+
+		_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
+	}
+}
+
+void DrawMouseCursor(void)
+{
+	int x;
+	int y;
+	int w;
+	int h;
+
+	/* Redraw mouse cursor but only when it's inside the window */
+	if (!_cursor.in_window) return;
+
+	// Don't draw the mouse cursor if it's already drawn
+	if (_cursor.visible) {
+		if (!_cursor.dirty) return;
+		UndrawMouseCursor();
+	}
+
+	w = _cursor.size.x;
+	x = _cursor.pos.x + _cursor.offs.x;
+	if (x < 0) {
+		w += x;
+		x = 0;
+	}
+	if (w > _screen.width - x) w = _screen.width - x;
+	if (w <= 0) return;
+	_cursor.draw_pos.x = x;
+	_cursor.draw_size.x = w;
+
+	h = _cursor.size.y;
+	y = _cursor.pos.y + _cursor.offs.y;
+	if (y < 0) {
+		h += y;
+		y = 0;
+	}
+	if (h > _screen.height - y) h = _screen.height - y;
+	if (h <= 0) return;
+	_cursor.draw_pos.y = y;
+	_cursor.draw_size.y = h;
+
+	assert(w * h < (int)sizeof(_cursor_backup));
+
+	// Make backup of stuff below cursor
+	memcpy_pitch(
+		_cursor_backup,
+		_screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch,
+		_cursor.draw_size.x, _cursor.draw_size.y, _screen.pitch, _cursor.draw_size.x);
+
+	// Draw cursor on screen
+	_cur_dpi = &_screen;
+	DrawSprite(_cursor.sprite, _cursor.pos.x, _cursor.pos.y);
+
+	_video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
+
+	_cursor.visible = true;
+	_cursor.dirty = false;
+}
+
+#if defined(_DEBUG)
+static void DbgScreenRect(int left, int top, int right, int bottom)
+{
+	DrawPixelInfo dp;
+	DrawPixelInfo *old;
+
+	old = _cur_dpi;
+	_cur_dpi = &dp;
+	dp = _screen;
+	GfxFillRect(left, top, right - 1, bottom - 1, rand() & 255);
+	_cur_dpi = old;
+}
+#endif
+
+void RedrawScreenRect(int left, int top, int right, int bottom)
+{
+	assert(right <= _screen.width && bottom <= _screen.height);
+	if (_cursor.visible) {
+		if (right > _cursor.draw_pos.x &&
+				left < _cursor.draw_pos.x + _cursor.draw_size.x &&
+				bottom > _cursor.draw_pos.y &&
+				top < _cursor.draw_pos.y + _cursor.draw_size.y) {
+			UndrawMouseCursor();
+		}
+	}
+	UndrawTextMessage();
+
+#if defined(_DEBUG)
+	if (_dbg_screen_rect)
+		DbgScreenRect(left, top, right, bottom);
+	else
+#endif
+		DrawOverlappedWindowForAll(left, top, right, bottom);
+
+	_video_driver->make_dirty(left, top, right - left, bottom - top);
+}
+
+void DrawDirtyBlocks(void)
+{
+	byte *b = _dirty_blocks;
+	const int w = ALIGN(_screen.width, 64);
+	const int h = ALIGN(_screen.height, 8);
+	int x;
+	int y;
+
+	if (IsGeneratingWorld() && !IsGeneratingWorldReadyForPaint()) return;
+
+	y = 0;
+	do {
+		x = 0;
+		do {
+			if (*b != 0) {
+				int left;
+				int top;
+				int right = x + 64;
+				int bottom = y;
+				byte *p = b;
+				int h2;
+
+				// First try coalescing downwards
+				do {
+					*p = 0;
+					p += DIRTY_BYTES_PER_LINE;
+					bottom += 8;
+				} while (bottom != h && *p != 0);
+
+				// Try coalescing to the right too.
+				h2 = (bottom - y) >> 3;
+				assert(h2 > 0);
+				p = b;
+
+				while (right != w) {
+					byte *p2 = ++p;
+					int h = h2;
+					// Check if a full line of dirty flags is set.
+					do {
+						if (!*p2) goto no_more_coalesc;
+						p2 += DIRTY_BYTES_PER_LINE;
+					} while (--h != 0);
+
+					// Wohoo, can combine it one step to the right!
+					// Do that, and clear the bits.
+					right += 64;
+
+					h = h2;
+					p2 = p;
+					do {
+						*p2 = 0;
+						p2 += DIRTY_BYTES_PER_LINE;
+					} while (--h != 0);
+				}
+				no_more_coalesc:
+
+				left = x;
+				top = y;
+
+				if (left   < _invalid_rect.left  ) left   = _invalid_rect.left;
+				if (top    < _invalid_rect.top   ) top    = _invalid_rect.top;
+				if (right  > _invalid_rect.right ) right  = _invalid_rect.right;
+				if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom;
+
+				if (left < right && top < bottom) {
+					RedrawScreenRect(left, top, right, bottom);
+				}
+
+			}
+		} while (b++, (x += 64) != w);
+	} while (b += -(w >> 6) + DIRTY_BYTES_PER_LINE, (y += 8) != h);
+
+	_invalid_rect.left = w;
+	_invalid_rect.top = h;
+	_invalid_rect.right = 0;
+	_invalid_rect.bottom = 0;
+
+	/* If we are generating a world, and waiting for a paint run, mark it here
+	 *  as done painting, so we can continue generating. */
+	if (IsGeneratingWorld() && IsGeneratingWorldReadyForPaint()) {
+		SetGeneratingWorldPaintStatus(false);
+	}
+}
+
+
+void SetDirtyBlocks(int left, int top, int right, int bottom)
+{
+	byte *b;
+	int width;
+	int height;
+
+	if (left < 0) left = 0;
+	if (top < 0) top = 0;
+	if (right > _screen.width) right = _screen.width;
+	if (bottom > _screen.height) bottom = _screen.height;
+
+	if (left >= right || top >= bottom) return;
+
+	if (left   < _invalid_rect.left  ) _invalid_rect.left   = left;
+	if (top    < _invalid_rect.top   ) _invalid_rect.top    = top;
+	if (right  > _invalid_rect.right ) _invalid_rect.right  = right;
+	if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom;
+
+	left >>= 6;
+	top  >>= 3;
+
+	b = _dirty_blocks + top * DIRTY_BYTES_PER_LINE + left;
+
+	width  = ((right  - 1) >> 6) - left + 1;
+	height = ((bottom - 1) >> 3) - top  + 1;
+
+	assert(width > 0 && height > 0);
+
+	do {
+		int i = width;
+
+		do b[--i] = 0xFF; while (i);
+
+		b += DIRTY_BYTES_PER_LINE;
+	} while (--height != 0);
+}
+
+void MarkWholeScreenDirty(void)
+{
+	SetDirtyBlocks(0, 0, _screen.width, _screen.height);
+}
+
+/** Set up a clipping area for only drawing into a certain area. To do this,
+ * Fill a DrawPixelInfo object with the supplied relative rectangle, backup
+ * the original (calling) _cur_dpi and assign the just returned DrawPixelInfo
+ * _cur_dpi. When you are done, give restore _cur_dpi's original value
+ * @param *n the DrawPixelInfo that will be the clipping rectangle box allowed
+ * for drawing
+ * @param left,top,width,height the relative coordinates of the clipping
+ * rectangle relative to the current _cur_dpi. This will most likely be the
+ * offset from the calling window coordinates
+ * @return return false if the requested rectangle is not possible with the
+ * current dpi pointer. Only continue of the return value is true, or you'll
+ * get some nasty results */
+bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
+{
+	const DrawPixelInfo *o = _cur_dpi;
+
+	n->zoom = 0;
+
+	assert(width > 0);
+	assert(height > 0);
+
+	if ((left -= o->left) < 0) {
+		width += left;
+		if (width <= 0) return false;
+		n->left = -left;
+		left = 0;
+	} else {
+		n->left = 0;
+	}
+
+	if (width > o->width - left) {
+		width = o->width - left;
+		if (width <= 0) return false;
+	}
+	n->width = width;
+
+	if ((top -= o->top) < 0) {
+		height += top;
+		if (height <= 0) return false;
+		n->top = -top;
+		top = 0;
+	} else {
+		n->top = 0;
+	}
+
+	n->dst_ptr = o->dst_ptr + left + top * (n->pitch = o->pitch);
+
+	if (height > o->height - top) {
+		height = o->height - top;
+		if (height <= 0) return false;
+	}
+	n->height = height;
+
+	return true;
+}
+
+static void SetCursorSprite(CursorID cursor)
+{
+	CursorVars *cv = &_cursor;
+	const Sprite *p;
+
+	if (cv->sprite == cursor) return;
+
+	p = GetSprite(cursor & SPRITE_MASK);
+	cv->sprite = cursor;
+	cv->size.y = p->height;
+	cv->size.x = p->width;
+	cv->offs.x = p->x_offs;
+	cv->offs.y = p->y_offs;
+
+	cv->dirty = true;
+}
+
+static void SwitchAnimatedCursor(void)
+{
+	CursorVars *cv = &_cursor;
+	const CursorID *cur = cv->animate_cur;
+	CursorID sprite;
+
+	// ANIM_CURSOR_END is 0xFFFF in table/animcursors.h
+	if (cur == NULL || *cur == 0xFFFF) cur = cv->animate_list;
+
+	sprite = cur[0];
+	cv->animate_timeout = cur[1];
+	cv->animate_cur = cur + 2;
+
+	SetCursorSprite(sprite);
+}
+
+void CursorTick(void)
+{
+	if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0)
+		SwitchAnimatedCursor();
+}
+
+void SetMouseCursor(CursorID cursor)
+{
+	// Turn off animation
+	_cursor.animate_timeout = 0;
+	// Set cursor
+	SetCursorSprite(cursor);
+}
+
+void SetAnimatedMouseCursor(const CursorID *table)
+{
+	_cursor.animate_list = table;
+	_cursor.animate_cur = NULL;
+	SwitchAnimatedCursor();
+}
+
+bool ChangeResInGame(int w, int h)
+{
+	return
+		(_screen.width == w && _screen.height == h) ||
+		_video_driver->change_resolution(w, h);
+}
+
+void ToggleFullScreen(bool fs)
+{
+	_video_driver->toggle_fullscreen(fs);
+	if (_fullscreen != fs && _num_resolutions == 0) {
+		DEBUG(driver, 0, "Could not find a suitable fullscreen resolution");
+	}
+}
+
+static int CDECL compare_res(const void *pa, const void *pb)
+{
+	int x = ((const uint16*)pa)[0] - ((const uint16*)pb)[0];
+	if (x != 0) return x;
+	return ((const uint16*)pa)[1] - ((const uint16*)pb)[1];
+}
+
+void SortResolutions(int count)
+{
+	qsort(_resolutions, count, sizeof(_resolutions[0]), compare_res);
+}
deleted file mode 100644
--- a/src/gfxinit.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "gfx.h"
-#include "gfxinit.h"
-#include "spritecache.h"
-#include "table/sprites.h"
-#include "fileio.h"
-#include "string.h"
-#include "newgrf.h"
-#include "md5.h"
-#include "variables.h"
-#include "fontcache.h"
-#include <string.h>
-
-typedef struct MD5File {
-	const char * const filename;     // filename
-	const md5_byte_t hash[16]; // md5 sum of the file
-} MD5File;
-
-typedef struct FileList {
-	const MD5File basic[4];     // grf files that always have to be loaded
-	const MD5File landscape[3]; // landscape specific grf files
-} FileList;
-
-enum {
-	SKIP = 0xFFFE,
-	END  = 0xFFFF
-};
-
-#include "table/files.h"
-#include "table/landscape_sprite.h"
-
-static const SpriteID * const _landscape_spriteindexes[] = {
-	_landscape_spriteindexes_1,
-	_landscape_spriteindexes_2,
-	_landscape_spriteindexes_3,
-};
-
-static const SpriteID * const _slopes_spriteindexes[] = {
-	_slopes_spriteindexes_0,
-	_slopes_spriteindexes_1,
-	_slopes_spriteindexes_2,
-	_slopes_spriteindexes_3,
-};
-
-
-static uint LoadGrfFile(const char* filename, uint load_index, int file_index)
-{
-	uint load_index_org = load_index;
-
-	FioOpenFile(file_index, filename);
-
-	DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
-
-	while (LoadNextSprite(load_index, file_index)) {
-		load_index++;
-		if (load_index >= MAX_SPRITES) {
-			error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
-		}
-	}
-	DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index);
-
-	return load_index - load_index_org;
-}
-
-
-static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index)
-{
-	uint start;
-
-	FioOpenFile(file_index, filename);
-
-	DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
-
-	while ((start = *index_tbl++) != END) {
-		uint end = *index_tbl++;
-
-		if (start == SKIP) { // skip sprites (amount in second var)
-			SkipSprites(end);
-		} else { // load sprites and use indexes from start to end
-			do {
-			#ifdef NDEBUG
-				LoadNextSprite(start, file_index);
-			#else
-				bool b = LoadNextSprite(start, file_index);
-				assert(b);
-			#endif
-			} while (++start <= end);
-		}
-	}
-}
-
-
-/* Check that the supplied MD5 hash matches that stored for the supplied filename */
-static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn)
-{
-	if (memcmp(file.hash, digest, sizeof(file.hash)) == 0) return true;
-	if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename);
-	return false;
-}
-
-/* Calculate and check the MD5 hash of the supplied filename.
- * returns true if the checksum is correct */
-static bool FileMD5(const MD5File file, bool warn)
-{
-	FILE *f;
-	char buf[MAX_PATH];
-
-	// open file
-	snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, file.filename);
-	f = fopen(buf, "rb");
-
-#if !defined(WIN32)
-	if (f == NULL) {
-		strtolower(buf + strlen(_paths.data_dir) - 1);
-		f = fopen(buf, "rb");
-	}
-#endif
-
-#if defined SECOND_DATA_DIR
-	/* If we failed to find the file in the first data directory, we will try the other one */
-
-	if (f == NULL) {
-		snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, file.filename);
-		f = fopen(buf, "rb");
-
-		if (f == NULL) {
-			strtolower(buf + strlen(_paths.second_data_dir) - 1);
-			f = fopen(buf, "rb");
-		}
-	}
-#endif
-
-	if (f != NULL) {
-		md5_state_t filemd5state;
-		md5_byte_t buffer[1024];
-		md5_byte_t digest[16];
-		size_t len;
-
-		md5_init(&filemd5state);
-		while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0)
-			md5_append(&filemd5state, buffer, len);
-
-		if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf);
-		fclose(f);
-
-		md5_finish(&filemd5state, digest);
-		return CheckMD5Digest(file, digest, warn);
-	} else { // file not found
-		return false;
-	}
-}
-
-/* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF)
- * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly.
- * If neither are found, Windows palette is assumed.
- *
- * (Note: Also checks sample.cat for corruption) */
-void CheckExternalFiles(void)
-{
-	uint i;
-	// count of files from this version
-	uint dos = 0;
-	uint win = 0;
-
-	for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++;
-	for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++;
-
-	for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++;
-	for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++;
-
-	if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false))
-		ShowInfo("Your 'sample.cat' file is corrupted or missing!");
-
-	for (i = 0; i < lengthof(files_openttd); i++) {
-		if (!FileMD5(files_openttd[i], false)) {
-			ShowInfoF("Your '%s' file is corrupted or missing!", files_openttd[i].filename);
-		}
-	}
-
-	/*
-	 * forced DOS palette via command line -> leave it that way
-	 * all Windows files present -> Windows palette
-	 * all DOS files present -> DOS palette
-	 * no Windows files present and any DOS file present -> DOS palette
-	 * otherwise -> Windows palette
-	 */
-	if (_use_dos_palette) {
-		return;
-	} else if (win == 5) {
-		_use_dos_palette = false;
-	} else if (dos == 5 || (win == 0 && dos > 0)) {
-		_use_dos_palette = true;
-	} else {
-		_use_dos_palette = false;
-	}
-}
-
-
-static const SpriteID trg1idx[] = {
-	   0,    1, // Mouse cursor, ZZZ
-/* Medium font */
-	   2,   92, // ' ' till 'z'
-	SKIP,   36,
-	 160,  160, // Move ¾ to the correct position
-	  98,   98, // Up arrow
-	 131,  133,
-	SKIP,    1, // skip currency sign
-	 135,  135,
-	SKIP,    1,
-	 137,  137,
-	SKIP,    1,
-	 139,  139,
-	 140,  140, // TODO Down arrow
-	 141,  141,
-	 142,  142, // TODO Check mark
-	 143,  143, // TODO Cross
-	 144,  144,
-	 145,  145, // TODO Right arrow
-	 146,  149,
-	 118,  122, // Transport markers
-	SKIP,    2,
-	 157,  157,
-	 114,  115, // Small up/down arrows
-	SKIP,    1,
-	 161,  225,
-/* Small font */
-	 226,  316, // ' ' till 'z'
-	SKIP,   36,
-	 384,  384, // Move ¾ to the correct position
-	 322,  322, // Up arrow
-	 355,  357,
-	SKIP,    1, // skip currency sign
-	 359,  359,
-	SKIP,    1,
-	 361,  361,
-	SKIP,    1,
-	 363,  363,
-	 364,  364, // TODO Down arrow
-	 365,  366,
-	SKIP,    1,
-	 368,  368,
-	 369,  369, // TODO Right arrow
-	 370,  373,
-	SKIP,    7,
-	 381,  381,
-	SKIP,    3,
-	 385,  449,
-/* Big font */
-	 450,  540, // ' ' till 'z'
-	SKIP,   36,
-	 608,  608, // Move ¾ to the correct position
-	SKIP,    1,
-	 579,  581,
-	SKIP,    1,
-	 583,  583,
-	SKIP,    5,
-	 589,  589,
-	SKIP,   15,
-	 605,  605,
-	SKIP,    3,
-	 609,  625,
-	SKIP,    1,
-	 627,  632,
-	SKIP,    1,
-	 634,  639,
-	SKIP,    1,
-	 641,  657,
-	SKIP,    1,
-	 659,  664,
-	SKIP,    2,
-	 667,  671,
-	SKIP,    1,
-	 673,  673,
-/* Graphics */
-	 674, 4792,
-	END
-};
-
-/* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the
- * amount of sprites and add them to the end of the list, with the index of
- * the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no
- * correspondence of any kind with the ID's in the grf file, but results in
- * a maximum use of sprite slots. */
-static const SpriteID _openttd_grf_indexes[] = {
-	SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc
-	134, 134,  // euro symbol medium size
-	582, 582,  // euro symbol large size
-	358, 358,  // euro symbol tiny
-	SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons
-	648, 648, // nordic char: æ
-	616, 616, // nordic char: Æ
-	666, 666, // nordic char: ø
-	634, 634, // nordic char: Ø
-	SPR_PIN_UP, SPR_CURSOR_CLONE_TRAIN, // more icons
-	382, 383, // ¼ ½ tiny
-	158, 159, // ¼ ½ medium
-	606, 607, // ¼ ½ large
-	360, 360, // ¦ tiny
-	362, 362, // ¨ tiny
-	136, 136, // ¦ medium
-	138, 138, // ¨ medium
-	584, 584, // ¦ large
-	586, 586, // ¨ large
-	626, 626, // Ð large
-	658, 658, // ð large
-	374, 374, // ´ tiny
-	378, 378, // ¸ tiny
-	150, 150, // ´ medium
-	154, 154, // ¸ medium
-	598, 598, // ´ large
-	602, 602, // ¸ large
-	640, 640, // Þ large
-	672, 672, // þ large
-	380, 380, // º tiny
-	156, 156, // º medium
-	604, 604, // º large
-	317, 320, // { | } ~ tiny
-	 93,  96, // { | } ~ medium
-	541, 544, // { | } ~ large
-	SPR_HOUSE_ICON, SPR_HOUSE_ICON,
-	585, 585, // § large
-	587, 587, // © large
-	592, 592, // ® large
-	594, 597, // ° ± ² ³ large
-	633, 633, // × large
-	665, 665, // ÷ large
-	SPR_SELL_TRAIN, SPR_SHARED_ORDERS_ICON,
-	377, 377, // · small
-	153, 153, // · medium
-	601, 601, // · large
-	END
-};
-
-
-static void LoadSpriteTables(void)
-{
-	const FileList* files = _use_dos_palette ? &files_dos : &files_win;
-	uint load_index;
-	uint i;
-
-	LoadGrfIndexed(files->basic[0].filename, trg1idx, 0);
-	DupSprite(  2, 130); // non-breaking space medium
-	DupSprite(226, 354); // non-breaking space tiny
-	DupSprite(450, 578); // non-breaking space large
-	load_index = 4793;
-
-	for (i = 1; files->basic[i].filename != NULL; i++) {
-		load_index += LoadGrfFile(files->basic[i].filename, load_index, i);
-	}
-
-	/* Load additional sprites for climates other than temperate */
-	if (_opt.landscape != LT_NORMAL) {
-		LoadGrfIndexed(
-			files->landscape[_opt.landscape - 1].filename,
-			_landscape_spriteindexes[_opt.landscape - 1],
-			i++
-		);
-	}
-
-	assert(load_index == SPR_SIGNALS_BASE);
-	load_index += LoadGrfFile("nsignalsw.grf", load_index, i++);
-
-	assert(load_index == SPR_CANALS_BASE);
-	load_index += LoadGrfFile("canalsw.grf", load_index, i++);
-
-	assert(load_index == SPR_SLOPES_BASE);
-	LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
-
-	load_index = SPR_AUTORAIL_BASE;
-	load_index += LoadGrfFile("autorail.grf", load_index, i++);
-
-	assert(load_index == SPR_ELRAIL_BASE);
-	load_index += LoadGrfFile("elrailsw.grf", load_index, i++);
-
-	assert(load_index == SPR_2CCMAP_BASE);
-	load_index += LoadGrfFile("2ccmap.grf", load_index, i++);
-
-	assert(load_index == SPR_OPENTTD_BASE);
-	LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
-	load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT;
-
-	assert(load_index == SPR_AIRPORTX_BASE);
-	load_index += LoadGrfFile("airports.grf", load_index, i++);
-
-	/* Initialize the unicode to sprite mapping table */
-	InitializeUnicodeGlyphMap();
-
-	LoadNewGRF(load_index, i);
-}
-
-
-void GfxLoadSprites(void)
-{
-	DEBUG(sprite, 2, "Loading sprite set %d", _opt.landscape);
-
-	GfxInitSpriteMem();
-	LoadSpriteTables();
-	GfxInitPalettes();
-}
new file mode 100644
--- /dev/null
+++ b/src/gfxinit.cpp
@@ -0,0 +1,404 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "gfx.h"
+#include "gfxinit.h"
+#include "spritecache.h"
+#include "table/sprites.h"
+#include "fileio.h"
+#include "string.h"
+#include "newgrf.h"
+#include "md5.h"
+#include "variables.h"
+#include "fontcache.h"
+#include <string.h>
+
+typedef struct MD5File {
+	const char * const filename;     // filename
+	const md5_byte_t hash[16]; // md5 sum of the file
+} MD5File;
+
+typedef struct FileList {
+	const MD5File basic[4];     // grf files that always have to be loaded
+	const MD5File landscape[3]; // landscape specific grf files
+} FileList;
+
+enum {
+	SKIP = 0xFFFE,
+	END  = 0xFFFF
+};
+
+#include "table/files.h"
+#include "table/landscape_sprite.h"
+
+static const SpriteID * const _landscape_spriteindexes[] = {
+	_landscape_spriteindexes_1,
+	_landscape_spriteindexes_2,
+	_landscape_spriteindexes_3,
+};
+
+static const SpriteID * const _slopes_spriteindexes[] = {
+	_slopes_spriteindexes_0,
+	_slopes_spriteindexes_1,
+	_slopes_spriteindexes_2,
+	_slopes_spriteindexes_3,
+};
+
+
+static uint LoadGrfFile(const char* filename, uint load_index, int file_index)
+{
+	uint load_index_org = load_index;
+
+	FioOpenFile(file_index, filename);
+
+	DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
+
+	while (LoadNextSprite(load_index, file_index)) {
+		load_index++;
+		if (load_index >= MAX_SPRITES) {
+			error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
+		}
+	}
+	DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index);
+
+	return load_index - load_index_org;
+}
+
+
+static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index)
+{
+	uint start;
+
+	FioOpenFile(file_index, filename);
+
+	DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
+
+	while ((start = *index_tbl++) != END) {
+		uint end = *index_tbl++;
+
+		if (start == SKIP) { // skip sprites (amount in second var)
+			SkipSprites(end);
+		} else { // load sprites and use indexes from start to end
+			do {
+			#ifdef NDEBUG
+				LoadNextSprite(start, file_index);
+			#else
+				bool b = LoadNextSprite(start, file_index);
+				assert(b);
+			#endif
+			} while (++start <= end);
+		}
+	}
+}
+
+
+/* Check that the supplied MD5 hash matches that stored for the supplied filename */
+static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn)
+{
+	if (memcmp(file.hash, digest, sizeof(file.hash)) == 0) return true;
+	if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename);
+	return false;
+}
+
+/* Calculate and check the MD5 hash of the supplied filename.
+ * returns true if the checksum is correct */
+static bool FileMD5(const MD5File file, bool warn)
+{
+	FILE *f;
+	char buf[MAX_PATH];
+
+	// open file
+	snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, file.filename);
+	f = fopen(buf, "rb");
+
+#if !defined(WIN32)
+	if (f == NULL) {
+		strtolower(buf + strlen(_paths.data_dir) - 1);
+		f = fopen(buf, "rb");
+	}
+#endif
+
+#if defined SECOND_DATA_DIR
+	/* If we failed to find the file in the first data directory, we will try the other one */
+
+	if (f == NULL) {
+		snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, file.filename);
+		f = fopen(buf, "rb");
+
+		if (f == NULL) {
+			strtolower(buf + strlen(_paths.second_data_dir) - 1);
+			f = fopen(buf, "rb");
+		}
+	}
+#endif
+
+	if (f != NULL) {
+		md5_state_t filemd5state;
+		md5_byte_t buffer[1024];
+		md5_byte_t digest[16];
+		size_t len;
+
+		md5_init(&filemd5state);
+		while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0)
+			md5_append(&filemd5state, buffer, len);
+
+		if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf);
+		fclose(f);
+
+		md5_finish(&filemd5state, digest);
+		return CheckMD5Digest(file, digest, warn);
+	} else { // file not found
+		return false;
+	}
+}
+
+/* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF)
+ * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly.
+ * If neither are found, Windows palette is assumed.
+ *
+ * (Note: Also checks sample.cat for corruption) */
+void CheckExternalFiles(void)
+{
+	uint i;
+	// count of files from this version
+	uint dos = 0;
+	uint win = 0;
+
+	for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++;
+	for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++;
+
+	for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++;
+	for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++;
+
+	if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false))
+		ShowInfo("Your 'sample.cat' file is corrupted or missing!");
+
+	for (i = 0; i < lengthof(files_openttd); i++) {
+		if (!FileMD5(files_openttd[i], false)) {
+			ShowInfoF("Your '%s' file is corrupted or missing!", files_openttd[i].filename);
+		}
+	}
+
+	/*
+	 * forced DOS palette via command line -> leave it that way
+	 * all Windows files present -> Windows palette
+	 * all DOS files present -> DOS palette
+	 * no Windows files present and any DOS file present -> DOS palette
+	 * otherwise -> Windows palette
+	 */
+	if (_use_dos_palette) {
+		return;
+	} else if (win == 5) {
+		_use_dos_palette = false;
+	} else if (dos == 5 || (win == 0 && dos > 0)) {
+		_use_dos_palette = true;
+	} else {
+		_use_dos_palette = false;
+	}
+}
+
+
+static const SpriteID trg1idx[] = {
+	   0,    1, // Mouse cursor, ZZZ
+/* Medium font */
+	   2,   92, // ' ' till 'z'
+	SKIP,   36,
+	 160,  160, // Move ¾ to the correct position
+	  98,   98, // Up arrow
+	 131,  133,
+	SKIP,    1, // skip currency sign
+	 135,  135,
+	SKIP,    1,
+	 137,  137,
+	SKIP,    1,
+	 139,  139,
+	 140,  140, // TODO Down arrow
+	 141,  141,
+	 142,  142, // TODO Check mark
+	 143,  143, // TODO Cross
+	 144,  144,
+	 145,  145, // TODO Right arrow
+	 146,  149,
+	 118,  122, // Transport markers
+	SKIP,    2,
+	 157,  157,
+	 114,  115, // Small up/down arrows
+	SKIP,    1,
+	 161,  225,
+/* Small font */
+	 226,  316, // ' ' till 'z'
+	SKIP,   36,
+	 384,  384, // Move ¾ to the correct position
+	 322,  322, // Up arrow
+	 355,  357,
+	SKIP,    1, // skip currency sign
+	 359,  359,
+	SKIP,    1,
+	 361,  361,
+	SKIP,    1,
+	 363,  363,
+	 364,  364, // TODO Down arrow
+	 365,  366,
+	SKIP,    1,
+	 368,  368,
+	 369,  369, // TODO Right arrow
+	 370,  373,
+	SKIP,    7,
+	 381,  381,
+	SKIP,    3,
+	 385,  449,
+/* Big font */
+	 450,  540, // ' ' till 'z'
+	SKIP,   36,
+	 608,  608, // Move ¾ to the correct position
+	SKIP,    1,
+	 579,  581,
+	SKIP,    1,
+	 583,  583,
+	SKIP,    5,
+	 589,  589,
+	SKIP,   15,
+	 605,  605,
+	SKIP,    3,
+	 609,  625,
+	SKIP,    1,
+	 627,  632,
+	SKIP,    1,
+	 634,  639,
+	SKIP,    1,
+	 641,  657,
+	SKIP,    1,
+	 659,  664,
+	SKIP,    2,
+	 667,  671,
+	SKIP,    1,
+	 673,  673,
+/* Graphics */
+	 674, 4792,
+	END
+};
+
+/* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the
+ * amount of sprites and add them to the end of the list, with the index of
+ * the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no
+ * correspondence of any kind with the ID's in the grf file, but results in
+ * a maximum use of sprite slots. */
+static const SpriteID _openttd_grf_indexes[] = {
+	SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc
+	134, 134,  // euro symbol medium size
+	582, 582,  // euro symbol large size
+	358, 358,  // euro symbol tiny
+	SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons
+	648, 648, // nordic char: æ
+	616, 616, // nordic char: Æ
+	666, 666, // nordic char: ø
+	634, 634, // nordic char: Ø
+	SPR_PIN_UP, SPR_CURSOR_CLONE_TRAIN, // more icons
+	382, 383, // ¼ ½ tiny
+	158, 159, // ¼ ½ medium
+	606, 607, // ¼ ½ large
+	360, 360, // ¦ tiny
+	362, 362, // ¨ tiny
+	136, 136, // ¦ medium
+	138, 138, // ¨ medium
+	584, 584, // ¦ large
+	586, 586, // ¨ large
+	626, 626, // Ð large
+	658, 658, // ð large
+	374, 374, // ´ tiny
+	378, 378, // ¸ tiny
+	150, 150, // ´ medium
+	154, 154, // ¸ medium
+	598, 598, // ´ large
+	602, 602, // ¸ large
+	640, 640, // Þ large
+	672, 672, // þ large
+	380, 380, // º tiny
+	156, 156, // º medium
+	604, 604, // º large
+	317, 320, // { | } ~ tiny
+	 93,  96, // { | } ~ medium
+	541, 544, // { | } ~ large
+	SPR_HOUSE_ICON, SPR_HOUSE_ICON,
+	585, 585, // § large
+	587, 587, // © large
+	592, 592, // ® large
+	594, 597, // ° ± ² ³ large
+	633, 633, // × large
+	665, 665, // ÷ large
+	SPR_SELL_TRAIN, SPR_SHARED_ORDERS_ICON,
+	377, 377, // · small
+	153, 153, // · medium
+	601, 601, // · large
+	END
+};
+
+
+static void LoadSpriteTables(void)
+{
+	const FileList* files = _use_dos_palette ? &files_dos : &files_win;
+	uint load_index;
+	uint i;
+
+	LoadGrfIndexed(files->basic[0].filename, trg1idx, 0);
+	DupSprite(  2, 130); // non-breaking space medium
+	DupSprite(226, 354); // non-breaking space tiny
+	DupSprite(450, 578); // non-breaking space large
+	load_index = 4793;
+
+	for (i = 1; files->basic[i].filename != NULL; i++) {
+		load_index += LoadGrfFile(files->basic[i].filename, load_index, i);
+	}
+
+	/* Load additional sprites for climates other than temperate */
+	if (_opt.landscape != LT_NORMAL) {
+		LoadGrfIndexed(
+			files->landscape[_opt.landscape - 1].filename,
+			_landscape_spriteindexes[_opt.landscape - 1],
+			i++
+		);
+	}
+
+	assert(load_index == SPR_SIGNALS_BASE);
+	load_index += LoadGrfFile("nsignalsw.grf", load_index, i++);
+
+	assert(load_index == SPR_CANALS_BASE);
+	load_index += LoadGrfFile("canalsw.grf", load_index, i++);
+
+	assert(load_index == SPR_SLOPES_BASE);
+	LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
+
+	load_index = SPR_AUTORAIL_BASE;
+	load_index += LoadGrfFile("autorail.grf", load_index, i++);
+
+	assert(load_index == SPR_ELRAIL_BASE);
+	load_index += LoadGrfFile("elrailsw.grf", load_index, i++);
+
+	assert(load_index == SPR_2CCMAP_BASE);
+	load_index += LoadGrfFile("2ccmap.grf", load_index, i++);
+
+	assert(load_index == SPR_OPENTTD_BASE);
+	LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
+	load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT;
+
+	assert(load_index == SPR_AIRPORTX_BASE);
+	load_index += LoadGrfFile("airports.grf", load_index, i++);
+
+	/* Initialize the unicode to sprite mapping table */
+	InitializeUnicodeGlyphMap();
+
+	LoadNewGRF(load_index, i);
+}
+
+
+void GfxLoadSprites(void)
+{
+	DEBUG(sprite, 2, "Loading sprite set %d", _opt.landscape);
+
+	GfxInitSpriteMem();
+	LoadSpriteTables();
+	GfxInitPalettes();
+}
deleted file mode 100644
--- a/src/graph_gui.c
+++ /dev/null
@@ -1,1258 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "functions.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "player.h"
-#include "economy.h"
-#include "signs.h"
-#include "strings.h"
-#include "debug.h"
-#include "variables.h"
-#include "date.h"
-
-const byte _cargo_colours[NUM_CARGO] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 48};
-
-static uint _legend_excludebits;
-static uint _legend_cargobits;
-
-/************************/
-/* GENERIC GRAPH DRAWER */
-/************************/
-
-enum {GRAPH_NUM = 16};
-
-typedef struct GraphDrawer {
-	uint sel; // bitmask of the players *excluded* (e.g. 11111111 means that no players are shown)
-	byte num_dataset;
-	byte num_on_x_axis;
-	byte month;
-	Year year;
-	bool include_neg;
-	byte num_vert_lines;
-	uint16 unk61A;
-	uint16 unk61C;
-	int left, top;
-	uint height;
-	StringID format_str_y_axis;
-	byte color_3, color_2, bg_line_color;
-	byte colors[GRAPH_NUM];
-	uint64 cost[GRAPH_NUM][24]; // last 2 years
-} GraphDrawer;
-
-#define INVALID_VALUE 0x80000000
-
-static void DrawGraph(const GraphDrawer *gw)
-{
-
-	int i,j,k;
-	uint x,y,old_x,old_y;
-	int color;
-	int right, bottom;
-	int num_x, num_dataset;
-	const uint64 *row_ptr, *col_ptr;
-	int64 mx;
-	int adj_height;
-	uint64 y_scaling, tmp;
-	int64 value;
-	int64 cur_val;
-	uint sel;
-
-	/* the colors and cost array of GraphDrawer must accomodate
-	 * both values for cargo and players. So if any are higher, quit */
-	assert(GRAPH_NUM >= NUM_CARGO && GRAPH_NUM >= MAX_PLAYERS);
-
-	color = _colour_gradient[gw->bg_line_color][4];
-
-	/* draw the vertical lines */
-	i = gw->num_vert_lines; assert(i > 0);
-	x = gw->left + 66;
-	bottom = gw->top + gw->height - 1;
-	do {
-		GfxFillRect(x, gw->top, x, bottom, color);
-		x += 22;
-	} while (--i);
-
-	/* draw the horizontal lines */
-	i = 9;
-	x = gw->left + 44;
-	y = gw->height + gw->top;
-	right = gw->left + 44 + gw->num_vert_lines*22-1;
-
-	do {
-		GfxFillRect(x, y, right, y, color);
-		y -= gw->height >> 3;
-	} while (--i);
-
-	/* draw vertical edge line */
-	GfxFillRect(x, gw->top, x, bottom, gw->color_2);
-
-	adj_height = gw->height;
-	if (gw->include_neg) adj_height >>= 1;
-
-	/* draw horiz edge line */
-	y = adj_height + gw->top;
-	GfxFillRect(x, y, right, y, gw->color_2);
-
-	/* find the max element */
-	if (gw->num_on_x_axis == 0)
-		return;
-
-	num_dataset = gw->num_dataset;
-	assert(num_dataset > 0);
-
-	row_ptr = gw->cost[0];
-	mx = 0;
-		/* bit selection for the showing of various players, base max element
-		 * on to-be shown player-information. This way the graph can scale */
-	sel = gw->sel;
-	do {
-		if (!(sel&1)) {
-			num_x = gw->num_on_x_axis;
-			assert(num_x > 0);
-			col_ptr = row_ptr;
-			do {
-				if (*col_ptr != INVALID_VALUE) {
-					mx = max64(mx, myabs64(*col_ptr));
-				}
-			} while (col_ptr++, --num_x);
-		}
-	} while (sel>>=1, row_ptr+=24, --num_dataset);
-
-	/* setup scaling */
-	y_scaling = INVALID_VALUE;
-	value = adj_height * 2;
-
-	if (mx > value) {
-		mx = (mx + 7) & ~7;
-		y_scaling = (((uint64) (value>>1) << 32) / mx);
-		value = mx;
-	}
-
-	/* draw text strings on the y axis */
-	tmp = value;
-	if (gw->include_neg) tmp >>= 1;
-	x = gw->left + 45;
-	y = gw->top - 3;
-	i = 9;
-	do {
-		SetDParam(0, gw->format_str_y_axis);
-		SetDParam64(1, (int64)tmp);
-		tmp -= (value >> 3);
-		DrawStringRightAligned(x, y, STR_0170, gw->color_3);
-		y += gw->height >> 3;
-	} while (--i);
-
-	/* draw strings on the x axis */
-	if (gw->month != 0xFF) {
-		x = gw->left + 44;
-		y = gw->top + gw->height + 1;
-		j = gw->month;
-		k = gw->year;
-		i = gw->num_on_x_axis;assert(i>0);
-		do {
-			SetDParam(2, k);
-			SetDParam(0, j + STR_0162_JAN);
-			SetDParam(1, j + STR_0162_JAN + 2);
-			DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3);
-
-			j += 3;
-			if (j >= 12) {
-				j = 0;
-				k++;
-			}
-			x += 22;
-		} while (--i);
-	} else {
-		x = gw->left + 52;
-		y = gw->top + gw->height + 1;
-		j = gw->unk61A;
-		i = gw->num_on_x_axis;assert(i>0);
-		do {
-			SetDParam(0, j);
-			DrawString(x, y, STR_01CB, gw->color_3);
-			j += gw->unk61C;
-			x += 22;
-		} while (--i);
-	}
-
-	/* draw lines and dots */
-	i = 0;
-	row_ptr = gw->cost[0];
-	sel = gw->sel; // show only selected lines. GraphDrawer qw->sel set in Graph-Legend (_legend_excludebits)
-	do {
-		if (!(sel & 1)) {
-			x = gw->left + 55;
-			j = gw->num_on_x_axis;assert(j>0);
-			col_ptr = row_ptr;
-			color = gw->colors[i];
-			old_y = old_x = INVALID_VALUE;
-			do {
-				cur_val = *col_ptr++;
-				if (cur_val != INVALID_VALUE) {
-					y = adj_height - BIGMULSS64(cur_val, y_scaling >> 1, 31) + gw->top;
-
-					GfxFillRect(x-1, y-1, x+1, y+1, color);
-					if (old_x != INVALID_VALUE)
-						GfxDrawLine(old_x, old_y, x, y, color);
-
-					old_x = x;
-					old_y = y;
-				} else {
-					old_x = INVALID_VALUE;
-				}
-			} while (x+=22,--j);
-		}
-	} while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset);
-}
-
-/****************/
-/* GRAPH LEGEND */
-/****************/
-
-void DrawPlayerIcon(PlayerID p, int x, int y)
-{
-	DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y);
-}
-
-static void GraphLegendWndProc(Window *w, WindowEvent *e)
-{
-	const Player* p;
-
-	switch (e->event) {
-	case WE_CREATE: {
-		uint i;
-		for (i = 3; i < w->widget_count; i++) {
-			if (!HASBIT(_legend_excludebits, i - 3)) LowerWindowWidget(w, i);
-		}
-		break;
-	}
-
-	case WE_PAINT:
-		FOR_ALL_PLAYERS(p) {
-			if (!p->is_active) {
-				SETBIT(_legend_excludebits, p->index);
-				RaiseWindowWidget(w, p->index + 3);
-			}
-		}
-		DrawWindowWidgets(w);
-
-		FOR_ALL_PLAYERS(p) {
-			if (!p->is_active) continue;
-
-			DrawPlayerIcon(p->index, 4, 18+p->index*12);
-
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, GetPlayerNameString(p->index, 3));
-			DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_excludebits, p->index) ? 0x10 : 0xC);
-		}
-		break;
-
-	case WE_CLICK:
-		if (IS_INT_INSIDE(e->we.click.widget, 3, 11)) {
-			_legend_excludebits ^= (1 << (e->we.click.widget - 3));
-			ToggleWidgetLoweredState(w, e->we.click.widget);
-			SetWindowDirty(w);
-			InvalidateWindow(WC_INCOME_GRAPH, 0);
-			InvalidateWindow(WC_OPERATING_PROFIT, 0);
-			InvalidateWindow(WC_DELIVERED_CARGO, 0);
-			InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
-			InvalidateWindow(WC_COMPANY_VALUE, 0);
-		}
-		break;
-	}
-}
-
-static const Widget _graph_legend_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_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,   113, 0x0,                            STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    16,    27, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    28,    39, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    40,    51, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    52,    63, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    64,    75, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    76,    87, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    88,    99, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,   100,   111, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _graph_legend_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 114,
-	WC_GRAPH_LEGEND,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_graph_legend_widgets,
-	GraphLegendWndProc
-};
-
-static void ShowGraphLegend(void)
-{
-	AllocateWindowDescFront(&_graph_legend_desc, 0);
-}
-
-/********************/
-/* OPERATING PROFIT */
-/********************/
-
-static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
-{
-	const Player* p;
-	uint excludebits = _legend_excludebits;
-	int nums;
-	int mo,yr;
-
-	// Exclude the players which aren't valid
-	FOR_ALL_PLAYERS(p) {
-		if (!p->is_active) SETBIT(excludebits,p->index);
-	}
-	gd->sel = excludebits;
-	gd->num_vert_lines = 24;
-
-	nums = 0;
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) nums = max(nums,p->num_valid_stat_ent);
-	}
-	gd->num_on_x_axis = min(nums,24);
-
-	mo = (_cur_month/3-nums)*3;
-	yr = _cur_year;
-	while (mo < 0) {
-		yr--;
-		mo += 12;
-	}
-
-	gd->year = yr;
-	gd->month = mo;
-}
-
-static void OperatingProfitWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		GraphDrawer gd;
-		const Player* p;
-		int i,j;
-		int numd;
-
-		DrawWindowWidgets(w);
-
-		gd.left = 2;
-		gd.top = 18;
-		gd.height = 136;
-		gd.include_neg = true;
-		gd.format_str_y_axis = STR_CURRCOMPACT;
-		gd.color_3 = 0x10;
-		gd.color_2 = 0xD7;
-		gd.bg_line_color = 0xE;
-
-		SetupGraphDrawerForPlayers(&gd);
-
-		numd = 0;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				gd.colors[numd] = _colour_gradient[p->player_color][6];
-				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)(p->old_economy[j].income + p->old_economy[j].expenses);
-					i++;
-				}
-			}
-			numd++;
-		}
-
-		gd.num_dataset = numd;
-
-		DrawGraph(&gd);
-	}	break;
-	case WE_CLICK:
-		if (e->we.click.widget == 2) /* Clicked on Legend */
-			ShowGraphLegend();
-		break;
-	}
-}
-
-static const Widget _operating_profit_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                    STR_704D_SHOW_KEY_TO_GRAPHS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   173, 0x0,                             STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _operating_profit_desc = {
-	WDP_AUTO, WDP_AUTO, 576, 174,
-	WC_OPERATING_PROFIT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_operating_profit_widgets,
-	OperatingProfitWndProc
-};
-
-
-void ShowOperatingProfitGraph(void)
-{
-	if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
-}
-
-
-/****************/
-/* INCOME GRAPH */
-/****************/
-
-static void IncomeGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		GraphDrawer gd;
-		const Player* p;
-		int i,j;
-		int numd;
-
-		DrawWindowWidgets(w);
-
-		gd.left = 2;
-		gd.top = 18;
-		gd.height = 104;
-		gd.include_neg = false;
-		gd.format_str_y_axis = STR_CURRCOMPACT;
-		gd.color_3 = 0x10;
-		gd.color_2 = 0xD7;
-		gd.bg_line_color = 0xE;
-		SetupGraphDrawerForPlayers(&gd);
-
-		numd = 0;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				gd.colors[numd] = _colour_gradient[p->player_color][6];
-				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].income;
-					i++;
-				}
-			}
-			numd++;
-		}
-
-		gd.num_dataset = numd;
-
-		DrawGraph(&gd);
-		break;
-	}
-
-	case WE_CLICK:
-		if (e->we.click.widget == 2)
-			ShowGraphLegend();
-		break;
-	}
-}
-
-static const Widget _income_graph_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,          STR_704D_SHOW_KEY_TO_GRAPHS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                   STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _income_graph_desc = {
-	WDP_AUTO, WDP_AUTO, 576, 142,
-	WC_INCOME_GRAPH,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_income_graph_widgets,
-	IncomeGraphWndProc
-};
-
-void ShowIncomeGraph(void)
-{
-	if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
-}
-
-/*******************/
-/* DELIVERED CARGO */
-/*******************/
-
-static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		GraphDrawer gd;
-		const Player* p;
-		int i,j;
-		int numd;
-
-		DrawWindowWidgets(w);
-
-		gd.left = 2;
-		gd.top = 18;
-		gd.height = 104;
-		gd.include_neg = false;
-		gd.format_str_y_axis = STR_7024;
-		gd.color_3 = 0x10;
-		gd.color_2 = 0xD7;
-		gd.bg_line_color = 0xE;
-		SetupGraphDrawerForPlayers(&gd);
-
-		numd = 0;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				gd.colors[numd] = _colour_gradient[p->player_color][6];
-				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].delivered_cargo;
-					i++;
-				}
-			}
-			numd++;
-		}
-
-		gd.num_dataset = numd;
-
-		DrawGraph(&gd);
-		break;
-	}
-
-	case WE_CLICK:
-		if (e->we.click.widget == 2)
-			ShowGraphLegend();
-		break;
-	}
-}
-
-static const Widget _delivered_cargo_graph_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                      STR_704D_SHOW_KEY_TO_GRAPHS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                               STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _delivered_cargo_graph_desc = {
-	WDP_AUTO, WDP_AUTO, 576, 142,
-	WC_DELIVERED_CARGO,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_delivered_cargo_graph_widgets,
-	DeliveredCargoGraphWndProc
-};
-
-void ShowDeliveredCargoGraph(void)
-{
-	if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
-}
-
-/***********************/
-/* PERFORMANCE HISTORY */
-/***********************/
-
-static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		GraphDrawer gd;
-		const Player* p;
-		int i,j;
-		int numd;
-
-		DrawWindowWidgets(w);
-
-		gd.left = 2;
-		gd.top = 18;
-		gd.height = 200;
-		gd.include_neg = false;
-		gd.format_str_y_axis = STR_7024;
-		gd.color_3 = 0x10;
-		gd.color_2 = 0xD7;
-		gd.bg_line_color = 0xE;
-		SetupGraphDrawerForPlayers(&gd);
-
-		numd = 0;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				gd.colors[numd] = _colour_gradient[p->player_color][6];
-				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].performance_history;
-					i++;
-				}
-			}
-			numd++;
-		}
-
-		gd.num_dataset = numd;
-
-		DrawGraph(&gd);
-		break;
-	}
-
-	case WE_CLICK:
-		if (e->we.click.widget == 2)
-			ShowGraphLegend();
-		if (e->we.click.widget == 3)
-			ShowPerformanceRatingDetail();
-		break;
-	}
-}
-
-static const Widget _performance_history_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                             STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   475,     0,    13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                         STR_704D_SHOW_KEY_TO_GRAPHS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   476,   525,     0,    13, STR_PERFORMANCE_DETAIL_KEY,           STR_704D_SHOW_KEY_TO_GRAPHS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                                  STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _performance_history_desc = {
-	WDP_AUTO, WDP_AUTO, 576, 238,
-	WC_PERFORMANCE_HISTORY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_performance_history_widgets,
-	PerformanceHistoryWndProc
-};
-
-void ShowPerformanceHistoryGraph(void)
-{
-	if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
-}
-
-/*****************/
-/* COMPANY VALUE */
-/*****************/
-
-static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		GraphDrawer gd;
-		const Player* p;
-		int i,j;
-		int numd;
-
-		DrawWindowWidgets(w);
-
-		gd.left = 2;
-		gd.top = 18;
-		gd.height = 200;
-		gd.include_neg = false;
-		gd.format_str_y_axis = STR_CURRCOMPACT;
-		gd.color_3 = 0x10;
-		gd.color_2 = 0xD7;
-		gd.bg_line_color = 0xE;
-		SetupGraphDrawerForPlayers(&gd);
-
-		numd = 0;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				gd.colors[numd] = _colour_gradient[p->player_color][6];
-				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].company_value;
-					i++;
-				}
-			}
-			numd++;
-		}
-
-		gd.num_dataset = numd;
-
-		DrawGraph(&gd);
-		break;
-	}
-
-	case WE_CLICK:
-		if (e->we.click.widget == 2)
-			ShowGraphLegend();
-		break;
-	}
-}
-
-static const Widget _company_value_graph_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,            STR_704D_SHOW_KEY_TO_GRAPHS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                     STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _company_value_graph_desc = {
-	WDP_AUTO, WDP_AUTO, 576, 238,
-	WC_COMPANY_VALUE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_company_value_graph_widgets,
-	CompanyValueGraphWndProc
-};
-
-void ShowCompanyValueGraph(void)
-{
-	if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
-}
-
-/*****************/
-/* PAYMENT RATES */
-/*****************/
-
-static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: {
-		uint i;
-		for (i = 3; i < w->widget_count; i++) {
-			if (!HASBIT(_legend_cargobits, i - 3)) LowerWindowWidget(w, i);
-		}
-		break;
-	}
-
-	case WE_PAINT: {
-		int j, x, y;
-		CargoID i;
-		GraphDrawer gd;
-
-		DrawWindowWidgets(w);
-
-		x = 495;
-		y = 24;
-
-		gd.sel = _legend_cargobits;
-		gd.left = 2;
-		gd.top = 24;
-		gd.height = 104;
-		gd.include_neg = false;
-		gd.format_str_y_axis = STR_CURRCOMPACT;
-		gd.color_3 = 16;
-		gd.color_2 = 215;
-		gd.bg_line_color = 14;
-		gd.num_dataset = NUM_CARGO;
-		gd.num_on_x_axis = 20;
-		gd.num_vert_lines = 20;
-		gd.month = 0xFF;
-		gd.unk61A = 10;
-		gd.unk61C = 10;
-
-		for (i = 0; i != NUM_CARGO; i++) {
-			/* Since the buttons have no text, no images,
-			 * both the text and the colored box have to be manually painted.
-			 * clk_dif will move one pixel down and one pixel to the right
-			 * when the button is clicked */
-			byte clk_dif = IsWindowWidgetLowered(w, i + 3) ? 1 : 0;
-
-			GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
-			GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, _cargo_colours[i]);
-			SetDParam(0, _cargoc.names_s[i]);
-			DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, 0);
-			y += 8;
-			gd.colors[i] = _cargo_colours[i];
-			for (j = 0; j != 20; j++) {
-				gd.cost[i][j] = (uint64)GetTransportedGoodsIncome(10, 20, j * 6 + 6, i);
-			}
-		}
-
-		DrawGraph(&gd);
-
-		DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0);
-		DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0);
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3: case 4: case 5: case 6:
-		case 7: case 8: case 9: case 10:
-		case 11: case 12: case 13: case 14:
-			TOGGLEBIT(_legend_cargobits, e->we.click.widget - 3);
-			ToggleWidgetLoweredState(w, e->we.click.widget);
-			SetWindowDirty(w);
-			break;
-		}
-	} break;
-	}
-}
-
-static const Widget _cargo_payment_rates_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   567,     0,    13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   567,    14,   141, 0x0,                          STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    24,    31, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    32,    39, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    40,    47, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    48,    55, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    56,    63, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    64,    71, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    72,    79, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    80,    87, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    88,    95, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    96,   103, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   104,   111, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   112,   119, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _cargo_payment_rates_desc = {
-	WDP_AUTO, WDP_AUTO, 568, 142,
-	WC_PAYMENT_RATES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_cargo_payment_rates_widgets,
-	CargoPaymentRatesWndProc
-};
-
-
-void ShowCargoPaymentRates(void)
-{
-	AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
-}
-
-/************************/
-/* COMPANY LEAGUE TABLE */
-/************************/
-
-static const StringID _performance_titles[] = {
-	STR_7066_ENGINEER,
-	STR_7066_ENGINEER,
-	STR_7067_TRAFFIC_MANAGER,
-	STR_7067_TRAFFIC_MANAGER,
-	STR_7068_TRANSPORT_COORDINATOR,
-	STR_7068_TRANSPORT_COORDINATOR,
-	STR_7069_ROUTE_SUPERVISOR,
-	STR_7069_ROUTE_SUPERVISOR,
-	STR_706A_DIRECTOR,
-	STR_706A_DIRECTOR,
-	STR_706B_CHIEF_EXECUTIVE,
-	STR_706B_CHIEF_EXECUTIVE,
-	STR_706C_CHAIRMAN,
-	STR_706C_CHAIRMAN,
-	STR_706D_PRESIDENT,
-	STR_706E_TYCOON,
-};
-
-static inline StringID GetPerformanceTitleFromValue(uint value)
-{
-	return _performance_titles[minu(value, 1000) >> 6];
-}
-
-static int CDECL PerfHistComp(const void* elem1, const void* elem2)
-{
-	const Player* p1 = *(const Player* const*)elem1;
-	const Player* p2 = *(const Player* const*)elem2;
-
-	return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
-}
-
-static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player* plist[MAX_PLAYERS];
-			const Player* p;
-			uint pl_num;
-			uint i;
-
-			DrawWindowWidgets(w);
-
-			pl_num = 0;
-			FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
-
-			qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
-
-			for (i = 0; i != pl_num; i++) {
-				p = plist[i];
-				SetDParam(0, i + STR_01AC_1ST);
-				SetDParam(1, p->name_1);
-				SetDParam(2, p->name_2);
-				SetDParam(3, GetPlayerNameString(p->index, 4));
-				SetDParam(5, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
-
-				DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
-				DrawPlayerIcon(p->index, 27, 16 + i * 10);
-			}
-
-			break;
-		}
-	}
-}
-
-
-static const Widget _company_league_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,  0, 13, STR_00C5,                      STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_NONE, 14,  11, 387,  0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399,  0, 13, STR_NULL,                      STR_STICKY_BUTTON},
-{      WWT_PANEL, RESIZE_NONE, 14,   0, 399, 14, 96, 0x0,                           STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _company_league_desc = {
-	WDP_AUTO, WDP_AUTO, 400, 97,
-	WC_COMPANY_LEAGUE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_company_league_widgets,
-	CompanyLeagueWndProc
-};
-
-void ShowCompanyLeagueTable(void)
-{
-	AllocateWindowDescFront(&_company_league_desc,0);
-}
-
-/*****************************/
-/* PERFORMANCE RATING DETAIL */
-/*****************************/
-
-static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
-{
-	static PlayerID _performance_rating_detail_player = 0;
-
-	switch (e->event) {
-		case WE_PAINT: {
-			int i;
-			byte x;
-			uint16 y = 14;
-			int total_score = 0;
-			int color_done, color_notdone;
-
-			// Draw standard stuff
-			DrawWindowWidgets(w);
-
-			// Paint the player icons
-			for (i = 0; i < MAX_PLAYERS; i++) {
-				if (!GetPlayer(i)->is_active) {
-					// Check if we have the player as an active player
-					if (!IsWindowWidgetDisabled(w, i + 13)) {
-						// Bah, player gone :(
-						DisableWindowWidget(w, i + 13);
-						// Is this player selected? If so, select first player (always save? :s)
-						if (IsWindowWidgetLowered(w, i + 13)) {
-							RaiseWindowWidget(w, i + 13);
-							LowerWindowWidget(w, 13);
-							_performance_rating_detail_player = 0;
-						}
-						// We need a repaint
-						SetWindowDirty(w);
-					}
-				continue;
-				}
-
-				// Check if we have the player marked as inactive
-				if (IsWindowWidgetDisabled(w, i + 13)) {
-					// New player! Yippie :p
-					EnableWindowWidget(w, i + 13);
-					// We need a repaint
-					SetWindowDirty(w);
-				}
-
-				x = (i == _performance_rating_detail_player) ? 1 : 0;
-				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
-			}
-
-			// The colors used to show how the progress is going
-			color_done = _colour_gradient[COLOUR_GREEN][4];
-			color_notdone = _colour_gradient[COLOUR_RED][4];
-
-			// Draw all the score parts
-			for (i = 0; i < NUM_SCORE; i++) {
-				int val    = _score_part[_performance_rating_detail_player][i];
-				int needed = _score_info[i].needed;
-				int score  = _score_info[i].score;
-
-				y += 20;
-				// SCORE_TOTAL has his own rulez ;)
-				if (i == SCORE_TOTAL) {
-					needed = total_score;
-					score = SCORE_MAX;
-				} else {
-					total_score += score;
-				}
-
-				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
-
-				// Draw the score
-				SetDParam(0, score);
-				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
-
-				// Calculate the %-bar
-				if (val > needed) {
-					x = 50;
-				} else if (val == 0) {
-					x = 0;
-				} else {
-					x = val * 50 / needed;
-				}
-
-				// SCORE_LOAN is inversed
-				if (val < 0 && i == SCORE_LOAN) x = 0;
-
-				// Draw the bar
-				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
-				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
-
-				// Calculate the %
-				x = (val <= needed) ? val * 100 / needed : 100;
-
-				// SCORE_LOAN is inversed
-				if (val < 0 && i == SCORE_LOAN) x = 0;
-
-				// Draw it
-				SetDParam(0, x);
-				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
-
-				// SCORE_LOAN is inversed
-				if (i == SCORE_LOAN) val = needed - val;
-
-				// Draw the amount we have against what is needed
-				//  For some of them it is in currency format
-				SetDParam(0, val);
-				SetDParam(1, needed);
-				switch (i) {
-					case SCORE_MIN_PROFIT:
-					case SCORE_MIN_INCOME:
-					case SCORE_MAX_INCOME:
-					case SCORE_MONEY:
-					case SCORE_LOAN:
-						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0);
-						break;
-					default:
-						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0);
-				}
-			}
-
-			break;
-		}
-
-		case WE_CLICK:
-			// Check which button is clicked
-			if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) {
-				// Is it no on disable?
-				if (!IsWindowWidgetDisabled(w, e->we.click.widget)) {
-					RaiseWindowWidget(w, _performance_rating_detail_player + 13);
-					_performance_rating_detail_player = e->we.click.widget - 13;
-					LowerWindowWidget(w, _performance_rating_detail_player + 13);
-					SetWindowDirty(w);
-				}
-			}
-			break;
-
-		case WE_CREATE: {
-			int i;
-			Player *p2;
-
-			/* Disable the players who are not active */
-			for (i = 0; i < MAX_PLAYERS; i++) {
-				SetWindowWidgetDisabledState(w, i + 13, !GetPlayer(i)->is_active);
-			}
-			/* Update all player stats with the current data
-			 * (this is because _score_info is not saved to a savegame) */
-			FOR_ALL_PLAYERS(p2) {
-				if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
-			}
-
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = 5;
-
-			_performance_rating_detail_player = 0;
-			LowerWindowWidget(w, _performance_rating_detail_player + 13);
-			SetWindowDirty(w);
-
-			break;
-		}
-
-		case WE_TICK: {
-			// Update the player score every 5 days
-			if (--w->custom[0] == 0) {
-				w->custom[0] = DAY_TICKS;
-				if (--w->custom[1] == 0) {
-					Player *p2;
-
-					w->custom[1] = 5;
-					FOR_ALL_PLAYERS(p2) {
-						// Skip if player is not active
-						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
-					}
-					SetWindowDirty(w);
-				}
-			}
-
-			break;
-		}
-	}
-}
-
-static const Widget _performance_rating_detail_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   298,     0,    13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    14,    27, 0x0,                    STR_NULL},
-
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    28,    47, 0x0,                    STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    48,    67, 0x0,                    STR_PERFORMANCE_DETAIL_STATIONS_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    68,    87, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    88,   107, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   108,   127, 0x0,                    STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   128,   147, 0x0,                    STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   148,   167, 0x0,                    STR_PERFORMANCE_DETAIL_CARGO_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   168,   187, 0x0,                    STR_PERFORMANCE_DETAIL_MONEY_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   188,   207, 0x0,                    STR_PERFORMANCE_DETAIL_LOAN_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   208,   227, 0x0,                    STR_PERFORMANCE_DETAIL_TOTAL_TIP},
-
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    38,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,    39,    75,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,    76,   112,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,   113,   149,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,   150,   186,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,   187,   223,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,   224,   260,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{      WWT_PANEL,   RESIZE_NONE,    14,   261,   297,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _performance_rating_detail_desc = {
-	WDP_AUTO, WDP_AUTO, 299, 228,
-	WC_PERFORMANCE_DETAIL,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_performance_rating_detail_widgets,
-	PerformanceRatingDetailWndProc
-};
-
-void ShowPerformanceRatingDetail(void)
-{
-	AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
-}
-
-
-static const Sign **_sign_sort;
-static uint _num_sign_sort;
-
-static char _bufcache[64];
-static const Sign *_last_sign;
-
-static int CDECL SignNameSorter(const void *a, const void *b)
-{
-	const Sign *sign0 = *(const Sign**)a;
-	const Sign *sign1 = *(const Sign**)b;
-	char buf1[64];
-
-	GetString(buf1, sign0->str, lastof(buf1));
-
-	if (sign1 != _last_sign) {
-		_last_sign = sign1;
-		GetString(_bufcache, sign1->str, lastof(_bufcache));
-	}
-
-	return strcmp(buf1, _bufcache); // sort by name
-}
-
-static void GlobalSortSignList(void)
-{
-	const Sign *si;
-	uint n = 0;
-
-	/* Create array for sorting */
-	_sign_sort = realloc((void *)_sign_sort, (GetMaxSignIndex() + 1)* sizeof(_sign_sort[0]));
-	if (_sign_sort == NULL) error("Could not allocate memory for the sign-sorting-list");
-
-	FOR_ALL_SIGNS(si) _sign_sort[n++] = si;
-	_num_sign_sort = n;
-
-	qsort((void*)_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);
-
-	_sign_sort_dirty = false;
-
-	DEBUG(misc, 3, "Resorting global signs list");
-}
-
-static void SignListWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int y = 16; // offset from top of widget
-
-		if (_sign_sort_dirty)
-			GlobalSortSignList();
-
-		SetVScrollCount(w, _num_sign_sort);
-
-		SetDParam(0, w->vscroll.count);
-		DrawWindowWidgets(w);
-
-		/* No signs? */
-		if (w->vscroll.count == 0) {
-			DrawString(2, y, STR_304A_NONE, 0);
-			return;
-		}
-
-		{
-			uint16 i;
-
-			/* Start drawing the signs */
-			for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
-				const Sign *si = _sign_sort[i];
-
-				if (si->owner != OWNER_NONE)
-					DrawPlayerIcon(si->owner, 4, y + 1);
-
-				DrawString(22, y, si->str, 8);
-				y += 10;
-			}
-		}
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3: {
-			uint32 id_v = (e->we.click.pt.y - 15) / 10;
-			const Sign *si;
-
-			if (id_v >= w->vscroll.cap)
-				return;
-
-			id_v += w->vscroll.pos;
-
-			if (id_v >= w->vscroll.count)
-				return;
-
-			si = _sign_sort[id_v];
-			ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
-		} break;
-		}
-	} break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 10;
-		break;
-	}
-}
-
-static const Widget _sign_list_widget[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,                   STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    14,   137, 0x0,                   STR_NULL},
-{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    14,   125, 0x0,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   126,   137, 0x0,                   STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _sign_list_desc = {
-	WDP_AUTO, WDP_AUTO, 358, 138,
-	WC_SIGN_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_sign_list_widget,
-	SignListWndProc
-};
-
-
-void ShowSignList(void)
-{
-	Window *w;
-
-	w = AllocateWindowDescFront(&_sign_list_desc, 0);
-	if (w != NULL) {
-		w->vscroll.cap = 12;
-		w->resize.step_height = 10;
-		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/graph_gui.cpp
@@ -0,0 +1,1258 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "functions.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "player.h"
+#include "economy.h"
+#include "signs.h"
+#include "strings.h"
+#include "debug.h"
+#include "variables.h"
+#include "date.h"
+
+const byte _cargo_colours[NUM_CARGO] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 48};
+
+static uint _legend_excludebits;
+static uint _legend_cargobits;
+
+/************************/
+/* GENERIC GRAPH DRAWER */
+/************************/
+
+enum {GRAPH_NUM = 16};
+
+typedef struct GraphDrawer {
+	uint sel; // bitmask of the players *excluded* (e.g. 11111111 means that no players are shown)
+	byte num_dataset;
+	byte num_on_x_axis;
+	byte month;
+	Year year;
+	bool include_neg;
+	byte num_vert_lines;
+	uint16 unk61A;
+	uint16 unk61C;
+	int left, top;
+	uint height;
+	StringID format_str_y_axis;
+	byte color_3, color_2, bg_line_color;
+	byte colors[GRAPH_NUM];
+	uint64 cost[GRAPH_NUM][24]; // last 2 years
+} GraphDrawer;
+
+#define INVALID_VALUE 0x80000000
+
+static void DrawGraph(const GraphDrawer *gw)
+{
+
+	int i,j,k;
+	uint x,y,old_x,old_y;
+	int color;
+	int right, bottom;
+	int num_x, num_dataset;
+	const uint64 *row_ptr, *col_ptr;
+	int64 mx;
+	int adj_height;
+	uint64 y_scaling, tmp;
+	int64 value;
+	int64 cur_val;
+	uint sel;
+
+	/* the colors and cost array of GraphDrawer must accomodate
+	 * both values for cargo and players. So if any are higher, quit */
+	assert(GRAPH_NUM >= NUM_CARGO && GRAPH_NUM >= MAX_PLAYERS);
+
+	color = _colour_gradient[gw->bg_line_color][4];
+
+	/* draw the vertical lines */
+	i = gw->num_vert_lines; assert(i > 0);
+	x = gw->left + 66;
+	bottom = gw->top + gw->height - 1;
+	do {
+		GfxFillRect(x, gw->top, x, bottom, color);
+		x += 22;
+	} while (--i);
+
+	/* draw the horizontal lines */
+	i = 9;
+	x = gw->left + 44;
+	y = gw->height + gw->top;
+	right = gw->left + 44 + gw->num_vert_lines*22-1;
+
+	do {
+		GfxFillRect(x, y, right, y, color);
+		y -= gw->height >> 3;
+	} while (--i);
+
+	/* draw vertical edge line */
+	GfxFillRect(x, gw->top, x, bottom, gw->color_2);
+
+	adj_height = gw->height;
+	if (gw->include_neg) adj_height >>= 1;
+
+	/* draw horiz edge line */
+	y = adj_height + gw->top;
+	GfxFillRect(x, y, right, y, gw->color_2);
+
+	/* find the max element */
+	if (gw->num_on_x_axis == 0)
+		return;
+
+	num_dataset = gw->num_dataset;
+	assert(num_dataset > 0);
+
+	row_ptr = gw->cost[0];
+	mx = 0;
+		/* bit selection for the showing of various players, base max element
+		 * on to-be shown player-information. This way the graph can scale */
+	sel = gw->sel;
+	do {
+		if (!(sel&1)) {
+			num_x = gw->num_on_x_axis;
+			assert(num_x > 0);
+			col_ptr = row_ptr;
+			do {
+				if (*col_ptr != INVALID_VALUE) {
+					mx = max64(mx, myabs64(*col_ptr));
+				}
+			} while (col_ptr++, --num_x);
+		}
+	} while (sel>>=1, row_ptr+=24, --num_dataset);
+
+	/* setup scaling */
+	y_scaling = INVALID_VALUE;
+	value = adj_height * 2;
+
+	if (mx > value) {
+		mx = (mx + 7) & ~7;
+		y_scaling = (((uint64) (value>>1) << 32) / mx);
+		value = mx;
+	}
+
+	/* draw text strings on the y axis */
+	tmp = value;
+	if (gw->include_neg) tmp >>= 1;
+	x = gw->left + 45;
+	y = gw->top - 3;
+	i = 9;
+	do {
+		SetDParam(0, gw->format_str_y_axis);
+		SetDParam64(1, (int64)tmp);
+		tmp -= (value >> 3);
+		DrawStringRightAligned(x, y, STR_0170, gw->color_3);
+		y += gw->height >> 3;
+	} while (--i);
+
+	/* draw strings on the x axis */
+	if (gw->month != 0xFF) {
+		x = gw->left + 44;
+		y = gw->top + gw->height + 1;
+		j = gw->month;
+		k = gw->year;
+		i = gw->num_on_x_axis;assert(i>0);
+		do {
+			SetDParam(2, k);
+			SetDParam(0, j + STR_0162_JAN);
+			SetDParam(1, j + STR_0162_JAN + 2);
+			DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3);
+
+			j += 3;
+			if (j >= 12) {
+				j = 0;
+				k++;
+			}
+			x += 22;
+		} while (--i);
+	} else {
+		x = gw->left + 52;
+		y = gw->top + gw->height + 1;
+		j = gw->unk61A;
+		i = gw->num_on_x_axis;assert(i>0);
+		do {
+			SetDParam(0, j);
+			DrawString(x, y, STR_01CB, gw->color_3);
+			j += gw->unk61C;
+			x += 22;
+		} while (--i);
+	}
+
+	/* draw lines and dots */
+	i = 0;
+	row_ptr = gw->cost[0];
+	sel = gw->sel; // show only selected lines. GraphDrawer qw->sel set in Graph-Legend (_legend_excludebits)
+	do {
+		if (!(sel & 1)) {
+			x = gw->left + 55;
+			j = gw->num_on_x_axis;assert(j>0);
+			col_ptr = row_ptr;
+			color = gw->colors[i];
+			old_y = old_x = INVALID_VALUE;
+			do {
+				cur_val = *col_ptr++;
+				if (cur_val != INVALID_VALUE) {
+					y = adj_height - BIGMULSS64(cur_val, y_scaling >> 1, 31) + gw->top;
+
+					GfxFillRect(x-1, y-1, x+1, y+1, color);
+					if (old_x != INVALID_VALUE)
+						GfxDrawLine(old_x, old_y, x, y, color);
+
+					old_x = x;
+					old_y = y;
+				} else {
+					old_x = INVALID_VALUE;
+				}
+			} while (x+=22,--j);
+		}
+	} while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset);
+}
+
+/****************/
+/* GRAPH LEGEND */
+/****************/
+
+void DrawPlayerIcon(PlayerID p, int x, int y)
+{
+	DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y);
+}
+
+static void GraphLegendWndProc(Window *w, WindowEvent *e)
+{
+	const Player* p;
+
+	switch (e->event) {
+	case WE_CREATE: {
+		uint i;
+		for (i = 3; i < w->widget_count; i++) {
+			if (!HASBIT(_legend_excludebits, i - 3)) LowerWindowWidget(w, i);
+		}
+		break;
+	}
+
+	case WE_PAINT:
+		FOR_ALL_PLAYERS(p) {
+			if (!p->is_active) {
+				SETBIT(_legend_excludebits, p->index);
+				RaiseWindowWidget(w, p->index + 3);
+			}
+		}
+		DrawWindowWidgets(w);
+
+		FOR_ALL_PLAYERS(p) {
+			if (!p->is_active) continue;
+
+			DrawPlayerIcon(p->index, 4, 18+p->index*12);
+
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			SetDParam(2, GetPlayerNameString(p->index, 3));
+			DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_excludebits, p->index) ? 0x10 : 0xC);
+		}
+		break;
+
+	case WE_CLICK:
+		if (IS_INT_INSIDE(e->we.click.widget, 3, 11)) {
+			_legend_excludebits ^= (1 << (e->we.click.widget - 3));
+			ToggleWidgetLoweredState(w, e->we.click.widget);
+			SetWindowDirty(w);
+			InvalidateWindow(WC_INCOME_GRAPH, 0);
+			InvalidateWindow(WC_OPERATING_PROFIT, 0);
+			InvalidateWindow(WC_DELIVERED_CARGO, 0);
+			InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
+			InvalidateWindow(WC_COMPANY_VALUE, 0);
+		}
+		break;
+	}
+}
+
+static const Widget _graph_legend_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_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,   113, 0x0,                            STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    16,    27, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    28,    39, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    40,    51, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    52,    63, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    64,    75, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    76,    87, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    88,    99, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,   100,   111, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _graph_legend_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 114,
+	WC_GRAPH_LEGEND,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_graph_legend_widgets,
+	GraphLegendWndProc
+};
+
+static void ShowGraphLegend(void)
+{
+	AllocateWindowDescFront(&_graph_legend_desc, 0);
+}
+
+/********************/
+/* OPERATING PROFIT */
+/********************/
+
+static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
+{
+	const Player* p;
+	uint excludebits = _legend_excludebits;
+	int nums;
+	int mo,yr;
+
+	// Exclude the players which aren't valid
+	FOR_ALL_PLAYERS(p) {
+		if (!p->is_active) SETBIT(excludebits,p->index);
+	}
+	gd->sel = excludebits;
+	gd->num_vert_lines = 24;
+
+	nums = 0;
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active) nums = max(nums,p->num_valid_stat_ent);
+	}
+	gd->num_on_x_axis = min(nums,24);
+
+	mo = (_cur_month/3-nums)*3;
+	yr = _cur_year;
+	while (mo < 0) {
+		yr--;
+		mo += 12;
+	}
+
+	gd->year = yr;
+	gd->month = mo;
+}
+
+static void OperatingProfitWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		GraphDrawer gd;
+		const Player* p;
+		int i,j;
+		int numd;
+
+		DrawWindowWidgets(w);
+
+		gd.left = 2;
+		gd.top = 18;
+		gd.height = 136;
+		gd.include_neg = true;
+		gd.format_str_y_axis = STR_CURRCOMPACT;
+		gd.color_3 = 0x10;
+		gd.color_2 = 0xD7;
+		gd.bg_line_color = 0xE;
+
+		SetupGraphDrawerForPlayers(&gd);
+
+		numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				gd.colors[numd] = _colour_gradient[p->player_color][6];
+				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
+					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)(p->old_economy[j].income + p->old_economy[j].expenses);
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		gd.num_dataset = numd;
+
+		DrawGraph(&gd);
+	}	break;
+	case WE_CLICK:
+		if (e->we.click.widget == 2) /* Clicked on Legend */
+			ShowGraphLegend();
+		break;
+	}
+}
+
+static const Widget _operating_profit_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                    STR_704D_SHOW_KEY_TO_GRAPHS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   173, 0x0,                             STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _operating_profit_desc = {
+	WDP_AUTO, WDP_AUTO, 576, 174,
+	WC_OPERATING_PROFIT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_operating_profit_widgets,
+	OperatingProfitWndProc
+};
+
+
+void ShowOperatingProfitGraph(void)
+{
+	if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+}
+
+
+/****************/
+/* INCOME GRAPH */
+/****************/
+
+static void IncomeGraphWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		GraphDrawer gd;
+		const Player* p;
+		int i,j;
+		int numd;
+
+		DrawWindowWidgets(w);
+
+		gd.left = 2;
+		gd.top = 18;
+		gd.height = 104;
+		gd.include_neg = false;
+		gd.format_str_y_axis = STR_CURRCOMPACT;
+		gd.color_3 = 0x10;
+		gd.color_2 = 0xD7;
+		gd.bg_line_color = 0xE;
+		SetupGraphDrawerForPlayers(&gd);
+
+		numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				gd.colors[numd] = _colour_gradient[p->player_color][6];
+				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
+					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].income;
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		gd.num_dataset = numd;
+
+		DrawGraph(&gd);
+		break;
+	}
+
+	case WE_CLICK:
+		if (e->we.click.widget == 2)
+			ShowGraphLegend();
+		break;
+	}
+}
+
+static const Widget _income_graph_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,          STR_704D_SHOW_KEY_TO_GRAPHS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                   STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _income_graph_desc = {
+	WDP_AUTO, WDP_AUTO, 576, 142,
+	WC_INCOME_GRAPH,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_income_graph_widgets,
+	IncomeGraphWndProc
+};
+
+void ShowIncomeGraph(void)
+{
+	if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+}
+
+/*******************/
+/* DELIVERED CARGO */
+/*******************/
+
+static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		GraphDrawer gd;
+		const Player* p;
+		int i,j;
+		int numd;
+
+		DrawWindowWidgets(w);
+
+		gd.left = 2;
+		gd.top = 18;
+		gd.height = 104;
+		gd.include_neg = false;
+		gd.format_str_y_axis = STR_7024;
+		gd.color_3 = 0x10;
+		gd.color_2 = 0xD7;
+		gd.bg_line_color = 0xE;
+		SetupGraphDrawerForPlayers(&gd);
+
+		numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				gd.colors[numd] = _colour_gradient[p->player_color][6];
+				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
+					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].delivered_cargo;
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		gd.num_dataset = numd;
+
+		DrawGraph(&gd);
+		break;
+	}
+
+	case WE_CLICK:
+		if (e->we.click.widget == 2)
+			ShowGraphLegend();
+		break;
+	}
+}
+
+static const Widget _delivered_cargo_graph_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                      STR_704D_SHOW_KEY_TO_GRAPHS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                               STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _delivered_cargo_graph_desc = {
+	WDP_AUTO, WDP_AUTO, 576, 142,
+	WC_DELIVERED_CARGO,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_delivered_cargo_graph_widgets,
+	DeliveredCargoGraphWndProc
+};
+
+void ShowDeliveredCargoGraph(void)
+{
+	if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+}
+
+/***********************/
+/* PERFORMANCE HISTORY */
+/***********************/
+
+static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		GraphDrawer gd;
+		const Player* p;
+		int i,j;
+		int numd;
+
+		DrawWindowWidgets(w);
+
+		gd.left = 2;
+		gd.top = 18;
+		gd.height = 200;
+		gd.include_neg = false;
+		gd.format_str_y_axis = STR_7024;
+		gd.color_3 = 0x10;
+		gd.color_2 = 0xD7;
+		gd.bg_line_color = 0xE;
+		SetupGraphDrawerForPlayers(&gd);
+
+		numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				gd.colors[numd] = _colour_gradient[p->player_color][6];
+				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
+					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].performance_history;
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		gd.num_dataset = numd;
+
+		DrawGraph(&gd);
+		break;
+	}
+
+	case WE_CLICK:
+		if (e->we.click.widget == 2)
+			ShowGraphLegend();
+		if (e->we.click.widget == 3)
+			ShowPerformanceRatingDetail();
+		break;
+	}
+}
+
+static const Widget _performance_history_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                             STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   475,     0,    13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                         STR_704D_SHOW_KEY_TO_GRAPHS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   476,   525,     0,    13, STR_PERFORMANCE_DETAIL_KEY,           STR_704D_SHOW_KEY_TO_GRAPHS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                                  STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _performance_history_desc = {
+	WDP_AUTO, WDP_AUTO, 576, 238,
+	WC_PERFORMANCE_HISTORY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_performance_history_widgets,
+	PerformanceHistoryWndProc
+};
+
+void ShowPerformanceHistoryGraph(void)
+{
+	if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+}
+
+/*****************/
+/* COMPANY VALUE */
+/*****************/
+
+static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		GraphDrawer gd;
+		const Player* p;
+		int i,j;
+		int numd;
+
+		DrawWindowWidgets(w);
+
+		gd.left = 2;
+		gd.top = 18;
+		gd.height = 200;
+		gd.include_neg = false;
+		gd.format_str_y_axis = STR_CURRCOMPACT;
+		gd.color_3 = 0x10;
+		gd.color_2 = 0xD7;
+		gd.bg_line_color = 0xE;
+		SetupGraphDrawerForPlayers(&gd);
+
+		numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				gd.colors[numd] = _colour_gradient[p->player_color][6];
+				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
+					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].company_value;
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		gd.num_dataset = numd;
+
+		DrawGraph(&gd);
+		break;
+	}
+
+	case WE_CLICK:
+		if (e->we.click.widget == 2)
+			ShowGraphLegend();
+		break;
+	}
+}
+
+static const Widget _company_value_graph_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,            STR_704D_SHOW_KEY_TO_GRAPHS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                     STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _company_value_graph_desc = {
+	WDP_AUTO, WDP_AUTO, 576, 238,
+	WC_COMPANY_VALUE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_company_value_graph_widgets,
+	CompanyValueGraphWndProc
+};
+
+void ShowCompanyValueGraph(void)
+{
+	if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+}
+
+/*****************/
+/* PAYMENT RATES */
+/*****************/
+
+static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: {
+		uint i;
+		for (i = 3; i < w->widget_count; i++) {
+			if (!HASBIT(_legend_cargobits, i - 3)) LowerWindowWidget(w, i);
+		}
+		break;
+	}
+
+	case WE_PAINT: {
+		int j, x, y;
+		CargoID i;
+		GraphDrawer gd;
+
+		DrawWindowWidgets(w);
+
+		x = 495;
+		y = 24;
+
+		gd.sel = _legend_cargobits;
+		gd.left = 2;
+		gd.top = 24;
+		gd.height = 104;
+		gd.include_neg = false;
+		gd.format_str_y_axis = STR_CURRCOMPACT;
+		gd.color_3 = 16;
+		gd.color_2 = 215;
+		gd.bg_line_color = 14;
+		gd.num_dataset = NUM_CARGO;
+		gd.num_on_x_axis = 20;
+		gd.num_vert_lines = 20;
+		gd.month = 0xFF;
+		gd.unk61A = 10;
+		gd.unk61C = 10;
+
+		for (i = 0; i != NUM_CARGO; i++) {
+			/* Since the buttons have no text, no images,
+			 * both the text and the colored box have to be manually painted.
+			 * clk_dif will move one pixel down and one pixel to the right
+			 * when the button is clicked */
+			byte clk_dif = IsWindowWidgetLowered(w, i + 3) ? 1 : 0;
+
+			GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
+			GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, _cargo_colours[i]);
+			SetDParam(0, _cargoc.names_s[i]);
+			DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, 0);
+			y += 8;
+			gd.colors[i] = _cargo_colours[i];
+			for (j = 0; j != 20; j++) {
+				gd.cost[i][j] = (uint64)GetTransportedGoodsIncome(10, 20, j * 6 + 6, i);
+			}
+		}
+
+		DrawGraph(&gd);
+
+		DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0);
+		DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0);
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3: case 4: case 5: case 6:
+		case 7: case 8: case 9: case 10:
+		case 11: case 12: case 13: case 14:
+			TOGGLEBIT(_legend_cargobits, e->we.click.widget - 3);
+			ToggleWidgetLoweredState(w, e->we.click.widget);
+			SetWindowDirty(w);
+			break;
+		}
+	} break;
+	}
+}
+
+static const Widget _cargo_payment_rates_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   567,     0,    13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   567,    14,   141, 0x0,                          STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    24,    31, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    32,    39, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    40,    47, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    48,    55, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    56,    63, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    64,    71, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    72,    79, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    80,    87, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    88,    95, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    96,   103, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   104,   111, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   112,   119, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _cargo_payment_rates_desc = {
+	WDP_AUTO, WDP_AUTO, 568, 142,
+	WC_PAYMENT_RATES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_cargo_payment_rates_widgets,
+	CargoPaymentRatesWndProc
+};
+
+
+void ShowCargoPaymentRates(void)
+{
+	AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
+}
+
+/************************/
+/* COMPANY LEAGUE TABLE */
+/************************/
+
+static const StringID _performance_titles[] = {
+	STR_7066_ENGINEER,
+	STR_7066_ENGINEER,
+	STR_7067_TRAFFIC_MANAGER,
+	STR_7067_TRAFFIC_MANAGER,
+	STR_7068_TRANSPORT_COORDINATOR,
+	STR_7068_TRANSPORT_COORDINATOR,
+	STR_7069_ROUTE_SUPERVISOR,
+	STR_7069_ROUTE_SUPERVISOR,
+	STR_706A_DIRECTOR,
+	STR_706A_DIRECTOR,
+	STR_706B_CHIEF_EXECUTIVE,
+	STR_706B_CHIEF_EXECUTIVE,
+	STR_706C_CHAIRMAN,
+	STR_706C_CHAIRMAN,
+	STR_706D_PRESIDENT,
+	STR_706E_TYCOON,
+};
+
+static inline StringID GetPerformanceTitleFromValue(uint value)
+{
+	return _performance_titles[minu(value, 1000) >> 6];
+}
+
+static int CDECL PerfHistComp(const void* elem1, const void* elem2)
+{
+	const Player* p1 = *(const Player* const*)elem1;
+	const Player* p2 = *(const Player* const*)elem2;
+
+	return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
+}
+
+static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			const Player* plist[MAX_PLAYERS];
+			const Player* p;
+			uint pl_num;
+			uint i;
+
+			DrawWindowWidgets(w);
+
+			pl_num = 0;
+			FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
+
+			qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
+
+			for (i = 0; i != pl_num; i++) {
+				p = plist[i];
+				SetDParam(0, i + STR_01AC_1ST);
+				SetDParam(1, p->name_1);
+				SetDParam(2, p->name_2);
+				SetDParam(3, GetPlayerNameString(p->index, 4));
+				SetDParam(5, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
+
+				DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
+				DrawPlayerIcon(p->index, 27, 16 + i * 10);
+			}
+
+			break;
+		}
+	}
+}
+
+
+static const Widget _company_league_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,  0, 13, STR_00C5,                      STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_NONE, 14,  11, 387,  0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399,  0, 13, STR_NULL,                      STR_STICKY_BUTTON},
+{      WWT_PANEL, RESIZE_NONE, 14,   0, 399, 14, 96, 0x0,                           STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _company_league_desc = {
+	WDP_AUTO, WDP_AUTO, 400, 97,
+	WC_COMPANY_LEAGUE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_company_league_widgets,
+	CompanyLeagueWndProc
+};
+
+void ShowCompanyLeagueTable(void)
+{
+	AllocateWindowDescFront(&_company_league_desc,0);
+}
+
+/*****************************/
+/* PERFORMANCE RATING DETAIL */
+/*****************************/
+
+static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
+{
+	static PlayerID _performance_rating_detail_player = 0;
+
+	switch (e->event) {
+		case WE_PAINT: {
+			int i;
+			byte x;
+			uint16 y = 14;
+			int total_score = 0;
+			int color_done, color_notdone;
+
+			// Draw standard stuff
+			DrawWindowWidgets(w);
+
+			// Paint the player icons
+			for (i = 0; i < MAX_PLAYERS; i++) {
+				if (!GetPlayer(i)->is_active) {
+					// Check if we have the player as an active player
+					if (!IsWindowWidgetDisabled(w, i + 13)) {
+						// Bah, player gone :(
+						DisableWindowWidget(w, i + 13);
+						// Is this player selected? If so, select first player (always save? :s)
+						if (IsWindowWidgetLowered(w, i + 13)) {
+							RaiseWindowWidget(w, i + 13);
+							LowerWindowWidget(w, 13);
+							_performance_rating_detail_player = 0;
+						}
+						// We need a repaint
+						SetWindowDirty(w);
+					}
+				continue;
+				}
+
+				// Check if we have the player marked as inactive
+				if (IsWindowWidgetDisabled(w, i + 13)) {
+					// New player! Yippie :p
+					EnableWindowWidget(w, i + 13);
+					// We need a repaint
+					SetWindowDirty(w);
+				}
+
+				x = (i == _performance_rating_detail_player) ? 1 : 0;
+				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
+			}
+
+			// The colors used to show how the progress is going
+			color_done = _colour_gradient[COLOUR_GREEN][4];
+			color_notdone = _colour_gradient[COLOUR_RED][4];
+
+			// Draw all the score parts
+			for (i = 0; i < NUM_SCORE; i++) {
+				int val    = _score_part[_performance_rating_detail_player][i];
+				int needed = _score_info[i].needed;
+				int score  = _score_info[i].score;
+
+				y += 20;
+				// SCORE_TOTAL has his own rulez ;)
+				if (i == SCORE_TOTAL) {
+					needed = total_score;
+					score = SCORE_MAX;
+				} else {
+					total_score += score;
+				}
+
+				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
+
+				// Draw the score
+				SetDParam(0, score);
+				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
+
+				// Calculate the %-bar
+				if (val > needed) {
+					x = 50;
+				} else if (val == 0) {
+					x = 0;
+				} else {
+					x = val * 50 / needed;
+				}
+
+				// SCORE_LOAN is inversed
+				if (val < 0 && i == SCORE_LOAN) x = 0;
+
+				// Draw the bar
+				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
+				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
+
+				// Calculate the %
+				x = (val <= needed) ? val * 100 / needed : 100;
+
+				// SCORE_LOAN is inversed
+				if (val < 0 && i == SCORE_LOAN) x = 0;
+
+				// Draw it
+				SetDParam(0, x);
+				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
+
+				// SCORE_LOAN is inversed
+				if (i == SCORE_LOAN) val = needed - val;
+
+				// Draw the amount we have against what is needed
+				//  For some of them it is in currency format
+				SetDParam(0, val);
+				SetDParam(1, needed);
+				switch (i) {
+					case SCORE_MIN_PROFIT:
+					case SCORE_MIN_INCOME:
+					case SCORE_MAX_INCOME:
+					case SCORE_MONEY:
+					case SCORE_LOAN:
+						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0);
+						break;
+					default:
+						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0);
+				}
+			}
+
+			break;
+		}
+
+		case WE_CLICK:
+			// Check which button is clicked
+			if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) {
+				// Is it no on disable?
+				if (!IsWindowWidgetDisabled(w, e->we.click.widget)) {
+					RaiseWindowWidget(w, _performance_rating_detail_player + 13);
+					_performance_rating_detail_player = e->we.click.widget - 13;
+					LowerWindowWidget(w, _performance_rating_detail_player + 13);
+					SetWindowDirty(w);
+				}
+			}
+			break;
+
+		case WE_CREATE: {
+			int i;
+			Player *p2;
+
+			/* Disable the players who are not active */
+			for (i = 0; i < MAX_PLAYERS; i++) {
+				SetWindowWidgetDisabledState(w, i + 13, !GetPlayer(i)->is_active);
+			}
+			/* Update all player stats with the current data
+			 * (this is because _score_info is not saved to a savegame) */
+			FOR_ALL_PLAYERS(p2) {
+				if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
+			}
+
+			w->custom[0] = DAY_TICKS;
+			w->custom[1] = 5;
+
+			_performance_rating_detail_player = 0;
+			LowerWindowWidget(w, _performance_rating_detail_player + 13);
+			SetWindowDirty(w);
+
+			break;
+		}
+
+		case WE_TICK: {
+			// Update the player score every 5 days
+			if (--w->custom[0] == 0) {
+				w->custom[0] = DAY_TICKS;
+				if (--w->custom[1] == 0) {
+					Player *p2;
+
+					w->custom[1] = 5;
+					FOR_ALL_PLAYERS(p2) {
+						// Skip if player is not active
+						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
+					}
+					SetWindowDirty(w);
+				}
+			}
+
+			break;
+		}
+	}
+}
+
+static const Widget _performance_rating_detail_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   298,     0,    13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    14,    27, 0x0,                    STR_NULL},
+
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    28,    47, 0x0,                    STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    48,    67, 0x0,                    STR_PERFORMANCE_DETAIL_STATIONS_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    68,    87, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    88,   107, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   108,   127, 0x0,                    STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   128,   147, 0x0,                    STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   148,   167, 0x0,                    STR_PERFORMANCE_DETAIL_CARGO_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   168,   187, 0x0,                    STR_PERFORMANCE_DETAIL_MONEY_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   188,   207, 0x0,                    STR_PERFORMANCE_DETAIL_LOAN_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   208,   227, 0x0,                    STR_PERFORMANCE_DETAIL_TOTAL_TIP},
+
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    38,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,    39,    75,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,    76,   112,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,   113,   149,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,   150,   186,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,   187,   223,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,   224,   260,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{      WWT_PANEL,   RESIZE_NONE,    14,   261,   297,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _performance_rating_detail_desc = {
+	WDP_AUTO, WDP_AUTO, 299, 228,
+	WC_PERFORMANCE_DETAIL,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_performance_rating_detail_widgets,
+	PerformanceRatingDetailWndProc
+};
+
+void ShowPerformanceRatingDetail(void)
+{
+	AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
+}
+
+
+static const Sign **_sign_sort;
+static uint _num_sign_sort;
+
+static char _bufcache[64];
+static const Sign *_last_sign;
+
+static int CDECL SignNameSorter(const void *a, const void *b)
+{
+	const Sign *sign0 = *(const Sign**)a;
+	const Sign *sign1 = *(const Sign**)b;
+	char buf1[64];
+
+	GetString(buf1, sign0->str, lastof(buf1));
+
+	if (sign1 != _last_sign) {
+		_last_sign = sign1;
+		GetString(_bufcache, sign1->str, lastof(_bufcache));
+	}
+
+	return strcmp(buf1, _bufcache); // sort by name
+}
+
+static void GlobalSortSignList(void)
+{
+	const Sign *si;
+	uint n = 0;
+
+	/* Create array for sorting */
+	_sign_sort = realloc((void *)_sign_sort, (GetMaxSignIndex() + 1)* sizeof(_sign_sort[0]));
+	if (_sign_sort == NULL) error("Could not allocate memory for the sign-sorting-list");
+
+	FOR_ALL_SIGNS(si) _sign_sort[n++] = si;
+	_num_sign_sort = n;
+
+	qsort((void*)_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);
+
+	_sign_sort_dirty = false;
+
+	DEBUG(misc, 3, "Resorting global signs list");
+}
+
+static void SignListWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int y = 16; // offset from top of widget
+
+		if (_sign_sort_dirty)
+			GlobalSortSignList();
+
+		SetVScrollCount(w, _num_sign_sort);
+
+		SetDParam(0, w->vscroll.count);
+		DrawWindowWidgets(w);
+
+		/* No signs? */
+		if (w->vscroll.count == 0) {
+			DrawString(2, y, STR_304A_NONE, 0);
+			return;
+		}
+
+		{
+			uint16 i;
+
+			/* Start drawing the signs */
+			for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
+				const Sign *si = _sign_sort[i];
+
+				if (si->owner != OWNER_NONE)
+					DrawPlayerIcon(si->owner, 4, y + 1);
+
+				DrawString(22, y, si->str, 8);
+				y += 10;
+			}
+		}
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3: {
+			uint32 id_v = (e->we.click.pt.y - 15) / 10;
+			const Sign *si;
+
+			if (id_v >= w->vscroll.cap)
+				return;
+
+			id_v += w->vscroll.pos;
+
+			if (id_v >= w->vscroll.count)
+				return;
+
+			si = _sign_sort[id_v];
+			ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
+		} break;
+		}
+	} break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 10;
+		break;
+	}
+}
+
+static const Widget _sign_list_widget[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,                   STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    14,   137, 0x0,                   STR_NULL},
+{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    14,   125, 0x0,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   126,   137, 0x0,                   STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _sign_list_desc = {
+	WDP_AUTO, WDP_AUTO, 358, 138,
+	WC_SIGN_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_sign_list_widget,
+	SignListWndProc
+};
+
+
+void ShowSignList(void)
+{
+	Window *w;
+
+	w = AllocateWindowDescFront(&_sign_list_desc, 0);
+	if (w != NULL) {
+		w->vscroll.cap = 12;
+		w->resize.step_height = 10;
+		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
+	}
+}
deleted file mode 100644
--- a/src/heightmap.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "variables.h"
-#include "functions.h"
-#include "heightmap.h"
-#include "clear_map.h"
-#include "table/strings.h"
-#include "void_map.h"
-#include "debug.h"
-#include "gfx.h"
-#include "gui.h"
-#include "saveload.h"
-#include "bmp.h"
-
-/**
- * Convert RGB colors to Grayscale using 29.9% Red, 58.7% Green, 11.4% Blue
- *  (average luminosity formula) -- Dalestan
- * This in fact is the NTSC Color Space -- TrueLight
- */
-static inline byte RGBToGrayscale(byte red, byte green, byte blue)
-{
-	/* To avoid doubles and stuff, multiple it with a total of 65536 (16bits), then
-	 *  divide by it to normalize the value to a byte again. */
-	return ((red * 19595) + (green * 38470) + (blue * 7471)) / 65536;
-}
-
-
-#ifdef WITH_PNG
-
-#include "png.h"
-
-/**
- * The PNG Heightmap loader.
- */
-static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop info_ptr)
-{
-	uint x, y;
-	byte gray_palette[256];
-	png_bytep *row_pointers = NULL;
-
-	/* Get palette and convert it to grayscale */
-	if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-		int i;
-		int palette_size;
-		png_color *palette;
-		bool all_gray = true;
-
-		png_get_PLTE(png_ptr, info_ptr, &palette, &palette_size);
-		for (i = 0; i < palette_size && (palette_size != 16 || all_gray); i++) {
-			all_gray &= palette[i].red == palette[i].green && palette[i].red == palette[i].blue;
-			gray_palette[i] = RGBToGrayscale(palette[i].red, palette[i].green, palette[i].blue);
-		}
-
-		/**
-		 * For a non-gray palette of size 16 we assume that
-		 * the order of the palette determines the height;
-		 * the first entry is the sea (level 0), the second one
-		 * level 1, etc.
-		 */
-		if (palette_size == 16 && !all_gray) {
-			for (i = 0; i < palette_size; i++) {
-				gray_palette[i] = 256 * i / palette_size;
-			}
-		}
-	}
-
-	row_pointers = png_get_rows(png_ptr, info_ptr);
-
-	/* Read the raw image data and convert in 8-bit grayscale */
-	for (x = 0; x < info_ptr->width; x++) {
-		for (y = 0; y < info_ptr->height; y++) {
-			byte *pixel = &map[y * info_ptr->width + x];
-			uint x_offset = x * info_ptr->channels;
-
-			if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-				*pixel = gray_palette[row_pointers[y][x_offset]];
-			} else if (info_ptr->channels == 3) {
-				*pixel = RGBToGrayscale(row_pointers[y][x_offset + 0],
-						row_pointers[y][x_offset + 1], row_pointers[y][x_offset + 2]);
-			} else {
-				*pixel = row_pointers[y][x_offset];
-			}
-		}
-	}
-}
-
-/**
- * Reads the heightmap and/or size of the heightmap from a PNG file.
- * If map == NULL only the size of the PNG is read, otherwise a map
- * with grayscale pixels is allocated and assigned to *map.
- */
-static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map)
-{
-	FILE *fp;
-	png_structp png_ptr = NULL;
-	png_infop info_ptr  = NULL;
-
-	fp = fopen(filename, "rb");
-	if (fp == NULL) {
-		ShowErrorMessage(STR_PNGMAP_ERR_FILE_NOT_FOUND, STR_PNGMAP_ERROR, 0, 0);
-		return false;
-	}
-
-	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-	if (png_ptr == NULL) {
-		ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
-		fclose(fp);
-		return false;
-	}
-
-	info_ptr = png_create_info_struct(png_ptr);
-	if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) {
-		ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
-		fclose(fp);
-		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-		return false;
-	}
-
-	png_init_io(png_ptr, fp);
-
-	/* Allocate memory and read image, without alpha or 16-bit samples
-	 * (result is either 8-bit indexed/grayscale or 24-bit RGB) */
-	png_set_packing(png_ptr);
-	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL);
-
-	/* Maps of wrong color-depth are not used.
-	 * (this should have been taken care of by stripping alpha and 16-bit samples on load) */
-	if ((info_ptr->channels != 1) && (info_ptr->channels != 3) && (info_ptr->bit_depth != 8)) {
-		ShowErrorMessage(STR_PNGMAP_ERR_IMAGE_TYPE, STR_PNGMAP_ERROR, 0, 0);
-		fclose(fp);
-		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-		return false;
-	}
-
-	if (map != NULL) {
-		*map = malloc(info_ptr->width * info_ptr->height * sizeof(byte));
-
-		if (*map == NULL) {
-			ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
-			fclose(fp);
-			png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-			return false;
-		}
-
-		ReadHeightmapPNGImageData(*map, png_ptr, info_ptr);
-	}
-
-	*x = info_ptr->width;
-	*y = info_ptr->height;
-
-	fclose(fp);
-	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-	return true;
-}
-
-#endif /* WITH_PNG */
-
-
-/**
- * The BMP Heightmap loader.
- */
-static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data)
-{
-	uint x, y;
-	byte gray_palette[256];
-
-	if (data->palette != NULL) {
-		uint i;
-		bool all_gray = true;
-
-		if (info->palette_size != 2) {
-			for (i = 0; i < info->palette_size && (info->palette_size != 16 || all_gray); i++) {
-				all_gray &= data->palette[i].r == data->palette[i].g && data->palette[i].r == data->palette[i].b;
-				gray_palette[i] = RGBToGrayscale(data->palette[i].r, data->palette[i].g, data->palette[i].b);
-			}
-
-			/**
-			 * For a non-gray palette of size 16 we assume that
-			 * the order of the palette determines the height;
-			 * the first entry is the sea (level 0), the second one
-			 * level 1, etc.
-			 */
-			if (info->palette_size == 16 && !all_gray) {
-				for (i = 0; i < info->palette_size; i++) {
-					gray_palette[i] = 256 * i / info->palette_size;
-				}
-			}
-		} else {
-			/**
-			 * For a palette of size 2 we assume that the order of the palette determines the height;
-			 * the first entry is the sea (level 0), the second one is the land (level 1)
-			 */
-			gray_palette[0] = 0;
-			gray_palette[1] = 16;
-		}
-	}
-
-	/* Read the raw image data and convert in 8-bit grayscale */
-	for (y = 0; y < info->height; y++) {
-		byte *pixel = &map[y * info->width];
-		byte *bitmap = &data->bitmap[y * info->width * (info->bpp == 24 ? 3 : 1)];
-
-		for (x = 0; x < info->width; x++) {
-			if (info->bpp != 24) {
-				*pixel++ = gray_palette[*bitmap++];
-			} else {
-				*pixel++ = RGBToGrayscale(*bitmap, *(bitmap + 1), *(bitmap + 2));
-				bitmap += 3;
-			}
-		}
-	}
-}
-
-/**
- * Reads the heightmap and/or size of the heightmap from a BMP file.
- * If map == NULL only the size of the BMP is read, otherwise a map
- * with grayscale pixels is allocated and assigned to *map.
- */
-static bool ReadHeightmapBMP(char *filename, uint *x, uint *y, byte **map)
-{
-	FILE *f;
-	BmpInfo info;
-	BmpData data;
-	BmpBuffer buffer;
-
-	f = fopen(filename, "rb");
-	if (f == NULL) {
-		ShowErrorMessage(STR_PNGMAP_ERR_FILE_NOT_FOUND, STR_BMPMAP_ERROR, 0, 0);
-		return false;
-	}
-
-	BmpInitializeBuffer(&buffer, f);
-
-	if (!BmpReadHeader(&buffer, &info, &data)) {
-		ShowErrorMessage(STR_BMPMAP_ERR_IMAGE_TYPE, STR_BMPMAP_ERROR, 0, 0);
-		fclose(f);
-		BmpDestroyData(&data);
-		return false;
-	}
-
-	if (map != NULL) {
-		if (!BmpReadBitmap(&buffer, &info, &data)) {
-			ShowErrorMessage(STR_BMPMAP_ERR_IMAGE_TYPE, STR_BMPMAP_ERROR, 0, 0);
-			fclose(f);
-			BmpDestroyData(&data);
-			return false;
-		}
-
-		*map = malloc(info.width * info.height * sizeof(byte));
-		if (*map == NULL) {
-			ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_BMPMAP_ERROR, 0, 0);
-			fclose(f);
-			BmpDestroyData(&data);
-			return false;
-		}
-
-		ReadHeightmapBMPImageData(*map, &info, &data);
-
-	}
-
-	BmpDestroyData(&data);
-
-	*x = info.width;
-	*y = info.height;
-
-	fclose(f);
-	return true;
-}
-
-static void GrayscaleToMapHeights(uint img_width, uint img_height, byte *map)
-{
-	/* Defines the detail of the aspect ratio (to avoid doubles) */
-	const uint num_div = 16384;
-
-	uint width, height;
-	uint row, col;
-	uint row_pad = 0, col_pad = 0;
-	uint img_scale;
-	uint img_row, img_col;
-	TileIndex tile;
-
-	/* Get map size and calculate scale and padding values */
-	switch (_patches.heightmap_rotation) {
-	case HM_COUNTER_CLOCKWISE:
-		width   = MapSizeX();
-		height  = MapSizeY();
-		break;
-	case HM_CLOCKWISE:
-		width   = MapSizeY();
-		height  = MapSizeX();
-		break;
-	default:
-		NOT_REACHED();
-		/* Avoids compiler warnings */
-		return;
-	}
-
-	if ((img_width * num_div) / img_height > ((width * num_div) / height)) {
-		/* Image is wider than map - center vertically */
-		img_scale = (width * num_div) / img_width;
-		row_pad = (height - ((img_height * img_scale) / num_div)) / 2;
-	} else {
-		/* Image is taller than map - center horizontally */
-		img_scale = (height * num_div) / img_height;
-		col_pad = (width - ((img_width * img_scale) / num_div)) / 2;
-	}
-
-	/* Form the landscape */
-	for (row = 0; row < height - 1; row++) {
-		for (col = 0; col < width - 1; col++) {
-			switch (_patches.heightmap_rotation) {
-			case HM_COUNTER_CLOCKWISE: tile = TileXY(col, row); break;
-			case HM_CLOCKWISE:         tile = TileXY(row, col); break;
-			default:                   NOT_REACHED(); return;
-			}
-
-			/* Check if current tile is within the 1-pixel map edge or padding regions */
-			if ((DistanceFromEdge(tile) <= 1) ||
-					(row < row_pad) || (row >= (img_height + row_pad)) ||
-					(col < col_pad) || (col >= (img_width  + col_pad))) {
-				SetTileHeight(tile, 0);
-			} else {
-				/* Use nearest neighbor resizing to scale map data.
-				 *  We rotate the map 45 degrees (counter)clockwise */
-				img_row = (((row - row_pad) * num_div) / img_scale);
-				switch (_patches.heightmap_rotation) {
-				case HM_COUNTER_CLOCKWISE:
-					img_col = (((width - 1 - col - col_pad) * num_div) / img_scale);
-					break;
-				case HM_CLOCKWISE:
-					img_col = (((col - col_pad) * num_div) / img_scale);
-					break;
-				default:
-					NOT_REACHED();
-					/* Avoids compiler warnings */
-					return;
-				}
-
-				assert(img_row < img_height);
-				assert(img_col < img_width);
-
-				/* Color scales from 0 to 255, OpenTTD height scales from 0 to 15 */
-				SetTileHeight(tile, map[img_row * img_width + img_col] / 16);
-			}
-			MakeClear(tile, CLEAR_GRASS, 3);
-		}
-	}
-}
-
-/**
- * This function takes care of the fact that land in OpenTTD can never differ
- * more than 1 in height
- */
-static void FixSlopes(void)
-{
-	uint width, height;
-	uint row, col;
-	byte current_tile;
-
-	/* Adjust height difference to maximum one horizontal/vertical change. */
-	width   = MapSizeX();
-	height  = MapSizeY();
-
-	/* Top and left edge */
-	for (row = 1; row < height - 2; row++) {
-		for (col = 1; col < width - 2; col++) {
-			/* Find lowest tile; either the top or left one */
-			current_tile = TileHeight(TileXY(col - 1, row)); // top edge
-			if (TileHeight(TileXY(col, row - 1)) < current_tile) {
-				current_tile = TileHeight(TileXY(col, row - 1)); // left edge
-			}
-
-			/* Does the height differ more than one? */
-			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
-				/* Then change the height to be no more than one */
-				SetTileHeight(TileXY(col, row), current_tile + 1);
-			}
-		}
-	}
-
-	/* Bottom and right edge */
-	for (row = height - 2; row > 0; row--) {
-		for (col = width - 2; col > 0; col--) {
-			/* Find lowest tile; either the bottom and right one */
-			current_tile = TileHeight(TileXY(col + 1, row)); // bottom edge
-			if (TileHeight(TileXY(col, row + 1)) < current_tile) {
-				current_tile = TileHeight(TileXY(col, row + 1)); // right edge
-			}
-
-			/* Does the height differ more than one? */
-			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
-				/* Then change the height to be no more than one */
-				SetTileHeight(TileXY(col, row), current_tile + 1);
-			}
-		}
-	}
-}
-
-/**
- * Reads the heightmap with the correct file reader
- */
-static bool ReadHeightMap(char *filename, uint *x, uint *y, byte **map)
-{
-	switch (_file_to_saveload.mode) {
-#ifdef WITH_PNG
-		case SL_PNG:
-			return ReadHeightmapPNG(filename, x, y, map);
-#endif /* WITH_PNG */
-		case SL_BMP:
-			return ReadHeightmapBMP(filename, x, y, map);
-
-		default:
-			NOT_REACHED();
-			/* Avoids compiler warnings */
-			return false;
-	}
-}
-
-bool GetHeightmapDimensions(char *filename, uint *x, uint *y)
-{
-	return ReadHeightMap(filename, x, y, NULL);
-}
-
-void LoadHeightmap(char *filename)
-{
-	uint x, y;
-	byte *map = NULL;
-
-	if (!ReadHeightMap(filename, &x, &y, &map)) {
-		free(map);
-		return;
-	}
-
-	GrayscaleToMapHeights(x, y, map);
-	free(map);
-
-	FixSlopes();
-	MarkWholeScreenDirty();
-}
-
-void FlatEmptyWorld(byte tile_height)
-{
-	uint width, height;
-	uint row, col;
-
-	width  = MapSizeX();
-	height = MapSizeY();
-
-	for (row = 2; row < height - 2; row++) {
-		for (col = 2; col < width - 2; col++) {
-			SetTileHeight(TileXY(col, row), tile_height);
-		}
-	}
-
-	FixSlopes();
-	MarkWholeScreenDirty();
-}
new file mode 100644
--- /dev/null
+++ b/src/heightmap.cpp
@@ -0,0 +1,459 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "variables.h"
+#include "functions.h"
+#include "heightmap.h"
+#include "clear_map.h"
+#include "table/strings.h"
+#include "void_map.h"
+#include "debug.h"
+#include "gfx.h"
+#include "gui.h"
+#include "saveload.h"
+#include "bmp.h"
+
+/**
+ * Convert RGB colors to Grayscale using 29.9% Red, 58.7% Green, 11.4% Blue
+ *  (average luminosity formula) -- Dalestan
+ * This in fact is the NTSC Color Space -- TrueLight
+ */
+static inline byte RGBToGrayscale(byte red, byte green, byte blue)
+{
+	/* To avoid doubles and stuff, multiple it with a total of 65536 (16bits), then
+	 *  divide by it to normalize the value to a byte again. */
+	return ((red * 19595) + (green * 38470) + (blue * 7471)) / 65536;
+}
+
+
+#ifdef WITH_PNG
+
+#include "png.h"
+
+/**
+ * The PNG Heightmap loader.
+ */
+static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop info_ptr)
+{
+	uint x, y;
+	byte gray_palette[256];
+	png_bytep *row_pointers = NULL;
+
+	/* Get palette and convert it to grayscale */
+	if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+		int i;
+		int palette_size;
+		png_color *palette;
+		bool all_gray = true;
+
+		png_get_PLTE(png_ptr, info_ptr, &palette, &palette_size);
+		for (i = 0; i < palette_size && (palette_size != 16 || all_gray); i++) {
+			all_gray &= palette[i].red == palette[i].green && palette[i].red == palette[i].blue;
+			gray_palette[i] = RGBToGrayscale(palette[i].red, palette[i].green, palette[i].blue);
+		}
+
+		/**
+		 * For a non-gray palette of size 16 we assume that
+		 * the order of the palette determines the height;
+		 * the first entry is the sea (level 0), the second one
+		 * level 1, etc.
+		 */
+		if (palette_size == 16 && !all_gray) {
+			for (i = 0; i < palette_size; i++) {
+				gray_palette[i] = 256 * i / palette_size;
+			}
+		}
+	}
+
+	row_pointers = png_get_rows(png_ptr, info_ptr);
+
+	/* Read the raw image data and convert in 8-bit grayscale */
+	for (x = 0; x < info_ptr->width; x++) {
+		for (y = 0; y < info_ptr->height; y++) {
+			byte *pixel = &map[y * info_ptr->width + x];
+			uint x_offset = x * info_ptr->channels;
+
+			if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+				*pixel = gray_palette[row_pointers[y][x_offset]];
+			} else if (info_ptr->channels == 3) {
+				*pixel = RGBToGrayscale(row_pointers[y][x_offset + 0],
+						row_pointers[y][x_offset + 1], row_pointers[y][x_offset + 2]);
+			} else {
+				*pixel = row_pointers[y][x_offset];
+			}
+		}
+	}
+}
+
+/**
+ * Reads the heightmap and/or size of the heightmap from a PNG file.
+ * If map == NULL only the size of the PNG is read, otherwise a map
+ * with grayscale pixels is allocated and assigned to *map.
+ */
+static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map)
+{
+	FILE *fp;
+	png_structp png_ptr = NULL;
+	png_infop info_ptr  = NULL;
+
+	fp = fopen(filename, "rb");
+	if (fp == NULL) {
+		ShowErrorMessage(STR_PNGMAP_ERR_FILE_NOT_FOUND, STR_PNGMAP_ERROR, 0, 0);
+		return false;
+	}
+
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL) {
+		ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
+		fclose(fp);
+		return false;
+	}
+
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) {
+		ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
+		fclose(fp);
+		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+		return false;
+	}
+
+	png_init_io(png_ptr, fp);
+
+	/* Allocate memory and read image, without alpha or 16-bit samples
+	 * (result is either 8-bit indexed/grayscale or 24-bit RGB) */
+	png_set_packing(png_ptr);
+	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL);
+
+	/* Maps of wrong color-depth are not used.
+	 * (this should have been taken care of by stripping alpha and 16-bit samples on load) */
+	if ((info_ptr->channels != 1) && (info_ptr->channels != 3) && (info_ptr->bit_depth != 8)) {
+		ShowErrorMessage(STR_PNGMAP_ERR_IMAGE_TYPE, STR_PNGMAP_ERROR, 0, 0);
+		fclose(fp);
+		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+		return false;
+	}
+
+	if (map != NULL) {
+		*map = malloc(info_ptr->width * info_ptr->height * sizeof(byte));
+
+		if (*map == NULL) {
+			ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_PNGMAP_ERROR, 0, 0);
+			fclose(fp);
+			png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+			return false;
+		}
+
+		ReadHeightmapPNGImageData(*map, png_ptr, info_ptr);
+	}
+
+	*x = info_ptr->width;
+	*y = info_ptr->height;
+
+	fclose(fp);
+	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+	return true;
+}
+
+#endif /* WITH_PNG */
+
+
+/**
+ * The BMP Heightmap loader.
+ */
+static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data)
+{
+	uint x, y;
+	byte gray_palette[256];
+
+	if (data->palette != NULL) {
+		uint i;
+		bool all_gray = true;
+
+		if (info->palette_size != 2) {
+			for (i = 0; i < info->palette_size && (info->palette_size != 16 || all_gray); i++) {
+				all_gray &= data->palette[i].r == data->palette[i].g && data->palette[i].r == data->palette[i].b;
+				gray_palette[i] = RGBToGrayscale(data->palette[i].r, data->palette[i].g, data->palette[i].b);
+			}
+
+			/**
+			 * For a non-gray palette of size 16 we assume that
+			 * the order of the palette determines the height;
+			 * the first entry is the sea (level 0), the second one
+			 * level 1, etc.
+			 */
+			if (info->palette_size == 16 && !all_gray) {
+				for (i = 0; i < info->palette_size; i++) {
+					gray_palette[i] = 256 * i / info->palette_size;
+				}
+			}
+		} else {
+			/**
+			 * For a palette of size 2 we assume that the order of the palette determines the height;
+			 * the first entry is the sea (level 0), the second one is the land (level 1)
+			 */
+			gray_palette[0] = 0;
+			gray_palette[1] = 16;
+		}
+	}
+
+	/* Read the raw image data and convert in 8-bit grayscale */
+	for (y = 0; y < info->height; y++) {
+		byte *pixel = &map[y * info->width];
+		byte *bitmap = &data->bitmap[y * info->width * (info->bpp == 24 ? 3 : 1)];
+
+		for (x = 0; x < info->width; x++) {
+			if (info->bpp != 24) {
+				*pixel++ = gray_palette[*bitmap++];
+			} else {
+				*pixel++ = RGBToGrayscale(*bitmap, *(bitmap + 1), *(bitmap + 2));
+				bitmap += 3;
+			}
+		}
+	}
+}
+
+/**
+ * Reads the heightmap and/or size of the heightmap from a BMP file.
+ * If map == NULL only the size of the BMP is read, otherwise a map
+ * with grayscale pixels is allocated and assigned to *map.
+ */
+static bool ReadHeightmapBMP(char *filename, uint *x, uint *y, byte **map)
+{
+	FILE *f;
+	BmpInfo info;
+	BmpData data;
+	BmpBuffer buffer;
+
+	f = fopen(filename, "rb");
+	if (f == NULL) {
+		ShowErrorMessage(STR_PNGMAP_ERR_FILE_NOT_FOUND, STR_BMPMAP_ERROR, 0, 0);
+		return false;
+	}
+
+	BmpInitializeBuffer(&buffer, f);
+
+	if (!BmpReadHeader(&buffer, &info, &data)) {
+		ShowErrorMessage(STR_BMPMAP_ERR_IMAGE_TYPE, STR_BMPMAP_ERROR, 0, 0);
+		fclose(f);
+		BmpDestroyData(&data);
+		return false;
+	}
+
+	if (map != NULL) {
+		if (!BmpReadBitmap(&buffer, &info, &data)) {
+			ShowErrorMessage(STR_BMPMAP_ERR_IMAGE_TYPE, STR_BMPMAP_ERROR, 0, 0);
+			fclose(f);
+			BmpDestroyData(&data);
+			return false;
+		}
+
+		*map = malloc(info.width * info.height * sizeof(byte));
+		if (*map == NULL) {
+			ShowErrorMessage(STR_PNGMAP_ERR_MISC, STR_BMPMAP_ERROR, 0, 0);
+			fclose(f);
+			BmpDestroyData(&data);
+			return false;
+		}
+
+		ReadHeightmapBMPImageData(*map, &info, &data);
+
+	}
+
+	BmpDestroyData(&data);
+
+	*x = info.width;
+	*y = info.height;
+
+	fclose(f);
+	return true;
+}
+
+static void GrayscaleToMapHeights(uint img_width, uint img_height, byte *map)
+{
+	/* Defines the detail of the aspect ratio (to avoid doubles) */
+	const uint num_div = 16384;
+
+	uint width, height;
+	uint row, col;
+	uint row_pad = 0, col_pad = 0;
+	uint img_scale;
+	uint img_row, img_col;
+	TileIndex tile;
+
+	/* Get map size and calculate scale and padding values */
+	switch (_patches.heightmap_rotation) {
+	case HM_COUNTER_CLOCKWISE:
+		width   = MapSizeX();
+		height  = MapSizeY();
+		break;
+	case HM_CLOCKWISE:
+		width   = MapSizeY();
+		height  = MapSizeX();
+		break;
+	default:
+		NOT_REACHED();
+		/* Avoids compiler warnings */
+		return;
+	}
+
+	if ((img_width * num_div) / img_height > ((width * num_div) / height)) {
+		/* Image is wider than map - center vertically */
+		img_scale = (width * num_div) / img_width;
+		row_pad = (height - ((img_height * img_scale) / num_div)) / 2;
+	} else {
+		/* Image is taller than map - center horizontally */
+		img_scale = (height * num_div) / img_height;
+		col_pad = (width - ((img_width * img_scale) / num_div)) / 2;
+	}
+
+	/* Form the landscape */
+	for (row = 0; row < height - 1; row++) {
+		for (col = 0; col < width - 1; col++) {
+			switch (_patches.heightmap_rotation) {
+			case HM_COUNTER_CLOCKWISE: tile = TileXY(col, row); break;
+			case HM_CLOCKWISE:         tile = TileXY(row, col); break;
+			default:                   NOT_REACHED(); return;
+			}
+
+			/* Check if current tile is within the 1-pixel map edge or padding regions */
+			if ((DistanceFromEdge(tile) <= 1) ||
+					(row < row_pad) || (row >= (img_height + row_pad)) ||
+					(col < col_pad) || (col >= (img_width  + col_pad))) {
+				SetTileHeight(tile, 0);
+			} else {
+				/* Use nearest neighbor resizing to scale map data.
+				 *  We rotate the map 45 degrees (counter)clockwise */
+				img_row = (((row - row_pad) * num_div) / img_scale);
+				switch (_patches.heightmap_rotation) {
+				case HM_COUNTER_CLOCKWISE:
+					img_col = (((width - 1 - col - col_pad) * num_div) / img_scale);
+					break;
+				case HM_CLOCKWISE:
+					img_col = (((col - col_pad) * num_div) / img_scale);
+					break;
+				default:
+					NOT_REACHED();
+					/* Avoids compiler warnings */
+					return;
+				}
+
+				assert(img_row < img_height);
+				assert(img_col < img_width);
+
+				/* Color scales from 0 to 255, OpenTTD height scales from 0 to 15 */
+				SetTileHeight(tile, map[img_row * img_width + img_col] / 16);
+			}
+			MakeClear(tile, CLEAR_GRASS, 3);
+		}
+	}
+}
+
+/**
+ * This function takes care of the fact that land in OpenTTD can never differ
+ * more than 1 in height
+ */
+static void FixSlopes(void)
+{
+	uint width, height;
+	uint row, col;
+	byte current_tile;
+
+	/* Adjust height difference to maximum one horizontal/vertical change. */
+	width   = MapSizeX();
+	height  = MapSizeY();
+
+	/* Top and left edge */
+	for (row = 1; row < height - 2; row++) {
+		for (col = 1; col < width - 2; col++) {
+			/* Find lowest tile; either the top or left one */
+			current_tile = TileHeight(TileXY(col - 1, row)); // top edge
+			if (TileHeight(TileXY(col, row - 1)) < current_tile) {
+				current_tile = TileHeight(TileXY(col, row - 1)); // left edge
+			}
+
+			/* Does the height differ more than one? */
+			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
+				/* Then change the height to be no more than one */
+				SetTileHeight(TileXY(col, row), current_tile + 1);
+			}
+		}
+	}
+
+	/* Bottom and right edge */
+	for (row = height - 2; row > 0; row--) {
+		for (col = width - 2; col > 0; col--) {
+			/* Find lowest tile; either the bottom and right one */
+			current_tile = TileHeight(TileXY(col + 1, row)); // bottom edge
+			if (TileHeight(TileXY(col, row + 1)) < current_tile) {
+				current_tile = TileHeight(TileXY(col, row + 1)); // right edge
+			}
+
+			/* Does the height differ more than one? */
+			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
+				/* Then change the height to be no more than one */
+				SetTileHeight(TileXY(col, row), current_tile + 1);
+			}
+		}
+	}
+}
+
+/**
+ * Reads the heightmap with the correct file reader
+ */
+static bool ReadHeightMap(char *filename, uint *x, uint *y, byte **map)
+{
+	switch (_file_to_saveload.mode) {
+#ifdef WITH_PNG
+		case SL_PNG:
+			return ReadHeightmapPNG(filename, x, y, map);
+#endif /* WITH_PNG */
+		case SL_BMP:
+			return ReadHeightmapBMP(filename, x, y, map);
+
+		default:
+			NOT_REACHED();
+			/* Avoids compiler warnings */
+			return false;
+	}
+}
+
+bool GetHeightmapDimensions(char *filename, uint *x, uint *y)
+{
+	return ReadHeightMap(filename, x, y, NULL);
+}
+
+void LoadHeightmap(char *filename)
+{
+	uint x, y;
+	byte *map = NULL;
+
+	if (!ReadHeightMap(filename, &x, &y, &map)) {
+		free(map);
+		return;
+	}
+
+	GrayscaleToMapHeights(x, y, map);
+	free(map);
+
+	FixSlopes();
+	MarkWholeScreenDirty();
+}
+
+void FlatEmptyWorld(byte tile_height)
+{
+	uint width, height;
+	uint row, col;
+
+	width  = MapSizeX();
+	height = MapSizeY();
+
+	for (row = 2; row < height - 2; row++) {
+		for (col = 2; col < width - 2; col++) {
+			SetTileHeight(TileXY(col, row), tile_height);
+		}
+	}
+
+	FixSlopes();
+	MarkWholeScreenDirty();
+}
deleted file mode 100644
--- a/src/industry_cmd.c
+++ /dev/null
@@ -1,1910 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "clear_map.h"
-#include "functions.h"
-#include "industry_map.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "tile.h"
-#include "viewport.h"
-#include "command.h"
-#include "industry.h"
-#include "town.h"
-#include "vehicle.h"
-#include "news.h"
-#include "saveload.h"
-#include "economy.h"
-#include "sound.h"
-#include "variables.h"
-#include "table/industry_land.h"
-#include "table/build_industry.h"
-#include "genworld.h"
-#include "date.h"
-#include "water_map.h"
-
-void ShowIndustryViewWindow(int industry);
-void BuildOilRig(TileIndex tile);
-void DeleteOilRig(TileIndex tile);
-
-static byte _industry_sound_ctr;
-static TileIndex _industry_sound_tile;
-
-/**
- * Called if a new block is added to the industry-pool
- */
-static void IndustryPoolNewBlock(uint start_item)
-{
-	Industry *i;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (i = GetIndustry(start_item); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) i->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Industry, Industry, IndustryPoolNewBlock, NULL)
-
-/**
- * Retrieve the type for this industry.  Although it is accessed by a tile,
- * it will return the general type of industry, and not the sprite index
- * as would do GetIndustryGfx.
- * The same information can be accessed by looking at Industry->type
- * @param tile that is queried
- * @pre IsTileType(tile, MP_INDUSTRY)
- * @return general type for this industry, as defined in industry.h
- **/
-IndustryType GetIndustryType(TileIndex tile)
-{
-	IndustryGfx this_type = GetIndustryGfx(tile);
-	IndustryType iloop;
-
-	assert(IsTileType(tile, MP_INDUSTRY));
-
-	for (iloop = IT_COAL_MINE; iloop < IT_END; iloop += 1) {
-		if (IS_BYTE_INSIDE(this_type, industry_gfx_Solver[iloop].MinGfx,
-				industry_gfx_Solver[iloop].MaxGfx+1)) {
-			return iloop;
-		}
-	}
-
-	return IT_INVALID;  //we have not found equivalent, whatever the reason
-}
-
-/**
- * Accessor for array _industry_specs.
- * This will ensure at once : proper access and
- * not allowing modifications of it.
- * @param thistype of industry (which is the index in _industry_specs)
- * @pre thistype < IT_END
- **/
-const IndustrySpec *GetIndustrySpec(IndustryType thistype)
-{
-	assert(thistype < IT_END);
-	return &_industry_specs[thistype];
-}
-
-void DestroyIndustry(Industry *i)
-{
-	BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
-		if (IsTileType(tile_cur, MP_INDUSTRY)) {
-			if (GetIndustryIndex(tile_cur) == i->index) {
-				DoClearSquare(tile_cur);
-			}
-		} else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
-			DeleteOilRig(tile_cur);
-		}
-	END_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
-
-	if (i->type == IT_FARM || i->type == IT_FARM_2) {
-		/* Remove the farmland and convert it to regular tiles over time. */
-		BEGIN_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiffXY(21, 21)) {
-			tile_cur = TILE_MASK(tile_cur);
-			if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
-					GetIndustryIndexOfField(tile_cur) == i->index) {
-				SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
-			}
-		} END_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiff(21, 21))
-	}
-
-	_industry_sort_dirty = true;
-	_total_industries--;
-	DeleteSubsidyWithIndustry(i->index);
-	DeleteWindowById(WC_INDUSTRY_VIEW, i->index);
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
-}
-
-static void IndustryDrawSugarMine(const TileInfo *ti)
-{
-	const DrawIndustrySpec1Struct *d;
-	uint32 image;
-
-	if (!IsIndustryCompleted(ti->tile)) return;
-
-	d = &_draw_industry_spec1[GetIndustryAnimationState(ti->tile)];
-
-	AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, d->x, 0);
-
-	image = d->image_2;
-	if (image != 0) AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + image - 1, 8, 41);
-
-	image = d->image_3;
-	if (image != 0) {
-		AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + image - 1,
-			_drawtile_proc1_x[image - 1], _drawtile_proc1_y[image - 1]);
-	}
-}
-
-static void IndustryDrawToffeeQuarry(const TileInfo *ti)
-{
-	int x = 0;
-
-	if (IsIndustryCompleted(ti->tile)) {
-		x = _industry_anim_offs[GetIndustryAnimationState(ti->tile)];
-		if ( (byte)x == 0xFF)
-			x = 0;
-	}
-
-	AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, 22 - x, 24 + x);
-	AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, 6, 14);
-}
-
-static void IndustryDrawBubbleGenerator( const TileInfo *ti)
-{
-	if (IsIndustryCompleted(ti->tile)) {
-		AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, 5, _industry_anim_offs_2[GetIndustryAnimationState(ti->tile)]);
-	} else {
-		AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, 3, 67);
-	}
-}
-
-static void IndustryDrawToyFactory(const TileInfo *ti)
-{
-	const DrawIndustrySpec4Struct *d;
-
-	d = &_industry_anim_offs_3[GetIndustryAnimationState(ti->tile)];
-
-	if (d->image_1 != 0xFF) {
-		AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, 50 - d->image_1 * 2, 96 + d->image_1);
-	}
-
-	if (d->image_2 != 0xFF) {
-		AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, 16 - d->image_2 * 2, 100 + d->image_2);
-	}
-
-	AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, 7, d->image_3);
-	AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, 0, 42);
-}
-
-static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
-{
-	if (IsIndustryCompleted(ti->tile)) {
-		uint image = GetIndustryAnimationState(ti->tile);
-
-		if (image != 0 && image < 7) {
-			AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
-				_coal_plant_sparks_x[image - 1],
-				_coal_plant_sparks_y[image - 1]
-			);
-		}
-	}
-}
-
-typedef void IndustryDrawTileProc(const TileInfo *ti);
-static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
-	IndustryDrawSugarMine,
-	IndustryDrawToffeeQuarry,
-	IndustryDrawBubbleGenerator,
-	IndustryDrawToyFactory,
-	IndustryDrawCoalPlantSparks,
-};
-
-static void DrawTile_Industry(TileInfo *ti)
-{
-	const IndustryGfx gfx = GetIndustryGfx(ti->tile);
-	const Industry *ind;
-	const DrawBuildingsTileStruct *dits;
-	byte z;
-	uint32 image, ormod;
-
-	/* Pointer to industry */
-	ind = GetIndustryByTile(ti->tile);
-	ormod = GENERAL_SPRITE_COLOR(ind->random_color);
-
-	/* Retrieve pointer to the draw industry tile struct */
-	dits = &_industry_draw_tile_data[gfx << 2 | (_industry_section_draw_animation_state[gfx] ?
-			GetIndustryAnimationState(ti->tile) & 3 :
-			GetIndustryConstructionStage(ti->tile))];
-
-	image = dits->ground;
-	if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0)
-		image |= ormod;
-
-	z = ti->z;
-	/* Add bricks below the industry? */
-	if (ti->tileh != SLOPE_FLAT) {
-		AddSortableSpriteToDraw(SPR_FOUNDATION_BASE + ti->tileh, ti->x, ti->y, 16, 16, 7, z);
-		AddChildSpriteScreen(image, 31, 1);
-		z += TILE_HEIGHT;
-	} else {
-		/* Else draw regular ground */
-		DrawGroundSprite(image);
-	}
-
-	/* Add industry on top of the ground? */
-	image = dits->building;
-	if (image != 0) {
-		if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0)
-			image |= ormod;
-
-		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-		AddSortableSpriteToDraw(image,
-			ti->x + dits->subtile_x,
-			ti->y + dits->subtile_y,
-			dits->width  + 1,
-			dits->height + 1,
-			dits->dz,
-			z);
-
-		if (_display_opt & DO_TRANS_BUILDINGS) return;
-	}
-
-	{
-		int proc = dits->draw_proc - 1;
-		if (proc >= 0) _industry_draw_tile_procs[proc](ti);
-	}
-}
-
-static uint GetSlopeZ_Industry(TileIndex tile, uint x, uint y)
-{
-	return GetTileMaxZ(tile);
-}
-
-static Slope GetSlopeTileh_Industry(TileIndex tile, Slope tileh)
-{
-	return SLOPE_FLAT;
-}
-
-static void GetAcceptedCargo_Industry(TileIndex tile, AcceptedCargo ac)
-{
-	IndustryGfx gfx = GetIndustryGfx(tile);
-	CargoID a;
-
-	a = _industry_section_accepts_1[gfx];
-	if (a != CT_INVALID) ac[a] = (a == 0) ? 1 : 8;
-
-	a = _industry_section_accepts_2[gfx];
-	if (a != CT_INVALID) ac[a] = 8;
-
-	a = _industry_section_accepts_3[gfx];
-	if (a != CT_INVALID) ac[a] = 8;
-}
-
-static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
-{
-	const Industry *i = GetIndustryByTile(tile);
-
-	td->owner = i->owner;
-	td->str = GetIndustrySpec(i->type)->name;
-	if (!IsIndustryCompleted(tile)) {
-		SetDParamX(td->dparam, 0, td->str);
-		td->str = STR_2058_UNDER_CONSTRUCTION;
-	}
-}
-
-static int32 ClearTile_Industry(TileIndex tile, byte flags)
-{
-	Industry *i = GetIndustryByTile(tile);
-
-	/* water can destroy industries
-	 * in editor you can bulldoze industries
-	 * with magic_bulldozer cheat you can destroy industries
-	 * (area around OILRIG is water, so water shouldn't flood it
-	 */
-	if ((_current_player != OWNER_WATER && _game_mode != GM_EDITOR &&
-			!_cheats.magic_bulldozer.value) ||
-			(_current_player == OWNER_WATER && i->type == IT_OIL_RIG)) {
-		SetDParam(0, GetIndustrySpec(i->type)->name);
-		return_cmd_error(STR_4800_IN_THE_WAY);
-	}
-
-	if (flags & DC_EXEC) DeleteIndustry(i);
-	return 0;
-}
-
-static void TransportIndustryGoods(TileIndex tile)
-{
-	Industry *i = GetIndustryByTile(tile);
-	const IndustrySpec *indspec = GetIndustrySpec(i->type);
-	uint cw, am;
-
-	cw = min(i->cargo_waiting[0], 255);
-	if (cw > indspec->minimal_cargo/* && i->produced_cargo[0] != 0xFF*/) {
-		i->cargo_waiting[0] -= cw;
-
-		/* fluctuating economy? */
-		if (_economy.fluct <= 0) cw = (cw + 1) / 2;
-
-		i->last_mo_production[0] += cw;
-
-		am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[0], cw);
-		i->last_mo_transported[0] += am;
-		if (am != 0) {
-			uint newgfx = _industry_produce_section[GetIndustryGfx(tile)];
-
-			if (newgfx != 0xFF) {
-				ResetIndustryConstructionStage(tile);
-				SetIndustryCompleted(tile, true);
-				SetIndustryGfx(tile, newgfx);
-				MarkTileDirtyByTile(tile);
-			}
-		}
-	}
-
-	cw = min(i->cargo_waiting[1], 255);
-	if (cw > indspec->minimal_cargo) {
-		i->cargo_waiting[1] -= cw;
-
-		if (_economy.fluct <= 0) cw = (cw + 1) / 2;
-
-		i->last_mo_production[1] += cw;
-
-		am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[1], cw);
-		i->last_mo_transported[1] += am;
-	}
-}
-
-
-static void AnimateTile_Industry(TileIndex tile)
-{
-	byte m;
-
-	switch (GetIndustryGfx(tile)) {
-	case GFX_SUGAR_MINE_SIEVE:
-		if ((_tick_counter & 1) == 0) {
-			m = GetIndustryAnimationState(tile) + 1;
-
-			switch (m & 7) {
-			case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
-			case 6: SndPlayTileFx(SND_29_RIP, tile); break;
-			}
-
-			if (m >= 96) {
-				m = 0;
-				DeleteAnimatedTile(tile);
-			}
-			SetIndustryAnimationState(tile, m);
-
-			MarkTileDirtyByTile(tile);
-		}
-		break;
-
-	case GFX_TOFFEE_QUARY:
-		if ((_tick_counter & 3) == 0) {
-			m = GetIndustryAnimationState(tile);
-
-			if (_industry_anim_offs[m] == 0xFF) {
-				SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
-			}
-
-			if (++m >= 70) {
-				m = 0;
-				DeleteAnimatedTile(tile);
-			}
-			SetIndustryAnimationState(tile, m);
-
-			MarkTileDirtyByTile(tile);
-		}
-		break;
-
-	case GFX_BUBBLE_CATCHER:
-		if ((_tick_counter & 1) == 0) {
-			m = GetIndustryAnimationState(tile);
-
-			if (++m >= 40) {
-				m = 0;
-				DeleteAnimatedTile(tile);
-			}
-			SetIndustryAnimationState(tile, m);
-
-			MarkTileDirtyByTile(tile);
-		}
-		break;
-
-	// Sparks on a coal plant
-	case GFX_POWERPLANT_SPARKS:
-		if ((_tick_counter & 3) == 0) {
-			m = GetIndustryAnimationState(tile);
-			if (m == 6) {
-				SetIndustryAnimationState(tile, 0);
-				DeleteAnimatedTile(tile);
-			} else {
-				SetIndustryAnimationState(tile, m + 1);
-				MarkTileDirtyByTile(tile);
-			}
-		}
-		break;
-
-	case GFX_TOY_FACTORY:
-		if ((_tick_counter & 1) == 0) {
-			m = GetIndustryAnimationState(tile) + 1;
-
-			if (m == 1) {
-				SndPlayTileFx(SND_2C_MACHINERY, tile);
-			} else if (m == 23) {
-				SndPlayTileFx(SND_2B_COMEDY_HIT, tile);
-			} else if (m == 28) {
-				SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile);
-			}
-
-			if (m >= 50) {
-				int n = GetIndustryAnimationLoop(tile) + 1;
-				m = 0;
-				if (n >= 8) {
-					n = 0;
-					DeleteAnimatedTile(tile);
-				}
-				SetIndustryAnimationLoop(tile, n);
-			}
-			SetIndustryAnimationState(tile, m);
-			MarkTileDirtyByTile(tile);
-		}
-		break;
-
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
-		if ((_tick_counter & 3) == 0) {
-			IndustryGfx gfx = GetIndustryGfx(tile);
-
-			gfx = (gfx < 155) ? gfx + 1 : 148;
-			SetIndustryGfx(tile, gfx);
-			MarkTileDirtyByTile(tile);
-		}
-		break;
-
-	case GFX_OILWELL_ANIMATED_1:
-	case GFX_OILWELL_ANIMATED_2:
-	case GFX_OILWELL_ANIMATED_3:
-		if ((_tick_counter & 7) == 0) {
-			bool b = CHANCE16(1,7);
-			IndustryGfx gfx = GetIndustryGfx(tile);
-
-			m = GetIndustryAnimationState(tile) + 1;
-			if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
-				SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
-				SetIndustryConstructionStage(tile, 3);
-				DeleteAnimatedTile(tile);
-			} else {
-				SetIndustryAnimationState(tile, m);
-				SetIndustryGfx(tile, gfx);
-				MarkTileDirtyByTile(tile);
-			}
-		}
-		break;
-
-	case GFX_COAL_MINE_TOWER_ANIMATED:
-	case GFX_COPPER_MINE_TOWER_ANIMATED:
-	case GFX_GOLD_MINE_TOWER_ANIMATED: {
-			int state = _tick_counter & 0x7FF;
-
-			if ((state -= 0x400) < 0)
-				return;
-
-			if (state < 0x1A0) {
-				if (state < 0x20 || state >= 0x180) {
-					m = GetIndustryAnimationState(tile);
-					if (!(m & 0x40)) {
-						SetIndustryAnimationState(tile, m | 0x40);
-						SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
-					}
-					if (state & 7)
-						return;
-				} else {
-					if (state & 3)
-						return;
-				}
-				m = (GetIndustryAnimationState(tile) + 1) | 0x40;
-				if (m > 0xC2) m = 0xC0;
-				SetIndustryAnimationState(tile, m);
-				MarkTileDirtyByTile(tile);
-			} else if (state >= 0x200 && state < 0x3A0) {
-				int i;
-				i = (state < 0x220 || state >= 0x380) ? 7 : 3;
-				if (state & i)
-					return;
-
-				m = (GetIndustryAnimationState(tile) & 0xBF) - 1;
-				if (m < 0x80) m = 0x82;
-				SetIndustryAnimationState(tile, m);
-				MarkTileDirtyByTile(tile);
-			}
-		} break;
-	}
-}
-
-static void CreateIndustryEffectSmoke(TileIndex tile)
-{
-	uint x = TileX(tile) * TILE_SIZE;
-	uint y = TileY(tile) * TILE_SIZE;
-	uint z = GetTileMaxZ(tile);
-
-	CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
-}
-
-static void MakeIndustryTileBigger(TileIndex tile)
-{
-	byte cnt = GetIndustryConstructionCounter(tile) + 1;
-	byte stage;
-
-	if (cnt != 4) {
-		SetIndustryConstructionCounter(tile, cnt);
-		return;
-	}
-
-	stage = GetIndustryConstructionStage(tile) + 1;
-	SetIndustryConstructionCounter(tile, 0);
-	SetIndustryConstructionStage(tile, stage);
-	if (stage == 3) {
-		SetIndustryCompleted(tile, true);
-	}
-
-	MarkTileDirtyByTile(tile);
-
-	if (!IsIndustryCompleted(tile)) return;
-
-	switch (GetIndustryGfx(tile)) {
-	case GFX_POWERPLANT_CHIMNEY:
-		CreateIndustryEffectSmoke(tile);
-		break;
-
-	case GFX_OILRIG_1:
-		if (GetIndustryGfx(tile + TileDiffXY(0, 1)) == GFX_OILRIG_1) BuildOilRig(tile);
-		break;
-
-	case GFX_TOY_FACTORY:
-	case GFX_BUBBLE_CATCHER:
-	case GFX_TOFFEE_QUARY:
-		SetIndustryAnimationState(tile, 0);
-		SetIndustryAnimationLoop(tile, 0);
-		break;
-
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
-	case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
-		AddAnimatedTile(tile);
-		break;
-	}
-}
-
-
-static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
-{
-	int dir;
-	Vehicle *v;
-	static const int8 _tileloop_ind_case_161[12] = {
-		11,   0, -4, -14,
-		-4, -10, -4,   1,
-		49,  59, 60,  65,
-	};
-
-	SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
-
-	dir = Random() & 3;
-
-	v = CreateEffectVehicleAbove(
-		TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0],
-		TileY(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 4],
-		_tileloop_ind_case_161[dir + 8],
-		EV_BUBBLE
-	);
-
-	if (v != NULL) v->u.special.unk2 = dir;
-}
-
-static void TileLoop_Industry(TileIndex tile)
-{
-	IndustryGfx newgfx;
-	IndustryGfx gfx;
-
-	if (!IsIndustryCompleted(tile)) {
-		MakeIndustryTileBigger(tile);
-		return;
-	}
-
-	if (_game_mode == GM_EDITOR) return;
-
-	TransportIndustryGoods(tile);
-
-	newgfx = _industry_section_animation_next[GetIndustryGfx(tile)];
-	if (newgfx != 255) {
-		ResetIndustryConstructionStage(tile);
-		SetIndustryGfx(tile, newgfx);
-		MarkTileDirtyByTile(tile);
-		return;
-	}
-
-	gfx = GetIndustryGfx(tile);
-
-	switch (gfx) {
-	case GFX_OILRIG_1: // coast line at oilrigs
-	case GFX_OILRIG_2:
-	case GFX_OILRIG_3:
-	case GFX_OILRIG_4:
-	case GFX_OILRIG_5:
-		TileLoop_Water(tile);
-		break;
-
-	case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
-	case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
-	case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
-		if (!(_tick_counter & 0x400) && CHANCE16(1, 2)) {
-			switch (gfx) {
-				case GFX_COAL_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_ANIMATED;   break;
-				case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
-				case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_ANIMATED;   break;
-			}
-			SetIndustryGfx(tile, gfx);
-			SetIndustryAnimationState(tile, 0x80);
-			AddAnimatedTile(tile);
-		}
-		break;
-
-	case GFX_OILWELL_NOT_ANIMATED:
-		if (CHANCE16(1, 6)) {
-			SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
-			SetIndustryAnimationState(tile, 0);
-			AddAnimatedTile(tile);
-		}
-		break;
-
-	case GFX_COAL_MINE_TOWER_ANIMATED:
-	case GFX_COPPER_MINE_TOWER_ANIMATED:
-	case GFX_GOLD_MINE_TOWER_ANIMATED:
-		if (!(_tick_counter & 0x400)) {
-			switch (gfx) {
-				case GFX_COAL_MINE_TOWER_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED;   break;
-				case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
-				case GFX_GOLD_MINE_TOWER_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED;   break;
-			}
-			SetIndustryGfx(tile, gfx);
-			SetIndustryCompleted(tile, true);
-			SetIndustryConstructionStage(tile, 3);
-			DeleteAnimatedTile(tile);
-		}
-		break;
-
-	case GFX_POWERPLANT_SPARKS:
-		if (CHANCE16(1,3)) {
-			SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
-			AddAnimatedTile(tile);
-		}
-		break;
-
-	case GFX_COPPER_MINE_CHIMNEY:
-		CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_SMOKE);
-		break;
-
-
-	case GFX_TOY_FACTORY: {
-			Industry *i = GetIndustryByTile(tile);
-			if (i->was_cargo_delivered) {
-				i->was_cargo_delivered = false;
-				SetIndustryAnimationLoop(tile, 0);
-				AddAnimatedTile(tile);
-			}
-		}
-		break;
-
-	case GFX_BUBBLE_GENERATOR:
-		TileLoopIndustry_BubbleGenerator(tile);
-		break;
-
-	case GFX_TOFFEE_QUARY:
-		AddAnimatedTile(tile);
-		break;
-
-	case GFX_SUGAR_MINE_SIEVE:
-		if (CHANCE16(1, 3)) AddAnimatedTile(tile);
-		break;
-	}
-}
-
-
-static void ClickTile_Industry(TileIndex tile)
-{
-	ShowIndustryViewWindow(GetIndustryIndex(tile));
-}
-
-static uint32 GetTileTrackStatus_Industry(TileIndex tile, TransportType mode)
-{
-	return 0;
-}
-
-static void GetProducedCargo_Industry(TileIndex tile, CargoID *b)
-{
-	const Industry *i = GetIndustryByTile(tile);
-
-	b[0] = i->produced_cargo[0];
-	b[1] = i->produced_cargo[1];
-}
-
-static void ChangeTileOwner_Industry(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	/* not used */
-}
-
-static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
-
-static bool IsBadFarmFieldTile(TileIndex tile)
-{
-	switch (GetTileType(tile)) {
-		case MP_CLEAR: return IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_SNOW);
-		case MP_TREES: return false;
-		default:       return true;
-	}
-}
-
-static bool IsBadFarmFieldTile2(TileIndex tile)
-{
-	switch (GetTileType(tile)) {
-		case MP_CLEAR: return IsClearGround(tile, CLEAR_SNOW);
-		case MP_TREES: return false;
-		default:       return true;
-	}
-}
-
-static void SetupFarmFieldFence(TileIndex tile, int size, byte type, Axis direction)
-{
-	do {
-		tile = TILE_MASK(tile);
-
-		if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
-			byte or = type;
-
-			if (or == 1 && CHANCE16(1, 7)) or = 2;
-
-			if (direction == AXIS_X) {
-				SetFenceSE(tile, or);
-			} else {
-				SetFenceSW(tile, or);
-			}
-		}
-
-		tile += (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
-	} while (--size);
-}
-
-static void PlantFarmField(TileIndex tile, IndustryID industry)
-{
-	uint size_x, size_y;
-	uint32 r;
-	uint count;
-	uint counter;
-	uint field_type;
-	int type;
-
-	if (_opt.landscape == LT_HILLY) {
-		if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line)
-			return;
-	}
-
-	/* determine field size */
-	r = (Random() & 0x303) + 0x404;
-	if (_opt.landscape == LT_HILLY) r += 0x404;
-	size_x = GB(r, 0, 8);
-	size_y = GB(r, 8, 8);
-
-	/* offset tile to match size */
-	tile -= TileDiffXY(size_x / 2, size_y / 2);
-
-	/* check the amount of bad tiles */
-	count = 0;
-	BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
-		cur_tile = TILE_MASK(cur_tile);
-		count += IsBadFarmFieldTile(cur_tile);
-	END_TILE_LOOP(cur_tile, size_x, size_y, tile)
-	if (count * 2 >= size_x * size_y) return;
-
-	/* determine type of field */
-	r = Random();
-	counter = GB(r, 5, 3);
-	field_type = GB(r, 8, 8) * 9 >> 8;
-
-	/* make field */
-	BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
-		cur_tile = TILE_MASK(cur_tile);
-		if (!IsBadFarmFieldTile2(cur_tile)) {
-			MakeField(cur_tile, field_type, industry);
-			SetClearCounter(cur_tile, counter);
-			MarkTileDirtyByTile(cur_tile);
-		}
-	END_TILE_LOOP(cur_tile, size_x, size_y, tile)
-
-	type = 3;
-	if (_opt.landscape != LT_HILLY && _opt.landscape != LT_DESERT) {
-		type = _plantfarmfield_type[Random() & 0xF];
-	}
-
-	SetupFarmFieldFence(tile - TileDiffXY(1, 0), size_y, type, AXIS_Y);
-	SetupFarmFieldFence(tile - TileDiffXY(0, 1), size_x, type, AXIS_X);
-	SetupFarmFieldFence(tile + TileDiffXY(size_x - 1, 0), size_y, type, AXIS_Y);
-	SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, AXIS_X);
-}
-
-void PlantRandomFarmField(const Industry *i)
-{
-	int x = i->width  / 2 + Random() % 31 - 16;
-	int y = i->height / 2 + Random() % 31 - 16;
-
-	TileIndex tile = TileAddWrap(i->xy, x, y);
-
-	if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
-}
-
-static void MaybePlantFarmField(const Industry *i)
-{
-	if (CHANCE16(1, 8)) PlantRandomFarmField(i);
-}
-
-/**
- * Search callback function for ChopLumberMillTrees
- * @param tile to test
- * @param data that is passed by the caller.  In this case, nothing
- * @result of the test
- */
-static bool SearchLumberMillTrees(TileIndex tile, uint32 data)
-{
-	if (IsTileType(tile, MP_TREES)) {
-		PlayerID old_player = _current_player;
-		/* found a tree */
-
-		_current_player = OWNER_NONE;
-		_industry_sound_ctr = 1;
-		_industry_sound_tile = tile;
-		SndPlayTileFx(SND_38_CHAINSAW, tile);
-
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-		SetTropicZone(tile, TROPICZONE_INVALID);
-
-		_current_player = old_player;
-		return true;
-	}
-	return false;
-}
-
-/**
- * Perform a circular search around the Lumber Mill in order to find trees to cut
- * @param i industry
- */
-static void ChopLumberMillTrees(Industry *i)
-{
-	TileIndex tile = i->xy;
-
-	if (!IsIndustryCompleted(tile)) return;  ///< Can't proceed if not completed
-
-	if (CircularTileSearch(tile, 40, SearchLumberMillTrees, 0)) ///< 40x40 tiles  to search
-		i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + 45); ///< Found a tree, add according value to waiting cargo
-}
-
-static const byte _industry_sounds[37][2] = {
-	{0},
-	{0},
-	{1, SND_28_SAWMILL},
-	{0},
-	{0},
-	{0},
-	{1, SND_03_FACTORY_WHISTLE},
-	{1, SND_03_FACTORY_WHISTLE},
-	{0},
-	{3, SND_24_SHEEP},
-	{0},
-	{0},
-	{0},
-	{0},
-	{1, SND_28_SAWMILL},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{1, SND_03_FACTORY_WHISTLE},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{0},
-	{1, SND_33_PLASTIC_MINE},
-	{0},
-	{0},
-	{0},
-	{0},
-};
-
-
-static void ProduceIndustryGoods(Industry *i)
-{
-	uint32 r;
-	uint num;
-
-	/* play a sound? */
-	if ((i->counter & 0x3F) == 0) {
-		if (CHANCE16R(1,14,r) && (num=_industry_sounds[i->type][0]) != 0) {
-			SndPlayTileFx(
-				_industry_sounds[i->type][1] + (((r >> 16) * num) >> 16),
-				i->xy);
-		}
-	}
-
-	i->counter--;
-
-	/* produce some cargo */
-	if ((i->counter & 0xFF) == 0) {
-		i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + i->production_rate[0]);
-		i->cargo_waiting[1] = min(0xffff, i->cargo_waiting[1] + i->production_rate[1]);
-
-		if (i->type == IT_FARM) {
-			MaybePlantFarmField(i);
-		} else if (i->type == IT_LUMBER_MILL && (i->counter & 0x1FF) == 0) {
-			ChopLumberMillTrees(i);
-		}
-	}
-}
-
-void OnTick_Industry(void)
-{
-	Industry *i;
-
-	if (_industry_sound_ctr != 0) {
-		_industry_sound_ctr++;
-
-		if (_industry_sound_ctr == 75) {
-			SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
-		} else if (_industry_sound_ctr == 160) {
-			_industry_sound_ctr = 0;
-			SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
-		}
-	}
-
-	if (_game_mode == GM_EDITOR) return;
-
-	FOR_ALL_INDUSTRIES(i) {
-		ProduceIndustryGoods(i);
-	}
-}
-
-
-static bool CheckNewIndustry_NULL(TileIndex tile)
-{
-	return true;
-}
-
-static bool CheckNewIndustry_Forest(TileIndex tile)
-{
-	if (_opt.landscape == LT_HILLY) {
-		if (GetTileZ(tile) < _opt.snow_line + TILE_HEIGHT * 2U) {
-			_error_message = STR_4831_FOREST_CAN_ONLY_BE_PLANTED;
-			return false;
-		}
-	}
-	return true;
-}
-
-static bool CheckNewIndustry_OilRefinery(TileIndex tile)
-{
-	if (_game_mode == GM_EDITOR) return true;
-	if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
-
-	_error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
-	return false;
-}
-
-extern bool _ignore_restrictions;
-
-static bool CheckNewIndustry_OilRig(TileIndex tile)
-{
-	if (_game_mode == GM_EDITOR && _ignore_restrictions) return true;
-	if (TileHeight(tile) == 0 &&
-			DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
-
-	_error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
-	return false;
-}
-
-static bool CheckNewIndustry_Farm(TileIndex tile)
-{
-	if (_opt.landscape == LT_HILLY) {
-		if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line) {
-			_error_message = STR_0239_SITE_UNSUITABLE;
-			return false;
-		}
-	}
-	return true;
-}
-
-static bool CheckNewIndustry_Plantation(TileIndex tile)
-{
-	if (GetTropicZone(tile) == TROPICZONE_DESERT) {
-		_error_message = STR_0239_SITE_UNSUITABLE;
-		return false;
-	}
-
-	return true;
-}
-
-static bool CheckNewIndustry_Water(TileIndex tile)
-{
-	if (GetTropicZone(tile) != TROPICZONE_DESERT) {
-		_error_message = STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT;
-		return false;
-	}
-
-	return true;
-}
-
-static bool CheckNewIndustry_Lumbermill(TileIndex tile)
-{
-	if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
-		_error_message = STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST;
-		return false;
-	}
-	return true;
-}
-
-static bool CheckNewIndustry_BubbleGen(TileIndex tile)
-{
-	return GetTileZ(tile) <= TILE_HEIGHT * 4;
-}
-
-typedef bool CheckNewIndustryProc(TileIndex tile);
-static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
-	CheckNewIndustry_NULL,
-	CheckNewIndustry_Forest,
-	CheckNewIndustry_OilRefinery,
-	CheckNewIndustry_Farm,
-	CheckNewIndustry_Plantation,
-	CheckNewIndustry_Water,
-	CheckNewIndustry_Lumbermill,
-	CheckNewIndustry_BubbleGen,
-	CheckNewIndustry_OilRig
-};
-
-static bool CheckSuitableIndustryPos(TileIndex tile)
-{
-	uint x = TileX(tile);
-	uint y = TileY(tile);
-
-	if (x < 2 || y < 2 || x > MapMaxX() - 3 || y > MapMaxY() - 3) {
-		_error_message = STR_0239_SITE_UNSUITABLE;
-		return false;
-	}
-
-	return true;
-}
-
-static const Town *CheckMultipleIndustryInTown(TileIndex tile, int type)
-{
-	const Town *t;
-	const Industry *i;
-
-	t = ClosestTownFromTile(tile, (uint)-1);
-
-	if (_patches.multiple_industry_per_town) return t;
-
-	FOR_ALL_INDUSTRIES(i) {
-		if (i->type == (byte)type &&
-				i->town == t) {
-			_error_message = STR_0287_ONLY_ONE_ALLOWED_PER_TOWN;
-			return NULL;
-		}
-	}
-
-	return t;
-}
-
-static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, int type)
-{
-	_error_message = STR_0239_SITE_UNSUITABLE;
-
-	do {
-		TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
-
-		if (!IsValidTile(cur_tile)) {
-			if (it->gfx == 0xff) continue;
-			return false;
-		}
-
-		if (it->gfx == 0xFF) {
-			if (!IsTileType(cur_tile, MP_WATER) ||
-					GetTileSlope(cur_tile, NULL) != SLOPE_FLAT) {
-				return false;
-			}
-		} else {
-			if (!EnsureNoVehicle(cur_tile)) return false;
-
-			if (type == IT_OIL_RIG)  {
-				if (!IsClearWaterTile(cur_tile)) return false;
-			} else {
-				Slope tileh;
-
-				if (IsClearWaterTile(cur_tile)) return false;
-
-				tileh = GetTileSlope(cur_tile, NULL);
-				if (IsSteepSlope(tileh)) return false;
-
-				if (_patches.land_generator != LG_TERRAGENESIS || !_generating_world) {
-					/* It is almost impossible to have a fully flat land in TG, so what we
-					 *  do is that we check if we can make the land flat later on. See
-					 *  CheckIfCanLevelIndustryPlatform(). */
-					if (tileh != SLOPE_FLAT) {
-						Slope t;
-						byte bits = _industry_section_bits[it->gfx];
-
-						if (bits & 0x10) return false;
-
-						t = ComplementSlope(tileh);
-
-						if (bits & 1 && (t & SLOPE_NW)) return false;
-						if (bits & 2 && (t & SLOPE_NE)) return false;
-						if (bits & 4 && (t & SLOPE_SW)) return false;
-						if (bits & 8 && (t & SLOPE_SE)) return false;
-					}
-				}
-
-				if (type == IT_BANK_TEMP) {
-					if (!IsTileType(cur_tile, MP_HOUSE)) {
-						_error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS;
-						return false;
-					}
-				} else if (type == IT_BANK_TROPIC_ARCTIC) {
-					if (!IsTileType(cur_tile, MP_HOUSE)) {
-						_error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS;
-						return false;
-					}
-				} else if (type == IT_TOY_SHOP) {
-					if (!IsTileType(cur_tile, MP_HOUSE)) goto do_clear;
-				} else if (type == IT_WATER_TOWER) {
-					if (!IsTileType(cur_tile, MP_HOUSE)) {
-						_error_message = STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS;
-						return false;
-					}
-				} else {
-do_clear:
-					if (CmdFailed(DoCommand(cur_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
-						return false;
-				}
-			}
-		}
-	} while ((++it)->ti.x != -0x80);
-
-	return true;
-}
-
-static bool CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
-{
-	if (type == IT_BANK_TEMP && t->population < 1200) {
-		_error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS;
-		return false;
-	}
-
-	if (type == IT_TOY_SHOP && DistanceMax(t->xy, tile) > 9) {
-		_error_message = STR_0239_SITE_UNSUITABLE;
-		return false;
-	}
-
-	return true;
-}
-
-static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
-{
-	int size_x, size_y;
-	uint curh;
-
-	size_x = 2;
-	size_y = 2;
-
-	/* Check if we don't leave the map */
-	if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
-
-	tile += TileDiffXY(-1, -1);
-	BEGIN_TILE_LOOP(tile_walk, size_x, size_y, tile) {
-		curh = TileHeight(tile_walk);
-		/* Is the tile clear? */
-		if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES))
-			return false;
-
-		/* Don't allow too big of a change if this is the sub-tile check */
-		if (internal != 0 && myabs(curh - height) > 1) return false;
-
-		/* Different height, so the surrounding tiles of this tile
-		 *  has to be correct too (in level, or almost in level)
-		 *  else you get a chain-reaction of terraforming. */
-		if (internal == 0 && curh != height) {
-			if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1))
-				return false;
-		}
-	} END_TILE_LOOP(tile_walk, size_x, size_y, tile);
-
-	return true;
-}
-
-/**
- * This function tries to flatten out the land below an industry, without
- *  damaging the surroundings too much.
- */
-static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, uint32 flags, const IndustryTileTable* it, int type)
-{
-	const int MKEND = -0x80;   // used for last element in an IndustryTileTable (see build_industry.h)
-	int max_x = 0;
-	int max_y = 0;
-	TileIndex cur_tile;
-	uint size_x, size_y;
-	uint h, curh;
-
-	/* Finds dimensions of largest variant of this industry */
-	do {
-		if (it->ti.x > max_x) max_x = it->ti.x;
-		if (it->ti.y > max_y) max_y = it->ti.y;
-	} while ((++it)->ti.x != MKEND);
-
-	/* Remember level height */
-	h = TileHeight(tile);
-
-	/* Check that all tiles in area and surrounding are clear
-	 * this determines that there are no obstructing items */
-	cur_tile = tile + TileDiffXY(-1, -1);
-	size_x = max_x + 4;
-	size_y = max_y + 4;
-
-	/* Check if we don't leave the map */
-	if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
-
-	BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
-		curh = TileHeight(tile_walk);
-		if (curh != h) {
-			/* This tile needs terraforming. Check if we can do that without
-			 *  damaging the surroundings too much. */
-			if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) return false;
-			/* This is not 100% correct check, but the best we can do without modifying the map.
-			 *  What is missing, is if the difference in height is more than 1.. */
-			if (CmdFailed(DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND))) return false;
-		}
-	} END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
-
-	if (flags & DC_EXEC) {
-		/* Terraform the land under the industry */
-		BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
-			curh = TileHeight(tile_walk);
-			while (curh != h) {
-				/* We give the terraforming for free here, because we can't calculate
-				 *  exact cost in the test-round, and as we all know, that will cause
-				 *  a nice assert if they don't match ;) */
-				DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
-				curh += (curh > h) ? -1 : 1;
-			}
-		} END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
-	}
-
-	return true;
-}
-
-
-static bool CheckIfTooCloseToIndustry(TileIndex tile, int type)
-{
-	const IndustrySpec *indspec = GetIndustrySpec(type);
-	const Industry *i;
-
-	// accepting industries won't be close, not even with patch
-	if (_patches.same_industry_close && indspec->accepts_cargo[0] == CT_INVALID)
-		return true;
-
-	FOR_ALL_INDUSTRIES(i) {
-		// check if an industry that accepts the same goods is nearby
-		if (DistanceMax(tile, i->xy) <= 14 &&
-				indspec->accepts_cargo[0] != CT_INVALID &&
-				indspec->accepts_cargo[0] == i->accepts_cargo[0] && (
-					_game_mode != GM_EDITOR ||
-					!_patches.same_industry_close ||
-					!_patches.multiple_industry_per_town
-				)) {
-			_error_message = STR_INDUSTRY_TOO_CLOSE;
-			return false;
-		}
-
-		// check "not close to" field.
-		if ((i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) &&
-				DistanceMax(tile, i->xy) <= 14) {
-			_error_message = STR_INDUSTRY_TOO_CLOSE;
-			return false;
-		}
-	}
-	return true;
-}
-
-static Industry *AllocateIndustry(void)
-{
-	Industry *i;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (i = GetIndustry(0); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) {
-		IndustryID index = i->index;
-
-		if (IsValidIndustry(i)) continue;
-
-		memset(i, 0, sizeof(*i));
-		i->index = index;
-
-		return i;
-	}
-
-	/* Check if we can add a block to the pool */
-	return AddBlockToPool(&_Industry_pool) ? AllocateIndustry() : NULL;
-}
-
-static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, const Town *t, byte owner)
-{
-	const IndustrySpec *indspec = GetIndustrySpec(type);
-	uint32 r;
-	int j;
-
-	_total_industries++;
-	i->xy = tile;
-	i->width = i->height = 0;
-	i->type = type;
-
-	i->produced_cargo[0] = indspec->produced_cargo[0];
-	i->produced_cargo[1] = indspec->produced_cargo[1];
-	i->accepts_cargo[0] = indspec->accepts_cargo[0];
-	i->accepts_cargo[1] = indspec->accepts_cargo[1];
-	i->accepts_cargo[2] = indspec->accepts_cargo[2];
-	i->production_rate[0] = indspec->production_rate[0];
-	i->production_rate[1] = indspec->production_rate[1];
-
-	if (_patches.smooth_economy) {
-		i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8 , 255);
-		i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8 , 255);
-	}
-
-	i->town = t;
-	i->owner = owner;
-
-	r = Random();
-	i->random_color = GB(r, 8, 4);
-	i->counter = GB(r, 0, 12);
-	i->cargo_waiting[0] = 0;
-	i->cargo_waiting[1] = 0;
-	i->last_mo_production[0] = 0;
-	i->last_mo_production[1] = 0;
-	i->last_mo_transported[0] = 0;
-	i->last_mo_transported[1] = 0;
-	i->pct_transported[0] = 0;
-	i->pct_transported[1] = 0;
-	i->total_transported[0] = 0;
-	i->total_transported[1] = 0;
-	i->was_cargo_delivered = false;
-	i->last_prod_year = _cur_year;
-	i->total_production[0] = i->production_rate[0] * 8;
-	i->total_production[1] = i->production_rate[1] * 8;
-
-	if (!_generating_world) i->total_production[0] = i->total_production[1] = 0;
-
-	i->prod_level = 0x10;
-
-	do {
-		TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
-
-		if (it->gfx != 0xFF) {
-			byte size;
-
-			size = it->ti.x;
-			if (size > i->width) i->width = size;
-			size = it->ti.y;
-			if (size > i->height)i->height = size;
-
-			DoCommand(cur_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-
-			MakeIndustry(cur_tile, i->index, it->gfx);
-			if (_generating_world) {
-				SetIndustryConstructionCounter(cur_tile, 3);
-				SetIndustryConstructionStage(cur_tile, 2);
-			}
-		}
-	} while ((++it)->ti.x != -0x80);
-
-	i->width++;
-	i->height++;
-
-	if (i->type == IT_FARM || i->type == IT_FARM_2) {
-		for (j = 0; j != 50; j++) PlantRandomFarmField(i);
-	}
-	_industry_sort_dirty = true;
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
-}
-
-static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, const IndustryTileTable *it)
-{
-	const Town *t;
-	Industry *i;
-
-	if (!CheckIfIndustryTilesAreFree(tile, it, type)) return NULL;
-	if (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL;
-	if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL;
-	if (!CheckIfTooCloseToIndustry(tile, type)) return NULL;
-
-	t = CheckMultipleIndustryInTown(tile, type);
-	if (t == NULL) return NULL;
-
-	if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL;
-	if (!CheckSuitableIndustryPos(tile)) return NULL;
-
-	i = AllocateIndustry();
-	if (i == NULL) return NULL;
-
-	if (flags & DC_EXEC) {
-		CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type);
-		DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE);
-	}
-
-	return i;
-}
-
-/** Build/Fund an industry
- * @param tile tile where industry is built
- * @param p1 industry type @see build_industry.h and @see industry.h
- * @param p2 unused
- */
-int32 CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int num;
-	const IndustryTileTable * const *itt;
-	const IndustryTileTable *it;
-	const IndustrySpec *indspec;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-
-	indspec = GetIndustrySpec(p1);
-
-	/* Check if the to-be built/founded industry is available for this climate. */
-	if (!HASBIT(indspec->climate_availability, _opt_ptr->landscape)) return CMD_ERROR;
-
-	/* If the patch for raw-material industries is not on, you cannot build raw-material industries.
-	 * Raw material industries are industries that do not accept cargo (at least for now)
-	 * Exclude the lumber mill (only "raw" industry that can be built) */
-	if (!_patches.build_rawmaterial_ind &&
-			indspec->accepts_cargo[0] == CT_INVALID &&
-			indspec->accepts_cargo[1] == CT_INVALID &&
-			indspec->accepts_cargo[2] == CT_INVALID &&
-			p1 != IT_LUMBER_MILL) {
-		return CMD_ERROR;
-	}
-
-	num = indspec->num_table;
-	itt = indspec->table;
-
-	do {
-		if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE);
-	} while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1));
-
-	if (CreateNewIndustryHelper(tile, p1, flags, indspec, it) == NULL) return CMD_ERROR;
-
-	return (_price.build_industry >> 5) * indspec->cost_multiplier;
-}
-
-
-Industry *CreateNewIndustry(TileIndex tile, IndustryType type)
-{
-	const IndustrySpec *indspec = GetIndustrySpec(type);
-	const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)];
-
-	return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, it);
-}
-
-static const byte _numof_industry_table[4][12] = {
-	// difficulty settings for number of industries
-	{0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0},   //none
-	{0, 1, 1, 1, 2, 2, 3, 3,  4,  4,  5},   //low
-	{0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10},   //normal
-	{0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10},   //high
-};
-
-static void PlaceInitialIndustry(IndustryType type, int amount)
-{
-	int num = _numof_industry_table[_opt.diff.number_industries][amount];
-
-	if (type == IT_OIL_REFINERY || type == IT_OIL_RIG) {
-		// These are always placed next to the coastline, so we scale by the perimeter instead.
-		num = ScaleByMapSize1D(num);
-	} else {
-		num = ScaleByMapSize(num);
-	}
-
-	if (_opt.diff.number_industries != 0) {
-		PlayerID old_player = _current_player;
-		_current_player = OWNER_NONE;
-		assert(num > 0);
-
-		do {
-			uint i;
-
-			IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
-
-			for (i = 0; i < 2000; i++) {
-				if (CreateNewIndustry(RandomTile(), type) != NULL) break;
-			}
-		} while (--num);
-
-		_current_player = old_player;
-	}
-}
-
-void GenerateIndustries(void)
-{
-	const byte *b;
-	uint i = 0;
-
-	/* Find the total amount of industries */
-	b = _industry_create_table[_opt.landscape];
-	do {
-		int num = _numof_industry_table[_opt.diff.number_industries][b[0]];
-
-		if (b[1] == IT_OIL_REFINERY || b[1] == IT_OIL_RIG) {
-			/* These are always placed next to the coastline, so we scale by the perimeter instead. */
-			num = ScaleByMapSize1D(num);
-		} else {
-			num = ScaleByMapSize(num);
-		}
-
-		i += num;
-	} while ( (b+=2)[0] != 0);
-	SetGeneratingWorldProgress(GWP_INDUSTRY, i);
-
-	b = _industry_create_table[_opt.landscape];
-	do {
-		PlaceInitialIndustry(b[1], b[0]);
-	} while ( (b+=2)[0] != 0);
-}
-
-/* Change industry production or do closure */
-static void ExtChangeIndustryProduction(Industry *i)
-{
-	bool closeit = true;
-	int j;
-	const IndustrySpec *indspec = GetIndustrySpec(i->type);
-
-	switch (indspec->life_type) {
-		case INDUSTRYLIFE_NOT_CLOSABLE:
-			return;
-
-		case INDUSTRYLIFE_CLOSABLE:
-			if ((byte)(_cur_year - i->last_prod_year) < 5 || !CHANCE16(1, 180))
-				closeit = false;
-			break;
-
-		default: /* INDUSTRY_PRODUCTION */
-			for (j = 0; j < 2 && i->produced_cargo[j] != CT_INVALID; j++){
-				uint32 r = Random();
-				int old, new, percent;
-				int mag;
-
-				new = old = i->production_rate[j];
-				if (CHANCE16I(20, 1024, r))
-					new -= ((RandomRange(50) + 10) * old) >> 8;
-				if (CHANCE16I(20 + (i->pct_transported[j] * 20 >> 8), 1024, r >> 16))
-					new += ((RandomRange(50) + 10) * old) >> 8;
-
-				new = clamp(new, 0, 255);
-				if (new == old) {
-					closeit = false;
-					continue;
-				}
-
-				percent = new * 100 / old - 100;
-				i->production_rate[j] = new;
-
-				if (new >= indspec->production_rate[j] / 4)
-					closeit = false;
-
-				mag = abs(percent);
-				if (mag >= 10) {
-					SetDParam(2, mag);
-					SetDParam(0, _cargoc.names_s[i->produced_cargo[j]]);
-					SetDParam(1, i->index);
-					AddNewsItem(
-						percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN,
-						NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0),
-						i->xy + TileDiffXY(1, 1), 0
-					);
-				}
-			}
-			break;
-	}
-
-	/* If industry will be closed down, show this */
-	if (closeit) {
-		i->prod_level = 0;
-		SetDParam(0, i->index);
-		AddNewsItem(
-			indspec->closure_text,
-			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0),
-			i->xy + TileDiffXY(1, 1), 0
-		);
-	}
-}
-
-
-static void UpdateIndustryStatistics(Industry *i)
-{
-	byte pct;
-
-	if (i->produced_cargo[0] != CT_INVALID) {
-		pct = 0;
-		if (i->last_mo_production[0] != 0) {
-			i->last_prod_year = _cur_year;
-			pct = min(i->last_mo_transported[0] * 256 / i->last_mo_production[0],255);
-		}
-		i->pct_transported[0] = pct;
-
-		i->total_production[0] = i->last_mo_production[0];
-		i->last_mo_production[0] = 0;
-
-		i->total_transported[0] = i->last_mo_transported[0];
-		i->last_mo_transported[0] = 0;
-	}
-
-	if (i->produced_cargo[1] != CT_INVALID) {
-		pct = 0;
-		if (i->last_mo_production[1] != 0) {
-			i->last_prod_year = _cur_year;
-			pct = min(i->last_mo_transported[1] * 256 / i->last_mo_production[1],255);
-		}
-		i->pct_transported[1] = pct;
-
-		i->total_production[1] = i->last_mo_production[1];
-		i->last_mo_production[1] = 0;
-
-		i->total_transported[1] = i->last_mo_transported[1];
-		i->last_mo_transported[1] = 0;
-	}
-
-
-	if (i->produced_cargo[0] != CT_INVALID || i->produced_cargo[1] != CT_INVALID)
-		InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
-
-	if (i->prod_level == 0) {
-		DeleteIndustry(i);
-	} else if (_patches.smooth_economy) {
-		ExtChangeIndustryProduction(i);
-	}
-}
-
-static const byte _new_industry_rand[4][32] = {
-	{12, 12, 12, 12, 12, 12, 12,  0,  0,  6,  6,  9,  9,  3,  3,  3, 18, 18,  4,  4,  2,  2,  5,  5,  5,  5,  5,  5,  1,  1,  8,  8},
-	{16, 16, 16,  0,  0,  0,  9,  9,  9,  9, 13, 13,  3,  3,  3,  3, 15, 15, 15,  4,  4, 11, 11, 11, 11, 11, 14, 14,  1,  1,  7,  7},
-	{21, 21, 21, 24, 22, 22, 22, 22, 23, 23, 16, 16, 16,  4,  4, 19, 19, 19, 13, 13, 20, 20, 20, 11, 11, 11, 17, 17, 17, 10, 10, 10},
-	{30, 30, 30, 36, 36, 31, 31, 31, 27, 27, 27, 28, 28, 28, 26, 26, 26, 34, 34, 34, 35, 35, 35, 29, 29, 29, 32, 32, 32, 33, 33, 33},
-};
-
-static void MaybeNewIndustry(uint32 r)
-{
-	int type;
-	int j;
-	Industry *i;
-
-	type = _new_industry_rand[_opt.landscape][GB(r, 16, 5)];
-
-	if (type == IT_OIL_WELL && _cur_year > 1950) return;
-	if (type == IT_OIL_RIG  && _cur_year < 1960) return;
-
-	j = 2000;
-	for (;;) {
-		i = CreateNewIndustry(RandomTile(), type);
-		if (i != NULL) break;
-		if (--j == 0) return;
-	}
-
-	SetDParam(0, GetIndustrySpec(type)->name);
-	SetDParam(1, i->town->index);
-	AddNewsItem(
-		(type != IT_FOREST && type != IT_FRUIT_PLANTATION && type != IT_RUBBER_PLANTATION && type != IT_COTTON_CANDY) ?
-			STR_482D_NEW_UNDER_CONSTRUCTION : STR_482E_NEW_BEING_PLANTED_NEAR,
-		NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY,0), i->xy, 0
-	);
-}
-
-static void ChangeIndustryProduction(Industry *i)
-{
-	bool only_decrease = false;
-	StringID str = STR_NULL;
-	int type = i->type;
-	const IndustrySpec *indspec = GetIndustrySpec(type);
-
-	switch (indspec->life_type) {
-		case INDUSTRYLIFE_NOT_CLOSABLE:
-			return;
-
-		case INDUSTRYLIFE_PRODUCTION:
-			/* decrease or increase */
-			if (type == IT_OIL_WELL && _opt.landscape == LT_NORMAL)
-				only_decrease = true;
-
-			if (only_decrease || CHANCE16(1,3)) {
-				/* If you transport > 60%, 66% chance we increase, else 33% chance we increase */
-				if (!only_decrease && (i->pct_transported[0] > 153) != CHANCE16(1,3)) {
-					/* Increase production */
-					if (i->prod_level != 0x80) {
-						byte b;
-
-						i->prod_level <<= 1;
-
-						b = i->production_rate[0] * 2;
-						if (i->production_rate[0] >= 128)
-							b = 0xFF;
-						i->production_rate[0] = b;
-
-						b = i->production_rate[1] * 2;
-						if (i->production_rate[1] >= 128)
-							b = 0xFF;
-						i->production_rate[1] = b;
-
-						str = indspec->production_up_text;
-					}
-				} else {
-					/* Decrease production */
-					if (i->prod_level == 4) {
-						i->prod_level = 0;
-						str = indspec->closure_text;
-					} else {
-						i->prod_level >>= 1;
-						i->production_rate[0] = (i->production_rate[0] + 1) >> 1;
-						i->production_rate[1] = (i->production_rate[1] + 1) >> 1;
-
-						str = indspec->production_down_text;
-					}
-				}
-			}
-			break;
-
-		case INDUSTRYLIFE_CLOSABLE:
-			/* maybe close */
-			if ( (byte)(_cur_year - i->last_prod_year) >= 5 && CHANCE16(1,2)) {
-				i->prod_level = 0;
-				str = indspec->closure_text;
-			}
-			break;
-	}
-
-	if (str != STR_NULL) {
-		SetDParam(0, i->index);
-		AddNewsItem(str, NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), i->xy + TileDiffXY(1, 1), 0);
-	}
-}
-
-void IndustryMonthlyLoop(void)
-{
-	Industry *i;
-	PlayerID old_player = _current_player;
-	_current_player = OWNER_NONE;
-
-	FOR_ALL_INDUSTRIES(i) {
-		UpdateIndustryStatistics(i);
-	}
-
-	/* 3% chance that we start a new industry */
-	if (CHANCE16(3, 100)) {
-		MaybeNewIndustry(Random());
-	} else if (!_patches.smooth_economy) {
-		i = GetRandomIndustry();
-		if (i != NULL) ChangeIndustryProduction(i);
-	}
-
-	_current_player = old_player;
-
-	// production-change
-	_industry_sort_dirty = true;
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
-}
-
-
-void InitializeIndustries(void)
-{
-	CleanPool(&_Industry_pool);
-	AddBlockToPool(&_Industry_pool);
-
-	_total_industries = 0;
-	_industry_sort_dirty = true;
-	_industry_sound_tile = 0;
-}
-
-const TileTypeProcs _tile_type_industry_procs = {
-	DrawTile_Industry,           /* draw_tile_proc */
-	GetSlopeZ_Industry,          /* get_slope_z_proc */
-	ClearTile_Industry,          /* clear_tile_proc */
-	GetAcceptedCargo_Industry,   /* get_accepted_cargo_proc */
-	GetTileDesc_Industry,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Industry, /* get_tile_track_status_proc */
-	ClickTile_Industry,          /* click_tile_proc */
-	AnimateTile_Industry,        /* animate_tile_proc */
-	TileLoop_Industry,           /* tile_loop_proc */
-	ChangeTileOwner_Industry,    /* change_tile_owner_proc */
-	GetProducedCargo_Industry,   /* get_produced_cargo_proc */
-	NULL,                        /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Industry,      /* get_slope_tileh_proc */
-};
-
-static const SaveLoad _industry_desc[] = {
-	SLE_CONDVAR(Industry, xy,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Industry, xy,                  SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLE_VAR(Industry, width,               SLE_UINT8),
-	    SLE_VAR(Industry, height,              SLE_UINT8),
-	    SLE_REF(Industry, town,                REF_TOWN),
-	    SLE_ARR(Industry, produced_cargo,      SLE_UINT8,  2),
-	    SLE_ARR(Industry, cargo_waiting,       SLE_UINT16, 2),
-	    SLE_ARR(Industry, production_rate,     SLE_UINT8,  2),
-	    SLE_ARR(Industry, accepts_cargo,       SLE_UINT8,  3),
-	    SLE_VAR(Industry, prod_level,          SLE_UINT8),
-	    SLE_ARR(Industry, last_mo_production,  SLE_UINT16, 2),
-	    SLE_ARR(Industry, last_mo_transported, SLE_UINT16, 2),
-	    SLE_ARR(Industry, pct_transported,     SLE_UINT8,  2),
-	    SLE_ARR(Industry, total_production,    SLE_UINT16, 2),
-	    SLE_ARR(Industry, total_transported,   SLE_UINT16, 2),
-
-	    SLE_VAR(Industry, counter,             SLE_UINT16),
-
-	    SLE_VAR(Industry, type,                SLE_UINT8),
-	    SLE_VAR(Industry, owner,               SLE_UINT8),
-	    SLE_VAR(Industry, random_color,        SLE_UINT8),
-	SLE_CONDVAR(Industry, last_prod_year,      SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Industry, last_prod_year,      SLE_INT32,                 31, SL_MAX_VERSION),
-	    SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8),
-
-	// reserve extra space in savegame here. (currently 32 bytes)
-	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static void Save_INDY(void)
-{
-	Industry *ind;
-
-	// Write the vehicles
-	FOR_ALL_INDUSTRIES(ind) {
-		SlSetArrayIndex(ind->index);
-		SlObject(ind, _industry_desc);
-	}
-}
-
-static void Load_INDY(void)
-{
-	int index;
-
-	_total_industries = 0;
-
-	while ((index = SlIterateArray()) != -1) {
-		Industry *i;
-
-		if (!AddBlockIfNeeded(&_Industry_pool, index))
-			error("Industries: failed loading savegame: too many industries");
-
-		i = GetIndustry(index);
-		SlObject(i, _industry_desc);
-
-		_total_industries++;
-	}
-}
-
-const ChunkHandler _industry_chunk_handlers[] = {
-	{ 'INDY', Save_INDY, Load_INDY, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/industry_cmd.cpp
@@ -0,0 +1,1910 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "clear_map.h"
+#include "functions.h"
+#include "industry_map.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "tile.h"
+#include "viewport.h"
+#include "command.h"
+#include "industry.h"
+#include "town.h"
+#include "vehicle.h"
+#include "news.h"
+#include "saveload.h"
+#include "economy.h"
+#include "sound.h"
+#include "variables.h"
+#include "table/industry_land.h"
+#include "table/build_industry.h"
+#include "genworld.h"
+#include "date.h"
+#include "water_map.h"
+
+void ShowIndustryViewWindow(int industry);
+void BuildOilRig(TileIndex tile);
+void DeleteOilRig(TileIndex tile);
+
+static byte _industry_sound_ctr;
+static TileIndex _industry_sound_tile;
+
+/**
+ * Called if a new block is added to the industry-pool
+ */
+static void IndustryPoolNewBlock(uint start_item)
+{
+	Industry *i;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (i = GetIndustry(start_item); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) i->index = start_item++;
+}
+
+DEFINE_OLD_POOL(Industry, Industry, IndustryPoolNewBlock, NULL)
+
+/**
+ * Retrieve the type for this industry.  Although it is accessed by a tile,
+ * it will return the general type of industry, and not the sprite index
+ * as would do GetIndustryGfx.
+ * The same information can be accessed by looking at Industry->type
+ * @param tile that is queried
+ * @pre IsTileType(tile, MP_INDUSTRY)
+ * @return general type for this industry, as defined in industry.h
+ **/
+IndustryType GetIndustryType(TileIndex tile)
+{
+	IndustryGfx this_type = GetIndustryGfx(tile);
+	IndustryType iloop;
+
+	assert(IsTileType(tile, MP_INDUSTRY));
+
+	for (iloop = IT_COAL_MINE; iloop < IT_END; iloop += 1) {
+		if (IS_BYTE_INSIDE(this_type, industry_gfx_Solver[iloop].MinGfx,
+				industry_gfx_Solver[iloop].MaxGfx+1)) {
+			return iloop;
+		}
+	}
+
+	return IT_INVALID;  //we have not found equivalent, whatever the reason
+}
+
+/**
+ * Accessor for array _industry_specs.
+ * This will ensure at once : proper access and
+ * not allowing modifications of it.
+ * @param thistype of industry (which is the index in _industry_specs)
+ * @pre thistype < IT_END
+ **/
+const IndustrySpec *GetIndustrySpec(IndustryType thistype)
+{
+	assert(thistype < IT_END);
+	return &_industry_specs[thistype];
+}
+
+void DestroyIndustry(Industry *i)
+{
+	BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
+		if (IsTileType(tile_cur, MP_INDUSTRY)) {
+			if (GetIndustryIndex(tile_cur) == i->index) {
+				DoClearSquare(tile_cur);
+			}
+		} else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
+			DeleteOilRig(tile_cur);
+		}
+	END_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
+
+	if (i->type == IT_FARM || i->type == IT_FARM_2) {
+		/* Remove the farmland and convert it to regular tiles over time. */
+		BEGIN_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiffXY(21, 21)) {
+			tile_cur = TILE_MASK(tile_cur);
+			if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
+					GetIndustryIndexOfField(tile_cur) == i->index) {
+				SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
+			}
+		} END_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiff(21, 21))
+	}
+
+	_industry_sort_dirty = true;
+	_total_industries--;
+	DeleteSubsidyWithIndustry(i->index);
+	DeleteWindowById(WC_INDUSTRY_VIEW, i->index);
+	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+}
+
+static void IndustryDrawSugarMine(const TileInfo *ti)
+{
+	const DrawIndustrySpec1Struct *d;
+	uint32 image;
+
+	if (!IsIndustryCompleted(ti->tile)) return;
+
+	d = &_draw_industry_spec1[GetIndustryAnimationState(ti->tile)];
+
+	AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, d->x, 0);
+
+	image = d->image_2;
+	if (image != 0) AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + image - 1, 8, 41);
+
+	image = d->image_3;
+	if (image != 0) {
+		AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + image - 1,
+			_drawtile_proc1_x[image - 1], _drawtile_proc1_y[image - 1]);
+	}
+}
+
+static void IndustryDrawToffeeQuarry(const TileInfo *ti)
+{
+	int x = 0;
+
+	if (IsIndustryCompleted(ti->tile)) {
+		x = _industry_anim_offs[GetIndustryAnimationState(ti->tile)];
+		if ( (byte)x == 0xFF)
+			x = 0;
+	}
+
+	AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, 22 - x, 24 + x);
+	AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, 6, 14);
+}
+
+static void IndustryDrawBubbleGenerator( const TileInfo *ti)
+{
+	if (IsIndustryCompleted(ti->tile)) {
+		AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, 5, _industry_anim_offs_2[GetIndustryAnimationState(ti->tile)]);
+	} else {
+		AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, 3, 67);
+	}
+}
+
+static void IndustryDrawToyFactory(const TileInfo *ti)
+{
+	const DrawIndustrySpec4Struct *d;
+
+	d = &_industry_anim_offs_3[GetIndustryAnimationState(ti->tile)];
+
+	if (d->image_1 != 0xFF) {
+		AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, 50 - d->image_1 * 2, 96 + d->image_1);
+	}
+
+	if (d->image_2 != 0xFF) {
+		AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, 16 - d->image_2 * 2, 100 + d->image_2);
+	}
+
+	AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, 7, d->image_3);
+	AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, 0, 42);
+}
+
+static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
+{
+	if (IsIndustryCompleted(ti->tile)) {
+		uint image = GetIndustryAnimationState(ti->tile);
+
+		if (image != 0 && image < 7) {
+			AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
+				_coal_plant_sparks_x[image - 1],
+				_coal_plant_sparks_y[image - 1]
+			);
+		}
+	}
+}
+
+typedef void IndustryDrawTileProc(const TileInfo *ti);
+static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
+	IndustryDrawSugarMine,
+	IndustryDrawToffeeQuarry,
+	IndustryDrawBubbleGenerator,
+	IndustryDrawToyFactory,
+	IndustryDrawCoalPlantSparks,
+};
+
+static void DrawTile_Industry(TileInfo *ti)
+{
+	const IndustryGfx gfx = GetIndustryGfx(ti->tile);
+	const Industry *ind;
+	const DrawBuildingsTileStruct *dits;
+	byte z;
+	uint32 image, ormod;
+
+	/* Pointer to industry */
+	ind = GetIndustryByTile(ti->tile);
+	ormod = GENERAL_SPRITE_COLOR(ind->random_color);
+
+	/* Retrieve pointer to the draw industry tile struct */
+	dits = &_industry_draw_tile_data[gfx << 2 | (_industry_section_draw_animation_state[gfx] ?
+			GetIndustryAnimationState(ti->tile) & 3 :
+			GetIndustryConstructionStage(ti->tile))];
+
+	image = dits->ground;
+	if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0)
+		image |= ormod;
+
+	z = ti->z;
+	/* Add bricks below the industry? */
+	if (ti->tileh != SLOPE_FLAT) {
+		AddSortableSpriteToDraw(SPR_FOUNDATION_BASE + ti->tileh, ti->x, ti->y, 16, 16, 7, z);
+		AddChildSpriteScreen(image, 31, 1);
+		z += TILE_HEIGHT;
+	} else {
+		/* Else draw regular ground */
+		DrawGroundSprite(image);
+	}
+
+	/* Add industry on top of the ground? */
+	image = dits->building;
+	if (image != 0) {
+		if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0)
+			image |= ormod;
+
+		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+		AddSortableSpriteToDraw(image,
+			ti->x + dits->subtile_x,
+			ti->y + dits->subtile_y,
+			dits->width  + 1,
+			dits->height + 1,
+			dits->dz,
+			z);
+
+		if (_display_opt & DO_TRANS_BUILDINGS) return;
+	}
+
+	{
+		int proc = dits->draw_proc - 1;
+		if (proc >= 0) _industry_draw_tile_procs[proc](ti);
+	}
+}
+
+static uint GetSlopeZ_Industry(TileIndex tile, uint x, uint y)
+{
+	return GetTileMaxZ(tile);
+}
+
+static Slope GetSlopeTileh_Industry(TileIndex tile, Slope tileh)
+{
+	return SLOPE_FLAT;
+}
+
+static void GetAcceptedCargo_Industry(TileIndex tile, AcceptedCargo ac)
+{
+	IndustryGfx gfx = GetIndustryGfx(tile);
+	CargoID a;
+
+	a = _industry_section_accepts_1[gfx];
+	if (a != CT_INVALID) ac[a] = (a == 0) ? 1 : 8;
+
+	a = _industry_section_accepts_2[gfx];
+	if (a != CT_INVALID) ac[a] = 8;
+
+	a = _industry_section_accepts_3[gfx];
+	if (a != CT_INVALID) ac[a] = 8;
+}
+
+static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
+{
+	const Industry *i = GetIndustryByTile(tile);
+
+	td->owner = i->owner;
+	td->str = GetIndustrySpec(i->type)->name;
+	if (!IsIndustryCompleted(tile)) {
+		SetDParamX(td->dparam, 0, td->str);
+		td->str = STR_2058_UNDER_CONSTRUCTION;
+	}
+}
+
+static int32 ClearTile_Industry(TileIndex tile, byte flags)
+{
+	Industry *i = GetIndustryByTile(tile);
+
+	/* water can destroy industries
+	 * in editor you can bulldoze industries
+	 * with magic_bulldozer cheat you can destroy industries
+	 * (area around OILRIG is water, so water shouldn't flood it
+	 */
+	if ((_current_player != OWNER_WATER && _game_mode != GM_EDITOR &&
+			!_cheats.magic_bulldozer.value) ||
+			(_current_player == OWNER_WATER && i->type == IT_OIL_RIG)) {
+		SetDParam(0, GetIndustrySpec(i->type)->name);
+		return_cmd_error(STR_4800_IN_THE_WAY);
+	}
+
+	if (flags & DC_EXEC) DeleteIndustry(i);
+	return 0;
+}
+
+static void TransportIndustryGoods(TileIndex tile)
+{
+	Industry *i = GetIndustryByTile(tile);
+	const IndustrySpec *indspec = GetIndustrySpec(i->type);
+	uint cw, am;
+
+	cw = min(i->cargo_waiting[0], 255);
+	if (cw > indspec->minimal_cargo/* && i->produced_cargo[0] != 0xFF*/) {
+		i->cargo_waiting[0] -= cw;
+
+		/* fluctuating economy? */
+		if (_economy.fluct <= 0) cw = (cw + 1) / 2;
+
+		i->last_mo_production[0] += cw;
+
+		am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[0], cw);
+		i->last_mo_transported[0] += am;
+		if (am != 0) {
+			uint newgfx = _industry_produce_section[GetIndustryGfx(tile)];
+
+			if (newgfx != 0xFF) {
+				ResetIndustryConstructionStage(tile);
+				SetIndustryCompleted(tile, true);
+				SetIndustryGfx(tile, newgfx);
+				MarkTileDirtyByTile(tile);
+			}
+		}
+	}
+
+	cw = min(i->cargo_waiting[1], 255);
+	if (cw > indspec->minimal_cargo) {
+		i->cargo_waiting[1] -= cw;
+
+		if (_economy.fluct <= 0) cw = (cw + 1) / 2;
+
+		i->last_mo_production[1] += cw;
+
+		am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[1], cw);
+		i->last_mo_transported[1] += am;
+	}
+}
+
+
+static void AnimateTile_Industry(TileIndex tile)
+{
+	byte m;
+
+	switch (GetIndustryGfx(tile)) {
+	case GFX_SUGAR_MINE_SIEVE:
+		if ((_tick_counter & 1) == 0) {
+			m = GetIndustryAnimationState(tile) + 1;
+
+			switch (m & 7) {
+			case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
+			case 6: SndPlayTileFx(SND_29_RIP, tile); break;
+			}
+
+			if (m >= 96) {
+				m = 0;
+				DeleteAnimatedTile(tile);
+			}
+			SetIndustryAnimationState(tile, m);
+
+			MarkTileDirtyByTile(tile);
+		}
+		break;
+
+	case GFX_TOFFEE_QUARY:
+		if ((_tick_counter & 3) == 0) {
+			m = GetIndustryAnimationState(tile);
+
+			if (_industry_anim_offs[m] == 0xFF) {
+				SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
+			}
+
+			if (++m >= 70) {
+				m = 0;
+				DeleteAnimatedTile(tile);
+			}
+			SetIndustryAnimationState(tile, m);
+
+			MarkTileDirtyByTile(tile);
+		}
+		break;
+
+	case GFX_BUBBLE_CATCHER:
+		if ((_tick_counter & 1) == 0) {
+			m = GetIndustryAnimationState(tile);
+
+			if (++m >= 40) {
+				m = 0;
+				DeleteAnimatedTile(tile);
+			}
+			SetIndustryAnimationState(tile, m);
+
+			MarkTileDirtyByTile(tile);
+		}
+		break;
+
+	// Sparks on a coal plant
+	case GFX_POWERPLANT_SPARKS:
+		if ((_tick_counter & 3) == 0) {
+			m = GetIndustryAnimationState(tile);
+			if (m == 6) {
+				SetIndustryAnimationState(tile, 0);
+				DeleteAnimatedTile(tile);
+			} else {
+				SetIndustryAnimationState(tile, m + 1);
+				MarkTileDirtyByTile(tile);
+			}
+		}
+		break;
+
+	case GFX_TOY_FACTORY:
+		if ((_tick_counter & 1) == 0) {
+			m = GetIndustryAnimationState(tile) + 1;
+
+			if (m == 1) {
+				SndPlayTileFx(SND_2C_MACHINERY, tile);
+			} else if (m == 23) {
+				SndPlayTileFx(SND_2B_COMEDY_HIT, tile);
+			} else if (m == 28) {
+				SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile);
+			}
+
+			if (m >= 50) {
+				int n = GetIndustryAnimationLoop(tile) + 1;
+				m = 0;
+				if (n >= 8) {
+					n = 0;
+					DeleteAnimatedTile(tile);
+				}
+				SetIndustryAnimationLoop(tile, n);
+			}
+			SetIndustryAnimationState(tile, m);
+			MarkTileDirtyByTile(tile);
+		}
+		break;
+
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
+		if ((_tick_counter & 3) == 0) {
+			IndustryGfx gfx = GetIndustryGfx(tile);
+
+			gfx = (gfx < 155) ? gfx + 1 : 148;
+			SetIndustryGfx(tile, gfx);
+			MarkTileDirtyByTile(tile);
+		}
+		break;
+
+	case GFX_OILWELL_ANIMATED_1:
+	case GFX_OILWELL_ANIMATED_2:
+	case GFX_OILWELL_ANIMATED_3:
+		if ((_tick_counter & 7) == 0) {
+			bool b = CHANCE16(1,7);
+			IndustryGfx gfx = GetIndustryGfx(tile);
+
+			m = GetIndustryAnimationState(tile) + 1;
+			if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
+				SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
+				SetIndustryConstructionStage(tile, 3);
+				DeleteAnimatedTile(tile);
+			} else {
+				SetIndustryAnimationState(tile, m);
+				SetIndustryGfx(tile, gfx);
+				MarkTileDirtyByTile(tile);
+			}
+		}
+		break;
+
+	case GFX_COAL_MINE_TOWER_ANIMATED:
+	case GFX_COPPER_MINE_TOWER_ANIMATED:
+	case GFX_GOLD_MINE_TOWER_ANIMATED: {
+			int state = _tick_counter & 0x7FF;
+
+			if ((state -= 0x400) < 0)
+				return;
+
+			if (state < 0x1A0) {
+				if (state < 0x20 || state >= 0x180) {
+					m = GetIndustryAnimationState(tile);
+					if (!(m & 0x40)) {
+						SetIndustryAnimationState(tile, m | 0x40);
+						SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
+					}
+					if (state & 7)
+						return;
+				} else {
+					if (state & 3)
+						return;
+				}
+				m = (GetIndustryAnimationState(tile) + 1) | 0x40;
+				if (m > 0xC2) m = 0xC0;
+				SetIndustryAnimationState(tile, m);
+				MarkTileDirtyByTile(tile);
+			} else if (state >= 0x200 && state < 0x3A0) {
+				int i;
+				i = (state < 0x220 || state >= 0x380) ? 7 : 3;
+				if (state & i)
+					return;
+
+				m = (GetIndustryAnimationState(tile) & 0xBF) - 1;
+				if (m < 0x80) m = 0x82;
+				SetIndustryAnimationState(tile, m);
+				MarkTileDirtyByTile(tile);
+			}
+		} break;
+	}
+}
+
+static void CreateIndustryEffectSmoke(TileIndex tile)
+{
+	uint x = TileX(tile) * TILE_SIZE;
+	uint y = TileY(tile) * TILE_SIZE;
+	uint z = GetTileMaxZ(tile);
+
+	CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
+}
+
+static void MakeIndustryTileBigger(TileIndex tile)
+{
+	byte cnt = GetIndustryConstructionCounter(tile) + 1;
+	byte stage;
+
+	if (cnt != 4) {
+		SetIndustryConstructionCounter(tile, cnt);
+		return;
+	}
+
+	stage = GetIndustryConstructionStage(tile) + 1;
+	SetIndustryConstructionCounter(tile, 0);
+	SetIndustryConstructionStage(tile, stage);
+	if (stage == 3) {
+		SetIndustryCompleted(tile, true);
+	}
+
+	MarkTileDirtyByTile(tile);
+
+	if (!IsIndustryCompleted(tile)) return;
+
+	switch (GetIndustryGfx(tile)) {
+	case GFX_POWERPLANT_CHIMNEY:
+		CreateIndustryEffectSmoke(tile);
+		break;
+
+	case GFX_OILRIG_1:
+		if (GetIndustryGfx(tile + TileDiffXY(0, 1)) == GFX_OILRIG_1) BuildOilRig(tile);
+		break;
+
+	case GFX_TOY_FACTORY:
+	case GFX_BUBBLE_CATCHER:
+	case GFX_TOFFEE_QUARY:
+		SetIndustryAnimationState(tile, 0);
+		SetIndustryAnimationLoop(tile, 0);
+		break;
+
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
+	case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
+		AddAnimatedTile(tile);
+		break;
+	}
+}
+
+
+static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
+{
+	int dir;
+	Vehicle *v;
+	static const int8 _tileloop_ind_case_161[12] = {
+		11,   0, -4, -14,
+		-4, -10, -4,   1,
+		49,  59, 60,  65,
+	};
+
+	SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
+
+	dir = Random() & 3;
+
+	v = CreateEffectVehicleAbove(
+		TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0],
+		TileY(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 4],
+		_tileloop_ind_case_161[dir + 8],
+		EV_BUBBLE
+	);
+
+	if (v != NULL) v->u.special.unk2 = dir;
+}
+
+static void TileLoop_Industry(TileIndex tile)
+{
+	IndustryGfx newgfx;
+	IndustryGfx gfx;
+
+	if (!IsIndustryCompleted(tile)) {
+		MakeIndustryTileBigger(tile);
+		return;
+	}
+
+	if (_game_mode == GM_EDITOR) return;
+
+	TransportIndustryGoods(tile);
+
+	newgfx = _industry_section_animation_next[GetIndustryGfx(tile)];
+	if (newgfx != 255) {
+		ResetIndustryConstructionStage(tile);
+		SetIndustryGfx(tile, newgfx);
+		MarkTileDirtyByTile(tile);
+		return;
+	}
+
+	gfx = GetIndustryGfx(tile);
+
+	switch (gfx) {
+	case GFX_OILRIG_1: // coast line at oilrigs
+	case GFX_OILRIG_2:
+	case GFX_OILRIG_3:
+	case GFX_OILRIG_4:
+	case GFX_OILRIG_5:
+		TileLoop_Water(tile);
+		break;
+
+	case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
+	case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
+	case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
+		if (!(_tick_counter & 0x400) && CHANCE16(1, 2)) {
+			switch (gfx) {
+				case GFX_COAL_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_ANIMATED;   break;
+				case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
+				case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_ANIMATED;   break;
+			}
+			SetIndustryGfx(tile, gfx);
+			SetIndustryAnimationState(tile, 0x80);
+			AddAnimatedTile(tile);
+		}
+		break;
+
+	case GFX_OILWELL_NOT_ANIMATED:
+		if (CHANCE16(1, 6)) {
+			SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
+			SetIndustryAnimationState(tile, 0);
+			AddAnimatedTile(tile);
+		}
+		break;
+
+	case GFX_COAL_MINE_TOWER_ANIMATED:
+	case GFX_COPPER_MINE_TOWER_ANIMATED:
+	case GFX_GOLD_MINE_TOWER_ANIMATED:
+		if (!(_tick_counter & 0x400)) {
+			switch (gfx) {
+				case GFX_COAL_MINE_TOWER_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED;   break;
+				case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
+				case GFX_GOLD_MINE_TOWER_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED;   break;
+			}
+			SetIndustryGfx(tile, gfx);
+			SetIndustryCompleted(tile, true);
+			SetIndustryConstructionStage(tile, 3);
+			DeleteAnimatedTile(tile);
+		}
+		break;
+
+	case GFX_POWERPLANT_SPARKS:
+		if (CHANCE16(1,3)) {
+			SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
+			AddAnimatedTile(tile);
+		}
+		break;
+
+	case GFX_COPPER_MINE_CHIMNEY:
+		CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_SMOKE);
+		break;
+
+
+	case GFX_TOY_FACTORY: {
+			Industry *i = GetIndustryByTile(tile);
+			if (i->was_cargo_delivered) {
+				i->was_cargo_delivered = false;
+				SetIndustryAnimationLoop(tile, 0);
+				AddAnimatedTile(tile);
+			}
+		}
+		break;
+
+	case GFX_BUBBLE_GENERATOR:
+		TileLoopIndustry_BubbleGenerator(tile);
+		break;
+
+	case GFX_TOFFEE_QUARY:
+		AddAnimatedTile(tile);
+		break;
+
+	case GFX_SUGAR_MINE_SIEVE:
+		if (CHANCE16(1, 3)) AddAnimatedTile(tile);
+		break;
+	}
+}
+
+
+static void ClickTile_Industry(TileIndex tile)
+{
+	ShowIndustryViewWindow(GetIndustryIndex(tile));
+}
+
+static uint32 GetTileTrackStatus_Industry(TileIndex tile, TransportType mode)
+{
+	return 0;
+}
+
+static void GetProducedCargo_Industry(TileIndex tile, CargoID *b)
+{
+	const Industry *i = GetIndustryByTile(tile);
+
+	b[0] = i->produced_cargo[0];
+	b[1] = i->produced_cargo[1];
+}
+
+static void ChangeTileOwner_Industry(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	/* not used */
+}
+
+static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
+
+static bool IsBadFarmFieldTile(TileIndex tile)
+{
+	switch (GetTileType(tile)) {
+		case MP_CLEAR: return IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_SNOW);
+		case MP_TREES: return false;
+		default:       return true;
+	}
+}
+
+static bool IsBadFarmFieldTile2(TileIndex tile)
+{
+	switch (GetTileType(tile)) {
+		case MP_CLEAR: return IsClearGround(tile, CLEAR_SNOW);
+		case MP_TREES: return false;
+		default:       return true;
+	}
+}
+
+static void SetupFarmFieldFence(TileIndex tile, int size, byte type, Axis direction)
+{
+	do {
+		tile = TILE_MASK(tile);
+
+		if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
+			byte or = type;
+
+			if (or == 1 && CHANCE16(1, 7)) or = 2;
+
+			if (direction == AXIS_X) {
+				SetFenceSE(tile, or);
+			} else {
+				SetFenceSW(tile, or);
+			}
+		}
+
+		tile += (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
+	} while (--size);
+}
+
+static void PlantFarmField(TileIndex tile, IndustryID industry)
+{
+	uint size_x, size_y;
+	uint32 r;
+	uint count;
+	uint counter;
+	uint field_type;
+	int type;
+
+	if (_opt.landscape == LT_HILLY) {
+		if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line)
+			return;
+	}
+
+	/* determine field size */
+	r = (Random() & 0x303) + 0x404;
+	if (_opt.landscape == LT_HILLY) r += 0x404;
+	size_x = GB(r, 0, 8);
+	size_y = GB(r, 8, 8);
+
+	/* offset tile to match size */
+	tile -= TileDiffXY(size_x / 2, size_y / 2);
+
+	/* check the amount of bad tiles */
+	count = 0;
+	BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
+		cur_tile = TILE_MASK(cur_tile);
+		count += IsBadFarmFieldTile(cur_tile);
+	END_TILE_LOOP(cur_tile, size_x, size_y, tile)
+	if (count * 2 >= size_x * size_y) return;
+
+	/* determine type of field */
+	r = Random();
+	counter = GB(r, 5, 3);
+	field_type = GB(r, 8, 8) * 9 >> 8;
+
+	/* make field */
+	BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
+		cur_tile = TILE_MASK(cur_tile);
+		if (!IsBadFarmFieldTile2(cur_tile)) {
+			MakeField(cur_tile, field_type, industry);
+			SetClearCounter(cur_tile, counter);
+			MarkTileDirtyByTile(cur_tile);
+		}
+	END_TILE_LOOP(cur_tile, size_x, size_y, tile)
+
+	type = 3;
+	if (_opt.landscape != LT_HILLY && _opt.landscape != LT_DESERT) {
+		type = _plantfarmfield_type[Random() & 0xF];
+	}
+
+	SetupFarmFieldFence(tile - TileDiffXY(1, 0), size_y, type, AXIS_Y);
+	SetupFarmFieldFence(tile - TileDiffXY(0, 1), size_x, type, AXIS_X);
+	SetupFarmFieldFence(tile + TileDiffXY(size_x - 1, 0), size_y, type, AXIS_Y);
+	SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, AXIS_X);
+}
+
+void PlantRandomFarmField(const Industry *i)
+{
+	int x = i->width  / 2 + Random() % 31 - 16;
+	int y = i->height / 2 + Random() % 31 - 16;
+
+	TileIndex tile = TileAddWrap(i->xy, x, y);
+
+	if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
+}
+
+static void MaybePlantFarmField(const Industry *i)
+{
+	if (CHANCE16(1, 8)) PlantRandomFarmField(i);
+}
+
+/**
+ * Search callback function for ChopLumberMillTrees
+ * @param tile to test
+ * @param data that is passed by the caller.  In this case, nothing
+ * @result of the test
+ */
+static bool SearchLumberMillTrees(TileIndex tile, uint32 data)
+{
+	if (IsTileType(tile, MP_TREES)) {
+		PlayerID old_player = _current_player;
+		/* found a tree */
+
+		_current_player = OWNER_NONE;
+		_industry_sound_ctr = 1;
+		_industry_sound_tile = tile;
+		SndPlayTileFx(SND_38_CHAINSAW, tile);
+
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		SetTropicZone(tile, TROPICZONE_INVALID);
+
+		_current_player = old_player;
+		return true;
+	}
+	return false;
+}
+
+/**
+ * Perform a circular search around the Lumber Mill in order to find trees to cut
+ * @param i industry
+ */
+static void ChopLumberMillTrees(Industry *i)
+{
+	TileIndex tile = i->xy;
+
+	if (!IsIndustryCompleted(tile)) return;  ///< Can't proceed if not completed
+
+	if (CircularTileSearch(tile, 40, SearchLumberMillTrees, 0)) ///< 40x40 tiles  to search
+		i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + 45); ///< Found a tree, add according value to waiting cargo
+}
+
+static const byte _industry_sounds[37][2] = {
+	{0},
+	{0},
+	{1, SND_28_SAWMILL},
+	{0},
+	{0},
+	{0},
+	{1, SND_03_FACTORY_WHISTLE},
+	{1, SND_03_FACTORY_WHISTLE},
+	{0},
+	{3, SND_24_SHEEP},
+	{0},
+	{0},
+	{0},
+	{0},
+	{1, SND_28_SAWMILL},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{1, SND_03_FACTORY_WHISTLE},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{0},
+	{1, SND_33_PLASTIC_MINE},
+	{0},
+	{0},
+	{0},
+	{0},
+};
+
+
+static void ProduceIndustryGoods(Industry *i)
+{
+	uint32 r;
+	uint num;
+
+	/* play a sound? */
+	if ((i->counter & 0x3F) == 0) {
+		if (CHANCE16R(1,14,r) && (num=_industry_sounds[i->type][0]) != 0) {
+			SndPlayTileFx(
+				_industry_sounds[i->type][1] + (((r >> 16) * num) >> 16),
+				i->xy);
+		}
+	}
+
+	i->counter--;
+
+	/* produce some cargo */
+	if ((i->counter & 0xFF) == 0) {
+		i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + i->production_rate[0]);
+		i->cargo_waiting[1] = min(0xffff, i->cargo_waiting[1] + i->production_rate[1]);
+
+		if (i->type == IT_FARM) {
+			MaybePlantFarmField(i);
+		} else if (i->type == IT_LUMBER_MILL && (i->counter & 0x1FF) == 0) {
+			ChopLumberMillTrees(i);
+		}
+	}
+}
+
+void OnTick_Industry(void)
+{
+	Industry *i;
+
+	if (_industry_sound_ctr != 0) {
+		_industry_sound_ctr++;
+
+		if (_industry_sound_ctr == 75) {
+			SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
+		} else if (_industry_sound_ctr == 160) {
+			_industry_sound_ctr = 0;
+			SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
+		}
+	}
+
+	if (_game_mode == GM_EDITOR) return;
+
+	FOR_ALL_INDUSTRIES(i) {
+		ProduceIndustryGoods(i);
+	}
+}
+
+
+static bool CheckNewIndustry_NULL(TileIndex tile)
+{
+	return true;
+}
+
+static bool CheckNewIndustry_Forest(TileIndex tile)
+{
+	if (_opt.landscape == LT_HILLY) {
+		if (GetTileZ(tile) < _opt.snow_line + TILE_HEIGHT * 2U) {
+			_error_message = STR_4831_FOREST_CAN_ONLY_BE_PLANTED;
+			return false;
+		}
+	}
+	return true;
+}
+
+static bool CheckNewIndustry_OilRefinery(TileIndex tile)
+{
+	if (_game_mode == GM_EDITOR) return true;
+	if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
+
+	_error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
+	return false;
+}
+
+extern bool _ignore_restrictions;
+
+static bool CheckNewIndustry_OilRig(TileIndex tile)
+{
+	if (_game_mode == GM_EDITOR && _ignore_restrictions) return true;
+	if (TileHeight(tile) == 0 &&
+			DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
+
+	_error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
+	return false;
+}
+
+static bool CheckNewIndustry_Farm(TileIndex tile)
+{
+	if (_opt.landscape == LT_HILLY) {
+		if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _opt.snow_line) {
+			_error_message = STR_0239_SITE_UNSUITABLE;
+			return false;
+		}
+	}
+	return true;
+}
+
+static bool CheckNewIndustry_Plantation(TileIndex tile)
+{
+	if (GetTropicZone(tile) == TROPICZONE_DESERT) {
+		_error_message = STR_0239_SITE_UNSUITABLE;
+		return false;
+	}
+
+	return true;
+}
+
+static bool CheckNewIndustry_Water(TileIndex tile)
+{
+	if (GetTropicZone(tile) != TROPICZONE_DESERT) {
+		_error_message = STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT;
+		return false;
+	}
+
+	return true;
+}
+
+static bool CheckNewIndustry_Lumbermill(TileIndex tile)
+{
+	if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
+		_error_message = STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST;
+		return false;
+	}
+	return true;
+}
+
+static bool CheckNewIndustry_BubbleGen(TileIndex tile)
+{
+	return GetTileZ(tile) <= TILE_HEIGHT * 4;
+}
+
+typedef bool CheckNewIndustryProc(TileIndex tile);
+static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
+	CheckNewIndustry_NULL,
+	CheckNewIndustry_Forest,
+	CheckNewIndustry_OilRefinery,
+	CheckNewIndustry_Farm,
+	CheckNewIndustry_Plantation,
+	CheckNewIndustry_Water,
+	CheckNewIndustry_Lumbermill,
+	CheckNewIndustry_BubbleGen,
+	CheckNewIndustry_OilRig
+};
+
+static bool CheckSuitableIndustryPos(TileIndex tile)
+{
+	uint x = TileX(tile);
+	uint y = TileY(tile);
+
+	if (x < 2 || y < 2 || x > MapMaxX() - 3 || y > MapMaxY() - 3) {
+		_error_message = STR_0239_SITE_UNSUITABLE;
+		return false;
+	}
+
+	return true;
+}
+
+static const Town *CheckMultipleIndustryInTown(TileIndex tile, int type)
+{
+	const Town *t;
+	const Industry *i;
+
+	t = ClosestTownFromTile(tile, (uint)-1);
+
+	if (_patches.multiple_industry_per_town) return t;
+
+	FOR_ALL_INDUSTRIES(i) {
+		if (i->type == (byte)type &&
+				i->town == t) {
+			_error_message = STR_0287_ONLY_ONE_ALLOWED_PER_TOWN;
+			return NULL;
+		}
+	}
+
+	return t;
+}
+
+static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, int type)
+{
+	_error_message = STR_0239_SITE_UNSUITABLE;
+
+	do {
+		TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
+
+		if (!IsValidTile(cur_tile)) {
+			if (it->gfx == 0xff) continue;
+			return false;
+		}
+
+		if (it->gfx == 0xFF) {
+			if (!IsTileType(cur_tile, MP_WATER) ||
+					GetTileSlope(cur_tile, NULL) != SLOPE_FLAT) {
+				return false;
+			}
+		} else {
+			if (!EnsureNoVehicle(cur_tile)) return false;
+
+			if (type == IT_OIL_RIG)  {
+				if (!IsClearWaterTile(cur_tile)) return false;
+			} else {
+				Slope tileh;
+
+				if (IsClearWaterTile(cur_tile)) return false;
+
+				tileh = GetTileSlope(cur_tile, NULL);
+				if (IsSteepSlope(tileh)) return false;
+
+				if (_patches.land_generator != LG_TERRAGENESIS || !_generating_world) {
+					/* It is almost impossible to have a fully flat land in TG, so what we
+					 *  do is that we check if we can make the land flat later on. See
+					 *  CheckIfCanLevelIndustryPlatform(). */
+					if (tileh != SLOPE_FLAT) {
+						Slope t;
+						byte bits = _industry_section_bits[it->gfx];
+
+						if (bits & 0x10) return false;
+
+						t = ComplementSlope(tileh);
+
+						if (bits & 1 && (t & SLOPE_NW)) return false;
+						if (bits & 2 && (t & SLOPE_NE)) return false;
+						if (bits & 4 && (t & SLOPE_SW)) return false;
+						if (bits & 8 && (t & SLOPE_SE)) return false;
+					}
+				}
+
+				if (type == IT_BANK_TEMP) {
+					if (!IsTileType(cur_tile, MP_HOUSE)) {
+						_error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS;
+						return false;
+					}
+				} else if (type == IT_BANK_TROPIC_ARCTIC) {
+					if (!IsTileType(cur_tile, MP_HOUSE)) {
+						_error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS;
+						return false;
+					}
+				} else if (type == IT_TOY_SHOP) {
+					if (!IsTileType(cur_tile, MP_HOUSE)) goto do_clear;
+				} else if (type == IT_WATER_TOWER) {
+					if (!IsTileType(cur_tile, MP_HOUSE)) {
+						_error_message = STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS;
+						return false;
+					}
+				} else {
+do_clear:
+					if (CmdFailed(DoCommand(cur_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
+						return false;
+				}
+			}
+		}
+	} while ((++it)->ti.x != -0x80);
+
+	return true;
+}
+
+static bool CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
+{
+	if (type == IT_BANK_TEMP && t->population < 1200) {
+		_error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS;
+		return false;
+	}
+
+	if (type == IT_TOY_SHOP && DistanceMax(t->xy, tile) > 9) {
+		_error_message = STR_0239_SITE_UNSUITABLE;
+		return false;
+	}
+
+	return true;
+}
+
+static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
+{
+	int size_x, size_y;
+	uint curh;
+
+	size_x = 2;
+	size_y = 2;
+
+	/* Check if we don't leave the map */
+	if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
+
+	tile += TileDiffXY(-1, -1);
+	BEGIN_TILE_LOOP(tile_walk, size_x, size_y, tile) {
+		curh = TileHeight(tile_walk);
+		/* Is the tile clear? */
+		if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES))
+			return false;
+
+		/* Don't allow too big of a change if this is the sub-tile check */
+		if (internal != 0 && myabs(curh - height) > 1) return false;
+
+		/* Different height, so the surrounding tiles of this tile
+		 *  has to be correct too (in level, or almost in level)
+		 *  else you get a chain-reaction of terraforming. */
+		if (internal == 0 && curh != height) {
+			if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1))
+				return false;
+		}
+	} END_TILE_LOOP(tile_walk, size_x, size_y, tile);
+
+	return true;
+}
+
+/**
+ * This function tries to flatten out the land below an industry, without
+ *  damaging the surroundings too much.
+ */
+static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, uint32 flags, const IndustryTileTable* it, int type)
+{
+	const int MKEND = -0x80;   // used for last element in an IndustryTileTable (see build_industry.h)
+	int max_x = 0;
+	int max_y = 0;
+	TileIndex cur_tile;
+	uint size_x, size_y;
+	uint h, curh;
+
+	/* Finds dimensions of largest variant of this industry */
+	do {
+		if (it->ti.x > max_x) max_x = it->ti.x;
+		if (it->ti.y > max_y) max_y = it->ti.y;
+	} while ((++it)->ti.x != MKEND);
+
+	/* Remember level height */
+	h = TileHeight(tile);
+
+	/* Check that all tiles in area and surrounding are clear
+	 * this determines that there are no obstructing items */
+	cur_tile = tile + TileDiffXY(-1, -1);
+	size_x = max_x + 4;
+	size_y = max_y + 4;
+
+	/* Check if we don't leave the map */
+	if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
+
+	BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
+		curh = TileHeight(tile_walk);
+		if (curh != h) {
+			/* This tile needs terraforming. Check if we can do that without
+			 *  damaging the surroundings too much. */
+			if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) return false;
+			/* This is not 100% correct check, but the best we can do without modifying the map.
+			 *  What is missing, is if the difference in height is more than 1.. */
+			if (CmdFailed(DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND))) return false;
+		}
+	} END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
+
+	if (flags & DC_EXEC) {
+		/* Terraform the land under the industry */
+		BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
+			curh = TileHeight(tile_walk);
+			while (curh != h) {
+				/* We give the terraforming for free here, because we can't calculate
+				 *  exact cost in the test-round, and as we all know, that will cause
+				 *  a nice assert if they don't match ;) */
+				DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
+				curh += (curh > h) ? -1 : 1;
+			}
+		} END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
+	}
+
+	return true;
+}
+
+
+static bool CheckIfTooCloseToIndustry(TileIndex tile, int type)
+{
+	const IndustrySpec *indspec = GetIndustrySpec(type);
+	const Industry *i;
+
+	// accepting industries won't be close, not even with patch
+	if (_patches.same_industry_close && indspec->accepts_cargo[0] == CT_INVALID)
+		return true;
+
+	FOR_ALL_INDUSTRIES(i) {
+		// check if an industry that accepts the same goods is nearby
+		if (DistanceMax(tile, i->xy) <= 14 &&
+				indspec->accepts_cargo[0] != CT_INVALID &&
+				indspec->accepts_cargo[0] == i->accepts_cargo[0] && (
+					_game_mode != GM_EDITOR ||
+					!_patches.same_industry_close ||
+					!_patches.multiple_industry_per_town
+				)) {
+			_error_message = STR_INDUSTRY_TOO_CLOSE;
+			return false;
+		}
+
+		// check "not close to" field.
+		if ((i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) &&
+				DistanceMax(tile, i->xy) <= 14) {
+			_error_message = STR_INDUSTRY_TOO_CLOSE;
+			return false;
+		}
+	}
+	return true;
+}
+
+static Industry *AllocateIndustry(void)
+{
+	Industry *i;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (i = GetIndustry(0); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) {
+		IndustryID index = i->index;
+
+		if (IsValidIndustry(i)) continue;
+
+		memset(i, 0, sizeof(*i));
+		i->index = index;
+
+		return i;
+	}
+
+	/* Check if we can add a block to the pool */
+	return AddBlockToPool(&_Industry_pool) ? AllocateIndustry() : NULL;
+}
+
+static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, const Town *t, byte owner)
+{
+	const IndustrySpec *indspec = GetIndustrySpec(type);
+	uint32 r;
+	int j;
+
+	_total_industries++;
+	i->xy = tile;
+	i->width = i->height = 0;
+	i->type = type;
+
+	i->produced_cargo[0] = indspec->produced_cargo[0];
+	i->produced_cargo[1] = indspec->produced_cargo[1];
+	i->accepts_cargo[0] = indspec->accepts_cargo[0];
+	i->accepts_cargo[1] = indspec->accepts_cargo[1];
+	i->accepts_cargo[2] = indspec->accepts_cargo[2];
+	i->production_rate[0] = indspec->production_rate[0];
+	i->production_rate[1] = indspec->production_rate[1];
+
+	if (_patches.smooth_economy) {
+		i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8 , 255);
+		i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8 , 255);
+	}
+
+	i->town = t;
+	i->owner = owner;
+
+	r = Random();
+	i->random_color = GB(r, 8, 4);
+	i->counter = GB(r, 0, 12);
+	i->cargo_waiting[0] = 0;
+	i->cargo_waiting[1] = 0;
+	i->last_mo_production[0] = 0;
+	i->last_mo_production[1] = 0;
+	i->last_mo_transported[0] = 0;
+	i->last_mo_transported[1] = 0;
+	i->pct_transported[0] = 0;
+	i->pct_transported[1] = 0;
+	i->total_transported[0] = 0;
+	i->total_transported[1] = 0;
+	i->was_cargo_delivered = false;
+	i->last_prod_year = _cur_year;
+	i->total_production[0] = i->production_rate[0] * 8;
+	i->total_production[1] = i->production_rate[1] * 8;
+
+	if (!_generating_world) i->total_production[0] = i->total_production[1] = 0;
+
+	i->prod_level = 0x10;
+
+	do {
+		TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
+
+		if (it->gfx != 0xFF) {
+			byte size;
+
+			size = it->ti.x;
+			if (size > i->width) i->width = size;
+			size = it->ti.y;
+			if (size > i->height)i->height = size;
+
+			DoCommand(cur_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+
+			MakeIndustry(cur_tile, i->index, it->gfx);
+			if (_generating_world) {
+				SetIndustryConstructionCounter(cur_tile, 3);
+				SetIndustryConstructionStage(cur_tile, 2);
+			}
+		}
+	} while ((++it)->ti.x != -0x80);
+
+	i->width++;
+	i->height++;
+
+	if (i->type == IT_FARM || i->type == IT_FARM_2) {
+		for (j = 0; j != 50; j++) PlantRandomFarmField(i);
+	}
+	_industry_sort_dirty = true;
+	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+}
+
+static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, const IndustryTileTable *it)
+{
+	const Town *t;
+	Industry *i;
+
+	if (!CheckIfIndustryTilesAreFree(tile, it, type)) return NULL;
+	if (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL;
+	if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL;
+	if (!CheckIfTooCloseToIndustry(tile, type)) return NULL;
+
+	t = CheckMultipleIndustryInTown(tile, type);
+	if (t == NULL) return NULL;
+
+	if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL;
+	if (!CheckSuitableIndustryPos(tile)) return NULL;
+
+	i = AllocateIndustry();
+	if (i == NULL) return NULL;
+
+	if (flags & DC_EXEC) {
+		CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type);
+		DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE);
+	}
+
+	return i;
+}
+
+/** Build/Fund an industry
+ * @param tile tile where industry is built
+ * @param p1 industry type @see build_industry.h and @see industry.h
+ * @param p2 unused
+ */
+int32 CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int num;
+	const IndustryTileTable * const *itt;
+	const IndustryTileTable *it;
+	const IndustrySpec *indspec;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+
+	indspec = GetIndustrySpec(p1);
+
+	/* Check if the to-be built/founded industry is available for this climate. */
+	if (!HASBIT(indspec->climate_availability, _opt_ptr->landscape)) return CMD_ERROR;
+
+	/* If the patch for raw-material industries is not on, you cannot build raw-material industries.
+	 * Raw material industries are industries that do not accept cargo (at least for now)
+	 * Exclude the lumber mill (only "raw" industry that can be built) */
+	if (!_patches.build_rawmaterial_ind &&
+			indspec->accepts_cargo[0] == CT_INVALID &&
+			indspec->accepts_cargo[1] == CT_INVALID &&
+			indspec->accepts_cargo[2] == CT_INVALID &&
+			p1 != IT_LUMBER_MILL) {
+		return CMD_ERROR;
+	}
+
+	num = indspec->num_table;
+	itt = indspec->table;
+
+	do {
+		if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE);
+	} while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1));
+
+	if (CreateNewIndustryHelper(tile, p1, flags, indspec, it) == NULL) return CMD_ERROR;
+
+	return (_price.build_industry >> 5) * indspec->cost_multiplier;
+}
+
+
+Industry *CreateNewIndustry(TileIndex tile, IndustryType type)
+{
+	const IndustrySpec *indspec = GetIndustrySpec(type);
+	const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)];
+
+	return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, it);
+}
+
+static const byte _numof_industry_table[4][12] = {
+	// difficulty settings for number of industries
+	{0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0},   //none
+	{0, 1, 1, 1, 2, 2, 3, 3,  4,  4,  5},   //low
+	{0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10},   //normal
+	{0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10},   //high
+};
+
+static void PlaceInitialIndustry(IndustryType type, int amount)
+{
+	int num = _numof_industry_table[_opt.diff.number_industries][amount];
+
+	if (type == IT_OIL_REFINERY || type == IT_OIL_RIG) {
+		// These are always placed next to the coastline, so we scale by the perimeter instead.
+		num = ScaleByMapSize1D(num);
+	} else {
+		num = ScaleByMapSize(num);
+	}
+
+	if (_opt.diff.number_industries != 0) {
+		PlayerID old_player = _current_player;
+		_current_player = OWNER_NONE;
+		assert(num > 0);
+
+		do {
+			uint i;
+
+			IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
+
+			for (i = 0; i < 2000; i++) {
+				if (CreateNewIndustry(RandomTile(), type) != NULL) break;
+			}
+		} while (--num);
+
+		_current_player = old_player;
+	}
+}
+
+void GenerateIndustries(void)
+{
+	const byte *b;
+	uint i = 0;
+
+	/* Find the total amount of industries */
+	b = _industry_create_table[_opt.landscape];
+	do {
+		int num = _numof_industry_table[_opt.diff.number_industries][b[0]];
+
+		if (b[1] == IT_OIL_REFINERY || b[1] == IT_OIL_RIG) {
+			/* These are always placed next to the coastline, so we scale by the perimeter instead. */
+			num = ScaleByMapSize1D(num);
+		} else {
+			num = ScaleByMapSize(num);
+		}
+
+		i += num;
+	} while ( (b+=2)[0] != 0);
+	SetGeneratingWorldProgress(GWP_INDUSTRY, i);
+
+	b = _industry_create_table[_opt.landscape];
+	do {
+		PlaceInitialIndustry(b[1], b[0]);
+	} while ( (b+=2)[0] != 0);
+}
+
+/* Change industry production or do closure */
+static void ExtChangeIndustryProduction(Industry *i)
+{
+	bool closeit = true;
+	int j;
+	const IndustrySpec *indspec = GetIndustrySpec(i->type);
+
+	switch (indspec->life_type) {
+		case INDUSTRYLIFE_NOT_CLOSABLE:
+			return;
+
+		case INDUSTRYLIFE_CLOSABLE:
+			if ((byte)(_cur_year - i->last_prod_year) < 5 || !CHANCE16(1, 180))
+				closeit = false;
+			break;
+
+		default: /* INDUSTRY_PRODUCTION */
+			for (j = 0; j < 2 && i->produced_cargo[j] != CT_INVALID; j++){
+				uint32 r = Random();
+				int old, new, percent;
+				int mag;
+
+				new = old = i->production_rate[j];
+				if (CHANCE16I(20, 1024, r))
+					new -= ((RandomRange(50) + 10) * old) >> 8;
+				if (CHANCE16I(20 + (i->pct_transported[j] * 20 >> 8), 1024, r >> 16))
+					new += ((RandomRange(50) + 10) * old) >> 8;
+
+				new = clamp(new, 0, 255);
+				if (new == old) {
+					closeit = false;
+					continue;
+				}
+
+				percent = new * 100 / old - 100;
+				i->production_rate[j] = new;
+
+				if (new >= indspec->production_rate[j] / 4)
+					closeit = false;
+
+				mag = abs(percent);
+				if (mag >= 10) {
+					SetDParam(2, mag);
+					SetDParam(0, _cargoc.names_s[i->produced_cargo[j]]);
+					SetDParam(1, i->index);
+					AddNewsItem(
+						percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN,
+						NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0),
+						i->xy + TileDiffXY(1, 1), 0
+					);
+				}
+			}
+			break;
+	}
+
+	/* If industry will be closed down, show this */
+	if (closeit) {
+		i->prod_level = 0;
+		SetDParam(0, i->index);
+		AddNewsItem(
+			indspec->closure_text,
+			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0),
+			i->xy + TileDiffXY(1, 1), 0
+		);
+	}
+}
+
+
+static void UpdateIndustryStatistics(Industry *i)
+{
+	byte pct;
+
+	if (i->produced_cargo[0] != CT_INVALID) {
+		pct = 0;
+		if (i->last_mo_production[0] != 0) {
+			i->last_prod_year = _cur_year;
+			pct = min(i->last_mo_transported[0] * 256 / i->last_mo_production[0],255);
+		}
+		i->pct_transported[0] = pct;
+
+		i->total_production[0] = i->last_mo_production[0];
+		i->last_mo_production[0] = 0;
+
+		i->total_transported[0] = i->last_mo_transported[0];
+		i->last_mo_transported[0] = 0;
+	}
+
+	if (i->produced_cargo[1] != CT_INVALID) {
+		pct = 0;
+		if (i->last_mo_production[1] != 0) {
+			i->last_prod_year = _cur_year;
+			pct = min(i->last_mo_transported[1] * 256 / i->last_mo_production[1],255);
+		}
+		i->pct_transported[1] = pct;
+
+		i->total_production[1] = i->last_mo_production[1];
+		i->last_mo_production[1] = 0;
+
+		i->total_transported[1] = i->last_mo_transported[1];
+		i->last_mo_transported[1] = 0;
+	}
+
+
+	if (i->produced_cargo[0] != CT_INVALID || i->produced_cargo[1] != CT_INVALID)
+		InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
+
+	if (i->prod_level == 0) {
+		DeleteIndustry(i);
+	} else if (_patches.smooth_economy) {
+		ExtChangeIndustryProduction(i);
+	}
+}
+
+static const byte _new_industry_rand[4][32] = {
+	{12, 12, 12, 12, 12, 12, 12,  0,  0,  6,  6,  9,  9,  3,  3,  3, 18, 18,  4,  4,  2,  2,  5,  5,  5,  5,  5,  5,  1,  1,  8,  8},
+	{16, 16, 16,  0,  0,  0,  9,  9,  9,  9, 13, 13,  3,  3,  3,  3, 15, 15, 15,  4,  4, 11, 11, 11, 11, 11, 14, 14,  1,  1,  7,  7},
+	{21, 21, 21, 24, 22, 22, 22, 22, 23, 23, 16, 16, 16,  4,  4, 19, 19, 19, 13, 13, 20, 20, 20, 11, 11, 11, 17, 17, 17, 10, 10, 10},
+	{30, 30, 30, 36, 36, 31, 31, 31, 27, 27, 27, 28, 28, 28, 26, 26, 26, 34, 34, 34, 35, 35, 35, 29, 29, 29, 32, 32, 32, 33, 33, 33},
+};
+
+static void MaybeNewIndustry(uint32 r)
+{
+	int type;
+	int j;
+	Industry *i;
+
+	type = _new_industry_rand[_opt.landscape][GB(r, 16, 5)];
+
+	if (type == IT_OIL_WELL && _cur_year > 1950) return;
+	if (type == IT_OIL_RIG  && _cur_year < 1960) return;
+
+	j = 2000;
+	for (;;) {
+		i = CreateNewIndustry(RandomTile(), type);
+		if (i != NULL) break;
+		if (--j == 0) return;
+	}
+
+	SetDParam(0, GetIndustrySpec(type)->name);
+	SetDParam(1, i->town->index);
+	AddNewsItem(
+		(type != IT_FOREST && type != IT_FRUIT_PLANTATION && type != IT_RUBBER_PLANTATION && type != IT_COTTON_CANDY) ?
+			STR_482D_NEW_UNDER_CONSTRUCTION : STR_482E_NEW_BEING_PLANTED_NEAR,
+		NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY,0), i->xy, 0
+	);
+}
+
+static void ChangeIndustryProduction(Industry *i)
+{
+	bool only_decrease = false;
+	StringID str = STR_NULL;
+	int type = i->type;
+	const IndustrySpec *indspec = GetIndustrySpec(type);
+
+	switch (indspec->life_type) {
+		case INDUSTRYLIFE_NOT_CLOSABLE:
+			return;
+
+		case INDUSTRYLIFE_PRODUCTION:
+			/* decrease or increase */
+			if (type == IT_OIL_WELL && _opt.landscape == LT_NORMAL)
+				only_decrease = true;
+
+			if (only_decrease || CHANCE16(1,3)) {
+				/* If you transport > 60%, 66% chance we increase, else 33% chance we increase */
+				if (!only_decrease && (i->pct_transported[0] > 153) != CHANCE16(1,3)) {
+					/* Increase production */
+					if (i->prod_level != 0x80) {
+						byte b;
+
+						i->prod_level <<= 1;
+
+						b = i->production_rate[0] * 2;
+						if (i->production_rate[0] >= 128)
+							b = 0xFF;
+						i->production_rate[0] = b;
+
+						b = i->production_rate[1] * 2;
+						if (i->production_rate[1] >= 128)
+							b = 0xFF;
+						i->production_rate[1] = b;
+
+						str = indspec->production_up_text;
+					}
+				} else {
+					/* Decrease production */
+					if (i->prod_level == 4) {
+						i->prod_level = 0;
+						str = indspec->closure_text;
+					} else {
+						i->prod_level >>= 1;
+						i->production_rate[0] = (i->production_rate[0] + 1) >> 1;
+						i->production_rate[1] = (i->production_rate[1] + 1) >> 1;
+
+						str = indspec->production_down_text;
+					}
+				}
+			}
+			break;
+
+		case INDUSTRYLIFE_CLOSABLE:
+			/* maybe close */
+			if ( (byte)(_cur_year - i->last_prod_year) >= 5 && CHANCE16(1,2)) {
+				i->prod_level = 0;
+				str = indspec->closure_text;
+			}
+			break;
+	}
+
+	if (str != STR_NULL) {
+		SetDParam(0, i->index);
+		AddNewsItem(str, NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), i->xy + TileDiffXY(1, 1), 0);
+	}
+}
+
+void IndustryMonthlyLoop(void)
+{
+	Industry *i;
+	PlayerID old_player = _current_player;
+	_current_player = OWNER_NONE;
+
+	FOR_ALL_INDUSTRIES(i) {
+		UpdateIndustryStatistics(i);
+	}
+
+	/* 3% chance that we start a new industry */
+	if (CHANCE16(3, 100)) {
+		MaybeNewIndustry(Random());
+	} else if (!_patches.smooth_economy) {
+		i = GetRandomIndustry();
+		if (i != NULL) ChangeIndustryProduction(i);
+	}
+
+	_current_player = old_player;
+
+	// production-change
+	_industry_sort_dirty = true;
+	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+}
+
+
+void InitializeIndustries(void)
+{
+	CleanPool(&_Industry_pool);
+	AddBlockToPool(&_Industry_pool);
+
+	_total_industries = 0;
+	_industry_sort_dirty = true;
+	_industry_sound_tile = 0;
+}
+
+const TileTypeProcs _tile_type_industry_procs = {
+	DrawTile_Industry,           /* draw_tile_proc */
+	GetSlopeZ_Industry,          /* get_slope_z_proc */
+	ClearTile_Industry,          /* clear_tile_proc */
+	GetAcceptedCargo_Industry,   /* get_accepted_cargo_proc */
+	GetTileDesc_Industry,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Industry, /* get_tile_track_status_proc */
+	ClickTile_Industry,          /* click_tile_proc */
+	AnimateTile_Industry,        /* animate_tile_proc */
+	TileLoop_Industry,           /* tile_loop_proc */
+	ChangeTileOwner_Industry,    /* change_tile_owner_proc */
+	GetProducedCargo_Industry,   /* get_produced_cargo_proc */
+	NULL,                        /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Industry,      /* get_slope_tileh_proc */
+};
+
+static const SaveLoad _industry_desc[] = {
+	SLE_CONDVAR(Industry, xy,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Industry, xy,                  SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLE_VAR(Industry, width,               SLE_UINT8),
+	    SLE_VAR(Industry, height,              SLE_UINT8),
+	    SLE_REF(Industry, town,                REF_TOWN),
+	    SLE_ARR(Industry, produced_cargo,      SLE_UINT8,  2),
+	    SLE_ARR(Industry, cargo_waiting,       SLE_UINT16, 2),
+	    SLE_ARR(Industry, production_rate,     SLE_UINT8,  2),
+	    SLE_ARR(Industry, accepts_cargo,       SLE_UINT8,  3),
+	    SLE_VAR(Industry, prod_level,          SLE_UINT8),
+	    SLE_ARR(Industry, last_mo_production,  SLE_UINT16, 2),
+	    SLE_ARR(Industry, last_mo_transported, SLE_UINT16, 2),
+	    SLE_ARR(Industry, pct_transported,     SLE_UINT8,  2),
+	    SLE_ARR(Industry, total_production,    SLE_UINT16, 2),
+	    SLE_ARR(Industry, total_transported,   SLE_UINT16, 2),
+
+	    SLE_VAR(Industry, counter,             SLE_UINT16),
+
+	    SLE_VAR(Industry, type,                SLE_UINT8),
+	    SLE_VAR(Industry, owner,               SLE_UINT8),
+	    SLE_VAR(Industry, random_color,        SLE_UINT8),
+	SLE_CONDVAR(Industry, last_prod_year,      SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Industry, last_prod_year,      SLE_INT32,                 31, SL_MAX_VERSION),
+	    SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8),
+
+	// reserve extra space in savegame here. (currently 32 bytes)
+	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static void Save_INDY(void)
+{
+	Industry *ind;
+
+	// Write the vehicles
+	FOR_ALL_INDUSTRIES(ind) {
+		SlSetArrayIndex(ind->index);
+		SlObject(ind, _industry_desc);
+	}
+}
+
+static void Load_INDY(void)
+{
+	int index;
+
+	_total_industries = 0;
+
+	while ((index = SlIterateArray()) != -1) {
+		Industry *i;
+
+		if (!AddBlockIfNeeded(&_Industry_pool, index))
+			error("Industries: failed loading savegame: too many industries");
+
+		i = GetIndustry(index);
+		SlObject(i, _industry_desc);
+
+		_total_industries++;
+	}
+}
+
+const ChunkHandler _industry_chunk_handlers[] = {
+	{ 'INDY', Save_INDY, Load_INDY, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/industry_gui.c
+++ /dev/null
@@ -1,693 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "strings.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "gui.h"
-#include "window.h"
-#include "gfx.h"
-#include "command.h"
-#include "viewport.h"
-#include "industry.h"
-#include "town.h"
-#include "variables.h"
-
-const byte _build_industry_types[4][12] = {
-	{  1,  2,  4,  6,  8,  0,  3,  5,  9, 11, 18 },
-	{  1, 14,  4, 13,  7,  0,  3,  9, 11, 15 },
-	{ 25, 13,  4, 23, 22, 11, 17, 10, 24, 19, 20, 21 },
-	{ 27, 30, 31, 33, 26, 28, 29, 32, 34, 35, 36 },
-};
-
-static void UpdateIndustryProduction(Industry *i);
-
-static void BuildIndustryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		if (_thd.place_mode == 1 && _thd.window_class == WC_BUILD_INDUSTRY) {
-			int ind_type = _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1];
-
-			SetDParam(0, (_price.build_industry >> 5) * GetIndustrySpec(ind_type)->cost_multiplier);
-			DrawStringCentered(85, w->height - 21, STR_482F_COST, 0);
-		}
-		break;
-
-	case WE_CLICK: {
-		int wid = e->we.click.widget;
-		if (wid >= 3) {
-			if (HandlePlacePushButton(w, wid, SPR_CURSOR_INDUSTRY, 1, NULL))
-				WP(w,def_d).data_1 = wid - 3;
-		}
-	} break;
-
-	case WE_PLACE_OBJ:
-		if (DoCommandP(e->we.place.tile, _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)))
-			ResetObjectToPlace();
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		break;
-	}
-}
-
-static const Widget _build_industry_land0_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_0242_SAWMILL,               STR_0264_CONSTRUCT_SAWMILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0247_STEEL_MILL,            STR_0269_CONSTRUCT_STEEL_MILL},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land1_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land2_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0250_LUMBER_MILL,           STR_0273_CONSTRUCT_LUMBER_MILL_TO},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0254_WATER_TOWER,           STR_0277_CONSTRUCT_WATER_TOWER_CAN},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land3_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0258_CANDY_FACTORY,         STR_027B_CONSTRUCT_CANDY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_025B_TOY_SHOP,              STR_027E_CONSTRUCT_TOY_SHOP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_025C_TOY_FACTORY,           STR_027F_CONSTRUCT_TOY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_025E_FIZZY_DRINK_FACTORY,   STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land0_widgets_extra[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   187, 0x0,                            STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_0242_SAWMILL,               STR_0264_CONSTRUCT_SAWMILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0247_STEEL_MILL,            STR_0269_CONSTRUCT_STEEL_MILL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0240_COAL_MINE,             STR_CONSTRUCT_COAL_MINE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0243_FOREST,                STR_CONSTRUCT_FOREST_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0245_OIL_RIG,               STR_CONSTRUCT_OIL_RIG_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0249_IRON_ORE_MINE,         STR_CONSTRUCT_IRON_ORE_MINE_TIP},
-
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land1_widgets_extra[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   174, 0x0,                            STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0240_COAL_MINE,             STR_CONSTRUCT_COAL_MINE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0243_FOREST,                STR_CONSTRUCT_FOREST_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_024F_GOLD_MINE,             STR_CONSTRUCT_GOLD_MINE_TIP},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land2_widgets_extra[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   200, 0x0,                            STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0250_LUMBER_MILL,           STR_0273_CONSTRUCT_LUMBER_MILL_TO},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0254_WATER_TOWER,           STR_0277_CONSTRUCT_WATER_TOWER_CAN},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0255_DIAMOND_MINE,          STR_CONSTRUCT_DIAMOND_MINE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0256_COPPER_ORE_MINE,       STR_CONSTRUCT_COPPER_ORE_MINE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_0251_FRUIT_PLANTATION,      STR_CONSTRUCT_FRUIT_PLANTATION_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0252_RUBBER_PLANTATION,     STR_CONSTRUCT_RUBBER_PLANTATION_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   162,   173, STR_0253_WATER_SUPPLY,          STR_CONSTRUCT_WATER_SUPPLY_TIP},
-{   WIDGETS_END},
-};
-
-static const Widget _build_industry_land3_widgets_extra[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   187, 0x0,                            STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0258_CANDY_FACTORY,         STR_027B_CONSTRUCT_CANDY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_025B_TOY_SHOP,              STR_027E_CONSTRUCT_TOY_SHOP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_025C_TOY_FACTORY,           STR_027F_CONSTRUCT_TOY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_025E_FIZZY_DRINK_FACTORY,   STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    71,    82, STR_0257_COTTON_CANDY_FOREST,   STR_CONSTRUCT_COTTON_CANDY_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0259_BATTERY_FARM,          STR_CONSTRUCT_BATTERY_FARM_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_025A_COLA_WELLS,            STR_CONSTRUCT_COLA_WELLS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_025D_PLASTIC_FOUNTAINS,     STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_025F_BUBBLE_GENERATOR,      STR_CONSTRUCT_BUBBLE_GENERATOR_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_0260_TOFFEE_QUARRY,         STR_CONSTRUCT_TOFFEE_QUARRY_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0261_SUGAR_MINE,            STR_CONSTRUCT_SUGAR_MINE_TIP},
-{   WIDGETS_END},
-};
-
-
-static const WindowDesc _build_industry_land0_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 116,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land0_widgets,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land1_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 116,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land1_widgets,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land2_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 116,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land2_widgets,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land3_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 116,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land3_widgets,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land0_desc_extra = {
-	WDP_AUTO, WDP_AUTO, 170, 188,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land0_widgets_extra,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land1_desc_extra = {
-	WDP_AUTO, WDP_AUTO, 170, 175,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land1_widgets_extra,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land2_desc_extra = {
-	WDP_AUTO, WDP_AUTO, 170, 201,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land2_widgets_extra,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc _build_industry_land3_desc_extra = {
-	WDP_AUTO, WDP_AUTO, 170, 188,
-	WC_BUILD_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_industry_land3_widgets_extra,
-	BuildIndustryWndProc
-};
-
-static const WindowDesc * const _industry_window_desc[2][4] = {
-	{
-	&_build_industry_land0_desc,
-	&_build_industry_land1_desc,
-	&_build_industry_land2_desc,
-	&_build_industry_land3_desc,
-	},
-	{
-	&_build_industry_land0_desc_extra,
-	&_build_industry_land1_desc_extra,
-	&_build_industry_land2_desc_extra,
-	&_build_industry_land3_desc_extra,
-	},
-};
-
-void ShowBuildIndustryWindow(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-	AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt_ptr->landscape],0);
-}
-
-static inline bool isProductionMinimum(const Industry *i, int pt) {
-	return i->production_rate[pt] == 1;
-}
-
-static inline bool isProductionMaximum(const Industry *i, int pt) {
-	return i->production_rate[pt] == 255;
-}
-
-static inline bool IsProductionAlterable(const Industry *i)
-{
-	return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) &&
-		     (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES));
-}
-
-static void IndustryViewWndProc(Window *w, WindowEvent *e)
-{
-	// WP(w,vp2_d).data_1 is for the editbox line
-	// WP(w,vp2_d).data_2 is for the clickline
-	// WP(w,vp2_d).data_3 is for the click pos (left or right)
-
-	switch (e->event) {
-	case WE_PAINT: {
-		const Industry *i = GetIndustry(w->window_number);
-
-		SetDParam(0, w->window_number);
-		DrawWindowWidgets(w);
-
-		if (i->accepts_cargo[0] != CT_INVALID) {
-			StringID str;
-
-			SetDParam(0, _cargoc.names_s[i->accepts_cargo[0]]);
-			str = STR_4827_REQUIRES;
-			if (i->accepts_cargo[1] != CT_INVALID) {
-				SetDParam(1, _cargoc.names_s[i->accepts_cargo[1]]);
-				str = STR_4828_REQUIRES;
-				if (i->accepts_cargo[2] != CT_INVALID) {
-					SetDParam(2, _cargoc.names_s[i->accepts_cargo[2]]);
-					str = STR_4829_REQUIRES;
-				}
-			}
-			DrawString(2, 107, str, 0);
-		}
-
-		if (i->produced_cargo[0] != CT_INVALID) {
-			DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0);
-
-			SetDParam(0, i->produced_cargo[0]);
-			SetDParam(1, i->total_production[0]);
-
-			SetDParam(2, i->pct_transported[0] * 100 >> 8);
-			DrawString(4 + (IsProductionAlterable(i) ? 30 : 0), 127, STR_482B_TRANSPORTED, 0);
-			// Let's put out those buttons..
-			if (IsProductionAlterable(i)) {
-				DrawArrowButtons(5, 127, 3, (WP(w,vp2_d).data_2 == 1) ? WP(w,vp2_d).data_3 : 0,
-						!isProductionMinimum(i, 0), !isProductionMaximum(i, 0));
-			}
-
-			if (i->produced_cargo[1] != CT_INVALID) {
-				SetDParam(0, i->produced_cargo[1]);
-				SetDParam(1, i->total_production[1]);
-				SetDParam(2, i->pct_transported[1] * 100 >> 8);
-				DrawString(4 + (IsProductionAlterable(i) ? 30 : 0), 137, STR_482B_TRANSPORTED, 0);
-				// Let's put out those buttons..
-				if (IsProductionAlterable(i)) {
-					DrawArrowButtons(5, 137, 3, (WP(w,vp2_d).data_2 == 2) ? WP(w,vp2_d).data_3 : 0,
-						!isProductionMinimum(i, 1), !isProductionMaximum(i, 1));
-				}
-			}
-		}
-
-		DrawWindowViewport(w);
-		}
-		break;
-
-	case WE_CLICK: {
-		Industry *i;
-
-		switch (e->we.click.widget) {
-		case 5: {
-			int line, x;
-
-			i = GetIndustry(w->window_number);
-
-			// We should work if needed..
-			if (!IsProductionAlterable(i)) return;
-
-			x = e->we.click.pt.x;
-			line = (e->we.click.pt.y - 127) / 10;
-			if (e->we.click.pt.y >= 127 && IS_INT_INSIDE(line, 0, 2) && i->produced_cargo[line] != CT_INVALID) {
-				if (IS_INT_INSIDE(x, 5, 25) ) {
-					/* Clicked buttons, decrease or increase production */
-					if (x < 15) {
-						if (isProductionMinimum(i, line)) return;
-						i->production_rate[line] = maxu(i->production_rate[line] / 2, 1);
-					} else {
-						if (isProductionMaximum(i, line)) return;
-						i->production_rate[line] = minu(i->production_rate[line] * 2, 255);
-					}
-
-					UpdateIndustryProduction(i);
-					SetWindowDirty(w);
-					w->flags4 |= 5 << WF_TIMEOUT_SHL;
-					WP(w,vp2_d).data_2 = line+1;
-					WP(w,vp2_d).data_3 = (x < 15 ? 1 : 2);
-				} else if (IS_INT_INSIDE(x, 34, 160)) {
-					// clicked the text
-					WP(w,vp2_d).data_1 = line;
-					SetDParam(0, i->production_rate[line] * 8);
-					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_GAME_PRODUCTION, 10, 100, w, CS_ALPHANUMERAL);
-				}
-			}
-		} break;
-		case 6:
-			i = GetIndustry(w->window_number);
-			ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1));
-		}	break;
-
-		}
-		break;
-	case WE_TIMEOUT:
-		WP(w,vp2_d).data_2 = 0;
-		WP(w,vp2_d).data_3 = 0;
-		SetWindowDirty(w);
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			Industry* i = GetIndustry(w->window_number);
-			int line = WP(w,vp2_d).data_1;
-
-			i->production_rate[line] = clampu(atoi(e->we.edittext.str), 0, 255);
-			UpdateIndustryProduction(i);
-			SetWindowDirty(w);
-		}
-	}
-}
-
-static void UpdateIndustryProduction(Industry *i)
-{
-	if (i->produced_cargo[0] != CT_INVALID)
-		i->total_production[0] = 8 * i->production_rate[0];
-
-	if (i->produced_cargo[1] != CT_INVALID)
-		i->total_production[1] = 8 * i->production_rate[1];
-}
-
-static const Widget _industry_view_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     9,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     9,    11,   247,     0,    13, STR_4801,          STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     9,   248,   259,     0,    13, 0x0,               STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,     9,     0,   259,    14,   105, 0x0,               STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,     9,     2,   257,    16,   103, 0x0,               STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     9,     0,   259,   106,   147, 0x0,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     9,     0,   129,   148,   159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
-{      WWT_PANEL,   RESIZE_NONE,     9,   130,   259,   148,   159, 0x0,               STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _industry_view_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 160,
-	WC_INDUSTRY_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_industry_view_widgets,
-	IndustryViewWndProc
-};
-
-void ShowIndustryViewWindow(int industry)
-{
-	Window *w = AllocateWindowDescFront(&_industry_view_desc, industry);
-
-	if (w != NULL) {
-		w->flags4 |= WF_DISABLE_VP_SCROLL;
-		WP(w,vp2_d).data_1 = 0;
-		WP(w,vp2_d).data_2 = 0;
-		WP(w,vp2_d).data_3 = 0;
-		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), 1);
-	}
-}
-
-static const Widget _industry_directory_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   495,     0,    13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    13,   496,   507,     0,    13, 0x0,                     STR_STICKY_BUTTON},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,   100,    14,    25, STR_SORT_BY_NAME,        STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   101,   200,    14,    25, STR_SORT_BY_TYPE,        STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   201,   300,    14,    25, STR_SORT_BY_PRODUCTION,  STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   301,   400,    14,    25, STR_SORT_BY_TRANSPORTED, STR_SORT_ORDER_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    13,   401,   495,    14,    25, 0x0,                     STR_NULL},
-{      WWT_PANEL, RESIZE_BOTTOM,    13,     0,   495,    26,   189, 0x0,                     STR_200A_TOWN_NAMES_CLICK_ON_NAME},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    13,   496,   507,    14,   177, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{  WWT_RESIZEBOX,     RESIZE_TB,    13,   496,   507,   178,   189, 0x0,                     STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static uint _num_industry_sort;
-
-static char _bufcache[96];
-static const Industry* _last_industry;
-
-static byte _industry_sort_order;
-
-static int CDECL GeneralIndustrySorter(const void *a, const void *b)
-{
-	const Industry* i = *(const Industry**)a;
-	const Industry* j = *(const Industry**)b;
-	int r;
-
-	switch (_industry_sort_order >> 1) {
-		default: NOT_REACHED();
-		case 0: /* Sort by Name (handled later) */
-			r = 0;
-			break;
-
-		case 1: /* Sort by Type */
-			r = i->type - j->type;
-			break;
-
-		case 2: /* Sort by Production */
-			if (i->produced_cargo[0] == CT_INVALID) {
-				r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
-			} else {
-				if (j->produced_cargo[0] == CT_INVALID) {
-					r = 1;
-				} else {
-					r =
-						(i->total_production[0] + i->total_production[1]) -
-						(j->total_production[0] + j->total_production[1]);
-				}
-			}
-			break;
-
-		case 3: /* Sort by transported fraction */
-			if (i->produced_cargo[0] == CT_INVALID) {
-				r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
-			} else {
-				if (j->produced_cargo[0] == CT_INVALID) {
-					r = 1;
-				} else {
-					int pi;
-					int pj;
-
-					pi = i->pct_transported[0] * 100 >> 8;
-					if (i->produced_cargo[1] != CT_INVALID) {
-						int p = i->pct_transported[1] * 100 >> 8;
-						if (p < pi) pi = p;
-					}
-
-					pj = j->pct_transported[0] * 100 >> 8;
-					if (j->produced_cargo[1] != CT_INVALID) {
-						int p = j->pct_transported[1] * 100 >> 8;
-						if (p < pj) pj = p;
-					}
-
-					r = pi - pj;
-				}
-			}
-			break;
-	}
-
-	// default to string sorting if they are otherwise equal
-	if (r == 0) {
-		char buf1[96];
-
-		SetDParam(0, i->town->index);
-		GetString(buf1, STR_TOWN, lastof(buf1));
-
-		if (j != _last_industry) {
-			_last_industry = j;
-			SetDParam(0, j->town->index);
-			GetString(_bufcache, STR_TOWN, lastof(_bufcache));
-		}
-		r = strcmp(buf1, _bufcache);
-	}
-
-	if (_industry_sort_order & 1) r = -r;
-	return r;
-}
-
-static void MakeSortedIndustryList(void)
-{
-	const Industry* i;
-	int n = 0;
-
-	/* Don't attempt a sort if there are no industries */
-	if (GetNumIndustries() == 0) return;
-
-	/* Create array for sorting */
-	_industry_sort = realloc((void *)_industry_sort, (GetMaxIndustryIndex() + 1) * sizeof(_industry_sort[0]));
-	if (_industry_sort == NULL) error("Could not allocate memory for the industry-sorting-list");
-
-	FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
-
-	_num_industry_sort = n;
-	_last_industry = NULL; // used for "cache"
-
-	qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
-
-	DEBUG(misc, 3, "Resorting industries list");
-}
-
-
-static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int n;
-		uint p;
-		static const uint16 _indicator_positions[4] = {88, 187, 284, 387};
-
-		if (_industry_sort_dirty) {
-			_industry_sort_dirty = false;
-			MakeSortedIndustryList();
-		}
-
-		SetVScrollCount(w, _num_industry_sort);
-
-		DrawWindowWidgets(w);
-		DoDrawString(_industry_sort_order & 1 ? DOWNARROW : UPARROW, _indicator_positions[_industry_sort_order>>1], 15, 0x10);
-
-		p = w->vscroll.pos;
-		n = 0;
-
-		while (p < _num_industry_sort) {
-			const Industry* i = _industry_sort[p];
-
-			SetDParam(0, i->index);
-			if (i->produced_cargo[0] != CT_INVALID) {
-				SetDParam(1, i->produced_cargo[0]);
-				SetDParam(2, i->total_production[0]);
-
-				if (i->produced_cargo[1] != CT_INVALID) {
-					SetDParam(3, i->produced_cargo[1]);
-					SetDParam(4, i->total_production[1]);
-					SetDParam(5, i->pct_transported[0] * 100 >> 8);
-					SetDParam(6, i->pct_transported[1] * 100 >> 8);
-					DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0);
-				} else {
-					SetDParam(3, i->pct_transported[0] * 100 >> 8);
-					DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM, 0);
-				}
-			} else {
-				DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_NOPROD, 0);
-			}
-			p++;
-			if (++n == w->vscroll.cap) break;
-		}
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: {
-			_industry_sort_order = _industry_sort_order==0 ? 1 : 0;
-			_industry_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 4: {
-			_industry_sort_order = _industry_sort_order==2 ? 3 : 2;
-			_industry_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 5: {
-			_industry_sort_order = _industry_sort_order==4 ? 5 : 4;
-			_industry_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 6: {
-			_industry_sort_order = _industry_sort_order==6 ? 7 : 6;
-			_industry_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 8: {
-			int y = (e->we.click.pt.y - 28) / 10;
-			uint16 p;
-
-			if (!IS_INT_INSIDE(y, 0, w->vscroll.cap)) return;
-			p = y + w->vscroll.pos;
-			if (p < _num_industry_sort) {
-				ScrollMainWindowToTile(_industry_sort[p]->xy);
-			}
-		} break;
-		}
-		break;
-
-	case WE_4:
-		SetWindowDirty(w);
-		break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 10;
-		break;
-	}
-}
-
-
-/* Industry List */
-static const WindowDesc _industry_directory_desc = {
-	WDP_AUTO, WDP_AUTO, 508, 190,
-	WC_INDUSTRY_DIRECTORY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_industry_directory_widgets,
-	IndustryDirectoryWndProc
-};
-
-
-void ShowIndustryDirectory(void)
-{
-	Window *w = AllocateWindowDescFront(&_industry_directory_desc, 0);
-
-	if (w != NULL) {
-		w->vscroll.cap = 16;
-		w->resize.height = w->height - 6 * 10; // minimum 10 items
-		w->resize.step_height = 10;
-		SetWindowDirty(w);
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/industry_gui.cpp
@@ -0,0 +1,693 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "gui.h"
+#include "window.h"
+#include "gfx.h"
+#include "command.h"
+#include "viewport.h"
+#include "industry.h"
+#include "town.h"
+#include "variables.h"
+
+const byte _build_industry_types[4][12] = {
+	{  1,  2,  4,  6,  8,  0,  3,  5,  9, 11, 18 },
+	{  1, 14,  4, 13,  7,  0,  3,  9, 11, 15 },
+	{ 25, 13,  4, 23, 22, 11, 17, 10, 24, 19, 20, 21 },
+	{ 27, 30, 31, 33, 26, 28, 29, 32, 34, 35, 36 },
+};
+
+static void UpdateIndustryProduction(Industry *i);
+
+static void BuildIndustryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		if (_thd.place_mode == 1 && _thd.window_class == WC_BUILD_INDUSTRY) {
+			int ind_type = _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1];
+
+			SetDParam(0, (_price.build_industry >> 5) * GetIndustrySpec(ind_type)->cost_multiplier);
+			DrawStringCentered(85, w->height - 21, STR_482F_COST, 0);
+		}
+		break;
+
+	case WE_CLICK: {
+		int wid = e->we.click.widget;
+		if (wid >= 3) {
+			if (HandlePlacePushButton(w, wid, SPR_CURSOR_INDUSTRY, 1, NULL))
+				WP(w,def_d).data_1 = wid - 3;
+		}
+	} break;
+
+	case WE_PLACE_OBJ:
+		if (DoCommandP(e->we.place.tile, _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)))
+			ResetObjectToPlace();
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		break;
+	}
+}
+
+static const Widget _build_industry_land0_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_0242_SAWMILL,               STR_0264_CONSTRUCT_SAWMILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0247_STEEL_MILL,            STR_0269_CONSTRUCT_STEEL_MILL},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land1_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land2_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0250_LUMBER_MILL,           STR_0273_CONSTRUCT_LUMBER_MILL_TO},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0254_WATER_TOWER,           STR_0277_CONSTRUCT_WATER_TOWER_CAN},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land3_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   115, 0x0,                            STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0258_CANDY_FACTORY,         STR_027B_CONSTRUCT_CANDY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_025B_TOY_SHOP,              STR_027E_CONSTRUCT_TOY_SHOP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_025C_TOY_FACTORY,           STR_027F_CONSTRUCT_TOY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_025E_FIZZY_DRINK_FACTORY,   STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land0_widgets_extra[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   187, 0x0,                            STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_0242_SAWMILL,               STR_0264_CONSTRUCT_SAWMILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0247_STEEL_MILL,            STR_0269_CONSTRUCT_STEEL_MILL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0240_COAL_MINE,             STR_CONSTRUCT_COAL_MINE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0243_FOREST,                STR_CONSTRUCT_FOREST_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0245_OIL_RIG,               STR_CONSTRUCT_OIL_RIG_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0249_IRON_ORE_MINE,         STR_CONSTRUCT_IRON_ORE_MINE_TIP},
+
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land1_widgets_extra[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   174, 0x0,                            STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0240_COAL_MINE,             STR_CONSTRUCT_COAL_MINE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0243_FOREST,                STR_CONSTRUCT_FOREST_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_024F_GOLD_MINE,             STR_CONSTRUCT_GOLD_MINE_TIP},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land2_widgets_extra[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   200, 0x0,                            STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0250_LUMBER_MILL,           STR_0273_CONSTRUCT_LUMBER_MILL_TO},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0246_FACTORY,               STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0254_WATER_TOWER,           STR_0277_CONSTRUCT_WATER_TOWER_CAN},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_024A_OIL_WELLS,             STR_CONSTRUCT_OIL_WELLS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_0255_DIAMOND_MINE,          STR_CONSTRUCT_DIAMOND_MINE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_0256_COPPER_ORE_MINE,       STR_CONSTRUCT_COPPER_ORE_MINE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_0248_FARM,                  STR_CONSTRUCT_FARM_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_0251_FRUIT_PLANTATION,      STR_CONSTRUCT_FRUIT_PLANTATION_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0252_RUBBER_PLANTATION,     STR_CONSTRUCT_RUBBER_PLANTATION_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   162,   173, STR_0253_WATER_SUPPLY,          STR_CONSTRUCT_WATER_SUPPLY_TIP},
+{   WIDGETS_END},
+};
+
+static const Widget _build_industry_land3_widgets_extra[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0314_FUND_NEW_INDUSTRY,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   187, 0x0,                            STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_0258_CANDY_FACTORY,         STR_027B_CONSTRUCT_CANDY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    29,    40, STR_025B_TOY_SHOP,              STR_027E_CONSTRUCT_TOY_SHOP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_025C_TOY_FACTORY,           STR_027F_CONSTRUCT_TOY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_025E_FIZZY_DRINK_FACTORY,   STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    71,    82, STR_0257_COTTON_CANDY_FOREST,   STR_CONSTRUCT_COTTON_CANDY_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    84,    95, STR_0259_BATTERY_FARM,          STR_CONSTRUCT_BATTERY_FARM_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    97,   108, STR_025A_COLA_WELLS,            STR_CONSTRUCT_COLA_WELLS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   110,   121, STR_025D_PLASTIC_FOUNTAINS,     STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   123,   134, STR_025F_BUBBLE_GENERATOR,      STR_CONSTRUCT_BUBBLE_GENERATOR_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   136,   147, STR_0260_TOFFEE_QUARRY,         STR_CONSTRUCT_TOFFEE_QUARRY_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   149,   160, STR_0261_SUGAR_MINE,            STR_CONSTRUCT_SUGAR_MINE_TIP},
+{   WIDGETS_END},
+};
+
+
+static const WindowDesc _build_industry_land0_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 116,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land0_widgets,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land1_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 116,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land1_widgets,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land2_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 116,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land2_widgets,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land3_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 116,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land3_widgets,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land0_desc_extra = {
+	WDP_AUTO, WDP_AUTO, 170, 188,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land0_widgets_extra,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land1_desc_extra = {
+	WDP_AUTO, WDP_AUTO, 170, 175,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land1_widgets_extra,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land2_desc_extra = {
+	WDP_AUTO, WDP_AUTO, 170, 201,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land2_widgets_extra,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc _build_industry_land3_desc_extra = {
+	WDP_AUTO, WDP_AUTO, 170, 188,
+	WC_BUILD_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_industry_land3_widgets_extra,
+	BuildIndustryWndProc
+};
+
+static const WindowDesc * const _industry_window_desc[2][4] = {
+	{
+	&_build_industry_land0_desc,
+	&_build_industry_land1_desc,
+	&_build_industry_land2_desc,
+	&_build_industry_land3_desc,
+	},
+	{
+	&_build_industry_land0_desc_extra,
+	&_build_industry_land1_desc_extra,
+	&_build_industry_land2_desc_extra,
+	&_build_industry_land3_desc_extra,
+	},
+};
+
+void ShowBuildIndustryWindow(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+	AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt_ptr->landscape],0);
+}
+
+static inline bool isProductionMinimum(const Industry *i, int pt) {
+	return i->production_rate[pt] == 1;
+}
+
+static inline bool isProductionMaximum(const Industry *i, int pt) {
+	return i->production_rate[pt] == 255;
+}
+
+static inline bool IsProductionAlterable(const Industry *i)
+{
+	return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) &&
+		     (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES));
+}
+
+static void IndustryViewWndProc(Window *w, WindowEvent *e)
+{
+	// WP(w,vp2_d).data_1 is for the editbox line
+	// WP(w,vp2_d).data_2 is for the clickline
+	// WP(w,vp2_d).data_3 is for the click pos (left or right)
+
+	switch (e->event) {
+	case WE_PAINT: {
+		const Industry *i = GetIndustry(w->window_number);
+
+		SetDParam(0, w->window_number);
+		DrawWindowWidgets(w);
+
+		if (i->accepts_cargo[0] != CT_INVALID) {
+			StringID str;
+
+			SetDParam(0, _cargoc.names_s[i->accepts_cargo[0]]);
+			str = STR_4827_REQUIRES;
+			if (i->accepts_cargo[1] != CT_INVALID) {
+				SetDParam(1, _cargoc.names_s[i->accepts_cargo[1]]);
+				str = STR_4828_REQUIRES;
+				if (i->accepts_cargo[2] != CT_INVALID) {
+					SetDParam(2, _cargoc.names_s[i->accepts_cargo[2]]);
+					str = STR_4829_REQUIRES;
+				}
+			}
+			DrawString(2, 107, str, 0);
+		}
+
+		if (i->produced_cargo[0] != CT_INVALID) {
+			DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0);
+
+			SetDParam(0, i->produced_cargo[0]);
+			SetDParam(1, i->total_production[0]);
+
+			SetDParam(2, i->pct_transported[0] * 100 >> 8);
+			DrawString(4 + (IsProductionAlterable(i) ? 30 : 0), 127, STR_482B_TRANSPORTED, 0);
+			// Let's put out those buttons..
+			if (IsProductionAlterable(i)) {
+				DrawArrowButtons(5, 127, 3, (WP(w,vp2_d).data_2 == 1) ? WP(w,vp2_d).data_3 : 0,
+						!isProductionMinimum(i, 0), !isProductionMaximum(i, 0));
+			}
+
+			if (i->produced_cargo[1] != CT_INVALID) {
+				SetDParam(0, i->produced_cargo[1]);
+				SetDParam(1, i->total_production[1]);
+				SetDParam(2, i->pct_transported[1] * 100 >> 8);
+				DrawString(4 + (IsProductionAlterable(i) ? 30 : 0), 137, STR_482B_TRANSPORTED, 0);
+				// Let's put out those buttons..
+				if (IsProductionAlterable(i)) {
+					DrawArrowButtons(5, 137, 3, (WP(w,vp2_d).data_2 == 2) ? WP(w,vp2_d).data_3 : 0,
+						!isProductionMinimum(i, 1), !isProductionMaximum(i, 1));
+				}
+			}
+		}
+
+		DrawWindowViewport(w);
+		}
+		break;
+
+	case WE_CLICK: {
+		Industry *i;
+
+		switch (e->we.click.widget) {
+		case 5: {
+			int line, x;
+
+			i = GetIndustry(w->window_number);
+
+			// We should work if needed..
+			if (!IsProductionAlterable(i)) return;
+
+			x = e->we.click.pt.x;
+			line = (e->we.click.pt.y - 127) / 10;
+			if (e->we.click.pt.y >= 127 && IS_INT_INSIDE(line, 0, 2) && i->produced_cargo[line] != CT_INVALID) {
+				if (IS_INT_INSIDE(x, 5, 25) ) {
+					/* Clicked buttons, decrease or increase production */
+					if (x < 15) {
+						if (isProductionMinimum(i, line)) return;
+						i->production_rate[line] = maxu(i->production_rate[line] / 2, 1);
+					} else {
+						if (isProductionMaximum(i, line)) return;
+						i->production_rate[line] = minu(i->production_rate[line] * 2, 255);
+					}
+
+					UpdateIndustryProduction(i);
+					SetWindowDirty(w);
+					w->flags4 |= 5 << WF_TIMEOUT_SHL;
+					WP(w,vp2_d).data_2 = line+1;
+					WP(w,vp2_d).data_3 = (x < 15 ? 1 : 2);
+				} else if (IS_INT_INSIDE(x, 34, 160)) {
+					// clicked the text
+					WP(w,vp2_d).data_1 = line;
+					SetDParam(0, i->production_rate[line] * 8);
+					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_GAME_PRODUCTION, 10, 100, w, CS_ALPHANUMERAL);
+				}
+			}
+		} break;
+		case 6:
+			i = GetIndustry(w->window_number);
+			ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1));
+		}	break;
+
+		}
+		break;
+	case WE_TIMEOUT:
+		WP(w,vp2_d).data_2 = 0;
+		WP(w,vp2_d).data_3 = 0;
+		SetWindowDirty(w);
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			Industry* i = GetIndustry(w->window_number);
+			int line = WP(w,vp2_d).data_1;
+
+			i->production_rate[line] = clampu(atoi(e->we.edittext.str), 0, 255);
+			UpdateIndustryProduction(i);
+			SetWindowDirty(w);
+		}
+	}
+}
+
+static void UpdateIndustryProduction(Industry *i)
+{
+	if (i->produced_cargo[0] != CT_INVALID)
+		i->total_production[0] = 8 * i->production_rate[0];
+
+	if (i->produced_cargo[1] != CT_INVALID)
+		i->total_production[1] = 8 * i->production_rate[1];
+}
+
+static const Widget _industry_view_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     9,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     9,    11,   247,     0,    13, STR_4801,          STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     9,   248,   259,     0,    13, 0x0,               STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,     9,     0,   259,    14,   105, 0x0,               STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,     9,     2,   257,    16,   103, 0x0,               STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     9,     0,   259,   106,   147, 0x0,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     9,     0,   129,   148,   159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
+{      WWT_PANEL,   RESIZE_NONE,     9,   130,   259,   148,   159, 0x0,               STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _industry_view_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 160,
+	WC_INDUSTRY_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_industry_view_widgets,
+	IndustryViewWndProc
+};
+
+void ShowIndustryViewWindow(int industry)
+{
+	Window *w = AllocateWindowDescFront(&_industry_view_desc, industry);
+
+	if (w != NULL) {
+		w->flags4 |= WF_DISABLE_VP_SCROLL;
+		WP(w,vp2_d).data_1 = 0;
+		WP(w,vp2_d).data_2 = 0;
+		WP(w,vp2_d).data_3 = 0;
+		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), 1);
+	}
+}
+
+static const Widget _industry_directory_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   495,     0,    13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    13,   496,   507,     0,    13, 0x0,                     STR_STICKY_BUTTON},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,   100,    14,    25, STR_SORT_BY_NAME,        STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   101,   200,    14,    25, STR_SORT_BY_TYPE,        STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   201,   300,    14,    25, STR_SORT_BY_PRODUCTION,  STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   301,   400,    14,    25, STR_SORT_BY_TRANSPORTED, STR_SORT_ORDER_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    13,   401,   495,    14,    25, 0x0,                     STR_NULL},
+{      WWT_PANEL, RESIZE_BOTTOM,    13,     0,   495,    26,   189, 0x0,                     STR_200A_TOWN_NAMES_CLICK_ON_NAME},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    13,   496,   507,    14,   177, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{  WWT_RESIZEBOX,     RESIZE_TB,    13,   496,   507,   178,   189, 0x0,                     STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static uint _num_industry_sort;
+
+static char _bufcache[96];
+static const Industry* _last_industry;
+
+static byte _industry_sort_order;
+
+static int CDECL GeneralIndustrySorter(const void *a, const void *b)
+{
+	const Industry* i = *(const Industry**)a;
+	const Industry* j = *(const Industry**)b;
+	int r;
+
+	switch (_industry_sort_order >> 1) {
+		default: NOT_REACHED();
+		case 0: /* Sort by Name (handled later) */
+			r = 0;
+			break;
+
+		case 1: /* Sort by Type */
+			r = i->type - j->type;
+			break;
+
+		case 2: /* Sort by Production */
+			if (i->produced_cargo[0] == CT_INVALID) {
+				r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
+			} else {
+				if (j->produced_cargo[0] == CT_INVALID) {
+					r = 1;
+				} else {
+					r =
+						(i->total_production[0] + i->total_production[1]) -
+						(j->total_production[0] + j->total_production[1]);
+				}
+			}
+			break;
+
+		case 3: /* Sort by transported fraction */
+			if (i->produced_cargo[0] == CT_INVALID) {
+				r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
+			} else {
+				if (j->produced_cargo[0] == CT_INVALID) {
+					r = 1;
+				} else {
+					int pi;
+					int pj;
+
+					pi = i->pct_transported[0] * 100 >> 8;
+					if (i->produced_cargo[1] != CT_INVALID) {
+						int p = i->pct_transported[1] * 100 >> 8;
+						if (p < pi) pi = p;
+					}
+
+					pj = j->pct_transported[0] * 100 >> 8;
+					if (j->produced_cargo[1] != CT_INVALID) {
+						int p = j->pct_transported[1] * 100 >> 8;
+						if (p < pj) pj = p;
+					}
+
+					r = pi - pj;
+				}
+			}
+			break;
+	}
+
+	// default to string sorting if they are otherwise equal
+	if (r == 0) {
+		char buf1[96];
+
+		SetDParam(0, i->town->index);
+		GetString(buf1, STR_TOWN, lastof(buf1));
+
+		if (j != _last_industry) {
+			_last_industry = j;
+			SetDParam(0, j->town->index);
+			GetString(_bufcache, STR_TOWN, lastof(_bufcache));
+		}
+		r = strcmp(buf1, _bufcache);
+	}
+
+	if (_industry_sort_order & 1) r = -r;
+	return r;
+}
+
+static void MakeSortedIndustryList(void)
+{
+	const Industry* i;
+	int n = 0;
+
+	/* Don't attempt a sort if there are no industries */
+	if (GetNumIndustries() == 0) return;
+
+	/* Create array for sorting */
+	_industry_sort = realloc((void *)_industry_sort, (GetMaxIndustryIndex() + 1) * sizeof(_industry_sort[0]));
+	if (_industry_sort == NULL) error("Could not allocate memory for the industry-sorting-list");
+
+	FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
+
+	_num_industry_sort = n;
+	_last_industry = NULL; // used for "cache"
+
+	qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
+
+	DEBUG(misc, 3, "Resorting industries list");
+}
+
+
+static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int n;
+		uint p;
+		static const uint16 _indicator_positions[4] = {88, 187, 284, 387};
+
+		if (_industry_sort_dirty) {
+			_industry_sort_dirty = false;
+			MakeSortedIndustryList();
+		}
+
+		SetVScrollCount(w, _num_industry_sort);
+
+		DrawWindowWidgets(w);
+		DoDrawString(_industry_sort_order & 1 ? DOWNARROW : UPARROW, _indicator_positions[_industry_sort_order>>1], 15, 0x10);
+
+		p = w->vscroll.pos;
+		n = 0;
+
+		while (p < _num_industry_sort) {
+			const Industry* i = _industry_sort[p];
+
+			SetDParam(0, i->index);
+			if (i->produced_cargo[0] != CT_INVALID) {
+				SetDParam(1, i->produced_cargo[0]);
+				SetDParam(2, i->total_production[0]);
+
+				if (i->produced_cargo[1] != CT_INVALID) {
+					SetDParam(3, i->produced_cargo[1]);
+					SetDParam(4, i->total_production[1]);
+					SetDParam(5, i->pct_transported[0] * 100 >> 8);
+					SetDParam(6, i->pct_transported[1] * 100 >> 8);
+					DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0);
+				} else {
+					SetDParam(3, i->pct_transported[0] * 100 >> 8);
+					DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM, 0);
+				}
+			} else {
+				DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_NOPROD, 0);
+			}
+			p++;
+			if (++n == w->vscroll.cap) break;
+		}
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: {
+			_industry_sort_order = _industry_sort_order==0 ? 1 : 0;
+			_industry_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 4: {
+			_industry_sort_order = _industry_sort_order==2 ? 3 : 2;
+			_industry_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 5: {
+			_industry_sort_order = _industry_sort_order==4 ? 5 : 4;
+			_industry_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 6: {
+			_industry_sort_order = _industry_sort_order==6 ? 7 : 6;
+			_industry_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 8: {
+			int y = (e->we.click.pt.y - 28) / 10;
+			uint16 p;
+
+			if (!IS_INT_INSIDE(y, 0, w->vscroll.cap)) return;
+			p = y + w->vscroll.pos;
+			if (p < _num_industry_sort) {
+				ScrollMainWindowToTile(_industry_sort[p]->xy);
+			}
+		} break;
+		}
+		break;
+
+	case WE_4:
+		SetWindowDirty(w);
+		break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 10;
+		break;
+	}
+}
+
+
+/* Industry List */
+static const WindowDesc _industry_directory_desc = {
+	WDP_AUTO, WDP_AUTO, 508, 190,
+	WC_INDUSTRY_DIRECTORY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_industry_directory_widgets,
+	IndustryDirectoryWndProc
+};
+
+
+void ShowIndustryDirectory(void)
+{
+	Window *w = AllocateWindowDescFront(&_industry_directory_desc, 0);
+
+	if (w != NULL) {
+		w->vscroll.cap = 16;
+		w->resize.height = w->height - 6 * 10; // minimum 10 items
+		w->resize.step_height = 10;
+		SetWindowDirty(w);
+	}
+}
deleted file mode 100644
--- a/src/intro_gui.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "functions.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "player.h"
-#include "network/network.h"
-#include "variables.h"
-#include "settings.h"
-#include "heightmap.h"
-#include "genworld.h"
-#include "network/network_gui.h"
-#include "newgrf.h"
-
-static const Widget _select_game_widgets[] = {
-{    WWT_CAPTION, RESIZE_NONE, 13,   0, 335,   0,  13, STR_0307_OPENTTD,         STR_NULL},
-{      WWT_PANEL, RESIZE_NONE, 13,   0, 335,  14, 194, 0x0,                      STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  22,  33, STR_0140_NEW_GAME,        STR_02FB_START_A_NEW_GAME},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  22,  33, STR_0141_LOAD_GAME,       STR_02FC_LOAD_A_SAVED_GAME},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  40,  51, STR_029A_PLAY_SCENARIO,   STR_0303_START_A_NEW_GAME_USING},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  40,  51, STR_PLAY_HEIGHTMAP,       STR_PLAY_HEIGHTMAP_HINT},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  58,  69, STR_0220_CREATE_SCENARIO, STR_02FE_CREATE_A_CUSTOMIZED_GAME},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  58,  69, STR_MULTIPLAYER,          STR_0300_SELECT_MULTIPLAYER_GAME},
-
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  77, 131, SPR_SELECT_TEMPERATE,     STR_030E_SELECT_TEMPERATE_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  77, 131, SPR_SELECT_SUB_ARCTIC,    STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  77, 131, SPR_SELECT_SUB_TROPICAL,  STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
-{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  77, 131, SPR_SELECT_TOYLAND,       STR_0311_SELECT_TOYLAND_LANDSCAPE},
-
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167, 139, 150, STR_0148_GAME_OPTIONS,    STR_0301_DISPLAY_GAME_OPTIONS},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 139, 150, STR_01FE_DIFFICULTY,      STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167, 157, 168, STR_CONFIG_PATCHES,       STR_CONFIG_PATCHES_TIP},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 157, 168, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL},
-
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 104, 231, 175, 186, STR_0304_QUIT,            STR_0305_QUIT_OPENTTD},
-{   WIDGETS_END},
-};
-
-static inline void SetNewLandscapeType(byte landscape)
-{
-	_opt_newgame.landscape = landscape;
-	InvalidateWindowClasses(WC_SELECT_GAME);
-}
-
-static void SelectGameWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _opt_newgame.landscape + 8); break;
-
-	case WE_PAINT:
-		SetWindowWidgetLoweredState(w, 8,  _opt_newgame.landscape == LT_NORMAL);
-		SetWindowWidgetLoweredState(w, 9,  _opt_newgame.landscape == LT_HILLY);
-		SetWindowWidgetLoweredState(w, 10, _opt_newgame.landscape == LT_DESERT);
-		SetWindowWidgetLoweredState(w, 11, _opt_newgame.landscape == LT_CANDY);
-		SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: ShowGenerateLandscape(); break;
-		case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
-		case 4: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
-		case 5: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
-		case 6: ShowCreateScenario(); break;
-		case 7:
-			if (!_network_available) {
-				ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
-			} else {
-				ShowNetworkGameWindow();
-			}
-			break;
-		case 8: case 9: case 10: case 11:
-			RaiseWindowWidget(w, _opt_newgame.landscape + 8);
-			SetNewLandscapeType(e->we.click.widget - 8);
-			break;
-		case 12: ShowGameOptions(); break;
-		case 13: ShowGameDifficulty(); break;
-		case 14: ShowPatchesSelection(); break;
-		case 15: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
-		case 16: HandleExitGameRequest(); break;
-		}
-		break;
-	}
-}
-
-static const WindowDesc _select_game_desc = {
-	WDP_CENTER, WDP_CENTER, 336, 195,
-	WC_SELECT_GAME,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_select_game_widgets,
-	SelectGameWndProc
-};
-
-void ShowSelectGameWindow(void)
-{
-	AllocateWindowDesc(&_select_game_desc);
-}
-
-static void AskExitGameCallback(Window *w, bool confirmed)
-{
-	if (confirmed) _exit_game = true;
-}
-
-void AskExitGame(void)
-{
-#if defined(_WIN32)
-		SetDParam(0, STR_0133_WINDOWS);
-#elif defined(__APPLE__)
-		SetDParam(0, STR_0135_OSX);
-#elif defined(__BEOS__)
-		SetDParam(0, STR_OSNAME_BEOS);
-#elif defined(__MORPHOS__)
-		SetDParam(0, STR_OSNAME_MORPHOS);
-#elif defined(__AMIGA__)
-		SetDParam(0, STR_OSNAME_AMIGAOS);
-#elif defined(__OS2__)
-		SetDParam(0, STR_OSNAME_OS2);
-#else
-		SetDParam(0, STR_0134_UNIX);
-#endif
-	ShowQuery(
-		STR_00C7_QUIT,
-		STR_00CA_ARE_YOU_SURE_YOU_WANT_TO,
-		NULL,
-		AskExitGameCallback
-	);
-}
-
-
-static void AskExitToGameMenuCallback(Window *w, bool confirmed)
-{
-	if (confirmed) _switch_mode = SM_MENU;
-}
-
-void AskExitToGameMenu(void)
-{
-	ShowQuery(
-		STR_0161_QUIT_GAME,
-		(_game_mode != GM_EDITOR) ? STR_ABANDON_GAME_QUERY : STR_QUIT_SCENARIO_QUERY,
-		NULL,
-		AskExitToGameMenuCallback
-	);
-}
new file mode 100644
--- /dev/null
+++ b/src/intro_gui.cpp
@@ -0,0 +1,149 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "functions.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "player.h"
+#include "network/network.h"
+#include "variables.h"
+#include "settings.h"
+#include "heightmap.h"
+#include "genworld.h"
+#include "network/network_gui.h"
+#include "newgrf.h"
+
+static const Widget _select_game_widgets[] = {
+{    WWT_CAPTION, RESIZE_NONE, 13,   0, 335,   0,  13, STR_0307_OPENTTD,         STR_NULL},
+{      WWT_PANEL, RESIZE_NONE, 13,   0, 335,  14, 194, 0x0,                      STR_NULL},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  22,  33, STR_0140_NEW_GAME,        STR_02FB_START_A_NEW_GAME},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  22,  33, STR_0141_LOAD_GAME,       STR_02FC_LOAD_A_SAVED_GAME},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  40,  51, STR_029A_PLAY_SCENARIO,   STR_0303_START_A_NEW_GAME_USING},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  40,  51, STR_PLAY_HEIGHTMAP,       STR_PLAY_HEIGHTMAP_HINT},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167,  58,  69, STR_0220_CREATE_SCENARIO, STR_02FE_CREATE_A_CUSTOMIZED_GAME},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325,  58,  69, STR_MULTIPLAYER,          STR_0300_SELECT_MULTIPLAYER_GAME},
+
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  10,  86,  77, 131, SPR_SELECT_TEMPERATE,     STR_030E_SELECT_TEMPERATE_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12,  90, 166,  77, 131, SPR_SELECT_SUB_ARCTIC,    STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 170, 246,  77, 131, SPR_SELECT_SUB_TROPICAL,  STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
+{   WWT_IMGBTN_2, RESIZE_NONE, 12, 250, 326,  77, 131, SPR_SELECT_TOYLAND,       STR_0311_SELECT_TOYLAND_LANDSCAPE},
+
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167, 139, 150, STR_0148_GAME_OPTIONS,    STR_0301_DISPLAY_GAME_OPTIONS},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 139, 150, STR_01FE_DIFFICULTY,      STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12,  10, 167, 157, 168, STR_CONFIG_PATCHES,       STR_CONFIG_PATCHES_TIP},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 157, 168, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL},
+
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 104, 231, 175, 186, STR_0304_QUIT,            STR_0305_QUIT_OPENTTD},
+{   WIDGETS_END},
+};
+
+static inline void SetNewLandscapeType(byte landscape)
+{
+	_opt_newgame.landscape = landscape;
+	InvalidateWindowClasses(WC_SELECT_GAME);
+}
+
+static void SelectGameWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _opt_newgame.landscape + 8); break;
+
+	case WE_PAINT:
+		SetWindowWidgetLoweredState(w, 8,  _opt_newgame.landscape == LT_NORMAL);
+		SetWindowWidgetLoweredState(w, 9,  _opt_newgame.landscape == LT_HILLY);
+		SetWindowWidgetLoweredState(w, 10, _opt_newgame.landscape == LT_DESERT);
+		SetWindowWidgetLoweredState(w, 11, _opt_newgame.landscape == LT_CANDY);
+		SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: ShowGenerateLandscape(); break;
+		case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+		case 4: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
+		case 5: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
+		case 6: ShowCreateScenario(); break;
+		case 7:
+			if (!_network_available) {
+				ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
+			} else {
+				ShowNetworkGameWindow();
+			}
+			break;
+		case 8: case 9: case 10: case 11:
+			RaiseWindowWidget(w, _opt_newgame.landscape + 8);
+			SetNewLandscapeType(e->we.click.widget - 8);
+			break;
+		case 12: ShowGameOptions(); break;
+		case 13: ShowGameDifficulty(); break;
+		case 14: ShowPatchesSelection(); break;
+		case 15: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
+		case 16: HandleExitGameRequest(); break;
+		}
+		break;
+	}
+}
+
+static const WindowDesc _select_game_desc = {
+	WDP_CENTER, WDP_CENTER, 336, 195,
+	WC_SELECT_GAME,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_select_game_widgets,
+	SelectGameWndProc
+};
+
+void ShowSelectGameWindow(void)
+{
+	AllocateWindowDesc(&_select_game_desc);
+}
+
+static void AskExitGameCallback(Window *w, bool confirmed)
+{
+	if (confirmed) _exit_game = true;
+}
+
+void AskExitGame(void)
+{
+#if defined(_WIN32)
+		SetDParam(0, STR_0133_WINDOWS);
+#elif defined(__APPLE__)
+		SetDParam(0, STR_0135_OSX);
+#elif defined(__BEOS__)
+		SetDParam(0, STR_OSNAME_BEOS);
+#elif defined(__MORPHOS__)
+		SetDParam(0, STR_OSNAME_MORPHOS);
+#elif defined(__AMIGA__)
+		SetDParam(0, STR_OSNAME_AMIGAOS);
+#elif defined(__OS2__)
+		SetDParam(0, STR_OSNAME_OS2);
+#else
+		SetDParam(0, STR_0134_UNIX);
+#endif
+	ShowQuery(
+		STR_00C7_QUIT,
+		STR_00CA_ARE_YOU_SURE_YOU_WANT_TO,
+		NULL,
+		AskExitGameCallback
+	);
+}
+
+
+static void AskExitToGameMenuCallback(Window *w, bool confirmed)
+{
+	if (confirmed) _switch_mode = SM_MENU;
+}
+
+void AskExitToGameMenu(void)
+{
+	ShowQuery(
+		STR_0161_QUIT_GAME,
+		(_game_mode != GM_EDITOR) ? STR_ABANDON_GAME_QUERY : STR_QUIT_SCENARIO_QUERY,
+		NULL,
+		AskExitToGameMenuCallback
+	);
+}
deleted file mode 100644
--- a/src/landscape.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "heightmap.h"
-#include "clear_map.h"
-#include "functions.h"
-#include "map.h"
-#include "player.h"
-#include "spritecache.h"
-#include "table/sprites.h"
-#include "tile.h"
-#include <stdarg.h>
-#include "viewport.h"
-#include "command.h"
-#include "vehicle.h"
-#include "variables.h"
-#include "void_map.h"
-#include "water_map.h"
-#include "tgp.h"
-#include "genworld.h"
-#include "heightmap.h"
-
-extern const TileTypeProcs
-	_tile_type_clear_procs,
-	_tile_type_rail_procs,
-	_tile_type_road_procs,
-	_tile_type_town_procs,
-	_tile_type_trees_procs,
-	_tile_type_station_procs,
-	_tile_type_water_procs,
-	_tile_type_dummy_procs,
-	_tile_type_industry_procs,
-	_tile_type_tunnelbridge_procs,
-	_tile_type_unmovable_procs;
-
-const TileTypeProcs * const _tile_type_procs[16] = {
-	&_tile_type_clear_procs,
-	&_tile_type_rail_procs,
-	&_tile_type_road_procs,
-	&_tile_type_town_procs,
-	&_tile_type_trees_procs,
-	&_tile_type_station_procs,
-	&_tile_type_water_procs,
-	&_tile_type_dummy_procs,
-	&_tile_type_industry_procs,
-	&_tile_type_tunnelbridge_procs,
-	&_tile_type_unmovable_procs,
-};
-
-/* landscape slope => sprite */
-const byte _tileh_to_sprite[32] = {
-	0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
-	0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
-};
-
-const byte _inclined_tileh[] = {
-	SLOPE_SW,  SLOPE_NW,  SLOPE_SW,  SLOPE_SE, SLOPE_NE, SLOPE_SE, SLOPE_NE, SLOPE_NW,
-	SLOPE_E,   SLOPE_N,   SLOPE_W,   SLOPE_S,
-	SLOPE_NWS, SLOPE_WSE, SLOPE_SEN, SLOPE_ENW
-};
-
-
-uint GetPartialZ(int x, int y, Slope corners)
-{
-	int z = 0;
-
-	switch (corners) {
-	case SLOPE_W:
-		if (x - y >= 0)
-			z = (x - y) >> 1;
-		break;
-
-	case SLOPE_S:
-		y^=0xF;
-		if ( (x - y) >= 0)
-			z = (x - y) >> 1;
-		break;
-
-	case SLOPE_SW:
-		z = (x>>1) + 1;
-		break;
-
-	case SLOPE_E:
-		if (y - x >= 0)
-			z = (y - x) >> 1;
-		break;
-
-	case SLOPE_EW:
-	case SLOPE_NS:
-	case SLOPE_ELEVATED:
-		z = 4;
-		break;
-
-	case SLOPE_SE:
-		z = (y>>1) + 1;
-		break;
-
-	case SLOPE_WSE:
-		z = 8;
-		y^=0xF;
-		if (x - y < 0)
-			z += (x - y) >> 1;
-		break;
-
-	case SLOPE_N:
-		y ^= 0xF;
-		if (y - x >= 0)
-			z = (y - x) >> 1;
-		break;
-
-	case SLOPE_NW:
-		z = (y^0xF)>>1;
-		break;
-
-	case SLOPE_NWS:
-		z = 8;
-		if (x - y < 0)
-			z += (x - y) >> 1;
-		break;
-
-	case SLOPE_NE:
-		z = (x^0xF)>>1;
-		break;
-
-	case SLOPE_ENW:
-		z = 8;
-		y ^= 0xF;
-		if (y - x < 0)
-			z += (y - x) >> 1;
-		break;
-
-	case SLOPE_SEN:
-		z = 8;
-		if (y - x < 0)
-			z += (y - x) >> 1;
-		break;
-
-	case SLOPE_STEEP_S:
-		z = 1 + ((x+y)>>1);
-		break;
-
-	case SLOPE_STEEP_W:
-		z = 1 + ((x+(y^0xF))>>1);
-		break;
-
-	case SLOPE_STEEP_N:
-		z = 1 + (((x^0xF)+(y^0xF))>>1);
-		break;
-
-	case SLOPE_STEEP_E:
-		z = 1 + (((x^0xF)+(y^0xF))>>1);
-		break;
-
-		default: break;
-	}
-
-	return z;
-}
-
-uint GetSlopeZ(int x, int y)
-{
-	TileIndex tile = TileVirtXY(x, y);
-
-	return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
-}
-
-
-static Slope GetFoundationSlope(TileIndex tile, uint* z)
-{
-	Slope tileh = GetTileSlope(tile, z);
-	Slope slope = _tile_type_procs[GetTileType(tile)]->get_slope_tileh_proc(tile, tileh);
-
-	// Flatter slope -> higher base height
-	if (slope < tileh) *z += TILE_HEIGHT;
-	return slope;
-}
-
-
-static bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
-{
-	uint z;
-	Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
-
-	return
-		(
-			z_here + (slope_here & SLOPE_N ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_N ? TILE_HEIGHT : 0) >
-			z      + (slope      & SLOPE_E ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_E ? TILE_HEIGHT : 0)
-		) || (
-			z_here + (slope_here & SLOPE_W ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_W ? TILE_HEIGHT : 0) >
-			z      + (slope      & SLOPE_S ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_S ? TILE_HEIGHT : 0)
-		);
-}
-
-
-static bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
-{
-	uint z;
-	Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
-
-	return
-		(
-			z_here + (slope_here & SLOPE_N ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_N ? TILE_HEIGHT : 0) >
-			z      + (slope      & SLOPE_W ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_W ? TILE_HEIGHT : 0)
-		) || (
-			z_here + (slope_here & SLOPE_E ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_E ? TILE_HEIGHT : 0) >
-			z      + (slope      & SLOPE_S ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_S ? TILE_HEIGHT : 0)
-		);
-}
-
-
-void DrawFoundation(TileInfo *ti, uint f)
-{
-	uint32 sprite_base = SPR_SLOPES_BASE - 15;
-	Slope slope;
-	uint z;
-
-	slope = GetFoundationSlope(ti->tile, &z);
-	if (!HasFoundationNW(ti->tile, slope, z)) sprite_base += 22;
-	if (!HasFoundationNE(ti->tile, slope, z)) sprite_base += 44;
-
-	if (IsSteepSlope(ti->tileh)) {
-		uint32 lower_base;
-
-		// Lower part of foundation
-		lower_base = sprite_base;
-		if (lower_base == SPR_SLOPES_BASE - 15) lower_base = SPR_FOUNDATION_BASE;
-		AddSortableSpriteToDraw(
-			lower_base + (ti->tileh & ~SLOPE_STEEP), ti->x, ti->y, 16, 16, 7, ti->z
-		);
-		ti->z += TILE_HEIGHT;
-		ti->tileh = _inclined_tileh[f - 15];
-		if (f < 15 + 8) {
-			// inclined
-			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 1, ti->z);
-			OffsetGroundSprite(31, 9);
-		} else if (f >= 15 + 8 + 4) {
-			// three corners raised
-			uint32 upper = sprite_base + 15 + (f - 15 - 8 - 4) * 2;
-
-			AddSortableSpriteToDraw(upper, ti->x, ti->y, 16, 16, 1, ti->z);
-			AddChildSpriteScreen(upper + 1, 31, 9);
-			OffsetGroundSprite(31, 9);
-		} else {
-			// one corner raised
-			OffsetGroundSprite(31, 1);
-		}
-	} else {
-		if (f < 15) {
-			// leveled foundation
-			// Use the original slope sprites if NW and NE borders should be visible
-			if (sprite_base  == SPR_SLOPES_BASE - 15) sprite_base = SPR_FOUNDATION_BASE;
-
-			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 7, ti->z);
-			ti->z += TILE_HEIGHT;
-			ti->tileh = SLOPE_FLAT;
-			OffsetGroundSprite(31, 1);
-		} else {
-			// inclined foundation
-			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 1, ti->z);
-			ti->tileh = _inclined_tileh[f - 15];
-			OffsetGroundSprite(31, 9);
-		}
-	}
-}
-
-void DoClearSquare(TileIndex tile)
-{
-	MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
-	MarkTileDirtyByTile(tile);
-}
-
-uint32 GetTileTrackStatus(TileIndex tile, TransportType mode)
-{
-	return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode);
-}
-
-void ChangeTileOwner(TileIndex tile, byte old_player, byte new_player)
-{
-	_tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_player, new_player);
-}
-
-void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac)
-{
-	memset(ac, 0, sizeof(AcceptedCargo));
-	_tile_type_procs[GetTileType(tile)]->get_accepted_cargo_proc(tile, ac);
-}
-
-void AnimateTile(TileIndex tile)
-{
-	_tile_type_procs[GetTileType(tile)]->animate_tile_proc(tile);
-}
-
-void ClickTile(TileIndex tile)
-{
-	_tile_type_procs[GetTileType(tile)]->click_tile_proc(tile);
-}
-
-void GetTileDesc(TileIndex tile, TileDesc *td)
-{
-	_tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
-}
-
-/** Clear a piece of landscape
- * @param tile tile to clear
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdLandscapeClear(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
-}
-
-/** Clear a big piece of landscape
- * @param tile end tile of area dragging
- * @param p1 start tile of area dragging
- * @param p2 unused
- */
-int32 CmdClearArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost, ret, money;
-	int ex;
-	int ey;
-	int sx,sy;
-	int x,y;
-	bool success = false;
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	// make sure sx,sy are smaller than ex,ey
-	ex = TileX(tile);
-	ey = TileY(tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-
-	money = GetAvailableMoneyForCommand();
-	cost = 0;
-
-	for (x = sx; x <= ex; ++x) {
-		for (y = sy; y <= ey; ++y) {
-			ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
-			if (CmdFailed(ret)) continue;
-			cost += ret;
-			success = true;
-
-			if (flags & DC_EXEC) {
-				if (ret > 0 && (money -= ret) < 0) {
-					_additional_cash_required = ret;
-					return cost - ret;
-				}
-				DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-
-				// draw explosion animation...
-				if ((x == sx || x == ex) && (y == sy || y == ey)) {
-					// big explosion in each corner, or small explosion for single tiles
-					CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
-						sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
-					);
-				}
-			}
-		}
-	}
-
-	return (success) ? cost : CMD_ERROR;
-}
-
-
-#define TILELOOP_BITS 4
-#define TILELOOP_SIZE (1 << TILELOOP_BITS)
-#define TILELOOP_ASSERTMASK ((TILELOOP_SIZE-1) + ((TILELOOP_SIZE-1) << MapLogX()))
-#define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
-
-void RunTileLoop(void)
-{
-	TileIndex tile;
-	uint count;
-
-	tile = _cur_tileloop_tile;
-
-	assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
-	count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
-	do {
-		_tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
-
-		if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
-			tile += TILELOOP_SIZE; /* no overflow */
-		} else {
-			tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
-		}
-	} while (--count);
-	assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
-
-	tile += 9;
-	if (tile & TILELOOP_CHKMASK)
-		tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
-	_cur_tileloop_tile = tile;
-}
-
-void InitializeLandscape(void)
-{
-	uint maxx = MapMaxX();
-	uint maxy = MapMaxY();
-	uint sizex = MapSizeX();
-	uint x;
-	uint y;
-
-	for (y = 0; y < maxy; y++) {
-		for (x = 0; x < maxx; x++) {
-			MakeClear(sizex * y + x, CLEAR_GRASS, 3);
-			SetTileHeight(sizex * y + x, 0);
-			_m[sizex * y + x].extra = 0;
-			ClearBridgeMiddle(sizex * y + x);
-		}
-		MakeVoid(sizex * y + x);
-	}
-	for (x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
-}
-
-void ConvertGroundTilesIntoWaterTiles(void)
-{
-	TileIndex tile;
-	uint z;
-	Slope slope;
-
-	for (tile = 0; tile < MapSize(); ++tile) {
-		slope = GetTileSlope(tile, &z);
-		if (IsTileType(tile, MP_CLEAR) && z == 0) {
-			/* Make both water for tiles at level 0
-			 * and make shore, as that looks much better
-			 * during the generation. */
-			switch (slope) {
-				case SLOPE_FLAT:
-					MakeWater(tile);
-					break;
-
-				case SLOPE_N:
-				case SLOPE_E:
-				case SLOPE_S:
-				case SLOPE_W:
-				case SLOPE_NW:
-				case SLOPE_SW:
-				case SLOPE_SE:
-				case SLOPE_NE:
-					MakeShore(tile);
-					break;
-
-				default:
-					break;
-			}
-		}
-	}
-}
-
-static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
-static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
-
-static void GenerateTerrain(int type, int flag)
-{
-	uint32 r;
-	uint x;
-	uint y;
-	uint w;
-	uint h;
-	const Sprite* template;
-	const byte *p;
-	Tile* tile;
-	byte direction;
-
-	r = Random();
-	template = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845);
-
-	x = r & MapMaxX();
-	y = (r >> MapLogX()) & MapMaxY();
-
-
-	if (x < 2 || y < 2) return;
-
-	direction = GB(r, 22, 2);
-	if (direction & 1) {
-		w = template->height;
-		h = template->width;
-	} else {
-		w = template->width;
-		h = template->height;
-	}
-	p = template->data;
-
-	if (flag & 4) {
-		uint xw = x * MapSizeY();
-		uint yw = y * MapSizeX();
-		uint bias = (MapSizeX() + MapSizeY()) * 16;
-
-		switch (flag & 3) {
-			case 0:
-				if (xw + yw > MapSize() - bias) return;
-				break;
-
-			case 1:
-				if (yw < xw + bias) return;
-				break;
-
-			case 2:
-				if (xw + yw < MapSize() + bias) return;
-				break;
-
-			case 3:
-				if (xw < yw + bias) return;
-				break;
-		}
-	}
-
-	if (x + w >= MapMaxX() - 1) return;
-	if (y + h >= MapMaxY() - 1) return;
-
-	tile = &_m[TileXY(x, y)];
-
-	switch (direction) {
-		case 0:
-			do {
-				Tile* tile_cur = tile;
-				uint w_cur;
-
-				for (w_cur = w; w_cur != 0; --w_cur) {
-					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
-					p++;
-					tile_cur++;
-				}
-				tile += TileDiffXY(0, 1);
-			} while (--h != 0);
-			break;
-
-		case 1:
-			do {
-				Tile* tile_cur = tile;
-				uint h_cur;
-
-				for (h_cur = h; h_cur != 0; --h_cur) {
-					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
-					p++;
-					tile_cur += TileDiffXY(0, 1);
-				}
-				tile++;
-			} while (--w != 0);
-			break;
-
-		case 2:
-			tile += TileDiffXY(w - 1, 0);
-			do {
-				Tile* tile_cur = tile;
-				uint w_cur;
-
-				for (w_cur = w; w_cur != 0; --w_cur) {
-					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
-					p++;
-					tile_cur--;
-				}
-				tile += TileDiffXY(0, 1);
-			} while (--h != 0);
-			break;
-
-		case 3:
-			tile += TileDiffXY(0, h - 1);
-			do {
-				Tile* tile_cur = tile;
-				uint h_cur;
-
-				for (h_cur = h; h_cur != 0; --h_cur) {
-					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
-					p++;
-					tile_cur -= TileDiffXY(0, 1);
-				}
-				tile++;
-			} while (--w != 0);
-			break;
-	}
-}
-
-
-#include "table/genland.h"
-
-static void CreateDesertOrRainForest(void)
-{
-	TileIndex tile;
-	TileIndex update_freq = MapSize() / 4;
-	const TileIndexDiffC *data;
-	uint i;
-
-	for (tile = 0; tile != MapSize(); ++tile) {
-		if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-		for (data = _make_desert_or_rainforest_data;
-				data != endof(_make_desert_or_rainforest_data); ++data) {
-			TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
-			if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break;
-		}
-		if (data == endof(_make_desert_or_rainforest_data))
-			SetTropicZone(tile, TROPICZONE_DESERT);
-	}
-
-	for (i = 0; i != 256; i++) {
-		if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-		RunTileLoop();
-	}
-
-	for (tile = 0; tile != MapSize(); ++tile) {
-		if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-		for (data = _make_desert_or_rainforest_data;
-				data != endof(_make_desert_or_rainforest_data); ++data) {
-			TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
-			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
-		}
-		if (data == endof(_make_desert_or_rainforest_data))
-			SetTropicZone(tile, TROPICZONE_RAINFOREST);
-	}
-}
-
-void GenerateLandscape(byte mode)
-{
-	const int gwp_desert_amount = 4 + 8;
-	uint i;
-	uint flag;
-	uint32 r;
-
-	if (mode == GW_HEIGHTMAP) {
-		SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_DESERT) ? 1 + gwp_desert_amount : 1);
-		LoadHeightmap(_file_to_saveload.name);
-		IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-	} else if (_patches.land_generator == LG_TERRAGENESIS) {
-		SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_DESERT) ? 3 + gwp_desert_amount : 3);
-		GenerateTerrainPerlin();
-	} else {
-		switch (_opt.landscape) {
-			case LT_HILLY:
-				SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
-
-				for (i = ScaleByMapSize((Random() & 0x7F) + 950); i != 0; --i) {
-					GenerateTerrain(2, 0);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-				r = Random();
-				flag = GB(r, 0, 2) | 4;
-				for (i = ScaleByMapSize(GB(r, 16, 7) + 450); i != 0; --i) {
-					GenerateTerrain(4, flag);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-				break;
-
-			case LT_DESERT:
-				SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
-
-				for (i = ScaleByMapSize((Random() & 0x7F) + 170); i != 0; --i) {
-					GenerateTerrain(0, 0);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-				r = Random();
-				flag = GB(r, 0, 2) | 4;
-				for (i = ScaleByMapSize(GB(r, 16, 8) + 1700); i != 0; --i) {
-					GenerateTerrain(0, flag);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-				flag ^= 2;
-
-				for (i = ScaleByMapSize((Random() & 0x7F) + 410); i != 0; --i) {
-					GenerateTerrain(3, flag);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-				break;
-
-			default:
-				SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
-
-				i = ScaleByMapSize((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes) * 256 + 100);
-				for (; i != 0; --i) {
-					GenerateTerrain(_opt.diff.terrain_type, 0);
-				}
-				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-				break;
-		}
-	}
-
-	ConvertGroundTilesIntoWaterTiles();
-
-	if (_opt.landscape == LT_DESERT) CreateDesertOrRainForest();
-}
-
-void OnTick_Town(void);
-void OnTick_Trees(void);
-void OnTick_Station(void);
-void OnTick_Industry(void);
-
-void OnTick_Players(void);
-void OnTick_Train(void);
-
-void CallLandscapeTick(void)
-{
-	OnTick_Town();
-	OnTick_Trees();
-	OnTick_Station();
-	OnTick_Industry();
-
-	OnTick_Players();
-	OnTick_Train();
-}
-
-TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
-{
-	int rn = rng;
-	uint32 r = Random();
-
-	return TILE_MASK(TileXY(
-		TileX(a) + (GB(r, 0, 8) * rn * 2 >> 8) - rn,
-		TileY(a) + (GB(r, 8, 8) * rn * 2 >> 8) - rn
-	));
-}
-
-bool IsValidTile(TileIndex tile)
-{
-	return (tile < MapSizeX() * MapMaxY() && TileX(tile) != MapMaxX());
-}
new file mode 100644
--- /dev/null
+++ b/src/landscape.cpp
@@ -0,0 +1,731 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "heightmap.h"
+#include "clear_map.h"
+#include "functions.h"
+#include "map.h"
+#include "player.h"
+#include "spritecache.h"
+#include "table/sprites.h"
+#include "tile.h"
+#include <stdarg.h>
+#include "viewport.h"
+#include "command.h"
+#include "vehicle.h"
+#include "variables.h"
+#include "void_map.h"
+#include "water_map.h"
+#include "tgp.h"
+#include "genworld.h"
+#include "heightmap.h"
+
+extern const TileTypeProcs
+	_tile_type_clear_procs,
+	_tile_type_rail_procs,
+	_tile_type_road_procs,
+	_tile_type_town_procs,
+	_tile_type_trees_procs,
+	_tile_type_station_procs,
+	_tile_type_water_procs,
+	_tile_type_dummy_procs,
+	_tile_type_industry_procs,
+	_tile_type_tunnelbridge_procs,
+	_tile_type_unmovable_procs;
+
+const TileTypeProcs * const _tile_type_procs[16] = {
+	&_tile_type_clear_procs,
+	&_tile_type_rail_procs,
+	&_tile_type_road_procs,
+	&_tile_type_town_procs,
+	&_tile_type_trees_procs,
+	&_tile_type_station_procs,
+	&_tile_type_water_procs,
+	&_tile_type_dummy_procs,
+	&_tile_type_industry_procs,
+	&_tile_type_tunnelbridge_procs,
+	&_tile_type_unmovable_procs,
+};
+
+/* landscape slope => sprite */
+const byte _tileh_to_sprite[32] = {
+	0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
+	0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
+};
+
+const byte _inclined_tileh[] = {
+	SLOPE_SW,  SLOPE_NW,  SLOPE_SW,  SLOPE_SE, SLOPE_NE, SLOPE_SE, SLOPE_NE, SLOPE_NW,
+	SLOPE_E,   SLOPE_N,   SLOPE_W,   SLOPE_S,
+	SLOPE_NWS, SLOPE_WSE, SLOPE_SEN, SLOPE_ENW
+};
+
+
+uint GetPartialZ(int x, int y, Slope corners)
+{
+	int z = 0;
+
+	switch (corners) {
+	case SLOPE_W:
+		if (x - y >= 0)
+			z = (x - y) >> 1;
+		break;
+
+	case SLOPE_S:
+		y^=0xF;
+		if ( (x - y) >= 0)
+			z = (x - y) >> 1;
+		break;
+
+	case SLOPE_SW:
+		z = (x>>1) + 1;
+		break;
+
+	case SLOPE_E:
+		if (y - x >= 0)
+			z = (y - x) >> 1;
+		break;
+
+	case SLOPE_EW:
+	case SLOPE_NS:
+	case SLOPE_ELEVATED:
+		z = 4;
+		break;
+
+	case SLOPE_SE:
+		z = (y>>1) + 1;
+		break;
+
+	case SLOPE_WSE:
+		z = 8;
+		y^=0xF;
+		if (x - y < 0)
+			z += (x - y) >> 1;
+		break;
+
+	case SLOPE_N:
+		y ^= 0xF;
+		if (y - x >= 0)
+			z = (y - x) >> 1;
+		break;
+
+	case SLOPE_NW:
+		z = (y^0xF)>>1;
+		break;
+
+	case SLOPE_NWS:
+		z = 8;
+		if (x - y < 0)
+			z += (x - y) >> 1;
+		break;
+
+	case SLOPE_NE:
+		z = (x^0xF)>>1;
+		break;
+
+	case SLOPE_ENW:
+		z = 8;
+		y ^= 0xF;
+		if (y - x < 0)
+			z += (y - x) >> 1;
+		break;
+
+	case SLOPE_SEN:
+		z = 8;
+		if (y - x < 0)
+			z += (y - x) >> 1;
+		break;
+
+	case SLOPE_STEEP_S:
+		z = 1 + ((x+y)>>1);
+		break;
+
+	case SLOPE_STEEP_W:
+		z = 1 + ((x+(y^0xF))>>1);
+		break;
+
+	case SLOPE_STEEP_N:
+		z = 1 + (((x^0xF)+(y^0xF))>>1);
+		break;
+
+	case SLOPE_STEEP_E:
+		z = 1 + (((x^0xF)+(y^0xF))>>1);
+		break;
+
+		default: break;
+	}
+
+	return z;
+}
+
+uint GetSlopeZ(int x, int y)
+{
+	TileIndex tile = TileVirtXY(x, y);
+
+	return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
+}
+
+
+static Slope GetFoundationSlope(TileIndex tile, uint* z)
+{
+	Slope tileh = GetTileSlope(tile, z);
+	Slope slope = _tile_type_procs[GetTileType(tile)]->get_slope_tileh_proc(tile, tileh);
+
+	// Flatter slope -> higher base height
+	if (slope < tileh) *z += TILE_HEIGHT;
+	return slope;
+}
+
+
+static bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
+{
+	uint z;
+	Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
+
+	return
+		(
+			z_here + (slope_here & SLOPE_N ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_N ? TILE_HEIGHT : 0) >
+			z      + (slope      & SLOPE_E ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_E ? TILE_HEIGHT : 0)
+		) || (
+			z_here + (slope_here & SLOPE_W ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_W ? TILE_HEIGHT : 0) >
+			z      + (slope      & SLOPE_S ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_S ? TILE_HEIGHT : 0)
+		);
+}
+
+
+static bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
+{
+	uint z;
+	Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
+
+	return
+		(
+			z_here + (slope_here & SLOPE_N ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_N ? TILE_HEIGHT : 0) >
+			z      + (slope      & SLOPE_W ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_W ? TILE_HEIGHT : 0)
+		) || (
+			z_here + (slope_here & SLOPE_E ? TILE_HEIGHT : 0) + (slope_here == SLOPE_STEEP_E ? TILE_HEIGHT : 0) >
+			z      + (slope      & SLOPE_S ? TILE_HEIGHT : 0) + (slope      == SLOPE_STEEP_S ? TILE_HEIGHT : 0)
+		);
+}
+
+
+void DrawFoundation(TileInfo *ti, uint f)
+{
+	uint32 sprite_base = SPR_SLOPES_BASE - 15;
+	Slope slope;
+	uint z;
+
+	slope = GetFoundationSlope(ti->tile, &z);
+	if (!HasFoundationNW(ti->tile, slope, z)) sprite_base += 22;
+	if (!HasFoundationNE(ti->tile, slope, z)) sprite_base += 44;
+
+	if (IsSteepSlope(ti->tileh)) {
+		uint32 lower_base;
+
+		// Lower part of foundation
+		lower_base = sprite_base;
+		if (lower_base == SPR_SLOPES_BASE - 15) lower_base = SPR_FOUNDATION_BASE;
+		AddSortableSpriteToDraw(
+			lower_base + (ti->tileh & ~SLOPE_STEEP), ti->x, ti->y, 16, 16, 7, ti->z
+		);
+		ti->z += TILE_HEIGHT;
+		ti->tileh = _inclined_tileh[f - 15];
+		if (f < 15 + 8) {
+			// inclined
+			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 1, ti->z);
+			OffsetGroundSprite(31, 9);
+		} else if (f >= 15 + 8 + 4) {
+			// three corners raised
+			uint32 upper = sprite_base + 15 + (f - 15 - 8 - 4) * 2;
+
+			AddSortableSpriteToDraw(upper, ti->x, ti->y, 16, 16, 1, ti->z);
+			AddChildSpriteScreen(upper + 1, 31, 9);
+			OffsetGroundSprite(31, 9);
+		} else {
+			// one corner raised
+			OffsetGroundSprite(31, 1);
+		}
+	} else {
+		if (f < 15) {
+			// leveled foundation
+			// Use the original slope sprites if NW and NE borders should be visible
+			if (sprite_base  == SPR_SLOPES_BASE - 15) sprite_base = SPR_FOUNDATION_BASE;
+
+			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 7, ti->z);
+			ti->z += TILE_HEIGHT;
+			ti->tileh = SLOPE_FLAT;
+			OffsetGroundSprite(31, 1);
+		} else {
+			// inclined foundation
+			AddSortableSpriteToDraw(sprite_base + f, ti->x, ti->y, 16, 16, 1, ti->z);
+			ti->tileh = _inclined_tileh[f - 15];
+			OffsetGroundSprite(31, 9);
+		}
+	}
+}
+
+void DoClearSquare(TileIndex tile)
+{
+	MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
+	MarkTileDirtyByTile(tile);
+}
+
+uint32 GetTileTrackStatus(TileIndex tile, TransportType mode)
+{
+	return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode);
+}
+
+void ChangeTileOwner(TileIndex tile, byte old_player, byte new_player)
+{
+	_tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_player, new_player);
+}
+
+void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac)
+{
+	memset(ac, 0, sizeof(AcceptedCargo));
+	_tile_type_procs[GetTileType(tile)]->get_accepted_cargo_proc(tile, ac);
+}
+
+void AnimateTile(TileIndex tile)
+{
+	_tile_type_procs[GetTileType(tile)]->animate_tile_proc(tile);
+}
+
+void ClickTile(TileIndex tile)
+{
+	_tile_type_procs[GetTileType(tile)]->click_tile_proc(tile);
+}
+
+void GetTileDesc(TileIndex tile, TileDesc *td)
+{
+	_tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
+}
+
+/** Clear a piece of landscape
+ * @param tile tile to clear
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdLandscapeClear(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
+}
+
+/** Clear a big piece of landscape
+ * @param tile end tile of area dragging
+ * @param p1 start tile of area dragging
+ * @param p2 unused
+ */
+int32 CmdClearArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost, ret, money;
+	int ex;
+	int ey;
+	int sx,sy;
+	int x,y;
+	bool success = false;
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	// make sure sx,sy are smaller than ex,ey
+	ex = TileX(tile);
+	ey = TileY(tile);
+	sx = TileX(p1);
+	sy = TileY(p1);
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+
+	money = GetAvailableMoneyForCommand();
+	cost = 0;
+
+	for (x = sx; x <= ex; ++x) {
+		for (y = sy; y <= ey; ++y) {
+			ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
+			if (CmdFailed(ret)) continue;
+			cost += ret;
+			success = true;
+
+			if (flags & DC_EXEC) {
+				if (ret > 0 && (money -= ret) < 0) {
+					_additional_cash_required = ret;
+					return cost - ret;
+				}
+				DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+
+				// draw explosion animation...
+				if ((x == sx || x == ex) && (y == sy || y == ey)) {
+					// big explosion in each corner, or small explosion for single tiles
+					CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
+						sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
+					);
+				}
+			}
+		}
+	}
+
+	return (success) ? cost : CMD_ERROR;
+}
+
+
+#define TILELOOP_BITS 4
+#define TILELOOP_SIZE (1 << TILELOOP_BITS)
+#define TILELOOP_ASSERTMASK ((TILELOOP_SIZE-1) + ((TILELOOP_SIZE-1) << MapLogX()))
+#define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
+
+void RunTileLoop(void)
+{
+	TileIndex tile;
+	uint count;
+
+	tile = _cur_tileloop_tile;
+
+	assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
+	count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
+	do {
+		_tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
+
+		if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
+			tile += TILELOOP_SIZE; /* no overflow */
+		} else {
+			tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
+		}
+	} while (--count);
+	assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
+
+	tile += 9;
+	if (tile & TILELOOP_CHKMASK)
+		tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
+	_cur_tileloop_tile = tile;
+}
+
+void InitializeLandscape(void)
+{
+	uint maxx = MapMaxX();
+	uint maxy = MapMaxY();
+	uint sizex = MapSizeX();
+	uint x;
+	uint y;
+
+	for (y = 0; y < maxy; y++) {
+		for (x = 0; x < maxx; x++) {
+			MakeClear(sizex * y + x, CLEAR_GRASS, 3);
+			SetTileHeight(sizex * y + x, 0);
+			_m[sizex * y + x].extra = 0;
+			ClearBridgeMiddle(sizex * y + x);
+		}
+		MakeVoid(sizex * y + x);
+	}
+	for (x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
+}
+
+void ConvertGroundTilesIntoWaterTiles(void)
+{
+	TileIndex tile;
+	uint z;
+	Slope slope;
+
+	for (tile = 0; tile < MapSize(); ++tile) {
+		slope = GetTileSlope(tile, &z);
+		if (IsTileType(tile, MP_CLEAR) && z == 0) {
+			/* Make both water for tiles at level 0
+			 * and make shore, as that looks much better
+			 * during the generation. */
+			switch (slope) {
+				case SLOPE_FLAT:
+					MakeWater(tile);
+					break;
+
+				case SLOPE_N:
+				case SLOPE_E:
+				case SLOPE_S:
+				case SLOPE_W:
+				case SLOPE_NW:
+				case SLOPE_SW:
+				case SLOPE_SE:
+				case SLOPE_NE:
+					MakeShore(tile);
+					break;
+
+				default:
+					break;
+			}
+		}
+	}
+}
+
+static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
+static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
+
+static void GenerateTerrain(int type, int flag)
+{
+	uint32 r;
+	uint x;
+	uint y;
+	uint w;
+	uint h;
+	const Sprite* template;
+	const byte *p;
+	Tile* tile;
+	byte direction;
+
+	r = Random();
+	template = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845);
+
+	x = r & MapMaxX();
+	y = (r >> MapLogX()) & MapMaxY();
+
+
+	if (x < 2 || y < 2) return;
+
+	direction = GB(r, 22, 2);
+	if (direction & 1) {
+		w = template->height;
+		h = template->width;
+	} else {
+		w = template->width;
+		h = template->height;
+	}
+	p = template->data;
+
+	if (flag & 4) {
+		uint xw = x * MapSizeY();
+		uint yw = y * MapSizeX();
+		uint bias = (MapSizeX() + MapSizeY()) * 16;
+
+		switch (flag & 3) {
+			case 0:
+				if (xw + yw > MapSize() - bias) return;
+				break;
+
+			case 1:
+				if (yw < xw + bias) return;
+				break;
+
+			case 2:
+				if (xw + yw < MapSize() + bias) return;
+				break;
+
+			case 3:
+				if (xw < yw + bias) return;
+				break;
+		}
+	}
+
+	if (x + w >= MapMaxX() - 1) return;
+	if (y + h >= MapMaxY() - 1) return;
+
+	tile = &_m[TileXY(x, y)];
+
+	switch (direction) {
+		case 0:
+			do {
+				Tile* tile_cur = tile;
+				uint w_cur;
+
+				for (w_cur = w; w_cur != 0; --w_cur) {
+					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
+					p++;
+					tile_cur++;
+				}
+				tile += TileDiffXY(0, 1);
+			} while (--h != 0);
+			break;
+
+		case 1:
+			do {
+				Tile* tile_cur = tile;
+				uint h_cur;
+
+				for (h_cur = h; h_cur != 0; --h_cur) {
+					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
+					p++;
+					tile_cur += TileDiffXY(0, 1);
+				}
+				tile++;
+			} while (--w != 0);
+			break;
+
+		case 2:
+			tile += TileDiffXY(w - 1, 0);
+			do {
+				Tile* tile_cur = tile;
+				uint w_cur;
+
+				for (w_cur = w; w_cur != 0; --w_cur) {
+					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
+					p++;
+					tile_cur--;
+				}
+				tile += TileDiffXY(0, 1);
+			} while (--h != 0);
+			break;
+
+		case 3:
+			tile += TileDiffXY(0, h - 1);
+			do {
+				Tile* tile_cur = tile;
+				uint h_cur;
+
+				for (h_cur = h; h_cur != 0; --h_cur) {
+					if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
+					p++;
+					tile_cur -= TileDiffXY(0, 1);
+				}
+				tile++;
+			} while (--w != 0);
+			break;
+	}
+}
+
+
+#include "table/genland.h"
+
+static void CreateDesertOrRainForest(void)
+{
+	TileIndex tile;
+	TileIndex update_freq = MapSize() / 4;
+	const TileIndexDiffC *data;
+	uint i;
+
+	for (tile = 0; tile != MapSize(); ++tile) {
+		if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+		for (data = _make_desert_or_rainforest_data;
+				data != endof(_make_desert_or_rainforest_data); ++data) {
+			TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
+			if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break;
+		}
+		if (data == endof(_make_desert_or_rainforest_data))
+			SetTropicZone(tile, TROPICZONE_DESERT);
+	}
+
+	for (i = 0; i != 256; i++) {
+		if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+		RunTileLoop();
+	}
+
+	for (tile = 0; tile != MapSize(); ++tile) {
+		if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+		for (data = _make_desert_or_rainforest_data;
+				data != endof(_make_desert_or_rainforest_data); ++data) {
+			TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
+			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
+		}
+		if (data == endof(_make_desert_or_rainforest_data))
+			SetTropicZone(tile, TROPICZONE_RAINFOREST);
+	}
+}
+
+void GenerateLandscape(byte mode)
+{
+	const int gwp_desert_amount = 4 + 8;
+	uint i;
+	uint flag;
+	uint32 r;
+
+	if (mode == GW_HEIGHTMAP) {
+		SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_DESERT) ? 1 + gwp_desert_amount : 1);
+		LoadHeightmap(_file_to_saveload.name);
+		IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+	} else if (_patches.land_generator == LG_TERRAGENESIS) {
+		SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_DESERT) ? 3 + gwp_desert_amount : 3);
+		GenerateTerrainPerlin();
+	} else {
+		switch (_opt.landscape) {
+			case LT_HILLY:
+				SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
+
+				for (i = ScaleByMapSize((Random() & 0x7F) + 950); i != 0; --i) {
+					GenerateTerrain(2, 0);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+				r = Random();
+				flag = GB(r, 0, 2) | 4;
+				for (i = ScaleByMapSize(GB(r, 16, 7) + 450); i != 0; --i) {
+					GenerateTerrain(4, flag);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+				break;
+
+			case LT_DESERT:
+				SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
+
+				for (i = ScaleByMapSize((Random() & 0x7F) + 170); i != 0; --i) {
+					GenerateTerrain(0, 0);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+				r = Random();
+				flag = GB(r, 0, 2) | 4;
+				for (i = ScaleByMapSize(GB(r, 16, 8) + 1700); i != 0; --i) {
+					GenerateTerrain(0, flag);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+				flag ^= 2;
+
+				for (i = ScaleByMapSize((Random() & 0x7F) + 410); i != 0; --i) {
+					GenerateTerrain(3, flag);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+				break;
+
+			default:
+				SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
+
+				i = ScaleByMapSize((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes) * 256 + 100);
+				for (; i != 0; --i) {
+					GenerateTerrain(_opt.diff.terrain_type, 0);
+				}
+				IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+				break;
+		}
+	}
+
+	ConvertGroundTilesIntoWaterTiles();
+
+	if (_opt.landscape == LT_DESERT) CreateDesertOrRainForest();
+}
+
+void OnTick_Town(void);
+void OnTick_Trees(void);
+void OnTick_Station(void);
+void OnTick_Industry(void);
+
+void OnTick_Players(void);
+void OnTick_Train(void);
+
+void CallLandscapeTick(void)
+{
+	OnTick_Town();
+	OnTick_Trees();
+	OnTick_Station();
+	OnTick_Industry();
+
+	OnTick_Players();
+	OnTick_Train();
+}
+
+TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
+{
+	int rn = rng;
+	uint32 r = Random();
+
+	return TILE_MASK(TileXY(
+		TileX(a) + (GB(r, 0, 8) * rn * 2 >> 8) - rn,
+		TileY(a) + (GB(r, 8, 8) * rn * 2 >> 8) - rn
+	));
+}
+
+bool IsValidTile(TileIndex tile)
+{
+	return (tile < MapSizeX() * MapMaxY() && TileX(tile) != MapMaxX());
+}
deleted file mode 100644
--- a/src/main_gui.c
+++ /dev/null
@@ -1,2436 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "heightmap.h"
-#include "currency.h"
-#include "functions.h"
-#include "spritecache.h"
-#include "station.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "player.h"
-#include "command.h"
-#include "news.h"
-#include "town.h"
-#include "vehicle.h"
-#include "console.h"
-#include "sound.h"
-#include "network/network.h"
-#include "signs.h"
-#include "waypoint.h"
-#include "variables.h"
-#include "train.h"
-#include "unmovable_map.h"
-#include "string.h"
-#include "screenshot.h"
-#include "genworld.h"
-#include "settings.h"
-#include "date.h"
-#include "vehicle_gui.h"
-#include "newgrf_config.h"
-
-#include "network/network_data.h"
-#include "network/network_client.h"
-#include "network/network_server.h"
-#include "network/network_gui.h"
-#include "industry.h"
-
-static int _rename_id = 1;
-static int _rename_what = -1;
-
-static byte _terraform_size = 1;
-RailType _last_built_railtype;
-static int _scengen_town_size = 2; // depress medium-sized towns per default
-
-extern void GenerateIndustries(void);
-extern bool GenerateTowns(void);
-
-
-void HandleOnEditText(const char *str)
-{
-	int id = _rename_id;
-	_cmd_text = str;
-
-	switch (_rename_what) {
-	case 0: /* Rename a s sign, if string is empty, delete sign */
-		DoCommandP(0, id, 0, NULL, CMD_RENAME_SIGN | CMD_MSG(STR_280C_CAN_T_CHANGE_SIGN_NAME));
-		break;
-	case 1: /* Rename a waypoint */
-		if (*str == '\0') return;
-		DoCommandP(0, id, 0, NULL, CMD_RENAME_WAYPOINT | CMD_MSG(STR_CANT_CHANGE_WAYPOINT_NAME));
-		break;
-#ifdef ENABLE_NETWORK
-	case 3: { /* Give money, you can only give money in excess of loan */
-		const Player *p = GetPlayer(_current_player);
-		int32 money = min(p->money64 - p->current_loan, atoi(str) / _currency->rate);
-		char msg[20];
-
-		money = clamp(money, 0, 20000000); // Clamp between 20 million and 0
-
-		// Give 'id' the money, and substract it from ourself
-		if (!DoCommandP(0, money, id, NULL, CMD_GIVE_MONEY | CMD_MSG(STR_INSUFFICIENT_FUNDS))) break;
-
-		// Inform the player of this action
-		snprintf(msg, sizeof(msg), "%d", money);
-
-		if (!_network_server) {
-			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, id, msg);
-		} else {
-			NetworkServer_HandleChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, id, msg, NETWORK_SERVER_INDEX);
-		}
-	}	break;
-#endif /* ENABLE_NETWORK */
-		default: NOT_REACHED();
-	}
-
-	_rename_id = _rename_what = -1;
-}
-
-/**
- * This code is shared for the majority of the pushbuttons.
- * Handles e.g. the pressing of a button (to build things), playing of click sound and sets certain parameters
- *
- * @param w Window which called the function
- * @param widget ID of the widget (=button) that called this function
- * @param cursor How should the cursor image change? E.g. cursor with depot image in it
- * @param mode Tile highlighting mode, e.g. drawing a rectangle or a dot on the ground
- * @param placeproc Procedure which will be called when someone clicks on the map
-
- * @return true if the button is clicked, false if it's unclicked
- */
-bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, int mode, PlaceProc *placeproc)
-{
-	if (IsWindowWidgetDisabled(w, widget)) return false;
-
-	SndPlayFx(SND_15_BEEP);
-	SetWindowDirty(w);
-
-	if (IsWindowWidgetLowered(w, widget)) {
-		ResetObjectToPlace();
-		return false;
-	}
-
-	SetObjectToPlace(cursor, mode, w->window_class, w->window_number);
-	LowerWindowWidget(w, widget);
-	_place_proc = placeproc;
-	return true;
-}
-
-
-void CcPlaySound10(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) SndPlayTileFx(SND_12_EXPLOSION, tile);
-}
-
-
-static void ToolbarPauseClick(Window *w)
-{
-	if (_networking && !_network_server) return; // only server can pause the game
-
-	if (DoCommandP(0, _pause ? 0 : 1, 0, NULL, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
-}
-
-static void ToolbarFastForwardClick(Window *w)
-{
-	_fast_forward ^= true;
-	SndPlayFx(SND_15_BEEP);
-}
-
-
-static void MenuClickSettings(int index)
-{
-	switch (index) {
-		case 0: ShowGameOptions();      return;
-		case 1: ShowGameDifficulty();   return;
-		case 2: ShowPatchesSelection(); return;
-		case 3: ShowNewGRFSettings(!_networking, true, true, &_grfconfig);   return;
-
-		case  5: _display_opt ^= DO_SHOW_TOWN_NAMES;    break;
-		case  6: _display_opt ^= DO_SHOW_STATION_NAMES; break;
-		case  7: _display_opt ^= DO_SHOW_SIGNS;         break;
-		case  8: _display_opt ^= DO_WAYPOINTS;          break;
-		case  9: _display_opt ^= DO_FULL_ANIMATION;     break;
-		case 10: _display_opt ^= DO_FULL_DETAIL;        break;
-		case 11: _display_opt ^= DO_TRANS_BUILDINGS;    break;
-		case 12: _display_opt ^= DO_TRANS_SIGNS;        break;
-	}
-	MarkWholeScreenDirty();
-}
-
-static void MenuClickSaveLoad(int index)
-{
-	if (_game_mode == GM_EDITOR) {
-		switch (index) {
-			case 0: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break;
-			case 1: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
-			case 2: AskExitToGameMenu();                   break;
-			case 4: HandleExitGameRequest();               break;
-		}
-	} else {
-		switch (index) {
-			case 0: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
-			case 1: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
-			case 2: AskExitToGameMenu();               break;
-			case 3: HandleExitGameRequest();           break;
-		}
-	}
-}
-
-static void MenuClickMap(int index)
-{
-	switch (index) {
-		case 0: ShowSmallMap();            break;
-		case 1: ShowExtraViewPortWindow(); break;
-		case 2: ShowSignList();            break;
-	}
-}
-
-static void MenuClickTown(int index)
-{
-	ShowTownDirectory();
-}
-
-static void MenuClickScenMap(int index)
-{
-	switch (index) {
-		case 0: ShowSmallMap();            break;
-		case 1: ShowExtraViewPortWindow(); break;
-		case 2: ShowSignList();            break;
-		case 3: ShowTownDirectory();       break;
-	}
-}
-
-static void MenuClickSubsidies(int index)
-{
-	ShowSubsidiesList();
-}
-
-static void MenuClickStations(int index)
-{
-	ShowPlayerStations(index);
-}
-
-static void MenuClickFinances(int index)
-{
-	ShowPlayerFinances(index);
-}
-
-static void MenuClickCompany(int index)
-{
-	if (_networking && index == 0) {
-		ShowClientList();
-	} else {
-		if (_networking) index--;
-		ShowPlayerCompany(index);
-	}
-}
-
-static void MenuClickGraphs(int index)
-{
-	switch (index) {
-		case 0: ShowOperatingProfitGraph();    break;
-		case 1: ShowIncomeGraph();             break;
-		case 2: ShowDeliveredCargoGraph();     break;
-		case 3: ShowPerformanceHistoryGraph(); break;
-		case 4: ShowCompanyValueGraph();       break;
-		case 5: ShowCargoPaymentRates();       break;
-	}
-}
-
-static void MenuClickLeague(int index)
-{
-	switch (index) {
-		case 0: ShowCompanyLeagueTable();      break;
-		case 1: ShowPerformanceRatingDetail(); break;
-	}
-}
-
-static void MenuClickIndustry(int index)
-{
-	switch (index) {
-		case 0: ShowIndustryDirectory();   break;
-		case 1: ShowBuildIndustryWindow(); break;
-	}
-}
-
-static void MenuClickShowTrains(int index)
-{
-	ShowVehicleListWindow(index, INVALID_STATION, VEH_Train);
-}
-
-static void MenuClickShowRoad(int index)
-{
-	ShowVehicleListWindow(index, INVALID_STATION, VEH_Road);
-}
-
-static void MenuClickShowShips(int index)
-{
-	ShowVehicleListWindow(index, INVALID_STATION, VEH_Ship);
-}
-
-static void MenuClickShowAir(int index)
-{
-	ShowVehicleListWindow(index, INVALID_STATION, VEH_Aircraft);
-}
-
-static void MenuClickBuildRail(int index)
-{
-	_last_built_railtype = index;
-	ShowBuildRailToolbar(_last_built_railtype, -1);
-}
-
-static void MenuClickBuildRoad(int index)
-{
-	ShowBuildRoadToolbar();
-}
-
-static void MenuClickBuildWater(int index)
-{
-	ShowBuildDocksToolbar();
-}
-
-static void MenuClickBuildAir(int index)
-{
-	ShowBuildAirToolbar();
-}
-
-#ifdef ENABLE_NETWORK
-void ShowNetworkGiveMoneyWindow(PlayerID player)
-{
-	_rename_id = player;
-	_rename_what = 3;
-	ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, 180, NULL, CS_NUMERAL);
-}
-#endif /* ENABLE_NETWORK */
-
-void ShowRenameSignWindow(const Sign *si)
-{
-	_rename_id = si->index;
-	_rename_what = 0;
-	ShowQueryString(si->str, STR_280B_EDIT_SIGN_TEXT, 30, 180, NULL, CS_ALPHANUMERAL);
-}
-
-void ShowRenameWaypointWindow(const Waypoint *wp)
-{
-	int id = wp->index;
-
-	/* Are we allowed to change the name of the waypoint? */
-	if (!CheckTileOwnership(wp->xy)) {
-		ShowErrorMessage(_error_message, STR_CANT_CHANGE_WAYPOINT_NAME,
-			TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
-		return;
-	}
-
-	_rename_id = id;
-	_rename_what = 1;
-	SetDParam(0, id);
-	ShowQueryString(STR_WAYPOINT_RAW, STR_EDIT_WAYPOINT_NAME, 30, 180, NULL, CS_ALPHANUMERAL);
-}
-
-static void SelectSignTool(void)
-{
-	if (_cursor.sprite == SPR_CURSOR_SIGN) {
-		ResetObjectToPlace();
-	} else {
-		SetObjectToPlace(SPR_CURSOR_SIGN, 1, 1, 0);
-		_place_proc = PlaceProc_Sign;
-	}
-}
-
-static void MenuClickForest(int index)
-{
-	switch (index) {
-		case 0: ShowTerraformToolbar();  break;
-		case 1: ShowBuildTreesToolbar(); break;
-		case 2: SelectSignTool();        break;
-	}
-}
-
-static void MenuClickMusicWindow(int index)
-{
-	ShowMusicWindow();
-}
-
-static void MenuClickNewspaper(int index)
-{
-	switch (index) {
-		case 0: ShowLastNewsMessage(); break;
-		case 1: ShowMessageOptions();  break;
-		case 2: ShowMessageHistory();  break;
-	}
-}
-
-static void MenuClickSmallScreenshot(void)
-{
-	SetScreenshotType(SC_VIEWPORT);
-}
-
-static void MenuClickWorldScreenshot(void)
-{
-	SetScreenshotType(SC_WORLD);
-}
-
-static void MenuClickHelp(int index)
-{
-	switch (index) {
-		case 0: PlaceLandBlockInfo();       break;
-		case 2: IConsoleSwitch();           break;
-		case 3: MenuClickSmallScreenshot(); break;
-		case 4: MenuClickWorldScreenshot(); break;
-		case 5: ShowAboutWindow();          break;
-	}
-}
-
-
-typedef void MenuClickedProc(int index);
-
-static MenuClickedProc * const _menu_clicked_procs[] = {
-	NULL,                 /* 0 */
-	NULL,                 /* 1 */
-	MenuClickSettings,    /* 2 */
-	MenuClickSaveLoad,    /* 3 */
-	MenuClickMap,         /* 4 */
-	MenuClickTown,        /* 5 */
-	MenuClickSubsidies,   /* 6 */
-	MenuClickStations,    /* 7 */
-	MenuClickFinances,    /* 8 */
-	MenuClickCompany,     /* 9 */
-	MenuClickGraphs,      /* 10 */
-	MenuClickLeague,      /* 11 */
-	MenuClickIndustry,    /* 12 */
-	MenuClickShowTrains,  /* 13 */
-	MenuClickShowRoad,    /* 14 */
-	MenuClickShowShips,   /* 15 */
-	MenuClickShowAir,     /* 16 */
-	MenuClickScenMap,     /* 17 */
-	NULL,                 /* 18 */
-	MenuClickBuildRail,   /* 19 */
-	MenuClickBuildRoad,   /* 20 */
-	MenuClickBuildWater,  /* 21 */
-	MenuClickBuildAir,    /* 22 */
-	MenuClickForest,      /* 23 */
-	MenuClickMusicWindow, /* 24 */
-	MenuClickNewspaper,   /* 25 */
-	MenuClickHelp,        /* 26 */
-};
-
-static void MenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE: w->widget[0].right = w->width - 1; break;
-
-	case WE_PAINT: {
-		int x, y;
-
-		byte count = WP(w, menu_d).item_count;
-		byte sel = WP(w, menu_d).sel_index;
-		uint16 chk = WP(w, menu_d).checked_items;
-		StringID string = WP(w, menu_d).string_id;
-		byte dis = WP(w, menu_d).disabled_items;
-
-		DrawWindowWidgets(w);
-
-		x = 1;
-		y = 1;
-
-		for (; count != 0; count--, string++, sel--) {
-			byte color = HASBIT(dis, 0) ? 14 : (sel == 0) ? 12 : 16;
-			if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
-
-			if (HASBIT(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
-			DrawString(x + 2, y, string, color);
-
-			y += 10;
-			chk >>= 1;
-			dis >>= 1;
-		}
-	} break;
-
-	case WE_DESTROY: {
-			Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-			RaiseWindowWidget(v, WP(w,menu_d).main_button);
-			SetWindowDirty(v);
-			return;
-		}
-
-	case WE_POPUPMENU_SELECT: {
-		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
-		int action_id;
-
-
-		if (index < 0) {
-			Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-			if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w,menu_d).main_button)
-				index = WP(w,menu_d).sel_index;
-		}
-
-		action_id = WP(w,menu_d).action_id;
-		DeleteWindow(w);
-
-		if (index >= 0) {
-			assert((uint)index <= lengthof(_menu_clicked_procs));
-			_menu_clicked_procs[action_id](index);
-		}
-
-		break;
-		}
-
-	case WE_POPUPMENU_OVER: {
-		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
-
-		if (index == -1 || index == WP(w,menu_d).sel_index) return;
-
-		WP(w,menu_d).sel_index = index;
-		SetWindowDirty(w);
-		return;
-		}
-	}
-}
-
-/* Dynamic widget length determined by toolbar-string length.
- * See PopupMainToolbMenu en MenuWndProc */
-static const Widget _menu_widgets[] = {
-{    WWT_PANEL, RESIZE_NONE, 14, 0,  0, 0, 0, 0x0, STR_NULL},
-{ WIDGETS_END},
-};
-
-
-static const Widget _player_menu_widgets[] = {
-{    WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
-{ WIDGETS_END},
-};
-
-
-static int GetPlayerIndexFromMenu(int index)
-{
-	if (index >= 0) {
-		const Player *p;
-
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && --index < 0) return p->index;
-		}
-	}
-	return -1;
-}
-
-static void UpdatePlayerMenuHeight(Window *w)
-{
-	byte num = ActivePlayerCount();
-
-	// Increase one to fit in PlayerList in the menu when in network
-	if (_networking && WP(w,menu_d).main_button == 9) num++;
-
-	if (WP(w,menu_d).item_count != num) {
-		WP(w,menu_d).item_count = num;
-		SetWindowDirty(w);
-		num = num * 10 + 2;
-		w->height = num;
-		w->widget[0].bottom = w->widget[0].top + num - 1;
-		SetWindowDirty(w);
-	}
-}
-
-extern void DrawPlayerIcon(PlayerID pid, int x, int y);
-
-static void PlayerMenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int x,y;
-		byte sel, color;
-		Player *p;
-		uint16 chk;
-
-		UpdatePlayerMenuHeight(w);
-		DrawWindowWidgets(w);
-
-		x = 1;
-		y = 1;
-		sel = WP(w,menu_d).sel_index;
-		chk = WP(w,menu_d).checked_items; // let this mean gray items.
-
-		// 9 = playerlist
-		if (_networking && WP(w,menu_d).main_button == 9) {
-			if (sel == 0) {
-				GfxFillRect(x, y, x + 238, y + 9, 0);
-			}
-			DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, 0x0);
-			y += 10;
-			sel--;
-		}
-
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				if (p->index == sel) {
-					GfxFillRect(x, y, x + 238, y + 9, 0);
-				}
-
-				DrawPlayerIcon(p->index, x + 2, y + 1);
-
-				SetDParam(0, p->name_1);
-				SetDParam(1, p->name_2);
-				SetDParam(2, GetPlayerNameString(p->index, 3));
-
-				color = (p->index == sel) ? 0xC : 0x10;
-				if (chk&1) color = 14;
-				DrawString(x + 19, y, STR_7021, color);
-
-				y += 10;
-			}
-			chk >>= 1;
-		}
-
-		break;
-		}
-
-	case WE_DESTROY: {
-		Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-		RaiseWindowWidget(v, WP(w,menu_d).main_button);
-		SetWindowDirty(v);
-		return;
-		}
-
-	case WE_POPUPMENU_SELECT: {
-		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
-		int action_id = WP(w,menu_d).action_id;
-
-		// We have a new entry at the top of the list of menu 9 when networking
-		//  so keep that in count
-		if (_networking && WP(w,menu_d).main_button == 9) {
-			if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-		} else {
-			index = GetPlayerIndexFromMenu(index);
-		}
-
-		if (index < 0) {
-			Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-			if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w,menu_d).main_button)
-				index = WP(w,menu_d).sel_index;
-		}
-
-		DeleteWindow(w);
-
-		if (index >= 0) {
-			assert(index >= 0 && index < 30);
-			_menu_clicked_procs[action_id](index);
-		}
-		break;
-		}
-	case WE_POPUPMENU_OVER: {
-		int index;
-		UpdatePlayerMenuHeight(w);
-		index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
-
-		// We have a new entry at the top of the list of menu 9 when networking
-		//  so keep that in count
-		if (_networking && WP(w,menu_d).main_button == 9) {
-			if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-		} else {
-			index = GetPlayerIndexFromMenu(index);
-		}
-
-		if (index == -1 || index == WP(w,menu_d).sel_index) return;
-
-		WP(w,menu_d).sel_index = index;
-		SetWindowDirty(w);
-		return;
-		}
-	}
-}
-
-/** Get the maximum length of a given string in a string-list. This is an
- * implicit string-list where the ID's are consecutive
- * @param base_string StringID of the first string in the list
- * @param count amount of StringID's in the list
- * @return the length of the longest string */
-static int GetStringListMaxWidth(StringID base_string, byte count)
-{
-	char buffer[512];
-	int width, max_width;
-	byte i;
-
-	max_width = 0;
-	for (i = 0; i != count; i++) {
-		GetString(buffer, base_string + i, lastof(buffer));
-		width = GetStringBoundingBox(buffer).width;
-		if (width > max_width) max_width = width;
-	}
-
-	return max_width;
-}
-
-/** Show a general dropdown menu. The positioning of the dropdown menu
- * defaults to the left side of the parent_button, eg the button that caused
- * this window to appear. The only exceptions are when the right side of this
- * dropdown would fall outside the main toolbar window, in that case it is
- * aligned with the toolbar's right side.
- * Since the disable-mask is only 8 bits right now, these dropdowns are
- * restricted to 8 items max if any bits of disabled_mask are active.
- * @param w Pointer to a window this dropdown menu belongs to. Has no effect
- * whatsoever, only graphically for positioning.
- * @param parent_button The widget identifier of the button that was clicked for
- * this dropdown. The created dropdown then knows what button to raise (button) on
- * action and whose function to execute (action).
- * It is possible to appoint another button for an action event by setting the
- * upper 8 bits of this parameter. If non is set, action is presumed to be the same
- * as button. So<br>
- * button bits 0 -  7 - widget clicked to get dropdown
- * action bits 8 - 15 - function of widget to execute on select (defaults to bits 0 - 7)
- * @param base_string The first StringID shown in the dropdown list. All others are
- * consecutive indeces from the language file. XXX - fix? Use ingame-string tables?
- * @param item_count Number of strings in the list, see previous parameter
- * @param disabled_mask Bitmask of disabled strings in the list
- * @return Return a pointer to the newly created dropdown window */
-static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask)
-{
-	int width;
-	int x = w->widget[GB(parent_button, 0, 8)].left;
-
-	assert(disabled_mask == 0 || item_count <= 8);
-	LowerWindowWidget(w, parent_button);
-	InvalidateWidget(w, parent_button);
-
-	DeleteWindowById(WC_TOOLBAR_MENU, 0);
-
-	/* Extend the dropdown toolbar to the longest string in the list and
-	 * also make sure the dropdown is fully visible within the window.
-	 * x + w->left because x is supposed to be the offset of the toolbar-button
-	 * we clicked on and w->left the toolbar window itself. So meaning that
-	 * the default position is aligned with the left side of the clicked button */
-	width = max(GetStringListMaxWidth(base_string, item_count) + 6, 140);
-	x = w->left + clamp(x, 0, w->width - width); // or alternatively '_screen.width - width'
-
-	w = AllocateWindow(x, 22, width, item_count * 10 + 2, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
-	w->widget[0].bottom = item_count * 10 + 1;
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-
-	WP(w,menu_d).item_count = item_count;
-	WP(w,menu_d).sel_index = 0;
-	WP(w,menu_d).main_button = GB(parent_button, 0, 8);
-	WP(w,menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
-	WP(w,menu_d).string_id = base_string;
-	WP(w,menu_d).checked_items = 0;
-	WP(w,menu_d).disabled_items = disabled_mask;
-
-	_popup_menu_active = true;
-
-	SndPlayFx(SND_15_BEEP);
-	return w;
-}
-
-static Window *PopupMainPlayerToolbMenu(Window *w, int x, int main_button, int gray)
-{
-	x += w->left;
-
-	LowerWindowWidget(w, main_button);
-	InvalidateWidget(w, main_button);
-
-	DeleteWindowById(WC_TOOLBAR_MENU, 0);
-	w = AllocateWindow(x, 0x16, 0xF1, 0x52, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w,menu_d).item_count = 0;
-	WP(w,menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
-	if (_networking && main_button == 9) {
-		if (_local_player != PLAYER_SPECTATOR) {
-			WP(w,menu_d).sel_index++;
-		} else {
-			/* Select client list by default for spectators */
-			WP(w,menu_d).sel_index = 0;
-		}
-	}
-	WP(w,menu_d).action_id = main_button;
-	WP(w,menu_d).main_button = main_button;
-	WP(w,menu_d).checked_items = gray;
-	WP(w,menu_d).disabled_items = 0;
-	_popup_menu_active = true;
-	SndPlayFx(SND_15_BEEP);
-	return w;
-}
-
-static void ToolbarSaveClick(Window *w)
-{
-	PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4, 0);
-}
-
-static void ToolbarMapClick(Window *w)
-{
-	PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3, 0);
-}
-
-static void ToolbarTownClick(Window *w)
-{
-	PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1, 0);
-}
-
-static void ToolbarSubsidiesClick(Window *w)
-{
-	PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1, 0);
-}
-
-static void ToolbarStationsClick(Window *w)
-{
-	PopupMainPlayerToolbMenu(w, 162, 7, 0);
-}
-
-static void ToolbarMoneyClick(Window *w)
-{
-	PopupMainPlayerToolbMenu(w, 191, 8, 0);
-}
-
-static void ToolbarPlayersClick(Window *w)
-{
-	PopupMainPlayerToolbMenu(w, 213, 9, 0);
-}
-
-static void ToolbarGraphsClick(Window *w)
-{
-	PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6, 0);
-}
-
-static void ToolbarLeagueClick(Window *w)
-{
-	PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2, 0);
-}
-
-static void ToolbarIndustryClick(Window *w)
-{
-	/* Disable build-industry menu if we are a spectator */
-	PopupMainToolbMenu(w, 12, STR_INDUSTRY_DIR, 2, (_current_player == PLAYER_SPECTATOR) ? (1 << 1) : 0);
-}
-
-static void ToolbarTrainClick(Window *w)
-{
-	const Vehicle *v;
-	int dis = -1;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && IsFrontEngine(v)) CLRBIT(dis, v->owner);
-	}
-	PopupMainPlayerToolbMenu(w, 310, 13, dis);
-}
-
-static void ToolbarRoadClick(Window *w)
-{
-	const Vehicle *v;
-	int dis = -1;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Road) CLRBIT(dis, v->owner);
-	}
-	PopupMainPlayerToolbMenu(w, 332, 14, dis);
-}
-
-static void ToolbarShipClick(Window *w)
-{
-	const Vehicle *v;
-	int dis = -1;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Ship) CLRBIT(dis, v->owner);
-	}
-	PopupMainPlayerToolbMenu(w, 354, 15, dis);
-}
-
-static void ToolbarAirClick(Window *w)
-{
-	const Vehicle *v;
-	int dis = -1;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Aircraft) CLRBIT(dis, v->owner);
-	}
-	PopupMainPlayerToolbMenu(w, 376, 16, dis);
-}
-
-/* Zooms a viewport in a window in or out */
-/* No button handling or what so ever */
-bool DoZoomInOutWindow(int how, Window *w)
-{
-	ViewPort *vp;
-
-	assert(w != NULL);
-	vp = w->viewport;
-
-	switch (how) {
-		case ZOOM_IN:
-			if (vp->zoom == 0) return false;
-			vp->zoom--;
-			vp->virtual_width >>= 1;
-			vp->virtual_height >>= 1;
-
-			WP(w,vp_d).scrollpos_x += vp->virtual_width >> 1;
-			WP(w,vp_d).scrollpos_y += vp->virtual_height >> 1;
-			break;
-		case ZOOM_OUT:
-			if (vp->zoom == 2) return false;
-			vp->zoom++;
-
-			WP(w,vp_d).scrollpos_x -= vp->virtual_width >> 1;
-			WP(w,vp_d).scrollpos_y -= vp->virtual_height >> 1;
-
-			vp->virtual_width <<= 1;
-			vp->virtual_height <<= 1;
-			break;
-	}
-	if (vp != NULL) { // the vp can be null when how == ZOOM_NONE
-		vp->virtual_left = WP(w, vp_d).scrollpos_x;
-		vp->virtual_top = WP(w, vp_d).scrollpos_y;
-	}
-	SetWindowDirty(w);
-	/* Update the windows that have zoom-buttons to perhaps disable their buttons */
-	SendWindowMessageClass(w->window_class, how, w->window_number, 0);
-	return true;
-}
-
-static void ToolbarZoomInClick(Window *w)
-{
-	if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
-		HandleButtonClick(w, 17);
-		SndPlayFx(SND_15_BEEP);
-	}
-}
-
-static void ToolbarZoomOutClick(Window *w)
-{
-	if (DoZoomInOutWindow(ZOOM_OUT,FindWindowById(WC_MAIN_WINDOW, 0))) {
-		HandleButtonClick(w, 18);
-		SndPlayFx(SND_15_BEEP);
-	}
-}
-
-static void ToolbarBuildRailClick(Window *w)
-{
-	const Player *p = GetPlayer(_local_player);
-	Window *w2;
-	w2 = PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes);
-	WP(w2,menu_d).sel_index = _last_built_railtype;
-}
-
-static void ToolbarBuildRoadClick(Window *w)
-{
-	PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 1, 0);
-}
-
-static void ToolbarBuildWaterClick(Window *w)
-{
-	PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1, 0);
-}
-
-static void ToolbarBuildAirClick(Window *w)
-{
-	PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1, 0);
-}
-
-static void ToolbarForestClick(Window *w)
-{
-	PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3, 0);
-}
-
-static void ToolbarMusicClick(Window *w)
-{
-	PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1, 0);
-}
-
-static void ToolbarNewspaperClick(Window *w)
-{
-	PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3, 0);
-}
-
-static void ToolbarHelpClick(Window *w)
-{
-	PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 6, 0);
-}
-
-static void ToolbarOptionsClick(Window *w)
-{
-	uint16 x = 0;
-
-	w = PopupMainToolbMenu(w, 2, STR_02C3_GAME_OPTIONS, 13, 0);
-
-	if (_display_opt & DO_SHOW_TOWN_NAMES)    SETBIT(x,  5);
-	if (_display_opt & DO_SHOW_STATION_NAMES) SETBIT(x,  6);
-	if (_display_opt & DO_SHOW_SIGNS)         SETBIT(x,  7);
-	if (_display_opt & DO_WAYPOINTS)          SETBIT(x,  8);
-	if (_display_opt & DO_FULL_ANIMATION)     SETBIT(x,  9);
-	if (_display_opt & DO_FULL_DETAIL)        SETBIT(x, 10);
-	if (_display_opt & DO_TRANS_BUILDINGS)    SETBIT(x, 11);
-	if (_display_opt & DO_TRANS_SIGNS)        SETBIT(x, 12);
-	WP(w,menu_d).checked_items = x;
-}
-
-
-static void ToolbarScenSaveOrLoad(Window *w)
-{
-	PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 5, 0);
-}
-
-static void ToolbarScenDateBackward(Window *w)
-{
-	// don't allow too fast scrolling
-	if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-		HandleButtonClick(w, 6);
-		SetWindowDirty(w);
-
-		_patches_newgame.starting_year = clamp(_patches_newgame.starting_year - 1, MIN_YEAR, MAX_YEAR);
-		SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-	}
-	_left_button_clicked = false;
-}
-
-static void ToolbarScenDateForward(Window *w)
-{
-	// don't allow too fast scrolling
-	if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
-		HandleButtonClick(w, 7);
-		SetWindowDirty(w);
-
-		_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + 1, MIN_YEAR, MAX_YEAR);
-		SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-	}
-	_left_button_clicked = false;
-}
-
-static void ToolbarScenMapTownDir(Window *w)
-{
-	/* Scenario editor button, *hack*hack* use different button to activate */
-	PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4, 0);
-}
-
-static void ToolbarScenZoomIn(Window *w)
-{
-	if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
-		HandleButtonClick(w, 9);
-		SndPlayFx(SND_15_BEEP);
-	}
-}
-
-static void ToolbarScenZoomOut(Window *w)
-{
-	if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
-		HandleButtonClick(w, 10);
-		SndPlayFx(SND_15_BEEP);
-	}
-}
-
-void ZoomInOrOutToCursorWindow(bool in, Window *w)
-{
-	ViewPort *vp;
-	Point pt;
-
-	assert(w != 0);
-
-	vp = w->viewport;
-
-	if (_game_mode != GM_MENU) {
-		if ((in && vp->zoom == 0) || (!in && vp->zoom == 2))
-			return;
-
-		pt = GetTileZoomCenterWindow(in,w);
-		if (pt.x != -1) {
-			ScrollWindowTo(pt.x, pt.y, w);
-
-			DoZoomInOutWindow(in ? ZOOM_IN : ZOOM_OUT, w);
-		}
-	}
-}
-
-// TODO - Incorporate into game itself to allow for ingame raising/lowering of
-// larger chunks at the same time OR remove altogether, as we have 'level land' ?
-/**
- * Raise/Lower a bigger chunk of land at the same time in the editor. When
- * raising get the lowest point, when lowering the highest point, and set all
- * tiles in the selection to that height.
- * @param tile The top-left tile where the terraforming will start
- * @param mode 1 for raising, 0 for lowering land
- */
-static void CommonRaiseLowerBigLand(TileIndex tile, int mode)
-{
-	int sizex, sizey;
-	byte h;
-
-	_generating_world = true; // used to create green terraformed land
-
-	if (_terraform_size == 1) {
-		StringID msg =
-			mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
-
-		DoCommandP(tile, 8, (uint32)mode, CcTerraform, CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(msg));
-	} else {
-		SndPlayTileFx(SND_1F_SPLAT, tile);
-
-		assert(_terraform_size != 0);
-		// check out for map overflows
-		sizex = min(MapSizeX() - TileX(tile) - 1, _terraform_size);
-		sizey = min(MapSizeY() - TileY(tile) - 1, _terraform_size);
-
-		if (sizex == 0 || sizey == 0) return;
-
-		if (mode != 0) {
-			/* Raise land */
-			h = 15; // XXX - max height
-			BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
-				h = min(h, TileHeight(tile2));
-			} END_TILE_LOOP(tile2, sizex, sizey, tile)
-		} else {
-			/* Lower land */
-			h = 0;
-			BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
-				h = max(h, TileHeight(tile2));
-			} END_TILE_LOOP(tile2, sizex, sizey, tile)
-		}
-
-		BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
-			if (TileHeight(tile2) == h) {
-				DoCommandP(tile2, 8, (uint32)mode, NULL, CMD_TERRAFORM_LAND | CMD_AUTO);
-			}
-		} END_TILE_LOOP(tile2, sizex, sizey, tile)
-	}
-
-	_generating_world = false;
-}
-
-static void PlaceProc_RaiseBigLand(TileIndex tile)
-{
-	CommonRaiseLowerBigLand(tile, 1);
-}
-
-static void PlaceProc_LowerBigLand(TileIndex tile)
-{
-	CommonRaiseLowerBigLand(tile, 0);
-}
-
-static void PlaceProc_RockyArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_RockyArea);
-}
-
-static void PlaceProc_LightHouse(TileIndex tile)
-{
-	if (!IsTileType(tile, MP_CLEAR) || IsSteepSlope(GetTileSlope(tile, NULL))) {
-		return;
-	}
-
-	MakeLighthouse(tile);
-	MarkTileDirtyByTile(tile);
-	SndPlayTileFx(SND_1F_SPLAT, tile);
-}
-
-static void PlaceProc_Transmitter(TileIndex tile)
-{
-	if (!IsTileType(tile, MP_CLEAR) || IsSteepSlope(GetTileSlope(tile, NULL))) {
-		return;
-	}
-
-	MakeTransmitter(tile);
-	MarkTileDirtyByTile(tile);
-	SndPlayTileFx(SND_1F_SPLAT, tile);
-}
-
-static void PlaceProc_DesertArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DesertArea);
-}
-
-static void PlaceProc_WaterArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_WaterArea);
-}
-
-static const Widget _scen_edit_land_gen_widgets[] = {
-{  WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                  STR_018B_CLOSE_WINDOW},
-{   WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0223_LAND_GENERATION,  STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_STICKYBOX,   RESIZE_NONE,     7,   170,   181,     0,    13, STR_NULL,                  STR_STICKY_BUTTON},
-{     WWT_PANEL,   RESIZE_NONE,     7,     0,   181,    14,    95, 0x0,                       STR_NULL},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,     2,    23,    14,    35, SPR_IMG_DYNAMITE,          STR_018D_DEMOLISH_BUILDINGS_ETC},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,    24,    45,    14,    35, SPR_IMG_TERRAFORM_DOWN,    STR_018E_LOWER_A_CORNER_OF_LAND},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,    46,    67,    14,    35, SPR_IMG_TERRAFORM_UP,      STR_018F_RAISE_A_CORNER_OF_LAND},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,    68,    89,    14,    35, SPR_IMG_LEVEL_LAND,        STR_LEVEL_LAND_TOOLTIP},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,    90,   111,    14,    35, SPR_IMG_BUILD_CANAL,       STR_CREATE_LAKE},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,   112,   134,    14,    35, SPR_IMG_ROCKS,             STR_028C_PLACE_ROCKY_AREAS_ON_LANDSCAPE},
-{    WWT_IMGBTN,   RESIZE_NONE,    14,   135,   157,    14,    35, SPR_IMG_LIGHTHOUSE_DESERT, STR_NULL}, // XXX - dynamic
-{    WWT_IMGBTN,   RESIZE_NONE,    14,   158,   179,    14,    35, SPR_IMG_TRANSMITTER,       STR_028E_PLACE_TRANSMITTER},
-{   WWT_TEXTBTN,   RESIZE_NONE,    14,   139,   149,    43,    54, STR_0224,                  STR_0228_INCREASE_SIZE_OF_LAND_AREA},
-{   WWT_TEXTBTN,   RESIZE_NONE,    14,   139,   149,    56,    67, STR_0225,                  STR_0229_DECREASE_SIZE_OF_LAND_AREA},
-{   WWT_TEXTBTN,   RESIZE_NONE,    14,    34,   149,    75,    86, STR_SE_NEW_WORLD,          STR_022A_GENERATE_RANDOM_LAND},
-{   WIDGETS_END},
-};
-
-static const int8 _multi_terraform_coords[][2] = {
-	{  0, -2},
-	{  4,  0}, { -4,  0}, {  0,  2},
-	{ -8,  2}, { -4,  4}, {  0,  6}, {  4,  4}, {  8,  2},
-	{-12,  0}, { -8, -2}, { -4, -4}, {  0, -6}, {  4, -4}, {  8, -2}, { 12,  0},
-	{-16,  2}, {-12,  4}, { -8,  6}, { -4,  8}, {  0, 10}, {  4,  8}, {  8,  6}, { 12,  4}, { 16,  2},
-	{-20,  0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, {  0,-10}, {  4, -8}, {  8, -6}, { 12, -4}, { 16, -2}, { 20,  0},
-	{-24,  2}, {-20,  4}, {-16,  6}, {-12,  8}, { -8, 10}, { -4, 12}, {  0, 14}, {  4, 12}, {  8, 10}, { 12,  8}, { 16,  6}, { 20,  4}, { 24,  2},
-	{-28,  0}, {-24, -2}, {-20, -4}, {-16, -6}, {-12, -8}, { -8,-10}, { -4,-12}, {  0,-14}, {  4,-12}, {  8,-10}, { 12, -8}, { 16, -6}, { 20, -4}, { 24, -2}, { 28,  0},
-};
-
-// TODO - Merge with terraform_gui.c (move there) after I have cooled down at its braindeadness
-// and changed OnButtonClick to include the widget as well in the function decleration. Post 0.4.0 - Darkvater
-static void EditorTerraformClick_Dynamite(Window *w)
-{
-	HandlePlacePushButton(w, 4, ANIMCURSOR_DEMOLISH, 1, PlaceProc_DemolishArea);
-}
-
-static void EditorTerraformClick_LowerBigLand(Window *w)
-{
-	HandlePlacePushButton(w, 5, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerBigLand);
-}
-
-static void EditorTerraformClick_RaiseBigLand(Window *w)
-{
-	HandlePlacePushButton(w, 6, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseBigLand);
-}
-
-static void EditorTerraformClick_LevelLand(Window *w)
-{
-	HandlePlacePushButton(w, 7, SPR_CURSOR_LEVEL_LAND, 2, PlaceProc_LevelLand);
-}
-
-static void EditorTerraformClick_WaterArea(Window *w)
-{
-	HandlePlacePushButton(w, 8, SPR_CURSOR_CANAL, 1, PlaceProc_WaterArea);
-}
-
-static void EditorTerraformClick_RockyArea(Window *w)
-{
-	HandlePlacePushButton(w, 9, SPR_CURSOR_ROCKY_AREA, 1, PlaceProc_RockyArea);
-}
-
-static void EditorTerraformClick_DesertLightHouse(Window *w)
-{
-	HandlePlacePushButton(w, 10, SPR_CURSOR_LIGHTHOUSE, 1, (_opt.landscape == LT_DESERT) ? PlaceProc_DesertArea : PlaceProc_LightHouse);
-}
-
-static void EditorTerraformClick_Transmitter(Window *w)
-{
-	HandlePlacePushButton(w, 11, SPR_CURSOR_TRANSMITTER, 1, PlaceProc_Transmitter);
-}
-
-static const uint16 _editor_terraform_keycodes[] = {
-	'D',
-	'Q',
-	'W',
-	'E',
-	'R',
-	'T',
-	'Y',
-	'U'
-};
-
-typedef void OnButtonClick(Window *w);
-static OnButtonClick * const _editor_terraform_button_proc[] = {
-	EditorTerraformClick_Dynamite,
-	EditorTerraformClick_LowerBigLand,
-	EditorTerraformClick_RaiseBigLand,
-	EditorTerraformClick_LevelLand,
-	EditorTerraformClick_WaterArea,
-	EditorTerraformClick_RockyArea,
-	EditorTerraformClick_DesertLightHouse,
-	EditorTerraformClick_Transmitter
-};
-
-static void ScenEditLandGenWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		// XXX - lighthouse button is widget 10!! Don't forget when changing
-		w->widget[10].tooltips = (_opt.landscape == LT_DESERT) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
-		break;
-
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-
-		{
-			int n = _terraform_size * _terraform_size;
-			const int8 *coords = &_multi_terraform_coords[0][0];
-
-			assert(n != 0);
-			do {
-				DrawSprite(SPR_WHITE_POINT, 77 + coords[0], 55 + coords[1]);
-				coords += 2;
-			} while (--n);
-		}
-
-		if (IsWindowWidgetLowered(w, 5) || IsWindowWidgetLowered(w, 6)) // change area-size if raise/lower corner is selected
-			SetTileSelectSize(_terraform_size, _terraform_size);
-
-		break;
-
-	case WE_KEYPRESS: {
-		uint i;
-
-		for (i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
-			if (e->we.keypress.keycode == _editor_terraform_keycodes[i]) {
-				e->we.keypress.cont = false;
-				_editor_terraform_button_proc[i](w);
-				break;
-			}
-		}
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11:
-			_editor_terraform_button_proc[e->we.click.widget - 4](w);
-			break;
-		case 12: case 13: { /* Increase/Decrease terraform size */
-			int size = (e->we.click.widget == 12) ? 1 : -1;
-			HandleButtonClick(w, e->we.click.widget);
-			size += _terraform_size;
-
-			if (!IS_INT_INSIDE(size, 1, 8 + 1)) return;
-			_terraform_size = size;
-
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-		} break;
-		case 14: /* gen random land */
-			HandleButtonClick(w, 14);
-			ShowCreateScenario();
-			break;
-		}
-		break;
-
-	case WE_TIMEOUT: {
-		uint i;
-		for (i = 0; i < w->widget_count; i++) {
-			if (IsWindowWidgetLowered(w, i)) {
-				RaiseWindowWidget(w, i);
-				InvalidateWidget(w, i);
-			}
-			if (i == 3) i = 11;
-		}
-		break;
-	}
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		break;
-	case WE_PLACE_DRAG:
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
-		break;
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) // dragged actions
-				GUIPlaceProcDragXY(e);
-		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const WindowDesc _scen_edit_land_gen_desc = {
-	WDP_AUTO, WDP_AUTO, 182, 96,
-	WC_SCEN_LAND_GEN,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_scen_edit_land_gen_widgets,
-	ScenEditLandGenWndProc,
-};
-
-static inline void ShowEditorTerraformToolBar(void)
-{
-	AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0);
-}
-
-static void ToolbarScenGenLand(Window *w)
-{
-	HandleButtonClick(w, 11);
-	SndPlayFx(SND_15_BEEP);
-
-	ShowEditorTerraformToolBar();
-}
-
-void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_1F_SPLAT, tile);
-		ResetObjectToPlace();
-	}
-}
-
-static void PlaceProc_Town(TileIndex tile)
-{
-	DoCommandP(tile, _scengen_town_size, 0, CcBuildTown, CMD_BUILD_TOWN | CMD_MSG(STR_0236_CAN_T_BUILD_TOWN_HERE));
-}
-
-
-static const Widget _scen_edit_town_gen_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_0233_TOWN_GENERATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   148,   159,     0,    13, 0x0,                      STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   159,    14,    81, 0x0,                      STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    16,    27, STR_0234_NEW_TOWN,        STR_0235_CONSTRUCT_NEW_TOWN},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    29,    40, STR_023D_RANDOM_TOWN,     STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    42,    53, STR_MANY_RANDOM_TOWNS,    STR_RANDOM_TOWNS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,    53,    68,    79, STR_02A1_SMALL,           STR_02A4_SELECT_TOWN_SIZE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    54,   105,    68,    79, STR_02A2_MEDIUM,          STR_02A4_SELECT_TOWN_SIZE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   106,   157,    68,    79, STR_02A3_LARGE,           STR_02A4_SELECT_TOWN_SIZE},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    54,    67, STR_02A5_TOWN_SIZE,       STR_NULL},
-{   WIDGETS_END},
-};
-
-static void ScenEditTownGenWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CREATE:
-		LowerWindowWidget(w, (_scengen_town_size - 1)+ 7);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 4: /* new town */
-			HandlePlacePushButton(w, 4, SPR_CURSOR_TOWN, 1, PlaceProc_Town);
-			break;
-		case 5: {/* random town */
-			Town *t;
-
-			HandleButtonClick(w, 5);
-			_generating_world = true;
-			t = CreateRandomTown(20, _scengen_town_size);
-			_generating_world = false;
-
-			if (t == NULL) {
-				ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
-			} else {
-				ScrollMainWindowToTile(t->xy);
-			}
-
-			break;
-		}
-		case 6: {/* many random towns */
-			HandleButtonClick(w, 6);
-
-			_generating_world = true;
-			if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
-			_generating_world = false;
-			break;
-		}
-
-		case 7: case 8: case 9:
-			RaiseWindowWidget(w, (_scengen_town_size - 1) + 7);
-			_scengen_town_size = (e->we.click.widget - 7) + 1;
-			LowerWindowWidget(w, (_scengen_town_size - 1) + 7);
-			SetWindowDirty(w);
-			break;
-		}
-		break;
-
-	case WE_TIMEOUT:
-		RaiseWindowWidget(w, 5);
-		RaiseWindowWidget(w, 6);
-		SetWindowDirty(w);
-		break;
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		break;
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		LowerWindowWidget(w, (_scengen_town_size - 1) + 7);
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const WindowDesc _scen_edit_town_gen_desc = {
-	WDP_AUTO, WDP_AUTO, 160, 82,
-	WC_SCEN_TOWN_GEN,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_scen_edit_town_gen_widgets,
-	ScenEditTownGenWndProc,
-};
-
-static void ToolbarScenGenTown(Window *w)
-{
-	HandleButtonClick(w, 12);
-	SndPlayFx(SND_15_BEEP);
-
-	AllocateWindowDescFront(&_scen_edit_town_gen_desc, 0);
-}
-
-
-static const Widget _scenedit_industry_normal_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                          STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,   STR_RANDOM_INDUSTRIES_TIP},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0240_COAL_MINE,           STR_0262_CONSTRUCT_COAL_MINE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0241_POWER_STATION,       STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0242_SAWMILL,             STR_0264_CONSTRUCT_SAWMILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0243_FOREST,              STR_0265_PLANT_FOREST},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_0244_OIL_REFINERY,        STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_0245_OIL_RIG,             STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_0246_FACTORY,             STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_0247_STEEL_MILL,          STR_0269_CONSTRUCT_STEEL_MILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0248_FARM,                STR_026A_CONSTRUCT_FARM},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_0249_IRON_ORE_MINE,       STR_026B_CONSTRUCT_IRON_ORE_MINE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024A_OIL_WELLS,           STR_026C_CONSTRUCT_OIL_WELLS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   185,   196, STR_024B_BANK,                STR_026D_CONSTRUCT_BANK_CAN_ONLY},
-{   WIDGETS_END},
-};
-
-
-static const Widget _scenedit_industry_hilly_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION,   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                            STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,     STR_RANDOM_INDUSTRIES_TIP},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0240_COAL_MINE,             STR_0262_CONSTRUCT_COAL_MINE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0243_FOREST,                STR_0265_PLANT_FOREST},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_024F_GOLD_MINE,             STR_0271_CONSTRUCT_GOLD_MINE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0248_FARM,                  STR_026A_CONSTRUCT_FARM},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_024B_BANK,                  STR_0272_CONSTRUCT_BANK_CAN_ONLY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024A_OIL_WELLS,             STR_026C_CONSTRUCT_OIL_WELLS},
-{   WIDGETS_END},
-};
-
-static const Widget _scenedit_industry_desert_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION,    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                             STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,      STR_RANDOM_INDUSTRIES_TIP},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0250_LUMBER_MILL,            STR_0273_CONSTRUCT_LUMBER_MILL_TO},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0251_FRUIT_PLANTATION,       STR_0274_PLANT_FRUIT_PLANTATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0252_RUBBER_PLANTATION,      STR_0275_PLANT_RUBBER_PLANTATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0244_OIL_REFINERY,           STR_0266_CONSTRUCT_OIL_REFINERY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_024D_FOOD_PROCESSING_PLANT,  STR_026F_CONSTRUCT_FOOD_PROCESSING},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_0246_FACTORY,                STR_0268_CONSTRUCT_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_0253_WATER_SUPPLY,           STR_0276_CONSTRUCT_WATER_SUPPLY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_0248_FARM,                   STR_026A_CONSTRUCT_FARM},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0254_WATER_TOWER,            STR_0277_CONSTRUCT_WATER_TOWER_CAN},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_024A_OIL_WELLS,              STR_026C_CONSTRUCT_OIL_WELLS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024B_BANK,                   STR_0272_CONSTRUCT_BANK_CAN_ONLY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   185,   196, STR_0255_DIAMOND_MINE,           STR_0278_CONSTRUCT_DIAMOND_MINE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   198,   209, STR_0256_COPPER_ORE_MINE,        STR_0279_CONSTRUCT_COPPER_ORE_MINE},
-{   WIDGETS_END},
-};
-
-static const Widget _scenedit_industry_candy_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                          STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,   STR_RANDOM_INDUSTRIES_TIP},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0257_COTTON_CANDY_FOREST, STR_027A_PLANT_COTTON_CANDY_FOREST},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0258_CANDY_FACTORY,       STR_027B_CONSTRUCT_CANDY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0259_BATTERY_FARM,        STR_027C_CONSTRUCT_BATTERY_FARM},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_025A_COLA_WELLS,          STR_027D_CONSTRUCT_COLA_WELLS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_025B_TOY_SHOP,            STR_027E_CONSTRUCT_TOY_SHOP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_025C_TOY_FACTORY,         STR_027F_CONSTRUCT_TOY_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_025D_PLASTIC_FOUNTAINS,   STR_0280_CONSTRUCT_PLASTIC_FOUNTAINS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_025F_BUBBLE_GENERATOR,    STR_0282_CONSTRUCT_BUBBLE_GENERATOR},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_0260_TOFFEE_QUARRY,       STR_0283_CONSTRUCT_TOFFEE_QUARRY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_0261_SUGAR_MINE,          STR_0284_CONSTRUCT_SUGAR_MINE},
-{   WIDGETS_END},
-};
-
-
-static bool AnyTownExists(void)
-{
-	const Town *t;
-
-	FOR_ALL_TOWNS(t) return true;
-
-	return false;
-}
-
-extern Industry *CreateNewIndustry(TileIndex tile, int type);
-
-/**
- * Search callback function for TryBuildIndustry
- * @param tile to test
- * @param data that is passed by the caller.  In this case, the type of industry been tested
- * @result of the operation
- */
-static bool SearchTileForIndustry(TileIndex tile, uint32 data)
-{
-	return CreateNewIndustry(tile, data) != NULL;
-}
-
-/**
- * Perform a 9*9 tiles circular search around a tile
- * in order to find a suitable zone to create the desired industry
- * @param tile to start search for
- * @param type of the desired industry
- */
-static bool TryBuildIndustry(TileIndex tile, int type)
-{
-	return CircularTileSearch(tile, 9, SearchTileForIndustry, type);
-}
-
-
-static const byte _industry_type_list[4][16] = {
-	{ 0,  1,  2,  3,  4,  5,  6,  8,  9, 18, 11, 12},
-	{ 0,  1, 14,  3,  4, 13,  7, 15,  9, 16, 11, 12},
-	{25, 19, 20,  4, 13, 23, 21, 24, 22, 11, 16, 17, 10},
-	{26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36},
-};
-
-static int _industry_type_to_place;
-bool _ignore_restrictions;
-
-static void ScenEditIndustryWndProc(Window *w, WindowEvent *e)
-{
-	int button;
-
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK:
-		if (e->we.click.widget == 3) {
-			HandleButtonClick(w, 3);
-
-			if (!AnyTownExists()) {
-				ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0);
-				return;
-			}
-
-			_generating_world = true;
-			GenerateIndustries();
-			_generating_world = false;
-		}
-
-		if ((button=e->we.click.widget) >= 4) {
-			if (HandlePlacePushButton(w, button, SPR_CURSOR_INDUSTRY, 1, NULL))
-				_industry_type_to_place = _industry_type_list[_opt.landscape][button - 4];
-		}
-		break;
-	case WE_PLACE_OBJ: {
-		int type;
-
-		// Show error if no town exists at all
-		type = _industry_type_to_place;
-		if (!AnyTownExists()) {
-			SetDParam(0, GetIndustrySpec(type)->name);
-			ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
-			return;
-		}
-
-		_current_player = OWNER_NONE;
-		_generating_world = true;
-		_ignore_restrictions = true;
-		if (!TryBuildIndustry(e->we.place.tile,type)) {
-			SetDParam(0, GetIndustrySpec(type)->name);
-			ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
-		}
-		_ignore_restrictions = false;
-		_generating_world = false;
-		break;
-	}
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		SetWindowDirty(w);
-		break;
-	case WE_TIMEOUT:
-		RaiseWindowWidget(w, 3);
-		InvalidateWidget(w, 3);
-		break;
-	}
-}
-
-static const WindowDesc _scenedit_industry_normal_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 225,
-	WC_SCEN_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_scenedit_industry_normal_widgets,
-	ScenEditIndustryWndProc,
-};
-
-static const WindowDesc _scenedit_industry_hilly_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 225,
-	WC_SCEN_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_scenedit_industry_hilly_widgets,
-	ScenEditIndustryWndProc,
-};
-
-static const WindowDesc _scenedit_industry_desert_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 225,
-	WC_SCEN_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_scenedit_industry_desert_widgets,
-	ScenEditIndustryWndProc,
-};
-
-static const WindowDesc _scenedit_industry_candy_desc = {
-	WDP_AUTO, WDP_AUTO, 170, 225,
-	WC_SCEN_INDUSTRY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_scenedit_industry_candy_widgets,
-	ScenEditIndustryWndProc,
-};
-
-static const WindowDesc * const _scenedit_industry_descs[] = {
-	&_scenedit_industry_normal_desc,
-	&_scenedit_industry_hilly_desc,
-	&_scenedit_industry_desert_desc,
-	&_scenedit_industry_candy_desc,
-};
-
-
-static void ToolbarScenGenIndustry(Window *w)
-{
-	HandleButtonClick(w, 13);
-	SndPlayFx(SND_15_BEEP);
-	AllocateWindowDescFront(_scenedit_industry_descs[_opt.landscape],0);
-}
-
-static void ToolbarScenBuildRoad(Window *w)
-{
-	HandleButtonClick(w, 14);
-	SndPlayFx(SND_15_BEEP);
-	ShowBuildRoadScenToolbar();
-}
-
-static void ToolbarScenPlantTrees(Window *w)
-{
-	HandleButtonClick(w, 15);
-	SndPlayFx(SND_15_BEEP);
-	ShowBuildTreesScenToolbar();
-}
-
-static void ToolbarScenPlaceSign(Window *w)
-{
-	HandleButtonClick(w, 16);
-	SndPlayFx(SND_15_BEEP);
-	SelectSignTool();
-}
-
-static void ToolbarBtn_NULL(Window *w)
-{
-}
-
-
-typedef void ToolbarButtonProc(Window *w);
-
-static ToolbarButtonProc * const _toolbar_button_procs[] = {
-	ToolbarPauseClick,
-	ToolbarFastForwardClick,
-	ToolbarOptionsClick,
-	ToolbarSaveClick,
-	ToolbarMapClick,
-	ToolbarTownClick,
-	ToolbarSubsidiesClick,
-	ToolbarStationsClick,
-	ToolbarMoneyClick,
-	ToolbarPlayersClick,
-	ToolbarGraphsClick,
-	ToolbarLeagueClick,
-	ToolbarIndustryClick,
-	ToolbarTrainClick,
-	ToolbarRoadClick,
-	ToolbarShipClick,
-	ToolbarAirClick,
-	ToolbarZoomInClick,
-	ToolbarZoomOutClick,
-	ToolbarBuildRailClick,
-	ToolbarBuildRoadClick,
-	ToolbarBuildWaterClick,
-	ToolbarBuildAirClick,
-	ToolbarForestClick,
-	ToolbarMusicClick,
-	ToolbarNewspaperClick,
-	ToolbarHelpClick,
-};
-
-static void MainToolbarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		// Draw brown-red toolbar bg.
-		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
-		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | PALETTE_MODIFIER_GREYOUT);
-
-		/* If spectator, disable all construction buttons
-		 * ie : Build road, rail, ships, airports and landscaping
-		 * Since enabled state is the default, just disable when needed */
-		SetWindowWidgetsDisabledState(w, _current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
-		/* disable company list drop downs, if there are no companies */
-		SetWindowWidgetsDisabledState(w, ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
-
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK: {
-		if (_game_mode != GM_MENU && !IsWindowWidgetDisabled(w, e->we.click.widget))
-			_toolbar_button_procs[e->we.click.widget](w);
-	} break;
-
-	case WE_KEYPRESS: {
-		switch (e->we.keypress.keycode) {
-		case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
-		case WKC_F2: ShowGameOptions(); break;
-		case WKC_F3: MenuClickSaveLoad(0); break;
-		case WKC_F4: ShowSmallMap(); break;
-		case WKC_F5: ShowTownDirectory(); break;
-		case WKC_F6: ShowSubsidiesList(); break;
-		case WKC_F7: ShowPlayerStations(_local_player); break;
-		case WKC_F8: ShowPlayerFinances(_local_player); break;
-		case WKC_F9: ShowPlayerCompany(_local_player); break;
-		case WKC_F10:ShowOperatingProfitGraph(); break;
-		case WKC_F11: ShowCompanyLeagueTable(); break;
-		case WKC_F12: ShowBuildIndustryWindow(); break;
-		case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Train); break;
-		case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Road); break;
-		case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Ship); break;
-		case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Aircraft); break;
-		case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
-		case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
-		case WKC_SHIFT | WKC_F7: ShowBuildRailToolbar(_last_built_railtype, -1); break;
-		case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(); break;
-		case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
-		case WKC_SHIFT | WKC_F10:ShowBuildAirToolbar(); break;
-		case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
-		case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
-		case WKC_CTRL  | 'S': MenuClickSmallScreenshot(); break;
-		case WKC_CTRL  | 'G': MenuClickWorldScreenshot(); break;
-		case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
-		case 'A': ShowBuildRailToolbar(_last_built_railtype, 4); break; /* Invoke Autorail */
-		case 'L': ShowTerraformToolbar(); break;
-		default: return;
-		}
-		e->we.keypress.cont = false;
-	} break;
-
-	case WE_PLACE_OBJ: {
-		_place_proc(e->we.place.tile);
-	} break;
-
-	case WE_ABORT_PLACE_OBJ: {
-		RaiseWindowWidget(w, 25);
-		SetWindowDirty(w);
-	} break;
-
-	case WE_MOUSELOOP:
-		if (IsWindowWidgetLowered(w, 0) != !!_pause) {
-			ToggleWidgetLoweredState(w, 0);
-			InvalidateWidget(w, 0);
-		}
-
-		if (IsWindowWidgetLowered(w, 1) != !!_fast_forward) {
-			ToggleWidgetLoweredState(w, 1);
-			InvalidateWidget(w, 1);
-		}
-		break;
-
-	case WE_TIMEOUT: {
-		uint i;
-		for (i = 2; i < w->widget_count; i++) {
-			if (IsWindowWidgetLowered(w, i)) {
-				RaiseWindowWidget(w, i);
-				InvalidateWidget(w, i);
-			}
-		}
-		break;
-	}
-
-		case WE_MESSAGE:
-			HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
-			break;
-	}
-}
-
-static const Widget _toolb_normal_widgets[] = {
-{     WWT_IMGBTN,   RESIZE_NONE,    14,     0,    21,     0,    21, SPR_IMG_PAUSE,           STR_0171_PAUSE_GAME},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,    22,    43,     0,    21, SPR_IMG_FASTFORWARD,     STR_FAST_FORWARD},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,    44,    65,     0,    21, SPR_IMG_SETTINGS,        STR_0187_OPTIONS},
-{   WWT_IMGBTN_2,   RESIZE_NONE,    14,    66,    87,     0,    21, SPR_IMG_SAVE,            STR_0172_SAVE_GAME_ABANDON_GAME},
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,    96,   117,     0,    21, SPR_IMG_SMALLMAP,        STR_0174_DISPLAY_MAP},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   118,   139,     0,    21, SPR_IMG_TOWN,            STR_0176_DISPLAY_TOWN_DIRECTORY},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   140,   161,     0,    21, SPR_IMG_SUBSIDIES,       STR_02DC_DISPLAY_SUBSIDIES},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   162,   183,     0,    21, SPR_IMG_COMPANY_LIST,    STR_0173_DISPLAY_LIST_OF_COMPANY},
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   191,   212,     0,    21, SPR_IMG_COMPANY_FINANCE, STR_0177_DISPLAY_COMPANY_FINANCES},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   213,   235,     0,    21, SPR_IMG_COMPANY_GENERAL, STR_0178_DISPLAY_COMPANY_GENERAL},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   236,   257,     0,    21, SPR_IMG_GRAPHS,          STR_0179_DISPLAY_GRAPHS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   258,   279,     0,    21, SPR_IMG_COMPANY_LEAGUE,  STR_017A_DISPLAY_COMPANY_LEAGUE},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   280,   301,     0,    21, SPR_IMG_INDUSTRY,        STR_0312_FUND_CONSTRUCTION_OF_NEW},
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   310,   331,     0,    21, SPR_IMG_TRAINLIST,       STR_017B_DISPLAY_LIST_OF_COMPANY},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   332,   353,     0,    21, SPR_IMG_TRUCKLIST,       STR_017C_DISPLAY_LIST_OF_COMPANY},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   354,   375,     0,    21, SPR_IMG_SHIPLIST,        STR_017D_DISPLAY_LIST_OF_COMPANY},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   376,   397,     0,    21, SPR_IMG_AIRPLANESLIST,   STR_017E_DISPLAY_LIST_OF_COMPANY},
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   406,   427,     0,    21, SPR_IMG_ZOOMIN,          STR_017F_ZOOM_THE_VIEW_IN},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   428,   449,     0,    21, SPR_IMG_ZOOMOUT,         STR_0180_ZOOM_THE_VIEW_OUT},
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   457,   478,     0,    21, SPR_IMG_BUILDRAIL,       STR_0181_BUILD_RAILROAD_TRACK},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   479,   500,     0,    21, SPR_IMG_BUILDROAD,       STR_0182_BUILD_ROADS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   501,   522,     0,    21, SPR_IMG_BUILDWATER,      STR_0183_BUILD_SHIP_DOCKS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   523,   544,     0,    21, SPR_IMG_BUILDAIR,        STR_0184_BUILD_AIRPORTS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   545,   566,     0,    21, SPR_IMG_LANDSCAPING,     STR_LANDSCAPING_TOOLBAR_TIP}, // tree icon is 0x2E6
-
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   574,   595,     0,    21, SPR_IMG_MUSIC,           STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   596,   617,     0,    21, SPR_IMG_MESSAGES,        STR_0203_SHOW_LAST_MESSAGE_NEWS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   618,   639,     0,    21, SPR_IMG_QUERY,           STR_0186_LAND_BLOCK_INFORMATION},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _toolb_normal_desc = {
-	0, 0, 640, 22,
-	WC_MAIN_TOOLBAR,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
-	_toolb_normal_widgets,
-	MainToolbarWndProc
-};
-
-
-static const Widget _toolb_scen_widgets[] = {
-{  WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  0, 21, SPR_IMG_PAUSE,       STR_0171_PAUSE_GAME},
-{  WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  0, 21, SPR_IMG_FASTFORWARD, STR_FAST_FORWARD},
-{  WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  0, 21, SPR_IMG_SETTINGS,    STR_0187_OPTIONS},
-{WWT_IMGBTN_2, RESIZE_NONE, 14,  66,  87,  0, 21, SPR_IMG_SAVE,        STR_0297_SAVE_SCENARIO_LOAD_SCENARIO},
-
-{   WWT_PANEL, RESIZE_NONE, 14,  96, 225,  0, 21, 0x0,                 STR_NULL},
-
-{   WWT_PANEL, RESIZE_NONE, 14, 233, 362,  0, 21, 0x0,                 STR_NULL},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 236, 247,  5, 16, SPR_ARROW_DOWN,      STR_029E_MOVE_THE_STARTING_DATE},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 347, 358,  5, 16, SPR_ARROW_UP,        STR_029F_MOVE_THE_STARTING_DATE},
-
-{  WWT_IMGBTN, RESIZE_NONE, 14, 371, 392,  0, 21, SPR_IMG_SMALLMAP,    STR_0175_DISPLAY_MAP_TOWN_DIRECTORY},
-
-{  WWT_IMGBTN, RESIZE_NONE, 14, 400, 421,  0, 21, SPR_IMG_ZOOMIN,      STR_017F_ZOOM_THE_VIEW_IN},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 422, 443,  0, 21, SPR_IMG_ZOOMOUT,     STR_0180_ZOOM_THE_VIEW_OUT},
-
-{  WWT_IMGBTN, RESIZE_NONE, 14, 452, 473,  0, 21, SPR_IMG_LANDSCAPING, STR_022E_LANDSCAPE_GENERATION},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 474, 495,  0, 21, SPR_IMG_TOWN,        STR_022F_TOWN_GENERATION},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 496, 517,  0, 21, SPR_IMG_INDUSTRY,    STR_0230_INDUSTRY_GENERATION},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 518, 539,  0, 21, SPR_IMG_BUILDROAD,   STR_0231_ROAD_CONSTRUCTION},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 540, 561,  0, 21, SPR_IMG_PLANTTREES,  STR_0288_PLANT_TREES},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 562, 583,  0, 21, SPR_IMG_SIGN,        STR_0289_PLACE_SIGN},
-
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 596, 617,  0, 21, SPR_IMG_MUSIC,       STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
-{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
-{  WWT_IMGBTN, RESIZE_NONE, 14, 618, 639,  0, 21, SPR_IMG_QUERY,       STR_0186_LAND_BLOCK_INFORMATION},
-{WIDGETS_END},
-};
-
-static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
-	ToolbarPauseClick,
-	ToolbarFastForwardClick,
-	ToolbarOptionsClick,
-	ToolbarScenSaveOrLoad,
-	ToolbarBtn_NULL,
-	ToolbarBtn_NULL,
-	ToolbarScenDateBackward,
-	ToolbarScenDateForward,
-	ToolbarScenMapTownDir,
-	ToolbarScenZoomIn,
-	ToolbarScenZoomOut,
-	ToolbarScenGenLand,
-	ToolbarScenGenTown,
-	ToolbarScenGenIndustry,
-	ToolbarScenBuildRoad,
-	ToolbarScenPlantTrees,
-	ToolbarScenPlaceSign,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	ToolbarMusicClick,
-	NULL,
-	ToolbarHelpClick,
-};
-
-static void ScenEditToolbarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		SetWindowWidgetDisabledState(w, 6, _patches_newgame.starting_year <= MIN_YEAR);
-		SetWindowWidgetDisabledState(w, 7, _patches_newgame.starting_year >= MAX_YEAR);
-
-		// Draw brown-red toolbar bg.
-		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
-		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | PALETTE_MODIFIER_GREYOUT);
-
-		DrawWindowWidgets(w);
-
-		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-		DrawStringCentered(298, 6, STR_00AF, 0);
-
-		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-		DrawStringCentered(161, 1, STR_0221_OPENTTD, 0);
-		DrawStringCentered(161, 11,STR_0222_SCENARIO_EDITOR, 0);
-
-		break;
-
-	case WE_CLICK: {
-		if (_game_mode == GM_MENU) return;
-		_scen_toolbar_button_procs[e->we.click.widget](w);
-	} break;
-
-	case WE_KEYPRESS:
-		switch (e->we.keypress.keycode) {
-			case WKC_F1: ToolbarPauseClick(w); break;
-			case WKC_F2: ShowGameOptions(); break;
-			case WKC_F3: MenuClickSaveLoad(0); break;
-			case WKC_F4: ToolbarScenGenLand(w); break;
-			case WKC_F5: ToolbarScenGenTown(w); break;
-			case WKC_F6: ToolbarScenGenIndustry(w); break;
-			case WKC_F7: ToolbarScenBuildRoad(w); break;
-			case WKC_F8: ToolbarScenPlantTrees(w); break;
-			case WKC_F9: ToolbarScenPlaceSign(w); break;
-			case WKC_F10: ShowMusicWindow(); break;
-			case WKC_F11: PlaceLandBlockInfo(); break;
-			case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
-			case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
-			case 'L': ShowEditorTerraformToolBar(); break;
-			default: return;
-		}
-		e->we.keypress.cont = false;
-		break;
-
-	case WE_PLACE_OBJ: {
-		_place_proc(e->we.place.tile);
-	} break;
-
-	case WE_ABORT_PLACE_OBJ: {
-		RaiseWindowWidget(w, 25);
-		SetWindowDirty(w);
-	} break;
-
-	case WE_MOUSELOOP:
-		if (IsWindowWidgetLowered(w, 0) != !!_pause) {
-			ToggleWidgetLoweredState(w, 0);
-			SetWindowDirty(w);
-		}
-
-		if (IsWindowWidgetLowered(w, 1) != !!_fast_forward) {
-			ToggleWidgetLoweredState(w, 1);
-			SetWindowDirty(w);
-		}
-		break;
-
-		case WE_MESSAGE:
-			HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 9, 10);
-			break;
-	}
-}
-
-static const WindowDesc _toolb_scen_desc = {
-	0, 0, 640, 22,
-	WC_MAIN_TOOLBAR,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_toolb_scen_widgets,
-	ScenEditToolbarWndProc
-};
-
-extern GetNewsStringCallbackProc * const _get_news_string_callback[];
-
-
-static bool DrawScrollingStatusText(const NewsItem *ni, int pos)
-{
-	char buf[512];
-	StringID str;
-	const char *s;
-	char *d;
-	DrawPixelInfo tmp_dpi, *old_dpi;
-	int x;
-	char buffer[256];
-
-	if (ni->display_mode == 3) {
-		str = _get_news_string_callback[ni->callback](ni);
-	} else {
-		COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-		str = ni->string_id;
-	}
-
-	GetString(buf, str, lastof(buf));
-
-	s = buf;
-	d = buffer;
-
-	for (;;) {
-		WChar c = Utf8Consume(&s);
-		if (c == 0) {
-			*d = '\0';
-			break;
-		} else if (*s == 0x0D) {
-			d[0] = d[1] = d[2] = d[3] = ' ';
-			d += 4;
-		} else if (IsPrintable(c)) {
-			d += Utf8Encode(d, c);
-		}
-	}
-
-	if (!FillDrawPixelInfo(&tmp_dpi, 141, 1, 358, 11)) return true;
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = &tmp_dpi;
-
-	x = DoDrawString(buffer, pos, 0, 13);
-	_cur_dpi = old_dpi;
-
-	return x > 0;
-}
-
-static void StatusBarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
-
-		DrawWindowWidgets(w);
-		SetDParam(0, _date);
-		DrawStringCentered(
-			70, 1, (_pause || _patches.status_long_date) ? STR_00AF : STR_00AE, 0
-		);
-
-		if (p != NULL) {
-			// Draw player money
-			SetDParam64(0, p->money64);
-			DrawStringCentered(570, 1, p->player_money >= 0 ? STR_0004 : STR_0005, 0);
-		}
-
-		// Draw status bar
-		if (w->message.msg) { // true when saving is active
-			DrawStringCentered(320, 1, STR_SAVING_GAME, 0);
-		} else if (_do_autosave) {
-			DrawStringCentered(320, 1, STR_032F_AUTOSAVE, 0);
-		} else if (_pause) {
-			DrawStringCentered(320, 1, STR_0319_PAUSED, 0);
-		} else if (WP(w,def_d).data_1 > -1280 && FindWindowById(WC_NEWS_WINDOW,0) == NULL && _statusbar_news_item.string_id != 0) {
-			// Draw the scrolling news text
-			if (!DrawScrollingStatusText(&_statusbar_news_item, WP(w,def_d).data_1))
-				WP(w,def_d).data_1 = -1280;
-		} else {
-			if (p != NULL) {
-				// This is the default text
-				SetDParam(0, p->name_1);
-				SetDParam(1, p->name_2);
-				DrawStringCentered(320, 1, STR_02BA, 0);
-			}
-		}
-
-		if (WP(w, def_d).data_2 > 0) DrawSprite(SPR_BLOT | PALETTE_TO_RED, 489, 2);
-	} break;
-
-	case WE_MESSAGE:
-		w->message.msg = e->we.message.msg;
-		SetWindowDirty(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 1: ShowLastNewsMessage(); break;
-			case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
-			default: ResetObjectToPlace();
-		}
-		break;
-
-	case WE_TICK: {
-		if (_pause) return;
-
-		if (WP(w, def_d).data_1 > -1280) { /* Scrolling text */
-			WP(w, def_d).data_1 -= 2;
-			InvalidateWidget(w, 1);
-		}
-
-		if (WP(w, def_d).data_2 > 0) { /* Red blot to show there are new unread newsmessages */
-			WP(w, def_d).data_2 -= 2;
-		} else if (WP(w, def_d).data_2 < 0) {
-			WP(w, def_d).data_2 = 0;
-			InvalidateWidget(w, 1);
-		}
-
-		break;
-	}
-	}
-}
-
-static const Widget _main_status_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   139,     0,    11, 0x0, STR_NULL},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   140,   499,     0,    11, 0x0, STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   500,   639,     0,    11, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static WindowDesc _main_status_desc = {
-	WDP_CENTER, 0, 640, 12,
-	WC_STATUS_BAR,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_main_status_widgets,
-	StatusBarWndProc
-};
-
-extern void UpdateAllStationVirtCoord(void);
-
-static void MainWindowWndProc(Window *w, WindowEvent *e)
-{
-	int off_x;
-
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowViewport(w);
-		if (_game_mode == GM_MENU) {
-			off_x = _screen.width / 2;
-
-			DrawSprite(SPR_OTTD_O, off_x - 120, 50);
-			DrawSprite(SPR_OTTD_P, off_x -  86, 50);
-			DrawSprite(SPR_OTTD_E, off_x -  53, 50);
-			DrawSprite(SPR_OTTD_N, off_x -  22, 50);
-
-			DrawSprite(SPR_OTTD_T, off_x +  34, 50);
-			DrawSprite(SPR_OTTD_T, off_x +  65, 50);
-			DrawSprite(SPR_OTTD_D, off_x +  96, 50);
-
-			/*
-			DrawSprite(SPR_OTTD_R, off_x + 119, 50);
-			DrawSprite(SPR_OTTD_A, off_x + 148, 50);
-			DrawSprite(SPR_OTTD_N, off_x + 181, 50);
-			DrawSprite(SPR_OTTD_S, off_x + 215, 50);
-			DrawSprite(SPR_OTTD_P, off_x + 246, 50);
-			DrawSprite(SPR_OTTD_O, off_x + 275, 50);
-			DrawSprite(SPR_OTTD_R, off_x + 307, 50);
-			DrawSprite(SPR_OTTD_T, off_x + 337, 50);
-
-			DrawSprite(SPR_OTTD_T, off_x + 390, 50);
-			DrawSprite(SPR_OTTD_Y, off_x + 417, 50);
-			DrawSprite(SPR_OTTD_C, off_x + 447, 50);
-			DrawSprite(SPR_OTTD_O, off_x + 478, 50);
-			DrawSprite(SPR_OTTD_O, off_x + 509, 50);
-			DrawSprite(SPR_OTTD_N, off_x + 541, 50);
-			*/
-		}
-		break;
-
-	case WE_KEYPRESS:
-		switch (e->we.keypress.keycode) {
-			case 'Q' | WKC_CTRL:
-			case 'Q' | WKC_META:
-				HandleExitGameRequest();
-				break;
-		}
-
-		/* Disable all key shortcuts, except quit shortcuts when
-		 * generating the world, otherwise they create threading
-		 * problem during the generating, resulting in random
-		 * assertions that are hard to trigger and debug */
-		if (IsGeneratingWorld()) break;
-
-		if (e->we.keypress.keycode == WKC_BACKQUOTE) {
-			IConsoleSwitch();
-			e->we.keypress.cont = false;
-			break;
-		}
-
-		if (_game_mode == GM_MENU) break;
-
-		switch (e->we.keypress.keycode) {
-			case 'C':
-			case 'Z': {
-				Point pt = GetTileBelowCursor();
-				if (pt.x != -1) {
-					ScrollMainWindowTo(pt.x, pt.y);
-					if (e->we.keypress.keycode == 'Z') MaxZoomInOut(ZOOM_IN, w);
-				}
-				break;
-			}
-
-			case WKC_ESC: ResetObjectToPlace(); break;
-			case WKC_DELETE: DeleteNonVitalWindows(); break;
-			case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
-			case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
-
-#if defined(_DEBUG)
-			case '0' | WKC_ALT: /* Crash the game */
-				*(byte*)0 = 0;
-				break;
-
-			case '1' | WKC_ALT: /* Gimme money */
-				/* Server can not cheat in advertise mode either! */
-				if (!_networking || !_network_server || !_network_advertise)
-					DoCommandP(0, -10000000, 0, NULL, CMD_MONEY_CHEAT);
-				break;
-
-			case '2' | WKC_ALT: /* Update the coordinates of all station signs */
-				UpdateAllStationVirtCoord();
-				break;
-#endif
-
-			case 'X':
-				_display_opt ^= DO_TRANS_BUILDINGS;
-				MarkWholeScreenDirty();
-				break;
-
-#ifdef ENABLE_NETWORK
-			case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
-				if (_networking) {
-					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
-					bool teamchat = false;
-
-					/* Only players actually playing can speak to team. Eg spectators cannot */
-					if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
-						const NetworkClientInfo *ci;
-						FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-							if (ci->client_playas == cio->client_playas && ci != cio) {
-								teamchat = true;
-								break;
-							}
-						}
-					}
-
-					ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
-				}
-				break;
-
-			case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
-				if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
-				break;
-
-			case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
-				if (_networking) {
-					const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
-					ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas);
-				}
-				break;
-#endif
-
-			default: return;
-		}
-		e->we.keypress.cont = false;
-		break;
-
-		case WE_SCROLL: {
-			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
-
-			if (vp == NULL) {
-				_cursor.fix_at = false;
-				_scrolling_viewport = false;
-			}
-
-			WP(w, vp_d).scrollpos_x += e->we.scroll.delta.x << vp->zoom;
-			WP(w, vp_d).scrollpos_y += e->we.scroll.delta.y << vp->zoom;
-		} break;
-
-		case WE_MOUSEWHEEL:
-			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
-			break;
-
-		case WE_MESSAGE:
-			/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
-			SendWindowMessage(WC_MAIN_TOOLBAR, 0, e->we.message.msg, e->we.message.wparam, e->we.message.lparam);
-			break;
-	}
-}
-
-
-void ShowSelectGameWindow(void);
-
-void SetupColorsAndInitialWindow(void)
-{
-	uint i;
-	Window *w;
-	int width, height;
-
-	for (i = 0; i != 16; i++) {
-		const byte *b = GetNonSprite(PALETTE_RECOLOR_START + i);
-
-		assert(b);
-		memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
-	}
-
-	width = _screen.width;
-	height = _screen.height;
-
-	w = AllocateWindow(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
-	AssignWindowViewport(w, 0, 0, width, height, TileXY(32, 32), 0);
-
-	// XXX: these are not done
-	switch (_game_mode) {
-		default: NOT_REACHED();
-		case GM_MENU:
-			ShowSelectGameWindow();
-			break;
-
-		case GM_NORMAL:
-		case GM_EDITOR:
-			ShowVitalWindows();
-			break;
-	}
-}
-
-void ShowVitalWindows(void)
-{
-	Window *w;
-
-	w = AllocateWindowDesc((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
-	DoZoomInOutWindow(ZOOM_NONE, w);
-
-	CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
-
-	SetWindowWidgetDisabledState(w, 0, _networking && !_network_server); // if not server, disable pause button
-	SetWindowWidgetDisabledState(w, 1, _networking); // if networking, disable fast-forward button
-
-	/* 'w' is for sure a WC_MAIN_TOOLBAR */
-	PositionMainToolbar(w);
-
-	/* Status bad only for normal games */
-	if (_game_mode == GM_EDITOR) return;
-
-	_main_status_desc.top = _screen.height - 12;
-	w = AllocateWindowDesc(&_main_status_desc);
-	CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
-
-	WP(w,def_d).data_1 = -1280;
-}
-
-void GameSizeChanged(void)
-{
-	_cur_resolution[0] = _screen.width;
-	_cur_resolution[1] = _screen.height;
-	RelocateAllWindows(_screen.width, _screen.height);
-	ScreenSizeChanged();
-	MarkWholeScreenDirty();
-}
-
-void InitializeMainGui(void)
-{
-	/* Clean old GUI values */
-	_last_built_railtype = 0;
-}
-
-
new file mode 100644
--- /dev/null
+++ b/src/main_gui.cpp
@@ -0,0 +1,2436 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "heightmap.h"
+#include "currency.h"
+#include "functions.h"
+#include "spritecache.h"
+#include "station.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "player.h"
+#include "command.h"
+#include "news.h"
+#include "town.h"
+#include "vehicle.h"
+#include "console.h"
+#include "sound.h"
+#include "network/network.h"
+#include "signs.h"
+#include "waypoint.h"
+#include "variables.h"
+#include "train.h"
+#include "unmovable_map.h"
+#include "string.h"
+#include "screenshot.h"
+#include "genworld.h"
+#include "settings.h"
+#include "date.h"
+#include "vehicle_gui.h"
+#include "newgrf_config.h"
+
+#include "network/network_data.h"
+#include "network/network_client.h"
+#include "network/network_server.h"
+#include "network/network_gui.h"
+#include "industry.h"
+
+static int _rename_id = 1;
+static int _rename_what = -1;
+
+static byte _terraform_size = 1;
+RailType _last_built_railtype;
+static int _scengen_town_size = 2; // depress medium-sized towns per default
+
+extern void GenerateIndustries(void);
+extern bool GenerateTowns(void);
+
+
+void HandleOnEditText(const char *str)
+{
+	int id = _rename_id;
+	_cmd_text = str;
+
+	switch (_rename_what) {
+	case 0: /* Rename a s sign, if string is empty, delete sign */
+		DoCommandP(0, id, 0, NULL, CMD_RENAME_SIGN | CMD_MSG(STR_280C_CAN_T_CHANGE_SIGN_NAME));
+		break;
+	case 1: /* Rename a waypoint */
+		if (*str == '\0') return;
+		DoCommandP(0, id, 0, NULL, CMD_RENAME_WAYPOINT | CMD_MSG(STR_CANT_CHANGE_WAYPOINT_NAME));
+		break;
+#ifdef ENABLE_NETWORK
+	case 3: { /* Give money, you can only give money in excess of loan */
+		const Player *p = GetPlayer(_current_player);
+		int32 money = min(p->money64 - p->current_loan, atoi(str) / _currency->rate);
+		char msg[20];
+
+		money = clamp(money, 0, 20000000); // Clamp between 20 million and 0
+
+		// Give 'id' the money, and substract it from ourself
+		if (!DoCommandP(0, money, id, NULL, CMD_GIVE_MONEY | CMD_MSG(STR_INSUFFICIENT_FUNDS))) break;
+
+		// Inform the player of this action
+		snprintf(msg, sizeof(msg), "%d", money);
+
+		if (!_network_server) {
+			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, id, msg);
+		} else {
+			NetworkServer_HandleChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, id, msg, NETWORK_SERVER_INDEX);
+		}
+	}	break;
+#endif /* ENABLE_NETWORK */
+		default: NOT_REACHED();
+	}
+
+	_rename_id = _rename_what = -1;
+}
+
+/**
+ * This code is shared for the majority of the pushbuttons.
+ * Handles e.g. the pressing of a button (to build things), playing of click sound and sets certain parameters
+ *
+ * @param w Window which called the function
+ * @param widget ID of the widget (=button) that called this function
+ * @param cursor How should the cursor image change? E.g. cursor with depot image in it
+ * @param mode Tile highlighting mode, e.g. drawing a rectangle or a dot on the ground
+ * @param placeproc Procedure which will be called when someone clicks on the map
+
+ * @return true if the button is clicked, false if it's unclicked
+ */
+bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, int mode, PlaceProc *placeproc)
+{
+	if (IsWindowWidgetDisabled(w, widget)) return false;
+
+	SndPlayFx(SND_15_BEEP);
+	SetWindowDirty(w);
+
+	if (IsWindowWidgetLowered(w, widget)) {
+		ResetObjectToPlace();
+		return false;
+	}
+
+	SetObjectToPlace(cursor, mode, w->window_class, w->window_number);
+	LowerWindowWidget(w, widget);
+	_place_proc = placeproc;
+	return true;
+}
+
+
+void CcPlaySound10(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) SndPlayTileFx(SND_12_EXPLOSION, tile);
+}
+
+
+static void ToolbarPauseClick(Window *w)
+{
+	if (_networking && !_network_server) return; // only server can pause the game
+
+	if (DoCommandP(0, _pause ? 0 : 1, 0, NULL, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
+}
+
+static void ToolbarFastForwardClick(Window *w)
+{
+	_fast_forward ^= true;
+	SndPlayFx(SND_15_BEEP);
+}
+
+
+static void MenuClickSettings(int index)
+{
+	switch (index) {
+		case 0: ShowGameOptions();      return;
+		case 1: ShowGameDifficulty();   return;
+		case 2: ShowPatchesSelection(); return;
+		case 3: ShowNewGRFSettings(!_networking, true, true, &_grfconfig);   return;
+
+		case  5: _display_opt ^= DO_SHOW_TOWN_NAMES;    break;
+		case  6: _display_opt ^= DO_SHOW_STATION_NAMES; break;
+		case  7: _display_opt ^= DO_SHOW_SIGNS;         break;
+		case  8: _display_opt ^= DO_WAYPOINTS;          break;
+		case  9: _display_opt ^= DO_FULL_ANIMATION;     break;
+		case 10: _display_opt ^= DO_FULL_DETAIL;        break;
+		case 11: _display_opt ^= DO_TRANS_BUILDINGS;    break;
+		case 12: _display_opt ^= DO_TRANS_SIGNS;        break;
+	}
+	MarkWholeScreenDirty();
+}
+
+static void MenuClickSaveLoad(int index)
+{
+	if (_game_mode == GM_EDITOR) {
+		switch (index) {
+			case 0: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break;
+			case 1: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
+			case 2: AskExitToGameMenu();                   break;
+			case 4: HandleExitGameRequest();               break;
+		}
+	} else {
+		switch (index) {
+			case 0: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
+			case 1: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+			case 2: AskExitToGameMenu();               break;
+			case 3: HandleExitGameRequest();           break;
+		}
+	}
+}
+
+static void MenuClickMap(int index)
+{
+	switch (index) {
+		case 0: ShowSmallMap();            break;
+		case 1: ShowExtraViewPortWindow(); break;
+		case 2: ShowSignList();            break;
+	}
+}
+
+static void MenuClickTown(int index)
+{
+	ShowTownDirectory();
+}
+
+static void MenuClickScenMap(int index)
+{
+	switch (index) {
+		case 0: ShowSmallMap();            break;
+		case 1: ShowExtraViewPortWindow(); break;
+		case 2: ShowSignList();            break;
+		case 3: ShowTownDirectory();       break;
+	}
+}
+
+static void MenuClickSubsidies(int index)
+{
+	ShowSubsidiesList();
+}
+
+static void MenuClickStations(int index)
+{
+	ShowPlayerStations(index);
+}
+
+static void MenuClickFinances(int index)
+{
+	ShowPlayerFinances(index);
+}
+
+static void MenuClickCompany(int index)
+{
+	if (_networking && index == 0) {
+		ShowClientList();
+	} else {
+		if (_networking) index--;
+		ShowPlayerCompany(index);
+	}
+}
+
+static void MenuClickGraphs(int index)
+{
+	switch (index) {
+		case 0: ShowOperatingProfitGraph();    break;
+		case 1: ShowIncomeGraph();             break;
+		case 2: ShowDeliveredCargoGraph();     break;
+		case 3: ShowPerformanceHistoryGraph(); break;
+		case 4: ShowCompanyValueGraph();       break;
+		case 5: ShowCargoPaymentRates();       break;
+	}
+}
+
+static void MenuClickLeague(int index)
+{
+	switch (index) {
+		case 0: ShowCompanyLeagueTable();      break;
+		case 1: ShowPerformanceRatingDetail(); break;
+	}
+}
+
+static void MenuClickIndustry(int index)
+{
+	switch (index) {
+		case 0: ShowIndustryDirectory();   break;
+		case 1: ShowBuildIndustryWindow(); break;
+	}
+}
+
+static void MenuClickShowTrains(int index)
+{
+	ShowVehicleListWindow(index, INVALID_STATION, VEH_Train);
+}
+
+static void MenuClickShowRoad(int index)
+{
+	ShowVehicleListWindow(index, INVALID_STATION, VEH_Road);
+}
+
+static void MenuClickShowShips(int index)
+{
+	ShowVehicleListWindow(index, INVALID_STATION, VEH_Ship);
+}
+
+static void MenuClickShowAir(int index)
+{
+	ShowVehicleListWindow(index, INVALID_STATION, VEH_Aircraft);
+}
+
+static void MenuClickBuildRail(int index)
+{
+	_last_built_railtype = index;
+	ShowBuildRailToolbar(_last_built_railtype, -1);
+}
+
+static void MenuClickBuildRoad(int index)
+{
+	ShowBuildRoadToolbar();
+}
+
+static void MenuClickBuildWater(int index)
+{
+	ShowBuildDocksToolbar();
+}
+
+static void MenuClickBuildAir(int index)
+{
+	ShowBuildAirToolbar();
+}
+
+#ifdef ENABLE_NETWORK
+void ShowNetworkGiveMoneyWindow(PlayerID player)
+{
+	_rename_id = player;
+	_rename_what = 3;
+	ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, 180, NULL, CS_NUMERAL);
+}
+#endif /* ENABLE_NETWORK */
+
+void ShowRenameSignWindow(const Sign *si)
+{
+	_rename_id = si->index;
+	_rename_what = 0;
+	ShowQueryString(si->str, STR_280B_EDIT_SIGN_TEXT, 30, 180, NULL, CS_ALPHANUMERAL);
+}
+
+void ShowRenameWaypointWindow(const Waypoint *wp)
+{
+	int id = wp->index;
+
+	/* Are we allowed to change the name of the waypoint? */
+	if (!CheckTileOwnership(wp->xy)) {
+		ShowErrorMessage(_error_message, STR_CANT_CHANGE_WAYPOINT_NAME,
+			TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
+		return;
+	}
+
+	_rename_id = id;
+	_rename_what = 1;
+	SetDParam(0, id);
+	ShowQueryString(STR_WAYPOINT_RAW, STR_EDIT_WAYPOINT_NAME, 30, 180, NULL, CS_ALPHANUMERAL);
+}
+
+static void SelectSignTool(void)
+{
+	if (_cursor.sprite == SPR_CURSOR_SIGN) {
+		ResetObjectToPlace();
+	} else {
+		SetObjectToPlace(SPR_CURSOR_SIGN, 1, 1, 0);
+		_place_proc = PlaceProc_Sign;
+	}
+}
+
+static void MenuClickForest(int index)
+{
+	switch (index) {
+		case 0: ShowTerraformToolbar();  break;
+		case 1: ShowBuildTreesToolbar(); break;
+		case 2: SelectSignTool();        break;
+	}
+}
+
+static void MenuClickMusicWindow(int index)
+{
+	ShowMusicWindow();
+}
+
+static void MenuClickNewspaper(int index)
+{
+	switch (index) {
+		case 0: ShowLastNewsMessage(); break;
+		case 1: ShowMessageOptions();  break;
+		case 2: ShowMessageHistory();  break;
+	}
+}
+
+static void MenuClickSmallScreenshot(void)
+{
+	SetScreenshotType(SC_VIEWPORT);
+}
+
+static void MenuClickWorldScreenshot(void)
+{
+	SetScreenshotType(SC_WORLD);
+}
+
+static void MenuClickHelp(int index)
+{
+	switch (index) {
+		case 0: PlaceLandBlockInfo();       break;
+		case 2: IConsoleSwitch();           break;
+		case 3: MenuClickSmallScreenshot(); break;
+		case 4: MenuClickWorldScreenshot(); break;
+		case 5: ShowAboutWindow();          break;
+	}
+}
+
+
+typedef void MenuClickedProc(int index);
+
+static MenuClickedProc * const _menu_clicked_procs[] = {
+	NULL,                 /* 0 */
+	NULL,                 /* 1 */
+	MenuClickSettings,    /* 2 */
+	MenuClickSaveLoad,    /* 3 */
+	MenuClickMap,         /* 4 */
+	MenuClickTown,        /* 5 */
+	MenuClickSubsidies,   /* 6 */
+	MenuClickStations,    /* 7 */
+	MenuClickFinances,    /* 8 */
+	MenuClickCompany,     /* 9 */
+	MenuClickGraphs,      /* 10 */
+	MenuClickLeague,      /* 11 */
+	MenuClickIndustry,    /* 12 */
+	MenuClickShowTrains,  /* 13 */
+	MenuClickShowRoad,    /* 14 */
+	MenuClickShowShips,   /* 15 */
+	MenuClickShowAir,     /* 16 */
+	MenuClickScenMap,     /* 17 */
+	NULL,                 /* 18 */
+	MenuClickBuildRail,   /* 19 */
+	MenuClickBuildRoad,   /* 20 */
+	MenuClickBuildWater,  /* 21 */
+	MenuClickBuildAir,    /* 22 */
+	MenuClickForest,      /* 23 */
+	MenuClickMusicWindow, /* 24 */
+	MenuClickNewspaper,   /* 25 */
+	MenuClickHelp,        /* 26 */
+};
+
+static void MenuWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_CREATE: w->widget[0].right = w->width - 1; break;
+
+	case WE_PAINT: {
+		int x, y;
+
+		byte count = WP(w, menu_d).item_count;
+		byte sel = WP(w, menu_d).sel_index;
+		uint16 chk = WP(w, menu_d).checked_items;
+		StringID string = WP(w, menu_d).string_id;
+		byte dis = WP(w, menu_d).disabled_items;
+
+		DrawWindowWidgets(w);
+
+		x = 1;
+		y = 1;
+
+		for (; count != 0; count--, string++, sel--) {
+			byte color = HASBIT(dis, 0) ? 14 : (sel == 0) ? 12 : 16;
+			if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
+
+			if (HASBIT(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
+			DrawString(x + 2, y, string, color);
+
+			y += 10;
+			chk >>= 1;
+			dis >>= 1;
+		}
+	} break;
+
+	case WE_DESTROY: {
+			Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
+			RaiseWindowWidget(v, WP(w,menu_d).main_button);
+			SetWindowDirty(v);
+			return;
+		}
+
+	case WE_POPUPMENU_SELECT: {
+		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
+		int action_id;
+
+
+		if (index < 0) {
+			Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
+			if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w,menu_d).main_button)
+				index = WP(w,menu_d).sel_index;
+		}
+
+		action_id = WP(w,menu_d).action_id;
+		DeleteWindow(w);
+
+		if (index >= 0) {
+			assert((uint)index <= lengthof(_menu_clicked_procs));
+			_menu_clicked_procs[action_id](index);
+		}
+
+		break;
+		}
+
+	case WE_POPUPMENU_OVER: {
+		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
+
+		if (index == -1 || index == WP(w,menu_d).sel_index) return;
+
+		WP(w,menu_d).sel_index = index;
+		SetWindowDirty(w);
+		return;
+		}
+	}
+}
+
+/* Dynamic widget length determined by toolbar-string length.
+ * See PopupMainToolbMenu en MenuWndProc */
+static const Widget _menu_widgets[] = {
+{    WWT_PANEL, RESIZE_NONE, 14, 0,  0, 0, 0, 0x0, STR_NULL},
+{ WIDGETS_END},
+};
+
+
+static const Widget _player_menu_widgets[] = {
+{    WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
+{ WIDGETS_END},
+};
+
+
+static int GetPlayerIndexFromMenu(int index)
+{
+	if (index >= 0) {
+		const Player *p;
+
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && --index < 0) return p->index;
+		}
+	}
+	return -1;
+}
+
+static void UpdatePlayerMenuHeight(Window *w)
+{
+	byte num = ActivePlayerCount();
+
+	// Increase one to fit in PlayerList in the menu when in network
+	if (_networking && WP(w,menu_d).main_button == 9) num++;
+
+	if (WP(w,menu_d).item_count != num) {
+		WP(w,menu_d).item_count = num;
+		SetWindowDirty(w);
+		num = num * 10 + 2;
+		w->height = num;
+		w->widget[0].bottom = w->widget[0].top + num - 1;
+		SetWindowDirty(w);
+	}
+}
+
+extern void DrawPlayerIcon(PlayerID pid, int x, int y);
+
+static void PlayerMenuWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int x,y;
+		byte sel, color;
+		Player *p;
+		uint16 chk;
+
+		UpdatePlayerMenuHeight(w);
+		DrawWindowWidgets(w);
+
+		x = 1;
+		y = 1;
+		sel = WP(w,menu_d).sel_index;
+		chk = WP(w,menu_d).checked_items; // let this mean gray items.
+
+		// 9 = playerlist
+		if (_networking && WP(w,menu_d).main_button == 9) {
+			if (sel == 0) {
+				GfxFillRect(x, y, x + 238, y + 9, 0);
+			}
+			DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, 0x0);
+			y += 10;
+			sel--;
+		}
+
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				if (p->index == sel) {
+					GfxFillRect(x, y, x + 238, y + 9, 0);
+				}
+
+				DrawPlayerIcon(p->index, x + 2, y + 1);
+
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				SetDParam(2, GetPlayerNameString(p->index, 3));
+
+				color = (p->index == sel) ? 0xC : 0x10;
+				if (chk&1) color = 14;
+				DrawString(x + 19, y, STR_7021, color);
+
+				y += 10;
+			}
+			chk >>= 1;
+		}
+
+		break;
+		}
+
+	case WE_DESTROY: {
+		Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		RaiseWindowWidget(v, WP(w,menu_d).main_button);
+		SetWindowDirty(v);
+		return;
+		}
+
+	case WE_POPUPMENU_SELECT: {
+		int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
+		int action_id = WP(w,menu_d).action_id;
+
+		// We have a new entry at the top of the list of menu 9 when networking
+		//  so keep that in count
+		if (_networking && WP(w,menu_d).main_button == 9) {
+			if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+		} else {
+			index = GetPlayerIndexFromMenu(index);
+		}
+
+		if (index < 0) {
+			Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
+			if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w,menu_d).main_button)
+				index = WP(w,menu_d).sel_index;
+		}
+
+		DeleteWindow(w);
+
+		if (index >= 0) {
+			assert(index >= 0 && index < 30);
+			_menu_clicked_procs[action_id](index);
+		}
+		break;
+		}
+	case WE_POPUPMENU_OVER: {
+		int index;
+		UpdatePlayerMenuHeight(w);
+		index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
+
+		// We have a new entry at the top of the list of menu 9 when networking
+		//  so keep that in count
+		if (_networking && WP(w,menu_d).main_button == 9) {
+			if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+		} else {
+			index = GetPlayerIndexFromMenu(index);
+		}
+
+		if (index == -1 || index == WP(w,menu_d).sel_index) return;
+
+		WP(w,menu_d).sel_index = index;
+		SetWindowDirty(w);
+		return;
+		}
+	}
+}
+
+/** Get the maximum length of a given string in a string-list. This is an
+ * implicit string-list where the ID's are consecutive
+ * @param base_string StringID of the first string in the list
+ * @param count amount of StringID's in the list
+ * @return the length of the longest string */
+static int GetStringListMaxWidth(StringID base_string, byte count)
+{
+	char buffer[512];
+	int width, max_width;
+	byte i;
+
+	max_width = 0;
+	for (i = 0; i != count; i++) {
+		GetString(buffer, base_string + i, lastof(buffer));
+		width = GetStringBoundingBox(buffer).width;
+		if (width > max_width) max_width = width;
+	}
+
+	return max_width;
+}
+
+/** Show a general dropdown menu. The positioning of the dropdown menu
+ * defaults to the left side of the parent_button, eg the button that caused
+ * this window to appear. The only exceptions are when the right side of this
+ * dropdown would fall outside the main toolbar window, in that case it is
+ * aligned with the toolbar's right side.
+ * Since the disable-mask is only 8 bits right now, these dropdowns are
+ * restricted to 8 items max if any bits of disabled_mask are active.
+ * @param w Pointer to a window this dropdown menu belongs to. Has no effect
+ * whatsoever, only graphically for positioning.
+ * @param parent_button The widget identifier of the button that was clicked for
+ * this dropdown. The created dropdown then knows what button to raise (button) on
+ * action and whose function to execute (action).
+ * It is possible to appoint another button for an action event by setting the
+ * upper 8 bits of this parameter. If non is set, action is presumed to be the same
+ * as button. So<br>
+ * button bits 0 -  7 - widget clicked to get dropdown
+ * action bits 8 - 15 - function of widget to execute on select (defaults to bits 0 - 7)
+ * @param base_string The first StringID shown in the dropdown list. All others are
+ * consecutive indeces from the language file. XXX - fix? Use ingame-string tables?
+ * @param item_count Number of strings in the list, see previous parameter
+ * @param disabled_mask Bitmask of disabled strings in the list
+ * @return Return a pointer to the newly created dropdown window */
+static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask)
+{
+	int width;
+	int x = w->widget[GB(parent_button, 0, 8)].left;
+
+	assert(disabled_mask == 0 || item_count <= 8);
+	LowerWindowWidget(w, parent_button);
+	InvalidateWidget(w, parent_button);
+
+	DeleteWindowById(WC_TOOLBAR_MENU, 0);
+
+	/* Extend the dropdown toolbar to the longest string in the list and
+	 * also make sure the dropdown is fully visible within the window.
+	 * x + w->left because x is supposed to be the offset of the toolbar-button
+	 * we clicked on and w->left the toolbar window itself. So meaning that
+	 * the default position is aligned with the left side of the clicked button */
+	width = max(GetStringListMaxWidth(base_string, item_count) + 6, 140);
+	x = w->left + clamp(x, 0, w->width - width); // or alternatively '_screen.width - width'
+
+	w = AllocateWindow(x, 22, width, item_count * 10 + 2, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
+	w->widget[0].bottom = item_count * 10 + 1;
+	w->flags4 &= ~WF_WHITE_BORDER_MASK;
+
+	WP(w,menu_d).item_count = item_count;
+	WP(w,menu_d).sel_index = 0;
+	WP(w,menu_d).main_button = GB(parent_button, 0, 8);
+	WP(w,menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
+	WP(w,menu_d).string_id = base_string;
+	WP(w,menu_d).checked_items = 0;
+	WP(w,menu_d).disabled_items = disabled_mask;
+
+	_popup_menu_active = true;
+
+	SndPlayFx(SND_15_BEEP);
+	return w;
+}
+
+static Window *PopupMainPlayerToolbMenu(Window *w, int x, int main_button, int gray)
+{
+	x += w->left;
+
+	LowerWindowWidget(w, main_button);
+	InvalidateWidget(w, main_button);
+
+	DeleteWindowById(WC_TOOLBAR_MENU, 0);
+	w = AllocateWindow(x, 0x16, 0xF1, 0x52, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
+	w->flags4 &= ~WF_WHITE_BORDER_MASK;
+	WP(w,menu_d).item_count = 0;
+	WP(w,menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
+	if (_networking && main_button == 9) {
+		if (_local_player != PLAYER_SPECTATOR) {
+			WP(w,menu_d).sel_index++;
+		} else {
+			/* Select client list by default for spectators */
+			WP(w,menu_d).sel_index = 0;
+		}
+	}
+	WP(w,menu_d).action_id = main_button;
+	WP(w,menu_d).main_button = main_button;
+	WP(w,menu_d).checked_items = gray;
+	WP(w,menu_d).disabled_items = 0;
+	_popup_menu_active = true;
+	SndPlayFx(SND_15_BEEP);
+	return w;
+}
+
+static void ToolbarSaveClick(Window *w)
+{
+	PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4, 0);
+}
+
+static void ToolbarMapClick(Window *w)
+{
+	PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3, 0);
+}
+
+static void ToolbarTownClick(Window *w)
+{
+	PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1, 0);
+}
+
+static void ToolbarSubsidiesClick(Window *w)
+{
+	PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1, 0);
+}
+
+static void ToolbarStationsClick(Window *w)
+{
+	PopupMainPlayerToolbMenu(w, 162, 7, 0);
+}
+
+static void ToolbarMoneyClick(Window *w)
+{
+	PopupMainPlayerToolbMenu(w, 191, 8, 0);
+}
+
+static void ToolbarPlayersClick(Window *w)
+{
+	PopupMainPlayerToolbMenu(w, 213, 9, 0);
+}
+
+static void ToolbarGraphsClick(Window *w)
+{
+	PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6, 0);
+}
+
+static void ToolbarLeagueClick(Window *w)
+{
+	PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2, 0);
+}
+
+static void ToolbarIndustryClick(Window *w)
+{
+	/* Disable build-industry menu if we are a spectator */
+	PopupMainToolbMenu(w, 12, STR_INDUSTRY_DIR, 2, (_current_player == PLAYER_SPECTATOR) ? (1 << 1) : 0);
+}
+
+static void ToolbarTrainClick(Window *w)
+{
+	const Vehicle *v;
+	int dis = -1;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && IsFrontEngine(v)) CLRBIT(dis, v->owner);
+	}
+	PopupMainPlayerToolbMenu(w, 310, 13, dis);
+}
+
+static void ToolbarRoadClick(Window *w)
+{
+	const Vehicle *v;
+	int dis = -1;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Road) CLRBIT(dis, v->owner);
+	}
+	PopupMainPlayerToolbMenu(w, 332, 14, dis);
+}
+
+static void ToolbarShipClick(Window *w)
+{
+	const Vehicle *v;
+	int dis = -1;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Ship) CLRBIT(dis, v->owner);
+	}
+	PopupMainPlayerToolbMenu(w, 354, 15, dis);
+}
+
+static void ToolbarAirClick(Window *w)
+{
+	const Vehicle *v;
+	int dis = -1;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Aircraft) CLRBIT(dis, v->owner);
+	}
+	PopupMainPlayerToolbMenu(w, 376, 16, dis);
+}
+
+/* Zooms a viewport in a window in or out */
+/* No button handling or what so ever */
+bool DoZoomInOutWindow(int how, Window *w)
+{
+	ViewPort *vp;
+
+	assert(w != NULL);
+	vp = w->viewport;
+
+	switch (how) {
+		case ZOOM_IN:
+			if (vp->zoom == 0) return false;
+			vp->zoom--;
+			vp->virtual_width >>= 1;
+			vp->virtual_height >>= 1;
+
+			WP(w,vp_d).scrollpos_x += vp->virtual_width >> 1;
+			WP(w,vp_d).scrollpos_y += vp->virtual_height >> 1;
+			break;
+		case ZOOM_OUT:
+			if (vp->zoom == 2) return false;
+			vp->zoom++;
+
+			WP(w,vp_d).scrollpos_x -= vp->virtual_width >> 1;
+			WP(w,vp_d).scrollpos_y -= vp->virtual_height >> 1;
+
+			vp->virtual_width <<= 1;
+			vp->virtual_height <<= 1;
+			break;
+	}
+	if (vp != NULL) { // the vp can be null when how == ZOOM_NONE
+		vp->virtual_left = WP(w, vp_d).scrollpos_x;
+		vp->virtual_top = WP(w, vp_d).scrollpos_y;
+	}
+	SetWindowDirty(w);
+	/* Update the windows that have zoom-buttons to perhaps disable their buttons */
+	SendWindowMessageClass(w->window_class, how, w->window_number, 0);
+	return true;
+}
+
+static void ToolbarZoomInClick(Window *w)
+{
+	if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
+		HandleButtonClick(w, 17);
+		SndPlayFx(SND_15_BEEP);
+	}
+}
+
+static void ToolbarZoomOutClick(Window *w)
+{
+	if (DoZoomInOutWindow(ZOOM_OUT,FindWindowById(WC_MAIN_WINDOW, 0))) {
+		HandleButtonClick(w, 18);
+		SndPlayFx(SND_15_BEEP);
+	}
+}
+
+static void ToolbarBuildRailClick(Window *w)
+{
+	const Player *p = GetPlayer(_local_player);
+	Window *w2;
+	w2 = PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes);
+	WP(w2,menu_d).sel_index = _last_built_railtype;
+}
+
+static void ToolbarBuildRoadClick(Window *w)
+{
+	PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 1, 0);
+}
+
+static void ToolbarBuildWaterClick(Window *w)
+{
+	PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1, 0);
+}
+
+static void ToolbarBuildAirClick(Window *w)
+{
+	PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1, 0);
+}
+
+static void ToolbarForestClick(Window *w)
+{
+	PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3, 0);
+}
+
+static void ToolbarMusicClick(Window *w)
+{
+	PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1, 0);
+}
+
+static void ToolbarNewspaperClick(Window *w)
+{
+	PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3, 0);
+}
+
+static void ToolbarHelpClick(Window *w)
+{
+	PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 6, 0);
+}
+
+static void ToolbarOptionsClick(Window *w)
+{
+	uint16 x = 0;
+
+	w = PopupMainToolbMenu(w, 2, STR_02C3_GAME_OPTIONS, 13, 0);
+
+	if (_display_opt & DO_SHOW_TOWN_NAMES)    SETBIT(x,  5);
+	if (_display_opt & DO_SHOW_STATION_NAMES) SETBIT(x,  6);
+	if (_display_opt & DO_SHOW_SIGNS)         SETBIT(x,  7);
+	if (_display_opt & DO_WAYPOINTS)          SETBIT(x,  8);
+	if (_display_opt & DO_FULL_ANIMATION)     SETBIT(x,  9);
+	if (_display_opt & DO_FULL_DETAIL)        SETBIT(x, 10);
+	if (_display_opt & DO_TRANS_BUILDINGS)    SETBIT(x, 11);
+	if (_display_opt & DO_TRANS_SIGNS)        SETBIT(x, 12);
+	WP(w,menu_d).checked_items = x;
+}
+
+
+static void ToolbarScenSaveOrLoad(Window *w)
+{
+	PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 5, 0);
+}
+
+static void ToolbarScenDateBackward(Window *w)
+{
+	// don't allow too fast scrolling
+	if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+		HandleButtonClick(w, 6);
+		SetWindowDirty(w);
+
+		_patches_newgame.starting_year = clamp(_patches_newgame.starting_year - 1, MIN_YEAR, MAX_YEAR);
+		SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+	}
+	_left_button_clicked = false;
+}
+
+static void ToolbarScenDateForward(Window *w)
+{
+	// don't allow too fast scrolling
+	if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
+		HandleButtonClick(w, 7);
+		SetWindowDirty(w);
+
+		_patches_newgame.starting_year = clamp(_patches_newgame.starting_year + 1, MIN_YEAR, MAX_YEAR);
+		SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+	}
+	_left_button_clicked = false;
+}
+
+static void ToolbarScenMapTownDir(Window *w)
+{
+	/* Scenario editor button, *hack*hack* use different button to activate */
+	PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4, 0);
+}
+
+static void ToolbarScenZoomIn(Window *w)
+{
+	if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
+		HandleButtonClick(w, 9);
+		SndPlayFx(SND_15_BEEP);
+	}
+}
+
+static void ToolbarScenZoomOut(Window *w)
+{
+	if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
+		HandleButtonClick(w, 10);
+		SndPlayFx(SND_15_BEEP);
+	}
+}
+
+void ZoomInOrOutToCursorWindow(bool in, Window *w)
+{
+	ViewPort *vp;
+	Point pt;
+
+	assert(w != 0);
+
+	vp = w->viewport;
+
+	if (_game_mode != GM_MENU) {
+		if ((in && vp->zoom == 0) || (!in && vp->zoom == 2))
+			return;
+
+		pt = GetTileZoomCenterWindow(in,w);
+		if (pt.x != -1) {
+			ScrollWindowTo(pt.x, pt.y, w);
+
+			DoZoomInOutWindow(in ? ZOOM_IN : ZOOM_OUT, w);
+		}
+	}
+}
+
+// TODO - Incorporate into game itself to allow for ingame raising/lowering of
+// larger chunks at the same time OR remove altogether, as we have 'level land' ?
+/**
+ * Raise/Lower a bigger chunk of land at the same time in the editor. When
+ * raising get the lowest point, when lowering the highest point, and set all
+ * tiles in the selection to that height.
+ * @param tile The top-left tile where the terraforming will start
+ * @param mode 1 for raising, 0 for lowering land
+ */
+static void CommonRaiseLowerBigLand(TileIndex tile, int mode)
+{
+	int sizex, sizey;
+	byte h;
+
+	_generating_world = true; // used to create green terraformed land
+
+	if (_terraform_size == 1) {
+		StringID msg =
+			mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
+
+		DoCommandP(tile, 8, (uint32)mode, CcTerraform, CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(msg));
+	} else {
+		SndPlayTileFx(SND_1F_SPLAT, tile);
+
+		assert(_terraform_size != 0);
+		// check out for map overflows
+		sizex = min(MapSizeX() - TileX(tile) - 1, _terraform_size);
+		sizey = min(MapSizeY() - TileY(tile) - 1, _terraform_size);
+
+		if (sizex == 0 || sizey == 0) return;
+
+		if (mode != 0) {
+			/* Raise land */
+			h = 15; // XXX - max height
+			BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
+				h = min(h, TileHeight(tile2));
+			} END_TILE_LOOP(tile2, sizex, sizey, tile)
+		} else {
+			/* Lower land */
+			h = 0;
+			BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
+				h = max(h, TileHeight(tile2));
+			} END_TILE_LOOP(tile2, sizex, sizey, tile)
+		}
+
+		BEGIN_TILE_LOOP(tile2, sizex, sizey, tile) {
+			if (TileHeight(tile2) == h) {
+				DoCommandP(tile2, 8, (uint32)mode, NULL, CMD_TERRAFORM_LAND | CMD_AUTO);
+			}
+		} END_TILE_LOOP(tile2, sizex, sizey, tile)
+	}
+
+	_generating_world = false;
+}
+
+static void PlaceProc_RaiseBigLand(TileIndex tile)
+{
+	CommonRaiseLowerBigLand(tile, 1);
+}
+
+static void PlaceProc_LowerBigLand(TileIndex tile)
+{
+	CommonRaiseLowerBigLand(tile, 0);
+}
+
+static void PlaceProc_RockyArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_RockyArea);
+}
+
+static void PlaceProc_LightHouse(TileIndex tile)
+{
+	if (!IsTileType(tile, MP_CLEAR) || IsSteepSlope(GetTileSlope(tile, NULL))) {
+		return;
+	}
+
+	MakeLighthouse(tile);
+	MarkTileDirtyByTile(tile);
+	SndPlayTileFx(SND_1F_SPLAT, tile);
+}
+
+static void PlaceProc_Transmitter(TileIndex tile)
+{
+	if (!IsTileType(tile, MP_CLEAR) || IsSteepSlope(GetTileSlope(tile, NULL))) {
+		return;
+	}
+
+	MakeTransmitter(tile);
+	MarkTileDirtyByTile(tile);
+	SndPlayTileFx(SND_1F_SPLAT, tile);
+}
+
+static void PlaceProc_DesertArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DesertArea);
+}
+
+static void PlaceProc_WaterArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_WaterArea);
+}
+
+static const Widget _scen_edit_land_gen_widgets[] = {
+{  WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                  STR_018B_CLOSE_WINDOW},
+{   WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_0223_LAND_GENERATION,  STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_STICKYBOX,   RESIZE_NONE,     7,   170,   181,     0,    13, STR_NULL,                  STR_STICKY_BUTTON},
+{     WWT_PANEL,   RESIZE_NONE,     7,     0,   181,    14,    95, 0x0,                       STR_NULL},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,     2,    23,    14,    35, SPR_IMG_DYNAMITE,          STR_018D_DEMOLISH_BUILDINGS_ETC},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,    24,    45,    14,    35, SPR_IMG_TERRAFORM_DOWN,    STR_018E_LOWER_A_CORNER_OF_LAND},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,    46,    67,    14,    35, SPR_IMG_TERRAFORM_UP,      STR_018F_RAISE_A_CORNER_OF_LAND},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,    68,    89,    14,    35, SPR_IMG_LEVEL_LAND,        STR_LEVEL_LAND_TOOLTIP},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,    90,   111,    14,    35, SPR_IMG_BUILD_CANAL,       STR_CREATE_LAKE},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,   112,   134,    14,    35, SPR_IMG_ROCKS,             STR_028C_PLACE_ROCKY_AREAS_ON_LANDSCAPE},
+{    WWT_IMGBTN,   RESIZE_NONE,    14,   135,   157,    14,    35, SPR_IMG_LIGHTHOUSE_DESERT, STR_NULL}, // XXX - dynamic
+{    WWT_IMGBTN,   RESIZE_NONE,    14,   158,   179,    14,    35, SPR_IMG_TRANSMITTER,       STR_028E_PLACE_TRANSMITTER},
+{   WWT_TEXTBTN,   RESIZE_NONE,    14,   139,   149,    43,    54, STR_0224,                  STR_0228_INCREASE_SIZE_OF_LAND_AREA},
+{   WWT_TEXTBTN,   RESIZE_NONE,    14,   139,   149,    56,    67, STR_0225,                  STR_0229_DECREASE_SIZE_OF_LAND_AREA},
+{   WWT_TEXTBTN,   RESIZE_NONE,    14,    34,   149,    75,    86, STR_SE_NEW_WORLD,          STR_022A_GENERATE_RANDOM_LAND},
+{   WIDGETS_END},
+};
+
+static const int8 _multi_terraform_coords[][2] = {
+	{  0, -2},
+	{  4,  0}, { -4,  0}, {  0,  2},
+	{ -8,  2}, { -4,  4}, {  0,  6}, {  4,  4}, {  8,  2},
+	{-12,  0}, { -8, -2}, { -4, -4}, {  0, -6}, {  4, -4}, {  8, -2}, { 12,  0},
+	{-16,  2}, {-12,  4}, { -8,  6}, { -4,  8}, {  0, 10}, {  4,  8}, {  8,  6}, { 12,  4}, { 16,  2},
+	{-20,  0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, {  0,-10}, {  4, -8}, {  8, -6}, { 12, -4}, { 16, -2}, { 20,  0},
+	{-24,  2}, {-20,  4}, {-16,  6}, {-12,  8}, { -8, 10}, { -4, 12}, {  0, 14}, {  4, 12}, {  8, 10}, { 12,  8}, { 16,  6}, { 20,  4}, { 24,  2},
+	{-28,  0}, {-24, -2}, {-20, -4}, {-16, -6}, {-12, -8}, { -8,-10}, { -4,-12}, {  0,-14}, {  4,-12}, {  8,-10}, { 12, -8}, { 16, -6}, { 20, -4}, { 24, -2}, { 28,  0},
+};
+
+// TODO - Merge with terraform_gui.c (move there) after I have cooled down at its braindeadness
+// and changed OnButtonClick to include the widget as well in the function decleration. Post 0.4.0 - Darkvater
+static void EditorTerraformClick_Dynamite(Window *w)
+{
+	HandlePlacePushButton(w, 4, ANIMCURSOR_DEMOLISH, 1, PlaceProc_DemolishArea);
+}
+
+static void EditorTerraformClick_LowerBigLand(Window *w)
+{
+	HandlePlacePushButton(w, 5, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerBigLand);
+}
+
+static void EditorTerraformClick_RaiseBigLand(Window *w)
+{
+	HandlePlacePushButton(w, 6, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseBigLand);
+}
+
+static void EditorTerraformClick_LevelLand(Window *w)
+{
+	HandlePlacePushButton(w, 7, SPR_CURSOR_LEVEL_LAND, 2, PlaceProc_LevelLand);
+}
+
+static void EditorTerraformClick_WaterArea(Window *w)
+{
+	HandlePlacePushButton(w, 8, SPR_CURSOR_CANAL, 1, PlaceProc_WaterArea);
+}
+
+static void EditorTerraformClick_RockyArea(Window *w)
+{
+	HandlePlacePushButton(w, 9, SPR_CURSOR_ROCKY_AREA, 1, PlaceProc_RockyArea);
+}
+
+static void EditorTerraformClick_DesertLightHouse(Window *w)
+{
+	HandlePlacePushButton(w, 10, SPR_CURSOR_LIGHTHOUSE, 1, (_opt.landscape == LT_DESERT) ? PlaceProc_DesertArea : PlaceProc_LightHouse);
+}
+
+static void EditorTerraformClick_Transmitter(Window *w)
+{
+	HandlePlacePushButton(w, 11, SPR_CURSOR_TRANSMITTER, 1, PlaceProc_Transmitter);
+}
+
+static const uint16 _editor_terraform_keycodes[] = {
+	'D',
+	'Q',
+	'W',
+	'E',
+	'R',
+	'T',
+	'Y',
+	'U'
+};
+
+typedef void OnButtonClick(Window *w);
+static OnButtonClick * const _editor_terraform_button_proc[] = {
+	EditorTerraformClick_Dynamite,
+	EditorTerraformClick_LowerBigLand,
+	EditorTerraformClick_RaiseBigLand,
+	EditorTerraformClick_LevelLand,
+	EditorTerraformClick_WaterArea,
+	EditorTerraformClick_RockyArea,
+	EditorTerraformClick_DesertLightHouse,
+	EditorTerraformClick_Transmitter
+};
+
+static void ScenEditLandGenWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE:
+		// XXX - lighthouse button is widget 10!! Don't forget when changing
+		w->widget[10].tooltips = (_opt.landscape == LT_DESERT) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
+		break;
+
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+
+		{
+			int n = _terraform_size * _terraform_size;
+			const int8 *coords = &_multi_terraform_coords[0][0];
+
+			assert(n != 0);
+			do {
+				DrawSprite(SPR_WHITE_POINT, 77 + coords[0], 55 + coords[1]);
+				coords += 2;
+			} while (--n);
+		}
+
+		if (IsWindowWidgetLowered(w, 5) || IsWindowWidgetLowered(w, 6)) // change area-size if raise/lower corner is selected
+			SetTileSelectSize(_terraform_size, _terraform_size);
+
+		break;
+
+	case WE_KEYPRESS: {
+		uint i;
+
+		for (i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
+			if (e->we.keypress.keycode == _editor_terraform_keycodes[i]) {
+				e->we.keypress.cont = false;
+				_editor_terraform_button_proc[i](w);
+				break;
+			}
+		}
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11:
+			_editor_terraform_button_proc[e->we.click.widget - 4](w);
+			break;
+		case 12: case 13: { /* Increase/Decrease terraform size */
+			int size = (e->we.click.widget == 12) ? 1 : -1;
+			HandleButtonClick(w, e->we.click.widget);
+			size += _terraform_size;
+
+			if (!IS_INT_INSIDE(size, 1, 8 + 1)) return;
+			_terraform_size = size;
+
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+		} break;
+		case 14: /* gen random land */
+			HandleButtonClick(w, 14);
+			ShowCreateScenario();
+			break;
+		}
+		break;
+
+	case WE_TIMEOUT: {
+		uint i;
+		for (i = 0; i < w->widget_count; i++) {
+			if (IsWindowWidgetLowered(w, i)) {
+				RaiseWindowWidget(w, i);
+				InvalidateWidget(w, i);
+			}
+			if (i == 3) i = 11;
+		}
+		break;
+	}
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		break;
+	case WE_PLACE_DRAG:
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
+		break;
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) // dragged actions
+				GUIPlaceProcDragXY(e);
+		}
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const WindowDesc _scen_edit_land_gen_desc = {
+	WDP_AUTO, WDP_AUTO, 182, 96,
+	WC_SCEN_LAND_GEN,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_scen_edit_land_gen_widgets,
+	ScenEditLandGenWndProc,
+};
+
+static inline void ShowEditorTerraformToolBar(void)
+{
+	AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0);
+}
+
+static void ToolbarScenGenLand(Window *w)
+{
+	HandleButtonClick(w, 11);
+	SndPlayFx(SND_15_BEEP);
+
+	ShowEditorTerraformToolBar();
+}
+
+void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_1F_SPLAT, tile);
+		ResetObjectToPlace();
+	}
+}
+
+static void PlaceProc_Town(TileIndex tile)
+{
+	DoCommandP(tile, _scengen_town_size, 0, CcBuildTown, CMD_BUILD_TOWN | CMD_MSG(STR_0236_CAN_T_BUILD_TOWN_HERE));
+}
+
+
+static const Widget _scen_edit_town_gen_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_0233_TOWN_GENERATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   148,   159,     0,    13, 0x0,                      STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   159,    14,    81, 0x0,                      STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    16,    27, STR_0234_NEW_TOWN,        STR_0235_CONSTRUCT_NEW_TOWN},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    29,    40, STR_023D_RANDOM_TOWN,     STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    42,    53, STR_MANY_RANDOM_TOWNS,    STR_RANDOM_TOWNS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,    53,    68,    79, STR_02A1_SMALL,           STR_02A4_SELECT_TOWN_SIZE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    54,   105,    68,    79, STR_02A2_MEDIUM,          STR_02A4_SELECT_TOWN_SIZE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   106,   157,    68,    79, STR_02A3_LARGE,           STR_02A4_SELECT_TOWN_SIZE},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    54,    67, STR_02A5_TOWN_SIZE,       STR_NULL},
+{   WIDGETS_END},
+};
+
+static void ScenEditTownGenWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CREATE:
+		LowerWindowWidget(w, (_scengen_town_size - 1)+ 7);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 4: /* new town */
+			HandlePlacePushButton(w, 4, SPR_CURSOR_TOWN, 1, PlaceProc_Town);
+			break;
+		case 5: {/* random town */
+			Town *t;
+
+			HandleButtonClick(w, 5);
+			_generating_world = true;
+			t = CreateRandomTown(20, _scengen_town_size);
+			_generating_world = false;
+
+			if (t == NULL) {
+				ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+			} else {
+				ScrollMainWindowToTile(t->xy);
+			}
+
+			break;
+		}
+		case 6: {/* many random towns */
+			HandleButtonClick(w, 6);
+
+			_generating_world = true;
+			if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+			_generating_world = false;
+			break;
+		}
+
+		case 7: case 8: case 9:
+			RaiseWindowWidget(w, (_scengen_town_size - 1) + 7);
+			_scengen_town_size = (e->we.click.widget - 7) + 1;
+			LowerWindowWidget(w, (_scengen_town_size - 1) + 7);
+			SetWindowDirty(w);
+			break;
+		}
+		break;
+
+	case WE_TIMEOUT:
+		RaiseWindowWidget(w, 5);
+		RaiseWindowWidget(w, 6);
+		SetWindowDirty(w);
+		break;
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		break;
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		LowerWindowWidget(w, (_scengen_town_size - 1) + 7);
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const WindowDesc _scen_edit_town_gen_desc = {
+	WDP_AUTO, WDP_AUTO, 160, 82,
+	WC_SCEN_TOWN_GEN,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_scen_edit_town_gen_widgets,
+	ScenEditTownGenWndProc,
+};
+
+static void ToolbarScenGenTown(Window *w)
+{
+	HandleButtonClick(w, 12);
+	SndPlayFx(SND_15_BEEP);
+
+	AllocateWindowDescFront(&_scen_edit_town_gen_desc, 0);
+}
+
+
+static const Widget _scenedit_industry_normal_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                          STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,   STR_RANDOM_INDUSTRIES_TIP},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0240_COAL_MINE,           STR_0262_CONSTRUCT_COAL_MINE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0241_POWER_STATION,       STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0242_SAWMILL,             STR_0264_CONSTRUCT_SAWMILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0243_FOREST,              STR_0265_PLANT_FOREST},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_0244_OIL_REFINERY,        STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_0245_OIL_RIG,             STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_0246_FACTORY,             STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_0247_STEEL_MILL,          STR_0269_CONSTRUCT_STEEL_MILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0248_FARM,                STR_026A_CONSTRUCT_FARM},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_0249_IRON_ORE_MINE,       STR_026B_CONSTRUCT_IRON_ORE_MINE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024A_OIL_WELLS,           STR_026C_CONSTRUCT_OIL_WELLS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   185,   196, STR_024B_BANK,                STR_026D_CONSTRUCT_BANK_CAN_ONLY},
+{   WIDGETS_END},
+};
+
+
+static const Widget _scenedit_industry_hilly_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION,   STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                            STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,     STR_RANDOM_INDUSTRIES_TIP},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0240_COAL_MINE,             STR_0262_CONSTRUCT_COAL_MINE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0241_POWER_STATION,         STR_0263_CONSTRUCT_POWER_STATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_024C_PAPER_MILL,            STR_026E_CONSTRUCT_PAPER_MILL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0243_FOREST,                STR_0265_PLANT_FOREST},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_0244_OIL_REFINERY,          STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_024D_FOOD_PROCESSING_PLANT, STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_024E_PRINTING_WORKS,        STR_0270_CONSTRUCT_PRINTING_WORKS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_024F_GOLD_MINE,             STR_0271_CONSTRUCT_GOLD_MINE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0248_FARM,                  STR_026A_CONSTRUCT_FARM},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_024B_BANK,                  STR_0272_CONSTRUCT_BANK_CAN_ONLY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024A_OIL_WELLS,             STR_026C_CONSTRUCT_OIL_WELLS},
+{   WIDGETS_END},
+};
+
+static const Widget _scenedit_industry_desert_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION,    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                             STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,      STR_RANDOM_INDUSTRIES_TIP},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0250_LUMBER_MILL,            STR_0273_CONSTRUCT_LUMBER_MILL_TO},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0251_FRUIT_PLANTATION,       STR_0274_PLANT_FRUIT_PLANTATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0252_RUBBER_PLANTATION,      STR_0275_PLANT_RUBBER_PLANTATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_0244_OIL_REFINERY,           STR_0266_CONSTRUCT_OIL_REFINERY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_024D_FOOD_PROCESSING_PLANT,  STR_026F_CONSTRUCT_FOOD_PROCESSING},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_0246_FACTORY,                STR_0268_CONSTRUCT_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_0253_WATER_SUPPLY,           STR_0276_CONSTRUCT_WATER_SUPPLY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_0248_FARM,                   STR_026A_CONSTRUCT_FARM},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_0254_WATER_TOWER,            STR_0277_CONSTRUCT_WATER_TOWER_CAN},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_024A_OIL_WELLS,              STR_026C_CONSTRUCT_OIL_WELLS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_024B_BANK,                   STR_0272_CONSTRUCT_BANK_CAN_ONLY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   185,   196, STR_0255_DIAMOND_MINE,           STR_0278_CONSTRUCT_DIAMOND_MINE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   198,   209, STR_0256_COPPER_ORE_MINE,        STR_0279_CONSTRUCT_COPPER_ORE_MINE},
+{   WIDGETS_END},
+};
+
+static const Widget _scenedit_industry_candy_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   169,     0,    13, STR_023F_INDUSTRY_GENERATION, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   169,    14,   224, 0x0,                          STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    16,    27, STR_MANY_RANDOM_INDUSTRIES,   STR_RANDOM_INDUSTRIES_TIP},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    42,    53, STR_0257_COTTON_CANDY_FOREST, STR_027A_PLANT_COTTON_CANDY_FOREST},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    55,    66, STR_0258_CANDY_FACTORY,       STR_027B_CONSTRUCT_CANDY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    68,    79, STR_0259_BATTERY_FARM,        STR_027C_CONSTRUCT_BATTERY_FARM},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    81,    92, STR_025A_COLA_WELLS,          STR_027D_CONSTRUCT_COLA_WELLS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,    94,   105, STR_025B_TOY_SHOP,            STR_027E_CONSTRUCT_TOY_SHOP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   107,   118, STR_025C_TOY_FACTORY,         STR_027F_CONSTRUCT_TOY_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   120,   131, STR_025D_PLASTIC_FOUNTAINS,   STR_0280_CONSTRUCT_PLASTIC_FOUNTAINS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   133,   144, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   146,   157, STR_025F_BUBBLE_GENERATOR,    STR_0282_CONSTRUCT_BUBBLE_GENERATOR},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   159,   170, STR_0260_TOFFEE_QUARRY,       STR_0283_CONSTRUCT_TOFFEE_QUARRY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   167,   172,   183, STR_0261_SUGAR_MINE,          STR_0284_CONSTRUCT_SUGAR_MINE},
+{   WIDGETS_END},
+};
+
+
+static bool AnyTownExists(void)
+{
+	const Town *t;
+
+	FOR_ALL_TOWNS(t) return true;
+
+	return false;
+}
+
+extern Industry *CreateNewIndustry(TileIndex tile, int type);
+
+/**
+ * Search callback function for TryBuildIndustry
+ * @param tile to test
+ * @param data that is passed by the caller.  In this case, the type of industry been tested
+ * @result of the operation
+ */
+static bool SearchTileForIndustry(TileIndex tile, uint32 data)
+{
+	return CreateNewIndustry(tile, data) != NULL;
+}
+
+/**
+ * Perform a 9*9 tiles circular search around a tile
+ * in order to find a suitable zone to create the desired industry
+ * @param tile to start search for
+ * @param type of the desired industry
+ */
+static bool TryBuildIndustry(TileIndex tile, int type)
+{
+	return CircularTileSearch(tile, 9, SearchTileForIndustry, type);
+}
+
+
+static const byte _industry_type_list[4][16] = {
+	{ 0,  1,  2,  3,  4,  5,  6,  8,  9, 18, 11, 12},
+	{ 0,  1, 14,  3,  4, 13,  7, 15,  9, 16, 11, 12},
+	{25, 19, 20,  4, 13, 23, 21, 24, 22, 11, 16, 17, 10},
+	{26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36},
+};
+
+static int _industry_type_to_place;
+bool _ignore_restrictions;
+
+static void ScenEditIndustryWndProc(Window *w, WindowEvent *e)
+{
+	int button;
+
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK:
+		if (e->we.click.widget == 3) {
+			HandleButtonClick(w, 3);
+
+			if (!AnyTownExists()) {
+				ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0);
+				return;
+			}
+
+			_generating_world = true;
+			GenerateIndustries();
+			_generating_world = false;
+		}
+
+		if ((button=e->we.click.widget) >= 4) {
+			if (HandlePlacePushButton(w, button, SPR_CURSOR_INDUSTRY, 1, NULL))
+				_industry_type_to_place = _industry_type_list[_opt.landscape][button - 4];
+		}
+		break;
+	case WE_PLACE_OBJ: {
+		int type;
+
+		// Show error if no town exists at all
+		type = _industry_type_to_place;
+		if (!AnyTownExists()) {
+			SetDParam(0, GetIndustrySpec(type)->name);
+			ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
+			return;
+		}
+
+		_current_player = OWNER_NONE;
+		_generating_world = true;
+		_ignore_restrictions = true;
+		if (!TryBuildIndustry(e->we.place.tile,type)) {
+			SetDParam(0, GetIndustrySpec(type)->name);
+			ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
+		}
+		_ignore_restrictions = false;
+		_generating_world = false;
+		break;
+	}
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		SetWindowDirty(w);
+		break;
+	case WE_TIMEOUT:
+		RaiseWindowWidget(w, 3);
+		InvalidateWidget(w, 3);
+		break;
+	}
+}
+
+static const WindowDesc _scenedit_industry_normal_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 225,
+	WC_SCEN_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_scenedit_industry_normal_widgets,
+	ScenEditIndustryWndProc,
+};
+
+static const WindowDesc _scenedit_industry_hilly_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 225,
+	WC_SCEN_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_scenedit_industry_hilly_widgets,
+	ScenEditIndustryWndProc,
+};
+
+static const WindowDesc _scenedit_industry_desert_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 225,
+	WC_SCEN_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_scenedit_industry_desert_widgets,
+	ScenEditIndustryWndProc,
+};
+
+static const WindowDesc _scenedit_industry_candy_desc = {
+	WDP_AUTO, WDP_AUTO, 170, 225,
+	WC_SCEN_INDUSTRY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_scenedit_industry_candy_widgets,
+	ScenEditIndustryWndProc,
+};
+
+static const WindowDesc * const _scenedit_industry_descs[] = {
+	&_scenedit_industry_normal_desc,
+	&_scenedit_industry_hilly_desc,
+	&_scenedit_industry_desert_desc,
+	&_scenedit_industry_candy_desc,
+};
+
+
+static void ToolbarScenGenIndustry(Window *w)
+{
+	HandleButtonClick(w, 13);
+	SndPlayFx(SND_15_BEEP);
+	AllocateWindowDescFront(_scenedit_industry_descs[_opt.landscape],0);
+}
+
+static void ToolbarScenBuildRoad(Window *w)
+{
+	HandleButtonClick(w, 14);
+	SndPlayFx(SND_15_BEEP);
+	ShowBuildRoadScenToolbar();
+}
+
+static void ToolbarScenPlantTrees(Window *w)
+{
+	HandleButtonClick(w, 15);
+	SndPlayFx(SND_15_BEEP);
+	ShowBuildTreesScenToolbar();
+}
+
+static void ToolbarScenPlaceSign(Window *w)
+{
+	HandleButtonClick(w, 16);
+	SndPlayFx(SND_15_BEEP);
+	SelectSignTool();
+}
+
+static void ToolbarBtn_NULL(Window *w)
+{
+}
+
+
+typedef void ToolbarButtonProc(Window *w);
+
+static ToolbarButtonProc * const _toolbar_button_procs[] = {
+	ToolbarPauseClick,
+	ToolbarFastForwardClick,
+	ToolbarOptionsClick,
+	ToolbarSaveClick,
+	ToolbarMapClick,
+	ToolbarTownClick,
+	ToolbarSubsidiesClick,
+	ToolbarStationsClick,
+	ToolbarMoneyClick,
+	ToolbarPlayersClick,
+	ToolbarGraphsClick,
+	ToolbarLeagueClick,
+	ToolbarIndustryClick,
+	ToolbarTrainClick,
+	ToolbarRoadClick,
+	ToolbarShipClick,
+	ToolbarAirClick,
+	ToolbarZoomInClick,
+	ToolbarZoomOutClick,
+	ToolbarBuildRailClick,
+	ToolbarBuildRoadClick,
+	ToolbarBuildWaterClick,
+	ToolbarBuildAirClick,
+	ToolbarForestClick,
+	ToolbarMusicClick,
+	ToolbarNewspaperClick,
+	ToolbarHelpClick,
+};
+
+static void MainToolbarWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		// Draw brown-red toolbar bg.
+		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
+		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | PALETTE_MODIFIER_GREYOUT);
+
+		/* If spectator, disable all construction buttons
+		 * ie : Build road, rail, ships, airports and landscaping
+		 * Since enabled state is the default, just disable when needed */
+		SetWindowWidgetsDisabledState(w, _current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
+		/* disable company list drop downs, if there are no companies */
+		SetWindowWidgetsDisabledState(w, ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
+
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK: {
+		if (_game_mode != GM_MENU && !IsWindowWidgetDisabled(w, e->we.click.widget))
+			_toolbar_button_procs[e->we.click.widget](w);
+	} break;
+
+	case WE_KEYPRESS: {
+		switch (e->we.keypress.keycode) {
+		case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
+		case WKC_F2: ShowGameOptions(); break;
+		case WKC_F3: MenuClickSaveLoad(0); break;
+		case WKC_F4: ShowSmallMap(); break;
+		case WKC_F5: ShowTownDirectory(); break;
+		case WKC_F6: ShowSubsidiesList(); break;
+		case WKC_F7: ShowPlayerStations(_local_player); break;
+		case WKC_F8: ShowPlayerFinances(_local_player); break;
+		case WKC_F9: ShowPlayerCompany(_local_player); break;
+		case WKC_F10:ShowOperatingProfitGraph(); break;
+		case WKC_F11: ShowCompanyLeagueTable(); break;
+		case WKC_F12: ShowBuildIndustryWindow(); break;
+		case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Train); break;
+		case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Road); break;
+		case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Ship); break;
+		case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, INVALID_STATION, VEH_Aircraft); break;
+		case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
+		case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
+		case WKC_SHIFT | WKC_F7: ShowBuildRailToolbar(_last_built_railtype, -1); break;
+		case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(); break;
+		case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
+		case WKC_SHIFT | WKC_F10:ShowBuildAirToolbar(); break;
+		case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
+		case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
+		case WKC_CTRL  | 'S': MenuClickSmallScreenshot(); break;
+		case WKC_CTRL  | 'G': MenuClickWorldScreenshot(); break;
+		case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
+		case 'A': ShowBuildRailToolbar(_last_built_railtype, 4); break; /* Invoke Autorail */
+		case 'L': ShowTerraformToolbar(); break;
+		default: return;
+		}
+		e->we.keypress.cont = false;
+	} break;
+
+	case WE_PLACE_OBJ: {
+		_place_proc(e->we.place.tile);
+	} break;
+
+	case WE_ABORT_PLACE_OBJ: {
+		RaiseWindowWidget(w, 25);
+		SetWindowDirty(w);
+	} break;
+
+	case WE_MOUSELOOP:
+		if (IsWindowWidgetLowered(w, 0) != !!_pause) {
+			ToggleWidgetLoweredState(w, 0);
+			InvalidateWidget(w, 0);
+		}
+
+		if (IsWindowWidgetLowered(w, 1) != !!_fast_forward) {
+			ToggleWidgetLoweredState(w, 1);
+			InvalidateWidget(w, 1);
+		}
+		break;
+
+	case WE_TIMEOUT: {
+		uint i;
+		for (i = 2; i < w->widget_count; i++) {
+			if (IsWindowWidgetLowered(w, i)) {
+				RaiseWindowWidget(w, i);
+				InvalidateWidget(w, i);
+			}
+		}
+		break;
+	}
+
+		case WE_MESSAGE:
+			HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
+			break;
+	}
+}
+
+static const Widget _toolb_normal_widgets[] = {
+{     WWT_IMGBTN,   RESIZE_NONE,    14,     0,    21,     0,    21, SPR_IMG_PAUSE,           STR_0171_PAUSE_GAME},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,    22,    43,     0,    21, SPR_IMG_FASTFORWARD,     STR_FAST_FORWARD},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,    44,    65,     0,    21, SPR_IMG_SETTINGS,        STR_0187_OPTIONS},
+{   WWT_IMGBTN_2,   RESIZE_NONE,    14,    66,    87,     0,    21, SPR_IMG_SAVE,            STR_0172_SAVE_GAME_ABANDON_GAME},
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,    96,   117,     0,    21, SPR_IMG_SMALLMAP,        STR_0174_DISPLAY_MAP},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   118,   139,     0,    21, SPR_IMG_TOWN,            STR_0176_DISPLAY_TOWN_DIRECTORY},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   140,   161,     0,    21, SPR_IMG_SUBSIDIES,       STR_02DC_DISPLAY_SUBSIDIES},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   162,   183,     0,    21, SPR_IMG_COMPANY_LIST,    STR_0173_DISPLAY_LIST_OF_COMPANY},
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   191,   212,     0,    21, SPR_IMG_COMPANY_FINANCE, STR_0177_DISPLAY_COMPANY_FINANCES},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   213,   235,     0,    21, SPR_IMG_COMPANY_GENERAL, STR_0178_DISPLAY_COMPANY_GENERAL},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   236,   257,     0,    21, SPR_IMG_GRAPHS,          STR_0179_DISPLAY_GRAPHS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   258,   279,     0,    21, SPR_IMG_COMPANY_LEAGUE,  STR_017A_DISPLAY_COMPANY_LEAGUE},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   280,   301,     0,    21, SPR_IMG_INDUSTRY,        STR_0312_FUND_CONSTRUCTION_OF_NEW},
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   310,   331,     0,    21, SPR_IMG_TRAINLIST,       STR_017B_DISPLAY_LIST_OF_COMPANY},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   332,   353,     0,    21, SPR_IMG_TRUCKLIST,       STR_017C_DISPLAY_LIST_OF_COMPANY},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   354,   375,     0,    21, SPR_IMG_SHIPLIST,        STR_017D_DISPLAY_LIST_OF_COMPANY},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   376,   397,     0,    21, SPR_IMG_AIRPLANESLIST,   STR_017E_DISPLAY_LIST_OF_COMPANY},
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   406,   427,     0,    21, SPR_IMG_ZOOMIN,          STR_017F_ZOOM_THE_VIEW_IN},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   428,   449,     0,    21, SPR_IMG_ZOOMOUT,         STR_0180_ZOOM_THE_VIEW_OUT},
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   457,   478,     0,    21, SPR_IMG_BUILDRAIL,       STR_0181_BUILD_RAILROAD_TRACK},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   479,   500,     0,    21, SPR_IMG_BUILDROAD,       STR_0182_BUILD_ROADS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   501,   522,     0,    21, SPR_IMG_BUILDWATER,      STR_0183_BUILD_SHIP_DOCKS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   523,   544,     0,    21, SPR_IMG_BUILDAIR,        STR_0184_BUILD_AIRPORTS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   545,   566,     0,    21, SPR_IMG_LANDSCAPING,     STR_LANDSCAPING_TOOLBAR_TIP}, // tree icon is 0x2E6
+
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   574,   595,     0,    21, SPR_IMG_MUSIC,           STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   596,   617,     0,    21, SPR_IMG_MESSAGES,        STR_0203_SHOW_LAST_MESSAGE_NEWS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   618,   639,     0,    21, SPR_IMG_QUERY,           STR_0186_LAND_BLOCK_INFORMATION},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _toolb_normal_desc = {
+	0, 0, 640, 22,
+	WC_MAIN_TOOLBAR,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
+	_toolb_normal_widgets,
+	MainToolbarWndProc
+};
+
+
+static const Widget _toolb_scen_widgets[] = {
+{  WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  0, 21, SPR_IMG_PAUSE,       STR_0171_PAUSE_GAME},
+{  WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  0, 21, SPR_IMG_FASTFORWARD, STR_FAST_FORWARD},
+{  WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  0, 21, SPR_IMG_SETTINGS,    STR_0187_OPTIONS},
+{WWT_IMGBTN_2, RESIZE_NONE, 14,  66,  87,  0, 21, SPR_IMG_SAVE,        STR_0297_SAVE_SCENARIO_LOAD_SCENARIO},
+
+{   WWT_PANEL, RESIZE_NONE, 14,  96, 225,  0, 21, 0x0,                 STR_NULL},
+
+{   WWT_PANEL, RESIZE_NONE, 14, 233, 362,  0, 21, 0x0,                 STR_NULL},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 236, 247,  5, 16, SPR_ARROW_DOWN,      STR_029E_MOVE_THE_STARTING_DATE},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 347, 358,  5, 16, SPR_ARROW_UP,        STR_029F_MOVE_THE_STARTING_DATE},
+
+{  WWT_IMGBTN, RESIZE_NONE, 14, 371, 392,  0, 21, SPR_IMG_SMALLMAP,    STR_0175_DISPLAY_MAP_TOWN_DIRECTORY},
+
+{  WWT_IMGBTN, RESIZE_NONE, 14, 400, 421,  0, 21, SPR_IMG_ZOOMIN,      STR_017F_ZOOM_THE_VIEW_IN},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 422, 443,  0, 21, SPR_IMG_ZOOMOUT,     STR_0180_ZOOM_THE_VIEW_OUT},
+
+{  WWT_IMGBTN, RESIZE_NONE, 14, 452, 473,  0, 21, SPR_IMG_LANDSCAPING, STR_022E_LANDSCAPE_GENERATION},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 474, 495,  0, 21, SPR_IMG_TOWN,        STR_022F_TOWN_GENERATION},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 496, 517,  0, 21, SPR_IMG_INDUSTRY,    STR_0230_INDUSTRY_GENERATION},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 518, 539,  0, 21, SPR_IMG_BUILDROAD,   STR_0231_ROAD_CONSTRUCTION},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 540, 561,  0, 21, SPR_IMG_PLANTTREES,  STR_0288_PLANT_TREES},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 562, 583,  0, 21, SPR_IMG_SIGN,        STR_0289_PLACE_SIGN},
+
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 596, 617,  0, 21, SPR_IMG_MUSIC,       STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
+{   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
+{  WWT_IMGBTN, RESIZE_NONE, 14, 618, 639,  0, 21, SPR_IMG_QUERY,       STR_0186_LAND_BLOCK_INFORMATION},
+{WIDGETS_END},
+};
+
+static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
+	ToolbarPauseClick,
+	ToolbarFastForwardClick,
+	ToolbarOptionsClick,
+	ToolbarScenSaveOrLoad,
+	ToolbarBtn_NULL,
+	ToolbarBtn_NULL,
+	ToolbarScenDateBackward,
+	ToolbarScenDateForward,
+	ToolbarScenMapTownDir,
+	ToolbarScenZoomIn,
+	ToolbarScenZoomOut,
+	ToolbarScenGenLand,
+	ToolbarScenGenTown,
+	ToolbarScenGenIndustry,
+	ToolbarScenBuildRoad,
+	ToolbarScenPlantTrees,
+	ToolbarScenPlaceSign,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	ToolbarMusicClick,
+	NULL,
+	ToolbarHelpClick,
+};
+
+static void ScenEditToolbarWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		SetWindowWidgetDisabledState(w, 6, _patches_newgame.starting_year <= MIN_YEAR);
+		SetWindowWidgetDisabledState(w, 7, _patches_newgame.starting_year >= MAX_YEAR);
+
+		// Draw brown-red toolbar bg.
+		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
+		GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | PALETTE_MODIFIER_GREYOUT);
+
+		DrawWindowWidgets(w);
+
+		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+		DrawStringCentered(298, 6, STR_00AF, 0);
+
+		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+		DrawStringCentered(161, 1, STR_0221_OPENTTD, 0);
+		DrawStringCentered(161, 11,STR_0222_SCENARIO_EDITOR, 0);
+
+		break;
+
+	case WE_CLICK: {
+		if (_game_mode == GM_MENU) return;
+		_scen_toolbar_button_procs[e->we.click.widget](w);
+	} break;
+
+	case WE_KEYPRESS:
+		switch (e->we.keypress.keycode) {
+			case WKC_F1: ToolbarPauseClick(w); break;
+			case WKC_F2: ShowGameOptions(); break;
+			case WKC_F3: MenuClickSaveLoad(0); break;
+			case WKC_F4: ToolbarScenGenLand(w); break;
+			case WKC_F5: ToolbarScenGenTown(w); break;
+			case WKC_F6: ToolbarScenGenIndustry(w); break;
+			case WKC_F7: ToolbarScenBuildRoad(w); break;
+			case WKC_F8: ToolbarScenPlantTrees(w); break;
+			case WKC_F9: ToolbarScenPlaceSign(w); break;
+			case WKC_F10: ShowMusicWindow(); break;
+			case WKC_F11: PlaceLandBlockInfo(); break;
+			case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
+			case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
+			case 'L': ShowEditorTerraformToolBar(); break;
+			default: return;
+		}
+		e->we.keypress.cont = false;
+		break;
+
+	case WE_PLACE_OBJ: {
+		_place_proc(e->we.place.tile);
+	} break;
+
+	case WE_ABORT_PLACE_OBJ: {
+		RaiseWindowWidget(w, 25);
+		SetWindowDirty(w);
+	} break;
+
+	case WE_MOUSELOOP:
+		if (IsWindowWidgetLowered(w, 0) != !!_pause) {
+			ToggleWidgetLoweredState(w, 0);
+			SetWindowDirty(w);
+		}
+
+		if (IsWindowWidgetLowered(w, 1) != !!_fast_forward) {
+			ToggleWidgetLoweredState(w, 1);
+			SetWindowDirty(w);
+		}
+		break;
+
+		case WE_MESSAGE:
+			HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 9, 10);
+			break;
+	}
+}
+
+static const WindowDesc _toolb_scen_desc = {
+	0, 0, 640, 22,
+	WC_MAIN_TOOLBAR,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_toolb_scen_widgets,
+	ScenEditToolbarWndProc
+};
+
+extern GetNewsStringCallbackProc * const _get_news_string_callback[];
+
+
+static bool DrawScrollingStatusText(const NewsItem *ni, int pos)
+{
+	char buf[512];
+	StringID str;
+	const char *s;
+	char *d;
+	DrawPixelInfo tmp_dpi, *old_dpi;
+	int x;
+	char buffer[256];
+
+	if (ni->display_mode == 3) {
+		str = _get_news_string_callback[ni->callback](ni);
+	} else {
+		COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+		str = ni->string_id;
+	}
+
+	GetString(buf, str, lastof(buf));
+
+	s = buf;
+	d = buffer;
+
+	for (;;) {
+		WChar c = Utf8Consume(&s);
+		if (c == 0) {
+			*d = '\0';
+			break;
+		} else if (*s == 0x0D) {
+			d[0] = d[1] = d[2] = d[3] = ' ';
+			d += 4;
+		} else if (IsPrintable(c)) {
+			d += Utf8Encode(d, c);
+		}
+	}
+
+	if (!FillDrawPixelInfo(&tmp_dpi, 141, 1, 358, 11)) return true;
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = &tmp_dpi;
+
+	x = DoDrawString(buffer, pos, 0, 13);
+	_cur_dpi = old_dpi;
+
+	return x > 0;
+}
+
+static void StatusBarWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
+
+		DrawWindowWidgets(w);
+		SetDParam(0, _date);
+		DrawStringCentered(
+			70, 1, (_pause || _patches.status_long_date) ? STR_00AF : STR_00AE, 0
+		);
+
+		if (p != NULL) {
+			// Draw player money
+			SetDParam64(0, p->money64);
+			DrawStringCentered(570, 1, p->player_money >= 0 ? STR_0004 : STR_0005, 0);
+		}
+
+		// Draw status bar
+		if (w->message.msg) { // true when saving is active
+			DrawStringCentered(320, 1, STR_SAVING_GAME, 0);
+		} else if (_do_autosave) {
+			DrawStringCentered(320, 1, STR_032F_AUTOSAVE, 0);
+		} else if (_pause) {
+			DrawStringCentered(320, 1, STR_0319_PAUSED, 0);
+		} else if (WP(w,def_d).data_1 > -1280 && FindWindowById(WC_NEWS_WINDOW,0) == NULL && _statusbar_news_item.string_id != 0) {
+			// Draw the scrolling news text
+			if (!DrawScrollingStatusText(&_statusbar_news_item, WP(w,def_d).data_1))
+				WP(w,def_d).data_1 = -1280;
+		} else {
+			if (p != NULL) {
+				// This is the default text
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				DrawStringCentered(320, 1, STR_02BA, 0);
+			}
+		}
+
+		if (WP(w, def_d).data_2 > 0) DrawSprite(SPR_BLOT | PALETTE_TO_RED, 489, 2);
+	} break;
+
+	case WE_MESSAGE:
+		w->message.msg = e->we.message.msg;
+		SetWindowDirty(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 1: ShowLastNewsMessage(); break;
+			case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
+			default: ResetObjectToPlace();
+		}
+		break;
+
+	case WE_TICK: {
+		if (_pause) return;
+
+		if (WP(w, def_d).data_1 > -1280) { /* Scrolling text */
+			WP(w, def_d).data_1 -= 2;
+			InvalidateWidget(w, 1);
+		}
+
+		if (WP(w, def_d).data_2 > 0) { /* Red blot to show there are new unread newsmessages */
+			WP(w, def_d).data_2 -= 2;
+		} else if (WP(w, def_d).data_2 < 0) {
+			WP(w, def_d).data_2 = 0;
+			InvalidateWidget(w, 1);
+		}
+
+		break;
+	}
+	}
+}
+
+static const Widget _main_status_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   139,     0,    11, 0x0, STR_NULL},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   140,   499,     0,    11, 0x0, STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   500,   639,     0,    11, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static WindowDesc _main_status_desc = {
+	WDP_CENTER, 0, 640, 12,
+	WC_STATUS_BAR,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_main_status_widgets,
+	StatusBarWndProc
+};
+
+extern void UpdateAllStationVirtCoord(void);
+
+static void MainWindowWndProc(Window *w, WindowEvent *e)
+{
+	int off_x;
+
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowViewport(w);
+		if (_game_mode == GM_MENU) {
+			off_x = _screen.width / 2;
+
+			DrawSprite(SPR_OTTD_O, off_x - 120, 50);
+			DrawSprite(SPR_OTTD_P, off_x -  86, 50);
+			DrawSprite(SPR_OTTD_E, off_x -  53, 50);
+			DrawSprite(SPR_OTTD_N, off_x -  22, 50);
+
+			DrawSprite(SPR_OTTD_T, off_x +  34, 50);
+			DrawSprite(SPR_OTTD_T, off_x +  65, 50);
+			DrawSprite(SPR_OTTD_D, off_x +  96, 50);
+
+			/*
+			DrawSprite(SPR_OTTD_R, off_x + 119, 50);
+			DrawSprite(SPR_OTTD_A, off_x + 148, 50);
+			DrawSprite(SPR_OTTD_N, off_x + 181, 50);
+			DrawSprite(SPR_OTTD_S, off_x + 215, 50);
+			DrawSprite(SPR_OTTD_P, off_x + 246, 50);
+			DrawSprite(SPR_OTTD_O, off_x + 275, 50);
+			DrawSprite(SPR_OTTD_R, off_x + 307, 50);
+			DrawSprite(SPR_OTTD_T, off_x + 337, 50);
+
+			DrawSprite(SPR_OTTD_T, off_x + 390, 50);
+			DrawSprite(SPR_OTTD_Y, off_x + 417, 50);
+			DrawSprite(SPR_OTTD_C, off_x + 447, 50);
+			DrawSprite(SPR_OTTD_O, off_x + 478, 50);
+			DrawSprite(SPR_OTTD_O, off_x + 509, 50);
+			DrawSprite(SPR_OTTD_N, off_x + 541, 50);
+			*/
+		}
+		break;
+
+	case WE_KEYPRESS:
+		switch (e->we.keypress.keycode) {
+			case 'Q' | WKC_CTRL:
+			case 'Q' | WKC_META:
+				HandleExitGameRequest();
+				break;
+		}
+
+		/* Disable all key shortcuts, except quit shortcuts when
+		 * generating the world, otherwise they create threading
+		 * problem during the generating, resulting in random
+		 * assertions that are hard to trigger and debug */
+		if (IsGeneratingWorld()) break;
+
+		if (e->we.keypress.keycode == WKC_BACKQUOTE) {
+			IConsoleSwitch();
+			e->we.keypress.cont = false;
+			break;
+		}
+
+		if (_game_mode == GM_MENU) break;
+
+		switch (e->we.keypress.keycode) {
+			case 'C':
+			case 'Z': {
+				Point pt = GetTileBelowCursor();
+				if (pt.x != -1) {
+					ScrollMainWindowTo(pt.x, pt.y);
+					if (e->we.keypress.keycode == 'Z') MaxZoomInOut(ZOOM_IN, w);
+				}
+				break;
+			}
+
+			case WKC_ESC: ResetObjectToPlace(); break;
+			case WKC_DELETE: DeleteNonVitalWindows(); break;
+			case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
+			case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
+
+#if defined(_DEBUG)
+			case '0' | WKC_ALT: /* Crash the game */
+				*(byte*)0 = 0;
+				break;
+
+			case '1' | WKC_ALT: /* Gimme money */
+				/* Server can not cheat in advertise mode either! */
+				if (!_networking || !_network_server || !_network_advertise)
+					DoCommandP(0, -10000000, 0, NULL, CMD_MONEY_CHEAT);
+				break;
+
+			case '2' | WKC_ALT: /* Update the coordinates of all station signs */
+				UpdateAllStationVirtCoord();
+				break;
+#endif
+
+			case 'X':
+				_display_opt ^= DO_TRANS_BUILDINGS;
+				MarkWholeScreenDirty();
+				break;
+
+#ifdef ENABLE_NETWORK
+			case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
+				if (_networking) {
+					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
+					bool teamchat = false;
+
+					/* Only players actually playing can speak to team. Eg spectators cannot */
+					if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
+						const NetworkClientInfo *ci;
+						FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+							if (ci->client_playas == cio->client_playas && ci != cio) {
+								teamchat = true;
+								break;
+							}
+						}
+					}
+
+					ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
+				}
+				break;
+
+			case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
+				if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
+				break;
+
+			case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
+				if (_networking) {
+					const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
+					ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas);
+				}
+				break;
+#endif
+
+			default: return;
+		}
+		e->we.keypress.cont = false;
+		break;
+
+		case WE_SCROLL: {
+			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
+
+			if (vp == NULL) {
+				_cursor.fix_at = false;
+				_scrolling_viewport = false;
+			}
+
+			WP(w, vp_d).scrollpos_x += e->we.scroll.delta.x << vp->zoom;
+			WP(w, vp_d).scrollpos_y += e->we.scroll.delta.y << vp->zoom;
+		} break;
+
+		case WE_MOUSEWHEEL:
+			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
+			break;
+
+		case WE_MESSAGE:
+			/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
+			SendWindowMessage(WC_MAIN_TOOLBAR, 0, e->we.message.msg, e->we.message.wparam, e->we.message.lparam);
+			break;
+	}
+}
+
+
+void ShowSelectGameWindow(void);
+
+void SetupColorsAndInitialWindow(void)
+{
+	uint i;
+	Window *w;
+	int width, height;
+
+	for (i = 0; i != 16; i++) {
+		const byte *b = GetNonSprite(PALETTE_RECOLOR_START + i);
+
+		assert(b);
+		memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
+	}
+
+	width = _screen.width;
+	height = _screen.height;
+
+	w = AllocateWindow(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
+	AssignWindowViewport(w, 0, 0, width, height, TileXY(32, 32), 0);
+
+	// XXX: these are not done
+	switch (_game_mode) {
+		default: NOT_REACHED();
+		case GM_MENU:
+			ShowSelectGameWindow();
+			break;
+
+		case GM_NORMAL:
+		case GM_EDITOR:
+			ShowVitalWindows();
+			break;
+	}
+}
+
+void ShowVitalWindows(void)
+{
+	Window *w;
+
+	w = AllocateWindowDesc((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
+	DoZoomInOutWindow(ZOOM_NONE, w);
+
+	CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
+
+	SetWindowWidgetDisabledState(w, 0, _networking && !_network_server); // if not server, disable pause button
+	SetWindowWidgetDisabledState(w, 1, _networking); // if networking, disable fast-forward button
+
+	/* 'w' is for sure a WC_MAIN_TOOLBAR */
+	PositionMainToolbar(w);
+
+	/* Status bad only for normal games */
+	if (_game_mode == GM_EDITOR) return;
+
+	_main_status_desc.top = _screen.height - 12;
+	w = AllocateWindowDesc(&_main_status_desc);
+	CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
+
+	WP(w,def_d).data_1 = -1280;
+}
+
+void GameSizeChanged(void)
+{
+	_cur_resolution[0] = _screen.width;
+	_cur_resolution[1] = _screen.height;
+	RelocateAllWindows(_screen.width, _screen.height);
+	ScreenSizeChanged();
+	MarkWholeScreenDirty();
+}
+
+void InitializeMainGui(void)
+{
+	/* Clean old GUI values */
+	_last_built_railtype = 0;
+}
+
+
deleted file mode 100644
--- a/src/map.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "macros.h"
-#include "map.h"
-#include "direction.h"
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400 /* VStudio 2005 is stupid! */
-/* Why the hell is that not in all MSVC headers?? */
-_CRTIMP void __cdecl _assert(void *, void *, unsigned);
-#endif
-
-uint _map_log_x;
-uint _map_size_x;
-uint _map_size_y;
-uint _map_tile_mask;
-uint _map_size;
-
-Tile* _m = NULL;
-
-
-void AllocateMap(uint size_x, uint size_y)
-{
-	// Make sure that the map size is within the limits and that
-	// the x axis size is a power of 2.
-	if (size_x < 64 || size_x > 2048 ||
-			size_y < 64 || size_y > 2048 ||
-			(size_x&(size_x-1)) != 0 ||
-			(size_y&(size_y-1)) != 0)
-		error("Invalid map size");
-
-	DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y);
-
-	_map_log_x = FindFirstBit(size_x);
-	_map_size_x = size_x;
-	_map_size_y = size_y;
-	_map_size = size_x * size_y;
-	_map_tile_mask = _map_size - 1;
-
-	free(_m);
-	_m = calloc(_map_size, sizeof(*_m));
-
-	// XXX TODO handle memory shortage more gracefully
-	if (_m == NULL) error("Failed to allocate memory for the map");
-}
-
-
-#ifdef _DEBUG
-TileIndex TileAdd(TileIndex tile, TileIndexDiff add,
-	const char *exp, const char *file, int line)
-{
-	int dx;
-	int dy;
-	uint x;
-	uint y;
-
-	dx = add & MapMaxX();
-	if (dx >= (int)MapSizeX() / 2) dx -= MapSizeX();
-	dy = (add - dx) / (int)MapSizeX();
-
-	x = TileX(tile) + dx;
-	y = TileY(tile) + dy;
-
-	if (x >= MapSizeX() || y >= MapSizeY()) {
-		char buf[512];
-
-		snprintf(buf, lengthof(buf), "TILE_ADD(%s) when adding 0x%.4X and 0x%.4X failed",
-			exp, tile, add);
-#if !defined(_MSC_VER)
-		fprintf(stderr, "%s:%d %s\n", file, line, buf);
-#else
-		_assert(buf, (char*)file, line);
-#endif
-	}
-
-	assert(TileXY(x,y) == TILE_MASK(tile + add));
-
-	return TileXY(x,y);
-}
-#endif
-
-
-uint ScaleByMapSize(uint n)
-{
-	// First shift by 12 to prevent integer overflow for large values of n.
-	// >>12 is safe since the min mapsize is 64x64
-	// Add (1<<4)-1 to round upwards.
-	return (n * (MapSize() >> 12) + (1<<4) - 1) >> 4;
-}
-
-
-// Scale relative to the circumference of the map
-uint ScaleByMapSize1D(uint n)
-{
-	// Normal circumference for the X+Y is 256+256 = 1<<9
-	// Note, not actually taking the full circumference into account,
-	// just half of it.
-	// (1<<9) - 1 is there to scale upwards.
-	return (n * (MapSizeX() + MapSizeY()) + (1<<9) - 1) >> 9;
-}
-
-
-// This function checks if we add addx/addy to tile, if we
-//  do wrap around the edges. For example, tile = (10,2) and
-//  addx = +3 and addy = -4. This function will now return
-//  INVALID_TILE, because the y is wrapped. This is needed in
-//  for example, farmland. When the tile is not wrapped,
-//  the result will be tile + TileDiffXY(addx, addy)
-uint TileAddWrap(TileIndex tile, int addx, int addy)
-{
-	uint x = TileX(tile) + addx;
-	uint y = TileY(tile) + addy;
-
-	// Are we about to wrap?
-	if (x < MapMaxX() && y < MapMaxY())
-		return tile + TileDiffXY(addx, addy);
-
-	return INVALID_TILE;
-}
-
-const TileIndexDiffC _tileoffs_by_diagdir[] = {
-	{-1,  0}, // DIAGDIR_NE
-	{ 0,  1}, // DIAGDIR_SE
-	{ 1,  0}, // DIAGDIR_SW
-	{ 0, -1}  // DIAGDIR_NW
-};
-
-const TileIndexDiffC _tileoffs_by_dir[] = {
-	{-1, -1}, // DIR_N
-	{-1,  0}, // DIR_NE
-	{-1,  1}, // DIR_E
-	{ 0,  1}, // DIR_SE
-	{ 1,  1}, // DIR_S
-	{ 1,  0}, // DIR_SW
-	{ 1, -1}, // DIR_W
-	{ 0, -1}  // DIR_NW
-};
-
-uint DistanceManhattan(TileIndex t0, TileIndex t1)
-{
-	const uint dx = abs(TileX(t0) - TileX(t1));
-	const uint dy = abs(TileY(t0) - TileY(t1));
-	return dx + dy;
-}
-
-
-uint DistanceSquare(TileIndex t0, TileIndex t1)
-{
-	const int dx = TileX(t0) - TileX(t1);
-	const int dy = TileY(t0) - TileY(t1);
-	return dx * dx + dy * dy;
-}
-
-
-uint DistanceMax(TileIndex t0, TileIndex t1)
-{
-	const uint dx = abs(TileX(t0) - TileX(t1));
-	const uint dy = abs(TileY(t0) - TileY(t1));
-	return dx > dy ? dx : dy;
-}
-
-
-uint DistanceMaxPlusManhattan(TileIndex t0, TileIndex t1)
-{
-	const uint dx = abs(TileX(t0) - TileX(t1));
-	const uint dy = abs(TileY(t0) - TileY(t1));
-	return dx > dy ? 2 * dx + dy : 2 * dy + dx;
-}
-
-uint DistanceFromEdge(TileIndex tile)
-{
-	const uint xl = TileX(tile);
-	const uint yl = TileY(tile);
-	const uint xh = MapSizeX() - 1 - xl;
-	const uint yh = MapSizeY() - 1 - yl;
-	const uint minl = xl < yl ? xl : yl;
-	const uint minh = xh < yh ? xh : yh;
-	return minl < minh ? minl : minh;
-}
-
-/**
- * Function performing a search around a center tile and going outward, thus in circle.
- * Although it really is a square search...
- * Every tile will be tested by means of the callback function proc,
- * which will determine if yes or no the given tile meets criteria of search.
- * @param tile to start the search from
- * @param size: number of tiles per side of the desired search area
- * @param proc: callback testing function pointer.
- * @param data to be passed to the callback function. Depends on the implementation
- * @result of the search
- * @pre proc != NULL
- * @pre size > 0
- */
-bool CircularTileSearch(TileIndex tile, uint size, TestTileOnSearchProc proc, uint32 data)
-{
-	uint n, x, y;
-	DiagDirection dir;
-
-	assert(proc != NULL);
-	assert(size > 0);
-
-	x = TileX(tile);
-	y = TileY(tile);
-
-	if (size % 2 == 1) {
-		/* If the length of the side is uneven, the center has to be checked
-		 * separately, as the pattern of uneven sides requires to go around the center */
-		n = 2;
-		if (proc(TileXY(x, y), data)) return true;
-
-		/* If tile test is not successfull, get one tile down and left,
-		 * ready for a test in first circle around center tile */
-		x += _tileoffs_by_dir[DIR_W].x;
-		y += _tileoffs_by_dir[DIR_W].y;
-	} else {
-		n = 1;
-		/* To use _tileoffs_by_diagdir's order, we must relocate to
-		 * another tile, as we now first go 'up', 'right', 'down', 'left'
-		 * instead of 'right', 'down', 'left', 'up', which the calling
-		 * function assume. */
-		x++;
-	}
-
-	for (; n < size; n += 2) {
-		for (dir = DIAGDIR_NE; dir < DIAGDIR_END; dir++) {
-			uint j;
-			for (j = n; j != 0; j--) {
-				if (x <= MapMaxX() && y <= MapMaxY() && ///< Is the tile within the map?
-						proc(TileXY(x, y), data)) {     ///< Is the callback successfulll?
-					return true;                        ///< then stop the search
-				}
-
-				/* Step to the next 'neighbour' in the circular line */
-				x += _tileoffs_by_diagdir[dir].x;
-				y += _tileoffs_by_diagdir[dir].y;
-			}
-		}
-		/* Jump to next circle to test */
-		x += _tileoffs_by_dir[DIR_W].x;
-		y += _tileoffs_by_dir[DIR_W].y;
-	}
-	return false;
-}
new file mode 100644
--- /dev/null
+++ b/src/map.cpp
@@ -0,0 +1,246 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "macros.h"
+#include "map.h"
+#include "direction.h"
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 /* VStudio 2005 is stupid! */
+/* Why the hell is that not in all MSVC headers?? */
+_CRTIMP void __cdecl _assert(void *, void *, unsigned);
+#endif
+
+uint _map_log_x;
+uint _map_size_x;
+uint _map_size_y;
+uint _map_tile_mask;
+uint _map_size;
+
+Tile* _m = NULL;
+
+
+void AllocateMap(uint size_x, uint size_y)
+{
+	// Make sure that the map size is within the limits and that
+	// the x axis size is a power of 2.
+	if (size_x < 64 || size_x > 2048 ||
+			size_y < 64 || size_y > 2048 ||
+			(size_x&(size_x-1)) != 0 ||
+			(size_y&(size_y-1)) != 0)
+		error("Invalid map size");
+
+	DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y);
+
+	_map_log_x = FindFirstBit(size_x);
+	_map_size_x = size_x;
+	_map_size_y = size_y;
+	_map_size = size_x * size_y;
+	_map_tile_mask = _map_size - 1;
+
+	free(_m);
+	_m = calloc(_map_size, sizeof(*_m));
+
+	// XXX TODO handle memory shortage more gracefully
+	if (_m == NULL) error("Failed to allocate memory for the map");
+}
+
+
+#ifdef _DEBUG
+TileIndex TileAdd(TileIndex tile, TileIndexDiff add,
+	const char *exp, const char *file, int line)
+{
+	int dx;
+	int dy;
+	uint x;
+	uint y;
+
+	dx = add & MapMaxX();
+	if (dx >= (int)MapSizeX() / 2) dx -= MapSizeX();
+	dy = (add - dx) / (int)MapSizeX();
+
+	x = TileX(tile) + dx;
+	y = TileY(tile) + dy;
+
+	if (x >= MapSizeX() || y >= MapSizeY()) {
+		char buf[512];
+
+		snprintf(buf, lengthof(buf), "TILE_ADD(%s) when adding 0x%.4X and 0x%.4X failed",
+			exp, tile, add);
+#if !defined(_MSC_VER)
+		fprintf(stderr, "%s:%d %s\n", file, line, buf);
+#else
+		_assert(buf, (char*)file, line);
+#endif
+	}
+
+	assert(TileXY(x,y) == TILE_MASK(tile + add));
+
+	return TileXY(x,y);
+}
+#endif
+
+
+uint ScaleByMapSize(uint n)
+{
+	// First shift by 12 to prevent integer overflow for large values of n.
+	// >>12 is safe since the min mapsize is 64x64
+	// Add (1<<4)-1 to round upwards.
+	return (n * (MapSize() >> 12) + (1<<4) - 1) >> 4;
+}
+
+
+// Scale relative to the circumference of the map
+uint ScaleByMapSize1D(uint n)
+{
+	// Normal circumference for the X+Y is 256+256 = 1<<9
+	// Note, not actually taking the full circumference into account,
+	// just half of it.
+	// (1<<9) - 1 is there to scale upwards.
+	return (n * (MapSizeX() + MapSizeY()) + (1<<9) - 1) >> 9;
+}
+
+
+// This function checks if we add addx/addy to tile, if we
+//  do wrap around the edges. For example, tile = (10,2) and
+//  addx = +3 and addy = -4. This function will now return
+//  INVALID_TILE, because the y is wrapped. This is needed in
+//  for example, farmland. When the tile is not wrapped,
+//  the result will be tile + TileDiffXY(addx, addy)
+uint TileAddWrap(TileIndex tile, int addx, int addy)
+{
+	uint x = TileX(tile) + addx;
+	uint y = TileY(tile) + addy;
+
+	// Are we about to wrap?
+	if (x < MapMaxX() && y < MapMaxY())
+		return tile + TileDiffXY(addx, addy);
+
+	return INVALID_TILE;
+}
+
+const TileIndexDiffC _tileoffs_by_diagdir[] = {
+	{-1,  0}, // DIAGDIR_NE
+	{ 0,  1}, // DIAGDIR_SE
+	{ 1,  0}, // DIAGDIR_SW
+	{ 0, -1}  // DIAGDIR_NW
+};
+
+const TileIndexDiffC _tileoffs_by_dir[] = {
+	{-1, -1}, // DIR_N
+	{-1,  0}, // DIR_NE
+	{-1,  1}, // DIR_E
+	{ 0,  1}, // DIR_SE
+	{ 1,  1}, // DIR_S
+	{ 1,  0}, // DIR_SW
+	{ 1, -1}, // DIR_W
+	{ 0, -1}  // DIR_NW
+};
+
+uint DistanceManhattan(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+	return dx + dy;
+}
+
+
+uint DistanceSquare(TileIndex t0, TileIndex t1)
+{
+	const int dx = TileX(t0) - TileX(t1);
+	const int dy = TileY(t0) - TileY(t1);
+	return dx * dx + dy * dy;
+}
+
+
+uint DistanceMax(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+	return dx > dy ? dx : dy;
+}
+
+
+uint DistanceMaxPlusManhattan(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+	return dx > dy ? 2 * dx + dy : 2 * dy + dx;
+}
+
+uint DistanceFromEdge(TileIndex tile)
+{
+	const uint xl = TileX(tile);
+	const uint yl = TileY(tile);
+	const uint xh = MapSizeX() - 1 - xl;
+	const uint yh = MapSizeY() - 1 - yl;
+	const uint minl = xl < yl ? xl : yl;
+	const uint minh = xh < yh ? xh : yh;
+	return minl < minh ? minl : minh;
+}
+
+/**
+ * Function performing a search around a center tile and going outward, thus in circle.
+ * Although it really is a square search...
+ * Every tile will be tested by means of the callback function proc,
+ * which will determine if yes or no the given tile meets criteria of search.
+ * @param tile to start the search from
+ * @param size: number of tiles per side of the desired search area
+ * @param proc: callback testing function pointer.
+ * @param data to be passed to the callback function. Depends on the implementation
+ * @result of the search
+ * @pre proc != NULL
+ * @pre size > 0
+ */
+bool CircularTileSearch(TileIndex tile, uint size, TestTileOnSearchProc proc, uint32 data)
+{
+	uint n, x, y;
+	DiagDirection dir;
+
+	assert(proc != NULL);
+	assert(size > 0);
+
+	x = TileX(tile);
+	y = TileY(tile);
+
+	if (size % 2 == 1) {
+		/* If the length of the side is uneven, the center has to be checked
+		 * separately, as the pattern of uneven sides requires to go around the center */
+		n = 2;
+		if (proc(TileXY(x, y), data)) return true;
+
+		/* If tile test is not successfull, get one tile down and left,
+		 * ready for a test in first circle around center tile */
+		x += _tileoffs_by_dir[DIR_W].x;
+		y += _tileoffs_by_dir[DIR_W].y;
+	} else {
+		n = 1;
+		/* To use _tileoffs_by_diagdir's order, we must relocate to
+		 * another tile, as we now first go 'up', 'right', 'down', 'left'
+		 * instead of 'right', 'down', 'left', 'up', which the calling
+		 * function assume. */
+		x++;
+	}
+
+	for (; n < size; n += 2) {
+		for (dir = DIAGDIR_NE; dir < DIAGDIR_END; dir++) {
+			uint j;
+			for (j = n; j != 0; j--) {
+				if (x <= MapMaxX() && y <= MapMaxY() && ///< Is the tile within the map?
+						proc(TileXY(x, y), data)) {     ///< Is the callback successfulll?
+					return true;                        ///< then stop the search
+				}
+
+				/* Step to the next 'neighbour' in the circular line */
+				x += _tileoffs_by_diagdir[dir].x;
+				y += _tileoffs_by_diagdir[dir].y;
+			}
+		}
+		/* Jump to next circle to test */
+		x += _tileoffs_by_dir[DIR_W].x;
+		y += _tileoffs_by_dir[DIR_W].y;
+	}
+	return false;
+}
deleted file mode 100644
--- a/src/md5.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/* $Id$ */
-
-/*
-  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-/* $Id$ */
-/*
-  Independent implementation of MD5 (RFC 1321).
-
-  This code implements the MD5 Algorithm defined in RFC 1321, whose
-  text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
-  The code is derived from the text of the RFC, including the test suite
-  (section A.5) but excluding the rest of Appendix A.  It does not include
-  any code or documentation that is identified in the RFC as being
-  copyrighted.
-
-  The original and principal author of md5.c is L. Peter Deutsch
-  <ghost@aladdin.com>.  Other authors are noted in the change history
-  that follows (in reverse chronological order):
-
-  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
-	either statically or dynamically; added missing #include <string.h>
-	in library.
-  2002-03-11 lpd Corrected argument list for main(), and added int return
-	type, in test program and T value program.
-  2002-02-21 lpd Added missing #include <stdio.h> in test program.
-  2000-07-03 lpd Patched to eliminate warnings about "constant is
-	unsigned in ANSI C, signed in traditional"; made test program
-	self-checking.
-  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
-  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
-  1999-05-03 lpd Original version.
- */
-
-#include "stdafx.h"
-#include "md5.h"
-#include <string.h>
-
-#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
-#if defined(TTD_BIG_ENDIAN)
-#  define BYTE_ORDER 1
-#else
-#  define BYTE_ORDER -1
-#endif
-
-#define T_MASK ((md5_word_t)~0)
-#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
-#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3    0x242070db
-#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
-#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6    0x4787c62a
-#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
-#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9    0x698098d8
-#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
-#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
-#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13    0x6b901122
-#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
-#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16    0x49b40821
-#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
-#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19    0x265e5a51
-#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
-#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22    0x02441453
-#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
-#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25    0x21e1cde6
-#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
-#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28    0x455a14ed
-#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
-#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31    0x676f02d9
-#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
-#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
-#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35    0x6d9d6122
-#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
-#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38    0x4bdecfa9
-#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
-#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41    0x289b7ec6
-#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
-#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44    0x04881d05
-#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
-#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47    0x1fa27cf8
-#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
-#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50    0x432aff97
-#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
-#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53    0x655b59c3
-#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
-#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
-#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57    0x6fa87e4f
-#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
-#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60    0x4e0811a1
-#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
-#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63    0x2ad7d2bb
-#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-
-
-static void
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
-{
-    md5_word_t
-	a = pms->abcd[0], b = pms->abcd[1],
-	c = pms->abcd[2], d = pms->abcd[3];
-    md5_word_t t;
-#if BYTE_ORDER > 0
-    /* Define storage only for big-endian CPUs. */
-    md5_word_t X[16];
-#else
-    /* Define storage for little-endian or both types of CPUs. */
-    md5_word_t xbuf[16];
-    const md5_word_t *X;
-#endif
-
-    {
-#if BYTE_ORDER == 0
-	/*
-	 * Determine dynamically whether this is a big-endian or
-	 * little-endian machine, since we can use a more efficient
-	 * algorithm on the latter.
-	 */
-	static const int w = 1;
-
-	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
-#endif
-#if BYTE_ORDER <= 0 /* little-endian */
-	{
-	    /*
-	     * On little-endian machines, we can process properly aligned
-	     * data without copying it.
-	     */
-	    if (!((data - (const md5_byte_t *)0) & 3)) {
-		/* data are properly aligned */
-		X = (const md5_word_t *)data;
-	    } else {
-		/* not aligned */
-		memcpy(xbuf, data, 64);
-		X = xbuf;
-	    }
-	}
-#endif
-#if BYTE_ORDER == 0
-	else /* dynamic big-endian */
-#endif
-#if BYTE_ORDER >= 0 /* big-endian */
-	{
-	    /*
-	     * On big-endian machines, we must arrange the bytes in the
-	     * right order.
-	     */
-	    const md5_byte_t *xp = data;
-	    int i;
-
-#  if BYTE_ORDER == 0
-	    X = xbuf; /* (dynamic only) */
-#  else
-#    define xbuf X /* (static only) */
-#  endif
-	    for (i = 0; i < 16; ++i, xp += 4)
-		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
-	}
-#endif
-    }
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-    /* Round 1. */
-    /* Let [abcd k s i] denote the operation
-       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + F(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-    /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  7,  T1);
-    SET(d, a, b, c,  1, 12,  T2);
-    SET(c, d, a, b,  2, 17,  T3);
-    SET(b, c, d, a,  3, 22,  T4);
-    SET(a, b, c, d,  4,  7,  T5);
-    SET(d, a, b, c,  5, 12,  T6);
-    SET(c, d, a, b,  6, 17,  T7);
-    SET(b, c, d, a,  7, 22,  T8);
-    SET(a, b, c, d,  8,  7,  T9);
-    SET(d, a, b, c,  9, 12, T10);
-    SET(c, d, a, b, 10, 17, T11);
-    SET(b, c, d, a, 11, 22, T12);
-    SET(a, b, c, d, 12,  7, T13);
-    SET(d, a, b, c, 13, 12, T14);
-    SET(c, d, a, b, 14, 17, T15);
-    SET(b, c, d, a, 15, 22, T16);
-#undef SET
-
-     /* Round 2. */
-     /* Let [abcd k s i] denote the operation
-          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + G(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  1,  5, T17);
-    SET(d, a, b, c,  6,  9, T18);
-    SET(c, d, a, b, 11, 14, T19);
-    SET(b, c, d, a,  0, 20, T20);
-    SET(a, b, c, d,  5,  5, T21);
-    SET(d, a, b, c, 10,  9, T22);
-    SET(c, d, a, b, 15, 14, T23);
-    SET(b, c, d, a,  4, 20, T24);
-    SET(a, b, c, d,  9,  5, T25);
-    SET(d, a, b, c, 14,  9, T26);
-    SET(c, d, a, b,  3, 14, T27);
-    SET(b, c, d, a,  8, 20, T28);
-    SET(a, b, c, d, 13,  5, T29);
-    SET(d, a, b, c,  2,  9, T30);
-    SET(c, d, a, b,  7, 14, T31);
-    SET(b, c, d, a, 12, 20, T32);
-#undef SET
-
-     /* Round 3. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + H(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  5,  4, T33);
-    SET(d, a, b, c,  8, 11, T34);
-    SET(c, d, a, b, 11, 16, T35);
-    SET(b, c, d, a, 14, 23, T36);
-    SET(a, b, c, d,  1,  4, T37);
-    SET(d, a, b, c,  4, 11, T38);
-    SET(c, d, a, b,  7, 16, T39);
-    SET(b, c, d, a, 10, 23, T40);
-    SET(a, b, c, d, 13,  4, T41);
-    SET(d, a, b, c,  0, 11, T42);
-    SET(c, d, a, b,  3, 16, T43);
-    SET(b, c, d, a,  6, 23, T44);
-    SET(a, b, c, d,  9,  4, T45);
-    SET(d, a, b, c, 12, 11, T46);
-    SET(c, d, a, b, 15, 16, T47);
-    SET(b, c, d, a,  2, 23, T48);
-#undef SET
-
-     /* Round 4. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + I(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  6, T49);
-    SET(d, a, b, c,  7, 10, T50);
-    SET(c, d, a, b, 14, 15, T51);
-    SET(b, c, d, a,  5, 21, T52);
-    SET(a, b, c, d, 12,  6, T53);
-    SET(d, a, b, c,  3, 10, T54);
-    SET(c, d, a, b, 10, 15, T55);
-    SET(b, c, d, a,  1, 21, T56);
-    SET(a, b, c, d,  8,  6, T57);
-    SET(d, a, b, c, 15, 10, T58);
-    SET(c, d, a, b,  6, 15, T59);
-    SET(b, c, d, a, 13, 21, T60);
-    SET(a, b, c, d,  4,  6, T61);
-    SET(d, a, b, c, 11, 10, T62);
-    SET(c, d, a, b,  2, 15, T63);
-    SET(b, c, d, a,  9, 21, T64);
-#undef SET
-
-     /* Then perform the following additions. (That is increment each
-        of the four registers by the value it had before this block
-        was started.) */
-    pms->abcd[0] += a;
-    pms->abcd[1] += b;
-    pms->abcd[2] += c;
-    pms->abcd[3] += d;
-}
-
-void
-md5_init(md5_state_t *pms)
-{
-    pms->count[0] = pms->count[1] = 0;
-    pms->abcd[0] = 0x67452301;
-    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
-    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
-    pms->abcd[3] = 0x10325476;
-}
-
-void
-md5_append(md5_state_t *pms, const void *data, size_t nbytes)
-{
-    const md5_byte_t *p = (const md5_byte_t *)data;
-    size_t left = nbytes;
-    size_t offset = (pms->count[0] >> 3) & 63;
-    md5_word_t nbits = (md5_word_t)(nbytes << 3);
-
-    if (nbytes <= 0)
-	return;
-
-    /* Update the message length. */
-    pms->count[1] += (md5_word_t)(nbytes >> 29);
-    pms->count[0] += nbits;
-    if (pms->count[0] < nbits)
-	pms->count[1]++;
-
-    /* Process an initial partial block. */
-    if (offset) {
-	size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
-	memcpy(pms->buf + offset, p, copy);
-	if (offset + copy < 64)
-	    return;
-	p += copy;
-	left -= copy;
-	md5_process(pms, pms->buf);
-    }
-
-    /* Process full blocks. */
-    for (; left >= 64; p += 64, left -= 64)
-	md5_process(pms, p);
-
-    /* Process a final partial block. */
-    if (left)
-	memcpy(pms->buf, p, left);
-}
-
-void
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])
-{
-    static const md5_byte_t pad[64] = {
-	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-    };
-    md5_byte_t data[8];
-    int i;
-
-    /* Save the length before padding. */
-    for (i = 0; i < 8; ++i)
-	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
-    /* Pad to 56 bytes mod 64. */
-    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
-    /* Append the length. */
-    md5_append(pms, data, 8);
-    for (i = 0; i < 16; ++i)
-	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
-}
new file mode 100644
--- /dev/null
+++ b/src/md5.cpp
@@ -0,0 +1,384 @@
+/* $Id$ */
+
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id$ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "stdafx.h"
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#if defined(TTD_BIG_ENDIAN)
+#  define BYTE_ORDER 1
+#else
+#  define BYTE_ORDER -1
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+	/*
+	 * Determine dynamically whether this is a big-endian or
+	 * little-endian machine, since we can use a more efficient
+	 * algorithm on the latter.
+	 */
+	static const int w = 1;
+
+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+	{
+	    /*
+	     * On little-endian machines, we can process properly aligned
+	     * data without copying it.
+	     */
+	    if (!((data - (const md5_byte_t *)0) & 3)) {
+		/* data are properly aligned */
+		X = (const md5_word_t *)data;
+	    } else {
+		/* not aligned */
+		memcpy(xbuf, data, 64);
+		X = xbuf;
+	    }
+	}
+#endif
+#if BYTE_ORDER == 0
+	else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+	{
+	    /*
+	     * On big-endian machines, we must arrange the bytes in the
+	     * right order.
+	     */
+	    const md5_byte_t *xp = data;
+	    int i;
+
+#  if BYTE_ORDER == 0
+	    X = xbuf; /* (dynamic only) */
+#  else
+#    define xbuf X /* (static only) */
+#  endif
+	    for (i = 0; i < 16; ++i, xp += 4)
+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+	}
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const void *data, size_t nbytes)
+{
+    const md5_byte_t *p = (const md5_byte_t *)data;
+    size_t left = nbytes;
+    size_t offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += (md5_word_t)(nbytes >> 29);
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
deleted file mode 100644
--- a/src/mersenne.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-
-#ifdef MERSENNE_TWISTER
-
-// Source code for Mersenne Twister.
-// A Random number generator with much higher quality random numbers.
-
-#define N              (624)                 // length of _mt_state vector
-#define M              (397)                 // a period parameter
-#define K              (0x9908B0DFU)         // a magic constant
-#define hiBit(u)       ((u) & 0x80000000U)   // mask all but highest   bit of u
-#define loBit(u)       ((u) & 0x00000001U)   // mask all but lowest    bit of u
-#define loBits(u)      ((u) & 0x7FFFFFFFU)   // mask     the highest   bit of u
-#define mixBits(u, v)  (hiBit(u)|loBits(v))  // move hi bit of u to hi bit of v
-
-static uint32   _mt_state[N+1];     // _mt_state vector + 1 extra to not violate ANSI C
-static uint32   *_mt_next;          // _mt_next random value is computed from here
-static int      _mt_left = -1;      // can *_mt_next++ this many times before reloading
-
-void SeedMT(uint32 seed)
-{
-    register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state;
-    register int    j;
-
-    for (_mt_left=0, *s++=x, j=N; --j;
-        *s++ = (x*=69069U) & 0xFFFFFFFFU);
- }
-
-
-static uint32 ReloadMT(void)
- {
-    register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1;
-    register int    j;
-
-    if (_mt_left < -1)
-        SeedMT(4357U);
-
-    _mt_left=N-1, _mt_next=_mt_state+1;
-
-    for (s0=_mt_state[0], s1=_mt_state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
-        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
-
-    for (pM=_mt_state, j=M; --j; s0=s1, s1=*p2++)
-        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
-
-    s1=_mt_state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
-    s1 ^= (s1 >> 11);
-    s1 ^= (s1 <<  7) & 0x9D2C5680U;
-    s1 ^= (s1 << 15) & 0xEFC60000U;
-    return(s1 ^ (s1 >> 18));
- }
-
-
-uint32 RandomMT(void)
-{
-	uint32 y;
-
-	if (--_mt_left < 0)
-		return ReloadMT();
-
-	y  = *_mt_next++;
-	y ^= (y >> 11);
-	y ^= (y <<  7) & 0x9D2C5680U;
-	y ^= (y << 15) & 0xEFC60000U;
-	return y ^ (y >> 18);
-}
-#else
-
-void SeedMT(uint32 seed) {}
-
-#endif /* MERSENNE_TWISTER */
new file mode 100644
--- /dev/null
+++ b/src/mersenne.cpp
@@ -0,0 +1,74 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+
+#ifdef MERSENNE_TWISTER
+
+// Source code for Mersenne Twister.
+// A Random number generator with much higher quality random numbers.
+
+#define N              (624)                 // length of _mt_state vector
+#define M              (397)                 // a period parameter
+#define K              (0x9908B0DFU)         // a magic constant
+#define hiBit(u)       ((u) & 0x80000000U)   // mask all but highest   bit of u
+#define loBit(u)       ((u) & 0x00000001U)   // mask all but lowest    bit of u
+#define loBits(u)      ((u) & 0x7FFFFFFFU)   // mask     the highest   bit of u
+#define mixBits(u, v)  (hiBit(u)|loBits(v))  // move hi bit of u to hi bit of v
+
+static uint32   _mt_state[N+1];     // _mt_state vector + 1 extra to not violate ANSI C
+static uint32   *_mt_next;          // _mt_next random value is computed from here
+static int      _mt_left = -1;      // can *_mt_next++ this many times before reloading
+
+void SeedMT(uint32 seed)
+{
+    register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state;
+    register int    j;
+
+    for (_mt_left=0, *s++=x, j=N; --j;
+        *s++ = (x*=69069U) & 0xFFFFFFFFU);
+ }
+
+
+static uint32 ReloadMT(void)
+ {
+    register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1;
+    register int    j;
+
+    if (_mt_left < -1)
+        SeedMT(4357U);
+
+    _mt_left=N-1, _mt_next=_mt_state+1;
+
+    for (s0=_mt_state[0], s1=_mt_state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
+        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+
+    for (pM=_mt_state, j=M; --j; s0=s1, s1=*p2++)
+        *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+
+    s1=_mt_state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+    s1 ^= (s1 >> 11);
+    s1 ^= (s1 <<  7) & 0x9D2C5680U;
+    s1 ^= (s1 << 15) & 0xEFC60000U;
+    return(s1 ^ (s1 >> 18));
+ }
+
+
+uint32 RandomMT(void)
+{
+	uint32 y;
+
+	if (--_mt_left < 0)
+		return ReloadMT();
+
+	y  = *_mt_next++;
+	y ^= (y >> 11);
+	y ^= (y <<  7) & 0x9D2C5680U;
+	y ^= (y << 15) & 0xEFC60000U;
+	return y ^ (y >> 18);
+}
+#else
+
+void SeedMT(uint32 seed) {}
+
+#endif /* MERSENNE_TWISTER */
deleted file mode 100644
--- a/src/minilzo.c
+++ /dev/null
@@ -1,1971 +0,0 @@
-/* $Id$ */
-
-/* minilzo.c -- mini subset of the LZO real-time data compression library
-
-   This file is part of the LZO real-time data compression library.
-
-   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
-   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
-   All Rights Reserved.
-
-   The LZO library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   The LZO library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with the LZO library; see the file COPYING.
-   If not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-   Markus F.X.J. Oberhumer
-   <markus@oberhumer.com>
-   http://www.oberhumer.com/opensource/lzo/
- */
-
-/*
- * NOTE:
- *   the full LZO package can be found at
- *   http://www.oberhumer.com/opensource/lzo/
- */
-
-#define LZO_DISABLE_CHECKS
-#define LZO1X
-
-#define __LZO_IN_MINILZO
-#define LZO_BUILD
-
-#ifdef MINILZO_HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#undef LZO_HAVE_CONFIG_H
-#include "minilzo.h"
-
-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1080)
-#  error "version mismatch in miniLZO source files"
-#endif
-
-#ifdef MINILZO_HAVE_CONFIG_H
-#  define LZO_HAVE_CONFIG_H
-#endif
-
-#if !defined(LZO_NO_SYS_TYPES_H)
-#  include <sys/types.h>
-#endif
-#include <stdio.h>
-
-#ifndef __LZO_CONF_H
-#define __LZO_CONF_H
-
-#if defined(__BOUNDS_CHECKING_ON)
-#  include <unchecked.h>
-#else
-#  define BOUNDS_CHECKING_OFF_DURING(stmt)	  stmt
-#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)	 (expr)
-#endif
-
-#if !defined(LZO_HAVE_CONFIG_H)
-#  include <stddef.h>
-#  include <string.h>
-#  if !defined(NO_STDLIB_H)
-#	include <stdlib.h>
-#  endif
-#  define HAVE_MEMCMP
-#  define HAVE_MEMCPY
-#  define HAVE_MEMMOVE
-#  define HAVE_MEMSET
-#else
-#  include <sys/types.h>
-#  if defined(HAVE_STDDEF_H)
-#	include <stddef.h>
-#  endif
-#  if defined(STDC_HEADERS)
-#	include <string.h>
-#	include <stdlib.h>
-#  endif
-#endif
-
-#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
-#  define HAVE_MALLOC_H
-#  define HAVE_HALLOC
-#endif
-
-#undef NDEBUG
-#if !defined(LZO_DEBUG)
-#  define NDEBUG
-#endif
-#if defined(LZO_DEBUG) || !defined(NDEBUG)
-#  if !defined(NO_STDIO_H)
-#	include <stdio.h>
-#  endif
-#endif
-#include <assert.h>
-
-#if !defined(LZO_COMPILE_TIME_ASSERT)
-#  define LZO_COMPILE_TIME_ASSERT(expr) \
-		{ typedef int __lzo_compile_time_assert_fail[1 - 2 * !(expr)]; }
-#endif
-
-#if !defined(LZO_UNUSED)
-#  if 1
-#	define LZO_UNUSED(var)	 ((void)&var)
-#  elif 0
-#	define LZO_UNUSED(var)	 { typedef int __lzo_unused[sizeof(var) ? 2 : 1]; }
-#  else
-#	define LZO_UNUSED(parm)	(parm = parm)
-#  endif
-#endif
-
-#if !defined(__inline__) && !defined(__GNUC__)
-#  if defined(__cplusplus)
-#	define __inline__	  inline
-#  else
-#	define __inline__
-#  endif
-#endif
-
-#if defined(NO_MEMCMP)
-#  undef HAVE_MEMCMP
-#endif
-
-#if 0
-#  define LZO_BYTE(x)	   ((unsigned char) (x))
-#else
-#  define LZO_BYTE(x)	   ((unsigned char) ((x) & 0xff))
-#endif
-
-#define LZO_MAX(a,b)		((a) >= (b) ? (a) : (b))
-#define LZO_MIN(a,b)		((a) <= (b) ? (a) : (b))
-#define LZO_MAX3(a,b,c)	 ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
-#define LZO_MIN3(a,b,c)	 ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
-
-#define lzo_sizeof(type)	((lzo_uint) (sizeof(type)))
-
-#define LZO_HIGH(array)	 ((lzo_uint) (sizeof(array)/sizeof(*(array))))
-
-#define LZO_SIZE(bits)	  (1u << (bits))
-#define LZO_MASK(bits)	  (LZO_SIZE(bits) - 1)
-
-#define LZO_LSIZE(bits)	 (1ul << (bits))
-#define LZO_LMASK(bits)	 (LZO_LSIZE(bits) - 1)
-
-#define LZO_USIZE(bits)	 ((lzo_uint) 1 << (bits))
-#define LZO_UMASK(bits)	 (LZO_USIZE(bits) - 1)
-
-#define LZO_STYPE_MAX(b)	(((1l  << (8*(b)-2)) - 1l)  + (1l  << (8*(b)-2)))
-#define LZO_UTYPE_MAX(b)	(((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
-
-#if !defined(SIZEOF_UNSIGNED)
-#  if (UINT_MAX == 0xffff)
-#	define SIZEOF_UNSIGNED		 2
-#  elif (UINT_MAX == LZO_0xffffffffL)
-#	define SIZEOF_UNSIGNED		 4
-#  elif (UINT_MAX >= LZO_0xffffffffL)
-#	define SIZEOF_UNSIGNED		 8
-#  else
-#	error "SIZEOF_UNSIGNED"
-#  endif
-#endif
-
-#if !defined(SIZEOF_UNSIGNED_LONG)
-#  if (ULONG_MAX == LZO_0xffffffffL)
-#	define SIZEOF_UNSIGNED_LONG	4
-#  elif (ULONG_MAX >= LZO_0xffffffffL)
-#	define SIZEOF_UNSIGNED_LONG	8
-#  else
-#	error "SIZEOF_UNSIGNED_LONG"
-#  endif
-#endif
-
-#if !defined(SIZEOF_SIZE_T)
-#  define SIZEOF_SIZE_T			 SIZEOF_UNSIGNED
-#endif
-#if !defined(SIZE_T_MAX)
-#  define SIZE_T_MAX				LZO_UTYPE_MAX(SIZEOF_SIZE_T)
-#endif
-
-#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL)
-#  if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff)
-#	define LZO_UNALIGNED_OK_2
-#  endif
-#  if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL)
-#	define LZO_UNALIGNED_OK_4
-#  endif
-#endif
-
-#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4)
-#  if !defined(LZO_UNALIGNED_OK)
-#	define LZO_UNALIGNED_OK
-#  endif
-#endif
-
-#if defined(__LZO_NO_UNALIGNED)
-#  undef LZO_UNALIGNED_OK
-#  undef LZO_UNALIGNED_OK_2
-#  undef LZO_UNALIGNED_OK_4
-#endif
-
-#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff)
-#  error "LZO_UNALIGNED_OK_2 must not be defined on this system"
-#endif
-#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
-#  error "LZO_UNALIGNED_OK_4 must not be defined on this system"
-#endif
-
-#if defined(__LZO_NO_ALIGNED)
-#  undef LZO_ALIGNED_OK_4
-#endif
-
-#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
-#  error "LZO_ALIGNED_OK_4 must not be defined on this system"
-#endif
-
-#define LZO_LITTLE_ENDIAN	   1234
-#define LZO_BIG_ENDIAN		  4321
-#define LZO_PDP_ENDIAN		  3412
-
-#if !defined(LZO_BYTE_ORDER)
-#  if defined(MFX_BYTE_ORDER)
-#	define LZO_BYTE_ORDER	  MFX_BYTE_ORDER
-#  elif defined(__LZO_i386)
-#	define LZO_BYTE_ORDER	  LZO_LITTLE_ENDIAN
-#  elif defined(BYTE_ORDER)
-#	define LZO_BYTE_ORDER	  BYTE_ORDER
-#  elif defined(__BYTE_ORDER)
-#	define LZO_BYTE_ORDER	  __BYTE_ORDER
-#  endif
-#endif
-
-#if defined(LZO_BYTE_ORDER)
-#  if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \
-	  (LZO_BYTE_ORDER != LZO_BIG_ENDIAN)
-#	error "invalid LZO_BYTE_ORDER"
-#  endif
-#endif
-
-#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER)
-#  error "LZO_BYTE_ORDER is not defined"
-#endif
-
-#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY
-
-#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__LZO_CHECKER)
-#  if defined(__GNUC__) && defined(__i386__)
-#	if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY)
-#	  define LZO_OPTIMIZE_GNUC_i386
-#	endif
-#  endif
-#endif
-
-__LZO_EXTERN_C int __lzo_init_done;
-__LZO_EXTERN_C const lzo_byte __lzo_copyright[];
-LZO_EXTERN(const lzo_byte *) lzo_copyright(void);
-__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256];
-
-#define _LZO_STRINGIZE(x)		   #x
-#define _LZO_MEXPAND(x)			 _LZO_STRINGIZE(x)
-
-#define _LZO_CONCAT2(a,b)		   a ## b
-#define _LZO_CONCAT3(a,b,c)		 a ## b ## c
-#define _LZO_CONCAT4(a,b,c,d)	   a ## b ## c ## d
-#define _LZO_CONCAT5(a,b,c,d,e)	 a ## b ## c ## d ## e
-
-#define _LZO_ECONCAT2(a,b)		  _LZO_CONCAT2(a,b)
-#define _LZO_ECONCAT3(a,b,c)		_LZO_CONCAT3(a,b,c)
-#define _LZO_ECONCAT4(a,b,c,d)	  _LZO_CONCAT4(a,b,c,d)
-#define _LZO_ECONCAT5(a,b,c,d,e)	_LZO_CONCAT5(a,b,c,d,e)
-
-#ifndef __LZO_PTR_H
-#define __LZO_PTR_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
-#  include <dos.h>
-#  if 1 && defined(__WATCOMC__)
-#	include <i86.h>
-	 __LZO_EXTERN_C unsigned char _HShift;
-#	define __LZO_HShift	_HShift
-#  elif 1 && defined(_MSC_VER)
-	 __LZO_EXTERN_C unsigned short __near _AHSHIFT;
-#	define __LZO_HShift	((unsigned) &_AHSHIFT)
-#  elif defined(__LZO_WIN16)
-#	define __LZO_HShift	3
-#  else
-#	define __LZO_HShift	12
-#  endif
-#  if !defined(_FP_SEG) && defined(FP_SEG)
-#	define _FP_SEG		 FP_SEG
-#  endif
-#  if !defined(_FP_OFF) && defined(FP_OFF)
-#	define _FP_OFF		 FP_OFF
-#  endif
-#endif
-
-#if !defined(lzo_ptrdiff_t)
-#  if (UINT_MAX >= LZO_0xffffffffL)
-	 typedef ptrdiff_t		  lzo_ptrdiff_t;
-#  else
-	 typedef long			   lzo_ptrdiff_t;
-#  endif
-#endif
-
-#if !defined(__LZO_HAVE_PTR_T)
-#  if defined(lzo_ptr_t)
-#	define __LZO_HAVE_PTR_T
-#  endif
-#endif
-#if !defined(__LZO_HAVE_PTR_T)
-#	if defined(_WIN64)
-		typedef unsigned __int64 lzo_ptr_t;
-		typedef signed __int64   lzo_sptr_r;
-#		define __LZO_HAVE_PTR_T
-#	endif
-#endif
-#if !defined(__LZO_HAVE_PTR_T)
-#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG)
-#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG)
-	   typedef unsigned long	lzo_ptr_t;
-	   typedef long			 lzo_sptr_t;
-#	  define __LZO_HAVE_PTR_T
-#	endif
-#  endif
-#endif
-#if !defined(__LZO_HAVE_PTR_T)
-#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED)
-#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED)
-	   typedef unsigned int	 lzo_ptr_t;
-	   typedef int			  lzo_sptr_t;
-#	  define __LZO_HAVE_PTR_T
-#	endif
-#  endif
-#endif
-#if !defined(__LZO_HAVE_PTR_T)
-#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT)
-#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT)
-	   typedef unsigned short   lzo_ptr_t;
-	   typedef short			lzo_sptr_t;
-#	  define __LZO_HAVE_PTR_T
-#	endif
-#  endif
-#endif
-#if !defined(__LZO_HAVE_PTR_T)
-#  if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P)
-#	error "no suitable type for lzo_ptr_t"
-#  else
-	 typedef unsigned long	  lzo_ptr_t;
-	 typedef long			   lzo_sptr_t;
-#	define __LZO_HAVE_PTR_T
-#  endif
-#endif
-
-#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
-#define PTR(a)			  ((lzo_bytep) (a))
-#define PTR_ALIGNED_4(a)	((_FP_OFF(a) & 3) == 0)
-#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0)
-#else
-#define PTR(a)			  ((lzo_ptr_t) (a))
-#define PTR_LINEAR(a)	   PTR(a)
-#define PTR_ALIGNED_4(a)	((PTR_LINEAR(a) & 3) == 0)
-#define PTR_ALIGNED_8(a)	((PTR_LINEAR(a) & 7) == 0)
-#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
-#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
-#endif
-
-#define PTR_LT(a,b)		 (PTR(a) < PTR(b))
-#define PTR_GE(a,b)		 (PTR(a) >= PTR(b))
-#define PTR_DIFF(a,b)	   ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
-#define pd(a,b)			 ((lzo_uint) ((a)-(b)))
-
-LZO_EXTERN(lzo_ptr_t)
-__lzo_ptr_linear(const lzo_voidp ptr);
-
-typedef union
-{
-	char			a_char;
-	unsigned char   a_uchar;
-	short		   a_short;
-	unsigned short  a_ushort;
-	int			 a_int;
-	unsigned int	a_uint;
-	long			a_long;
-	unsigned long   a_ulong;
-	lzo_int		 a_lzo_int;
-	lzo_uint		a_lzo_uint;
-	lzo_int32	   a_lzo_int32;
-	lzo_uint32	  a_lzo_uint32;
-	ptrdiff_t	   a_ptrdiff_t;
-	lzo_ptrdiff_t   a_lzo_ptrdiff_t;
-	lzo_ptr_t	   a_lzo_ptr_t;
-	lzo_voidp	   a_lzo_voidp;
-	void *		  a_void_p;
-	lzo_bytep	   a_lzo_bytep;
-	lzo_bytepp	  a_lzo_bytepp;
-	lzo_uintp	   a_lzo_uintp;
-	lzo_uint *	  a_lzo_uint_p;
-	lzo_uint32p	 a_lzo_uint32p;
-	lzo_uint32 *	a_lzo_uint32_p;
-	unsigned char * a_uchar_p;
-	char *		  a_char_p;
-}
-lzo_full_align_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-#define LZO_DETERMINISTIC
-
-#define LZO_DICT_USE_PTR
-#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT)
-#  undef LZO_DICT_USE_PTR
-#endif
-
-#if defined(LZO_DICT_USE_PTR)
-#  define lzo_dict_t	const lzo_bytep
-#  define lzo_dict_p	lzo_dict_t __LZO_MMODEL *
-#else
-#  define lzo_dict_t	lzo_uint
-#  define lzo_dict_p	lzo_dict_t __LZO_MMODEL *
-#endif
-
-#if !defined(lzo_moff_t)
-#define lzo_moff_t	  lzo_uint
-#endif
-
-#endif
-
-
-#ifndef __LZO_UTIL_H
-#define __LZO_UTIL_H
-
-#ifndef __LZO_CONF_H
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if 1 && defined(HAVE_MEMCPY)
-#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16)
-
-#define MEMCPY8_DS(dest,src,len) \
-	memcpy(dest,src,len); \
-	dest += len; \
-	src += len
-
-#endif
-#endif
-
-#if 0 && !defined(MEMCPY8_DS)
-
-#define MEMCPY8_DS(dest,src,len) \
-	{ do { \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		len -= 8; \
-	} while (len > 0); }
-
-#endif
-
-#if !defined(MEMCPY8_DS)
-
-#define MEMCPY8_DS(dest,src,len) \
-	{ register lzo_uint __l = (len) / 8; \
-	do { \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-		*dest++ = *src++; \
-	} while (--__l > 0); }
-
-#endif
-
-#define MEMCPY_DS(dest,src,len) \
-	do *dest++ = *src++; \
-	while (--len > 0)
-
-#define MEMMOVE_DS(dest,src,len) \
-	do *dest++ = *src++; \
-	while (--len > 0)
-
-#if 0 && defined(LZO_OPTIMIZE_GNUC_i386)
-
-#define BZERO8_PTR(s,l,n) \
-__asm__ __volatile__( \
-	"movl  %0,%%eax \n"			 \
-	"movl  %1,%%edi \n"			 \
-	"movl  %2,%%ecx \n"			 \
-	"cld \n"						\
-	"rep \n"						\
-	"stosl %%eax,(%%edi) \n"		\
-	:			   \
-	:"g" (0),"g" (s),"g" (n)		\
-	:"eax","edi","ecx", "memory", "cc" \
-)
-
-#elif (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
-
-#if 1
-#define BZERO8_PTR(s,l,n)   memset((s),0,(lzo_uint)(l)*(n))
-#else
-#define BZERO8_PTR(s,l,n)   memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
-#endif
-
-#else
-
-#define BZERO8_PTR(s,l,n) \
-	lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
-
-#endif
-
-#if 0
-#if defined(__GNUC__) && defined(__i386__)
-
-unsigned char lzo_rotr8(unsigned char value, int shift);
-extern __inline__ unsigned char lzo_rotr8(unsigned char value, int shift)
-{
-	unsigned char result;
-
-	__asm__ __volatile__ ("movb %b1, %b0; rorb %b2, %b0"
-						: "=a"(result) : "g"(value), "c"(shift));
-	return result;
-}
-
-unsigned short lzo_rotr16(unsigned short value, int shift);
-extern __inline__ unsigned short lzo_rotr16(unsigned short value, int shift)
-{
-	unsigned short result;
-
-	__asm__ __volatile__ ("movw %b1, %b0; rorw %b2, %b0"
-						: "=a"(result) : "g"(value), "c"(shift));
-	return result;
-}
-
-#endif
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
-/* If you use the LZO library in a product, you *must* keep this
- * copyright string in the executable of your product.
- */
-
-const lzo_byte __lzo_copyright[] =
-#if !defined(__LZO_IN_MINLZO)
-	LZO_VERSION_STRING;
-#else
-	"\n\n\n"
-	"LZO real-time data compression library.\n"
-	"Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer\n"
-	"<markus.oberhumer@jk.uni-linz.ac.at>\n"
-	"http://www.oberhumer.com/opensource/lzo/\n"
-	"\n"
-	"LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n"
-	"LZO build date: " __DATE__ " " __TIME__ "\n\n"
-	"LZO special compilation options:\n"
-#ifdef __cplusplus
-	" __cplusplus\n"
-#endif
-#if defined(__PIC__)
-	" __PIC__\n"
-#elif defined(__pic__)
-	" __pic__\n"
-#endif
-#if (UINT_MAX < LZO_0xffffffffL)
-	" 16BIT\n"
-#endif
-#if defined(__LZO_STRICT_16BIT)
-	" __LZO_STRICT_16BIT\n"
-#endif
-#if (UINT_MAX > LZO_0xffffffffL)
-	" UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n"
-#endif
-#if (ULONG_MAX > LZO_0xffffffffL)
-	" ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n"
-#endif
-#if defined(LZO_BYTE_ORDER)
-	" LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n"
-#endif
-#if defined(LZO_UNALIGNED_OK_2)
-	" LZO_UNALIGNED_OK_2\n"
-#endif
-#if defined(LZO_UNALIGNED_OK_4)
-	" LZO_UNALIGNED_OK_4\n"
-#endif
-#if defined(LZO_ALIGNED_OK_4)
-	" LZO_ALIGNED_OK_4\n"
-#endif
-#if defined(LZO_DICT_USE_PTR)
-	" LZO_DICT_USE_PTR\n"
-#endif
-#if defined(__LZO_QUERY_COMPRESS)
-	" __LZO_QUERY_COMPRESS\n"
-#endif
-#if defined(__LZO_QUERY_DECOMPRESS)
-	" __LZO_QUERY_DECOMPRESS\n"
-#endif
-#if defined(__LZO_IN_MINILZO)
-	" __LZO_IN_MINILZO\n"
-#endif
-	"\n\n"
-	"$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__
-#if defined(__GNUC__) && defined(__VERSION__)
-	" by gcc " __VERSION__
-#elif defined(__BORLANDC__)
-	" by Borland C " _LZO_MEXPAND(__BORLANDC__)
-#elif defined(_MSC_VER)
-	" by Microsoft C " _LZO_MEXPAND(_MSC_VER)
-#elif defined(__PUREC__)
-	" by Pure C " _LZO_MEXPAND(__PUREC__)
-#elif defined(__SC__)
-	" by Symantec C " _LZO_MEXPAND(__SC__)
-#elif defined(__TURBOC__)
-	" by Turbo C " _LZO_MEXPAND(__TURBOC__)
-#elif defined(__WATCOMC__)
-	" by Watcom C " _LZO_MEXPAND(__WATCOMC__)
-#endif
-	" $\n"
-	"$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer $\n";
-#endif
-
-#define LZO_BASE 65521u
-#define LZO_NMAX 5552
-
-#define LZO_DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
-#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
-#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
-#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
-#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
-
-LZO_PUBLIC(lzo_uint32)
-lzo_adler32(lzo_uint32 adler, const lzo_byte *buf, lzo_uint len)
-{
-	lzo_uint32 s1 = adler & 0xffff;
-	lzo_uint32 s2 = (adler >> 16) & 0xffff;
-	int k;
-
-	if (buf == NULL)
-		return 1;
-
-	while (len > 0)
-	{
-		k = len < LZO_NMAX ? (int) len : LZO_NMAX;
-		len -= k;
-		if (k >= 16) do
-		{
-			LZO_DO16(buf,0);
-			buf += 16;
-			k -= 16;
-		} while (k >= 16);
-		if (k != 0) do
-		{
-			s1 += *buf++;
-			s2 += s1;
-		} while (--k > 0);
-		s1 %= LZO_BASE;
-		s2 %= LZO_BASE;
-		}
-	return (s2 << 16) | s1;
-}
-
-#if 0
-#  define IS_SIGNED(type)	   (((type) (1ul << (8 * sizeof(type) - 1))) < 0)
-#  define IS_UNSIGNED(type)	 (((type) (1ul << (8 * sizeof(type) - 1))) > 0)
-#else
-#  define IS_SIGNED(type)	   (((type) (-1)) < ((type) 0))
-#  define IS_UNSIGNED(type)	 (((type) (-1)) > ((type) 0))
-#endif
-
-#define IS_POWER_OF_2(x)		(((x) & ((x) - 1)) == 0)
-
-// static lzo_bool schedule_insns_bug(void);
-// static lzo_bool strength_reduce_bug(int *);
-
-#if 0 || defined(LZO_DEBUG)
-#include <stdio.h>
-static lzo_bool __lzo_assert_fail(const char *s, unsigned line)
-{
-#if defined(__palmos__)
-	printf("LZO assertion failed in line %u: '%s'\n",line,s);
-#else
-	fprintf(stderr,"LZO assertion failed in line %u: '%s'\n",line,s);
-#endif
-	return 0;
-}
-#  define __lzo_assert(x)   ((x) ? 1 : __lzo_assert_fail(#x,__LINE__))
-#else
-#  define __lzo_assert(x)   ((x) ? 1 : 0)
-#endif
-
-#undef COMPILE_TIME_ASSERT
-#if 0
-#  define COMPILE_TIME_ASSERT(expr)	 r &= __lzo_assert(expr)
-#else
-#  define COMPILE_TIME_ASSERT(expr)	 LZO_COMPILE_TIME_ASSERT(expr)
-#endif
-
-
-#define do_compress		 _lzo1x_1_do_compress
-
-#define LZO_NEED_DICT_H
-#define D_BITS		  12
-#define D_INDEX1(d,p)	   d = DM((0x21*DX3(p,5,5,6)) >> 5)
-#define D_INDEX2(d,p)	   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
-
-#ifndef __LZO_CONFIG1X_H
-#define __LZO_CONFIG1X_H
-
-#define LZO_EOF_CODE
-#undef LZO_DETERMINISTIC
-
-#define M1_MAX_OFFSET   0x0400
-#ifndef M2_MAX_OFFSET
-#define M2_MAX_OFFSET   0x0800
-#endif
-#define M3_MAX_OFFSET   0x4000
-#define M4_MAX_OFFSET   0xbfff
-
-#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
-
-#define M1_MIN_LEN	  2
-#define M1_MAX_LEN	  2
-#define M2_MIN_LEN	  3
-#ifndef M2_MAX_LEN
-#define M2_MAX_LEN	  8
-#endif
-#define M3_MIN_LEN	  3
-#define M3_MAX_LEN	  33
-#define M4_MIN_LEN	  3
-#define M4_MAX_LEN	  9
-
-#define M1_MARKER	   0
-#define M2_MARKER	   64
-#define M3_MARKER	   32
-#define M4_MARKER	   16
-
-#ifndef MIN_LOOKAHEAD
-#define MIN_LOOKAHEAD	   (M2_MAX_LEN + 1)
-#endif
-
-#if defined(LZO_NEED_DICT_H)
-
-#ifndef LZO_HASH
-#define LZO_HASH			LZO_HASH_LZO_INCREMENTAL_B
-#endif
-#define DL_MIN_LEN		  M2_MIN_LEN
-
-#ifndef __LZO_DICT_H
-#define __LZO_DICT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if !defined(D_BITS) && defined(DBITS)
-#  define D_BITS		DBITS
-#endif
-#if !defined(D_BITS)
-#  error "D_BITS is not defined"
-#endif
-#if (D_BITS < 16)
-#  define D_SIZE		LZO_SIZE(D_BITS)
-#  define D_MASK		LZO_MASK(D_BITS)
-#else
-#  define D_SIZE		LZO_USIZE(D_BITS)
-#  define D_MASK		LZO_UMASK(D_BITS)
-#endif
-#define D_HIGH		  ((D_MASK >> 1) + 1)
-
-#if !defined(DD_BITS)
-#  define DD_BITS	   0
-#endif
-#define DD_SIZE		 LZO_SIZE(DD_BITS)
-#define DD_MASK		 LZO_MASK(DD_BITS)
-
-#if !defined(DL_BITS)
-#  define DL_BITS	   (D_BITS - DD_BITS)
-#endif
-#if (DL_BITS < 16)
-#  define DL_SIZE	   LZO_SIZE(DL_BITS)
-#  define DL_MASK	   LZO_MASK(DL_BITS)
-#else
-#  define DL_SIZE	   LZO_USIZE(DL_BITS)
-#  define DL_MASK	   LZO_UMASK(DL_BITS)
-#endif
-
-#if (D_BITS != DL_BITS + DD_BITS)
-#  error "D_BITS does not match"
-#endif
-#if (D_BITS < 8 || D_BITS > 18)
-#  error "invalid D_BITS"
-#endif
-#if (DL_BITS < 8 || DL_BITS > 20)
-#  error "invalid DL_BITS"
-#endif
-#if (DD_BITS < 0 || DD_BITS > 6)
-#  error "invalid DD_BITS"
-#endif
-
-#if !defined(DL_MIN_LEN)
-#  define DL_MIN_LEN	3
-#endif
-#if !defined(DL_SHIFT)
-#  define DL_SHIFT	  ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
-#endif
-
-#define LZO_HASH_GZIP				   1
-#define LZO_HASH_GZIP_INCREMENTAL	   2
-#define LZO_HASH_LZO_INCREMENTAL_A	  3
-#define LZO_HASH_LZO_INCREMENTAL_B	  4
-
-#if !defined(LZO_HASH)
-#  error "choose a hashing strategy"
-#endif
-
-#if (DL_MIN_LEN == 3)
-#  define _DV2_A(p,shift1,shift2) \
-		(((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
-#  define _DV2_B(p,shift1,shift2) \
-		(((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
-#  define _DV3_B(p,shift1,shift2,shift3) \
-		((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
-#elif (DL_MIN_LEN == 2)
-#  define _DV2_A(p,shift1,shift2) \
-		(( (lzo_uint32)(p[0]) << shift1) ^ p[1])
-#  define _DV2_B(p,shift1,shift2) \
-		(( (lzo_uint32)(p[1]) << shift1) ^ p[2])
-#else
-#  error "invalid DL_MIN_LEN"
-#endif
-#define _DV_A(p,shift)	  _DV2_A(p,shift,shift)
-#define _DV_B(p,shift)	  _DV2_B(p,shift,shift)
-#define DA2(p,s1,s2) \
-		(((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
-#define DS2(p,s1,s2) \
-		(((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
-#define DX2(p,s1,s2) \
-		(((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
-#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
-#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
-#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
-#define DMS(v,s)		((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
-#define DM(v)		   DMS(v,0)
-
-#if (LZO_HASH == LZO_HASH_GZIP)
-#  define _DINDEX(dv,p)	 (_DV_A((p),DL_SHIFT))
-
-#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
-#  define __LZO_HASH_INCREMENTAL
-#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)
-#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])
-#  define _DINDEX(dv,p)	 (dv)
-#  define DVAL_LOOKAHEAD	DL_MIN_LEN
-
-#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
-#  define __LZO_HASH_INCREMENTAL
-#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)
-#  define DVAL_NEXT(dv,p) \
-				dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
-#  define _DINDEX(dv,p)	 ((0x9f5f * (dv)) >> 5)
-#  define DVAL_LOOKAHEAD	DL_MIN_LEN
-
-#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
-#  define __LZO_HASH_INCREMENTAL
-#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)
-#  define DVAL_NEXT(dv,p) \
-				dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5)))
-#  define _DINDEX(dv,p)	 ((0x9f5f * (dv)) >> 5)
-#  define DVAL_LOOKAHEAD	DL_MIN_LEN
-
-#else
-#  error "choose a hashing strategy"
-#endif
-
-#ifndef DINDEX
-#define DINDEX(dv,p)		((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
-#endif
-#if !defined(DINDEX1) && defined(D_INDEX1)
-#define DINDEX1			 D_INDEX1
-#endif
-#if !defined(DINDEX2) && defined(D_INDEX2)
-#define DINDEX2			 D_INDEX2
-#endif
-
-#if !defined(__LZO_HASH_INCREMENTAL)
-#  define DVAL_FIRST(dv,p)  ((void) 0)
-#  define DVAL_NEXT(dv,p)   ((void) 0)
-#  define DVAL_LOOKAHEAD	0
-#endif
-
-#if !defined(DVAL_ASSERT)
-#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
-static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte *p)
-{
-	lzo_uint32 df;
-	DVAL_FIRST(df,(p));
-	assert(DINDEX(dv,p) == DINDEX(df,p));
-}
-#else
-#  define DVAL_ASSERT(dv,p) ((void) 0)
-#endif
-#endif
-
-#if defined(LZO_DICT_USE_PTR)
-#  define DENTRY(p,in)						  (p)
-#  define GINDEX(m_pos,m_off,dict,dindex,in)	m_pos = dict[dindex]
-#else
-#  define DENTRY(p,in)						  ((lzo_uint) ((p)-(in)))
-#  define GINDEX(m_pos,m_off,dict,dindex,in)	m_off = dict[dindex]
-#endif
-
-#if (DD_BITS == 0)
-
-#  define UPDATE_D(dict,drun,dv,p,in)	   dict[ DINDEX(dv,p) ] = DENTRY(p,in)
-#  define UPDATE_I(dict,drun,index,p,in)	dict[index] = DENTRY(p,in)
-#  define UPDATE_P(ptr,drun,p,in)		   (ptr)[0] = DENTRY(p,in)
-
-#else
-
-#  define UPDATE_D(dict,drun,dv,p,in)   \
-		dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
-#  define UPDATE_I(dict,drun,index,p,in)	\
-		dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
-#  define UPDATE_P(ptr,drun,p,in)   \
-		(ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
-
-#endif
-
-#if defined(LZO_DICT_USE_PTR)
-
-#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
-		(m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
-
-#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
-	(BOUNDS_CHECKING_OFF_IN_EXPR( \
-		(PTR_LT(m_pos,in) || \
-		 (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
-		  m_off > max_offset) ))
-
-#else
-
-#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
-		(m_off == 0 || \
-		 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
-		 (m_pos = (ip) - (m_off), 0) )
-
-#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
-		((lzo_moff_t) ((ip)-(in)) <= m_off || \
-		 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
-		 (m_pos = (ip) - (m_off), 0) )
-
-#endif
-
-#if defined(LZO_DETERMINISTIC)
-#  define LZO_CHECK_MPOS	LZO_CHECK_MPOS_DET
-#else
-#  define LZO_CHECK_MPOS	LZO_CHECK_MPOS_NON_DET
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-#endif
-
-#endif
-
-#define DO_COMPRESS	 lzo1x_1_compress
-
-static
-lzo_uint do_compress	 ( const lzo_byte *in , lzo_uint  in_len,
-								 lzo_byte *out, lzo_uintp out_len,
-								 lzo_voidp wrkmem )
-{
-		register const lzo_byte *ip;
-		lzo_byte *op;
-		const lzo_byte * const in_end = in + in_len;
-		const lzo_byte * const ip_end = in + in_len - M2_MAX_LEN - 5;
-		const lzo_byte *ii;
-		lzo_dict_p const dict = (lzo_dict_p) wrkmem;
-
-		op = out;
-		ip = in;
-		ii = ip;
-
-		ip += 4;
-		for (;;)
-		{
-		register const lzo_byte *m_pos;
-		lzo_moff_t m_off;
-		lzo_uint m_len;
-		lzo_uint dindex;
-
-		DINDEX1(dindex,ip);
-		GINDEX(m_pos,m_off,dict,dindex,in);
-		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
-			goto literal;
-		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
-			goto try_match;
-		DINDEX2(dindex,ip);
-		GINDEX(m_pos,m_off,dict,dindex,in);
-		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
-			goto literal;
-		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
-			goto try_match;
-		goto literal;
-
-try_match:
-#if 1 && defined(LZO_UNALIGNED_OK_2)
-		if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
-#else
-		if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
-#endif
-		{
-		}
-		else
-		{
-			if (m_pos[2] == ip[2])
-			{
-					goto match;
-			}
-		}
-
-literal:
-		UPDATE_I(dict,0,dindex,ip,in);
-		++ip;
-		if (ip >= ip_end)
-			break;
-		continue;
-
-match:
-		UPDATE_I(dict,0,dindex,ip,in);
-		if (pd(ip,ii) > 0)
-		{
-			register lzo_uint t = pd(ip,ii);
-
-			if (t <= 3)
-			{
-				assert(op - 2 > out);
-				op[-2] |= LZO_BYTE(t);
-			}
-			else if (t <= 18)
-				*op++ = LZO_BYTE(t - 3);
-			else
-			{
-				register lzo_uint tt = t - 18;
-
-				*op++ = 0;
-				while (tt > 255)
-				{
-					tt -= 255;
-					*op++ = 0;
-				}
-				assert(tt > 0);
-				*op++ = LZO_BYTE(tt);
-			}
-			do *op++ = *ii++; while (--t > 0);
-		}
-
-		assert(ii == ip);
-		ip += 3;
-		if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
-			m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++) {
-
-			--ip;
-			m_len = ip - ii;
-			assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
-
-			if (m_off <= M2_MAX_OFFSET)
-			{
-				m_off -= 1;
-				*op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
-				*op++ = LZO_BYTE(m_off >> 3);
-			}
-			else if (m_off <= M3_MAX_OFFSET)
-			{
-				m_off -= 1;
-				*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
-				goto m3_m4_offset;
-			}
-			else
-			{
-				m_off -= 0x4000;
-				assert(m_off > 0); assert(m_off <= 0x7fff);
-				*op++ = LZO_BYTE(M4_MARKER |
-								 ((m_off & 0x4000) >> 11) | (m_len - 2));
-				goto m3_m4_offset;
-			}
-		}
-		else
-		{
-			{
-				const lzo_byte *end = in_end;
-				const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
-				while (ip < end && *m == *ip)
-					m++, ip++;
-				m_len = (ip - ii);
-			}
-			assert(m_len > M2_MAX_LEN);
-
-			if (m_off <= M3_MAX_OFFSET)
-			{
-				m_off -= 1;
-				if (m_len <= 33)
-					*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
-				else
-				{
-					m_len -= 33;
-					*op++ = M3_MARKER | 0;
-					goto m3_m4_len;
-				}
-			}
-			else
-			{
-				m_off -= 0x4000;
-				assert(m_off > 0); assert(m_off <= 0x7fff);
-				if (m_len <= M4_MAX_LEN)
-					*op++ = LZO_BYTE(M4_MARKER |
-									 ((m_off & 0x4000) >> 11) | (m_len - 2));
-				else
-				{
-					m_len -= M4_MAX_LEN;
-					*op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
-m3_m4_len:
-					while (m_len > 255)
-					{
-						m_len -= 255;
-						*op++ = 0;
-					}
-					assert(m_len > 0);
-					*op++ = LZO_BYTE(m_len);
-				}
-			}
-
-m3_m4_offset:
-			*op++ = LZO_BYTE((m_off & 63) << 2);
-			*op++ = LZO_BYTE(m_off >> 6);
-		}
-
-		ii = ip;
-		if (ip >= ip_end)
-			break;
-	}
-
-	*out_len = op - out;
-	return pd(in_end,ii);
-}
-
-LZO_PUBLIC(int)
-DO_COMPRESS	  ( const lzo_byte *in , lzo_uint  in_len,
-						 lzo_byte *out, lzo_uintp out_len,
-						 lzo_voidp wrkmem )
-{
-	lzo_byte *op = out;
-	lzo_uint t;
-
-	if (in_len <= M2_MAX_LEN + 5)
-		t = in_len;
-	else
-	{
-		t = do_compress(in,in_len,op,out_len,wrkmem);
-		op += *out_len;
-	}
-
-	if (t > 0)
-	{
-		const lzo_byte *ii = in + in_len - t;
-
-		if (op == out && t <= 238)
-			*op++ = LZO_BYTE(17 + t);
-		else if (t <= 3)
-			op[-2] |= LZO_BYTE(t);
-		else if (t <= 18)
-			*op++ = LZO_BYTE(t - 3);
-		else
-		{
-			lzo_uint tt = t - 18;
-
-			*op++ = 0;
-			while (tt > 255)
-			{
-				tt -= 255;
-				*op++ = 0;
-			}
-			assert(tt > 0);
-			*op++ = LZO_BYTE(tt);
-		}
-		do *op++ = *ii++; while (--t > 0);
-	}
-
-	*op++ = M4_MARKER | 1;
-	*op++ = 0;
-	*op++ = 0;
-
-	*out_len = op - out;
-	return LZO_E_OK;
-}
-
-#undef do_compress
-#undef DO_COMPRESS
-#undef LZO_HASH
-
-#undef LZO_TEST_DECOMPRESS_OVERRUN
-#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT
-#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT
-#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
-#undef DO_DECOMPRESS
-#define DO_DECOMPRESS	   lzo1x_decompress
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_INPUT	   2
-#  endif
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT	  2
-#  endif
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
-#  endif
-#endif
-
-#undef TEST_IP
-#undef TEST_OP
-#undef TEST_LOOKBEHIND
-#undef NEED_IP
-#undef NEED_OP
-#undef HAVE_TEST_IP
-#undef HAVE_TEST_OP
-#undef HAVE_NEED_IP
-#undef HAVE_NEED_OP
-#undef HAVE_ANY_IP
-#undef HAVE_ANY_OP
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
-#	define TEST_IP			 (ip < ip_end)
-#  endif
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
-#	define NEED_IP(x) \
-			if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
-#  endif
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
-#	define TEST_OP			 (op <= op_end)
-#  endif
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
-#	undef TEST_OP
-#	define NEED_OP(x) \
-			if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
-#  endif
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-#  define TEST_LOOKBEHIND(m_pos,out)	if (m_pos < out) goto lookbehind_overrun
-#else
-#  define TEST_LOOKBEHIND(m_pos,op)	 ((void) 0)
-#endif
-
-#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
-#  define TEST_IP			   (ip < ip_end)
-#endif
-
-#if defined(TEST_IP)
-#  define HAVE_TEST_IP
-#else
-#  define TEST_IP			   1
-#endif
-#if defined(TEST_OP)
-#  define HAVE_TEST_OP
-#else
-#  define TEST_OP			   1
-#endif
-
-#if defined(NEED_IP)
-#  define HAVE_NEED_IP
-#else
-#  define NEED_IP(x)			((void) 0)
-#endif
-#if defined(NEED_OP)
-#  define HAVE_NEED_OP
-#else
-#  define NEED_OP(x)			((void) 0)
-#endif
-
-#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-#  define HAVE_ANY_IP
-#endif
-#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-#  define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src)	* (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-#  define COPY4(dst,src)	__COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-#  define COPY4(dst,src)	__COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
-#endif
-
-#if defined(DO_DECOMPRESS)
-LZO_PUBLIC(int)
-DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
-					   lzo_byte *out, lzo_uintp out_len,
-					   lzo_voidp wrkmem )
-#endif
-{
-	register lzo_byte *op;
-	register const lzo_byte *ip;
-	register lzo_uint t;
-	register const lzo_byte *m_pos;
-
-	const lzo_byte * const ip_end = in + in_len;
-#if defined(HAVE_ANY_OP)
-	lzo_byte * const op_end = out + *out_len;
-#endif
-
-	LZO_UNUSED(wrkmem);
-
-	*out_len = 0;
-
-	op = out;
-	ip = in;
-
-	if (*ip > 17)
-	{
-		t = *ip++ - 17;
-		if (t < 4)
-			goto match_next;
-		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
-		do *op++ = *ip++; while (--t > 0);
-		goto first_literal_run;
-	}
-
-	while (TEST_IP && TEST_OP)
-	{
-		t = *ip++;
-		if (t >= 16)
-			goto match;
-		if (t == 0)
-		{
-			NEED_IP(1);
-			while (*ip == 0)
-			{
-				t += 255;
-				ip++;
-				NEED_IP(1);
-			}
-			t += 15 + *ip++;
-		}
-		assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
-#if !defined(LZO_UNALIGNED_OK_4)
-		if (PTR_ALIGNED2_4(op,ip))
-		{
-#endif
-		COPY4(op,ip);
-		op += 4; ip += 4;
-		if (--t > 0)
-		{
-			if (t >= 4)
-			{
-				do {
-					COPY4(op,ip);
-					op += 4; ip += 4; t -= 4;
-				} while (t >= 4);
-				if (t > 0) do *op++ = *ip++; while (--t > 0);
-			}
-			else
-				do *op++ = *ip++; while (--t > 0);
-		}
-#if !defined(LZO_UNALIGNED_OK_4)
-		}
-		else
-#endif
-#endif
-#if !defined(LZO_UNALIGNED_OK_4)
-		{
-			*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
-			do *op++ = *ip++; while (--t > 0);
-		}
-#endif
-
-first_literal_run:
-
-		t = *ip++;
-		if (t >= 16)
-			goto match;
-		m_pos = op - (1 + M2_MAX_OFFSET);
-		m_pos -= t >> 2;
-		m_pos -= *ip++ << 2;
-		TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
-		*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
-		goto match_done;
-
-		while (TEST_IP && TEST_OP)
-		{
-match:
-			if (t >= 64)
-			{
-#if defined(LZO1X)
-				m_pos = op - 1;
-				m_pos -= (t >> 2) & 7;
-				m_pos -= *ip++ << 3;
-				t = (t >> 5) - 1;
-#endif
-				TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
-				goto copy_match;
-			}
-			else if (t >= 32)
-			{
-				t &= 31;
-				if (t == 0)
-				{
-					NEED_IP(1);
-					while (*ip == 0)
-					{
-						t += 255;
-						ip++;
-						NEED_IP(1);
-					}
-					t += 31 + *ip++;
-				}
-#if defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
-				m_pos = op - 1;
-				m_pos -= (* (const lzo_ushortp) ip) >> 2;
-#else
-				m_pos = op - 1;
-				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-#endif
-				ip += 2;
-			}
-			else if (t >= 16)
-			{
-				m_pos = op;
-				m_pos -= (t & 8) << 11;
-				t &= 7;
-				if (t == 0)
-				{
-					NEED_IP(1);
-					while (*ip == 0)
-					{
-						t += 255;
-						ip++;
-						NEED_IP(1);
-					}
-					t += 7 + *ip++;
-				}
-#if defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
-				m_pos -= (* (const lzo_ushortp) ip) >> 2;
-#else
-				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-#endif
-				ip += 2;
-				if (m_pos == op)
-					goto eof_found;
-				m_pos -= 0x4000;
-			}
-			else
-			{
-				m_pos = op - 1;
-				m_pos -= t >> 2;
-				m_pos -= *ip++ << 2;
-				TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
-				*op++ = *m_pos++; *op++ = *m_pos;
-				goto match_done;
-			}
-
-			TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
-#if !defined(LZO_UNALIGNED_OK_4)
-			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
-			{
-				assert((op - m_pos) >= 4);
-#else
-			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
-			{
-#endif
-				COPY4(op,m_pos);
-				op += 4; m_pos += 4; t -= 4 - (3 - 1);
-				do {
-					COPY4(op,m_pos);
-					op += 4; m_pos += 4; t -= 4;
-				} while (t >= 4);
-				if (t > 0) do *op++ = *m_pos++; while (--t > 0);
-			}
-			else
-#endif
-			{
-copy_match:
-				*op++ = *m_pos++; *op++ = *m_pos++;
-				do *op++ = *m_pos++; while (--t > 0);
-			}
-
-match_done:
-			t = ip[-2] & 3;
-			if (t == 0)
-				break;
-
-match_next:
-			assert(t > 0); NEED_OP(t); NEED_IP(t+1);
-			do *op++ = *ip++; while (--t > 0);
-			t = *ip++;
-		}
-	}
-
-#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
-	*out_len = op - out;
-	return LZO_E_EOF_NOT_FOUND;
-#endif
-
-eof_found:
-	assert(t == 1);
-	*out_len = op - out;
-	return (ip == ip_end ? LZO_E_OK :
-		   (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
-
-#if defined(HAVE_NEED_IP)
-input_overrun:
-	*out_len = op - out;
-	return LZO_E_INPUT_OVERRUN;
-#endif
-
-#if defined(HAVE_NEED_OP)
-output_overrun:
-	*out_len = op - out;
-	return LZO_E_OUTPUT_OVERRUN;
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-lookbehind_overrun:
-	*out_len = op - out;
-	return LZO_E_LOOKBEHIND_OVERRUN;
-#endif
-}
-
-#define LZO_TEST_DECOMPRESS_OVERRUN
-#undef DO_DECOMPRESS
-#define DO_DECOMPRESS	   lzo1x_decompress_safe
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_INPUT	   2
-#  endif
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT	  2
-#  endif
-#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-#	define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
-#  endif
-#endif
-
-#undef TEST_IP
-#undef TEST_OP
-#undef TEST_LOOKBEHIND
-#undef NEED_IP
-#undef NEED_OP
-#undef HAVE_TEST_IP
-#undef HAVE_TEST_OP
-#undef HAVE_NEED_IP
-#undef HAVE_NEED_OP
-#undef HAVE_ANY_IP
-#undef HAVE_ANY_OP
-
-
-#if 0
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
-#	define TEST_IP			 (ip < ip_end)
-#  endif
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
-#	define NEED_IP(x) \
-			if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
-#  endif
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
-#	define TEST_OP			 (op <= op_end)
-#  endif
-#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
-#	undef TEST_OP
-#	define NEED_OP(x) \
-			if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
-#  endif
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-#  define TEST_LOOKBEHIND(m_pos,out)	if (m_pos < out) goto lookbehind_overrun
-#else
-#  define TEST_LOOKBEHIND(m_pos,op)	 ((void) 0)
-#endif
-
-#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
-#  define TEST_IP			   (ip < ip_end)
-#endif
-
-#if defined(TEST_IP)
-#  define HAVE_TEST_IP
-#else
-#  define TEST_IP			   1
-#endif
-#if defined(TEST_OP)
-#  define HAVE_TEST_OP
-#else
-#  define TEST_OP			   1
-#endif
-
-#if defined(NEED_IP)
-#  define HAVE_NEED_IP
-#else
-#  define NEED_IP(x)			((void) 0)
-#endif
-#if defined(NEED_OP)
-#  define HAVE_NEED_OP
-#else
-#  define NEED_OP(x)			((void) 0)
-#endif
-
-#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-#  define HAVE_ANY_IP
-#endif
-#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-#  define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src)	* (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-#  define COPY4(dst,src)	__COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-#  define COPY4(dst,src)	__COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
-#endif
-
-#if defined(DO_DECOMPRESS)
-LZO_PUBLIC(int)
-DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
-					   lzo_byte *out, lzo_uintp out_len,
-					   lzo_voidp wrkmem )
-#endif
-{
-	register lzo_byte *op;
-	register const lzo_byte *ip;
-	register lzo_uint t;
-	register const lzo_byte *m_pos;
-
-	const lzo_byte * const ip_end = in + in_len;
-#if defined(HAVE_ANY_OP)
-	lzo_byte * const op_end = out + *out_len;
-#endif
-
-	LZO_UNUSED(wrkmem);
-
-	*out_len = 0;
-
-	op = out;
-	ip = in;
-
-	if (*ip > 17)
-	{
-		t = *ip++ - 17;
-		if (t < 4)
-			goto match_next;
-		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
-		do *op++ = *ip++; while (--t > 0);
-		goto first_literal_run;
-	}
-
-	while (TEST_IP && TEST_OP)
-	{
-		t = *ip++;
-		if (t >= 16)
-			goto match;
-		if (t == 0)
-		{
-			NEED_IP(1);
-			while (*ip == 0)
-			{
-				t += 255;
-				ip++;
-				NEED_IP(1);
-			}
-			t += 15 + *ip++;
-		}
-		assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
-#if !defined(LZO_UNALIGNED_OK_4)
-		if (PTR_ALIGNED2_4(op,ip))
-		{
-#endif
-		COPY4(op,ip);
-		op += 4; ip += 4;
-		if (--t > 0)
-		{
-			if (t >= 4)
-			{
-				do {
-					COPY4(op,ip);
-					op += 4; ip += 4; t -= 4;
-				} while (t >= 4);
-				if (t > 0) do *op++ = *ip++; while (--t > 0);
-			}
-			else
-				do *op++ = *ip++; while (--t > 0);
-		}
-#if !defined(LZO_UNALIGNED_OK_4)
-		}
-		else
-#endif
-#endif
-#if !defined(LZO_UNALIGNED_OK_4)
-		{
-			*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
-			do *op++ = *ip++; while (--t > 0);
-		}
-#endif
-
-first_literal_run:
-
-		t = *ip++;
-		if (t >= 16)
-			goto match;
-#if defined(LZO1Z)
-		t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
-		m_pos = op - t;
-		last_m_off = t;
-#else
-		m_pos = op - (1 + M2_MAX_OFFSET);
-		m_pos -= t >> 2;
-		m_pos -= *ip++ << 2;
-#endif
-		TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
-		*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
-		goto match_done;
-
-		while (TEST_IP && TEST_OP)
-		{
-match:
-			if (t >= 64)
-			{
-#if defined(LZO1X)
-				m_pos = op - 1;
-				m_pos -= (t >> 2) & 7;
-				m_pos -= *ip++ << 3;
-				t = (t >> 5) - 1;
-#elif defined(LZO1Y)
-				m_pos = op - 1;
-				m_pos -= (t >> 2) & 3;
-				m_pos -= *ip++ << 2;
-				t = (t >> 4) - 3;
-#elif defined(LZO1Z)
-				{
-					lzo_uint off = t & 0x1f;
-					m_pos = op;
-					if (off >= 0x1c)
-					{
-						assert(last_m_off > 0);
-						m_pos -= last_m_off;
-					}
-					else
-					{
-						off = 1 + (off << 6) + (*ip++ >> 2);
-						m_pos -= off;
-						last_m_off = off;
-					}
-				}
-				t = (t >> 5) - 1;
-#endif
-				TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
-				goto copy_match;
-			}
-			else if (t >= 32)
-			{
-				t &= 31;
-				if (t == 0)
-				{
-					NEED_IP(1);
-					while (*ip == 0)
-					{
-						t += 255;
-						ip++;
-						NEED_IP(1);
-					}
-					t += 31 + *ip++;
-				}
-#if defined(LZO1Z)
-				{
-					lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
-					m_pos = op - off;
-					last_m_off = off;
-				}
-#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
-				m_pos = op - 1;
-				m_pos -= (* (const lzo_ushortp) ip) >> 2;
-#else
-				m_pos = op - 1;
-				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-#endif
-				ip += 2;
-			}
-			else if (t >= 16)
-			{
-				m_pos = op;
-				m_pos -= (t & 8) << 11;
-				t &= 7;
-				if (t == 0)
-				{
-					NEED_IP(1);
-					while (*ip == 0)
-					{
-						t += 255;
-						ip++;
-						NEED_IP(1);
-					}
-					t += 7 + *ip++;
-				}
-#if defined(LZO1Z)
-				m_pos -= (ip[0] << 6) + (ip[1] >> 2);
-#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
-				m_pos -= (* (const lzo_ushortp) ip) >> 2;
-#else
-				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
-#endif
-				ip += 2;
-				if (m_pos == op)
-					goto eof_found;
-				m_pos -= 0x4000;
-#if defined(LZO1Z)
-				last_m_off = op - m_pos;
-#endif
-			}
-			else
-			{
-#if defined(LZO1Z)
-				t = 1 + (t << 6) + (*ip++ >> 2);
-				m_pos = op - t;
-				last_m_off = t;
-#else
-				m_pos = op - 1;
-				m_pos -= t >> 2;
-				m_pos -= *ip++ << 2;
-#endif
-				TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
-				*op++ = *m_pos++; *op++ = *m_pos;
-				goto match_done;
-			}
-
-			TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
-#if !defined(LZO_UNALIGNED_OK_4)
-			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
-			{
-				assert((op - m_pos) >= 4);
-#else
-			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
-			{
-#endif
-				COPY4(op,m_pos);
-				op += 4; m_pos += 4; t -= 4 - (3 - 1);
-				do {
-					COPY4(op,m_pos);
-					op += 4; m_pos += 4; t -= 4;
-				} while (t >= 4);
-				if (t > 0) do *op++ = *m_pos++; while (--t > 0);
-			}
-			else
-#endif
-			{
-copy_match:
-				*op++ = *m_pos++; *op++ = *m_pos++;
-				do *op++ = *m_pos++; while (--t > 0);
-			}
-
-
-match_done:
-#if defined(LZO1Z)
-			t = ip[-1] & 3;
-#else
-			t = ip[-2] & 3;
-#endif
-			if (t == 0)
-				break;
-
-match_next:
-			assert(t > 0); NEED_OP(t); NEED_IP(t+1);
-			do *op++ = *ip++; while (--t > 0);
-			t = *ip++;
-		}
-	}
-
-#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
-	*out_len = op - out;
-	return LZO_E_EOF_NOT_FOUND;
-#endif
-
-eof_found:
-	assert(t == 1);
-	*out_len = op - out;
-	return (ip == ip_end ? LZO_E_OK :
-		   (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
-
-#if defined(HAVE_NEED_IP)
-input_overrun:
-	*out_len = op - out;
-	return LZO_E_INPUT_OVERRUN;
-#endif
-
-#if defined(HAVE_NEED_OP)
-output_overrun:
-	*out_len = op - out;
-	return LZO_E_OUTPUT_OVERRUN;
-#endif
-
-#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
-lookbehind_overrun:
-	*out_len = op - out;
-	return LZO_E_LOOKBEHIND_OVERRUN;
-#endif
-}
-
-#endif
-
-/***** End of minilzo.c *****/
new file mode 100644
--- /dev/null
+++ b/src/minilzo.cpp
@@ -0,0 +1,1971 @@
+/* $Id$ */
+
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#define LZO_DISABLE_CHECKS
+#define LZO1X
+
+#define __LZO_IN_MINILZO
+#define LZO_BUILD
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1080)
+#  error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  define LZO_HAVE_CONFIG_H
+#endif
+
+#if !defined(LZO_NO_SYS_TYPES_H)
+#  include <sys/types.h>
+#endif
+#include <stdio.h>
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H
+
+#if defined(__BOUNDS_CHECKING_ON)
+#  include <unchecked.h>
+#else
+#  define BOUNDS_CHECKING_OFF_DURING(stmt)	  stmt
+#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)	 (expr)
+#endif
+
+#if !defined(LZO_HAVE_CONFIG_H)
+#  include <stddef.h>
+#  include <string.h>
+#  if !defined(NO_STDLIB_H)
+#	include <stdlib.h>
+#  endif
+#  define HAVE_MEMCMP
+#  define HAVE_MEMCPY
+#  define HAVE_MEMMOVE
+#  define HAVE_MEMSET
+#else
+#  include <sys/types.h>
+#  if defined(HAVE_STDDEF_H)
+#	include <stddef.h>
+#  endif
+#  if defined(STDC_HEADERS)
+#	include <string.h>
+#	include <stdlib.h>
+#  endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  define HAVE_MALLOC_H
+#  define HAVE_HALLOC
+#endif
+
+#undef NDEBUG
+#if !defined(LZO_DEBUG)
+#  define NDEBUG
+#endif
+#if defined(LZO_DEBUG) || !defined(NDEBUG)
+#  if !defined(NO_STDIO_H)
+#	include <stdio.h>
+#  endif
+#endif
+#include <assert.h>
+
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+#  define LZO_COMPILE_TIME_ASSERT(expr) \
+		{ typedef int __lzo_compile_time_assert_fail[1 - 2 * !(expr)]; }
+#endif
+
+#if !defined(LZO_UNUSED)
+#  if 1
+#	define LZO_UNUSED(var)	 ((void)&var)
+#  elif 0
+#	define LZO_UNUSED(var)	 { typedef int __lzo_unused[sizeof(var) ? 2 : 1]; }
+#  else
+#	define LZO_UNUSED(parm)	(parm = parm)
+#  endif
+#endif
+
+#if !defined(__inline__) && !defined(__GNUC__)
+#  if defined(__cplusplus)
+#	define __inline__	  inline
+#  else
+#	define __inline__
+#  endif
+#endif
+
+#if defined(NO_MEMCMP)
+#  undef HAVE_MEMCMP
+#endif
+
+#if 0
+#  define LZO_BYTE(x)	   ((unsigned char) (x))
+#else
+#  define LZO_BYTE(x)	   ((unsigned char) ((x) & 0xff))
+#endif
+
+#define LZO_MAX(a,b)		((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)		((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)	 ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c)	 ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type)	((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array)	 ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits)	  (1u << (bits))
+#define LZO_MASK(bits)	  (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits)	 (1ul << (bits))
+#define LZO_LMASK(bits)	 (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits)	 ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits)	 (LZO_USIZE(bits) - 1)
+
+#define LZO_STYPE_MAX(b)	(((1l  << (8*(b)-2)) - 1l)  + (1l  << (8*(b)-2)))
+#define LZO_UTYPE_MAX(b)	(((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
+
+#if !defined(SIZEOF_UNSIGNED)
+#  if (UINT_MAX == 0xffff)
+#	define SIZEOF_UNSIGNED		 2
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#	define SIZEOF_UNSIGNED		 4
+#  elif (UINT_MAX >= LZO_0xffffffffL)
+#	define SIZEOF_UNSIGNED		 8
+#  else
+#	error "SIZEOF_UNSIGNED"
+#  endif
+#endif
+
+#if !defined(SIZEOF_UNSIGNED_LONG)
+#  if (ULONG_MAX == LZO_0xffffffffL)
+#	define SIZEOF_UNSIGNED_LONG	4
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+#	define SIZEOF_UNSIGNED_LONG	8
+#  else
+#	error "SIZEOF_UNSIGNED_LONG"
+#  endif
+#endif
+
+#if !defined(SIZEOF_SIZE_T)
+#  define SIZEOF_SIZE_T			 SIZEOF_UNSIGNED
+#endif
+#if !defined(SIZE_T_MAX)
+#  define SIZE_T_MAX				LZO_UTYPE_MAX(SIZEOF_SIZE_T)
+#endif
+
+#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL)
+#  if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff)
+#	define LZO_UNALIGNED_OK_2
+#  endif
+#  if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL)
+#	define LZO_UNALIGNED_OK_4
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4)
+#  if !defined(LZO_UNALIGNED_OK)
+#	define LZO_UNALIGNED_OK
+#  endif
+#endif
+
+#if defined(__LZO_NO_UNALIGNED)
+#  undef LZO_UNALIGNED_OK
+#  undef LZO_UNALIGNED_OK_2
+#  undef LZO_UNALIGNED_OK_4
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff)
+#  error "LZO_UNALIGNED_OK_2 must not be defined on this system"
+#endif
+#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_UNALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#if defined(__LZO_NO_ALIGNED)
+#  undef LZO_ALIGNED_OK_4
+#endif
+
+#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_ALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#define LZO_LITTLE_ENDIAN	   1234
+#define LZO_BIG_ENDIAN		  4321
+#define LZO_PDP_ENDIAN		  3412
+
+#if !defined(LZO_BYTE_ORDER)
+#  if defined(MFX_BYTE_ORDER)
+#	define LZO_BYTE_ORDER	  MFX_BYTE_ORDER
+#  elif defined(__LZO_i386)
+#	define LZO_BYTE_ORDER	  LZO_LITTLE_ENDIAN
+#  elif defined(BYTE_ORDER)
+#	define LZO_BYTE_ORDER	  BYTE_ORDER
+#  elif defined(__BYTE_ORDER)
+#	define LZO_BYTE_ORDER	  __BYTE_ORDER
+#  endif
+#endif
+
+#if defined(LZO_BYTE_ORDER)
+#  if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \
+	  (LZO_BYTE_ORDER != LZO_BIG_ENDIAN)
+#	error "invalid LZO_BYTE_ORDER"
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER)
+#  error "LZO_BYTE_ORDER is not defined"
+#endif
+
+#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY
+
+#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__LZO_CHECKER)
+#  if defined(__GNUC__) && defined(__i386__)
+#	if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY)
+#	  define LZO_OPTIMIZE_GNUC_i386
+#	endif
+#  endif
+#endif
+
+__LZO_EXTERN_C int __lzo_init_done;
+__LZO_EXTERN_C const lzo_byte __lzo_copyright[];
+LZO_EXTERN(const lzo_byte *) lzo_copyright(void);
+__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256];
+
+#define _LZO_STRINGIZE(x)		   #x
+#define _LZO_MEXPAND(x)			 _LZO_STRINGIZE(x)
+
+#define _LZO_CONCAT2(a,b)		   a ## b
+#define _LZO_CONCAT3(a,b,c)		 a ## b ## c
+#define _LZO_CONCAT4(a,b,c,d)	   a ## b ## c ## d
+#define _LZO_CONCAT5(a,b,c,d,e)	 a ## b ## c ## d ## e
+
+#define _LZO_ECONCAT2(a,b)		  _LZO_CONCAT2(a,b)
+#define _LZO_ECONCAT3(a,b,c)		_LZO_CONCAT3(a,b,c)
+#define _LZO_ECONCAT4(a,b,c,d)	  _LZO_CONCAT4(a,b,c,d)
+#define _LZO_ECONCAT5(a,b,c,d,e)	_LZO_CONCAT5(a,b,c,d,e)
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  include <dos.h>
+#  if 1 && defined(__WATCOMC__)
+#	include <i86.h>
+	 __LZO_EXTERN_C unsigned char _HShift;
+#	define __LZO_HShift	_HShift
+#  elif 1 && defined(_MSC_VER)
+	 __LZO_EXTERN_C unsigned short __near _AHSHIFT;
+#	define __LZO_HShift	((unsigned) &_AHSHIFT)
+#  elif defined(__LZO_WIN16)
+#	define __LZO_HShift	3
+#  else
+#	define __LZO_HShift	12
+#  endif
+#  if !defined(_FP_SEG) && defined(FP_SEG)
+#	define _FP_SEG		 FP_SEG
+#  endif
+#  if !defined(_FP_OFF) && defined(FP_OFF)
+#	define _FP_OFF		 FP_OFF
+#  endif
+#endif
+
+#if !defined(lzo_ptrdiff_t)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+	 typedef ptrdiff_t		  lzo_ptrdiff_t;
+#  else
+	 typedef long			   lzo_ptrdiff_t;
+#  endif
+#endif
+
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(lzo_ptr_t)
+#	define __LZO_HAVE_PTR_T
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#	if defined(_WIN64)
+		typedef unsigned __int64 lzo_ptr_t;
+		typedef signed __int64   lzo_sptr_r;
+#		define __LZO_HAVE_PTR_T
+#	endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG)
+#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG)
+	   typedef unsigned long	lzo_ptr_t;
+	   typedef long			 lzo_sptr_t;
+#	  define __LZO_HAVE_PTR_T
+#	endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED)
+#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED)
+	   typedef unsigned int	 lzo_ptr_t;
+	   typedef int			  lzo_sptr_t;
+#	  define __LZO_HAVE_PTR_T
+#	endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT)
+#	if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT)
+	   typedef unsigned short   lzo_ptr_t;
+	   typedef short			lzo_sptr_t;
+#	  define __LZO_HAVE_PTR_T
+#	endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P)
+#	error "no suitable type for lzo_ptr_t"
+#  else
+	 typedef unsigned long	  lzo_ptr_t;
+	 typedef long			   lzo_sptr_t;
+#	define __LZO_HAVE_PTR_T
+#  endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#define PTR(a)			  ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a)	((_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0)
+#else
+#define PTR(a)			  ((lzo_ptr_t) (a))
+#define PTR_LINEAR(a)	   PTR(a)
+#define PTR_ALIGNED_4(a)	((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a)	((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b)		 (PTR(a) < PTR(b))
+#define PTR_GE(a,b)		 (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b)	   ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
+#define pd(a,b)			 ((lzo_uint) ((a)-(b)))
+
+LZO_EXTERN(lzo_ptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr);
+
+typedef union
+{
+	char			a_char;
+	unsigned char   a_uchar;
+	short		   a_short;
+	unsigned short  a_ushort;
+	int			 a_int;
+	unsigned int	a_uint;
+	long			a_long;
+	unsigned long   a_ulong;
+	lzo_int		 a_lzo_int;
+	lzo_uint		a_lzo_uint;
+	lzo_int32	   a_lzo_int32;
+	lzo_uint32	  a_lzo_uint32;
+	ptrdiff_t	   a_ptrdiff_t;
+	lzo_ptrdiff_t   a_lzo_ptrdiff_t;
+	lzo_ptr_t	   a_lzo_ptr_t;
+	lzo_voidp	   a_lzo_voidp;
+	void *		  a_void_p;
+	lzo_bytep	   a_lzo_bytep;
+	lzo_bytepp	  a_lzo_bytepp;
+	lzo_uintp	   a_lzo_uintp;
+	lzo_uint *	  a_lzo_uint_p;
+	lzo_uint32p	 a_lzo_uint32p;
+	lzo_uint32 *	a_lzo_uint32_p;
+	unsigned char * a_uchar_p;
+	char *		  a_char_p;
+}
+lzo_full_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#define LZO_DETERMINISTIC
+
+#define LZO_DICT_USE_PTR
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT)
+#  undef LZO_DICT_USE_PTR
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+#  define lzo_dict_t	const lzo_bytep
+#  define lzo_dict_p	lzo_dict_t __LZO_MMODEL *
+#else
+#  define lzo_dict_t	lzo_uint
+#  define lzo_dict_p	lzo_dict_t __LZO_MMODEL *
+#endif
+
+#if !defined(lzo_moff_t)
+#define lzo_moff_t	  lzo_uint
+#endif
+
+#endif
+
+
+#ifndef __LZO_UTIL_H
+#define __LZO_UTIL_H
+
+#ifndef __LZO_CONF_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 1 && defined(HAVE_MEMCPY)
+#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16)
+
+#define MEMCPY8_DS(dest,src,len) \
+	memcpy(dest,src,len); \
+	dest += len; \
+	src += len
+
+#endif
+#endif
+
+#if 0 && !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+	{ do { \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		len -= 8; \
+	} while (len > 0); }
+
+#endif
+
+#if !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+	{ register lzo_uint __l = (len) / 8; \
+	do { \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+		*dest++ = *src++; \
+	} while (--__l > 0); }
+
+#endif
+
+#define MEMCPY_DS(dest,src,len) \
+	do *dest++ = *src++; \
+	while (--len > 0)
+
+#define MEMMOVE_DS(dest,src,len) \
+	do *dest++ = *src++; \
+	while (--len > 0)
+
+#if 0 && defined(LZO_OPTIMIZE_GNUC_i386)
+
+#define BZERO8_PTR(s,l,n) \
+__asm__ __volatile__( \
+	"movl  %0,%%eax \n"			 \
+	"movl  %1,%%edi \n"			 \
+	"movl  %2,%%ecx \n"			 \
+	"cld \n"						\
+	"rep \n"						\
+	"stosl %%eax,(%%edi) \n"		\
+	:			   \
+	:"g" (0),"g" (s),"g" (n)		\
+	:"eax","edi","ecx", "memory", "cc" \
+)
+
+#elif (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+
+#if 1
+#define BZERO8_PTR(s,l,n)   memset((s),0,(lzo_uint)(l)*(n))
+#else
+#define BZERO8_PTR(s,l,n)   memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+#endif
+
+#else
+
+#define BZERO8_PTR(s,l,n) \
+	lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#endif
+
+#if 0
+#if defined(__GNUC__) && defined(__i386__)
+
+unsigned char lzo_rotr8(unsigned char value, int shift);
+extern __inline__ unsigned char lzo_rotr8(unsigned char value, int shift)
+{
+	unsigned char result;
+
+	__asm__ __volatile__ ("movb %b1, %b0; rorb %b2, %b0"
+						: "=a"(result) : "g"(value), "c"(shift));
+	return result;
+}
+
+unsigned short lzo_rotr16(unsigned short value, int shift);
+extern __inline__ unsigned short lzo_rotr16(unsigned short value, int shift)
+{
+	unsigned short result;
+
+	__asm__ __volatile__ ("movw %b1, %b0; rorw %b2, %b0"
+						: "=a"(result) : "g"(value), "c"(shift));
+	return result;
+}
+
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+/* If you use the LZO library in a product, you *must* keep this
+ * copyright string in the executable of your product.
+ */
+
+const lzo_byte __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+	LZO_VERSION_STRING;
+#else
+	"\n\n\n"
+	"LZO real-time data compression library.\n"
+	"Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer\n"
+	"<markus.oberhumer@jk.uni-linz.ac.at>\n"
+	"http://www.oberhumer.com/opensource/lzo/\n"
+	"\n"
+	"LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n"
+	"LZO build date: " __DATE__ " " __TIME__ "\n\n"
+	"LZO special compilation options:\n"
+#ifdef __cplusplus
+	" __cplusplus\n"
+#endif
+#if defined(__PIC__)
+	" __PIC__\n"
+#elif defined(__pic__)
+	" __pic__\n"
+#endif
+#if (UINT_MAX < LZO_0xffffffffL)
+	" 16BIT\n"
+#endif
+#if defined(__LZO_STRICT_16BIT)
+	" __LZO_STRICT_16BIT\n"
+#endif
+#if (UINT_MAX > LZO_0xffffffffL)
+	" UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n"
+#endif
+#if (ULONG_MAX > LZO_0xffffffffL)
+	" ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n"
+#endif
+#if defined(LZO_BYTE_ORDER)
+	" LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+	" LZO_UNALIGNED_OK_2\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+	" LZO_UNALIGNED_OK_4\n"
+#endif
+#if defined(LZO_ALIGNED_OK_4)
+	" LZO_ALIGNED_OK_4\n"
+#endif
+#if defined(LZO_DICT_USE_PTR)
+	" LZO_DICT_USE_PTR\n"
+#endif
+#if defined(__LZO_QUERY_COMPRESS)
+	" __LZO_QUERY_COMPRESS\n"
+#endif
+#if defined(__LZO_QUERY_DECOMPRESS)
+	" __LZO_QUERY_DECOMPRESS\n"
+#endif
+#if defined(__LZO_IN_MINILZO)
+	" __LZO_IN_MINILZO\n"
+#endif
+	"\n\n"
+	"$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__
+#if defined(__GNUC__) && defined(__VERSION__)
+	" by gcc " __VERSION__
+#elif defined(__BORLANDC__)
+	" by Borland C " _LZO_MEXPAND(__BORLANDC__)
+#elif defined(_MSC_VER)
+	" by Microsoft C " _LZO_MEXPAND(_MSC_VER)
+#elif defined(__PUREC__)
+	" by Pure C " _LZO_MEXPAND(__PUREC__)
+#elif defined(__SC__)
+	" by Symantec C " _LZO_MEXPAND(__SC__)
+#elif defined(__TURBOC__)
+	" by Turbo C " _LZO_MEXPAND(__TURBOC__)
+#elif defined(__WATCOMC__)
+	" by Watcom C " _LZO_MEXPAND(__WATCOMC__)
+#endif
+	" $\n"
+	"$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer $\n";
+#endif
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+LZO_PUBLIC(lzo_uint32)
+lzo_adler32(lzo_uint32 adler, const lzo_byte *buf, lzo_uint len)
+{
+	lzo_uint32 s1 = adler & 0xffff;
+	lzo_uint32 s2 = (adler >> 16) & 0xffff;
+	int k;
+
+	if (buf == NULL)
+		return 1;
+
+	while (len > 0)
+	{
+		k = len < LZO_NMAX ? (int) len : LZO_NMAX;
+		len -= k;
+		if (k >= 16) do
+		{
+			LZO_DO16(buf,0);
+			buf += 16;
+			k -= 16;
+		} while (k >= 16);
+		if (k != 0) do
+		{
+			s1 += *buf++;
+			s2 += s1;
+		} while (--k > 0);
+		s1 %= LZO_BASE;
+		s2 %= LZO_BASE;
+		}
+	return (s2 << 16) | s1;
+}
+
+#if 0
+#  define IS_SIGNED(type)	   (((type) (1ul << (8 * sizeof(type) - 1))) < 0)
+#  define IS_UNSIGNED(type)	 (((type) (1ul << (8 * sizeof(type) - 1))) > 0)
+#else
+#  define IS_SIGNED(type)	   (((type) (-1)) < ((type) 0))
+#  define IS_UNSIGNED(type)	 (((type) (-1)) > ((type) 0))
+#endif
+
+#define IS_POWER_OF_2(x)		(((x) & ((x) - 1)) == 0)
+
+// static lzo_bool schedule_insns_bug(void);
+// static lzo_bool strength_reduce_bug(int *);
+
+#if 0 || defined(LZO_DEBUG)
+#include <stdio.h>
+static lzo_bool __lzo_assert_fail(const char *s, unsigned line)
+{
+#if defined(__palmos__)
+	printf("LZO assertion failed in line %u: '%s'\n",line,s);
+#else
+	fprintf(stderr,"LZO assertion failed in line %u: '%s'\n",line,s);
+#endif
+	return 0;
+}
+#  define __lzo_assert(x)   ((x) ? 1 : __lzo_assert_fail(#x,__LINE__))
+#else
+#  define __lzo_assert(x)   ((x) ? 1 : 0)
+#endif
+
+#undef COMPILE_TIME_ASSERT
+#if 0
+#  define COMPILE_TIME_ASSERT(expr)	 r &= __lzo_assert(expr)
+#else
+#  define COMPILE_TIME_ASSERT(expr)	 LZO_COMPILE_TIME_ASSERT(expr)
+#endif
+
+
+#define do_compress		 _lzo1x_1_do_compress
+
+#define LZO_NEED_DICT_H
+#define D_BITS		  12
+#define D_INDEX1(d,p)	   d = DM((0x21*DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)	   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H
+
+#define LZO_EOF_CODE
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET   0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET   0x0800
+#endif
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN	  2
+#define M1_MAX_LEN	  2
+#define M2_MIN_LEN	  3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN	  8
+#endif
+#define M3_MIN_LEN	  3
+#define M3_MAX_LEN	  33
+#define M4_MIN_LEN	  3
+#define M4_MAX_LEN	  9
+
+#define M1_MARKER	   0
+#define M2_MARKER	   64
+#define M3_MARKER	   32
+#define M4_MARKER	   16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD	   (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH			LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN		  M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+#  define D_BITS		DBITS
+#endif
+#if !defined(D_BITS)
+#  error "D_BITS is not defined"
+#endif
+#if (D_BITS < 16)
+#  define D_SIZE		LZO_SIZE(D_BITS)
+#  define D_MASK		LZO_MASK(D_BITS)
+#else
+#  define D_SIZE		LZO_USIZE(D_BITS)
+#  define D_MASK		LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH		  ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+#  define DD_BITS	   0
+#endif
+#define DD_SIZE		 LZO_SIZE(DD_BITS)
+#define DD_MASK		 LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+#  define DL_BITS	   (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+#  define DL_SIZE	   LZO_SIZE(DL_BITS)
+#  define DL_MASK	   LZO_MASK(DL_BITS)
+#else
+#  define DL_SIZE	   LZO_USIZE(DL_BITS)
+#  define DL_MASK	   LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+#  error "D_BITS does not match"
+#endif
+#if (D_BITS < 8 || D_BITS > 18)
+#  error "invalid D_BITS"
+#endif
+#if (DL_BITS < 8 || DL_BITS > 20)
+#  error "invalid DL_BITS"
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+#  error "invalid DD_BITS"
+#endif
+
+#if !defined(DL_MIN_LEN)
+#  define DL_MIN_LEN	3
+#endif
+#if !defined(DL_SHIFT)
+#  define DL_SHIFT	  ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP				   1
+#define LZO_HASH_GZIP_INCREMENTAL	   2
+#define LZO_HASH_LZO_INCREMENTAL_A	  3
+#define LZO_HASH_LZO_INCREMENTAL_B	  4
+
+#if !defined(LZO_HASH)
+#  error "choose a hashing strategy"
+#endif
+
+#if (DL_MIN_LEN == 3)
+#  define _DV2_A(p,shift1,shift2) \
+		(((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+#  define _DV2_B(p,shift1,shift2) \
+		(((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+#  define _DV3_B(p,shift1,shift2,shift3) \
+		((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+#  define _DV2_A(p,shift1,shift2) \
+		(( (lzo_uint32)(p[0]) << shift1) ^ p[1])
+#  define _DV2_B(p,shift1,shift2) \
+		(( (lzo_uint32)(p[1]) << shift1) ^ p[2])
+#else
+#  error "invalid DL_MIN_LEN"
+#endif
+#define _DV_A(p,shift)	  _DV2_A(p,shift,shift)
+#define _DV_B(p,shift)	  _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+		(((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+		(((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+		(((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s)		((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)		   DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+#  define _DINDEX(dv,p)	 (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)
+#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])
+#  define _DINDEX(dv,p)	 (dv)
+#  define DVAL_LOOKAHEAD	DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)
+#  define DVAL_NEXT(dv,p) \
+				dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+#  define _DINDEX(dv,p)	 ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD	DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)
+#  define DVAL_NEXT(dv,p) \
+				dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5)))
+#  define _DINDEX(dv,p)	 ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD	DL_MIN_LEN
+
+#else
+#  error "choose a hashing strategy"
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p)		((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1			 D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2			 D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+#  define DVAL_FIRST(dv,p)  ((void) 0)
+#  define DVAL_NEXT(dv,p)   ((void) 0)
+#  define DVAL_LOOKAHEAD	0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte *p)
+{
+	lzo_uint32 df;
+	DVAL_FIRST(df,(p));
+	assert(DINDEX(dv,p) == DINDEX(df,p));
+}
+#else
+#  define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+#  define DENTRY(p,in)						  (p)
+#  define GINDEX(m_pos,m_off,dict,dindex,in)	m_pos = dict[dindex]
+#else
+#  define DENTRY(p,in)						  ((lzo_uint) ((p)-(in)))
+#  define GINDEX(m_pos,m_off,dict,dindex,in)	m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+#  define UPDATE_D(dict,drun,dv,p,in)	   dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+#  define UPDATE_I(dict,drun,index,p,in)	dict[index] = DENTRY(p,in)
+#  define UPDATE_P(ptr,drun,p,in)		   (ptr)[0] = DENTRY(p,in)
+
+#else
+
+#  define UPDATE_D(dict,drun,dv,p,in)   \
+		dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_I(dict,drun,index,p,in)	\
+		dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_P(ptr,drun,p,in)   \
+		(ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+		(m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+	(BOUNDS_CHECKING_OFF_IN_EXPR( \
+		(PTR_LT(m_pos,in) || \
+		 (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
+		  m_off > max_offset) ))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+		(m_off == 0 || \
+		 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+		 (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+		((lzo_moff_t) ((ip)-(in)) <= m_off || \
+		 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+		 (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if defined(LZO_DETERMINISTIC)
+#  define LZO_CHECK_MPOS	LZO_CHECK_MPOS_DET
+#else
+#  define LZO_CHECK_MPOS	LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
+#endif
+
+#define DO_COMPRESS	 lzo1x_1_compress
+
+static
+lzo_uint do_compress	 ( const lzo_byte *in , lzo_uint  in_len,
+								 lzo_byte *out, lzo_uintp out_len,
+								 lzo_voidp wrkmem )
+{
+		register const lzo_byte *ip;
+		lzo_byte *op;
+		const lzo_byte * const in_end = in + in_len;
+		const lzo_byte * const ip_end = in + in_len - M2_MAX_LEN - 5;
+		const lzo_byte *ii;
+		lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+		op = out;
+		ip = in;
+		ii = ip;
+
+		ip += 4;
+		for (;;)
+		{
+		register const lzo_byte *m_pos;
+		lzo_moff_t m_off;
+		lzo_uint m_len;
+		lzo_uint dindex;
+
+		DINDEX1(dindex,ip);
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		DINDEX2(dindex,ip);
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		goto literal;
+
+try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+		if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+		if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+		{
+		}
+		else
+		{
+			if (m_pos[2] == ip[2])
+			{
+					goto match;
+			}
+		}
+
+literal:
+		UPDATE_I(dict,0,dindex,ip,in);
+		++ip;
+		if (ip >= ip_end)
+			break;
+		continue;
+
+match:
+		UPDATE_I(dict,0,dindex,ip,in);
+		if (pd(ip,ii) > 0)
+		{
+			register lzo_uint t = pd(ip,ii);
+
+			if (t <= 3)
+			{
+				assert(op - 2 > out);
+				op[-2] |= LZO_BYTE(t);
+			}
+			else if (t <= 18)
+				*op++ = LZO_BYTE(t - 3);
+			else
+			{
+				register lzo_uint tt = t - 18;
+
+				*op++ = 0;
+				while (tt > 255)
+				{
+					tt -= 255;
+					*op++ = 0;
+				}
+				assert(tt > 0);
+				*op++ = LZO_BYTE(tt);
+			}
+			do *op++ = *ii++; while (--t > 0);
+		}
+
+		assert(ii == ip);
+		ip += 3;
+		if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
+			m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++) {
+
+			--ip;
+			m_len = ip - ii;
+			assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
+
+			if (m_off <= M2_MAX_OFFSET)
+			{
+				m_off -= 1;
+				*op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+				*op++ = LZO_BYTE(m_off >> 3);
+			}
+			else if (m_off <= M3_MAX_OFFSET)
+			{
+				m_off -= 1;
+				*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+				goto m3_m4_offset;
+			}
+			else
+			{
+				m_off -= 0x4000;
+				assert(m_off > 0); assert(m_off <= 0x7fff);
+				*op++ = LZO_BYTE(M4_MARKER |
+								 ((m_off & 0x4000) >> 11) | (m_len - 2));
+				goto m3_m4_offset;
+			}
+		}
+		else
+		{
+			{
+				const lzo_byte *end = in_end;
+				const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
+				while (ip < end && *m == *ip)
+					m++, ip++;
+				m_len = (ip - ii);
+			}
+			assert(m_len > M2_MAX_LEN);
+
+			if (m_off <= M3_MAX_OFFSET)
+			{
+				m_off -= 1;
+				if (m_len <= 33)
+					*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+				else
+				{
+					m_len -= 33;
+					*op++ = M3_MARKER | 0;
+					goto m3_m4_len;
+				}
+			}
+			else
+			{
+				m_off -= 0x4000;
+				assert(m_off > 0); assert(m_off <= 0x7fff);
+				if (m_len <= M4_MAX_LEN)
+					*op++ = LZO_BYTE(M4_MARKER |
+									 ((m_off & 0x4000) >> 11) | (m_len - 2));
+				else
+				{
+					m_len -= M4_MAX_LEN;
+					*op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
+m3_m4_len:
+					while (m_len > 255)
+					{
+						m_len -= 255;
+						*op++ = 0;
+					}
+					assert(m_len > 0);
+					*op++ = LZO_BYTE(m_len);
+				}
+			}
+
+m3_m4_offset:
+			*op++ = LZO_BYTE((m_off & 63) << 2);
+			*op++ = LZO_BYTE(m_off >> 6);
+		}
+
+		ii = ip;
+		if (ip >= ip_end)
+			break;
+	}
+
+	*out_len = op - out;
+	return pd(in_end,ii);
+}
+
+LZO_PUBLIC(int)
+DO_COMPRESS	  ( const lzo_byte *in , lzo_uint  in_len,
+						 lzo_byte *out, lzo_uintp out_len,
+						 lzo_voidp wrkmem )
+{
+	lzo_byte *op = out;
+	lzo_uint t;
+
+	if (in_len <= M2_MAX_LEN + 5)
+		t = in_len;
+	else
+	{
+		t = do_compress(in,in_len,op,out_len,wrkmem);
+		op += *out_len;
+	}
+
+	if (t > 0)
+	{
+		const lzo_byte *ii = in + in_len - t;
+
+		if (op == out && t <= 238)
+			*op++ = LZO_BYTE(17 + t);
+		else if (t <= 3)
+			op[-2] |= LZO_BYTE(t);
+		else if (t <= 18)
+			*op++ = LZO_BYTE(t - 3);
+		else
+		{
+			lzo_uint tt = t - 18;
+
+			*op++ = 0;
+			while (tt > 255)
+			{
+				tt -= 255;
+				*op++ = 0;
+			}
+			assert(tt > 0);
+			*op++ = LZO_BYTE(tt);
+		}
+		do *op++ = *ii++; while (--t > 0);
+	}
+
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+
+	*out_len = op - out;
+	return LZO_E_OK;
+}
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_DECOMPRESS_OVERRUN
+#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS	   lzo1x_decompress
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_INPUT	   2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT	  2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#	define TEST_IP			 (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#	define NEED_IP(x) \
+			if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#	define TEST_OP			 (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#	undef TEST_OP
+#	define NEED_OP(x) \
+			if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)	if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)	 ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP			   (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP			   1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP			   1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)			((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)			((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)	* (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)	__COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)	__COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
+					   lzo_byte *out, lzo_uintp out_len,
+					   lzo_voidp wrkmem )
+#endif
+{
+	register lzo_byte *op;
+	register const lzo_byte *ip;
+	register lzo_uint t;
+	register const lzo_byte *m_pos;
+
+	const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+	lzo_byte * const op_end = out + *out_len;
+#endif
+
+	LZO_UNUSED(wrkmem);
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17)
+	{
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+		do *op++ = *ip++; while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP)
+	{
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		if (t == 0)
+		{
+			NEED_IP(1);
+			while (*ip == 0)
+			{
+				t += 255;
+				ip++;
+				NEED_IP(1);
+			}
+			t += 15 + *ip++;
+		}
+		assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+		if (PTR_ALIGNED2_4(op,ip))
+		{
+#endif
+		COPY4(op,ip);
+		op += 4; ip += 4;
+		if (--t > 0)
+		{
+			if (t >= 4)
+			{
+				do {
+					COPY4(op,ip);
+					op += 4; ip += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0) do *op++ = *ip++; while (--t > 0);
+			}
+			else
+				do *op++ = *ip++; while (--t > 0);
+		}
+#if !defined(LZO_UNALIGNED_OK_4)
+		}
+		else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+		{
+			*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+			do *op++ = *ip++; while (--t > 0);
+		}
+#endif
+
+first_literal_run:
+
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+		TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
+		*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+		goto match_done;
+
+		while (TEST_IP && TEST_OP)
+		{
+match:
+			if (t >= 64)
+			{
+#if defined(LZO1X)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+#endif
+				TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+				goto copy_match;
+			}
+			else if (t >= 32)
+			{
+				t &= 31;
+				if (t == 0)
+				{
+					NEED_IP(1);
+					while (*ip == 0)
+					{
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 31 + *ip++;
+				}
+#if defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos = op - 1;
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos = op - 1;
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+			}
+			else if (t >= 16)
+			{
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+				t &= 7;
+				if (t == 0)
+				{
+					NEED_IP(1);
+					while (*ip == 0)
+					{
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 7 + *ip++;
+				}
+#if defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+			}
+			else
+			{
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+				TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
+				*op++ = *m_pos++; *op++ = *m_pos;
+				goto match_done;
+			}
+
+			TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+			{
+				assert((op - m_pos) >= 4);
+#else
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+			{
+#endif
+				COPY4(op,m_pos);
+				op += 4; m_pos += 4; t -= 4 - (3 - 1);
+				do {
+					COPY4(op,m_pos);
+					op += 4; m_pos += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+			}
+			else
+#endif
+			{
+copy_match:
+				*op++ = *m_pos++; *op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+match_done:
+			t = ip[-2] & 3;
+			if (t == 0)
+				break;
+
+match_next:
+			assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+			do *op++ = *ip++; while (--t > 0);
+			t = *ip++;
+		}
+	}
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+	*out_len = op - out;
+	return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+	assert(t == 1);
+	*out_len = op - out;
+	return (ip == ip_end ? LZO_E_OK :
+		   (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+	*out_len = op - out;
+	return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+	*out_len = op - out;
+	return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+	*out_len = op - out;
+	return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#define LZO_TEST_DECOMPRESS_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS	   lzo1x_decompress_safe
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_INPUT	   2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT	  2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#	define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+
+#if 0
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#	define TEST_IP			 (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#	define NEED_IP(x) \
+			if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#	define TEST_OP			 (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#	undef TEST_OP
+#	define NEED_OP(x) \
+			if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)	if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)	 ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP			   (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP			   1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP			   1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)			((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)			((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)	* (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)	__COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)	__COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
+					   lzo_byte *out, lzo_uintp out_len,
+					   lzo_voidp wrkmem )
+#endif
+{
+	register lzo_byte *op;
+	register const lzo_byte *ip;
+	register lzo_uint t;
+	register const lzo_byte *m_pos;
+
+	const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+	lzo_byte * const op_end = out + *out_len;
+#endif
+
+	LZO_UNUSED(wrkmem);
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17)
+	{
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+		do *op++ = *ip++; while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP)
+	{
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		if (t == 0)
+		{
+			NEED_IP(1);
+			while (*ip == 0)
+			{
+				t += 255;
+				ip++;
+				NEED_IP(1);
+			}
+			t += 15 + *ip++;
+		}
+		assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+		if (PTR_ALIGNED2_4(op,ip))
+		{
+#endif
+		COPY4(op,ip);
+		op += 4; ip += 4;
+		if (--t > 0)
+		{
+			if (t >= 4)
+			{
+				do {
+					COPY4(op,ip);
+					op += 4; ip += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0) do *op++ = *ip++; while (--t > 0);
+			}
+			else
+				do *op++ = *ip++; while (--t > 0);
+		}
+#if !defined(LZO_UNALIGNED_OK_4)
+		}
+		else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+		{
+			*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+			do *op++ = *ip++; while (--t > 0);
+		}
+#endif
+
+first_literal_run:
+
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+#if defined(LZO1Z)
+		t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		m_pos = op - t;
+		last_m_off = t;
+#else
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+#endif
+		TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
+		*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+		goto match_done;
+
+		while (TEST_IP && TEST_OP)
+		{
+match:
+			if (t >= 64)
+			{
+#if defined(LZO1X)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 3;
+				m_pos -= *ip++ << 2;
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				{
+					lzo_uint off = t & 0x1f;
+					m_pos = op;
+					if (off >= 0x1c)
+					{
+						assert(last_m_off > 0);
+						m_pos -= last_m_off;
+					}
+					else
+					{
+						off = 1 + (off << 6) + (*ip++ >> 2);
+						m_pos -= off;
+						last_m_off = off;
+					}
+				}
+				t = (t >> 5) - 1;
+#endif
+				TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+				goto copy_match;
+			}
+			else if (t >= 32)
+			{
+				t &= 31;
+				if (t == 0)
+				{
+					NEED_IP(1);
+					while (*ip == 0)
+					{
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 31 + *ip++;
+				}
+#if defined(LZO1Z)
+				{
+					lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+					m_pos = op - off;
+					last_m_off = off;
+				}
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos = op - 1;
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos = op - 1;
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+			}
+			else if (t >= 16)
+			{
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+				t &= 7;
+				if (t == 0)
+				{
+					NEED_IP(1);
+					while (*ip == 0)
+					{
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 7 + *ip++;
+				}
+#if defined(LZO1Z)
+				m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+#if defined(LZO1Z)
+				last_m_off = op - m_pos;
+#endif
+			}
+			else
+			{
+#if defined(LZO1Z)
+				t = 1 + (t << 6) + (*ip++ >> 2);
+				m_pos = op - t;
+				last_m_off = t;
+#else
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+#endif
+				TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
+				*op++ = *m_pos++; *op++ = *m_pos;
+				goto match_done;
+			}
+
+			TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+			{
+				assert((op - m_pos) >= 4);
+#else
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+			{
+#endif
+				COPY4(op,m_pos);
+				op += 4; m_pos += 4; t -= 4 - (3 - 1);
+				do {
+					COPY4(op,m_pos);
+					op += 4; m_pos += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+			}
+			else
+#endif
+			{
+copy_match:
+				*op++ = *m_pos++; *op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+
+match_done:
+#if defined(LZO1Z)
+			t = ip[-1] & 3;
+#else
+			t = ip[-2] & 3;
+#endif
+			if (t == 0)
+				break;
+
+match_next:
+			assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+			do *op++ = *ip++; while (--t > 0);
+			t = *ip++;
+		}
+	}
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+	*out_len = op - out;
+	return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+	assert(t == 1);
+	*out_len = op - out;
+	return (ip == ip_end ? LZO_E_OK :
+		   (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+	*out_len = op - out;
+	return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+	*out_len = op - out;
+	return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+	*out_len = op - out;
+	return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#endif
+
+/***** End of minilzo.c *****/
deleted file mode 100644
--- a/src/misc.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "functions.h"
-#include "news.h"
-#include "player.h"
-#include "string.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "vehicle.h"
-#include "saveload.h"
-#include "engine.h"
-#include "vehicle_gui.h"
-#include "variables.h"
-#include "ai/ai.h"
-#include "table/landscape_const.h"
-#include "date.h"
-
-char _name_array[512][32];
-
-#ifndef MERSENNE_TWISTER
-
-#ifdef RANDOM_DEBUG
-#include "network/network_data.h"
-uint32 DoRandom(int line, const char *file)
-#else // RANDOM_DEBUG
-uint32 Random(void)
-#endif // RANDOM_DEBUG
-{
-
-uint32 s;
-uint32 t;
-
-#ifdef RANDOM_DEBUG
-	if (_networking && (DEREF_CLIENT(0)->status != STATUS_INACTIVE || !_network_server))
-		printf("Random [%d/%d] %s:%d\n",_frame_counter, _current_player, file, line);
-#endif
-
-	s = _random_seeds[0][0];
-	t = _random_seeds[0][1];
-	_random_seeds[0][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
-	return _random_seeds[0][1] = ROR(s, 3) - 1;
-}
-#endif // MERSENNE_TWISTER
-
-#if defined(RANDOM_DEBUG) && !defined(MERSENNE_TWISTER)
-uint DoRandomRange(uint max, int line, const char *file)
-{
-	return GB(DoRandom(line, file), 0, 16) * max >> 16;
-}
-#else
-uint RandomRange(uint max)
-{
-	return GB(Random(), 0, 16) * max >> 16;
-}
-#endif
-
-
-uint32 InteractiveRandom(void)
-{
-	uint32 t = _random_seeds[1][1];
-	uint32 s = _random_seeds[1][0];
-	_random_seeds[1][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
-	return _random_seeds[1][1] = ROR(s, 3) - 1;
-}
-
-uint InteractiveRandomRange(uint max)
-{
-	return GB(InteractiveRandom(), 0, 16) * max >> 16;
-}
-
-void InitializeVehicles(void);
-void InitializeWaypoints(void);
-void InitializeDepots(void);
-void InitializeEngines(void);
-void InitializeOrders(void);
-void InitializeClearLand(void);
-void InitializeRailGui(void);
-void InitializeRoadGui(void);
-void InitializeAirportGui(void);
-void InitializeDockGui(void);
-void InitializeIndustries(void);
-void InitializeMainGui(void);
-void InitializeLandscape(void);
-void InitializeTowns(void);
-void InitializeTrees(void);
-void InitializeSigns(void);
-void InitializeStations(void);
-static void InitializeNameMgr(void);
-void InitializePlayers(void);
-static void InitializeCheats(void);
-void InitializeNPF(void);
-
-void InitializeGame(int mode, uint size_x, uint size_y)
-{
-	AllocateMap(size_x, size_y);
-
-	AddTypeToEngines(); // make sure all engines have a type
-
-	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
-
-	_pause = 0;
-	_fast_forward = 0;
-	_tick_counter = 0;
-	_date_fract = 0;
-	_cur_tileloop_tile = 0;
-
-	if ((mode & IG_DATE_RESET) == IG_DATE_RESET) {
-		SetDate(ConvertYMDToDate(_patches.starting_year, 0, 1));
-	}
-
-	InitializeEngines();
-	InitializeVehicles();
-	InitializeWaypoints();
-	InitializeDepots();
-	InitializeOrders();
-
-	InitNewsItemStructs();
-	InitializeLandscape();
-	InitializeClearLand();
-	InitializeRailGui();
-	InitializeRoadGui();
-	InitializeAirportGui();
-	InitializeDockGui();
-	InitializeTowns();
-	InitializeTrees();
-	InitializeSigns();
-	InitializeStations();
-	InitializeIndustries();
-	InitializeMainGui();
-
-	InitializeNameMgr();
-	InitializeVehiclesGuiList();
-	InitializeTrains();
-	InitializeNPF();
-
-	AI_Initialize();
-	InitializePlayers();
-	InitializeCheats();
-
-	InitTextEffects();
-	InitTextMessage();
-	InitializeAnimatedTiles();
-
-	InitializeLandscapeVariables(false);
-
-	ResetObjectToPlace();
-}
-
-bool IsCustomName(StringID id)
-{
-	return GB(id, 11, 5) == 15;
-}
-
-void DeleteName(StringID id)
-{
-	if (IsCustomName(id)) {
-		memset(_name_array[id & 0x1FF], 0, sizeof(_name_array[id & 0x1FF]));
-	}
-}
-
-char *GetName(char *buff, StringID id, const char* last)
-{
-	return strecpy(buff, _name_array[id & ~0x600], last);
-}
-
-
-static void InitializeCheats(void)
-{
-	memset(&_cheats, 0, sizeof(Cheats));
-}
-
-
-static void InitializeNameMgr(void)
-{
-	memset(_name_array, 0, sizeof(_name_array));
-}
-
-StringID RealAllocateName(const char *name, byte skip, bool check_double)
-{
-	char (*free_item)[lengthof(*_name_array)] = NULL;
-	char (*i)[lengthof(*_name_array)];
-
-	for (i = _name_array; i != endof(_name_array); ++i) {
-		if ((*i)[0] == '\0') {
-			if (free_item == NULL) free_item = i;
-		} else if (check_double && strncmp(*i, name, lengthof(*i) - 1) == 0) {
-			_error_message = STR_0132_CHOSEN_NAME_IN_USE_ALREADY;
-			return 0;
-		}
-	}
-
-	if (free_item != NULL) {
-		ttd_strlcpy(*free_item, name, lengthof(*free_item));
-		return (free_item - _name_array) | 0x7800 | (skip << 8);
-	} else {
-		_error_message = STR_0131_TOO_MANY_NAMES_DEFINED;
-		return 0;
-	}
-}
-
-void ConvertNameArray(void)
-{
-	uint i;
-
-	for (i = 0; i < lengthof(_name_array); i++) {
-		const char *strfrom = _name_array[i];
-		char tmp[sizeof(*_name_array)];
-		char *strto = tmp;
-
-		for (; *strfrom != '\0'; strfrom++) {
-			WChar c = (byte)*strfrom;
-			switch (c) {
-				case 0xA4: c = 0x20AC; break; // Euro
-				case 0xA6: c = 0x0160; break; // S with caron
-				case 0xA8: c = 0x0161; break; // s with caron
-				case 0xB4: c = 0x017D; break; // Z with caron
-				case 0xB8: c = 0x017E; break; // z with caron
-				case 0xBC: c = 0x0152; break; // OE ligature
-				case 0xBD: c = 0x0153; break; // oe ligature
-				case 0xBE: c = 0x0178; break; // Y with diaresis
-				default: break;
-			}
-			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
-			strto += Utf8Encode(strto, c);
-		}
-
-		/* Terminate the new string and copy it back to the name array */
-		*strto = '\0';
-		memcpy(_name_array[i], tmp, sizeof(*_name_array));
-	}
-}
-
-// Calculate constants that depend on the landscape type.
-void InitializeLandscapeVariables(bool only_constants)
-{
-	const CargoTypesValues *lpd;
-	uint i;
-	StringID str;
-
-	lpd = &_cargo_types_base_values[_opt.landscape];
-
-	for (i = 0; i != NUM_CARGO; i++) {
-		_cargoc.sprites[i] = lpd->sprites[i];
-
-		str = lpd->names[i];
-		_cargoc.names_s[i] = str;
-		_cargoc.names_long[i] = (str += 0x40);
-		_cargoc.names_short[i] = (str += 0x20);
-		_cargoc.weights[i] = lpd->weights[i];
-
-		if (!only_constants) {
-			_cargo_payment_rates[i] = lpd->initial_cargo_payment[i];
-			_cargo_payment_rates_frac[i] = 0;
-		}
-
-		_cargoc.transit_days_1[i] = lpd->transit_days_table_1[i];
-		_cargoc.transit_days_2[i] = lpd->transit_days_table_2[i];
-	}
-}
-
-
-
-int FindFirstBit(uint32 value)
-{
-	// This is much faster than the one that was before here.
-	//  Created by Darkvater.. blame him if it is wrong ;)
-	// Btw, the macro FINDFIRSTBIT is better to use when your value is
-	//  not more than 128.
-	byte i = 0;
-	if (value & 0xffff0000) { value >>= 16; i += 16; }
-	if (value & 0x0000ff00) { value >>= 8;  i +=  8; }
-	if (value & 0x000000f0) { value >>= 4;  i +=  4; }
-	if (value & 0x0000000c) { value >>= 2;  i +=  2; }
-	if (value & 0x00000002) { i += 1; }
-	return i;
-}
-
-
-static void Save_NAME(void)
-{
-	int i;
-
-	for (i = 0; i != lengthof(_name_array); ++i) {
-		if (_name_array[i][0] != '\0') {
-			SlSetArrayIndex(i);
-			SlArray(_name_array[i], (uint)strlen(_name_array[i]), SLE_UINT8);
-		}
-	}
-}
-
-static void Load_NAME(void)
-{
-	int index;
-
-	while ((index = SlIterateArray()) != -1) {
-		SlArray(_name_array[index],SlGetFieldLength(),SLE_UINT8);
-	}
-}
-
-static const SaveLoadGlobVarList _date_desc[] = {
-	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
-	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
-	    SLEG_VAR(_date_fract,             SLE_UINT16),
-	    SLEG_VAR(_tick_counter,           SLE_UINT16),
-	    SLEG_VAR(_vehicle_id_ctr_day,     SLE_UINT16),
-	    SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8),
-	    SLEG_VAR(_avail_aircraft,         SLE_UINT8),
-	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLEG_VAR(_disaster_delay,         SLE_UINT16),
-	    SLEG_VAR(_station_tick_ctr,       SLE_UINT16),
-	    SLEG_VAR(_random_seeds[0][0],     SLE_UINT32),
-	    SLEG_VAR(_random_seeds[0][1],     SLE_UINT32),
-	SLEG_CONDVAR(_cur_town_ctr,           SLE_FILE_U8  | SLE_VAR_U32,  0, 9),
-	SLEG_CONDVAR(_cur_town_ctr,           SLE_UINT32,                 10, SL_MAX_VERSION),
-	    SLEG_VAR(_cur_player_tick_index,  SLE_FILE_U8  | SLE_VAR_U32),
-	    SLEG_VAR(_next_competitor_start,  SLE_FILE_U16 | SLE_VAR_U32),
-	    SLEG_VAR(_trees_tick_ctr,         SLE_UINT8),
-	SLEG_CONDVAR(_pause,                  SLE_UINT8,                   4, SL_MAX_VERSION),
-	SLEG_CONDVAR(_cur_town_iter,          SLE_UINT32,                 11, SL_MAX_VERSION),
-	    SLEG_END()
-};
-
-// Save load date related variables as well as persistent tick counters
-// XXX: currently some unrelated stuff is just put here
-static void SaveLoad_DATE(void)
-{
-	SlGlobList(_date_desc);
-}
-
-
-static const SaveLoadGlobVarList _view_desc[] = {
-	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
-	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_INT32,                  6, SL_MAX_VERSION),
-	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
-	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_INT32,                  6, SL_MAX_VERSION),
-	    SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8),
-	    SLEG_END()
-};
-
-static void SaveLoad_VIEW(void)
-{
-	SlGlobList(_view_desc);
-}
-
-static uint32 _map_dim_x;
-static uint32 _map_dim_y;
-
-static const SaveLoadGlobVarList _map_dimensions[] = {
-	SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
-	SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
-	    SLEG_END()
-};
-
-static void Save_MAPS(void)
-{
-	_map_dim_x = MapSizeX();
-	_map_dim_y = MapSizeY();
-	SlGlobList(_map_dimensions);
-}
-
-static void Load_MAPS(void)
-{
-	SlGlobList(_map_dimensions);
-	AllocateMap(_map_dim_x, _map_dim_y);
-}
-
-static void Load_MAPT(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].type_height = buf[j];
-	}
-}
-
-static void Save_MAPT(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].type_height;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-static void Load_MAP1(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].m1 = buf[j];
-	}
-}
-
-static void Save_MAP1(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m1;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-static void Load_MAP2(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		uint16 buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf),
-			/* In those versions the m2 was 8 bits */
-			CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
-		);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].m2 = buf[j];
-	}
-}
-
-static void Save_MAP2(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size * sizeof(_m[0].m2));
-	for (i = 0; i != size;) {
-		uint16 buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m2;
-		SlArray(buf, lengthof(buf), SLE_UINT16);
-	}
-}
-
-static void Load_MAP3(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].m3 = buf[j];
-	}
-}
-
-static void Save_MAP3(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m3;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-static void Load_MAP4(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].m4 = buf[j];
-	}
-}
-
-static void Save_MAP4(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m4;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-static void Load_MAP5(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) _m[i++].m5 = buf[j];
-	}
-}
-
-static void Save_MAP5(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		byte buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m5;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-static void Load_MAPE(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	if (CheckSavegameVersion(42)) {
-		for (i = 0; i != size;) {
-			uint8 buf[1024];
-			uint j;
-
-			SlArray(buf, lengthof(buf), SLE_UINT8);
-			for (j = 0; j != lengthof(buf); j++) {
-				_m[i++].extra = GB(buf[j], 0, 2);
-				_m[i++].extra = GB(buf[j], 2, 2);
-				_m[i++].extra = GB(buf[j], 4, 2);
-				_m[i++].extra = GB(buf[j], 6, 2);
-			}
-		}
-	} else {
-		for (i = 0; i != size;) {
-			byte buf[4096];
-			uint j;
-
-			SlArray(buf, lengthof(buf), SLE_UINT8);
-			for (j = 0; j != lengthof(buf); j++) _m[i++].extra = buf[j];
-		}
-	}
-}
-
-static void Save_MAPE(void)
-{
-	uint size = MapSize();
-	uint i;
-
-	SlSetLength(size);
-	for (i = 0; i != size;) {
-		uint8 buf[4096];
-		uint j;
-
-		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].extra;
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-	}
-}
-
-
-static void Save_CHTS(void)
-{
-	byte count = sizeof(_cheats)/sizeof(Cheat);
-	Cheat* cht = (Cheat*) &_cheats;
-	Cheat* cht_last = &cht[count];
-
-	SlSetLength(count * 2);
-	for (; cht != cht_last; cht++) {
-		SlWriteByte(cht->been_used);
-		SlWriteByte(cht->value);
-	}
-}
-
-static void Load_CHTS(void)
-{
-	Cheat* cht = (Cheat*)&_cheats;
-	uint count = SlGetFieldLength() / 2;
-	uint i;
-
-	for (i = 0; i < count; i++) {
-		cht[i].been_used = SlReadByte();
-		cht[i].value     = SlReadByte();
-	}
-}
-
-
-const ChunkHandler _misc_chunk_handlers[] = {
-	{ 'MAPS', Save_MAPS,     Load_MAPS,     CH_RIFF },
-	{ 'MAPT', Save_MAPT,     Load_MAPT,     CH_RIFF },
-	{ 'MAPO', Save_MAP1,     Load_MAP1,     CH_RIFF },
-	{ 'MAP2', Save_MAP2,     Load_MAP2,     CH_RIFF },
-	{ 'M3LO', Save_MAP3,     Load_MAP3,     CH_RIFF },
-	{ 'M3HI', Save_MAP4,     Load_MAP4,     CH_RIFF },
-	{ 'MAP5', Save_MAP5,     Load_MAP5,     CH_RIFF },
-	{ 'MAPE', Save_MAPE,     Load_MAPE,     CH_RIFF },
-
-	{ 'NAME', Save_NAME,     Load_NAME,     CH_ARRAY},
-	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
-	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF},
-	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
-};
new file mode 100644
--- /dev/null
+++ b/src/misc.cpp
@@ -0,0 +1,634 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "functions.h"
+#include "news.h"
+#include "player.h"
+#include "string.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "vehicle.h"
+#include "saveload.h"
+#include "engine.h"
+#include "vehicle_gui.h"
+#include "variables.h"
+#include "ai/ai.h"
+#include "table/landscape_const.h"
+#include "date.h"
+
+char _name_array[512][32];
+
+#ifndef MERSENNE_TWISTER
+
+#ifdef RANDOM_DEBUG
+#include "network/network_data.h"
+uint32 DoRandom(int line, const char *file)
+#else // RANDOM_DEBUG
+uint32 Random(void)
+#endif // RANDOM_DEBUG
+{
+
+uint32 s;
+uint32 t;
+
+#ifdef RANDOM_DEBUG
+	if (_networking && (DEREF_CLIENT(0)->status != STATUS_INACTIVE || !_network_server))
+		printf("Random [%d/%d] %s:%d\n",_frame_counter, _current_player, file, line);
+#endif
+
+	s = _random_seeds[0][0];
+	t = _random_seeds[0][1];
+	_random_seeds[0][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
+	return _random_seeds[0][1] = ROR(s, 3) - 1;
+}
+#endif // MERSENNE_TWISTER
+
+#if defined(RANDOM_DEBUG) && !defined(MERSENNE_TWISTER)
+uint DoRandomRange(uint max, int line, const char *file)
+{
+	return GB(DoRandom(line, file), 0, 16) * max >> 16;
+}
+#else
+uint RandomRange(uint max)
+{
+	return GB(Random(), 0, 16) * max >> 16;
+}
+#endif
+
+
+uint32 InteractiveRandom(void)
+{
+	uint32 t = _random_seeds[1][1];
+	uint32 s = _random_seeds[1][0];
+	_random_seeds[1][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
+	return _random_seeds[1][1] = ROR(s, 3) - 1;
+}
+
+uint InteractiveRandomRange(uint max)
+{
+	return GB(InteractiveRandom(), 0, 16) * max >> 16;
+}
+
+void InitializeVehicles(void);
+void InitializeWaypoints(void);
+void InitializeDepots(void);
+void InitializeEngines(void);
+void InitializeOrders(void);
+void InitializeClearLand(void);
+void InitializeRailGui(void);
+void InitializeRoadGui(void);
+void InitializeAirportGui(void);
+void InitializeDockGui(void);
+void InitializeIndustries(void);
+void InitializeMainGui(void);
+void InitializeLandscape(void);
+void InitializeTowns(void);
+void InitializeTrees(void);
+void InitializeSigns(void);
+void InitializeStations(void);
+static void InitializeNameMgr(void);
+void InitializePlayers(void);
+static void InitializeCheats(void);
+void InitializeNPF(void);
+
+void InitializeGame(int mode, uint size_x, uint size_y)
+{
+	AllocateMap(size_x, size_y);
+
+	AddTypeToEngines(); // make sure all engines have a type
+
+	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
+
+	_pause = 0;
+	_fast_forward = 0;
+	_tick_counter = 0;
+	_date_fract = 0;
+	_cur_tileloop_tile = 0;
+
+	if ((mode & IG_DATE_RESET) == IG_DATE_RESET) {
+		SetDate(ConvertYMDToDate(_patches.starting_year, 0, 1));
+	}
+
+	InitializeEngines();
+	InitializeVehicles();
+	InitializeWaypoints();
+	InitializeDepots();
+	InitializeOrders();
+
+	InitNewsItemStructs();
+	InitializeLandscape();
+	InitializeClearLand();
+	InitializeRailGui();
+	InitializeRoadGui();
+	InitializeAirportGui();
+	InitializeDockGui();
+	InitializeTowns();
+	InitializeTrees();
+	InitializeSigns();
+	InitializeStations();
+	InitializeIndustries();
+	InitializeMainGui();
+
+	InitializeNameMgr();
+	InitializeVehiclesGuiList();
+	InitializeTrains();
+	InitializeNPF();
+
+	AI_Initialize();
+	InitializePlayers();
+	InitializeCheats();
+
+	InitTextEffects();
+	InitTextMessage();
+	InitializeAnimatedTiles();
+
+	InitializeLandscapeVariables(false);
+
+	ResetObjectToPlace();
+}
+
+bool IsCustomName(StringID id)
+{
+	return GB(id, 11, 5) == 15;
+}
+
+void DeleteName(StringID id)
+{
+	if (IsCustomName(id)) {
+		memset(_name_array[id & 0x1FF], 0, sizeof(_name_array[id & 0x1FF]));
+	}
+}
+
+char *GetName(char *buff, StringID id, const char* last)
+{
+	return strecpy(buff, _name_array[id & ~0x600], last);
+}
+
+
+static void InitializeCheats(void)
+{
+	memset(&_cheats, 0, sizeof(Cheats));
+}
+
+
+static void InitializeNameMgr(void)
+{
+	memset(_name_array, 0, sizeof(_name_array));
+}
+
+StringID RealAllocateName(const char *name, byte skip, bool check_double)
+{
+	char (*free_item)[lengthof(*_name_array)] = NULL;
+	char (*i)[lengthof(*_name_array)];
+
+	for (i = _name_array; i != endof(_name_array); ++i) {
+		if ((*i)[0] == '\0') {
+			if (free_item == NULL) free_item = i;
+		} else if (check_double && strncmp(*i, name, lengthof(*i) - 1) == 0) {
+			_error_message = STR_0132_CHOSEN_NAME_IN_USE_ALREADY;
+			return 0;
+		}
+	}
+
+	if (free_item != NULL) {
+		ttd_strlcpy(*free_item, name, lengthof(*free_item));
+		return (free_item - _name_array) | 0x7800 | (skip << 8);
+	} else {
+		_error_message = STR_0131_TOO_MANY_NAMES_DEFINED;
+		return 0;
+	}
+}
+
+void ConvertNameArray(void)
+{
+	uint i;
+
+	for (i = 0; i < lengthof(_name_array); i++) {
+		const char *strfrom = _name_array[i];
+		char tmp[sizeof(*_name_array)];
+		char *strto = tmp;
+
+		for (; *strfrom != '\0'; strfrom++) {
+			WChar c = (byte)*strfrom;
+			switch (c) {
+				case 0xA4: c = 0x20AC; break; // Euro
+				case 0xA6: c = 0x0160; break; // S with caron
+				case 0xA8: c = 0x0161; break; // s with caron
+				case 0xB4: c = 0x017D; break; // Z with caron
+				case 0xB8: c = 0x017E; break; // z with caron
+				case 0xBC: c = 0x0152; break; // OE ligature
+				case 0xBD: c = 0x0153; break; // oe ligature
+				case 0xBE: c = 0x0178; break; // Y with diaresis
+				default: break;
+			}
+			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
+			strto += Utf8Encode(strto, c);
+		}
+
+		/* Terminate the new string and copy it back to the name array */
+		*strto = '\0';
+		memcpy(_name_array[i], tmp, sizeof(*_name_array));
+	}
+}
+
+// Calculate constants that depend on the landscape type.
+void InitializeLandscapeVariables(bool only_constants)
+{
+	const CargoTypesValues *lpd;
+	uint i;
+	StringID str;
+
+	lpd = &_cargo_types_base_values[_opt.landscape];
+
+	for (i = 0; i != NUM_CARGO; i++) {
+		_cargoc.sprites[i] = lpd->sprites[i];
+
+		str = lpd->names[i];
+		_cargoc.names_s[i] = str;
+		_cargoc.names_long[i] = (str += 0x40);
+		_cargoc.names_short[i] = (str += 0x20);
+		_cargoc.weights[i] = lpd->weights[i];
+
+		if (!only_constants) {
+			_cargo_payment_rates[i] = lpd->initial_cargo_payment[i];
+			_cargo_payment_rates_frac[i] = 0;
+		}
+
+		_cargoc.transit_days_1[i] = lpd->transit_days_table_1[i];
+		_cargoc.transit_days_2[i] = lpd->transit_days_table_2[i];
+	}
+}
+
+
+
+int FindFirstBit(uint32 value)
+{
+	// This is much faster than the one that was before here.
+	//  Created by Darkvater.. blame him if it is wrong ;)
+	// Btw, the macro FINDFIRSTBIT is better to use when your value is
+	//  not more than 128.
+	byte i = 0;
+	if (value & 0xffff0000) { value >>= 16; i += 16; }
+	if (value & 0x0000ff00) { value >>= 8;  i +=  8; }
+	if (value & 0x000000f0) { value >>= 4;  i +=  4; }
+	if (value & 0x0000000c) { value >>= 2;  i +=  2; }
+	if (value & 0x00000002) { i += 1; }
+	return i;
+}
+
+
+static void Save_NAME(void)
+{
+	int i;
+
+	for (i = 0; i != lengthof(_name_array); ++i) {
+		if (_name_array[i][0] != '\0') {
+			SlSetArrayIndex(i);
+			SlArray(_name_array[i], (uint)strlen(_name_array[i]), SLE_UINT8);
+		}
+	}
+}
+
+static void Load_NAME(void)
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		SlArray(_name_array[index],SlGetFieldLength(),SLE_UINT8);
+	}
+}
+
+static const SaveLoadGlobVarList _date_desc[] = {
+	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
+	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
+	    SLEG_VAR(_date_fract,             SLE_UINT16),
+	    SLEG_VAR(_tick_counter,           SLE_UINT16),
+	    SLEG_VAR(_vehicle_id_ctr_day,     SLE_UINT16),
+	    SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8),
+	    SLEG_VAR(_avail_aircraft,         SLE_UINT8),
+	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLEG_VAR(_disaster_delay,         SLE_UINT16),
+	    SLEG_VAR(_station_tick_ctr,       SLE_UINT16),
+	    SLEG_VAR(_random_seeds[0][0],     SLE_UINT32),
+	    SLEG_VAR(_random_seeds[0][1],     SLE_UINT32),
+	SLEG_CONDVAR(_cur_town_ctr,           SLE_FILE_U8  | SLE_VAR_U32,  0, 9),
+	SLEG_CONDVAR(_cur_town_ctr,           SLE_UINT32,                 10, SL_MAX_VERSION),
+	    SLEG_VAR(_cur_player_tick_index,  SLE_FILE_U8  | SLE_VAR_U32),
+	    SLEG_VAR(_next_competitor_start,  SLE_FILE_U16 | SLE_VAR_U32),
+	    SLEG_VAR(_trees_tick_ctr,         SLE_UINT8),
+	SLEG_CONDVAR(_pause,                  SLE_UINT8,                   4, SL_MAX_VERSION),
+	SLEG_CONDVAR(_cur_town_iter,          SLE_UINT32,                 11, SL_MAX_VERSION),
+	    SLEG_END()
+};
+
+// Save load date related variables as well as persistent tick counters
+// XXX: currently some unrelated stuff is just put here
+static void SaveLoad_DATE(void)
+{
+	SlGlobList(_date_desc);
+}
+
+
+static const SaveLoadGlobVarList _view_desc[] = {
+	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_INT32,                  6, SL_MAX_VERSION),
+	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_INT32,                  6, SL_MAX_VERSION),
+	    SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8),
+	    SLEG_END()
+};
+
+static void SaveLoad_VIEW(void)
+{
+	SlGlobList(_view_desc);
+}
+
+static uint32 _map_dim_x;
+static uint32 _map_dim_y;
+
+static const SaveLoadGlobVarList _map_dimensions[] = {
+	SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
+	SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
+	    SLEG_END()
+};
+
+static void Save_MAPS(void)
+{
+	_map_dim_x = MapSizeX();
+	_map_dim_y = MapSizeY();
+	SlGlobList(_map_dimensions);
+}
+
+static void Load_MAPS(void)
+{
+	SlGlobList(_map_dimensions);
+	AllocateMap(_map_dim_x, _map_dim_y);
+}
+
+static void Load_MAPT(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].type_height = buf[j];
+	}
+}
+
+static void Save_MAPT(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].type_height;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+static void Load_MAP1(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].m1 = buf[j];
+	}
+}
+
+static void Save_MAP1(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m1;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+static void Load_MAP2(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		uint16 buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf),
+			/* In those versions the m2 was 8 bits */
+			CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
+		);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].m2 = buf[j];
+	}
+}
+
+static void Save_MAP2(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size * sizeof(_m[0].m2));
+	for (i = 0; i != size;) {
+		uint16 buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m2;
+		SlArray(buf, lengthof(buf), SLE_UINT16);
+	}
+}
+
+static void Load_MAP3(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].m3 = buf[j];
+	}
+}
+
+static void Save_MAP3(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m3;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+static void Load_MAP4(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].m4 = buf[j];
+	}
+}
+
+static void Save_MAP4(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m4;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+static void Load_MAP5(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+		for (j = 0; j != lengthof(buf); j++) _m[i++].m5 = buf[j];
+	}
+}
+
+static void Save_MAP5(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		byte buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].m5;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+static void Load_MAPE(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	if (CheckSavegameVersion(42)) {
+		for (i = 0; i != size;) {
+			uint8 buf[1024];
+			uint j;
+
+			SlArray(buf, lengthof(buf), SLE_UINT8);
+			for (j = 0; j != lengthof(buf); j++) {
+				_m[i++].extra = GB(buf[j], 0, 2);
+				_m[i++].extra = GB(buf[j], 2, 2);
+				_m[i++].extra = GB(buf[j], 4, 2);
+				_m[i++].extra = GB(buf[j], 6, 2);
+			}
+		}
+	} else {
+		for (i = 0; i != size;) {
+			byte buf[4096];
+			uint j;
+
+			SlArray(buf, lengthof(buf), SLE_UINT8);
+			for (j = 0; j != lengthof(buf); j++) _m[i++].extra = buf[j];
+		}
+	}
+}
+
+static void Save_MAPE(void)
+{
+	uint size = MapSize();
+	uint i;
+
+	SlSetLength(size);
+	for (i = 0; i != size;) {
+		uint8 buf[4096];
+		uint j;
+
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].extra;
+		SlArray(buf, lengthof(buf), SLE_UINT8);
+	}
+}
+
+
+static void Save_CHTS(void)
+{
+	byte count = sizeof(_cheats)/sizeof(Cheat);
+	Cheat* cht = (Cheat*) &_cheats;
+	Cheat* cht_last = &cht[count];
+
+	SlSetLength(count * 2);
+	for (; cht != cht_last; cht++) {
+		SlWriteByte(cht->been_used);
+		SlWriteByte(cht->value);
+	}
+}
+
+static void Load_CHTS(void)
+{
+	Cheat* cht = (Cheat*)&_cheats;
+	uint count = SlGetFieldLength() / 2;
+	uint i;
+
+	for (i = 0; i < count; i++) {
+		cht[i].been_used = SlReadByte();
+		cht[i].value     = SlReadByte();
+	}
+}
+
+
+const ChunkHandler _misc_chunk_handlers[] = {
+	{ 'MAPS', Save_MAPS,     Load_MAPS,     CH_RIFF },
+	{ 'MAPT', Save_MAPT,     Load_MAPT,     CH_RIFF },
+	{ 'MAPO', Save_MAP1,     Load_MAP1,     CH_RIFF },
+	{ 'MAP2', Save_MAP2,     Load_MAP2,     CH_RIFF },
+	{ 'M3LO', Save_MAP3,     Load_MAP3,     CH_RIFF },
+	{ 'M3HI', Save_MAP4,     Load_MAP4,     CH_RIFF },
+	{ 'MAP5', Save_MAP5,     Load_MAP5,     CH_RIFF },
+	{ 'MAPE', Save_MAPE,     Load_MAPE,     CH_RIFF },
+
+	{ 'NAME', Save_NAME,     Load_NAME,     CH_ARRAY},
+	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
+	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF},
+	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
+};
deleted file mode 100644
--- a/src/misc_cmd.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "string.h"
-#include "table/strings.h"
-#include "command.h"
-#include "player.h"
-#include "gfx.h"
-#include "window.h"
-#include "gui.h"
-#include "economy.h"
-#include "network/network.h"
-#include "variables.h"
-#include "livery.h"
-
-/** Change the player's face.
- * @param tile unused
- * @param p1 unused
- * @param p2 face bitmasked
- */
-int32 CmdSetPlayerFace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	if (flags & DC_EXEC) {
-		GetPlayer(_current_player)->face = p2;
-		MarkWholeScreenDirty();
-	}
-	return 0;
-}
-
-/** Change the player's company-colour
- * @param tile unused
- * @param p1 bitstuffed:
- * p1 bits 0-7 scheme to set
- * p1 bits 8-9 set in use state or first/second colour
- * @param p2 new colour for vehicles, property, etc.
- */
-int32 CmdSetPlayerColor(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p, *pp;
-	byte colour;
-	LiveryScheme scheme = GB(p1, 0, 8);
-	byte state = GB(p1, 8, 2);
-
-	if (p2 >= 16) return CMD_ERROR; // max 16 colours
-	colour = p2;
-
-	if (scheme >= LS_END || state >= 3) return CMD_ERROR;
-
-	p = GetPlayer(_current_player);
-
-	/* Ensure no two companies have the same primary colour */
-	if (scheme == LS_DEFAULT && state == 0) {
-		FOR_ALL_PLAYERS(pp) {
-			if (pp->is_active && pp != p && pp->player_color == colour) return CMD_ERROR;
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		switch (state) {
-			case 0:
-				p->livery[scheme].colour1 = colour;
-
-				/* If setting the first colour of the default scheme, adjust the
-				 * original and cached player colours too. */
-				if (scheme == LS_DEFAULT) {
-					_player_colors[_current_player] = colour;
-					p->player_color = colour;
-				}
-				break;
-
-			case 1:
-				p->livery[scheme].colour2 = colour;
-				break;
-
-			case 2:
-				p->livery[scheme].in_use = colour != 0;
-
-				/* Now handle setting the default scheme's in_use flag.
-				 * This is different to the other schemes, as it signifies if any
-				 * scheme is active at all. If this flag is not set, then no
-				 * processing of vehicle types occurs at all, and only the default
-				 * colours will be used. */
-
-				/* If enabling a scheme, set the default scheme to be in use too */
-				if (colour != 0) {
-					p->livery[LS_DEFAULT].in_use = true;
-					break;
-				}
-
-				/* Else loop through all schemes to see if any are left enabled.
-				 * If not, disable the default scheme too. */
-				p->livery[LS_DEFAULT].in_use = false;
-				for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-					if (p->livery[scheme].in_use) {
-						p->livery[LS_DEFAULT].in_use = true;
-						break;
-					}
-				}
-				break;
-
-			default:
-				break;
-		}
-		MarkWholeScreenDirty();
-	}
-	return 0;
-}
-
-/** Increase the loan of your company.
- * @param tile unused
- * @param p1 unused
- * @param p2 when set, loans the maximum amount in one go (press CTRL)
- */
-int32 CmdIncreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-
-	p = GetPlayer(_current_player);
-
-	if (p->current_loan >= _economy.max_loan) {
-		SetDParam(0, _economy.max_loan);
-		return_cmd_error(STR_702B_MAXIMUM_PERMITTED_LOAN);
-	}
-
-	if (flags & DC_EXEC) {
-		/* Loan the maximum amount or not? */
-		int32 loan = (p2) ? _economy.max_loan - p->current_loan : (IsHumanPlayer(_current_player) || _patches.ainew_active) ? 10000 : 50000;
-
-		p->money64 += loan;
-		p->current_loan += loan;
-		UpdatePlayerMoney32(p);
-		InvalidatePlayerWindows(p);
-	}
-
-	return 0;
-}
-
-/** Decrease the loan of your company.
- * @param tile unused
- * @param p1 unused
- * @param p2 when set, pays back the maximum loan permitting money (press CTRL)
- */
-int32 CmdDecreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-	int32 loan;
-
-	p = GetPlayer(_current_player);
-
-	if (p->current_loan == 0) return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED);
-
-	loan = p->current_loan;
-
-	/* p2 is true while CTRL is pressed (repay all possible loan, or max money you have)
-	 * Repay any loan in chunks of 10.000 pounds */
-	if (p2) {
-		loan = min(loan, p->player_money);
-		loan = max(loan, 10000);
-		loan -= loan % 10000;
-	} else {
-		loan = min(loan, (IsHumanPlayer(_current_player) || _patches.ainew_active) ? 10000 : 50000);
-	}
-
-	if (p->player_money < loan) {
-		SetDParam(0, loan);
-		return_cmd_error(STR_702E_REQUIRED);
-	}
-
-	if (flags & DC_EXEC) {
-		p->money64 -= loan;
-		p->current_loan -= loan;
-		UpdatePlayerMoney32(p);
-		InvalidatePlayerWindows(p);
-	}
-	return 0;
-}
-
-/** Change the name of the company.
- * @param tile unused
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdChangeCompanyName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID str;
-	Player *p;
-
-	if (_cmd_text[0] == '\0') return CMD_ERROR;
-
-	str = AllocateNameUnique(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		p = GetPlayer(_current_player);
-		DeleteName(p->name_1);
-		p->name_1 = str;
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-
-	return 0;
-}
-
-/** Change the name of the president.
- * @param tile unused
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdChangePresidentName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID str;
-	Player *p;
-
-	if (_cmd_text[0] == '\0') return CMD_ERROR;
-
-	str = AllocateNameUnique(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		p = GetPlayer(_current_player);
-		DeleteName(p->president_name_1);
-		p->president_name_1 = str;
-
-		if (p->name_1 == STR_SV_UNNAMED) {
-			char buf[80];
-
-			snprintf(buf, lengthof(buf), "%s Transport", _cmd_text);
-			_cmd_text = buf;
-			DoCommand(0, 0, 0, DC_EXEC, CMD_CHANGE_COMPANY_NAME);
-		}
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-
-	return 0;
-}
-
-/** Pause/Unpause the game (server-only).
- * Increase or decrease the pause counter. If the counter is zero,
- * the game is unpaused. A counter is used instead of a boolean value
- * to have more control over the game when saving/loading, etc.
- * @param tile unused
- * @param p1 0 = decrease pause counter; 1 = increase pause counter
- * @param p2 unused
- */
-int32 CmdPause(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	if (flags & DC_EXEC) {
-		_pause += (p1 == 1) ? 1 : -1;
-		if (_pause == (byte)-1) _pause = 0;
-		InvalidateWindow(WC_STATUS_BAR, 0);
-		InvalidateWindow(WC_MAIN_TOOLBAR, 0);
-	}
-	return 0;
-}
-
-/** Change the financial flow of your company.
- * This is normally only enabled in offline mode, but if there is a debug
- * build, you can cheat (to test).
- * @param tile unused
- * @param p1 the amount of money to receive (if negative), or spend (if positive)
- * @param p2 unused
- */
-int32 CmdMoneyCheat(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-#ifndef _DEBUG
-	if (_networking) return CMD_ERROR;
-#endif
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-	return (int32)p1;
-}
-
-/** Transfer funds (money) from one player to another.
- * To prevent abuse in multiplayer games you can only send money to other
- * players if you have paid off your loan (either explicitely, or implicitely
- * given the fact that you have more money than loan).
- * @param tile unused
- * @param p1 the amount of money to transfer; max 20.000.000
- * @param p2 the player to transfer the money to
- */
-int32 CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	const Player *p = GetPlayer(_current_player);
-	int32 amount = min((int32)p1, 20000000);
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-
-	/* You can only transfer funds that is in excess of your loan */
-	if (p->money64 - p->current_loan < amount || amount <= 0) return CMD_ERROR;
-	if (!_networking || !IsValidPlayer((PlayerID)p2)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		/* Add money to player */
-		PlayerID old_cp = _current_player;
-		_current_player = p2;
-		SubtractMoneyFromPlayer(-amount);
-		_current_player = old_cp;
-	}
-
-	/* Subtract money from local-player */
-	return amount;
-}
-
-/** Change difficulty level/settings (server-only).
- * We cannot really check for valid values of p2 (too much work mostly); stored
- * in file 'settings_gui.c' _game_setting_info[]; we'll just trust the server it knows
- * what to do and does this correctly
- * @param tile unused
- * @param p1 the difficulty setting being changed. If it is -1, the difficulty level
- *           itself is changed. The new value is inside p2
- * @param p2 new value for a difficulty setting or difficulty level
- */
-int32 CmdChangeDifficultyLevel(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	if (p1 != (uint32)-1L && ((int32)p1 >= GAME_DIFFICULTY_NUM || (int32)p1 < 0)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		if (p1 != (uint32)-1L) {
-			((int*)&_opt_ptr->diff)[p1] = p2;
-			_opt_ptr->diff_level = 3; // custom difficulty level
-		} else {
-			_opt_ptr->diff_level = p2;
-		}
-
-		/* If we are a network-client, update the difficult setting (if it is open).
-		 * Use this instead of just dirtying the window because we need to load in
-		 * the new difficulty settings */
-		if (_networking && !_network_server && FindWindowById(WC_GAME_OPTIONS, 0) != NULL)
-			ShowGameDifficulty();
-	}
-	return 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/misc_cmd.cpp
@@ -0,0 +1,336 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "string.h"
+#include "table/strings.h"
+#include "command.h"
+#include "player.h"
+#include "gfx.h"
+#include "window.h"
+#include "gui.h"
+#include "economy.h"
+#include "network/network.h"
+#include "variables.h"
+#include "livery.h"
+
+/** Change the player's face.
+ * @param tile unused
+ * @param p1 unused
+ * @param p2 face bitmasked
+ */
+int32 CmdSetPlayerFace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	if (flags & DC_EXEC) {
+		GetPlayer(_current_player)->face = p2;
+		MarkWholeScreenDirty();
+	}
+	return 0;
+}
+
+/** Change the player's company-colour
+ * @param tile unused
+ * @param p1 bitstuffed:
+ * p1 bits 0-7 scheme to set
+ * p1 bits 8-9 set in use state or first/second colour
+ * @param p2 new colour for vehicles, property, etc.
+ */
+int32 CmdSetPlayerColor(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p, *pp;
+	byte colour;
+	LiveryScheme scheme = GB(p1, 0, 8);
+	byte state = GB(p1, 8, 2);
+
+	if (p2 >= 16) return CMD_ERROR; // max 16 colours
+	colour = p2;
+
+	if (scheme >= LS_END || state >= 3) return CMD_ERROR;
+
+	p = GetPlayer(_current_player);
+
+	/* Ensure no two companies have the same primary colour */
+	if (scheme == LS_DEFAULT && state == 0) {
+		FOR_ALL_PLAYERS(pp) {
+			if (pp->is_active && pp != p && pp->player_color == colour) return CMD_ERROR;
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		switch (state) {
+			case 0:
+				p->livery[scheme].colour1 = colour;
+
+				/* If setting the first colour of the default scheme, adjust the
+				 * original and cached player colours too. */
+				if (scheme == LS_DEFAULT) {
+					_player_colors[_current_player] = colour;
+					p->player_color = colour;
+				}
+				break;
+
+			case 1:
+				p->livery[scheme].colour2 = colour;
+				break;
+
+			case 2:
+				p->livery[scheme].in_use = colour != 0;
+
+				/* Now handle setting the default scheme's in_use flag.
+				 * This is different to the other schemes, as it signifies if any
+				 * scheme is active at all. If this flag is not set, then no
+				 * processing of vehicle types occurs at all, and only the default
+				 * colours will be used. */
+
+				/* If enabling a scheme, set the default scheme to be in use too */
+				if (colour != 0) {
+					p->livery[LS_DEFAULT].in_use = true;
+					break;
+				}
+
+				/* Else loop through all schemes to see if any are left enabled.
+				 * If not, disable the default scheme too. */
+				p->livery[LS_DEFAULT].in_use = false;
+				for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+					if (p->livery[scheme].in_use) {
+						p->livery[LS_DEFAULT].in_use = true;
+						break;
+					}
+				}
+				break;
+
+			default:
+				break;
+		}
+		MarkWholeScreenDirty();
+	}
+	return 0;
+}
+
+/** Increase the loan of your company.
+ * @param tile unused
+ * @param p1 unused
+ * @param p2 when set, loans the maximum amount in one go (press CTRL)
+ */
+int32 CmdIncreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+
+	p = GetPlayer(_current_player);
+
+	if (p->current_loan >= _economy.max_loan) {
+		SetDParam(0, _economy.max_loan);
+		return_cmd_error(STR_702B_MAXIMUM_PERMITTED_LOAN);
+	}
+
+	if (flags & DC_EXEC) {
+		/* Loan the maximum amount or not? */
+		int32 loan = (p2) ? _economy.max_loan - p->current_loan : (IsHumanPlayer(_current_player) || _patches.ainew_active) ? 10000 : 50000;
+
+		p->money64 += loan;
+		p->current_loan += loan;
+		UpdatePlayerMoney32(p);
+		InvalidatePlayerWindows(p);
+	}
+
+	return 0;
+}
+
+/** Decrease the loan of your company.
+ * @param tile unused
+ * @param p1 unused
+ * @param p2 when set, pays back the maximum loan permitting money (press CTRL)
+ */
+int32 CmdDecreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+	int32 loan;
+
+	p = GetPlayer(_current_player);
+
+	if (p->current_loan == 0) return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED);
+
+	loan = p->current_loan;
+
+	/* p2 is true while CTRL is pressed (repay all possible loan, or max money you have)
+	 * Repay any loan in chunks of 10.000 pounds */
+	if (p2) {
+		loan = min(loan, p->player_money);
+		loan = max(loan, 10000);
+		loan -= loan % 10000;
+	} else {
+		loan = min(loan, (IsHumanPlayer(_current_player) || _patches.ainew_active) ? 10000 : 50000);
+	}
+
+	if (p->player_money < loan) {
+		SetDParam(0, loan);
+		return_cmd_error(STR_702E_REQUIRED);
+	}
+
+	if (flags & DC_EXEC) {
+		p->money64 -= loan;
+		p->current_loan -= loan;
+		UpdatePlayerMoney32(p);
+		InvalidatePlayerWindows(p);
+	}
+	return 0;
+}
+
+/** Change the name of the company.
+ * @param tile unused
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdChangeCompanyName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID str;
+	Player *p;
+
+	if (_cmd_text[0] == '\0') return CMD_ERROR;
+
+	str = AllocateNameUnique(_cmd_text, 4);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		p = GetPlayer(_current_player);
+		DeleteName(p->name_1);
+		p->name_1 = str;
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+
+	return 0;
+}
+
+/** Change the name of the president.
+ * @param tile unused
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdChangePresidentName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID str;
+	Player *p;
+
+	if (_cmd_text[0] == '\0') return CMD_ERROR;
+
+	str = AllocateNameUnique(_cmd_text, 4);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		p = GetPlayer(_current_player);
+		DeleteName(p->president_name_1);
+		p->president_name_1 = str;
+
+		if (p->name_1 == STR_SV_UNNAMED) {
+			char buf[80];
+
+			snprintf(buf, lengthof(buf), "%s Transport", _cmd_text);
+			_cmd_text = buf;
+			DoCommand(0, 0, 0, DC_EXEC, CMD_CHANGE_COMPANY_NAME);
+		}
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+
+	return 0;
+}
+
+/** Pause/Unpause the game (server-only).
+ * Increase or decrease the pause counter. If the counter is zero,
+ * the game is unpaused. A counter is used instead of a boolean value
+ * to have more control over the game when saving/loading, etc.
+ * @param tile unused
+ * @param p1 0 = decrease pause counter; 1 = increase pause counter
+ * @param p2 unused
+ */
+int32 CmdPause(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	if (flags & DC_EXEC) {
+		_pause += (p1 == 1) ? 1 : -1;
+		if (_pause == (byte)-1) _pause = 0;
+		InvalidateWindow(WC_STATUS_BAR, 0);
+		InvalidateWindow(WC_MAIN_TOOLBAR, 0);
+	}
+	return 0;
+}
+
+/** Change the financial flow of your company.
+ * This is normally only enabled in offline mode, but if there is a debug
+ * build, you can cheat (to test).
+ * @param tile unused
+ * @param p1 the amount of money to receive (if negative), or spend (if positive)
+ * @param p2 unused
+ */
+int32 CmdMoneyCheat(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+#ifndef _DEBUG
+	if (_networking) return CMD_ERROR;
+#endif
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+	return (int32)p1;
+}
+
+/** Transfer funds (money) from one player to another.
+ * To prevent abuse in multiplayer games you can only send money to other
+ * players if you have paid off your loan (either explicitely, or implicitely
+ * given the fact that you have more money than loan).
+ * @param tile unused
+ * @param p1 the amount of money to transfer; max 20.000.000
+ * @param p2 the player to transfer the money to
+ */
+int32 CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	const Player *p = GetPlayer(_current_player);
+	int32 amount = min((int32)p1, 20000000);
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+
+	/* You can only transfer funds that is in excess of your loan */
+	if (p->money64 - p->current_loan < amount || amount <= 0) return CMD_ERROR;
+	if (!_networking || !IsValidPlayer((PlayerID)p2)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		/* Add money to player */
+		PlayerID old_cp = _current_player;
+		_current_player = p2;
+		SubtractMoneyFromPlayer(-amount);
+		_current_player = old_cp;
+	}
+
+	/* Subtract money from local-player */
+	return amount;
+}
+
+/** Change difficulty level/settings (server-only).
+ * We cannot really check for valid values of p2 (too much work mostly); stored
+ * in file 'settings_gui.c' _game_setting_info[]; we'll just trust the server it knows
+ * what to do and does this correctly
+ * @param tile unused
+ * @param p1 the difficulty setting being changed. If it is -1, the difficulty level
+ *           itself is changed. The new value is inside p2
+ * @param p2 new value for a difficulty setting or difficulty level
+ */
+int32 CmdChangeDifficultyLevel(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	if (p1 != (uint32)-1L && ((int32)p1 >= GAME_DIFFICULTY_NUM || (int32)p1 < 0)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		if (p1 != (uint32)-1L) {
+			((int*)&_opt_ptr->diff)[p1] = p2;
+			_opt_ptr->diff_level = 3; // custom difficulty level
+		} else {
+			_opt_ptr->diff_level = p2;
+		}
+
+		/* If we are a network-client, update the difficult setting (if it is open).
+		 * Use this instead of just dirtying the window because we need to load in
+		 * the new difficulty settings */
+		if (_networking && !_network_server && FindWindowById(WC_GAME_OPTIONS, 0) != NULL)
+			ShowGameDifficulty();
+	}
+	return 0;
+}
deleted file mode 100644
--- a/src/misc_gui.c
+++ /dev/null
@@ -1,1915 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "hal.h"
-#include "heightmap.h"
-#include "debug.h"
-#include "functions.h"
-#include "newgrf.h"
-#include "saveload.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "table/tree_land.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "station.h"
-#include "command.h"
-#include "player.h"
-#include "town.h"
-#include "sound.h"
-#include "network/network.h"
-#include "string.h"
-#include "variables.h"
-#include "vehicle.h"
-#include "train.h"
-#include "tgp.h"
-#include "settings.h"
-#include "date.h"
-
-#include "fios.h"
-/* Variables to display file lists */
-FiosItem *_fios_list;
-int _saveload_mode;
-
-extern void GenerateLandscape(byte mode);
-extern void SwitchMode(int new_mode);
-
-static bool _fios_path_changed;
-static bool _savegame_sort_dirty;
-
-enum {
-	LAND_INFO_LINES          =   7,
-	LAND_INFO_LINE_BUFF_SIZE = 512,
-};
-
-static char _landinfo_data[LAND_INFO_LINES][LAND_INFO_LINE_BUFF_SIZE];
-
-static void LandInfoWndProc(Window *w, WindowEvent *e)
-{
-	if (e->event == WE_PAINT) {
-		DrawWindowWidgets(w);
-
-		DoDrawStringCentered(140, 16, _landinfo_data[0], 13);
-		DoDrawStringCentered(140, 27, _landinfo_data[1], 0);
-		DoDrawStringCentered(140, 38, _landinfo_data[2], 0);
-		DoDrawStringCentered(140, 49, _landinfo_data[3], 0);
-		DoDrawStringCentered(140, 60, _landinfo_data[4], 0);
-		if (_landinfo_data[5][0] != '\0') DrawStringMultiCenter(140, 76, BindCString(_landinfo_data[5]), 276);
-		if (_landinfo_data[6][0] != '\0') DoDrawStringCentered(140, 71, _landinfo_data[6], 0);
-	}
-}
-
-static const Widget _land_info_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   279,     0,    13, STR_01A3_LAND_AREA_INFORMATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    92, 0x0,                            STR_NULL},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _land_info_desc = {
-	WDP_AUTO, WDP_AUTO, 280, 93,
-	WC_LAND_INFO,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_land_info_widgets,
-	LandInfoWndProc
-};
-
-static void Place_LandInfo(TileIndex tile)
-{
-	Player *p;
-	Window *w;
-	Town *t;
-	int64 old_money;
-	int64 costclear;
-	AcceptedCargo ac;
-	TileDesc td;
-	StringID str;
-
-	DeleteWindowById(WC_LAND_INFO, 0);
-
-	w = AllocateWindowDesc(&_land_info_desc);
-	WP(w, void_d).data = &_landinfo_data;
-
-	p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
-	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-
-	old_money = p->money64;
-	p->money64 = p->player_money = 0x7fffffff;
-	costclear = DoCommand(tile, 0, 0, 0, CMD_LANDSCAPE_CLEAR);
-	p->money64 = old_money;
-	UpdatePlayerMoney32(p);
-
-	/* Because build_date is not set yet in every TileDesc, we make sure it is empty */
-	td.build_date = 0;
-	GetAcceptedCargo(tile, ac);
-	GetTileDesc(tile, &td);
-
-	SetDParam(0, td.dparam[0]);
-	GetString(_landinfo_data[0], td.str, lastof(_landinfo_data[0]));
-
-	SetDParam(0, STR_01A6_N_A);
-	if (td.owner != OWNER_NONE && td.owner != OWNER_WATER) GetNameOfOwner(td.owner, tile);
-	GetString(_landinfo_data[1], STR_01A7_OWNER, lastof(_landinfo_data[1]));
-
-	str = STR_01A4_COST_TO_CLEAR_N_A;
-	if (!CmdFailed(costclear)) {
-		SetDParam(0, costclear);
-		str = STR_01A5_COST_TO_CLEAR;
-	}
-	GetString(_landinfo_data[2], str, lastof(_landinfo_data[2]));
-
-	snprintf(_userstring, lengthof(_userstring), "0x%.4X", tile);
-	SetDParam(0, TileX(tile));
-	SetDParam(1, TileY(tile));
-	SetDParam(2, STR_SPEC_USERSTRING);
-	GetString(_landinfo_data[3], STR_LANDINFO_COORDS, lastof(_landinfo_data[3]));
-
-	SetDParam(0, STR_01A9_NONE);
-	if (t != NULL && IsValidTown(t)) {
-		SetDParam(0, STR_TOWN);
-		SetDParam(1, t->index);
-	}
-	GetString(_landinfo_data[4], STR_01A8_LOCAL_AUTHORITY, lastof(_landinfo_data[4]));
-
-	{
-		int i;
-		char *p = GetString(_landinfo_data[5], STR_01CE_CARGO_ACCEPTED, lastof(_landinfo_data[5]));
-		bool found = false;
-
-		for (i = 0; i < NUM_CARGO; ++i) {
-			if (ac[i] > 0) {
-				/* Add a comma between each item. */
-				if (found) {
-					*p++ = ',';
-					*p++ = ' ';
-				}
-				found = true;
-
-				/* If the accepted value is less than 8, show it in 1/8:ths */
-				if (ac[i] < 8) {
-					SetDParam(0, ac[i]);
-					SetDParam(1, _cargoc.names_s[i]);
-					p = GetString(p, STR_01D1_8, lastof(_landinfo_data[5]));
-				} else {
-					p = GetString(p, _cargoc.names_s[i], lastof(_landinfo_data[5]));
-				}
-			}
-		}
-
-		if (!found) _landinfo_data[5][0] = '\0';
-	}
-
-	if (td.build_date != 0) {
-		SetDParam(0, td.build_date);
-		GetString(_landinfo_data[6], STR_BUILD_DATE, lastof(_landinfo_data[6]));
-	} else {
-		_landinfo_data[6][0] = '\0';
-	}
-
-#if defined(_DEBUG)
-#	define LANDINFOD_LEVEL 0
-#else
-#	define LANDINFOD_LEVEL 1
-#endif
-	DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile));
-	DEBUG(misc, LANDINFOD_LEVEL, "type_height  = %#x", _m[tile].type_height);
-	DEBUG(misc, LANDINFOD_LEVEL, "m1           = %#x", _m[tile].m1);
-	DEBUG(misc, LANDINFOD_LEVEL, "m2           = %#x", _m[tile].m2);
-	DEBUG(misc, LANDINFOD_LEVEL, "m3           = %#x", _m[tile].m3);
-	DEBUG(misc, LANDINFOD_LEVEL, "m4           = %#x", _m[tile].m4);
-	DEBUG(misc, LANDINFOD_LEVEL, "m5           = %#x", _m[tile].m5);
-	DEBUG(misc, LANDINFOD_LEVEL, "extra        = %#x", _m[tile].extra);
-#undef LANDINFOD_LEVEL
-}
-
-void PlaceLandBlockInfo(void)
-{
-	if (_cursor.sprite == SPR_CURSOR_QUERY) {
-		ResetObjectToPlace();
-	} else {
-		_place_proc = Place_LandInfo;
-		SetObjectToPlace(SPR_CURSOR_QUERY, 1, 1, 0);
-	}
-}
-
-static const char *credits[] = {
-	/*************************************************************************
-	 *                      maximum length of string which fits in window   -^*/
-	"Original design by Chris Sawyer",
-	"Original graphics by Simon Foster",
-	"",
-	"The OpenTTD team (in alphabetical order):",
-	"  Jean-Francois Claeys (Belugas) - In training, not yet specialized",
-	"  Bjarni Corfitzen (Bjarni) - MacOSX port, coder",
-	"  Matthijs Kooijman (blathijs) - Pathfinder-guru",
-	"  Victor Fischer (Celestar) - Programming everywhere you need him to",
-	"  Tamás Faragó (Darkvater) - Lead coder",
-	"  Loïc Guilloux (glx) - In training, not yet specialized",
-	"  Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
-	"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
-	"  Peter Nelson (peter1138) - Spiritual descendant from newgrf gods",
-	"  Remko Bijker (Rubidium) - Belugas code scrutinizer",
-	"  Christoph Mallon (Tron) - Programmer, code correctness police",
-	"  Patric Stout (TrueLight) - Coder, network guru, SVN- and website host",
-	"",
-	"Retired Developers:",
-	"  Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
-	"  Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
-	"  Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
-	"  Owen Rudge (orudge) - Forum- and masterserver host, OS/2 port (0.1 - 0.4.8)",
-	"",
-	"Special thanks go out to:",
-	"  Josef Drexler - For his great work on TTDPatch",
-	"  Marcin Grzegorczyk - For his documentation of TTD internals",
-	"  Petr Baudis (pasky) - Many patches, newgrf support",
-	"  Stefan Meißner (sign_de) - For his work on the console",
-	"  Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with (and PBS)",
-	"  Cian Duffy (MYOB) - BeOS port / manual writing",
-	"  Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
-	"  Richard Kempton (richK) - additional airports, initial TGP implementation",
-	"",
-	"  Michael Blunck - Pre-Signals and Semaphores © 2003",
-	"  George - Canal/Lock graphics © 2003-2004",
-	"  Marcin Grzegorczyk - Foundations for Tracks on Slopes",
-	"  All Translators - Who made OpenTTD a truly international game",
-	"  Bug Reporters - Without whom OpenTTD would still be full of bugs!",
-	"",
-	"",
-	"And last but not least:",
-	"  Chris Sawyer - For an amazing game!"
-};
-
-static void AboutWindowProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: /* Set up window counter and start position of scroller */
-		WP(w, scroller_d).counter = 0;
-		WP(w, scroller_d).height = w->height - 40;
-		break;
-	case WE_PAINT: {
-		uint i;
-		int y = WP(w, scroller_d).height;
-		DrawWindowWidgets(w);
-
-		// Show original copyright and revision version
-		DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, 0);
-		DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, 0);
-
-		// Show all scrolling credits
-		for (i = 0; i < lengthof(credits); i++) {
-			if (y >= 50 && y < (w->height - 40)) {
-				DoDrawString(credits[i], 10, y, 0x10);
-			}
-			y += 10;
-		}
-
-		// If the last text has scrolled start anew from the start
-		if (y < 50) WP(w, scroller_d).height = w->height - 40;
-
-		DoDrawStringCentered(210, w->height - 25, "Website: http://www.openttd.org", 16);
-		DrawStringCentered(210, w->height - 15, STR_00BA_COPYRIGHT_OPENTTD, 0);
-	}	break;
-	case WE_MOUSELOOP: /* Timer to scroll the text and adjust the new top */
-		if (WP(w, scroller_d).counter++ % 3 == 0) {
-			WP(w, scroller_d).height--;
-			SetWindowDirty(w);
-		}
-		break;
-	}
-}
-
-static const Widget _about_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   419,     0,    13, STR_015B_OPENTTD, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   419,    14,   271, 0x0,              STR_NULL},
-{      WWT_FRAME,   RESIZE_NONE,    14,     5,   414,    40,   245, STR_NULL,         STR_NULL},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _about_desc = {
-	WDP_CENTER, WDP_CENTER, 420, 272,
-	WC_GAME_OPTIONS,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_about_widgets,
-	AboutWindowProc
-};
-
-
-void ShowAboutWindow(void)
-{
-	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	AllocateWindowDesc(&_about_desc);
-}
-
-static int _tree_to_plant;
-
-static const uint32 _tree_sprites[] = {
-	0x655, 0x663, 0x678, 0x62B, 0x647, 0x639, 0x64E, 0x632, 0x67F, 0x68D, 0x69B, 0x6A9,
-	0x6AF, 0x6D2, 0x6D9, 0x6C4, 0x6CB, 0x6B6, 0x6BD, 0x6E0,
-	0x72E, 0x734, 0x74A, 0x74F, 0x76B, 0x78F, 0x788, 0x77B, 0x75F, 0x774, 0x720, 0x797,
-	0x79E, 0x7A5 | PALETTE_TO_GREEN, 0x7AC | PALETTE_TO_RED, 0x7B3, 0x7BA, 0x7C1 | PALETTE_TO_RED, 0x7C8 | PALETTE_TO_PALE_GREEN, 0x7CF | PALETTE_TO_YELLOW, 0x7D6 | PALETTE_TO_RED
-};
-
-static void BuildTreesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int x,y;
-		int i, count;
-
-		DrawWindowWidgets(w);
-
-		WP(w,tree_d).base = i = _tree_base_by_landscape[_opt.landscape];
-		WP(w,tree_d).count = count = _tree_count_by_landscape[_opt.landscape];
-
-		x = 18;
-		y = 54;
-		do {
-			DrawSprite(_tree_sprites[i], x, y);
-			x += 35;
-			if (!(++i & 3)) {
-				x -= 35 * 4;
-				y += 47;
-			}
-		} while (--count);
-	} break;
-
-	case WE_CLICK: {
-		int wid = e->we.click.widget;
-
-		switch (wid) {
-		case 0:
-			ResetObjectToPlace();
-			break;
-
-		case 3: case 4: case 5: case 6:
-		case 7: case 8: case 9: case 10:
-		case 11:case 12: case 13: case 14:
-			if (wid - 3 >= WP(w,tree_d).count) break;
-
-			if (HandlePlacePushButton(w, wid, SPR_CURSOR_TREE, 1, NULL))
-				_tree_to_plant = WP(w,tree_d).base + wid - 3;
-			break;
-
-		case 15: // tree of random type.
-			if (HandlePlacePushButton(w, 15, SPR_CURSOR_TREE, 1, NULL))
-				_tree_to_plant = -1;
-			break;
-
-		case 16: /* place trees randomly over the landscape*/
-			LowerWindowWidget(w, 16);
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-			SndPlayFx(SND_15_BEEP);
-			PlaceTreesRandomly();
-			MarkWholeScreenDirty();
-			break;
-		}
-	} break;
-
-	case WE_PLACE_OBJ:
-		VpStartPlaceSizing(e->we.place.tile, VPM_X_AND_Y_LIMITED);
-		VpSetPlaceSizingLimit(20);
-		break;
-
-	case WE_PLACE_DRAG:
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
-		return;
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			DoCommandP(e->we.place.tile, _tree_to_plant, e->we.place.starttile, NULL,
-				CMD_PLANT_TREE | CMD_AUTO | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
-		}
-		break;
-
-	case WE_TIMEOUT:
-		RaiseWindowWidget(w, 16);
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		break;
-	}
-}
-
-static const Widget _build_trees_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   170, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _build_trees_desc = {
-	497, 22, 143, 171,
-	WC_BUILD_TREES, WC_SCEN_LAND_GEN,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_trees_widgets,
-	BuildTreesWndProc
-};
-
-static const Widget _build_trees_scen_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   183, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   170,   181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _build_trees_scen_desc = {
-	WDP_AUTO, WDP_AUTO, 143, 184,
-	WC_BUILD_TREES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_trees_scen_widgets,
-	BuildTreesWndProc
-};
-
-
-void ShowBuildTreesToolbar(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-	AllocateWindowDescFront(&_build_trees_desc, 0);
-}
-
-void ShowBuildTreesScenToolbar(void)
-{
-	AllocateWindowDescFront(&_build_trees_scen_desc, 0);
-}
-
-static uint32 _errmsg_decode_params[20];
-static StringID _errmsg_message_1, _errmsg_message_2;
-static uint _errmsg_duration;
-
-
-static const Widget _errmsg_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     4,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     4,    11,   239,     0,    13, STR_00B2_MESSAGE, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     4,     0,   239,    14,    45, 0x0,              STR_NULL},
-{    WIDGETS_END},
-};
-
-static const Widget _errmsg_face_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     4,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     4,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     4,     0,   333,    14,   136, 0x0,                   STR_NULL},
-{   WIDGETS_END},
-};
-
-static void ErrmsgWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		COPY_IN_DPARAM(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
-		DrawWindowWidgets(w);
-		COPY_IN_DPARAM(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
-		if (!IsWindowOfPrototype(w, _errmsg_face_widgets)) {
-			DrawStringMultiCenter(
-				120,
-				(_errmsg_message_1 == INVALID_STRING_ID ? 25 : 15),
-				_errmsg_message_2,
-				238);
-			if (_errmsg_message_1 != INVALID_STRING_ID)
-				DrawStringMultiCenter(
-					120,
-					30,
-					_errmsg_message_1,
-					238);
-		} else {
-			const Player *p = GetPlayer(GetDParamX(_errmsg_decode_params,2));
-			DrawPlayerFace(p->face, p->player_color, 2, 16);
-
-			DrawStringMultiCenter(
-				214,
-				(_errmsg_message_1 == INVALID_STRING_ID ? 65 : 45),
-				_errmsg_message_2,
-				238);
-			if (_errmsg_message_1 != INVALID_STRING_ID)
-				DrawStringMultiCenter(
-					214,
-					90,
-					_errmsg_message_1,
-					238);
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		if (_right_button_down) DeleteWindow(w);
-		break;
-
-	case WE_4:
-		if (--_errmsg_duration == 0) DeleteWindow(w);
-		break;
-
-	case WE_DESTROY:
-		SetRedErrorSquare(0);
-		_switch_mode_errorstr = INVALID_STRING_ID;
-		break;
-
-	case WE_KEYPRESS:
-		if (e->we.keypress.keycode == WKC_SPACE) {
-			// Don't continue.
-			e->we.keypress.cont = false;
-			DeleteWindow(w);
-		}
-		break;
-	}
-}
-
-void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
-{
-	Window *w;
-	const ViewPort *vp;
-	Point pt;
-
-	DeleteWindowById(WC_ERRMSG, 0);
-
-	//assert(msg_2);
-	if (msg_2 == 0) msg_2 = STR_EMPTY;
-
-	_errmsg_message_1 = msg_1;
-	_errmsg_message_2 = msg_2;
-	COPY_OUT_DPARAM(_errmsg_decode_params, 0, lengthof(_errmsg_decode_params));
-	_errmsg_duration = _patches.errmsg_duration;
-	if (!_errmsg_duration) return;
-
-	if (_errmsg_message_1 != STR_013B_OWNED_BY || GetDParamX(_errmsg_decode_params,2) >= 8) {
-
-		if ( (x|y) != 0) {
-			pt = RemapCoords2(x, y);
-			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
-
-			// move x pos to opposite corner
-			pt.x = ((pt.x - vp->virtual_left) >> vp->zoom) + vp->left;
-			pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - 260 : 20;
-
-			// move y pos to opposite corner
-			pt.y = ((pt.y - vp->virtual_top) >> vp->zoom) + vp->top;
-			pt.y = (pt.y < (_screen.height >> 1)) ? _screen.height - 80 : 100;
-
-		} else {
-			pt.x = (_screen.width - 240) >> 1;
-			pt.y = (_screen.height - 46) >> 1;
-		}
-		w = AllocateWindow(pt.x, pt.y, 240, 46, ErrmsgWndProc, WC_ERRMSG, _errmsg_widgets);
-	} else {
-		if ( (x|y) != 0) {
-			pt = RemapCoords2(x, y);
-			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
-			pt.x = clamp(((pt.x - vp->virtual_left) >> vp->zoom) + vp->left - (334/2), 0, _screen.width - 334);
-			pt.y = clamp(((pt.y - vp->virtual_top) >> vp->zoom) + vp->top - (137/2), 22, _screen.height - 137);
-		} else {
-			pt.x = (_screen.width - 334) >> 1;
-			pt.y = (_screen.height - 137) >> 1;
-		}
-		w = AllocateWindow(pt.x, pt.y, 334, 137, ErrmsgWndProc, WC_ERRMSG, _errmsg_face_widgets);
-	}
-
-	w->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
-}
-
-
-void ShowEstimatedCostOrIncome(int32 cost, int x, int y)
-{
-	StringID msg = STR_0805_ESTIMATED_COST;
-
-	if (cost < 0) {
-		cost = -cost;
-		msg = STR_0807_ESTIMATED_INCOME;
-	}
-	SetDParam(0, cost);
-	ShowErrorMessage(INVALID_STRING_ID, msg, x, y);
-}
-
-void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost)
-{
-	StringID msg;
-	Point pt = RemapCoords(x,y,z);
-
-	msg = STR_0801_COST;
-	if (cost < 0) {
-		cost = -cost;
-		msg = STR_0803_INCOME;
-	}
-	SetDParam(0, cost);
-	AddTextEffect(msg, pt.x, pt.y, 0x250);
-}
-
-void ShowFeederIncomeAnimation(int x, int y, int z, int32 cost)
-{
-	Point pt = RemapCoords(x,y,z);
-
-	SetDParam(0, cost);
-	AddTextEffect(STR_FEEDER, pt.x, pt.y, 0x250);
-}
-
-static const Widget _tooltips_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   199,     0,    31, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-
-static void TooltipsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			uint arg;
-			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0);
-			GfxFillRect(1, 1, w->width - 2, w->height - 2, 0x44);
-
-			for (arg = 0; arg < WP(w, tooltips_d).paramcount; arg++) {
-				SetDParam(arg, WP(w, tooltips_d).params[arg]);
-			}
-			DrawStringMultiCenter((w->width >> 1), (w->height >> 1) - 5, WP(w, tooltips_d).string_id, 197);
-			break;
-		}
-
-		case WE_MOUSELOOP:
-			/* We can show tooltips while dragging tools. These are shown as long as
-			 * we are dragging the tool. Normal tooltips work with rmb */
-			if (WP(w, tooltips_d).paramcount == 0 ) {
-				if (!_right_button_down) DeleteWindow(w);
-			} else {
-				if (!_left_button_down) DeleteWindow(w);
-			}
-
-			break;
-	}
-}
-
-/** Shows a tooltip
-* @param str String to be displayed
-* @param params (optional) up to 5 pieces of additional information that may be
-* added to a tooltip; currently only supports parameters of {NUM} (integer) */
-void GuiShowTooltipsWithArgs(StringID str, uint paramcount, const uint32 params[])
-{
-	char buffer[512];
-	BoundingRect br;
-	Window *w;
-	uint i;
-	int x, y;
-
-	DeleteWindowById(WC_TOOLTIPS, 0);
-
-	/* We only show measurement tooltips with patch setting on */
-	if (str == STR_NULL || (paramcount != 0 && !_patches.measure_tooltip)) return;
-
-	for (i = 0; i != paramcount; i++) SetDParam(i, params[i]);
-	GetString(buffer, str, lastof(buffer));
-
-	br = GetStringBoundingBox(buffer);
-	br.width += 6; br.height += 4; // increase slightly to have some space around the box
-
-	/* Cut tooltip length to 200 pixels max, wrap to new line if longer */
-	if (br.width > 200) {
-		br.height += ((br.width - 4) / 176) * 10;
-		br.width = 200;
-	}
-
-	/* Correctly position the tooltip position, watch out for window and cursor size
-	 * Clamp value to below main toolbar and above statusbar. If tooltip would
-	 * go below window, flip it so it is shown above the cursor */
-	y = clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, 22, _screen.height - 12);
-	if (y + br.height > _screen.height - 12) y = _cursor.pos.y + _cursor.offs.y - br.height - 5;
-	x = clamp(_cursor.pos.x - (br.width >> 1), 0, _screen.width - br.width);
-
-	w = AllocateWindow(x, y, br.width, br.height, TooltipsWndProc, WC_TOOLTIPS, _tooltips_widgets);
-
-	WP(w, tooltips_d).string_id = str;
-	assert(sizeof(WP(w, tooltips_d).params[0]) == sizeof(params[0]));
-	memcpy(WP(w, tooltips_d).params, params, sizeof(WP(w, tooltips_d).params[0]) * paramcount);
-	WP(w, tooltips_d).paramcount = paramcount;
-
-	w->flags4 &= ~WF_WHITE_BORDER_MASK; // remove white-border from tooltip
-	w->widget[0].right = br.width;
-	w->widget[0].bottom = br.height;
-}
-
-
-static void DrawStationCoverageText(const AcceptedCargo accepts,
-	int str_x, int str_y, uint mask)
-{
-	char *b = _userstring;
-	bool first = true;
-	int i;
-
-	b = InlineString(b, STR_000D_ACCEPTS);
-
-	for (i = 0; i != NUM_CARGO; i++, mask >>= 1) {
-		if (b >= lastof(_userstring) - 5) break;
-		if (accepts[i] >= 8 && mask & 1) {
-			if (first) {
-				first = false;
-			} else {
-				/* Add a comma if this is not the first item */
-				*b++ = ',';
-				*b++ = ' ';
-			}
-			b = InlineString(b, _cargoc.names_s[i]);
-		}
-	}
-
-	/* If first is still true then no cargo is accepted */
-	if (first) b = InlineString(b, STR_00D0_NOTHING);
-
-	*b = '\0';
-	DrawStringMultiLine(str_x, str_y, STR_SPEC_USERSTRING, 144);
-}
-
-void DrawStationCoverageAreaText(int sx, int sy, uint mask, int rad) {
-	TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
-	AcceptedCargo accepts;
-	if (tile < MapSize()) {
-		GetAcceptanceAroundTiles(accepts, tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE , rad);
-		DrawStationCoverageText(accepts, sx, sy, mask);
-	}
-}
-
-void CheckRedrawStationCoverage(const Window *w)
-{
-	if (_thd.dirty & 1) {
-		_thd.dirty &= ~1;
-		SetWindowDirty(w);
-	}
-}
-
-void SetVScrollCount(Window *w, int num)
-{
-	w->vscroll.count = num;
-	num -= w->vscroll.cap;
-	if (num < 0) num = 0;
-	if (num < w->vscroll.pos) w->vscroll.pos = num;
-}
-
-void SetVScroll2Count(Window *w, int num)
-{
-	w->vscroll2.count = num;
-	num -= w->vscroll2.cap;
-	if (num < 0) num = 0;
-	if (num < w->vscroll2.pos) w->vscroll2.pos = num;
-}
-
-void SetHScrollCount(Window *w, int num)
-{
-	w->hscroll.count = num;
-	num -= w->hscroll.cap;
-	if (num < 0) num = 0;
-	if (num < w->hscroll.pos) w->hscroll.pos = num;
-}
-
-/* Delete a character at the caret position in a text buf.
- * If backspace is set, delete the character before the caret,
- * else delete the character after it. */
-static void DelChar(Textbuf *tb, bool backspace)
-{
-	WChar c;
-	uint width;
-	size_t len;
-
-	if (backspace) {
-		do {
-			tb->caretpos--;
-		} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
-	}
-
-	len = Utf8Decode(&c, tb->buf + tb->caretpos);
-	width = GetCharacterWidth(FS_NORMAL, c);
-
-	tb->width  -= width;
-	if (backspace) tb->caretxoffs -= width;
-
-	/* Move the remaining characters over the marker */
-	memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + len, tb->length - tb->caretpos - len + 1);
-	tb->length -= len;
-}
-
-/**
- * Delete a character from a textbuffer, either with 'Delete' or 'Backspace'
- * The character is delete from the position the caret is at
- * @param tb @Textbuf type to be changed
- * @param delmode Type of deletion, either @WKC_BACKSPACE or @WKC_DELETE
- * @return Return true on successfull change of Textbuf, or false otherwise
- */
-bool DeleteTextBufferChar(Textbuf *tb, int delmode)
-{
-	if (delmode == WKC_BACKSPACE && tb->caretpos != 0) {
-		DelChar(tb, true);
-		return true;
-	} else if (delmode == WKC_DELETE && tb->caretpos < tb->length) {
-		DelChar(tb, false);
-		return true;
-	}
-
-	return false;
-}
-
-/**
- * Delete every character in the textbuffer
- * @param tb @Textbuf buffer to be emptied
- */
-void DeleteTextBufferAll(Textbuf *tb)
-{
-	memset(tb->buf, 0, tb->maxlength);
-	tb->length = tb->width = 0;
-	tb->caretpos = tb->caretxoffs = 0;
-}
-
-/**
- * Insert a character to a textbuffer. If maxwidth of the Textbuf is zero,
- * we don't care about the visual-length but only about the physical
- * length of the string
- * @param tb @Textbuf type to be changed
- * @param key Character to be inserted
- * @return Return true on successfull change of Textbuf, or false otherwise
- */
-bool InsertTextBufferChar(Textbuf *tb, WChar key)
-{
-	const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
-	size_t len = Utf8CharLen(key);
-	if (tb->length < (tb->maxlength - len) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
-		memmove(tb->buf + tb->caretpos + len, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
-		Utf8Encode(tb->buf + tb->caretpos, key);
-		tb->length += len;
-		tb->width  += charwidth;
-
-		tb->caretpos   += len;
-		tb->caretxoffs += charwidth;
-		return true;
-	}
-	return false;
-}
-
-/**
- * Handle text navigation with arrow keys left/right.
- * This defines where the caret will blink and the next characer interaction will occur
- * @param tb @Textbuf type where navigation occurs
- * @param navmode Direction in which navigation occurs @WKC_LEFT, @WKC_RIGHT, @WKC_END, @WKC_HOME
- * @return Return true on successfull change of Textbuf, or false otherwise
- */
-bool MoveTextBufferPos(Textbuf *tb, int navmode)
-{
-	switch (navmode) {
-	case WKC_LEFT:
-		if (tb->caretpos != 0) {
-			WChar c;
-
-			do {
-				tb->caretpos--;
-			} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
-
-			Utf8Decode(&c, tb->buf + tb->caretpos);
-			tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
-
-			return true;
-		}
-		break;
-	case WKC_RIGHT:
-		if (tb->caretpos < tb->length) {
-			WChar c;
-
-			tb->caretpos   += Utf8Decode(&c, tb->buf + tb->caretpos);
-			tb->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
-
-			return true;
-		}
-		break;
-	case WKC_HOME:
-		tb->caretpos = 0;
-		tb->caretxoffs = 0;
-		return true;
-	case WKC_END:
-		tb->caretpos = tb->length;
-		tb->caretxoffs = tb->width;
-		return true;
-	}
-
-	return false;
-}
-
-/**
- * Initialize the textbuffer by supplying it the buffer to write into
- * and the maximum length of this buffer
- * @param tb @Textbuf type which is getting initialized
- * @param buf the buffer that will be holding the data for input
- * @param maxlength maximum length in characters of this buffer
- * @param maxwidth maximum length in pixels of this buffer. If reached, buffer
- * cannot grow, even if maxlength would allow because there is space. A length
- * of zero '0' means the buffer is only restricted by maxlength */
-void InitializeTextBuffer(Textbuf *tb, const char *buf, uint16 maxlength, uint16 maxwidth)
-{
-	tb->buf = (char*)buf;
-	tb->maxlength = maxlength;
-	tb->maxwidth  = maxwidth;
-	tb->caret = true;
-	UpdateTextBufferSize(tb);
-}
-
-/**
- * Update @Textbuf type with its actual physical character and screenlength
- * Get the count of characters in the string as well as the width in pixels.
- * Useful when copying in a larger amount of text at once
- * @param tb @Textbuf type which length is calculated
- */
-void UpdateTextBufferSize(Textbuf *tb)
-{
-	const char *buf = tb->buf;
-	WChar c = Utf8Consume(&buf);
-
-	tb->width = 0;
-	tb->length = 0;
-
-	for (; c != '\0' && tb->length < (tb->maxlength - 1); c = Utf8Consume(&buf)) {
-		tb->width += GetCharacterWidth(FS_NORMAL, c);
-		tb->length += Utf8CharLen(c);
-	}
-
-	tb->caretpos = tb->length;
-	tb->caretxoffs = tb->width;
-}
-
-int HandleEditBoxKey(Window *w, querystr_d *string, int wid, WindowEvent *e)
-{
-	e->we.keypress.cont = false;
-
-	switch (e->we.keypress.keycode) {
-	case WKC_ESC: return 2;
-	case WKC_RETURN: case WKC_NUM_ENTER: return 1;
-	case (WKC_CTRL | 'V'):
-		if (InsertTextBufferClipboard(&string->text))
-			InvalidateWidget(w, wid);
-		break;
-	case (WKC_CTRL | 'U'):
-		DeleteTextBufferAll(&string->text);
-		InvalidateWidget(w, wid);
-		break;
-	case WKC_BACKSPACE: case WKC_DELETE:
-		if (DeleteTextBufferChar(&string->text, e->we.keypress.keycode))
-			InvalidateWidget(w, wid);
-		break;
-	case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
-		if (MoveTextBufferPos(&string->text, e->we.keypress.keycode))
-			InvalidateWidget(w, wid);
-		break;
-	default:
-		if (IsValidChar(e->we.keypress.key, string->afilter)) {
-			if (InsertTextBufferChar(&string->text, e->we.keypress.key)) {
-				InvalidateWidget(w, wid);
-			}
-		} else { // key wasn't caught. Continue only if standard entry specified
-			e->we.keypress.cont = (string->afilter == CS_ALPHANUMERAL);
-		}
-	}
-
-	return 0;
-}
-
-bool HandleCaret(Textbuf *tb)
-{
-	/* caret changed? */
-	bool b = !!(_caret_timer & 0x20);
-
-	if (b != tb->caret) {
-		tb->caret = b;
-		return true;
-	}
-	return false;
-}
-
-void HandleEditBox(Window *w, querystr_d *string, int wid)
-{
-	if (HandleCaret(&string->text)) InvalidateWidget(w, wid);
-}
-
-void DrawEditBox(Window *w, querystr_d *string, int wid)
-{
-	DrawPixelInfo dpi, *old_dpi;
-	int delta;
-	const Widget *wi = &w->widget[wid];
-	const Textbuf *tb = &string->text;
-
-	/* Limit the drawing of the string inside the widget boundaries */
-	if (!FillDrawPixelInfo(&dpi,
-	      wi->left + 4,
-	      wi->top + 1,
-	      wi->right - wi->left - 4,
-	      wi->bottom - wi->top - 1)
-	) return;
-
-	GfxFillRect(wi->left + 1, wi->top + 1, wi->right - 1, wi->bottom - 1, 215);
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = &dpi;
-
-	/* We will take the current widget length as maximum width, with a small
-	 * space reserved at the end for the caret to show */
-	delta = (wi->right - wi->left) - tb->width - 10;
-	if (delta > 0) delta = 0;
-
-	if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
-
-	DoDrawString(tb->buf, delta, 0, 8);
-	if (tb->caret) DoDrawString("_", tb->caretxoffs + delta, 0, 12);
-
-	_cur_dpi = old_dpi;
-}
-
-enum QueryStringWidgets {
-	QUERY_STR_WIDGET_TEXT = 3,
-	QUERY_STR_WIDGET_CANCEL,
-	QUERY_STR_WIDGET_OK
-};
-
-
-static void QueryStringWndProc(Window *w, WindowEvent *e)
-{
-	querystr_d *qs = &WP(w, querystr_d);
-
-	switch (e->event) {
-		case WE_CREATE:
-			SETBIT(_no_scroll, SCROLL_EDIT);
-			break;
-
-		case WE_PAINT:
-			SetDParam(0, qs->caption);
-			DrawWindowWidgets(w);
-
-			DrawEditBox(w, qs, QUERY_STR_WIDGET_TEXT);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case QUERY_STR_WIDGET_OK:
-		press_ok:;
-					if (qs->orig == NULL || strcmp(qs->text.buf, qs->orig) != 0) {
-						Window *parent = w->parent;
-						qs->handled = true;
-
-						/* If the parent is NULL, the editbox is handled by general function
-						 * HandleOnEditText */
-						if (parent != NULL) {
-							WindowEvent e;
-							e.event = WE_ON_EDIT_TEXT;
-							e.we.edittext.str = qs->text.buf;
-							parent->wndproc(parent, &e);
-						} else {
-							HandleOnEditText(qs->text.buf);
-						}
-					}
-					/* Fallthrough */
-				case QUERY_STR_WIDGET_CANCEL:
-					DeleteWindow(w);
-					break;
-			}
-			break;
-
-		case WE_MOUSELOOP:
-			HandleEditBox(w, qs, QUERY_STR_WIDGET_TEXT);
-			break;
-
-		case WE_KEYPRESS:
-			switch (HandleEditBoxKey(w, qs, QUERY_STR_WIDGET_TEXT, e)) {
-				case 1: goto press_ok; /* Enter pressed, confirms change */
-				case 2: DeleteWindow(w); break; /* ESC pressed, closes window, abandons changes */
-			}
-			break;
-
-		case WE_DESTROY: /* Call cancellation of query, if we have not handled it before */
-			if (!qs->handled && w->parent != NULL) {
-				WindowEvent e;
-				Window *parent = w->parent;
-
-				qs->handled = true;
-				e.event = WE_ON_EDIT_TEXT_CANCEL;
-				parent->wndproc(parent, &e);
-			}
-			CLRBIT(_no_scroll, SCROLL_EDIT);
-			break;
-		}
-}
-
-static const Widget _query_string_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   259,     0,    13, STR_012D,        STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   259,    14,    29, 0x0,             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   257,    16,    27, 0x0,             STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,   129,    30,    41, STR_012E_CANCEL, STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   259,    30,    41, STR_012F_OK,     STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _query_string_desc = {
-	190, 219, 260, 42,
-	WC_QUERY_STRING,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_query_string_widgets,
-	QueryStringWndProc
-};
-
-static char _edit_str_buf[64];
-
-/** Show a query popup window with a textbox in it.
- * @param str StringID for the text shown in the textbox
- * @param caption StringID of text shown in caption of querywindow
- * @param maxlen maximum length in characters allowed. If bit 12 is set we
- * will not check the resulting string against to original string to return success
- * @param maxwidth maximum width in pixels allowed
- * @param parent pointer to a Window that will handle the events (ok/cancel) of this
- * window. If NULL, results are handled by global function HandleOnEditText
- * @param afilter filters out unwanted character input */
-void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter)
-{
-	static char orig_str_buf[lengthof(_edit_str_buf)];
-	Window *w;
-	uint realmaxlen = maxlen & ~0x1000;
-
-	assert(realmaxlen < lengthof(_edit_str_buf));
-
-	DeleteWindowById(WC_QUERY_STRING, 0);
-	DeleteWindowById(WC_SAVELOAD, 0);
-
-	w = AllocateWindowDesc(&_query_string_desc);
-	w->parent = parent;
-
-	GetString(_edit_str_buf, str, lastof(_edit_str_buf));
-	_edit_str_buf[realmaxlen - 1] = '\0';
-
-	if (maxlen & 0x1000) {
-		WP(w, querystr_d).orig = NULL;
-	} else {
-		strecpy(orig_str_buf, _edit_str_buf, lastof(orig_str_buf));
-		WP(w, querystr_d).orig = orig_str_buf;
-	}
-
-	LowerWindowWidget(w, QUERY_STR_WIDGET_TEXT);
-	WP(w, querystr_d).caption = caption;
-	WP(w, querystr_d).afilter = afilter;
-	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, realmaxlen, maxwidth);
-}
-
-
-enum QueryWidgets {
-	QUERY_WIDGET_CAPTION = 1,
-	QUERY_WIDGET_NO = 3,
-	QUERY_WIDGET_YES
-};
-
-
-typedef struct query_d {
-	void (*proc)(Window*, bool); ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise
-	StringID message;            ///< message shown for query window
-	uint32 params[20];           ///< local copy of _decode_parameters
-	bool calledback;             ///< has callback been executed already (internal usage for WE_DESTROY event)
-} query_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(query_d));
-
-
-static void QueryWndProc(Window *w, WindowEvent *e)
-{
-	query_d *q = &WP(w, query_d);
-
-	switch (e->event) {
-		case WE_PAINT:
-			COPY_IN_DPARAM(0, q->params, lengthof(q->params));
-			DrawWindowWidgets(w);
-			COPY_IN_DPARAM(0, q->params, lengthof(q->params));
-
-			DrawStringMultiCenter(w->width / 2, (w->height / 2) - 10, q->message, w->width);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case QUERY_WIDGET_YES:
-					q->calledback = true;
-					if (q->proc != NULL) q->proc(w->parent, true);
-					/* Fallthrough */
-				case QUERY_WIDGET_NO:
-					DeleteWindow(w);
-					break;
-				}
-			break;
-
-		case WE_KEYPRESS: /* ESC closes the window, Enter confirms the action */
-			switch (e->we.keypress.keycode) {
-				case WKC_RETURN:
-				case WKC_NUM_ENTER:
-					q->calledback = true;
-					if (q->proc != NULL) q->proc(w->parent, true);
-					/* Fallthrough */
-				case WKC_ESC:
-					e->we.keypress.cont = false;
-					DeleteWindow(w);
-					break;
-			}
-			break;
-
-		case WE_DESTROY: /* Call callback function (if any) on window close if not yet called */
-			if (!q->calledback && q->proc != NULL) {
-				q->calledback = true;
-				q->proc(w->parent, false);
-			}
-			break;
-	}
-}
-
-
-static const Widget _query_widgets[] = {
-{  WWT_CLOSEBOX, RESIZE_NONE,  4,   0,  10,   0,  13, STR_00C5,        STR_018B_CLOSE_WINDOW},
-{   WWT_CAPTION, RESIZE_NONE,  4,  11, 209,   0,  13, STR_NULL,        STR_NULL},
-{     WWT_PANEL, RESIZE_NONE,  4,   0, 209,  14,  81, 0x0, /*OVERRIDE*/STR_NULL},
-{WWT_PUSHTXTBTN, RESIZE_NONE,  3,  20,  90,  62,  73, STR_00C9_NO,     STR_NULL},
-{WWT_PUSHTXTBTN, RESIZE_NONE,  3, 120, 190,  62,  73, STR_00C8_YES,    STR_NULL},
-{   WIDGETS_END },
-};
-
-static const WindowDesc _query_desc = {
-	WDP_CENTER, WDP_CENTER, 210, 82,
-	WC_CONFIRM_POPUP_QUERY, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_DEF_WIDGET | WDF_MODAL,
-	_query_widgets,
-	QueryWndProc
-};
-
-/** Show a modal confirmation window with standard 'yes' and 'no' buttons
- * The window is aligned to the centre of its parent.
- * NOTE: You cannot use BindCString as parameter for this window!
- * @param caption string shown as window caption
- * @param message string that will be shown for the window
- * @param parent pointer to parent window, if this pointer is NULL the parent becomes
- * the main window WC_MAIN_WINDOW
- * @param x,y coordinates to show the window at
- * @param yes_no_callback callback function called when window is closed through any button */
-void ShowQuery(StringID caption, StringID message, Window *parent, void (*callback)(Window*, bool))
-{
-	Window *w = AllocateWindowDesc(&_query_desc);
-	if (w == NULL) return;
-
-	if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0);
-	w->parent = parent;
-	w->left = parent->left + (parent->width / 2) - (w->width / 2);
-	w->top = parent->top + (parent->height / 2) - (w->height / 2);
-
-	/* Create a backup of the variadic arguments to strings because it will be
-	 * overridden pretty often. We will copy these back for drawing */
-	COPY_OUT_DPARAM(WP(w, query_d).params, 0, lengthof(WP(w, query_d).params));
-	w->widget[QUERY_WIDGET_CAPTION].data = caption;
-	WP(w, query_d).message    = message;
-	WP(w, query_d).proc       = callback;
-	WP(w, query_d).calledback = false;
-}
-
-
-static const Widget _load_dialog_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   256,     0,    13, STR_NULL,         STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   127,    14,    25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   128,   256,    14,    25, STR_SORT_BY_DATE, STR_SORT_ORDER_TIP},
-{      WWT_PANEL,  RESIZE_RIGHT,    14,     0,   256,    26,    47, 0x0,              STR_NULL},
-{      WWT_PANEL,     RESIZE_RB,    14,     0,   256,    48,   293, 0x0,              STR_NULL},
-{ WWT_PUSHIMGBTN,     RESIZE_LR,    14,   245,   256,    48,    59, SPR_HOUSE_ICON,   STR_SAVELOAD_HOME_BUTTON},
-{      WWT_INSET,     RESIZE_RB,    14,     2,   243,    50,   291, 0x0,              STR_400A_LIST_OF_DRIVES_DIRECTORIES},
-{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   245,   256,    60,   281, 0x0,              STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   245,   256,   282,   293, 0x0,              STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const Widget _save_dialog_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   256,     0,    13, STR_NULL,         STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   127,    14,    25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   128,   256,    14,    25, STR_SORT_BY_DATE, STR_SORT_ORDER_TIP},
-{      WWT_PANEL,  RESIZE_RIGHT,    14,     0,   256,    26,    47, 0x0,              STR_NULL},
-{      WWT_PANEL,     RESIZE_RB,    14,     0,   256,    48,   291, 0x0,              STR_NULL},
-{ WWT_PUSHIMGBTN,     RESIZE_LR,    14,   245,   256,    48,    59, SPR_HOUSE_ICON,   STR_SAVELOAD_HOME_BUTTON},
-{      WWT_INSET,     RESIZE_RB,    14,     2,   243,    50,   290, 0x0,              STR_400A_LIST_OF_DRIVES_DIRECTORIES},
-{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   245,   256,    60,   291, 0x0,              STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,    RESIZE_RTB,    14,     0,   256,   292,   307, 0x0,              STR_NULL},
-{      WWT_PANEL,    RESIZE_RTB,    14,     2,   254,   294,   305, 0x0,              STR_400B_CURRENTLY_SELECTED_NAME},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   127,   308,   319, STR_4003_DELETE,  STR_400C_DELETE_THE_CURRENTLY_SELECTED},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   128,   244,   308,   319, STR_4002_SAVE,    STR_400D_SAVE_THE_CURRENT_GAME_USING},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   245,   256,   308,   319, 0x0,              STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-// Colors for fios types
-const byte _fios_colors[] = {13, 9, 9, 6, 5, 6, 5, 6, 6, 8};
-
-void BuildFileList(void)
-{
-	_fios_path_changed = true;
-	FiosFreeSavegameList();
-
-	switch (_saveload_mode) {
-		case SLD_NEW_GAME:
-		case SLD_LOAD_SCENARIO:
-		case SLD_SAVE_SCENARIO:
-			_fios_list = FiosGetScenarioList(_saveload_mode); break;
-		case SLD_LOAD_HEIGHTMAP:
-			_fios_list = FiosGetHeightmapList(_saveload_mode); break;
-
-		default: _fios_list = FiosGetSavegameList(_saveload_mode); break;
-	}
-}
-
-static void DrawFiosTexts(uint maxw)
-{
-	static const char *path = NULL;
-	static StringID str = STR_4006_UNABLE_TO_READ_DRIVE;
-	static uint32 tot = 0;
-
-	if (_fios_path_changed) {
-		str = FiosGetDescText(&path, &tot);
-		_fios_path_changed = false;
-	}
-
-	if (str != STR_4006_UNABLE_TO_READ_DRIVE) SetDParam(0, tot);
-	DrawString(2, 37, str, 0);
-	DoDrawStringTruncated(path, 2, 27, 16, maxw);
-}
-
-static void MakeSortedSaveGameList(void)
-{
-	uint sort_start = 0;
-	uint sort_end = 0;
-	uint s_amount;
-	int i;
-
-	/* Directories are always above the files (FIOS_TYPE_DIR)
-	 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
-	 * Only sort savegames/scenarios, not directories
-	 */
-	for (i = 0; i < _fios_num; i++) {
-		switch (_fios_list[i].type) {
-			case FIOS_TYPE_DIR:    sort_start++; break;
-			case FIOS_TYPE_PARENT: sort_start++; break;
-			case FIOS_TYPE_DRIVE:  sort_end++;   break;
-		}
-	}
-
-	s_amount = _fios_num - sort_start - sort_end;
-	if (s_amount > 0)
-		qsort(_fios_list + sort_start, s_amount, sizeof(FiosItem), compare_FiosItems);
-}
-
-static void GenerateFileName(void)
-{
-	/* Check if we are not a specatator who wants to generate a name..
-	    Let's use the name of player #0 for now. */
-	const Player *p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
-
-	SetDParam(0, p->name_1);
-	SetDParam(1, p->name_2);
-	SetDParam(2, _date);
-	GetString(_edit_str_buf, STR_4004, lastof(_edit_str_buf));
-}
-
-extern void StartupEngines(void);
-
-static void SaveLoadDlgWndProc(Window *w, WindowEvent *e)
-{
-	static FiosItem o_dir;
-
-	switch (e->event) {
-	case WE_CREATE: { /* Set up OPENTTD button */
-		o_dir.type = FIOS_TYPE_DIRECT;
-		switch (_saveload_mode) {
-			case SLD_SAVE_GAME:
-			case SLD_LOAD_GAME:
-				ttd_strlcpy(&o_dir.name[0], _paths.save_dir, sizeof(o_dir.name));
-				break;
-
-			case SLD_SAVE_SCENARIO:
-			case SLD_LOAD_SCENARIO:
-				ttd_strlcpy(&o_dir.name[0], _paths.scenario_dir, sizeof(o_dir.name));
-				break;
-
-			case SLD_LOAD_HEIGHTMAP:
-				ttd_strlcpy(&o_dir.name[0], _paths.heightmap_dir, sizeof(o_dir.name));
-				break;
-
-			default:
-				ttd_strlcpy(&o_dir.name[0], _paths.personal_dir, sizeof(o_dir.name));
-		}
-		break;
-		}
-
-	case WE_PAINT: {
-		int pos;
-		int y;
-
-		SetVScrollCount(w, _fios_num);
-		DrawWindowWidgets(w);
-		DrawFiosTexts(w->width);
-
-		if (_savegame_sort_dirty) {
-			_savegame_sort_dirty = false;
-			MakeSortedSaveGameList();
-		}
-
-		GfxFillRect(w->widget[7].left + 1, w->widget[7].top + 1, w->widget[7].right, w->widget[7].bottom, 0xD7);
-		DoDrawString(
-			_savegame_sort_order & SORT_DESCENDING ? DOWNARROW : UPARROW,
-			_savegame_sort_order & SORT_BY_NAME ? w->widget[2].right - 9 : w->widget[3].right - 9,
-			15, 16
-		);
-
-		y = w->widget[7].top + 1;
-		for (pos = w->vscroll.pos; pos < _fios_num; pos++) {
-			const FiosItem *item = _fios_list + pos;
-
-			DoDrawStringTruncated(item->title, 4, y, _fios_colors[item->type], w->width - 18);
-			y += 10;
-			if (y >= w->vscroll.cap * 10 + w->widget[7].top + 1) break;
-		}
-
-		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
-			DrawEditBox(w, &WP(w,querystr_d), 10);
-		}
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: /* Sort save names by name */
-			_savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ?
-				SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME;
-			_savegame_sort_dirty = true;
-			SetWindowDirty(w);
-			break;
-
-		case 3: /* Sort save names by date */
-			_savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ?
-				SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE;
-			_savegame_sort_dirty = true;
-			SetWindowDirty(w);
-			break;
-
-		case 6: /* OpenTTD 'button', jumps to OpenTTD directory */
-			FiosBrowseTo(&o_dir);
-			SetWindowDirty(w);
-			BuildFileList();
-			break;
-
-		case 7: { /* Click the listbox */
-			int y = (e->we.click.pt.y - w->widget[e->we.click.widget].top - 1) / 10;
-			char *name;
-			const FiosItem *file;
-
-			if (y < 0 || (y += w->vscroll.pos) >= w->vscroll.count) return;
-
-			file = _fios_list + y;
-
-			name = FiosBrowseTo(file);
-			if (name != NULL) {
-				if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
-					_switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD;
-
-					SetFiosType(file->type);
-					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
-					ttd_strlcpy(_file_to_saveload.title, file->title, sizeof(_file_to_saveload.title));
-
-					DeleteWindow(w);
-				} else if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
-					SetFiosType(file->type);
-					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
-					ttd_strlcpy(_file_to_saveload.title, file->title, sizeof(_file_to_saveload.title));
-
-					DeleteWindow(w);
-					ShowHeightmapLoad();
-				} else {
-					// SLD_SAVE_GAME, SLD_SAVE_SCENARIO copy clicked name to editbox
-					ttd_strlcpy(WP(w, querystr_d).text.buf, file->title, WP(w, querystr_d).text.maxlength);
-					UpdateTextBufferSize(&WP(w, querystr_d).text);
-					InvalidateWidget(w, 10);
-				}
-			} else {
-				// Changed directory, need repaint.
-				SetWindowDirty(w);
-				BuildFileList();
-			}
-			break;
-		}
-
-		case 11: case 12: /* Delete, Save game */
-			break;
-		}
-		break;
-	case WE_MOUSELOOP:
-		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
-			HandleEditBox(w, &WP(w, querystr_d), 10);
-		}
-		break;
-	case WE_KEYPRESS:
-		if (e->we.keypress.keycode == WKC_ESC) {
-			DeleteWindow(w);
-			return;
-		}
-
-		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
-			if (HandleEditBoxKey(w, &WP(w, querystr_d), 10, e) == 1) /* Press Enter */
-					HandleButtonClick(w, 12);
-		}
-		break;
-	case WE_TIMEOUT:
-		/* This test protects against using widgets 11 and 12 which are only available
-		 * in those two saveload mode  */
-		if (!(_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO)) break;
-
-		if (IsWindowWidgetLowered(w, 11)) { /* Delete button clicked */
-			if (!FiosDelete(WP(w,querystr_d).text.buf)) {
-				ShowErrorMessage(INVALID_STRING_ID, STR_4008_UNABLE_TO_DELETE_FILE, 0, 0);
-			} else {
-				BuildFileList();
-				/* Reset file name to current date on successfull delete */
-				if (_saveload_mode == SLD_SAVE_GAME) GenerateFileName();
-			}
-
-			UpdateTextBufferSize(&WP(w, querystr_d).text);
-			SetWindowDirty(w);
-		} else if (IsWindowWidgetLowered(w, 12)) { /* Save button clicked */
-			_switch_mode = SM_SAVE;
-			FiosMakeSavegameName(_file_to_saveload.name, WP(w,querystr_d).text.buf, sizeof(_file_to_saveload.name));
-
-			/* In the editor set up the vehicle engines correctly (date might have changed) */
-			if (_game_mode == GM_EDITOR) StartupEngines();
-		}
-		break;
-	case WE_DESTROY:
-		// pause is only used in single-player, non-editor mode, non menu mode
-		if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
-			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
-		}
-		FiosFreeSavegameList();
-		CLRBIT(_no_scroll, SCROLL_SAVE);
-		break;
-	case WE_RESIZE: {
-		/* Widget 2 and 3 have to go with halve speed, make it so obiwan */
-		uint diff = e->we.sizing.diff.x / 2;
-		w->widget[2].right += diff;
-		w->widget[3].left  += diff;
-		w->widget[3].right += e->we.sizing.diff.x;
-
-		/* Same for widget 11 and 12 in save-dialog */
-		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
-			w->widget[11].right += diff;
-			w->widget[12].left  += diff;
-			w->widget[12].right += e->we.sizing.diff.x;
-		}
-
-		w->vscroll.cap += e->we.sizing.diff.y / 10;
-		} break;
-	}
-}
-
-static const WindowDesc _load_dialog_desc = {
-	WDP_CENTER, WDP_CENTER, 257, 294,
-	WC_SAVELOAD,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_load_dialog_widgets,
-	SaveLoadDlgWndProc,
-};
-
-static const WindowDesc _save_dialog_desc = {
-	WDP_CENTER, WDP_CENTER, 257, 320,
-	WC_SAVELOAD,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_save_dialog_widgets,
-	SaveLoadDlgWndProc,
-};
-
-void ShowSaveLoadDialog(int mode)
-{
-	static const StringID saveload_captions[] = {
-		STR_4001_LOAD_GAME,
-		STR_0298_LOAD_SCENARIO,
-		STR_4000_SAVE_GAME,
-		STR_0299_SAVE_SCENARIO,
-		STR_4011_LOAD_HEIGHTMAP,
-	};
-
-	Window *w;
-	const WindowDesc *sld = &_save_dialog_desc;
-
-
-	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
-	DeleteWindowById(WC_QUERY_STRING, 0);
-	DeleteWindowById(WC_SAVELOAD, 0);
-
-	_saveload_mode = mode;
-	SETBIT(_no_scroll, SCROLL_SAVE);
-
-	switch (mode) {
-		case SLD_SAVE_GAME:     GenerateFileName(); break;
-		case SLD_SAVE_SCENARIO: strcpy(_edit_str_buf, "UNNAMED"); break;
-		default:                sld = &_load_dialog_desc; break;
-	}
-
-	assert((uint)mode < lengthof(saveload_captions));
-	w = AllocateWindowDesc(sld);
-	w->widget[1].data = saveload_captions[mode];
-	w->vscroll.cap = 24;
-	w->resize.step_width = 2;
-	w->resize.step_height = 10;
-	w->resize.height = w->height - 14 * 10; // Minimum of 10 items
-	LowerWindowWidget(w, 7);
-
-	WP(w, querystr_d).afilter = CS_ALPHANUMERAL;
-	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 240);
-
-	// pause is only used in single-player, non-editor mode, non-menu mode. It
-	// will be unpaused in the WE_DESTROY event handler.
-	if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) {
-		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-	}
-
-	BuildFileList();
-
-	ResetObjectToPlace();
-}
-
-void RedrawAutosave(void)
-{
-	SetWindowDirty(FindWindowById(WC_STATUS_BAR, 0));
-}
-
-void SetFiosType(const byte fiostype)
-{
-	switch (fiostype) {
-		case FIOS_TYPE_FILE:
-		case FIOS_TYPE_SCENARIO:
-			_file_to_saveload.mode = SL_LOAD;
-			break;
-
-		case FIOS_TYPE_OLDFILE:
-		case FIOS_TYPE_OLD_SCENARIO:
-			_file_to_saveload.mode = SL_OLD_LOAD;
-			break;
-
-#ifdef WITH_PNG
-		case FIOS_TYPE_PNG:
-			_file_to_saveload.mode = SL_PNG;
-			break;
-#endif /* WITH_PNG */
-
-		case FIOS_TYPE_BMP:
-			_file_to_saveload.mode = SL_BMP;
-			break;
-
-		default:
-			_file_to_saveload.mode = SL_INVALID;
-			break;
-	}
-}
-
-static int32 ClickMoneyCheat(int32 p1, int32 p2)
-{
-		DoCommandP(0, -10000000, 0, NULL, CMD_MONEY_CHEAT);
-		return true;
-}
-
-// p1 player to set to, p2 is -1 or +1 (down/up)
-static int32 ClickChangePlayerCheat(int32 p1, int32 p2)
-{
-	while (IsValidPlayer((PlayerID)p1)) {
-		if (_players[p1].is_active) {
-			SetLocalPlayer((PlayerID)p1);
-
-			MarkWholeScreenDirty();
-			return _local_player;
-		}
-		p1 += p2;
-	}
-
-	return _local_player;
-}
-
-// p1 -1 or +1 (down/up)
-static int32 ClickChangeClimateCheat(int32 p1, int32 p2)
-{
-	if (p1 == -1) p1 = 3;
-	if (p1 ==  4) p1 = 0;
-	_opt.landscape = p1;
-	ReloadNewGRFData();
-	return _opt.landscape;
-}
-
-extern void EnginesMonthlyLoop(void);
-
-// p2 1 (increase) or -1 (decrease)
-static int32 ClickChangeDateCheat(int32 p1, int32 p2)
-{
-	YearMonthDay ymd;
-	ConvertDateToYMD(_date, &ymd);
-
-	if ((ymd.year == MIN_YEAR && p2 == -1) || (ymd.year == MAX_YEAR && p2 == 1)) return _cur_year;
-
-	SetDate(ConvertYMDToDate(_cur_year + p2, ymd.month, ymd.day));
-	EnginesMonthlyLoop();
-	SetWindowDirty(FindWindowById(WC_STATUS_BAR, 0));
-	return _cur_year;
-}
-
-typedef int32 CheckButtonClick(int32, int32);
-
-enum ce_flags {CE_CLICK = 1 << 0};
-
-typedef byte ce_flags;
-
-typedef struct CheatEntry {
-	VarType type;          // type of selector
-	ce_flags flags;        // selector flags
-	StringID str;          // string with descriptive text
-	void *variable;        // pointer to the variable
-	bool *been_used;       // has this cheat been used before?
-	CheckButtonClick *proc;// procedure
-	int16 min, max;        // range for spinbox setting
-} CheatEntry;
-
-static const CheatEntry _cheats_ui[] = {
-	{SLE_BOOL,CE_CLICK, STR_CHEAT_MONEY,          &_cheats.money.value,           &_cheats.money.been_used,           &ClickMoneyCheat,         0,  0},
-	{SLE_UINT8,      0, STR_CHEAT_CHANGE_PLAYER,  &_local_player,                 &_cheats.switch_player.been_used,   &ClickChangePlayerCheat,  0, 11},
-	{SLE_BOOL,       0, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, NULL,                     0,  0},
-	{SLE_BOOL,       0, STR_CHEAT_CROSSINGTUNNELS,&_cheats.crossing_tunnels.value,&_cheats.crossing_tunnels.been_used,NULL,                     0,  0},
-	{SLE_BOOL,       0, STR_CHEAT_BUILD_IN_PAUSE, &_cheats.build_in_pause.value,  &_cheats.build_in_pause.been_used,  NULL,                     0,  0},
-	{SLE_BOOL,       0, STR_CHEAT_NO_JETCRASH,    &_cheats.no_jetcrash.value,     &_cheats.no_jetcrash.been_used,     NULL,                     0,  0},
-	{SLE_BOOL,       0, STR_CHEAT_SETUP_PROD,     &_cheats.setup_prod.value,      &_cheats.setup_prod.been_used,      NULL,                     0,  0},
-	{SLE_UINT8,      0, STR_CHEAT_SWITCH_CLIMATE, &_opt.landscape,                &_cheats.switch_climate.been_used,  &ClickChangeClimateCheat,-1,  4},
-	{SLE_INT32,      0, STR_CHEAT_CHANGE_DATE,    &_cur_year,                     &_cheats.change_date.been_used,     &ClickChangeDateCheat,   -1,  1},
-};
-
-
-static const Widget _cheat_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,   STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   399,     0,    13, STR_CHEATS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   399,    14,   169, 0x0,        STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   399,    14,   169, 0x0,        STR_CHEATS_TIP},
-{   WIDGETS_END},
-};
-
-extern void DrawPlayerIcon(PlayerID pid, int x, int y);
-
-static void CheatsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int clk = WP(w,def_d).data_1;
-		int x, y;
-		int i;
-
-		DrawWindowWidgets(w);
-
-		DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, 350);
-
-		x = 0;
-		y = 45;
-
-		for (i = 0; i != lengthof(_cheats_ui); i++) {
-			const CheatEntry *ce = &_cheats_ui[i];
-
-			DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, x + 5, y + 2);
-
-			switch (ce->type) {
-			case SLE_BOOL: {
-				bool on = (*(bool*)ce->variable);
-
-				if (ce->flags & CE_CLICK) {
-					DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, 0, (clk - (i * 2) == 1) ? FR_LOWERED : 0);
-					if (i == 0) { // XXX - hack/hack for first element which is increase money. Told ya it's a mess
-						SetDParam64(0, 10000000);
-					} else {
-						SetDParam(0, false);
-					}
-				} else {
-					DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : 0);
-					SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
-				}
-			} break;
-			default: {
-				int32 val = (int32)ReadValue(ce->variable, ce->type);
-				char buf[512];
-
-				/* Draw [<][>] boxes for settings of an integer-type */
-				DrawArrowButtons(x + 20, y, 3, clk - (i * 2), true, true);
-
-				switch (ce->str) {
-				/* Display date for change date cheat */
-				case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
-				/* Draw colored flag for change player cheat */
-				case STR_CHEAT_CHANGE_PLAYER:
-					SetDParam(0, val);
-					GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
-					DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
-					break;
-				/* Set correct string for switch climate cheat */
-				case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
-				/* Fallthrough */
-				default: SetDParam(0, val);
-				}
-			} break;
-			}
-
-			DrawString(50, y + 1, ce->str, 0);
-
-			y += 12;
-		}
-		break;
-	}
-
-	case WE_CLICK: {
-			const CheatEntry *ce;
-			uint btn = (e->we.click.pt.y - 46) / 12;
-			int32 value, oldvalue;
-			uint x = e->we.click.pt.x;
-
-			// not clicking a button?
-			if (!IS_INT_INSIDE(x, 20, 40) || btn >= lengthof(_cheats_ui)) break;
-
-			ce = &_cheats_ui[btn];
-			oldvalue = value = (int32)ReadValue(ce->variable, ce->type);
-
-			*ce->been_used = true;
-
-			switch (ce->type) {
-			case SLE_BOOL:
-				if (ce->flags & CE_CLICK) WP(w,def_d).data_1 = btn * 2 + 1;
-				value ^= 1;
-				if (ce->proc != NULL) ce->proc(value, 0);
-				break;
-			default: {
-				/* Add a dynamic step-size to the scroller. In a maximum of
-				 * 50-steps you should be able to get from min to max */
-				uint16 step = ((ce->max - ce->min) / 20);
-				if (step == 0) step = 1;
-
-				/* Increase or decrease the value and clamp it to extremes */
-				value += (x >= 30) ? step : -step;
-				clamp(value, ce->min, ce->max);
-
-				// take whatever the function returns
-				value = ce->proc(value, (x >= 30) ? 1 : -1);
-
-				if (value != oldvalue) {
-					WP(w,def_d).data_1 = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
-				}
-			} break;
-			}
-
-			if (value != oldvalue) {
-				WriteValue(ce->variable, ce->type, (int64)value);
-				SetWindowDirty(w);
-			}
-
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-
-			SetWindowDirty(w);
-		}
-		break;
-	case WE_TIMEOUT:
-		WP(w,def_d).data_1 = 0;
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const WindowDesc _cheats_desc = {
-	240, 22, 400, 170,
-	WC_CHEATS,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_cheat_widgets,
-	CheatsWndProc
-};
-
-
-void ShowCheatWindow(void)
-{
-	DeleteWindowById(WC_CHEATS, 0);
-	AllocateWindowDesc(&_cheats_desc);
-}
new file mode 100644
--- /dev/null
+++ b/src/misc_gui.cpp
@@ -0,0 +1,1915 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "hal.h"
+#include "heightmap.h"
+#include "debug.h"
+#include "functions.h"
+#include "newgrf.h"
+#include "saveload.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "table/tree_land.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "station.h"
+#include "command.h"
+#include "player.h"
+#include "town.h"
+#include "sound.h"
+#include "network/network.h"
+#include "string.h"
+#include "variables.h"
+#include "vehicle.h"
+#include "train.h"
+#include "tgp.h"
+#include "settings.h"
+#include "date.h"
+
+#include "fios.h"
+/* Variables to display file lists */
+FiosItem *_fios_list;
+int _saveload_mode;
+
+extern void GenerateLandscape(byte mode);
+extern void SwitchMode(int new_mode);
+
+static bool _fios_path_changed;
+static bool _savegame_sort_dirty;
+
+enum {
+	LAND_INFO_LINES          =   7,
+	LAND_INFO_LINE_BUFF_SIZE = 512,
+};
+
+static char _landinfo_data[LAND_INFO_LINES][LAND_INFO_LINE_BUFF_SIZE];
+
+static void LandInfoWndProc(Window *w, WindowEvent *e)
+{
+	if (e->event == WE_PAINT) {
+		DrawWindowWidgets(w);
+
+		DoDrawStringCentered(140, 16, _landinfo_data[0], 13);
+		DoDrawStringCentered(140, 27, _landinfo_data[1], 0);
+		DoDrawStringCentered(140, 38, _landinfo_data[2], 0);
+		DoDrawStringCentered(140, 49, _landinfo_data[3], 0);
+		DoDrawStringCentered(140, 60, _landinfo_data[4], 0);
+		if (_landinfo_data[5][0] != '\0') DrawStringMultiCenter(140, 76, BindCString(_landinfo_data[5]), 276);
+		if (_landinfo_data[6][0] != '\0') DoDrawStringCentered(140, 71, _landinfo_data[6], 0);
+	}
+}
+
+static const Widget _land_info_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   279,     0,    13, STR_01A3_LAND_AREA_INFORMATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    92, 0x0,                            STR_NULL},
+{    WIDGETS_END},
+};
+
+static const WindowDesc _land_info_desc = {
+	WDP_AUTO, WDP_AUTO, 280, 93,
+	WC_LAND_INFO,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_land_info_widgets,
+	LandInfoWndProc
+};
+
+static void Place_LandInfo(TileIndex tile)
+{
+	Player *p;
+	Window *w;
+	Town *t;
+	int64 old_money;
+	int64 costclear;
+	AcceptedCargo ac;
+	TileDesc td;
+	StringID str;
+
+	DeleteWindowById(WC_LAND_INFO, 0);
+
+	w = AllocateWindowDesc(&_land_info_desc);
+	WP(w, void_d).data = &_landinfo_data;
+
+	p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
+	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
+
+	old_money = p->money64;
+	p->money64 = p->player_money = 0x7fffffff;
+	costclear = DoCommand(tile, 0, 0, 0, CMD_LANDSCAPE_CLEAR);
+	p->money64 = old_money;
+	UpdatePlayerMoney32(p);
+
+	/* Because build_date is not set yet in every TileDesc, we make sure it is empty */
+	td.build_date = 0;
+	GetAcceptedCargo(tile, ac);
+	GetTileDesc(tile, &td);
+
+	SetDParam(0, td.dparam[0]);
+	GetString(_landinfo_data[0], td.str, lastof(_landinfo_data[0]));
+
+	SetDParam(0, STR_01A6_N_A);
+	if (td.owner != OWNER_NONE && td.owner != OWNER_WATER) GetNameOfOwner(td.owner, tile);
+	GetString(_landinfo_data[1], STR_01A7_OWNER, lastof(_landinfo_data[1]));
+
+	str = STR_01A4_COST_TO_CLEAR_N_A;
+	if (!CmdFailed(costclear)) {
+		SetDParam(0, costclear);
+		str = STR_01A5_COST_TO_CLEAR;
+	}
+	GetString(_landinfo_data[2], str, lastof(_landinfo_data[2]));
+
+	snprintf(_userstring, lengthof(_userstring), "0x%.4X", tile);
+	SetDParam(0, TileX(tile));
+	SetDParam(1, TileY(tile));
+	SetDParam(2, STR_SPEC_USERSTRING);
+	GetString(_landinfo_data[3], STR_LANDINFO_COORDS, lastof(_landinfo_data[3]));
+
+	SetDParam(0, STR_01A9_NONE);
+	if (t != NULL && IsValidTown(t)) {
+		SetDParam(0, STR_TOWN);
+		SetDParam(1, t->index);
+	}
+	GetString(_landinfo_data[4], STR_01A8_LOCAL_AUTHORITY, lastof(_landinfo_data[4]));
+
+	{
+		int i;
+		char *p = GetString(_landinfo_data[5], STR_01CE_CARGO_ACCEPTED, lastof(_landinfo_data[5]));
+		bool found = false;
+
+		for (i = 0; i < NUM_CARGO; ++i) {
+			if (ac[i] > 0) {
+				/* Add a comma between each item. */
+				if (found) {
+					*p++ = ',';
+					*p++ = ' ';
+				}
+				found = true;
+
+				/* If the accepted value is less than 8, show it in 1/8:ths */
+				if (ac[i] < 8) {
+					SetDParam(0, ac[i]);
+					SetDParam(1, _cargoc.names_s[i]);
+					p = GetString(p, STR_01D1_8, lastof(_landinfo_data[5]));
+				} else {
+					p = GetString(p, _cargoc.names_s[i], lastof(_landinfo_data[5]));
+				}
+			}
+		}
+
+		if (!found) _landinfo_data[5][0] = '\0';
+	}
+
+	if (td.build_date != 0) {
+		SetDParam(0, td.build_date);
+		GetString(_landinfo_data[6], STR_BUILD_DATE, lastof(_landinfo_data[6]));
+	} else {
+		_landinfo_data[6][0] = '\0';
+	}
+
+#if defined(_DEBUG)
+#	define LANDINFOD_LEVEL 0
+#else
+#	define LANDINFOD_LEVEL 1
+#endif
+	DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile));
+	DEBUG(misc, LANDINFOD_LEVEL, "type_height  = %#x", _m[tile].type_height);
+	DEBUG(misc, LANDINFOD_LEVEL, "m1           = %#x", _m[tile].m1);
+	DEBUG(misc, LANDINFOD_LEVEL, "m2           = %#x", _m[tile].m2);
+	DEBUG(misc, LANDINFOD_LEVEL, "m3           = %#x", _m[tile].m3);
+	DEBUG(misc, LANDINFOD_LEVEL, "m4           = %#x", _m[tile].m4);
+	DEBUG(misc, LANDINFOD_LEVEL, "m5           = %#x", _m[tile].m5);
+	DEBUG(misc, LANDINFOD_LEVEL, "extra        = %#x", _m[tile].extra);
+#undef LANDINFOD_LEVEL
+}
+
+void PlaceLandBlockInfo(void)
+{
+	if (_cursor.sprite == SPR_CURSOR_QUERY) {
+		ResetObjectToPlace();
+	} else {
+		_place_proc = Place_LandInfo;
+		SetObjectToPlace(SPR_CURSOR_QUERY, 1, 1, 0);
+	}
+}
+
+static const char *credits[] = {
+	/*************************************************************************
+	 *                      maximum length of string which fits in window   -^*/
+	"Original design by Chris Sawyer",
+	"Original graphics by Simon Foster",
+	"",
+	"The OpenTTD team (in alphabetical order):",
+	"  Jean-Francois Claeys (Belugas) - In training, not yet specialized",
+	"  Bjarni Corfitzen (Bjarni) - MacOSX port, coder",
+	"  Matthijs Kooijman (blathijs) - Pathfinder-guru",
+	"  Victor Fischer (Celestar) - Programming everywhere you need him to",
+	"  Tamás Faragó (Darkvater) - Lead coder",
+	"  Loïc Guilloux (glx) - In training, not yet specialized",
+	"  Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
+	"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
+	"  Peter Nelson (peter1138) - Spiritual descendant from newgrf gods",
+	"  Remko Bijker (Rubidium) - Belugas code scrutinizer",
+	"  Christoph Mallon (Tron) - Programmer, code correctness police",
+	"  Patric Stout (TrueLight) - Coder, network guru, SVN- and website host",
+	"",
+	"Retired Developers:",
+	"  Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
+	"  Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
+	"  Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
+	"  Owen Rudge (orudge) - Forum- and masterserver host, OS/2 port (0.1 - 0.4.8)",
+	"",
+	"Special thanks go out to:",
+	"  Josef Drexler - For his great work on TTDPatch",
+	"  Marcin Grzegorczyk - For his documentation of TTD internals",
+	"  Petr Baudis (pasky) - Many patches, newgrf support",
+	"  Stefan Meißner (sign_de) - For his work on the console",
+	"  Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with (and PBS)",
+	"  Cian Duffy (MYOB) - BeOS port / manual writing",
+	"  Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
+	"  Richard Kempton (richK) - additional airports, initial TGP implementation",
+	"",
+	"  Michael Blunck - Pre-Signals and Semaphores © 2003",
+	"  George - Canal/Lock graphics © 2003-2004",
+	"  Marcin Grzegorczyk - Foundations for Tracks on Slopes",
+	"  All Translators - Who made OpenTTD a truly international game",
+	"  Bug Reporters - Without whom OpenTTD would still be full of bugs!",
+	"",
+	"",
+	"And last but not least:",
+	"  Chris Sawyer - For an amazing game!"
+};
+
+static void AboutWindowProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: /* Set up window counter and start position of scroller */
+		WP(w, scroller_d).counter = 0;
+		WP(w, scroller_d).height = w->height - 40;
+		break;
+	case WE_PAINT: {
+		uint i;
+		int y = WP(w, scroller_d).height;
+		DrawWindowWidgets(w);
+
+		// Show original copyright and revision version
+		DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, 0);
+		DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, 0);
+
+		// Show all scrolling credits
+		for (i = 0; i < lengthof(credits); i++) {
+			if (y >= 50 && y < (w->height - 40)) {
+				DoDrawString(credits[i], 10, y, 0x10);
+			}
+			y += 10;
+		}
+
+		// If the last text has scrolled start anew from the start
+		if (y < 50) WP(w, scroller_d).height = w->height - 40;
+
+		DoDrawStringCentered(210, w->height - 25, "Website: http://www.openttd.org", 16);
+		DrawStringCentered(210, w->height - 15, STR_00BA_COPYRIGHT_OPENTTD, 0);
+	}	break;
+	case WE_MOUSELOOP: /* Timer to scroll the text and adjust the new top */
+		if (WP(w, scroller_d).counter++ % 3 == 0) {
+			WP(w, scroller_d).height--;
+			SetWindowDirty(w);
+		}
+		break;
+	}
+}
+
+static const Widget _about_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   419,     0,    13, STR_015B_OPENTTD, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   419,    14,   271, 0x0,              STR_NULL},
+{      WWT_FRAME,   RESIZE_NONE,    14,     5,   414,    40,   245, STR_NULL,         STR_NULL},
+{    WIDGETS_END},
+};
+
+static const WindowDesc _about_desc = {
+	WDP_CENTER, WDP_CENTER, 420, 272,
+	WC_GAME_OPTIONS,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_about_widgets,
+	AboutWindowProc
+};
+
+
+void ShowAboutWindow(void)
+{
+	DeleteWindowById(WC_GAME_OPTIONS, 0);
+	AllocateWindowDesc(&_about_desc);
+}
+
+static int _tree_to_plant;
+
+static const uint32 _tree_sprites[] = {
+	0x655, 0x663, 0x678, 0x62B, 0x647, 0x639, 0x64E, 0x632, 0x67F, 0x68D, 0x69B, 0x6A9,
+	0x6AF, 0x6D2, 0x6D9, 0x6C4, 0x6CB, 0x6B6, 0x6BD, 0x6E0,
+	0x72E, 0x734, 0x74A, 0x74F, 0x76B, 0x78F, 0x788, 0x77B, 0x75F, 0x774, 0x720, 0x797,
+	0x79E, 0x7A5 | PALETTE_TO_GREEN, 0x7AC | PALETTE_TO_RED, 0x7B3, 0x7BA, 0x7C1 | PALETTE_TO_RED, 0x7C8 | PALETTE_TO_PALE_GREEN, 0x7CF | PALETTE_TO_YELLOW, 0x7D6 | PALETTE_TO_RED
+};
+
+static void BuildTreesWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int x,y;
+		int i, count;
+
+		DrawWindowWidgets(w);
+
+		WP(w,tree_d).base = i = _tree_base_by_landscape[_opt.landscape];
+		WP(w,tree_d).count = count = _tree_count_by_landscape[_opt.landscape];
+
+		x = 18;
+		y = 54;
+		do {
+			DrawSprite(_tree_sprites[i], x, y);
+			x += 35;
+			if (!(++i & 3)) {
+				x -= 35 * 4;
+				y += 47;
+			}
+		} while (--count);
+	} break;
+
+	case WE_CLICK: {
+		int wid = e->we.click.widget;
+
+		switch (wid) {
+		case 0:
+			ResetObjectToPlace();
+			break;
+
+		case 3: case 4: case 5: case 6:
+		case 7: case 8: case 9: case 10:
+		case 11:case 12: case 13: case 14:
+			if (wid - 3 >= WP(w,tree_d).count) break;
+
+			if (HandlePlacePushButton(w, wid, SPR_CURSOR_TREE, 1, NULL))
+				_tree_to_plant = WP(w,tree_d).base + wid - 3;
+			break;
+
+		case 15: // tree of random type.
+			if (HandlePlacePushButton(w, 15, SPR_CURSOR_TREE, 1, NULL))
+				_tree_to_plant = -1;
+			break;
+
+		case 16: /* place trees randomly over the landscape*/
+			LowerWindowWidget(w, 16);
+			w->flags4 |= 5 << WF_TIMEOUT_SHL;
+			SndPlayFx(SND_15_BEEP);
+			PlaceTreesRandomly();
+			MarkWholeScreenDirty();
+			break;
+		}
+	} break;
+
+	case WE_PLACE_OBJ:
+		VpStartPlaceSizing(e->we.place.tile, VPM_X_AND_Y_LIMITED);
+		VpSetPlaceSizingLimit(20);
+		break;
+
+	case WE_PLACE_DRAG:
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
+		return;
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			DoCommandP(e->we.place.tile, _tree_to_plant, e->we.place.starttile, NULL,
+				CMD_PLANT_TREE | CMD_AUTO | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
+		}
+		break;
+
+	case WE_TIMEOUT:
+		RaiseWindowWidget(w, 16);
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		break;
+	}
+}
+
+static const Widget _build_trees_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   170, 0x0,                   STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
+{    WIDGETS_END},
+};
+
+static const WindowDesc _build_trees_desc = {
+	497, 22, 143, 171,
+	WC_BUILD_TREES, WC_SCEN_LAND_GEN,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_trees_widgets,
+	BuildTreesWndProc
+};
+
+static const Widget _build_trees_scen_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   183, 0x0,                   STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   170,   181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER},
+{    WIDGETS_END},
+};
+
+static const WindowDesc _build_trees_scen_desc = {
+	WDP_AUTO, WDP_AUTO, 143, 184,
+	WC_BUILD_TREES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_trees_scen_widgets,
+	BuildTreesWndProc
+};
+
+
+void ShowBuildTreesToolbar(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+	AllocateWindowDescFront(&_build_trees_desc, 0);
+}
+
+void ShowBuildTreesScenToolbar(void)
+{
+	AllocateWindowDescFront(&_build_trees_scen_desc, 0);
+}
+
+static uint32 _errmsg_decode_params[20];
+static StringID _errmsg_message_1, _errmsg_message_2;
+static uint _errmsg_duration;
+
+
+static const Widget _errmsg_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     4,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     4,    11,   239,     0,    13, STR_00B2_MESSAGE, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     4,     0,   239,    14,    45, 0x0,              STR_NULL},
+{    WIDGETS_END},
+};
+
+static const Widget _errmsg_face_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     4,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     4,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     4,     0,   333,    14,   136, 0x0,                   STR_NULL},
+{   WIDGETS_END},
+};
+
+static void ErrmsgWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		COPY_IN_DPARAM(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
+		DrawWindowWidgets(w);
+		COPY_IN_DPARAM(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
+		if (!IsWindowOfPrototype(w, _errmsg_face_widgets)) {
+			DrawStringMultiCenter(
+				120,
+				(_errmsg_message_1 == INVALID_STRING_ID ? 25 : 15),
+				_errmsg_message_2,
+				238);
+			if (_errmsg_message_1 != INVALID_STRING_ID)
+				DrawStringMultiCenter(
+					120,
+					30,
+					_errmsg_message_1,
+					238);
+		} else {
+			const Player *p = GetPlayer(GetDParamX(_errmsg_decode_params,2));
+			DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+			DrawStringMultiCenter(
+				214,
+				(_errmsg_message_1 == INVALID_STRING_ID ? 65 : 45),
+				_errmsg_message_2,
+				238);
+			if (_errmsg_message_1 != INVALID_STRING_ID)
+				DrawStringMultiCenter(
+					214,
+					90,
+					_errmsg_message_1,
+					238);
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		if (_right_button_down) DeleteWindow(w);
+		break;
+
+	case WE_4:
+		if (--_errmsg_duration == 0) DeleteWindow(w);
+		break;
+
+	case WE_DESTROY:
+		SetRedErrorSquare(0);
+		_switch_mode_errorstr = INVALID_STRING_ID;
+		break;
+
+	case WE_KEYPRESS:
+		if (e->we.keypress.keycode == WKC_SPACE) {
+			// Don't continue.
+			e->we.keypress.cont = false;
+			DeleteWindow(w);
+		}
+		break;
+	}
+}
+
+void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
+{
+	Window *w;
+	const ViewPort *vp;
+	Point pt;
+
+	DeleteWindowById(WC_ERRMSG, 0);
+
+	//assert(msg_2);
+	if (msg_2 == 0) msg_2 = STR_EMPTY;
+
+	_errmsg_message_1 = msg_1;
+	_errmsg_message_2 = msg_2;
+	COPY_OUT_DPARAM(_errmsg_decode_params, 0, lengthof(_errmsg_decode_params));
+	_errmsg_duration = _patches.errmsg_duration;
+	if (!_errmsg_duration) return;
+
+	if (_errmsg_message_1 != STR_013B_OWNED_BY || GetDParamX(_errmsg_decode_params,2) >= 8) {
+
+		if ( (x|y) != 0) {
+			pt = RemapCoords2(x, y);
+			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
+
+			// move x pos to opposite corner
+			pt.x = ((pt.x - vp->virtual_left) >> vp->zoom) + vp->left;
+			pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - 260 : 20;
+
+			// move y pos to opposite corner
+			pt.y = ((pt.y - vp->virtual_top) >> vp->zoom) + vp->top;
+			pt.y = (pt.y < (_screen.height >> 1)) ? _screen.height - 80 : 100;
+
+		} else {
+			pt.x = (_screen.width - 240) >> 1;
+			pt.y = (_screen.height - 46) >> 1;
+		}
+		w = AllocateWindow(pt.x, pt.y, 240, 46, ErrmsgWndProc, WC_ERRMSG, _errmsg_widgets);
+	} else {
+		if ( (x|y) != 0) {
+			pt = RemapCoords2(x, y);
+			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
+			pt.x = clamp(((pt.x - vp->virtual_left) >> vp->zoom) + vp->left - (334/2), 0, _screen.width - 334);
+			pt.y = clamp(((pt.y - vp->virtual_top) >> vp->zoom) + vp->top - (137/2), 22, _screen.height - 137);
+		} else {
+			pt.x = (_screen.width - 334) >> 1;
+			pt.y = (_screen.height - 137) >> 1;
+		}
+		w = AllocateWindow(pt.x, pt.y, 334, 137, ErrmsgWndProc, WC_ERRMSG, _errmsg_face_widgets);
+	}
+
+	w->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
+}
+
+
+void ShowEstimatedCostOrIncome(int32 cost, int x, int y)
+{
+	StringID msg = STR_0805_ESTIMATED_COST;
+
+	if (cost < 0) {
+		cost = -cost;
+		msg = STR_0807_ESTIMATED_INCOME;
+	}
+	SetDParam(0, cost);
+	ShowErrorMessage(INVALID_STRING_ID, msg, x, y);
+}
+
+void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost)
+{
+	StringID msg;
+	Point pt = RemapCoords(x,y,z);
+
+	msg = STR_0801_COST;
+	if (cost < 0) {
+		cost = -cost;
+		msg = STR_0803_INCOME;
+	}
+	SetDParam(0, cost);
+	AddTextEffect(msg, pt.x, pt.y, 0x250);
+}
+
+void ShowFeederIncomeAnimation(int x, int y, int z, int32 cost)
+{
+	Point pt = RemapCoords(x,y,z);
+
+	SetDParam(0, cost);
+	AddTextEffect(STR_FEEDER, pt.x, pt.y, 0x250);
+}
+
+static const Widget _tooltips_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   199,     0,    31, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+
+static void TooltipsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			uint arg;
+			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0);
+			GfxFillRect(1, 1, w->width - 2, w->height - 2, 0x44);
+
+			for (arg = 0; arg < WP(w, tooltips_d).paramcount; arg++) {
+				SetDParam(arg, WP(w, tooltips_d).params[arg]);
+			}
+			DrawStringMultiCenter((w->width >> 1), (w->height >> 1) - 5, WP(w, tooltips_d).string_id, 197);
+			break;
+		}
+
+		case WE_MOUSELOOP:
+			/* We can show tooltips while dragging tools. These are shown as long as
+			 * we are dragging the tool. Normal tooltips work with rmb */
+			if (WP(w, tooltips_d).paramcount == 0 ) {
+				if (!_right_button_down) DeleteWindow(w);
+			} else {
+				if (!_left_button_down) DeleteWindow(w);
+			}
+
+			break;
+	}
+}
+
+/** Shows a tooltip
+* @param str String to be displayed
+* @param params (optional) up to 5 pieces of additional information that may be
+* added to a tooltip; currently only supports parameters of {NUM} (integer) */
+void GuiShowTooltipsWithArgs(StringID str, uint paramcount, const uint32 params[])
+{
+	char buffer[512];
+	BoundingRect br;
+	Window *w;
+	uint i;
+	int x, y;
+
+	DeleteWindowById(WC_TOOLTIPS, 0);
+
+	/* We only show measurement tooltips with patch setting on */
+	if (str == STR_NULL || (paramcount != 0 && !_patches.measure_tooltip)) return;
+
+	for (i = 0; i != paramcount; i++) SetDParam(i, params[i]);
+	GetString(buffer, str, lastof(buffer));
+
+	br = GetStringBoundingBox(buffer);
+	br.width += 6; br.height += 4; // increase slightly to have some space around the box
+
+	/* Cut tooltip length to 200 pixels max, wrap to new line if longer */
+	if (br.width > 200) {
+		br.height += ((br.width - 4) / 176) * 10;
+		br.width = 200;
+	}
+
+	/* Correctly position the tooltip position, watch out for window and cursor size
+	 * Clamp value to below main toolbar and above statusbar. If tooltip would
+	 * go below window, flip it so it is shown above the cursor */
+	y = clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, 22, _screen.height - 12);
+	if (y + br.height > _screen.height - 12) y = _cursor.pos.y + _cursor.offs.y - br.height - 5;
+	x = clamp(_cursor.pos.x - (br.width >> 1), 0, _screen.width - br.width);
+
+	w = AllocateWindow(x, y, br.width, br.height, TooltipsWndProc, WC_TOOLTIPS, _tooltips_widgets);
+
+	WP(w, tooltips_d).string_id = str;
+	assert(sizeof(WP(w, tooltips_d).params[0]) == sizeof(params[0]));
+	memcpy(WP(w, tooltips_d).params, params, sizeof(WP(w, tooltips_d).params[0]) * paramcount);
+	WP(w, tooltips_d).paramcount = paramcount;
+
+	w->flags4 &= ~WF_WHITE_BORDER_MASK; // remove white-border from tooltip
+	w->widget[0].right = br.width;
+	w->widget[0].bottom = br.height;
+}
+
+
+static void DrawStationCoverageText(const AcceptedCargo accepts,
+	int str_x, int str_y, uint mask)
+{
+	char *b = _userstring;
+	bool first = true;
+	int i;
+
+	b = InlineString(b, STR_000D_ACCEPTS);
+
+	for (i = 0; i != NUM_CARGO; i++, mask >>= 1) {
+		if (b >= lastof(_userstring) - 5) break;
+		if (accepts[i] >= 8 && mask & 1) {
+			if (first) {
+				first = false;
+			} else {
+				/* Add a comma if this is not the first item */
+				*b++ = ',';
+				*b++ = ' ';
+			}
+			b = InlineString(b, _cargoc.names_s[i]);
+		}
+	}
+
+	/* If first is still true then no cargo is accepted */
+	if (first) b = InlineString(b, STR_00D0_NOTHING);
+
+	*b = '\0';
+	DrawStringMultiLine(str_x, str_y, STR_SPEC_USERSTRING, 144);
+}
+
+void DrawStationCoverageAreaText(int sx, int sy, uint mask, int rad) {
+	TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
+	AcceptedCargo accepts;
+	if (tile < MapSize()) {
+		GetAcceptanceAroundTiles(accepts, tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE , rad);
+		DrawStationCoverageText(accepts, sx, sy, mask);
+	}
+}
+
+void CheckRedrawStationCoverage(const Window *w)
+{
+	if (_thd.dirty & 1) {
+		_thd.dirty &= ~1;
+		SetWindowDirty(w);
+	}
+}
+
+void SetVScrollCount(Window *w, int num)
+{
+	w->vscroll.count = num;
+	num -= w->vscroll.cap;
+	if (num < 0) num = 0;
+	if (num < w->vscroll.pos) w->vscroll.pos = num;
+}
+
+void SetVScroll2Count(Window *w, int num)
+{
+	w->vscroll2.count = num;
+	num -= w->vscroll2.cap;
+	if (num < 0) num = 0;
+	if (num < w->vscroll2.pos) w->vscroll2.pos = num;
+}
+
+void SetHScrollCount(Window *w, int num)
+{
+	w->hscroll.count = num;
+	num -= w->hscroll.cap;
+	if (num < 0) num = 0;
+	if (num < w->hscroll.pos) w->hscroll.pos = num;
+}
+
+/* Delete a character at the caret position in a text buf.
+ * If backspace is set, delete the character before the caret,
+ * else delete the character after it. */
+static void DelChar(Textbuf *tb, bool backspace)
+{
+	WChar c;
+	uint width;
+	size_t len;
+
+	if (backspace) {
+		do {
+			tb->caretpos--;
+		} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
+	}
+
+	len = Utf8Decode(&c, tb->buf + tb->caretpos);
+	width = GetCharacterWidth(FS_NORMAL, c);
+
+	tb->width  -= width;
+	if (backspace) tb->caretxoffs -= width;
+
+	/* Move the remaining characters over the marker */
+	memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + len, tb->length - tb->caretpos - len + 1);
+	tb->length -= len;
+}
+
+/**
+ * Delete a character from a textbuffer, either with 'Delete' or 'Backspace'
+ * The character is delete from the position the caret is at
+ * @param tb @Textbuf type to be changed
+ * @param delmode Type of deletion, either @WKC_BACKSPACE or @WKC_DELETE
+ * @return Return true on successfull change of Textbuf, or false otherwise
+ */
+bool DeleteTextBufferChar(Textbuf *tb, int delmode)
+{
+	if (delmode == WKC_BACKSPACE && tb->caretpos != 0) {
+		DelChar(tb, true);
+		return true;
+	} else if (delmode == WKC_DELETE && tb->caretpos < tb->length) {
+		DelChar(tb, false);
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Delete every character in the textbuffer
+ * @param tb @Textbuf buffer to be emptied
+ */
+void DeleteTextBufferAll(Textbuf *tb)
+{
+	memset(tb->buf, 0, tb->maxlength);
+	tb->length = tb->width = 0;
+	tb->caretpos = tb->caretxoffs = 0;
+}
+
+/**
+ * Insert a character to a textbuffer. If maxwidth of the Textbuf is zero,
+ * we don't care about the visual-length but only about the physical
+ * length of the string
+ * @param tb @Textbuf type to be changed
+ * @param key Character to be inserted
+ * @return Return true on successfull change of Textbuf, or false otherwise
+ */
+bool InsertTextBufferChar(Textbuf *tb, WChar key)
+{
+	const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
+	size_t len = Utf8CharLen(key);
+	if (tb->length < (tb->maxlength - len) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
+		memmove(tb->buf + tb->caretpos + len, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
+		Utf8Encode(tb->buf + tb->caretpos, key);
+		tb->length += len;
+		tb->width  += charwidth;
+
+		tb->caretpos   += len;
+		tb->caretxoffs += charwidth;
+		return true;
+	}
+	return false;
+}
+
+/**
+ * Handle text navigation with arrow keys left/right.
+ * This defines where the caret will blink and the next characer interaction will occur
+ * @param tb @Textbuf type where navigation occurs
+ * @param navmode Direction in which navigation occurs @WKC_LEFT, @WKC_RIGHT, @WKC_END, @WKC_HOME
+ * @return Return true on successfull change of Textbuf, or false otherwise
+ */
+bool MoveTextBufferPos(Textbuf *tb, int navmode)
+{
+	switch (navmode) {
+	case WKC_LEFT:
+		if (tb->caretpos != 0) {
+			WChar c;
+
+			do {
+				tb->caretpos--;
+			} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
+
+			Utf8Decode(&c, tb->buf + tb->caretpos);
+			tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
+
+			return true;
+		}
+		break;
+	case WKC_RIGHT:
+		if (tb->caretpos < tb->length) {
+			WChar c;
+
+			tb->caretpos   += Utf8Decode(&c, tb->buf + tb->caretpos);
+			tb->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
+
+			return true;
+		}
+		break;
+	case WKC_HOME:
+		tb->caretpos = 0;
+		tb->caretxoffs = 0;
+		return true;
+	case WKC_END:
+		tb->caretpos = tb->length;
+		tb->caretxoffs = tb->width;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Initialize the textbuffer by supplying it the buffer to write into
+ * and the maximum length of this buffer
+ * @param tb @Textbuf type which is getting initialized
+ * @param buf the buffer that will be holding the data for input
+ * @param maxlength maximum length in characters of this buffer
+ * @param maxwidth maximum length in pixels of this buffer. If reached, buffer
+ * cannot grow, even if maxlength would allow because there is space. A length
+ * of zero '0' means the buffer is only restricted by maxlength */
+void InitializeTextBuffer(Textbuf *tb, const char *buf, uint16 maxlength, uint16 maxwidth)
+{
+	tb->buf = (char*)buf;
+	tb->maxlength = maxlength;
+	tb->maxwidth  = maxwidth;
+	tb->caret = true;
+	UpdateTextBufferSize(tb);
+}
+
+/**
+ * Update @Textbuf type with its actual physical character and screenlength
+ * Get the count of characters in the string as well as the width in pixels.
+ * Useful when copying in a larger amount of text at once
+ * @param tb @Textbuf type which length is calculated
+ */
+void UpdateTextBufferSize(Textbuf *tb)
+{
+	const char *buf = tb->buf;
+	WChar c = Utf8Consume(&buf);
+
+	tb->width = 0;
+	tb->length = 0;
+
+	for (; c != '\0' && tb->length < (tb->maxlength - 1); c = Utf8Consume(&buf)) {
+		tb->width += GetCharacterWidth(FS_NORMAL, c);
+		tb->length += Utf8CharLen(c);
+	}
+
+	tb->caretpos = tb->length;
+	tb->caretxoffs = tb->width;
+}
+
+int HandleEditBoxKey(Window *w, querystr_d *string, int wid, WindowEvent *e)
+{
+	e->we.keypress.cont = false;
+
+	switch (e->we.keypress.keycode) {
+	case WKC_ESC: return 2;
+	case WKC_RETURN: case WKC_NUM_ENTER: return 1;
+	case (WKC_CTRL | 'V'):
+		if (InsertTextBufferClipboard(&string->text))
+			InvalidateWidget(w, wid);
+		break;
+	case (WKC_CTRL | 'U'):
+		DeleteTextBufferAll(&string->text);
+		InvalidateWidget(w, wid);
+		break;
+	case WKC_BACKSPACE: case WKC_DELETE:
+		if (DeleteTextBufferChar(&string->text, e->we.keypress.keycode))
+			InvalidateWidget(w, wid);
+		break;
+	case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
+		if (MoveTextBufferPos(&string->text, e->we.keypress.keycode))
+			InvalidateWidget(w, wid);
+		break;
+	default:
+		if (IsValidChar(e->we.keypress.key, string->afilter)) {
+			if (InsertTextBufferChar(&string->text, e->we.keypress.key)) {
+				InvalidateWidget(w, wid);
+			}
+		} else { // key wasn't caught. Continue only if standard entry specified
+			e->we.keypress.cont = (string->afilter == CS_ALPHANUMERAL);
+		}
+	}
+
+	return 0;
+}
+
+bool HandleCaret(Textbuf *tb)
+{
+	/* caret changed? */
+	bool b = !!(_caret_timer & 0x20);
+
+	if (b != tb->caret) {
+		tb->caret = b;
+		return true;
+	}
+	return false;
+}
+
+void HandleEditBox(Window *w, querystr_d *string, int wid)
+{
+	if (HandleCaret(&string->text)) InvalidateWidget(w, wid);
+}
+
+void DrawEditBox(Window *w, querystr_d *string, int wid)
+{
+	DrawPixelInfo dpi, *old_dpi;
+	int delta;
+	const Widget *wi = &w->widget[wid];
+	const Textbuf *tb = &string->text;
+
+	/* Limit the drawing of the string inside the widget boundaries */
+	if (!FillDrawPixelInfo(&dpi,
+	      wi->left + 4,
+	      wi->top + 1,
+	      wi->right - wi->left - 4,
+	      wi->bottom - wi->top - 1)
+	) return;
+
+	GfxFillRect(wi->left + 1, wi->top + 1, wi->right - 1, wi->bottom - 1, 215);
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = &dpi;
+
+	/* We will take the current widget length as maximum width, with a small
+	 * space reserved at the end for the caret to show */
+	delta = (wi->right - wi->left) - tb->width - 10;
+	if (delta > 0) delta = 0;
+
+	if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
+
+	DoDrawString(tb->buf, delta, 0, 8);
+	if (tb->caret) DoDrawString("_", tb->caretxoffs + delta, 0, 12);
+
+	_cur_dpi = old_dpi;
+}
+
+enum QueryStringWidgets {
+	QUERY_STR_WIDGET_TEXT = 3,
+	QUERY_STR_WIDGET_CANCEL,
+	QUERY_STR_WIDGET_OK
+};
+
+
+static void QueryStringWndProc(Window *w, WindowEvent *e)
+{
+	querystr_d *qs = &WP(w, querystr_d);
+
+	switch (e->event) {
+		case WE_CREATE:
+			SETBIT(_no_scroll, SCROLL_EDIT);
+			break;
+
+		case WE_PAINT:
+			SetDParam(0, qs->caption);
+			DrawWindowWidgets(w);
+
+			DrawEditBox(w, qs, QUERY_STR_WIDGET_TEXT);
+			break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case QUERY_STR_WIDGET_OK:
+		press_ok:;
+					if (qs->orig == NULL || strcmp(qs->text.buf, qs->orig) != 0) {
+						Window *parent = w->parent;
+						qs->handled = true;
+
+						/* If the parent is NULL, the editbox is handled by general function
+						 * HandleOnEditText */
+						if (parent != NULL) {
+							WindowEvent e;
+							e.event = WE_ON_EDIT_TEXT;
+							e.we.edittext.str = qs->text.buf;
+							parent->wndproc(parent, &e);
+						} else {
+							HandleOnEditText(qs->text.buf);
+						}
+					}
+					/* Fallthrough */
+				case QUERY_STR_WIDGET_CANCEL:
+					DeleteWindow(w);
+					break;
+			}
+			break;
+
+		case WE_MOUSELOOP:
+			HandleEditBox(w, qs, QUERY_STR_WIDGET_TEXT);
+			break;
+
+		case WE_KEYPRESS:
+			switch (HandleEditBoxKey(w, qs, QUERY_STR_WIDGET_TEXT, e)) {
+				case 1: goto press_ok; /* Enter pressed, confirms change */
+				case 2: DeleteWindow(w); break; /* ESC pressed, closes window, abandons changes */
+			}
+			break;
+
+		case WE_DESTROY: /* Call cancellation of query, if we have not handled it before */
+			if (!qs->handled && w->parent != NULL) {
+				WindowEvent e;
+				Window *parent = w->parent;
+
+				qs->handled = true;
+				e.event = WE_ON_EDIT_TEXT_CANCEL;
+				parent->wndproc(parent, &e);
+			}
+			CLRBIT(_no_scroll, SCROLL_EDIT);
+			break;
+		}
+}
+
+static const Widget _query_string_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   259,     0,    13, STR_012D,        STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   259,    14,    29, 0x0,             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   257,    16,    27, 0x0,             STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,   129,    30,    41, STR_012E_CANCEL, STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   259,    30,    41, STR_012F_OK,     STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _query_string_desc = {
+	190, 219, 260, 42,
+	WC_QUERY_STRING,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_query_string_widgets,
+	QueryStringWndProc
+};
+
+static char _edit_str_buf[64];
+
+/** Show a query popup window with a textbox in it.
+ * @param str StringID for the text shown in the textbox
+ * @param caption StringID of text shown in caption of querywindow
+ * @param maxlen maximum length in characters allowed. If bit 12 is set we
+ * will not check the resulting string against to original string to return success
+ * @param maxwidth maximum width in pixels allowed
+ * @param parent pointer to a Window that will handle the events (ok/cancel) of this
+ * window. If NULL, results are handled by global function HandleOnEditText
+ * @param afilter filters out unwanted character input */
+void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter)
+{
+	static char orig_str_buf[lengthof(_edit_str_buf)];
+	Window *w;
+	uint realmaxlen = maxlen & ~0x1000;
+
+	assert(realmaxlen < lengthof(_edit_str_buf));
+
+	DeleteWindowById(WC_QUERY_STRING, 0);
+	DeleteWindowById(WC_SAVELOAD, 0);
+
+	w = AllocateWindowDesc(&_query_string_desc);
+	w->parent = parent;
+
+	GetString(_edit_str_buf, str, lastof(_edit_str_buf));
+	_edit_str_buf[realmaxlen - 1] = '\0';
+
+	if (maxlen & 0x1000) {
+		WP(w, querystr_d).orig = NULL;
+	} else {
+		strecpy(orig_str_buf, _edit_str_buf, lastof(orig_str_buf));
+		WP(w, querystr_d).orig = orig_str_buf;
+	}
+
+	LowerWindowWidget(w, QUERY_STR_WIDGET_TEXT);
+	WP(w, querystr_d).caption = caption;
+	WP(w, querystr_d).afilter = afilter;
+	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, realmaxlen, maxwidth);
+}
+
+
+enum QueryWidgets {
+	QUERY_WIDGET_CAPTION = 1,
+	QUERY_WIDGET_NO = 3,
+	QUERY_WIDGET_YES
+};
+
+
+typedef struct query_d {
+	void (*proc)(Window*, bool); ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise
+	StringID message;            ///< message shown for query window
+	uint32 params[20];           ///< local copy of _decode_parameters
+	bool calledback;             ///< has callback been executed already (internal usage for WE_DESTROY event)
+} query_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(query_d));
+
+
+static void QueryWndProc(Window *w, WindowEvent *e)
+{
+	query_d *q = &WP(w, query_d);
+
+	switch (e->event) {
+		case WE_PAINT:
+			COPY_IN_DPARAM(0, q->params, lengthof(q->params));
+			DrawWindowWidgets(w);
+			COPY_IN_DPARAM(0, q->params, lengthof(q->params));
+
+			DrawStringMultiCenter(w->width / 2, (w->height / 2) - 10, q->message, w->width);
+			break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case QUERY_WIDGET_YES:
+					q->calledback = true;
+					if (q->proc != NULL) q->proc(w->parent, true);
+					/* Fallthrough */
+				case QUERY_WIDGET_NO:
+					DeleteWindow(w);
+					break;
+				}
+			break;
+
+		case WE_KEYPRESS: /* ESC closes the window, Enter confirms the action */
+			switch (e->we.keypress.keycode) {
+				case WKC_RETURN:
+				case WKC_NUM_ENTER:
+					q->calledback = true;
+					if (q->proc != NULL) q->proc(w->parent, true);
+					/* Fallthrough */
+				case WKC_ESC:
+					e->we.keypress.cont = false;
+					DeleteWindow(w);
+					break;
+			}
+			break;
+
+		case WE_DESTROY: /* Call callback function (if any) on window close if not yet called */
+			if (!q->calledback && q->proc != NULL) {
+				q->calledback = true;
+				q->proc(w->parent, false);
+			}
+			break;
+	}
+}
+
+
+static const Widget _query_widgets[] = {
+{  WWT_CLOSEBOX, RESIZE_NONE,  4,   0,  10,   0,  13, STR_00C5,        STR_018B_CLOSE_WINDOW},
+{   WWT_CAPTION, RESIZE_NONE,  4,  11, 209,   0,  13, STR_NULL,        STR_NULL},
+{     WWT_PANEL, RESIZE_NONE,  4,   0, 209,  14,  81, 0x0, /*OVERRIDE*/STR_NULL},
+{WWT_PUSHTXTBTN, RESIZE_NONE,  3,  20,  90,  62,  73, STR_00C9_NO,     STR_NULL},
+{WWT_PUSHTXTBTN, RESIZE_NONE,  3, 120, 190,  62,  73, STR_00C8_YES,    STR_NULL},
+{   WIDGETS_END },
+};
+
+static const WindowDesc _query_desc = {
+	WDP_CENTER, WDP_CENTER, 210, 82,
+	WC_CONFIRM_POPUP_QUERY, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_DEF_WIDGET | WDF_MODAL,
+	_query_widgets,
+	QueryWndProc
+};
+
+/** Show a modal confirmation window with standard 'yes' and 'no' buttons
+ * The window is aligned to the centre of its parent.
+ * NOTE: You cannot use BindCString as parameter for this window!
+ * @param caption string shown as window caption
+ * @param message string that will be shown for the window
+ * @param parent pointer to parent window, if this pointer is NULL the parent becomes
+ * the main window WC_MAIN_WINDOW
+ * @param x,y coordinates to show the window at
+ * @param yes_no_callback callback function called when window is closed through any button */
+void ShowQuery(StringID caption, StringID message, Window *parent, void (*callback)(Window*, bool))
+{
+	Window *w = AllocateWindowDesc(&_query_desc);
+	if (w == NULL) return;
+
+	if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0);
+	w->parent = parent;
+	w->left = parent->left + (parent->width / 2) - (w->width / 2);
+	w->top = parent->top + (parent->height / 2) - (w->height / 2);
+
+	/* Create a backup of the variadic arguments to strings because it will be
+	 * overridden pretty often. We will copy these back for drawing */
+	COPY_OUT_DPARAM(WP(w, query_d).params, 0, lengthof(WP(w, query_d).params));
+	w->widget[QUERY_WIDGET_CAPTION].data = caption;
+	WP(w, query_d).message    = message;
+	WP(w, query_d).proc       = callback;
+	WP(w, query_d).calledback = false;
+}
+
+
+static const Widget _load_dialog_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   256,     0,    13, STR_NULL,         STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   127,    14,    25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   128,   256,    14,    25, STR_SORT_BY_DATE, STR_SORT_ORDER_TIP},
+{      WWT_PANEL,  RESIZE_RIGHT,    14,     0,   256,    26,    47, 0x0,              STR_NULL},
+{      WWT_PANEL,     RESIZE_RB,    14,     0,   256,    48,   293, 0x0,              STR_NULL},
+{ WWT_PUSHIMGBTN,     RESIZE_LR,    14,   245,   256,    48,    59, SPR_HOUSE_ICON,   STR_SAVELOAD_HOME_BUTTON},
+{      WWT_INSET,     RESIZE_RB,    14,     2,   243,    50,   291, 0x0,              STR_400A_LIST_OF_DRIVES_DIRECTORIES},
+{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   245,   256,    60,   281, 0x0,              STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   245,   256,   282,   293, 0x0,              STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const Widget _save_dialog_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   256,     0,    13, STR_NULL,         STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   127,    14,    25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   128,   256,    14,    25, STR_SORT_BY_DATE, STR_SORT_ORDER_TIP},
+{      WWT_PANEL,  RESIZE_RIGHT,    14,     0,   256,    26,    47, 0x0,              STR_NULL},
+{      WWT_PANEL,     RESIZE_RB,    14,     0,   256,    48,   291, 0x0,              STR_NULL},
+{ WWT_PUSHIMGBTN,     RESIZE_LR,    14,   245,   256,    48,    59, SPR_HOUSE_ICON,   STR_SAVELOAD_HOME_BUTTON},
+{      WWT_INSET,     RESIZE_RB,    14,     2,   243,    50,   290, 0x0,              STR_400A_LIST_OF_DRIVES_DIRECTORIES},
+{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   245,   256,    60,   291, 0x0,              STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,    RESIZE_RTB,    14,     0,   256,   292,   307, 0x0,              STR_NULL},
+{      WWT_PANEL,    RESIZE_RTB,    14,     2,   254,   294,   305, 0x0,              STR_400B_CURRENTLY_SELECTED_NAME},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   127,   308,   319, STR_4003_DELETE,  STR_400C_DELETE_THE_CURRENTLY_SELECTED},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   128,   244,   308,   319, STR_4002_SAVE,    STR_400D_SAVE_THE_CURRENT_GAME_USING},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   245,   256,   308,   319, 0x0,              STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+// Colors for fios types
+const byte _fios_colors[] = {13, 9, 9, 6, 5, 6, 5, 6, 6, 8};
+
+void BuildFileList(void)
+{
+	_fios_path_changed = true;
+	FiosFreeSavegameList();
+
+	switch (_saveload_mode) {
+		case SLD_NEW_GAME:
+		case SLD_LOAD_SCENARIO:
+		case SLD_SAVE_SCENARIO:
+			_fios_list = FiosGetScenarioList(_saveload_mode); break;
+		case SLD_LOAD_HEIGHTMAP:
+			_fios_list = FiosGetHeightmapList(_saveload_mode); break;
+
+		default: _fios_list = FiosGetSavegameList(_saveload_mode); break;
+	}
+}
+
+static void DrawFiosTexts(uint maxw)
+{
+	static const char *path = NULL;
+	static StringID str = STR_4006_UNABLE_TO_READ_DRIVE;
+	static uint32 tot = 0;
+
+	if (_fios_path_changed) {
+		str = FiosGetDescText(&path, &tot);
+		_fios_path_changed = false;
+	}
+
+	if (str != STR_4006_UNABLE_TO_READ_DRIVE) SetDParam(0, tot);
+	DrawString(2, 37, str, 0);
+	DoDrawStringTruncated(path, 2, 27, 16, maxw);
+}
+
+static void MakeSortedSaveGameList(void)
+{
+	uint sort_start = 0;
+	uint sort_end = 0;
+	uint s_amount;
+	int i;
+
+	/* Directories are always above the files (FIOS_TYPE_DIR)
+	 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
+	 * Only sort savegames/scenarios, not directories
+	 */
+	for (i = 0; i < _fios_num; i++) {
+		switch (_fios_list[i].type) {
+			case FIOS_TYPE_DIR:    sort_start++; break;
+			case FIOS_TYPE_PARENT: sort_start++; break;
+			case FIOS_TYPE_DRIVE:  sort_end++;   break;
+		}
+	}
+
+	s_amount = _fios_num - sort_start - sort_end;
+	if (s_amount > 0)
+		qsort(_fios_list + sort_start, s_amount, sizeof(FiosItem), compare_FiosItems);
+}
+
+static void GenerateFileName(void)
+{
+	/* Check if we are not a specatator who wants to generate a name..
+	    Let's use the name of player #0 for now. */
+	const Player *p = GetPlayer(IsValidPlayer(_local_player) ? _local_player : 0);
+
+	SetDParam(0, p->name_1);
+	SetDParam(1, p->name_2);
+	SetDParam(2, _date);
+	GetString(_edit_str_buf, STR_4004, lastof(_edit_str_buf));
+}
+
+extern void StartupEngines(void);
+
+static void SaveLoadDlgWndProc(Window *w, WindowEvent *e)
+{
+	static FiosItem o_dir;
+
+	switch (e->event) {
+	case WE_CREATE: { /* Set up OPENTTD button */
+		o_dir.type = FIOS_TYPE_DIRECT;
+		switch (_saveload_mode) {
+			case SLD_SAVE_GAME:
+			case SLD_LOAD_GAME:
+				ttd_strlcpy(&o_dir.name[0], _paths.save_dir, sizeof(o_dir.name));
+				break;
+
+			case SLD_SAVE_SCENARIO:
+			case SLD_LOAD_SCENARIO:
+				ttd_strlcpy(&o_dir.name[0], _paths.scenario_dir, sizeof(o_dir.name));
+				break;
+
+			case SLD_LOAD_HEIGHTMAP:
+				ttd_strlcpy(&o_dir.name[0], _paths.heightmap_dir, sizeof(o_dir.name));
+				break;
+
+			default:
+				ttd_strlcpy(&o_dir.name[0], _paths.personal_dir, sizeof(o_dir.name));
+		}
+		break;
+		}
+
+	case WE_PAINT: {
+		int pos;
+		int y;
+
+		SetVScrollCount(w, _fios_num);
+		DrawWindowWidgets(w);
+		DrawFiosTexts(w->width);
+
+		if (_savegame_sort_dirty) {
+			_savegame_sort_dirty = false;
+			MakeSortedSaveGameList();
+		}
+
+		GfxFillRect(w->widget[7].left + 1, w->widget[7].top + 1, w->widget[7].right, w->widget[7].bottom, 0xD7);
+		DoDrawString(
+			_savegame_sort_order & SORT_DESCENDING ? DOWNARROW : UPARROW,
+			_savegame_sort_order & SORT_BY_NAME ? w->widget[2].right - 9 : w->widget[3].right - 9,
+			15, 16
+		);
+
+		y = w->widget[7].top + 1;
+		for (pos = w->vscroll.pos; pos < _fios_num; pos++) {
+			const FiosItem *item = _fios_list + pos;
+
+			DoDrawStringTruncated(item->title, 4, y, _fios_colors[item->type], w->width - 18);
+			y += 10;
+			if (y >= w->vscroll.cap * 10 + w->widget[7].top + 1) break;
+		}
+
+		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
+			DrawEditBox(w, &WP(w,querystr_d), 10);
+		}
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: /* Sort save names by name */
+			_savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ?
+				SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME;
+			_savegame_sort_dirty = true;
+			SetWindowDirty(w);
+			break;
+
+		case 3: /* Sort save names by date */
+			_savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ?
+				SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE;
+			_savegame_sort_dirty = true;
+			SetWindowDirty(w);
+			break;
+
+		case 6: /* OpenTTD 'button', jumps to OpenTTD directory */
+			FiosBrowseTo(&o_dir);
+			SetWindowDirty(w);
+			BuildFileList();
+			break;
+
+		case 7: { /* Click the listbox */
+			int y = (e->we.click.pt.y - w->widget[e->we.click.widget].top - 1) / 10;
+			char *name;
+			const FiosItem *file;
+
+			if (y < 0 || (y += w->vscroll.pos) >= w->vscroll.count) return;
+
+			file = _fios_list + y;
+
+			name = FiosBrowseTo(file);
+			if (name != NULL) {
+				if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
+					_switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD;
+
+					SetFiosType(file->type);
+					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
+					ttd_strlcpy(_file_to_saveload.title, file->title, sizeof(_file_to_saveload.title));
+
+					DeleteWindow(w);
+				} else if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
+					SetFiosType(file->type);
+					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
+					ttd_strlcpy(_file_to_saveload.title, file->title, sizeof(_file_to_saveload.title));
+
+					DeleteWindow(w);
+					ShowHeightmapLoad();
+				} else {
+					// SLD_SAVE_GAME, SLD_SAVE_SCENARIO copy clicked name to editbox
+					ttd_strlcpy(WP(w, querystr_d).text.buf, file->title, WP(w, querystr_d).text.maxlength);
+					UpdateTextBufferSize(&WP(w, querystr_d).text);
+					InvalidateWidget(w, 10);
+				}
+			} else {
+				// Changed directory, need repaint.
+				SetWindowDirty(w);
+				BuildFileList();
+			}
+			break;
+		}
+
+		case 11: case 12: /* Delete, Save game */
+			break;
+		}
+		break;
+	case WE_MOUSELOOP:
+		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
+			HandleEditBox(w, &WP(w, querystr_d), 10);
+		}
+		break;
+	case WE_KEYPRESS:
+		if (e->we.keypress.keycode == WKC_ESC) {
+			DeleteWindow(w);
+			return;
+		}
+
+		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
+			if (HandleEditBoxKey(w, &WP(w, querystr_d), 10, e) == 1) /* Press Enter */
+					HandleButtonClick(w, 12);
+		}
+		break;
+	case WE_TIMEOUT:
+		/* This test protects against using widgets 11 and 12 which are only available
+		 * in those two saveload mode  */
+		if (!(_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO)) break;
+
+		if (IsWindowWidgetLowered(w, 11)) { /* Delete button clicked */
+			if (!FiosDelete(WP(w,querystr_d).text.buf)) {
+				ShowErrorMessage(INVALID_STRING_ID, STR_4008_UNABLE_TO_DELETE_FILE, 0, 0);
+			} else {
+				BuildFileList();
+				/* Reset file name to current date on successfull delete */
+				if (_saveload_mode == SLD_SAVE_GAME) GenerateFileName();
+			}
+
+			UpdateTextBufferSize(&WP(w, querystr_d).text);
+			SetWindowDirty(w);
+		} else if (IsWindowWidgetLowered(w, 12)) { /* Save button clicked */
+			_switch_mode = SM_SAVE;
+			FiosMakeSavegameName(_file_to_saveload.name, WP(w,querystr_d).text.buf, sizeof(_file_to_saveload.name));
+
+			/* In the editor set up the vehicle engines correctly (date might have changed) */
+			if (_game_mode == GM_EDITOR) StartupEngines();
+		}
+		break;
+	case WE_DESTROY:
+		// pause is only used in single-player, non-editor mode, non menu mode
+		if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
+			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+		}
+		FiosFreeSavegameList();
+		CLRBIT(_no_scroll, SCROLL_SAVE);
+		break;
+	case WE_RESIZE: {
+		/* Widget 2 and 3 have to go with halve speed, make it so obiwan */
+		uint diff = e->we.sizing.diff.x / 2;
+		w->widget[2].right += diff;
+		w->widget[3].left  += diff;
+		w->widget[3].right += e->we.sizing.diff.x;
+
+		/* Same for widget 11 and 12 in save-dialog */
+		if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
+			w->widget[11].right += diff;
+			w->widget[12].left  += diff;
+			w->widget[12].right += e->we.sizing.diff.x;
+		}
+
+		w->vscroll.cap += e->we.sizing.diff.y / 10;
+		} break;
+	}
+}
+
+static const WindowDesc _load_dialog_desc = {
+	WDP_CENTER, WDP_CENTER, 257, 294,
+	WC_SAVELOAD,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_load_dialog_widgets,
+	SaveLoadDlgWndProc,
+};
+
+static const WindowDesc _save_dialog_desc = {
+	WDP_CENTER, WDP_CENTER, 257, 320,
+	WC_SAVELOAD,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_save_dialog_widgets,
+	SaveLoadDlgWndProc,
+};
+
+void ShowSaveLoadDialog(int mode)
+{
+	static const StringID saveload_captions[] = {
+		STR_4001_LOAD_GAME,
+		STR_0298_LOAD_SCENARIO,
+		STR_4000_SAVE_GAME,
+		STR_0299_SAVE_SCENARIO,
+		STR_4011_LOAD_HEIGHTMAP,
+	};
+
+	Window *w;
+	const WindowDesc *sld = &_save_dialog_desc;
+
+
+	SetObjectToPlace(SPR_CURSOR_ZZZ, 0, 0, 0);
+	DeleteWindowById(WC_QUERY_STRING, 0);
+	DeleteWindowById(WC_SAVELOAD, 0);
+
+	_saveload_mode = mode;
+	SETBIT(_no_scroll, SCROLL_SAVE);
+
+	switch (mode) {
+		case SLD_SAVE_GAME:     GenerateFileName(); break;
+		case SLD_SAVE_SCENARIO: strcpy(_edit_str_buf, "UNNAMED"); break;
+		default:                sld = &_load_dialog_desc; break;
+	}
+
+	assert((uint)mode < lengthof(saveload_captions));
+	w = AllocateWindowDesc(sld);
+	w->widget[1].data = saveload_captions[mode];
+	w->vscroll.cap = 24;
+	w->resize.step_width = 2;
+	w->resize.step_height = 10;
+	w->resize.height = w->height - 14 * 10; // Minimum of 10 items
+	LowerWindowWidget(w, 7);
+
+	WP(w, querystr_d).afilter = CS_ALPHANUMERAL;
+	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 240);
+
+	// pause is only used in single-player, non-editor mode, non-menu mode. It
+	// will be unpaused in the WE_DESTROY event handler.
+	if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) {
+		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+	}
+
+	BuildFileList();
+
+	ResetObjectToPlace();
+}
+
+void RedrawAutosave(void)
+{
+	SetWindowDirty(FindWindowById(WC_STATUS_BAR, 0));
+}
+
+void SetFiosType(const byte fiostype)
+{
+	switch (fiostype) {
+		case FIOS_TYPE_FILE:
+		case FIOS_TYPE_SCENARIO:
+			_file_to_saveload.mode = SL_LOAD;
+			break;
+
+		case FIOS_TYPE_OLDFILE:
+		case FIOS_TYPE_OLD_SCENARIO:
+			_file_to_saveload.mode = SL_OLD_LOAD;
+			break;
+
+#ifdef WITH_PNG
+		case FIOS_TYPE_PNG:
+			_file_to_saveload.mode = SL_PNG;
+			break;
+#endif /* WITH_PNG */
+
+		case FIOS_TYPE_BMP:
+			_file_to_saveload.mode = SL_BMP;
+			break;
+
+		default:
+			_file_to_saveload.mode = SL_INVALID;
+			break;
+	}
+}
+
+static int32 ClickMoneyCheat(int32 p1, int32 p2)
+{
+		DoCommandP(0, -10000000, 0, NULL, CMD_MONEY_CHEAT);
+		return true;
+}
+
+// p1 player to set to, p2 is -1 or +1 (down/up)
+static int32 ClickChangePlayerCheat(int32 p1, int32 p2)
+{
+	while (IsValidPlayer((PlayerID)p1)) {
+		if (_players[p1].is_active) {
+			SetLocalPlayer((PlayerID)p1);
+
+			MarkWholeScreenDirty();
+			return _local_player;
+		}
+		p1 += p2;
+	}
+
+	return _local_player;
+}
+
+// p1 -1 or +1 (down/up)
+static int32 ClickChangeClimateCheat(int32 p1, int32 p2)
+{
+	if (p1 == -1) p1 = 3;
+	if (p1 ==  4) p1 = 0;
+	_opt.landscape = p1;
+	ReloadNewGRFData();
+	return _opt.landscape;
+}
+
+extern void EnginesMonthlyLoop(void);
+
+// p2 1 (increase) or -1 (decrease)
+static int32 ClickChangeDateCheat(int32 p1, int32 p2)
+{
+	YearMonthDay ymd;
+	ConvertDateToYMD(_date, &ymd);
+
+	if ((ymd.year == MIN_YEAR && p2 == -1) || (ymd.year == MAX_YEAR && p2 == 1)) return _cur_year;
+
+	SetDate(ConvertYMDToDate(_cur_year + p2, ymd.month, ymd.day));
+	EnginesMonthlyLoop();
+	SetWindowDirty(FindWindowById(WC_STATUS_BAR, 0));
+	return _cur_year;
+}
+
+typedef int32 CheckButtonClick(int32, int32);
+
+enum ce_flags {CE_CLICK = 1 << 0};
+
+typedef byte ce_flags;
+
+typedef struct CheatEntry {
+	VarType type;          // type of selector
+	ce_flags flags;        // selector flags
+	StringID str;          // string with descriptive text
+	void *variable;        // pointer to the variable
+	bool *been_used;       // has this cheat been used before?
+	CheckButtonClick *proc;// procedure
+	int16 min, max;        // range for spinbox setting
+} CheatEntry;
+
+static const CheatEntry _cheats_ui[] = {
+	{SLE_BOOL,CE_CLICK, STR_CHEAT_MONEY,          &_cheats.money.value,           &_cheats.money.been_used,           &ClickMoneyCheat,         0,  0},
+	{SLE_UINT8,      0, STR_CHEAT_CHANGE_PLAYER,  &_local_player,                 &_cheats.switch_player.been_used,   &ClickChangePlayerCheat,  0, 11},
+	{SLE_BOOL,       0, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, NULL,                     0,  0},
+	{SLE_BOOL,       0, STR_CHEAT_CROSSINGTUNNELS,&_cheats.crossing_tunnels.value,&_cheats.crossing_tunnels.been_used,NULL,                     0,  0},
+	{SLE_BOOL,       0, STR_CHEAT_BUILD_IN_PAUSE, &_cheats.build_in_pause.value,  &_cheats.build_in_pause.been_used,  NULL,                     0,  0},
+	{SLE_BOOL,       0, STR_CHEAT_NO_JETCRASH,    &_cheats.no_jetcrash.value,     &_cheats.no_jetcrash.been_used,     NULL,                     0,  0},
+	{SLE_BOOL,       0, STR_CHEAT_SETUP_PROD,     &_cheats.setup_prod.value,      &_cheats.setup_prod.been_used,      NULL,                     0,  0},
+	{SLE_UINT8,      0, STR_CHEAT_SWITCH_CLIMATE, &_opt.landscape,                &_cheats.switch_climate.been_used,  &ClickChangeClimateCheat,-1,  4},
+	{SLE_INT32,      0, STR_CHEAT_CHANGE_DATE,    &_cur_year,                     &_cheats.change_date.been_used,     &ClickChangeDateCheat,   -1,  1},
+};
+
+
+static const Widget _cheat_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,   STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   399,     0,    13, STR_CHEATS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   399,    14,   169, 0x0,        STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   399,    14,   169, 0x0,        STR_CHEATS_TIP},
+{   WIDGETS_END},
+};
+
+extern void DrawPlayerIcon(PlayerID pid, int x, int y);
+
+static void CheatsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int clk = WP(w,def_d).data_1;
+		int x, y;
+		int i;
+
+		DrawWindowWidgets(w);
+
+		DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, 350);
+
+		x = 0;
+		y = 45;
+
+		for (i = 0; i != lengthof(_cheats_ui); i++) {
+			const CheatEntry *ce = &_cheats_ui[i];
+
+			DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, x + 5, y + 2);
+
+			switch (ce->type) {
+			case SLE_BOOL: {
+				bool on = (*(bool*)ce->variable);
+
+				if (ce->flags & CE_CLICK) {
+					DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, 0, (clk - (i * 2) == 1) ? FR_LOWERED : 0);
+					if (i == 0) { // XXX - hack/hack for first element which is increase money. Told ya it's a mess
+						SetDParam64(0, 10000000);
+					} else {
+						SetDParam(0, false);
+					}
+				} else {
+					DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : 0);
+					SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+				}
+			} break;
+			default: {
+				int32 val = (int32)ReadValue(ce->variable, ce->type);
+				char buf[512];
+
+				/* Draw [<][>] boxes for settings of an integer-type */
+				DrawArrowButtons(x + 20, y, 3, clk - (i * 2), true, true);
+
+				switch (ce->str) {
+				/* Display date for change date cheat */
+				case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
+				/* Draw colored flag for change player cheat */
+				case STR_CHEAT_CHANGE_PLAYER:
+					SetDParam(0, val);
+					GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
+					DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
+					break;
+				/* Set correct string for switch climate cheat */
+				case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
+				/* Fallthrough */
+				default: SetDParam(0, val);
+				}
+			} break;
+			}
+
+			DrawString(50, y + 1, ce->str, 0);
+
+			y += 12;
+		}
+		break;
+	}
+
+	case WE_CLICK: {
+			const CheatEntry *ce;
+			uint btn = (e->we.click.pt.y - 46) / 12;
+			int32 value, oldvalue;
+			uint x = e->we.click.pt.x;
+
+			// not clicking a button?
+			if (!IS_INT_INSIDE(x, 20, 40) || btn >= lengthof(_cheats_ui)) break;
+
+			ce = &_cheats_ui[btn];
+			oldvalue = value = (int32)ReadValue(ce->variable, ce->type);
+
+			*ce->been_used = true;
+
+			switch (ce->type) {
+			case SLE_BOOL:
+				if (ce->flags & CE_CLICK) WP(w,def_d).data_1 = btn * 2 + 1;
+				value ^= 1;
+				if (ce->proc != NULL) ce->proc(value, 0);
+				break;
+			default: {
+				/* Add a dynamic step-size to the scroller. In a maximum of
+				 * 50-steps you should be able to get from min to max */
+				uint16 step = ((ce->max - ce->min) / 20);
+				if (step == 0) step = 1;
+
+				/* Increase or decrease the value and clamp it to extremes */
+				value += (x >= 30) ? step : -step;
+				clamp(value, ce->min, ce->max);
+
+				// take whatever the function returns
+				value = ce->proc(value, (x >= 30) ? 1 : -1);
+
+				if (value != oldvalue) {
+					WP(w,def_d).data_1 = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
+				}
+			} break;
+			}
+
+			if (value != oldvalue) {
+				WriteValue(ce->variable, ce->type, (int64)value);
+				SetWindowDirty(w);
+			}
+
+			w->flags4 |= 5 << WF_TIMEOUT_SHL;
+
+			SetWindowDirty(w);
+		}
+		break;
+	case WE_TIMEOUT:
+		WP(w,def_d).data_1 = 0;
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const WindowDesc _cheats_desc = {
+	240, 22, 400, 170,
+	WC_CHEATS,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_cheat_widgets,
+	CheatsWndProc
+};
+
+
+void ShowCheatWindow(void)
+{
+	DeleteWindowById(WC_CHEATS, 0);
+	AllocateWindowDesc(&_cheats_desc);
+}
deleted file mode 100644
--- a/src/mixer.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "mixer.h"
-
-struct MixerChannel {
-	bool active;
-
-	// pointer to allocated buffer memory
-	int8 *memory;
-
-	// current position in memory
-	uint32 pos;
-	uint32 frac_pos;
-	uint32 frac_speed;
-	uint32 samples_left;
-
-	// Mixing volume
-	uint volume_left;
-	uint volume_right;
-
-	uint flags;
-};
-
-static MixerChannel _channels[8];
-static uint32 _play_rate;
-
-
-static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
-{
-	int8 *b;
-	uint32 frac_pos;
-	uint32 frac_speed;
-	uint volume_left;
-	uint volume_right;
-
-	if (samples > sc->samples_left) samples = sc->samples_left;
-	sc->samples_left -= samples;
-	assert(samples > 0);
-
-	b = sc->memory + sc->pos;
-	frac_pos = sc->frac_pos;
-	frac_speed = sc->frac_speed;
-	volume_left = sc->volume_left;
-	volume_right = sc->volume_right;
-
-	if (frac_speed == 0x10000) {
-		// Special case when frac_speed is 0x10000
-		do {
-			buffer[0] += *b * volume_left >> 8;
-			buffer[1] += *b * volume_right >> 8;
-			b++;
-			buffer += 2;
-		} while (--samples > 0);
-	} else {
-		do {
-			buffer[0] += *b * volume_left >> 8;
-			buffer[1] += *b * volume_right >> 8;
-			buffer += 2;
-			frac_pos += frac_speed;
-			b += frac_pos >> 16;
-			frac_pos &= 0xffff;
-		} while (--samples > 0);
-	}
-
-	sc->frac_pos = frac_pos;
-	sc->pos = b - sc->memory;
-}
-
-static void MxCloseChannel(MixerChannel *mc)
-{
-	if (mc->flags & MX_AUTOFREE) free(mc->memory);
-	mc->active = false;
-	mc->memory = NULL;
-}
-
-void MxMixSamples(void *buffer, uint samples)
-{
-	MixerChannel *mc;
-
-	// Clear the buffer
-	memset(buffer, 0, sizeof(int16) * 2 * samples);
-
-	// Mix each channel
-	for (mc = _channels; mc != endof(_channels); mc++) {
-		if (mc->active) {
-			mix_int8_to_int16(mc, buffer, samples);
-			if (mc->samples_left == 0) MxCloseChannel(mc);
-		}
-	}
-}
-
-MixerChannel *MxAllocateChannel(void)
-{
-	MixerChannel *mc;
-	for (mc = _channels; mc != endof(_channels); mc++)
-		if (mc->memory == NULL) {
-			mc->active = false;
-			return mc;
-		}
-	return NULL;
-}
-
-void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
-{
-	mc->memory = mem;
-	mc->flags = flags;
-	mc->frac_pos = 0;
-	mc->pos = 0;
-
-	mc->frac_speed = (rate << 16) / _play_rate;
-
-	// adjust the magnitude to prevent overflow
-	while (size & 0xFFFF0000) {
-		size >>= 1;
-		rate = (rate >> 1) + 1;
-	}
-
-	mc->samples_left = size * _play_rate / rate;
-}
-
-void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
-{
-	mc->volume_left = left;
-	mc->volume_right = right;
-}
-
-
-void MxActivateChannel(MixerChannel* mc)
-{
-	mc->active = true;
-}
-
-
-bool MxInitialize(uint rate)
-{
-	_play_rate = rate;
-	return true;
-}
new file mode 100644
--- /dev/null
+++ b/src/mixer.cpp
@@ -0,0 +1,140 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "mixer.h"
+
+struct MixerChannel {
+	bool active;
+
+	// pointer to allocated buffer memory
+	int8 *memory;
+
+	// current position in memory
+	uint32 pos;
+	uint32 frac_pos;
+	uint32 frac_speed;
+	uint32 samples_left;
+
+	// Mixing volume
+	uint volume_left;
+	uint volume_right;
+
+	uint flags;
+};
+
+static MixerChannel _channels[8];
+static uint32 _play_rate;
+
+
+static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
+{
+	int8 *b;
+	uint32 frac_pos;
+	uint32 frac_speed;
+	uint volume_left;
+	uint volume_right;
+
+	if (samples > sc->samples_left) samples = sc->samples_left;
+	sc->samples_left -= samples;
+	assert(samples > 0);
+
+	b = sc->memory + sc->pos;
+	frac_pos = sc->frac_pos;
+	frac_speed = sc->frac_speed;
+	volume_left = sc->volume_left;
+	volume_right = sc->volume_right;
+
+	if (frac_speed == 0x10000) {
+		// Special case when frac_speed is 0x10000
+		do {
+			buffer[0] += *b * volume_left >> 8;
+			buffer[1] += *b * volume_right >> 8;
+			b++;
+			buffer += 2;
+		} while (--samples > 0);
+	} else {
+		do {
+			buffer[0] += *b * volume_left >> 8;
+			buffer[1] += *b * volume_right >> 8;
+			buffer += 2;
+			frac_pos += frac_speed;
+			b += frac_pos >> 16;
+			frac_pos &= 0xffff;
+		} while (--samples > 0);
+	}
+
+	sc->frac_pos = frac_pos;
+	sc->pos = b - sc->memory;
+}
+
+static void MxCloseChannel(MixerChannel *mc)
+{
+	if (mc->flags & MX_AUTOFREE) free(mc->memory);
+	mc->active = false;
+	mc->memory = NULL;
+}
+
+void MxMixSamples(void *buffer, uint samples)
+{
+	MixerChannel *mc;
+
+	// Clear the buffer
+	memset(buffer, 0, sizeof(int16) * 2 * samples);
+
+	// Mix each channel
+	for (mc = _channels; mc != endof(_channels); mc++) {
+		if (mc->active) {
+			mix_int8_to_int16(mc, buffer, samples);
+			if (mc->samples_left == 0) MxCloseChannel(mc);
+		}
+	}
+}
+
+MixerChannel *MxAllocateChannel(void)
+{
+	MixerChannel *mc;
+	for (mc = _channels; mc != endof(_channels); mc++)
+		if (mc->memory == NULL) {
+			mc->active = false;
+			return mc;
+		}
+	return NULL;
+}
+
+void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
+{
+	mc->memory = mem;
+	mc->flags = flags;
+	mc->frac_pos = 0;
+	mc->pos = 0;
+
+	mc->frac_speed = (rate << 16) / _play_rate;
+
+	// adjust the magnitude to prevent overflow
+	while (size & 0xFFFF0000) {
+		size >>= 1;
+		rate = (rate >> 1) + 1;
+	}
+
+	mc->samples_left = size * _play_rate / rate;
+}
+
+void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
+{
+	mc->volume_left = left;
+	mc->volume_right = right;
+}
+
+
+void MxActivateChannel(MixerChannel* mc)
+{
+	mc->active = true;
+}
+
+
+bool MxInitialize(uint rate)
+{
+	_play_rate = rate;
+	return true;
+}
deleted file mode 100644
--- a/src/music.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* $Id$ */
-
-#include "music.h"
-
-const SongSpecs origin_songs_specs[NUM_SONGS_AVAILABLE] = {
-	{"gm_tt00.gm", "Tycoon DELUXE Theme"},
-	{"gm_tt02.gm", "Easy Driver"},
-	{"gm_tt03.gm", "Little Red Diesel"},
-	{"gm_tt17.gm", "Cruise Control"},
-	{"gm_tt07.gm", "Don't Walk!"},
-	{"gm_tt09.gm", "Fell Apart On Me"},
-	{"gm_tt04.gm", "City Groove"},
-	{"gm_tt19.gm", "Funk Central"},
-	{"gm_tt06.gm", "Stoke It"},
-	{"gm_tt12.gm", "Road Hog"},
-	{"gm_tt05.gm", "Aliens Ate My Railway"},
-	{"gm_tt01.gm", "Snarl Up"},
-	{"gm_tt18.gm", "Stroll On"},
-	{"gm_tt10.gm", "Can't Get There From Here"},
-	{"gm_tt08.gm", "Sawyer's Tune"},
-	{"gm_tt13.gm", "Hold That Train!"},
-	{"gm_tt21.gm", "Movin' On"},
-	{"gm_tt15.gm", "Goss Groove"},
-	{"gm_tt16.gm", "Small Town"},
-	{"gm_tt14.gm", "Broomer's Oil Rag"},
-	{"gm_tt20.gm", "Jammit"},
-	{"gm_tt11.gm", "Hard Drivin'"},
-};
new file mode 100644
--- /dev/null
+++ b/src/music.cpp
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+#include "music.h"
+
+const SongSpecs origin_songs_specs[NUM_SONGS_AVAILABLE] = {
+	{"gm_tt00.gm", "Tycoon DELUXE Theme"},
+	{"gm_tt02.gm", "Easy Driver"},
+	{"gm_tt03.gm", "Little Red Diesel"},
+	{"gm_tt17.gm", "Cruise Control"},
+	{"gm_tt07.gm", "Don't Walk!"},
+	{"gm_tt09.gm", "Fell Apart On Me"},
+	{"gm_tt04.gm", "City Groove"},
+	{"gm_tt19.gm", "Funk Central"},
+	{"gm_tt06.gm", "Stoke It"},
+	{"gm_tt12.gm", "Road Hog"},
+	{"gm_tt05.gm", "Aliens Ate My Railway"},
+	{"gm_tt01.gm", "Snarl Up"},
+	{"gm_tt18.gm", "Stroll On"},
+	{"gm_tt10.gm", "Can't Get There From Here"},
+	{"gm_tt08.gm", "Sawyer's Tune"},
+	{"gm_tt13.gm", "Hold That Train!"},
+	{"gm_tt21.gm", "Movin' On"},
+	{"gm_tt15.gm", "Goss Groove"},
+	{"gm_tt16.gm", "Small Town"},
+	{"gm_tt14.gm", "Broomer's Oil Rag"},
+	{"gm_tt20.gm", "Jammit"},
+	{"gm_tt11.gm", "Hard Drivin'"},
+};
deleted file mode 100644
--- a/src/music/extmidi.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $Id$ */
-
-#ifndef __MORPHOS__
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../sound.h"
-#include "../string.h"
-#include "../variables.h"
-#include "../debug.h"
-#include "extmidi.h"
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-static struct {
-	char song[MAX_PATH];
-	pid_t pid;
-} _midi;
-
-static void DoPlay(void);
-static void DoStop(void);
-
-static const char* ExtMidiStart(const char* const * parm)
-{
-	_midi.song[0] = '\0';
-	_midi.pid = -1;
-	return NULL;
-}
-
-static void ExtMidiStop(void)
-{
-	_midi.song[0] = '\0';
-	DoStop();
-}
-
-static void ExtMidiPlaySong(const char* filename)
-{
-	ttd_strlcpy(_midi.song, filename, lengthof(_midi.song));
-	DoStop();
-}
-
-static void ExtMidiStopSong(void)
-{
-	_midi.song[0] = '\0';
-	DoStop();
-}
-
-static bool ExtMidiIsPlaying(void)
-{
-	if (_midi.pid != -1 && waitpid(_midi.pid, NULL, WNOHANG) == _midi.pid)
-		_midi.pid = -1;
-	if (_midi.pid == -1 && _midi.song[0] != '\0') DoPlay();
-	return _midi.pid != -1;
-}
-
-static void ExtMidiSetVolume(byte vol)
-{
-	DEBUG(driver, 1, "extmidi: set volume not implemented");
-}
-
-static void DoPlay(void)
-{
-	_midi.pid = fork();
-	switch (_midi.pid) {
-		case 0: {
-			int d;
-
-			close(0);
-			d = open("/dev/null", O_RDONLY);
-			if (d != -1 && dup2(d, 1) != -1 && dup2(d, 2) != -1) {
-				#if defined(MIDI_ARG)
-					execlp(msf.extmidi, "extmidi", MIDI_ARG, _midi.song, (char*)0);
-				#else
-					execlp(msf.extmidi, "extmidi", _midi.song, (char*)0);
-				#endif
-			}
-			_exit(1);
-		}
-
-		case -1:
-			DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno));
-			/* FALLTHROUGH */
-
-		default:
-			_midi.song[0] = '\0';
-			break;
-	}
-}
-
-static void DoStop(void)
-{
-	if (_midi.pid != -1) kill(_midi.pid, SIGTERM);
-}
-
-const HalMusicDriver _extmidi_music_driver = {
-	ExtMidiStart,
-	ExtMidiStop,
-	ExtMidiPlaySong,
-	ExtMidiStopSong,
-	ExtMidiIsPlaying,
-	ExtMidiSetVolume,
-};
-
-#endif /* __MORPHOS__ */
new file mode 100644
--- /dev/null
+++ b/src/music/extmidi.cpp
@@ -0,0 +1,108 @@
+/* $Id$ */
+
+#ifndef __MORPHOS__
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../sound.h"
+#include "../string.h"
+#include "../variables.h"
+#include "../debug.h"
+#include "extmidi.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+static struct {
+	char song[MAX_PATH];
+	pid_t pid;
+} _midi;
+
+static void DoPlay(void);
+static void DoStop(void);
+
+static const char* ExtMidiStart(const char* const * parm)
+{
+	_midi.song[0] = '\0';
+	_midi.pid = -1;
+	return NULL;
+}
+
+static void ExtMidiStop(void)
+{
+	_midi.song[0] = '\0';
+	DoStop();
+}
+
+static void ExtMidiPlaySong(const char* filename)
+{
+	ttd_strlcpy(_midi.song, filename, lengthof(_midi.song));
+	DoStop();
+}
+
+static void ExtMidiStopSong(void)
+{
+	_midi.song[0] = '\0';
+	DoStop();
+}
+
+static bool ExtMidiIsPlaying(void)
+{
+	if (_midi.pid != -1 && waitpid(_midi.pid, NULL, WNOHANG) == _midi.pid)
+		_midi.pid = -1;
+	if (_midi.pid == -1 && _midi.song[0] != '\0') DoPlay();
+	return _midi.pid != -1;
+}
+
+static void ExtMidiSetVolume(byte vol)
+{
+	DEBUG(driver, 1, "extmidi: set volume not implemented");
+}
+
+static void DoPlay(void)
+{
+	_midi.pid = fork();
+	switch (_midi.pid) {
+		case 0: {
+			int d;
+
+			close(0);
+			d = open("/dev/null", O_RDONLY);
+			if (d != -1 && dup2(d, 1) != -1 && dup2(d, 2) != -1) {
+				#if defined(MIDI_ARG)
+					execlp(msf.extmidi, "extmidi", MIDI_ARG, _midi.song, (char*)0);
+				#else
+					execlp(msf.extmidi, "extmidi", _midi.song, (char*)0);
+				#endif
+			}
+			_exit(1);
+		}
+
+		case -1:
+			DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno));
+			/* FALLTHROUGH */
+
+		default:
+			_midi.song[0] = '\0';
+			break;
+	}
+}
+
+static void DoStop(void)
+{
+	if (_midi.pid != -1) kill(_midi.pid, SIGTERM);
+}
+
+const HalMusicDriver _extmidi_music_driver = {
+	ExtMidiStart,
+	ExtMidiStop,
+	ExtMidiPlaySong,
+	ExtMidiStopSong,
+	ExtMidiIsPlaying,
+	ExtMidiSetVolume,
+};
+
+#endif /* __MORPHOS__ */
deleted file mode 100644
--- a/src/music/null_m.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "null_m.h"
-
-static const char* NullMidiStart(const char* const* parm) { return NULL; }
-static void NullMidiStop(void) {}
-static void NullMidiPlaySong(const char *filename) {}
-static void NullMidiStopSong(void) {}
-static bool NullMidiIsSongPlaying(void) { return true; }
-static void NullMidiSetVolume(byte vol) {}
-
-const HalMusicDriver _null_music_driver = {
-	NullMidiStart,
-	NullMidiStop,
-	NullMidiPlaySong,
-	NullMidiStopSong,
-	NullMidiIsSongPlaying,
-	NullMidiSetVolume,
-};
new file mode 100644
--- /dev/null
+++ b/src/music/null_m.cpp
@@ -0,0 +1,21 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "null_m.h"
+
+static const char* NullMidiStart(const char* const* parm) { return NULL; }
+static void NullMidiStop(void) {}
+static void NullMidiPlaySong(const char *filename) {}
+static void NullMidiStopSong(void) {}
+static bool NullMidiIsSongPlaying(void) { return true; }
+static void NullMidiSetVolume(byte vol) {}
+
+const HalMusicDriver _null_music_driver = {
+	NullMidiStart,
+	NullMidiStop,
+	NullMidiPlaySong,
+	NullMidiStopSong,
+	NullMidiIsSongPlaying,
+	NullMidiSetVolume,
+};
deleted file mode 100644
--- a/src/music/os2_m.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "os2_m.h"
-
-#define INCL_DOS
-#define INCL_OS2MM
-#define INCL_WIN
-
-#include <stdarg.h>
-#include <os2.h>
-#include <os2me.h>
-
-/**********************
- * OS/2 MIDI PLAYER
- **********************/
-
-/* Interesting how similar the MCI API in OS/2 is to the Win32 MCI API,
- * eh? Anyone would think they both came from the same place originally! ;)
- */
-
-static long CDECL MidiSendCommand(const char *cmd, ...)
-{
-	va_list va;
-	char buf[512];
-	va_start(va, cmd);
-	vsprintf(buf, cmd, va);
-	va_end(va);
-	return mciSendString(buf, NULL, 0, NULL, 0);
-}
-
-static void OS2MidiPlaySong(const char *filename)
-{
-	MidiSendCommand("close all");
-
-	if (MidiSendCommand("open %s type sequencer alias song", filename) != 0)
-		return;
-
-	MidiSendCommand("play song from 0");
-}
-
-static void OS2MidiStopSong(void)
-{
-	MidiSendCommand("close all");
-}
-
-static void OS2MidiSetVolume(byte vol)
-{
-	MidiSendCommand("set song audio volume %d", ((vol/127)*100));
-}
-
-static bool OS2MidiIsSongPlaying(void)
-{
-	char buf[16];
-	mciSendString("status song mode", buf, sizeof(buf), NULL, 0);
-	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
-}
-
-static const char *OS2MidiStart(const char * const *parm)
-{
-	return 0;
-}
-
-static void OS2MidiStop(void)
-{
-	MidiSendCommand("close all");
-}
-
-const HalMusicDriver _os2_music_driver = {
-	OS2MidiStart,
-	OS2MidiStop,
-	OS2MidiPlaySong,
-	OS2MidiStopSong,
-	OS2MidiIsSongPlaying,
-	OS2MidiSetVolume,
-};
new file mode 100644
--- /dev/null
+++ b/src/music/os2_m.cpp
@@ -0,0 +1,77 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "os2_m.h"
+
+#define INCL_DOS
+#define INCL_OS2MM
+#define INCL_WIN
+
+#include <stdarg.h>
+#include <os2.h>
+#include <os2me.h>
+
+/**********************
+ * OS/2 MIDI PLAYER
+ **********************/
+
+/* Interesting how similar the MCI API in OS/2 is to the Win32 MCI API,
+ * eh? Anyone would think they both came from the same place originally! ;)
+ */
+
+static long CDECL MidiSendCommand(const char *cmd, ...)
+{
+	va_list va;
+	char buf[512];
+	va_start(va, cmd);
+	vsprintf(buf, cmd, va);
+	va_end(va);
+	return mciSendString(buf, NULL, 0, NULL, 0);
+}
+
+static void OS2MidiPlaySong(const char *filename)
+{
+	MidiSendCommand("close all");
+
+	if (MidiSendCommand("open %s type sequencer alias song", filename) != 0)
+		return;
+
+	MidiSendCommand("play song from 0");
+}
+
+static void OS2MidiStopSong(void)
+{
+	MidiSendCommand("close all");
+}
+
+static void OS2MidiSetVolume(byte vol)
+{
+	MidiSendCommand("set song audio volume %d", ((vol/127)*100));
+}
+
+static bool OS2MidiIsSongPlaying(void)
+{
+	char buf[16];
+	mciSendString("status song mode", buf, sizeof(buf), NULL, 0);
+	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
+}
+
+static const char *OS2MidiStart(const char * const *parm)
+{
+	return 0;
+}
+
+static void OS2MidiStop(void)
+{
+	MidiSendCommand("close all");
+}
+
+const HalMusicDriver _os2_music_driver = {
+	OS2MidiStart,
+	OS2MidiStop,
+	OS2MidiPlaySong,
+	OS2MidiStopSong,
+	OS2MidiIsSongPlaying,
+	OS2MidiSetVolume,
+};
deleted file mode 100644
--- a/src/music/qtmidi.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/* $Id$ */
-
-/**
- * @file qtmidi.c
- * @brief MIDI music player for MacOS X using QuickTime.
- *
- * This music player should work in all MacOS X releases starting from 10.0,
- * as QuickTime is an integral part of the system since the old days of the
- * Motorola 68k-based Macintoshes. The only extra dependency apart from
- * QuickTime itself is Carbon, which is included since 10.0 as well.
- *
- * QuickTime gets fooled with the MIDI files from Transport Tycoon Deluxe
- * because of the @c .gm suffix. To force QuickTime to load the MIDI files
- * without the need of dealing with the individual QuickTime components
- * needed to play music (data source, MIDI parser, note allocators,
- * synthesizers and the like) some Carbon functions are used to set the file
- * type as seen by QuickTime, using @c FSpSetFInfo() (which modifies the
- * file's resource fork).
- */
-
-
-/*
- * OpenTTD includes.
- */
-#define  WindowClass OSX_WindowClass
-#include <QuickTime/QuickTime.h>
-#undef   WindowClass
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "qtmidi.h"
-
-/*
- * System includes. We need to workaround with some defines because there's
- * stuff already defined in QuickTime headers.
- */
-#define  OTTD_Random OSX_OTTD_Random
-#undef   OTTD_Random
-#undef   WindowClass
-#undef   SL_ERROR
-#undef   bool
-
-#include <assert.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-// we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2
-#include "../debug.h"
-
-
-enum {
-	midiType = 'Midi' /**< OSType code for MIDI songs. */
-};
-
-
-/**
- * Converts a Unix-like pathname to a @c FSSpec structure which may be
- * used with functions from several MacOS X frameworks (Carbon, QuickTime,
- * etc). The pointed file or directory must exist.
- *
- * @param *path A string containing a Unix-like path.
- * @param *spec Pointer to a @c FSSpec structure where the result will be
- *              stored.
- * @return Wether the conversion was successful.
- */
-static bool PathToFSSpec(const char *path, FSSpec *spec)
-{
-	FSRef ref;
-	assert(spec != NULL);
-	assert(path != NULL);
-
-	return
-		FSPathMakeRef((UInt8*)path, &ref, NULL) == noErr &&
-		FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL) == noErr;
-}
-
-
-/**
- * Sets the @c OSType of a given file to @c 'Midi', but only if it's not
- * already set.
- *
- * @param *spec A @c FSSpec structure referencing a file.
- */
-static void SetMIDITypeIfNeeded(const FSSpec *spec)
-{
-	FSRef ref;
-	FSCatalogInfo catalogInfo;
-
-	assert(spec);
-
-	if (noErr != FSpMakeFSRef(spec, &ref)) return;
-	if (noErr != FSGetCatalogInfo(&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
-	if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
-		FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
-		if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) {
-			OSErr e;
-			info->fileType = midiType;
-			e = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo);
-			if (e == noErr) {
-				DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
-			} else {
-				DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
-			}
-		}
-	}
-}
-
-
-/**
- * Loads a MIDI file and returns it as a QuickTime Movie structure.
- *
- * @param *path String with the path of an existing MIDI file.
- * @param *moov Pointer to a @c Movie where the result will be stored.
- * @return Wether the file was loaded and the @c Movie successfully created.
- */
-static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
-{
-	int fd;
-	int ret;
-	char magic[4];
-	FSSpec fsspec;
-	short refnum = 0;
-	short resid  = 0;
-
-	assert(path != NULL);
-	assert(moov != NULL);
-
-	DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
-
-	/*
-	 * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
-	 * QuickTime load MIDI files without a .mid suffix without knowing it's
-	 * a MIDI file and setting the OSType of the file to the 'Midi' value.
-	 * Perhahaps ugly, but it seems that it does the Right Thing(tm).
-	 */
-	fd = open(path, O_RDONLY, 0);
-	if (fd == -1) return false;
-	ret = read(fd, magic, 4);
-	close(fd);
-	if (ret < 4) return false;
-
-	DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
-	if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd')
-		return false;
-
-	if (!PathToFSSpec(path, &fsspec)) return false;
-	SetMIDITypeIfNeeded(&fsspec);
-
-	if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
-	DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
-
-	if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
-				newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
-		CloseMovieFile(refnum);
-		return false;
-	}
-	DEBUG(driver, 3, "qtmidi: movie container created");
-
-	CloseMovieFile(refnum);
-	return true;
-}
-
-
-/**
- * Flag which has the @c true value when QuickTime is available and
- * initialized.
- */
-static bool _quicktime_started = false;
-
-
-/**
- * Initialize QuickTime if needed. This function sets the
- * #_quicktime_started flag to @c true if QuickTime is present in the system
- * and it was initialized properly.
- */
-static void InitQuickTimeIfNeeded(void)
-{
-	OSStatus dummy;
-
-	if (_quicktime_started) return;
-
-	DEBUG(driver, 2, "qtmidi: initializing Quicktime");
-	/* Be polite: check wether QuickTime is available and initialize it. */
-	_quicktime_started =
-		(noErr == Gestalt(gestaltQuickTime, &dummy)) &&
-		(noErr == EnterMovies());
-	if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
-}
-
-
-/** Possible states of the QuickTime music driver. */
-enum {
-	QT_STATE_IDLE, /**< No file loaded. */
-	QT_STATE_PLAY, /**< File loaded, playing. */
-	QT_STATE_STOP, /**< File loaded, stopped. */
-};
-
-
-static Movie _quicktime_movie;                  /**< Current QuickTime @c Movie. */
-static byte  _quicktime_volume = 127;           /**< Current volume. */
-static int   _quicktime_state  = QT_STATE_IDLE; /**< Current player state. */
-
-
-/**
- * Maps OpenTTD volume to QuickTime notion of volume.
- */
-#define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
-
-
-static void StopSong(void);
-
-
-/**
- * Initialized the MIDI player, including QuickTime initialization.
- *
- * @todo Give better error messages by inspecting error codes returned by
- * @c Gestalt() and @c EnterMovies(). Needs changes in
- * #InitQuickTimeIfNeeded.
- */
-static const char* StartDriver(const char * const *parm)
-{
-	InitQuickTimeIfNeeded();
-	return (_quicktime_started) ? NULL : "can't initialize QuickTime";
-}
-
-
-/**
- * Checks wether the player is active.
- *
- * This function is called at regular intervals from OpenTTD's main loop, so
- * we call @c MoviesTask() from here to let QuickTime do its work.
- */
-static bool SongIsPlaying(void)
-{
-	if (!_quicktime_started) return true;
-
-	switch (_quicktime_state) {
-		case QT_STATE_IDLE:
-		case QT_STATE_STOP:
-			/* Do nothing. */
-			break;
-		case QT_STATE_PLAY:
-			MoviesTask(_quicktime_movie, 0);
-			/* Check wether movie ended. */
-			if (IsMovieDone(_quicktime_movie) ||
-					(GetMovieTime(_quicktime_movie, NULL) >=
-					 GetMovieDuration(_quicktime_movie)))
-				_quicktime_state = QT_STATE_STOP;
-	}
-
-	return _quicktime_state == QT_STATE_PLAY;
-}
-
-
-/**
- * Stops the MIDI player.
- *
- * Stops playing and frees any used resources before returning. As it
- * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false.
- */
-static void StopDriver(void)
-{
-	if (!_quicktime_started) return;
-
-	DEBUG(driver, 2, "qtmidi: stopping driver...");
-	switch (_quicktime_state) {
-		case QT_STATE_IDLE:
-			DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
-			/* Do nothing. */
-			break;
-		case QT_STATE_PLAY:
-			StopSong();
-		case QT_STATE_STOP:
-			DisposeMovie(_quicktime_movie);
-	}
-
-	ExitMovies();
-	_quicktime_started = false;
-}
-
-
-/**
- * Starts playing a new song.
- *
- * @param filename Path to a MIDI file.
- */
-static void PlaySong(const char *filename)
-{
-	if (!_quicktime_started) return;
-
-	DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename);
-	switch (_quicktime_state) {
-		case QT_STATE_PLAY:
-			StopSong();
-			DEBUG(driver, 3, "qtmidi: previous tune stopped");
-			/* XXX Fall-through -- no break needed. */
-		case QT_STATE_STOP:
-			DisposeMovie(_quicktime_movie);
-			DEBUG(driver, 3, "qtmidi: previous tune disposed");
-			_quicktime_state = QT_STATE_IDLE;
-			/* XXX Fall-through -- no break needed. */
-		case QT_STATE_IDLE:
-			LoadMovieForMIDIFile(filename, &_quicktime_movie);
-			SetMovieVolume(_quicktime_movie, VOLUME);
-			StartMovie(_quicktime_movie);
-			_quicktime_state = QT_STATE_PLAY;
-	}
-	DEBUG(driver, 3, "qtmidi: playing '%s'", filename);
-}
-
-
-/**
- * Stops playing the current song, if the player is active.
- */
-static void StopSong(void)
-{
-	if (!_quicktime_started) return;
-
-	switch (_quicktime_state) {
-		case QT_STATE_IDLE:
-			/* XXX Fall-through -- no break needed. */
-		case QT_STATE_STOP:
-			DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
-			/* Do nothing. */
-			break;
-		case QT_STATE_PLAY:
-			StopMovie(_quicktime_movie);
-			_quicktime_state = QT_STATE_STOP;
-			DEBUG(driver, 3, "qtmidi: player stopped");
-	}
-}
-
-
-/**
- * Changes the playing volume of the MIDI player.
- *
- * As QuickTime controls volume in a per-movie basis, the desired volume is
- * stored in #_quicktime_volume, and the volume is set here using the
- * #VOLUME macro, @b and when loading new song in #PlaySong.
- *
- * @param vol The desired volume, range of the value is @c 0-127
- */
-static void SetVolume(byte vol)
-{
-	if (!_quicktime_started) return;
-
-	_quicktime_volume = vol;
-
-	DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME);
-	switch (_quicktime_state) {
-		case QT_STATE_IDLE:
-			/* Do nothing. */
-			break;
-		case QT_STATE_PLAY:
-		case QT_STATE_STOP:
-			SetMovieVolume(_quicktime_movie, VOLUME);
-	}
-}
-
-
-/**
- * Table of callbacks that implement the QuickTime MIDI player.
- */
-const HalMusicDriver _qtime_music_driver = {
-	StartDriver,
-	StopDriver,
-	PlaySong,
-	StopSong,
-	SongIsPlaying,
-	SetVolume,
-};
new file mode 100644
--- /dev/null
+++ b/src/music/qtmidi.cpp
@@ -0,0 +1,371 @@
+/* $Id$ */
+
+/**
+ * @file qtmidi.c
+ * @brief MIDI music player for MacOS X using QuickTime.
+ *
+ * This music player should work in all MacOS X releases starting from 10.0,
+ * as QuickTime is an integral part of the system since the old days of the
+ * Motorola 68k-based Macintoshes. The only extra dependency apart from
+ * QuickTime itself is Carbon, which is included since 10.0 as well.
+ *
+ * QuickTime gets fooled with the MIDI files from Transport Tycoon Deluxe
+ * because of the @c .gm suffix. To force QuickTime to load the MIDI files
+ * without the need of dealing with the individual QuickTime components
+ * needed to play music (data source, MIDI parser, note allocators,
+ * synthesizers and the like) some Carbon functions are used to set the file
+ * type as seen by QuickTime, using @c FSpSetFInfo() (which modifies the
+ * file's resource fork).
+ */
+
+
+/*
+ * OpenTTD includes.
+ */
+#define  WindowClass OSX_WindowClass
+#include <QuickTime/QuickTime.h>
+#undef   WindowClass
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "qtmidi.h"
+
+/*
+ * System includes. We need to workaround with some defines because there's
+ * stuff already defined in QuickTime headers.
+ */
+#define  OTTD_Random OSX_OTTD_Random
+#undef   OTTD_Random
+#undef   WindowClass
+#undef   SL_ERROR
+#undef   bool
+
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+// we need to include debug.h after CoreServices because defining DEBUG will break CoreServices in OSX 10.2
+#include "../debug.h"
+
+
+enum {
+	midiType = 'Midi' /**< OSType code for MIDI songs. */
+};
+
+
+/**
+ * Converts a Unix-like pathname to a @c FSSpec structure which may be
+ * used with functions from several MacOS X frameworks (Carbon, QuickTime,
+ * etc). The pointed file or directory must exist.
+ *
+ * @param *path A string containing a Unix-like path.
+ * @param *spec Pointer to a @c FSSpec structure where the result will be
+ *              stored.
+ * @return Wether the conversion was successful.
+ */
+static bool PathToFSSpec(const char *path, FSSpec *spec)
+{
+	FSRef ref;
+	assert(spec != NULL);
+	assert(path != NULL);
+
+	return
+		FSPathMakeRef((UInt8*)path, &ref, NULL) == noErr &&
+		FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL) == noErr;
+}
+
+
+/**
+ * Sets the @c OSType of a given file to @c 'Midi', but only if it's not
+ * already set.
+ *
+ * @param *spec A @c FSSpec structure referencing a file.
+ */
+static void SetMIDITypeIfNeeded(const FSSpec *spec)
+{
+	FSRef ref;
+	FSCatalogInfo catalogInfo;
+
+	assert(spec);
+
+	if (noErr != FSpMakeFSRef(spec, &ref)) return;
+	if (noErr != FSGetCatalogInfo(&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return;
+	if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
+		FileInfo * const info = (FileInfo *) catalogInfo.finderInfo;
+		if (info->fileType != midiType && !(info->finderFlags & kIsAlias)) {
+			OSErr e;
+			info->fileType = midiType;
+			e = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo);
+			if (e == noErr) {
+				DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'");
+			} else {
+				DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e);
+			}
+		}
+	}
+}
+
+
+/**
+ * Loads a MIDI file and returns it as a QuickTime Movie structure.
+ *
+ * @param *path String with the path of an existing MIDI file.
+ * @param *moov Pointer to a @c Movie where the result will be stored.
+ * @return Wether the file was loaded and the @c Movie successfully created.
+ */
+static bool LoadMovieForMIDIFile(const char *path, Movie *moov)
+{
+	int fd;
+	int ret;
+	char magic[4];
+	FSSpec fsspec;
+	short refnum = 0;
+	short resid  = 0;
+
+	assert(path != NULL);
+	assert(moov != NULL);
+
+	DEBUG(driver, 2, "qtmidi: start loading '%s'...", path);
+
+	/*
+	 * XXX Manual check for MIDI header ('MThd'), as I don't know how to make
+	 * QuickTime load MIDI files without a .mid suffix without knowing it's
+	 * a MIDI file and setting the OSType of the file to the 'Midi' value.
+	 * Perhahaps ugly, but it seems that it does the Right Thing(tm).
+	 */
+	fd = open(path, O_RDONLY, 0);
+	if (fd == -1) return false;
+	ret = read(fd, magic, 4);
+	close(fd);
+	if (ret < 4) return false;
+
+	DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic);
+	if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd')
+		return false;
+
+	if (!PathToFSSpec(path, &fsspec)) return false;
+	SetMIDITypeIfNeeded(&fsspec);
+
+	if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false;
+	DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path);
+
+	if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL,
+				newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) {
+		CloseMovieFile(refnum);
+		return false;
+	}
+	DEBUG(driver, 3, "qtmidi: movie container created");
+
+	CloseMovieFile(refnum);
+	return true;
+}
+
+
+/**
+ * Flag which has the @c true value when QuickTime is available and
+ * initialized.
+ */
+static bool _quicktime_started = false;
+
+
+/**
+ * Initialize QuickTime if needed. This function sets the
+ * #_quicktime_started flag to @c true if QuickTime is present in the system
+ * and it was initialized properly.
+ */
+static void InitQuickTimeIfNeeded(void)
+{
+	OSStatus dummy;
+
+	if (_quicktime_started) return;
+
+	DEBUG(driver, 2, "qtmidi: initializing Quicktime");
+	/* Be polite: check wether QuickTime is available and initialize it. */
+	_quicktime_started =
+		(noErr == Gestalt(gestaltQuickTime, &dummy)) &&
+		(noErr == EnterMovies());
+	if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!");
+}
+
+
+/** Possible states of the QuickTime music driver. */
+enum {
+	QT_STATE_IDLE, /**< No file loaded. */
+	QT_STATE_PLAY, /**< File loaded, playing. */
+	QT_STATE_STOP, /**< File loaded, stopped. */
+};
+
+
+static Movie _quicktime_movie;                  /**< Current QuickTime @c Movie. */
+static byte  _quicktime_volume = 127;           /**< Current volume. */
+static int   _quicktime_state  = QT_STATE_IDLE; /**< Current player state. */
+
+
+/**
+ * Maps OpenTTD volume to QuickTime notion of volume.
+ */
+#define VOLUME  ((short)((0x00FF & _quicktime_volume) << 1))
+
+
+static void StopSong(void);
+
+
+/**
+ * Initialized the MIDI player, including QuickTime initialization.
+ *
+ * @todo Give better error messages by inspecting error codes returned by
+ * @c Gestalt() and @c EnterMovies(). Needs changes in
+ * #InitQuickTimeIfNeeded.
+ */
+static const char* StartDriver(const char * const *parm)
+{
+	InitQuickTimeIfNeeded();
+	return (_quicktime_started) ? NULL : "can't initialize QuickTime";
+}
+
+
+/**
+ * Checks wether the player is active.
+ *
+ * This function is called at regular intervals from OpenTTD's main loop, so
+ * we call @c MoviesTask() from here to let QuickTime do its work.
+ */
+static bool SongIsPlaying(void)
+{
+	if (!_quicktime_started) return true;
+
+	switch (_quicktime_state) {
+		case QT_STATE_IDLE:
+		case QT_STATE_STOP:
+			/* Do nothing. */
+			break;
+		case QT_STATE_PLAY:
+			MoviesTask(_quicktime_movie, 0);
+			/* Check wether movie ended. */
+			if (IsMovieDone(_quicktime_movie) ||
+					(GetMovieTime(_quicktime_movie, NULL) >=
+					 GetMovieDuration(_quicktime_movie)))
+				_quicktime_state = QT_STATE_STOP;
+	}
+
+	return _quicktime_state == QT_STATE_PLAY;
+}
+
+
+/**
+ * Stops the MIDI player.
+ *
+ * Stops playing and frees any used resources before returning. As it
+ * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false.
+ */
+static void StopDriver(void)
+{
+	if (!_quicktime_started) return;
+
+	DEBUG(driver, 2, "qtmidi: stopping driver...");
+	switch (_quicktime_state) {
+		case QT_STATE_IDLE:
+			DEBUG(driver, 3, "qtmidi: stopping not needed, already idle");
+			/* Do nothing. */
+			break;
+		case QT_STATE_PLAY:
+			StopSong();
+		case QT_STATE_STOP:
+			DisposeMovie(_quicktime_movie);
+	}
+
+	ExitMovies();
+	_quicktime_started = false;
+}
+
+
+/**
+ * Starts playing a new song.
+ *
+ * @param filename Path to a MIDI file.
+ */
+static void PlaySong(const char *filename)
+{
+	if (!_quicktime_started) return;
+
+	DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename);
+	switch (_quicktime_state) {
+		case QT_STATE_PLAY:
+			StopSong();
+			DEBUG(driver, 3, "qtmidi: previous tune stopped");
+			/* XXX Fall-through -- no break needed. */
+		case QT_STATE_STOP:
+			DisposeMovie(_quicktime_movie);
+			DEBUG(driver, 3, "qtmidi: previous tune disposed");
+			_quicktime_state = QT_STATE_IDLE;
+			/* XXX Fall-through -- no break needed. */
+		case QT_STATE_IDLE:
+			LoadMovieForMIDIFile(filename, &_quicktime_movie);
+			SetMovieVolume(_quicktime_movie, VOLUME);
+			StartMovie(_quicktime_movie);
+			_quicktime_state = QT_STATE_PLAY;
+	}
+	DEBUG(driver, 3, "qtmidi: playing '%s'", filename);
+}
+
+
+/**
+ * Stops playing the current song, if the player is active.
+ */
+static void StopSong(void)
+{
+	if (!_quicktime_started) return;
+
+	switch (_quicktime_state) {
+		case QT_STATE_IDLE:
+			/* XXX Fall-through -- no break needed. */
+		case QT_STATE_STOP:
+			DEBUG(driver, 3, "qtmidi: stop requested, but already idle");
+			/* Do nothing. */
+			break;
+		case QT_STATE_PLAY:
+			StopMovie(_quicktime_movie);
+			_quicktime_state = QT_STATE_STOP;
+			DEBUG(driver, 3, "qtmidi: player stopped");
+	}
+}
+
+
+/**
+ * Changes the playing volume of the MIDI player.
+ *
+ * As QuickTime controls volume in a per-movie basis, the desired volume is
+ * stored in #_quicktime_volume, and the volume is set here using the
+ * #VOLUME macro, @b and when loading new song in #PlaySong.
+ *
+ * @param vol The desired volume, range of the value is @c 0-127
+ */
+static void SetVolume(byte vol)
+{
+	if (!_quicktime_started) return;
+
+	_quicktime_volume = vol;
+
+	DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME);
+	switch (_quicktime_state) {
+		case QT_STATE_IDLE:
+			/* Do nothing. */
+			break;
+		case QT_STATE_PLAY:
+		case QT_STATE_STOP:
+			SetMovieVolume(_quicktime_movie, VOLUME);
+	}
+}
+
+
+/**
+ * Table of callbacks that implement the QuickTime MIDI player.
+ */
+const HalMusicDriver _qtime_music_driver = {
+	StartDriver,
+	StopDriver,
+	PlaySong,
+	StopSong,
+	SongIsPlaying,
+	SetVolume,
+};
deleted file mode 100644
--- a/src/music/win32_m.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "win32_m.h"
-#include <windows.h>
-#include <mmsystem.h>
-
-static struct {
-	bool stop_song;
-	bool terminate;
-	bool playing;
-	int new_vol;
-	HANDLE wait_obj;
-	UINT_PTR devid;
-	char start_song[260];
-} _midi;
-
-static void Win32MidiPlaySong(const char *filename)
-{
-	strcpy(_midi.start_song, filename);
-	_midi.playing = true;
-	_midi.stop_song = false;
-	SetEvent(_midi.wait_obj);
-}
-
-static void Win32MidiStopSong(void)
-{
-	if (_midi.playing) {
-		_midi.stop_song = true;
-		_midi.start_song[0] = '\0';
-		SetEvent(_midi.wait_obj);
-	}
-}
-
-static bool Win32MidiIsSongPlaying(void)
-{
-	return _midi.playing;
-}
-
-static void Win32MidiSetVolume(byte vol)
-{
-	_midi.new_vol = vol;
-	SetEvent(_midi.wait_obj);
-}
-
-static MCIERROR CDECL MidiSendCommand(const char* cmd, ...)
-{
-	va_list va;
-	char buf[512];
-
-	va_start(va, cmd);
-	vsprintf(buf, cmd, va);
-	va_end(va);
-	return mciSendStringA(buf, NULL, 0, 0);
-}
-
-static bool MidiIntPlaySong(const char *filename)
-{
-	MidiSendCommand("close all");
-	if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0)
-		return false;
-
-	if (MidiSendCommand("play song from 0") != 0)
-		return false;
-	return true;
-}
-
-static void MidiIntStopSong(void)
-{
-	MidiSendCommand("close all");
-}
-
-static void MidiIntSetVolume(int vol)
-{
-	DWORD v = (vol * 65535 / 127);
-	midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
-}
-
-static bool MidiIntIsSongPlaying(void)
-{
-	char buf[16];
-	mciSendStringA("status song mode", buf, sizeof(buf), 0);
-	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
-}
-
-static DWORD WINAPI MidiThread(LPVOID arg)
-{
-	_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL);
-
-	do {
-		char *s;
-		int vol;
-
-		vol = _midi.new_vol;
-		if (vol != -1) {
-			_midi.new_vol = -1;
-			MidiIntSetVolume(vol);
-		}
-
-		s = _midi.start_song;
-		if (s[0] != '\0') {
-			_midi.playing = MidiIntPlaySong(s);
-			s[0] = '\0';
-
-			// Delay somewhat in case we don't manage to play.
-			if (!_midi.playing) {
-				Sleep(5000);
-			}
-		}
-
-		if (_midi.stop_song && _midi.playing) {
-			_midi.stop_song = false;
-			_midi.playing = false;
-			MidiIntStopSong();
-		}
-
-		if (_midi.playing && !MidiIntIsSongPlaying())
-			_midi.playing = false;
-
-		WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
-	} while (!_midi.terminate);
-
-	DeleteObject(_midi.wait_obj);
-	return 0;
-}
-
-static const char *Win32MidiStart(const char * const *parm)
-{
-	MIDIOUTCAPS midicaps;
-	DWORD threadId;
-	UINT nbdev;
-	UINT_PTR dev;
-	char buf[16];
-
-	mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
-	if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
-
-	memset(&_midi, 0, sizeof(_midi));
-	_midi.new_vol = -1;
-
-	/* Get midi device */
-	_midi.devid = MIDI_MAPPER;
-	for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
-		if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
-			_midi.devid = dev;
-			break;
-		}
-	}
-
-	if (CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId) == NULL)
-		return "Failed to create thread";
-
-	return NULL;
-}
-
-static void Win32MidiStop(void)
-{
-	_midi.terminate = true;
-	SetEvent(_midi.wait_obj);
-}
-
-const HalMusicDriver _win32_music_driver = {
-	Win32MidiStart,
-	Win32MidiStop,
-	Win32MidiPlaySong,
-	Win32MidiStopSong,
-	Win32MidiIsSongPlaying,
-	Win32MidiSetVolume,
-};
new file mode 100644
--- /dev/null
+++ b/src/music/win32_m.cpp
@@ -0,0 +1,170 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "win32_m.h"
+#include <windows.h>
+#include <mmsystem.h>
+
+static struct {
+	bool stop_song;
+	bool terminate;
+	bool playing;
+	int new_vol;
+	HANDLE wait_obj;
+	UINT_PTR devid;
+	char start_song[260];
+} _midi;
+
+static void Win32MidiPlaySong(const char *filename)
+{
+	strcpy(_midi.start_song, filename);
+	_midi.playing = true;
+	_midi.stop_song = false;
+	SetEvent(_midi.wait_obj);
+}
+
+static void Win32MidiStopSong(void)
+{
+	if (_midi.playing) {
+		_midi.stop_song = true;
+		_midi.start_song[0] = '\0';
+		SetEvent(_midi.wait_obj);
+	}
+}
+
+static bool Win32MidiIsSongPlaying(void)
+{
+	return _midi.playing;
+}
+
+static void Win32MidiSetVolume(byte vol)
+{
+	_midi.new_vol = vol;
+	SetEvent(_midi.wait_obj);
+}
+
+static MCIERROR CDECL MidiSendCommand(const char* cmd, ...)
+{
+	va_list va;
+	char buf[512];
+
+	va_start(va, cmd);
+	vsprintf(buf, cmd, va);
+	va_end(va);
+	return mciSendStringA(buf, NULL, 0, 0);
+}
+
+static bool MidiIntPlaySong(const char *filename)
+{
+	MidiSendCommand("close all");
+	if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0)
+		return false;
+
+	if (MidiSendCommand("play song from 0") != 0)
+		return false;
+	return true;
+}
+
+static void MidiIntStopSong(void)
+{
+	MidiSendCommand("close all");
+}
+
+static void MidiIntSetVolume(int vol)
+{
+	DWORD v = (vol * 65535 / 127);
+	midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16));
+}
+
+static bool MidiIntIsSongPlaying(void)
+{
+	char buf[16];
+	mciSendStringA("status song mode", buf, sizeof(buf), 0);
+	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
+}
+
+static DWORD WINAPI MidiThread(LPVOID arg)
+{
+	_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	do {
+		char *s;
+		int vol;
+
+		vol = _midi.new_vol;
+		if (vol != -1) {
+			_midi.new_vol = -1;
+			MidiIntSetVolume(vol);
+		}
+
+		s = _midi.start_song;
+		if (s[0] != '\0') {
+			_midi.playing = MidiIntPlaySong(s);
+			s[0] = '\0';
+
+			// Delay somewhat in case we don't manage to play.
+			if (!_midi.playing) {
+				Sleep(5000);
+			}
+		}
+
+		if (_midi.stop_song && _midi.playing) {
+			_midi.stop_song = false;
+			_midi.playing = false;
+			MidiIntStopSong();
+		}
+
+		if (_midi.playing && !MidiIntIsSongPlaying())
+			_midi.playing = false;
+
+		WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000);
+	} while (!_midi.terminate);
+
+	DeleteObject(_midi.wait_obj);
+	return 0;
+}
+
+static const char *Win32MidiStart(const char * const *parm)
+{
+	MIDIOUTCAPS midicaps;
+	DWORD threadId;
+	UINT nbdev;
+	UINT_PTR dev;
+	char buf[16];
+
+	mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0);
+	if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio";
+
+	memset(&_midi, 0, sizeof(_midi));
+	_midi.new_vol = -1;
+
+	/* Get midi device */
+	_midi.devid = MIDI_MAPPER;
+	for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) {
+		if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) {
+			_midi.devid = dev;
+			break;
+		}
+	}
+
+	if (CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId) == NULL)
+		return "Failed to create thread";
+
+	return NULL;
+}
+
+static void Win32MidiStop(void)
+{
+	_midi.terminate = true;
+	SetEvent(_midi.wait_obj);
+}
+
+const HalMusicDriver _win32_music_driver = {
+	Win32MidiStart,
+	Win32MidiStop,
+	Win32MidiPlaySong,
+	Win32MidiStopSong,
+	Win32MidiIsSongPlaying,
+	Win32MidiSetVolume,
+};
deleted file mode 100644
--- a/src/music_gui.c
+++ /dev/null
@@ -1,506 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "functions.h"
-#include "window.h"
-#include "gfx.h"
-#include "sound.h"
-#include "hal.h"
-#include "macros.h"
-#include "variables.h"
-#include "music.h"
-
-static byte _music_wnd_cursong;
-static bool _song_is_active;
-static byte _cur_playlist[NUM_SONGS_PLAYLIST];
-
-
-
-static byte _playlist_all[] = {
-	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0
-};
-
-static byte _playlist_old_style[] = {
-	1, 8, 2, 9, 14, 15, 19, 13, 0
-};
-
-static byte _playlist_new_style[] = {
-	6, 11, 10, 17, 21, 18, 5, 0
-};
-
-static byte _playlist_ezy_street[] = {
-	12, 7, 16, 3, 20, 4, 0
-};
-
-static byte * const _playlists[] = {
-	_playlist_all,
-	_playlist_old_style,
-	_playlist_new_style,
-	_playlist_ezy_street,
-	msf.custom_1,
-	msf.custom_2,
-};
-
-static void SkipToPrevSong(void)
-{
-	byte *b = _cur_playlist;
-	byte *p = b;
-	byte t;
-
-	if (b[0] == 0) return; // empty playlist
-
-	do p++; while (p[0] != 0); // find the end
-
-	t = *--p; // and copy the bytes
-	while (p != b) {
-		p--;
-		p[1] = p[0];
-	}
-	*b = t;
-
-	_song_is_active = false;
-}
-
-static void SkipToNextSong(void)
-{
-	byte* b = _cur_playlist;
-	byte t;
-
-	t = b[0];
-	if (t != 0) {
-		while (b[1] != 0) {
-			b[0] = b[1];
-			b++;
-		}
-		b[0] = t;
-	}
-
-	_song_is_active = false;
-}
-
-static void MusicVolumeChanged(byte new_vol)
-{
-	_music_driver->set_volume(new_vol);
-}
-
-static void DoPlaySong(void)
-{
-	char filename[256];
-	snprintf(filename, sizeof(filename), "%s%s",
-		_paths.gm_dir, origin_songs_specs[_music_wnd_cursong - 1].filename);
-	_music_driver->play_song(filename);
-}
-
-static void DoStopMusic(void)
-{
-	_music_driver->stop_song();
-}
-
-static void SelectSongToPlay(void)
-{
-	uint i = 0;
-	uint j = 0;
-	char filename[256];
-
-	memset(_cur_playlist, 0, sizeof(_cur_playlist));
-	do {
-		if (_playlists[msf.playlist][i] != 0) {  // Don't evaluate playlist terminator
-			snprintf(filename, sizeof(filename),  "%s%s",
-				_paths.gm_dir, origin_songs_specs[(_playlists[msf.playlist][i]) - 1].filename);
-
-			/* we are now checking for the existence of that file prior
-			 * to add it to the list of available songs */
-			if (FileExists(filename)) {
-				_cur_playlist[j] = _playlists[msf.playlist][i];
-				j++;
-			}
-		}
-	} while (_playlists[msf.playlist][i++] != 0 && i < lengthof(_cur_playlist) - 1);
-
-	if (msf.shuffle) {
-		i = 500;
-		do {
-			uint32 r = InteractiveRandom();
-			byte *a = &_cur_playlist[GB(r, 0, 5)];
-			byte *b = &_cur_playlist[GB(r, 8, 5)];
-
-			if (*a != 0 && *b != 0) {
-				byte t = *a;
-				*a = *b;
-				*b = t;
-			}
-		} while (--i);
-	}
-}
-
-static void StopMusic(void)
-{
-	_music_wnd_cursong = 0;
-	DoStopMusic();
-	_song_is_active = false;
-	InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
-}
-
-static void PlayPlaylistSong(void)
-{
-	if (_cur_playlist[0] == 0) {
-		SelectSongToPlay();
-		/* if there is not songs in the playlist, it may indicate
-		 * no file on the gm folder, or even no gm folder.
-		 * Stop the playback, then */
-		if (_cur_playlist[0] == 0) {
-			_song_is_active = false;
-			_music_wnd_cursong = 0;
-			msf.playing = false;
-			return;
-		}
-	}
-	_music_wnd_cursong = _cur_playlist[0];
-	DoPlaySong();
-	_song_is_active = true;
-
-	InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
-}
-
-void ResetMusic(void)
-{
-	_music_wnd_cursong = 1;
-	DoPlaySong();
-}
-
-void MusicLoop(void)
-{
-	if (!msf.playing && _song_is_active) {
-		StopMusic();
-	} else if (msf.playing && !_song_is_active) {
-		PlayPlaylistSong();
-	}
-
-	if (!_song_is_active) return;
-
-	if (!_music_driver->is_song_playing()) {
-		if (_game_mode != GM_MENU) {
-			StopMusic();
-			SkipToNextSong();
-			PlayPlaylistSong();
-		} else {
-			ResetMusic();
-		}
-	}
-}
-
-static void MusicTrackSelectionWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const byte* p;
-		uint i;
-		int y;
-
-		SetWindowWidgetDisabledState(w, 11, msf.playlist <= 3);
-		LowerWindowWidget(w, 3);
-		LowerWindowWidget(w, 4);
-		DrawWindowWidgets(w);
-
-		GfxFillRect(3, 23, 3+177,23+191,0);
-		GfxFillRect(251, 23, 251+177,23+191,0);
-
-		DrawStringCentered(92, 15, STR_01EE_TRACK_INDEX, 0);
-
-		SetDParam(0, STR_01D5_ALL + msf.playlist);
-		DrawStringCentered(340, 15, STR_01EF_PROGRAM, 0);
-
-		for (i = 1; i <= NUM_SONGS_AVAILABLE; i++) {
-			SetDParam(0, i);
-			SetDParam(2, i);
-			SetDParam(1, SPECSTR_SONGNAME);
-			DrawString(4, 23+(i-1)*6, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
-		}
-
-		for (i = 0; i != 6; i++) {
-			DrawStringCentered(216, 45 + i * 8, STR_01D5_ALL + i, (i == msf.playlist) ? 0xC : 0x10);
-		}
-
-		DrawStringCentered(216, 45+8*6+16, STR_01F0_CLEAR, 0);
-#if 0
-		DrawStringCentered(216, 45 + 8 * 6 + 16 * 2, STR_01F1_SAVE, 0);
-#endif
-
-		y = 23;
-		for (p = _playlists[msf.playlist], i = 0; (i = *p) != 0; p++) {
-			SetDParam(0, i);
-			SetDParam(1, SPECSTR_SONGNAME);
-			SetDParam(2, i);
-			DrawString(252, y, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
-			y += 6;
-		}
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: { // add to playlist
-			int y = (e->we.click.pt.y - 23) / 6;
-			uint i;
-			byte *p;
-
-			if (msf.playlist < 4) return;
-			if (!IS_INT_INSIDE(y, 0, NUM_SONGS_AVAILABLE)) return;
-
-			p = _playlists[msf.playlist];
-			for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
-				if (p[i] == 0) {
-					p[i] = y + 1;
-					p[i + 1] = 0;
-					SetWindowDirty(w);
-					SelectSongToPlay();
-					break;
-				}
-			}
-		} break;
-
-		case 4: { // remove from playlist
-			int y = (e->we.click.pt.y - 23) / 6;
-			uint i;
-			byte *p;
-
-			if (msf.playlist < 4) return;
-			if (!IS_INT_INSIDE(y, 0, NUM_SONGS_AVAILABLE)) return;
-
-			p = _playlists[msf.playlist];
-			for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
-				p[i] = p[i + 1];
-				}
-
-			SetWindowDirty(w);
-			SelectSongToPlay();
-		} break;
-
-		case 11: // clear
-			_playlists[msf.playlist][0] = 0;
-			SetWindowDirty(w);
-			StopMusic();
-			SelectSongToPlay();
-			break;
-
-#if 0
-		case 12: // save
-			ShowInfo("MusicTrackSelectionWndProc:save not implemented");
-			break;
-#endif
-
-		case 5: case 6: case 7: case 8: case 9: case 10: /* set playlist */
-			msf.playlist = e->we.click.widget - 5;
-			SetWindowDirty(w);
-			InvalidateWindow(WC_MUSIC_WINDOW, 0);
-			StopMusic();
-			SelectSongToPlay();
-			break;
-		}
-		break;
-	}
-}
-
-static const Widget _music_track_selection_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   431,     0,    13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   431,    14,   217, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   181,    22,   215, 0x0,                              STR_01FA_CLICK_ON_MUSIC_TRACK_TO},
-{      WWT_PANEL,   RESIZE_NONE,    14,   250,   429,    22,   215, 0x0,                              STR_CLICK_ON_TRACK_TO_REMOVE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    44,    51, 0x0,                              STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    52,    59, 0x0,                              STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    60,    67, 0x0,                              STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    68,    75, 0x0,                              STR_0330_SELECT_EZY_STREET_STYLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    76,    83, 0x0,                              STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    84,    91, 0x0,                              STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   108,   115, 0x0,                              STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1},
-#if 0
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   124,   131, 0x0,                              STR_01F9_SAVE_MUSIC_SETTINGS},
-#endif
-{   WIDGETS_END},
-};
-
-static const WindowDesc _music_track_selection_desc = {
-	104, 131, 432, 218,
-	WC_MUSIC_TRACK_SELECTION,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_music_track_selection_widgets,
-	MusicTrackSelectionWndProc
-};
-
-static void ShowMusicTrackSelection(void)
-{
-	AllocateWindowDescFront(&_music_track_selection_desc, 0);
-}
-
-static void MusicWindowWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		uint i;
-		StringID str;
-
-		RaiseWindowWidget(w, 7);
-		RaiseWindowWidget(w, 9);
-		DrawWindowWidgets(w);
-
-		GfxFillRect(187, 16, 200, 33, 0);
-
-		for (i = 0; i != 8; i++) {
-			int color = 0xD0;
-			if (i > 4) {
-				color = 0xBF;
-				if (i > 6) {
-					color = 0xB8;
-				}
-			}
-			GfxFillRect(187, NUM_SONGS_PLAYLIST - i * 2, 200, NUM_SONGS_PLAYLIST - i * 2, color);
-		}
-
-		GfxFillRect(60, 46, 239, 52, 0);
-
-		if (_song_is_active == 0 || _music_wnd_cursong == 0) {
-			str = STR_01E3;
-		} else {
-			SetDParam(0, _music_wnd_cursong);
-			str = (_music_wnd_cursong < 10) ? STR_01E4_0 : STR_01E5;
-		}
-		DrawString(62, 46, str, 0);
-
-		str = STR_01E6;
-		if (_song_is_active != 0 && _music_wnd_cursong != 0) {
-			str = STR_01E7;
-			SetDParam(0, SPECSTR_SONGNAME);
-			SetDParam(1, _music_wnd_cursong);
-		}
-		DrawStringCentered(155, 46, str, 0);
-
-
-		DrawString(60, 38, STR_01E8_TRACK_XTITLE, 0);
-
-		for (i = 0; i != 6; i++) {
-			DrawStringCentered(25 + i * 50, 59, STR_01D5_ALL + i, msf.playlist == i ? 0xC : 0x10);
-		}
-
-		DrawStringCentered(31, 43, STR_01E9_SHUFFLE, (msf.shuffle ? 0xC : 0x10));
-		DrawStringCentered(269, 43, STR_01EA_PROGRAM, 0);
-		DrawStringCentered(141, 15, STR_01DB_MUSIC_VOLUME, 0);
-		DrawStringCentered(141, 29, STR_01DD_MIN_MAX, 0);
-		DrawStringCentered(247, 15, STR_01DC_EFFECTS_VOLUME, 0);
-		DrawStringCentered(247, 29, STR_01DD_MIN_MAX, 0);
-
-		DrawFrameRect(108, 23, 174, 26, 14, FR_LOWERED);
-		DrawFrameRect(214, 23, 280, 26, 14, FR_LOWERED);
-
-		DrawFrameRect(
-			108 + msf.music_vol / 2, 22, 111 + msf.music_vol / 2, 28, 14, 0
-		);
-
-		DrawFrameRect(
-			214 + msf.effect_vol / 2, 22, 217 + msf.effect_vol / 2, 28, 14, 0
-		);
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: // skip to prev
-			if (!_song_is_active)
-				return;
-			SkipToPrevSong();
-			break;
-		case 3: // skip to next
-			if (!_song_is_active)
-				return;
-			SkipToNextSong();
-			break;
-		case 4: // stop playing
-			msf.playing = false;
-			break;
-		case 5: // start playing
-			msf.playing = true;
-			break;
-		case 6:{ // volume sliders
-			byte *vol,new_vol;
-			int x = e->we.click.pt.x - 88;
-
-			if (x < 0)
-				return;
-
-			vol = &msf.music_vol;
-			if (x >= 106) {
-				vol = &msf.effect_vol;
-				x -= 106;
-			}
-
-			new_vol = min(max(x-21,0)*2,127);
-			if (new_vol != *vol) {
-				*vol = new_vol;
-				if (vol == &msf.music_vol)
-					MusicVolumeChanged(new_vol);
-				SetWindowDirty(w);
-			}
-
-			_left_button_clicked = false;
-		} break;
-		case 10: //toggle shuffle
-			msf.shuffle ^= 1;
-			StopMusic();
-			SelectSongToPlay();
-			break;
-		case 11: //show track selection
-			ShowMusicTrackSelection();
-			break;
-		case 12: case 13: case 14: case 15: case 16: case 17: // playlist
-			msf.playlist = e->we.click.widget - 12;
-			SetWindowDirty(w);
-			InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
-			StopMusic();
-			SelectSongToPlay();
-			break;
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 7);
-		break;
-	}
-
-}
-
-static const Widget _music_window_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   299,     0,    13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,     0,    21,    14,    35, SPR_IMG_SKIP_TO_PREV,  STR_01DE_SKIP_TO_PREVIOUS_TRACK},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    22,    43,    14,    35, SPR_IMG_SKIP_TO_NEXT,  STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    44,    65,    14,    35, SPR_IMG_STOP_MUSIC,    STR_01E0_STOP_PLAYING_MUSIC},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    66,    87,    14,    35, SPR_IMG_PLAY_MUSIC,    STR_01E1_START_PLAYING_MUSIC},
-{      WWT_PANEL,   RESIZE_NONE,    14,    88,   299,    14,    35, 0x0,                   STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},
-{      WWT_PANEL,   RESIZE_NONE,    14,   186,   201,    15,    34, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   299,    36,    57, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    59,   240,    45,    53, 0x0,                   STR_NULL},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,     6,    55,    42,    49, 0x0,                   STR_01FB_TOGGLE_PROGRAM_SHUFFLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   244,   293,    42,    49, 0x0,                   STR_01FC_SHOW_MUSIC_TRACK_SELECTION},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,     0,    49,    58,    65, 0x0,                   STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,    50,    99,    58,    65, 0x0,                   STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   100,   149,    58,    65, 0x0,                   STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   150,   199,    58,    65, 0x0,                   STR_0330_SELECT_EZY_STREET_STYLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   200,   249,    58,    65, 0x0,                   STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   250,   299,    58,    65, 0x0,                   STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _music_window_desc = {
-	0, 22, 300, 66,
-	WC_MUSIC_WINDOW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_music_window_widgets,
-	MusicWindowWndProc
-};
-
-void ShowMusicWindow(void)
-{
-	AllocateWindowDescFront(&_music_window_desc, 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/music_gui.cpp
@@ -0,0 +1,506 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "functions.h"
+#include "window.h"
+#include "gfx.h"
+#include "sound.h"
+#include "hal.h"
+#include "macros.h"
+#include "variables.h"
+#include "music.h"
+
+static byte _music_wnd_cursong;
+static bool _song_is_active;
+static byte _cur_playlist[NUM_SONGS_PLAYLIST];
+
+
+
+static byte _playlist_all[] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0
+};
+
+static byte _playlist_old_style[] = {
+	1, 8, 2, 9, 14, 15, 19, 13, 0
+};
+
+static byte _playlist_new_style[] = {
+	6, 11, 10, 17, 21, 18, 5, 0
+};
+
+static byte _playlist_ezy_street[] = {
+	12, 7, 16, 3, 20, 4, 0
+};
+
+static byte * const _playlists[] = {
+	_playlist_all,
+	_playlist_old_style,
+	_playlist_new_style,
+	_playlist_ezy_street,
+	msf.custom_1,
+	msf.custom_2,
+};
+
+static void SkipToPrevSong(void)
+{
+	byte *b = _cur_playlist;
+	byte *p = b;
+	byte t;
+
+	if (b[0] == 0) return; // empty playlist
+
+	do p++; while (p[0] != 0); // find the end
+
+	t = *--p; // and copy the bytes
+	while (p != b) {
+		p--;
+		p[1] = p[0];
+	}
+	*b = t;
+
+	_song_is_active = false;
+}
+
+static void SkipToNextSong(void)
+{
+	byte* b = _cur_playlist;
+	byte t;
+
+	t = b[0];
+	if (t != 0) {
+		while (b[1] != 0) {
+			b[0] = b[1];
+			b++;
+		}
+		b[0] = t;
+	}
+
+	_song_is_active = false;
+}
+
+static void MusicVolumeChanged(byte new_vol)
+{
+	_music_driver->set_volume(new_vol);
+}
+
+static void DoPlaySong(void)
+{
+	char filename[256];
+	snprintf(filename, sizeof(filename), "%s%s",
+		_paths.gm_dir, origin_songs_specs[_music_wnd_cursong - 1].filename);
+	_music_driver->play_song(filename);
+}
+
+static void DoStopMusic(void)
+{
+	_music_driver->stop_song();
+}
+
+static void SelectSongToPlay(void)
+{
+	uint i = 0;
+	uint j = 0;
+	char filename[256];
+
+	memset(_cur_playlist, 0, sizeof(_cur_playlist));
+	do {
+		if (_playlists[msf.playlist][i] != 0) {  // Don't evaluate playlist terminator
+			snprintf(filename, sizeof(filename),  "%s%s",
+				_paths.gm_dir, origin_songs_specs[(_playlists[msf.playlist][i]) - 1].filename);
+
+			/* we are now checking for the existence of that file prior
+			 * to add it to the list of available songs */
+			if (FileExists(filename)) {
+				_cur_playlist[j] = _playlists[msf.playlist][i];
+				j++;
+			}
+		}
+	} while (_playlists[msf.playlist][i++] != 0 && i < lengthof(_cur_playlist) - 1);
+
+	if (msf.shuffle) {
+		i = 500;
+		do {
+			uint32 r = InteractiveRandom();
+			byte *a = &_cur_playlist[GB(r, 0, 5)];
+			byte *b = &_cur_playlist[GB(r, 8, 5)];
+
+			if (*a != 0 && *b != 0) {
+				byte t = *a;
+				*a = *b;
+				*b = t;
+			}
+		} while (--i);
+	}
+}
+
+static void StopMusic(void)
+{
+	_music_wnd_cursong = 0;
+	DoStopMusic();
+	_song_is_active = false;
+	InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
+}
+
+static void PlayPlaylistSong(void)
+{
+	if (_cur_playlist[0] == 0) {
+		SelectSongToPlay();
+		/* if there is not songs in the playlist, it may indicate
+		 * no file on the gm folder, or even no gm folder.
+		 * Stop the playback, then */
+		if (_cur_playlist[0] == 0) {
+			_song_is_active = false;
+			_music_wnd_cursong = 0;
+			msf.playing = false;
+			return;
+		}
+	}
+	_music_wnd_cursong = _cur_playlist[0];
+	DoPlaySong();
+	_song_is_active = true;
+
+	InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 9);
+}
+
+void ResetMusic(void)
+{
+	_music_wnd_cursong = 1;
+	DoPlaySong();
+}
+
+void MusicLoop(void)
+{
+	if (!msf.playing && _song_is_active) {
+		StopMusic();
+	} else if (msf.playing && !_song_is_active) {
+		PlayPlaylistSong();
+	}
+
+	if (!_song_is_active) return;
+
+	if (!_music_driver->is_song_playing()) {
+		if (_game_mode != GM_MENU) {
+			StopMusic();
+			SkipToNextSong();
+			PlayPlaylistSong();
+		} else {
+			ResetMusic();
+		}
+	}
+}
+
+static void MusicTrackSelectionWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const byte* p;
+		uint i;
+		int y;
+
+		SetWindowWidgetDisabledState(w, 11, msf.playlist <= 3);
+		LowerWindowWidget(w, 3);
+		LowerWindowWidget(w, 4);
+		DrawWindowWidgets(w);
+
+		GfxFillRect(3, 23, 3+177,23+191,0);
+		GfxFillRect(251, 23, 251+177,23+191,0);
+
+		DrawStringCentered(92, 15, STR_01EE_TRACK_INDEX, 0);
+
+		SetDParam(0, STR_01D5_ALL + msf.playlist);
+		DrawStringCentered(340, 15, STR_01EF_PROGRAM, 0);
+
+		for (i = 1; i <= NUM_SONGS_AVAILABLE; i++) {
+			SetDParam(0, i);
+			SetDParam(2, i);
+			SetDParam(1, SPECSTR_SONGNAME);
+			DrawString(4, 23+(i-1)*6, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
+		}
+
+		for (i = 0; i != 6; i++) {
+			DrawStringCentered(216, 45 + i * 8, STR_01D5_ALL + i, (i == msf.playlist) ? 0xC : 0x10);
+		}
+
+		DrawStringCentered(216, 45+8*6+16, STR_01F0_CLEAR, 0);
+#if 0
+		DrawStringCentered(216, 45 + 8 * 6 + 16 * 2, STR_01F1_SAVE, 0);
+#endif
+
+		y = 23;
+		for (p = _playlists[msf.playlist], i = 0; (i = *p) != 0; p++) {
+			SetDParam(0, i);
+			SetDParam(1, SPECSTR_SONGNAME);
+			SetDParam(2, i);
+			DrawString(252, y, (i < 10) ? STR_01EC_0 : STR_01ED, 0);
+			y += 6;
+		}
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: { // add to playlist
+			int y = (e->we.click.pt.y - 23) / 6;
+			uint i;
+			byte *p;
+
+			if (msf.playlist < 4) return;
+			if (!IS_INT_INSIDE(y, 0, NUM_SONGS_AVAILABLE)) return;
+
+			p = _playlists[msf.playlist];
+			for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
+				if (p[i] == 0) {
+					p[i] = y + 1;
+					p[i + 1] = 0;
+					SetWindowDirty(w);
+					SelectSongToPlay();
+					break;
+				}
+			}
+		} break;
+
+		case 4: { // remove from playlist
+			int y = (e->we.click.pt.y - 23) / 6;
+			uint i;
+			byte *p;
+
+			if (msf.playlist < 4) return;
+			if (!IS_INT_INSIDE(y, 0, NUM_SONGS_AVAILABLE)) return;
+
+			p = _playlists[msf.playlist];
+			for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
+				p[i] = p[i + 1];
+				}
+
+			SetWindowDirty(w);
+			SelectSongToPlay();
+		} break;
+
+		case 11: // clear
+			_playlists[msf.playlist][0] = 0;
+			SetWindowDirty(w);
+			StopMusic();
+			SelectSongToPlay();
+			break;
+
+#if 0
+		case 12: // save
+			ShowInfo("MusicTrackSelectionWndProc:save not implemented");
+			break;
+#endif
+
+		case 5: case 6: case 7: case 8: case 9: case 10: /* set playlist */
+			msf.playlist = e->we.click.widget - 5;
+			SetWindowDirty(w);
+			InvalidateWindow(WC_MUSIC_WINDOW, 0);
+			StopMusic();
+			SelectSongToPlay();
+			break;
+		}
+		break;
+	}
+}
+
+static const Widget _music_track_selection_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   431,     0,    13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   431,    14,   217, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   181,    22,   215, 0x0,                              STR_01FA_CLICK_ON_MUSIC_TRACK_TO},
+{      WWT_PANEL,   RESIZE_NONE,    14,   250,   429,    22,   215, 0x0,                              STR_CLICK_ON_TRACK_TO_REMOVE},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    44,    51, 0x0,                              STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    52,    59, 0x0,                              STR_01F4_SELECT_OLD_STYLE_MUSIC},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    60,    67, 0x0,                              STR_01F5_SELECT_NEW_STYLE_MUSIC},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    68,    75, 0x0,                              STR_0330_SELECT_EZY_STREET_STYLE},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    76,    83, 0x0,                              STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    84,    91, 0x0,                              STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   108,   115, 0x0,                              STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1},
+#if 0
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   124,   131, 0x0,                              STR_01F9_SAVE_MUSIC_SETTINGS},
+#endif
+{   WIDGETS_END},
+};
+
+static const WindowDesc _music_track_selection_desc = {
+	104, 131, 432, 218,
+	WC_MUSIC_TRACK_SELECTION,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_music_track_selection_widgets,
+	MusicTrackSelectionWndProc
+};
+
+static void ShowMusicTrackSelection(void)
+{
+	AllocateWindowDescFront(&_music_track_selection_desc, 0);
+}
+
+static void MusicWindowWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		uint i;
+		StringID str;
+
+		RaiseWindowWidget(w, 7);
+		RaiseWindowWidget(w, 9);
+		DrawWindowWidgets(w);
+
+		GfxFillRect(187, 16, 200, 33, 0);
+
+		for (i = 0; i != 8; i++) {
+			int color = 0xD0;
+			if (i > 4) {
+				color = 0xBF;
+				if (i > 6) {
+					color = 0xB8;
+				}
+			}
+			GfxFillRect(187, NUM_SONGS_PLAYLIST - i * 2, 200, NUM_SONGS_PLAYLIST - i * 2, color);
+		}
+
+		GfxFillRect(60, 46, 239, 52, 0);
+
+		if (_song_is_active == 0 || _music_wnd_cursong == 0) {
+			str = STR_01E3;
+		} else {
+			SetDParam(0, _music_wnd_cursong);
+			str = (_music_wnd_cursong < 10) ? STR_01E4_0 : STR_01E5;
+		}
+		DrawString(62, 46, str, 0);
+
+		str = STR_01E6;
+		if (_song_is_active != 0 && _music_wnd_cursong != 0) {
+			str = STR_01E7;
+			SetDParam(0, SPECSTR_SONGNAME);
+			SetDParam(1, _music_wnd_cursong);
+		}
+		DrawStringCentered(155, 46, str, 0);
+
+
+		DrawString(60, 38, STR_01E8_TRACK_XTITLE, 0);
+
+		for (i = 0; i != 6; i++) {
+			DrawStringCentered(25 + i * 50, 59, STR_01D5_ALL + i, msf.playlist == i ? 0xC : 0x10);
+		}
+
+		DrawStringCentered(31, 43, STR_01E9_SHUFFLE, (msf.shuffle ? 0xC : 0x10));
+		DrawStringCentered(269, 43, STR_01EA_PROGRAM, 0);
+		DrawStringCentered(141, 15, STR_01DB_MUSIC_VOLUME, 0);
+		DrawStringCentered(141, 29, STR_01DD_MIN_MAX, 0);
+		DrawStringCentered(247, 15, STR_01DC_EFFECTS_VOLUME, 0);
+		DrawStringCentered(247, 29, STR_01DD_MIN_MAX, 0);
+
+		DrawFrameRect(108, 23, 174, 26, 14, FR_LOWERED);
+		DrawFrameRect(214, 23, 280, 26, 14, FR_LOWERED);
+
+		DrawFrameRect(
+			108 + msf.music_vol / 2, 22, 111 + msf.music_vol / 2, 28, 14, 0
+		);
+
+		DrawFrameRect(
+			214 + msf.effect_vol / 2, 22, 217 + msf.effect_vol / 2, 28, 14, 0
+		);
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: // skip to prev
+			if (!_song_is_active)
+				return;
+			SkipToPrevSong();
+			break;
+		case 3: // skip to next
+			if (!_song_is_active)
+				return;
+			SkipToNextSong();
+			break;
+		case 4: // stop playing
+			msf.playing = false;
+			break;
+		case 5: // start playing
+			msf.playing = true;
+			break;
+		case 6:{ // volume sliders
+			byte *vol,new_vol;
+			int x = e->we.click.pt.x - 88;
+
+			if (x < 0)
+				return;
+
+			vol = &msf.music_vol;
+			if (x >= 106) {
+				vol = &msf.effect_vol;
+				x -= 106;
+			}
+
+			new_vol = min(max(x-21,0)*2,127);
+			if (new_vol != *vol) {
+				*vol = new_vol;
+				if (vol == &msf.music_vol)
+					MusicVolumeChanged(new_vol);
+				SetWindowDirty(w);
+			}
+
+			_left_button_clicked = false;
+		} break;
+		case 10: //toggle shuffle
+			msf.shuffle ^= 1;
+			StopMusic();
+			SelectSongToPlay();
+			break;
+		case 11: //show track selection
+			ShowMusicTrackSelection();
+			break;
+		case 12: case 13: case 14: case 15: case 16: case 17: // playlist
+			msf.playlist = e->we.click.widget - 12;
+			SetWindowDirty(w);
+			InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
+			StopMusic();
+			SelectSongToPlay();
+			break;
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 7);
+		break;
+	}
+
+}
+
+static const Widget _music_window_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   299,     0,    13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,     0,    21,    14,    35, SPR_IMG_SKIP_TO_PREV,  STR_01DE_SKIP_TO_PREVIOUS_TRACK},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    22,    43,    14,    35, SPR_IMG_SKIP_TO_NEXT,  STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    44,    65,    14,    35, SPR_IMG_STOP_MUSIC,    STR_01E0_STOP_PLAYING_MUSIC},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    66,    87,    14,    35, SPR_IMG_PLAY_MUSIC,    STR_01E1_START_PLAYING_MUSIC},
+{      WWT_PANEL,   RESIZE_NONE,    14,    88,   299,    14,    35, 0x0,                   STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},
+{      WWT_PANEL,   RESIZE_NONE,    14,   186,   201,    15,    34, 0x0,                   STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   299,    36,    57, 0x0,                   STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    59,   240,    45,    53, 0x0,                   STR_NULL},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,     6,    55,    42,    49, 0x0,                   STR_01FB_TOGGLE_PROGRAM_SHUFFLE},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   244,   293,    42,    49, 0x0,                   STR_01FC_SHOW_MUSIC_TRACK_SELECTION},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,     0,    49,    58,    65, 0x0,                   STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,    50,    99,    58,    65, 0x0,                   STR_01F4_SELECT_OLD_STYLE_MUSIC},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   100,   149,    58,    65, 0x0,                   STR_01F5_SELECT_NEW_STYLE_MUSIC},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   150,   199,    58,    65, 0x0,                   STR_0330_SELECT_EZY_STREET_STYLE},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   200,   249,    58,    65, 0x0,                   STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   250,   299,    58,    65, 0x0,                   STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _music_window_desc = {
+	0, 22, 300, 66,
+	WC_MUSIC_WINDOW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_music_window_widgets,
+	MusicWindowWndProc
+};
+
+void ShowMusicWindow(void)
+{
+	AllocateWindowDescFront(&_music_window_desc, 0);
+}
deleted file mode 100644
--- a/src/namegen.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "macros.h"
-#include "namegen.h"
-#include "table/namegen.h"
-#include "string.h"
-
-static inline uint32 SeedChance(int shift_by, int max, uint32 seed)
-{
-	return (GB(seed, shift_by, 16) * max) >> 16;
-}
-
-static inline uint32 SeedModChance(int shift_by, int max, uint32 seed)
-{
-	/* This actually gives *MUCH* more even distribution of the values
-	 * than SeedChance(), which is absolutely horrible in that. If
-	 * you do not believe me, try with i.e. the Czech town names,
-	 * compare the words (nicely visible on prefixes) generated by
-	 * SeedChance() and SeedModChance(). Do not get dicouraged by the
-	 * never-use-modulo myths, which hold true only for the linear
-	 * congruential generators (and Random() isn't such a generator).
-	 * --pasky */
-	// TODO: Perhaps we should use it for all the name generators? --pasky
-	return (seed >> shift_by) % max;
-}
-
-static inline int32 SeedChanceBias(int shift_by, int max, uint32 seed, int bias)
-{
-	return SeedChance(shift_by, max + bias, seed) - bias;
-}
-
-static void ReplaceWords(const char *org, const char *rep, char *buf)
-{
-	if (strncmp(buf, org, 4) == 0) strncpy(buf, rep, 4);
-}
-
-static byte MakeEnglishOriginalTownName(char *buf, uint32 seed, const char *last)
-{
-	int i;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChanceBias(0, lengthof(name_original_english_1), seed, 50);
-	if (i >= 0)
-		strecat(buf, name_original_english_1[i], last);
-
-	//mandatory middle segments
-	strecat(buf, name_original_english_2[SeedChance(4,  lengthof(name_original_english_2), seed)], last);
-	strecat(buf, name_original_english_3[SeedChance(7,  lengthof(name_original_english_3), seed)], last);
-	strecat(buf, name_original_english_4[SeedChance(10, lengthof(name_original_english_4), seed)], last);
-	strecat(buf, name_original_english_5[SeedChance(13, lengthof(name_original_english_5), seed)], last);
-
-	//optional last segment
-	i = SeedChanceBias(15, lengthof(name_original_english_6), seed, 60);
-	if (i >= 0)
-		strecat(buf, name_original_english_6[i], last);
-
-	if (buf[0] == 'C' && (buf[1] == 'e' || buf[1] == 'i'))
-		buf[0] = 'K';
-
-	ReplaceWords("Cunt", "East", buf);
-	ReplaceWords("Slag", "Pits", buf);
-	ReplaceWords("Slut", "Edin", buf);
-	//ReplaceWords("Fart", "Boot", buf);
-	ReplaceWords("Drar", "Quar", buf);
-	ReplaceWords("Dreh", "Bash", buf);
-	ReplaceWords("Frar", "Shor", buf);
-	ReplaceWords("Grar", "Aber", buf);
-	ReplaceWords("Brar", "Over", buf);
-	ReplaceWords("Wrar", "Inve", buf);
-
-	return 0;
-}
-
-
-static byte MakeEnglishAdditionalTownName(char *buf, uint32 seed, const char *last)
-{
-	int i;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChanceBias(0, lengthof(name_additional_english_prefix), seed, 50);
-	if (i >= 0)
-		strecat(buf,name_additional_english_prefix[i], last);
-
-	if (SeedChance(3, 20, seed) >= 14) {
-		strecat(buf, name_additional_english_1a[SeedChance(6, lengthof(name_additional_english_1a), seed)], last);
-	} else {
-		strecat(buf, name_additional_english_1b1[SeedChance(6, lengthof(name_additional_english_1b1), seed)], last);
-		strecat(buf, name_additional_english_1b2[SeedChance(9, lengthof(name_additional_english_1b2), seed)], last);
-		if (SeedChance(11, 20, seed) >= 4) {
-			strecat(buf, name_additional_english_1b3a[SeedChance(12, lengthof(name_additional_english_1b3a), seed)], last);
-		} else {
-			strecat(buf, name_additional_english_1b3b[SeedChance(12, lengthof(name_additional_english_1b3b), seed)], last);
-		}
-	}
-
-	strecat(buf, name_additional_english_2[SeedChance(14, lengthof(name_additional_english_2), seed)], last);
-
-	//optional last segment
-	i = SeedChanceBias(15, lengthof(name_additional_english_3), seed, 60);
-	if (i >= 0)
-		strecat(buf, name_additional_english_3[i], last);
-
-	ReplaceWords("Cunt", "East", buf);
-	ReplaceWords("Slag", "Pits", buf);
-	ReplaceWords("Slut", "Edin", buf);
-	ReplaceWords("Fart", "Boot", buf);
-	ReplaceWords("Drar", "Quar", buf);
-	ReplaceWords("Dreh", "Bash", buf);
-	ReplaceWords("Frar", "Shor", buf);
-	ReplaceWords("Grar", "Aber", buf);
-	ReplaceWords("Brar", "Over", buf);
-	ReplaceWords("Wrar", "Stan", buf);
-
-	return 0;
-}
-
-static byte MakeAustrianTownName(char *buf, uint32 seed, const char *last)
-{
-	int i, j = 0;
-	strecpy(buf, "", last);
-
-	// Bad, Maria, Gross, ...
-	i = SeedChanceBias(0, lengthof(name_austrian_a1), seed, 15);
-	if (i >= 0) strecat(buf, name_austrian_a1[i], last);
-
-	i = SeedChance(4, 6, seed);
-	if (i >= 4) {
-		// Kaisers-kirchen
-		strecat(buf, name_austrian_a2[SeedChance( 7, lengthof(name_austrian_a2), seed)], last);
-		strecat(buf, name_austrian_a3[SeedChance(13, lengthof(name_austrian_a3), seed)], last);
-	} else if (i >= 2) {
-		// St. Johann
-		strecat(buf, name_austrian_a5[SeedChance( 7, lengthof(name_austrian_a5), seed)], last);
-		strecat(buf, name_austrian_a6[SeedChance( 9, lengthof(name_austrian_a6), seed)], last);
-		j = 1; // More likely to have a " an der " or " am "
-	} else {
-		// Zell
-		strecat(buf, name_austrian_a4[SeedChance( 7, lengthof(name_austrian_a4), seed)], last);
-	}
-
-	i = SeedChance(1, 6, seed);
-	if (i >= 4 - j) {
-		// an der Donau (rivers)
-		strecat(buf, name_austrian_f1[SeedChance(4, lengthof(name_austrian_f1), seed)], last);
-		strecat(buf, name_austrian_f2[SeedChance(5, lengthof(name_austrian_f2), seed)], last);
-	} else if (i >= 2 - j) {
-		// am Dachstein (mountains)
-		strecat(buf, name_austrian_b1[SeedChance(4, lengthof(name_austrian_b1), seed)], last);
-		strecat(buf, name_austrian_b2[SeedChance(5, lengthof(name_austrian_b2), seed)], last);
-	}
-
-	return 0;
-}
-
-static byte MakeGermanTownName(char *buf, uint32 seed, const char *last)
-{
-	uint i;
-	uint seed_derivative;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	seed_derivative = SeedChance(7, 28, seed);
-
-	//optional prefix
-	if (seed_derivative == 12 || seed_derivative == 19) {
-		i = SeedChance(2, lengthof(name_german_pre), seed);
-		strecat(buf,name_german_pre[i], last);
-	}
-
-	// mandatory middle segments including option of hardcoded name
-	i = SeedChance(3, lengthof(name_german_real) + lengthof(name_german_1), seed);
-	if (i < lengthof(name_german_real)) {
-		strecat(buf,name_german_real[i], last);
-	} else {
-		strecat(buf, name_german_1[i - lengthof(name_german_real)], last);
-
-		i = SeedChance(5, lengthof(name_german_2), seed);
-		strecat(buf, name_german_2[i], last);
-	}
-
-	// optional suffix
-	if (seed_derivative == 24) {
-		i = SeedChance(9,
-			lengthof(name_german_4_an_der) + lengthof(name_german_4_am), seed);
-		if (i < lengthof(name_german_4_an_der)) {
-			strecat(buf, name_german_3_an_der[0], last);
-			strecat(buf, name_german_4_an_der[i], last);
-		} else {
-			strecat(buf, name_german_3_am[0], last);
-			strecat(buf, name_german_4_am[i - lengthof(name_german_4_an_der)], last);
-		}
-	}
-	return 0;
-}
-
-static byte MakeSpanishTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_spanish_real[SeedChance(0, lengthof(name_spanish_real), seed)], last);
-	return 0;
-}
-
-static byte MakeFrenchTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_french_real[SeedChance(0, lengthof(name_french_real), seed)], last);
-	return 0;
-}
-
-static byte MakeSillyTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_silly_1[SeedChance( 0, lengthof(name_silly_1), seed)], last);
-	strecat(buf, name_silly_2[SeedChance(16, lengthof(name_silly_2), seed)], last);
-	return 0;
-}
-
-static byte MakeSwedishTownName(char *buf, uint32 seed, const char *last)
-{
-	int i;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChanceBias(0, lengthof(name_swedish_1), seed, 50);
-	if (i >= 0)
-		strecat(buf, name_swedish_1[i], last);
-
-	// mandatory middle segments including option of hardcoded name
-	if (SeedChance(4, 5, seed) >= 3) {
-		strecat(buf, name_swedish_2[SeedChance( 7, lengthof(name_swedish_2), seed)], last);
-	} else {
-		strecat(buf, name_swedish_2a[SeedChance( 7, lengthof(name_swedish_2a), seed)], last);
-		strecat(buf, name_swedish_2b[SeedChance(10, lengthof(name_swedish_2b), seed)], last);
-		strecat(buf, name_swedish_2c[SeedChance(13, lengthof(name_swedish_2c), seed)], last);
-	}
-
-	strecat(buf, name_swedish_3[SeedChance(16, lengthof(name_swedish_3), seed)], last);
-
-	return 0;
-}
-
-static byte MakeDutchTownName(char *buf, uint32 seed, const char *last)
-{
-	int i;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChanceBias(0, lengthof(name_dutch_1), seed, 50);
-	if (i >= 0)
-		strecat(buf, name_dutch_1[i], last);
-
-	// mandatory middle segments including option of hardcoded name
-	if (SeedChance(6, 9, seed) > 4) {
-		strecat(buf, name_dutch_2[SeedChance( 9, lengthof(name_dutch_2), seed)], last);
-	} else {
-		strecat(buf, name_dutch_3[SeedChance( 9, lengthof(name_dutch_3), seed)], last);
-		strecat(buf, name_dutch_4[SeedChance(12, lengthof(name_dutch_4), seed)], last);
-	}
-	strecat(buf, name_dutch_5[SeedChance(15, lengthof(name_dutch_5), seed)], last);
-
-	return 0;
-}
-
-static byte MakeFinnishTownName(char *buf, uint32 seed, const char *last)
-{
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// Select randomly if town name should consists of one or two parts.
-	if (SeedChance(0, 15, seed) >= 10) {
-		strecat(buf, name_finnish_real[SeedChance(2, lengthof(name_finnish_real), seed)], last);
-	} else if (SeedChance(0, 15, seed) >= 5) {
-		// A two-part name by combining one of name_finnish_1 + "la"/"lä"
-		// The reason for not having the contents of name_finnish_{1,2} in the same table is
-		// that the ones in name_finnish_2 are not good for this purpose.
-		uint sel = SeedChance( 0, lengthof(name_finnish_1), seed);
-		char *end;
-		strecat(buf, name_finnish_1[sel], last);
-		end = &buf[strlen(buf)-1];
-		if (*end == 'i')
-			*end = 'e';
-		if (strstr(buf, "a") || strstr(buf, "o") || strstr(buf, "u") ||
-			strstr(buf, "A") || strstr(buf, "O") || strstr(buf, "U"))
-		{
-			strecat(buf, "la", last);
-		} else {
-			strecat(buf, "lä", last);
-		}
-	} else {
-		// A two-part name by combining one of name_finnish_{1,2} + name_finnish_3.
-		// Why aren't name_finnish_{1,2} just one table? See above.
-		uint sel = SeedChance(2,
-			lengthof(name_finnish_1) + lengthof(name_finnish_2), seed);
-		if (sel >= lengthof(name_finnish_1)) {
-			strecat(buf, name_finnish_2[sel-lengthof(name_finnish_1)], last);
-		} else {
-			strecat(buf, name_finnish_1[sel], last);
-		}
-		strecat(buf, name_finnish_3[SeedChance(10, lengthof(name_finnish_3), seed)], last);
-	}
-
-	return 0;
-}
-
-static byte MakePolishTownName(char *buf, uint32 seed, const char *last)
-{
-	uint i;
-	uint j;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChance(0,
-		lengthof(name_polish_2_o) + lengthof(name_polish_2_m) +
-		lengthof(name_polish_2_f) + lengthof(name_polish_2_n),
-		seed);
-	j = SeedChance(2, 20, seed);
-
-
-	if (i < lengthof(name_polish_2_o)) {
-		strecat(buf, name_polish_2_o[SeedChance(3, lengthof(name_polish_2_o), seed)], last);
-	} else if (i < lengthof(name_polish_2_m) + lengthof(name_polish_2_o)) {
-		if (j < 4)
-			strecat(buf, name_polish_1_m[SeedChance(5, lengthof(name_polish_1_m), seed)], last);
-
-		strecat(buf, name_polish_2_m[SeedChance(7, lengthof(name_polish_2_m), seed)], last);
-
-		if (j >= 4 && j < 16)
-			strecat(buf, name_polish_3_m[SeedChance(10, lengthof(name_polish_3_m), seed)], last);
-	} else if (i < lengthof(name_polish_2_f) + lengthof(name_polish_2_m) + lengthof(name_polish_2_o)) {
-		if (j < 4)
-			strecat(buf, name_polish_1_f[SeedChance(5, lengthof(name_polish_1_f), seed)], last);
-
-		strecat(buf, name_polish_2_f[SeedChance(7, lengthof(name_polish_2_f), seed)], last);
-
-		if (j >= 4 && j < 16)
-			strecat(buf, name_polish_3_f[SeedChance(10, lengthof(name_polish_3_f), seed)], last);
-	} else {
-		if (j < 4)
-			strecat(buf, name_polish_1_n[SeedChance(5, lengthof(name_polish_1_n), seed)], last);
-
-		strecat(buf, name_polish_2_n[SeedChance(7, lengthof(name_polish_2_n), seed)], last);
-
-		if (j >= 4 && j < 16)
-			strecat(buf, name_polish_3_n[SeedChance(10, lengthof(name_polish_3_n), seed)], last);
-	}
-	return 0;
-}
-
-static byte MakeCzechTownName(char *buf, uint32 seed, const char *last)
-{
-	/* Probability of prefixes/suffixes */
-	/* 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
-	int prob_tails;
-	bool do_prefix, do_suffix, dynamic_subst;
-	/* IDs of the respective parts */
-	int prefix = 0, ending = 0, suffix = 0;
-	uint postfix = 0;
-	uint stem;
-	/* The select criteria. */
-	CzechGender gender;
-	CzechChoose choose;
-	CzechAllow allow;
-
-	// 1:3 chance to use a real name.
-	if (SeedModChance(0, 4, seed) == 0) {
-		strecpy(buf, name_czech_real[SeedModChance(4, lengthof(name_czech_real), seed)], last);
-		return 0;
-	}
-
-	// NUL terminates the string for strcat()
-	strecpy(buf, "", last);
-
-	prob_tails = SeedModChance(2, 32, seed);
-	do_prefix = prob_tails < 12;
-	do_suffix = prob_tails > 11 && prob_tails < 17;
-
-	if (do_prefix) prefix = SeedModChance(5, lengthof(name_czech_adj) * 12, seed) / 12;
-	if (do_suffix) suffix = SeedModChance(7, lengthof(name_czech_suffix), seed);
-	// 3:1 chance 3:1 to use dynamic substantive
-	stem = SeedModChance(9,
-		lengthof(name_czech_subst_full) + 3 * lengthof(name_czech_subst_stem),
-		seed);
-	if (stem < lengthof(name_czech_subst_full)) {
-		// That was easy!
-		dynamic_subst = false;
-		gender = name_czech_subst_full[stem].gender;
-		choose = name_czech_subst_full[stem].choose;
-		allow = name_czech_subst_full[stem].allow;
-	} else {
-		unsigned int map[lengthof(name_czech_subst_ending)];
-		int ending_start = -1, ending_stop = -1;
-		int i;
-
-		// Load the substantive
-		dynamic_subst = true;
-		stem -= lengthof(name_czech_subst_full);
-		stem %= lengthof(name_czech_subst_stem);
-		gender = name_czech_subst_stem[stem].gender;
-		choose = name_czech_subst_stem[stem].choose;
-		allow = name_czech_subst_stem[stem].allow;
-
-		// Load the postfix (1:1 chance that a postfix will be inserted)
-		postfix = SeedModChance(14, lengthof(name_czech_subst_postfix) * 2, seed);
-
-		if (choose & CZC_POSTFIX) {
-			// Always get a real postfix.
-			postfix %= lengthof(name_czech_subst_postfix);
-		}
-		if (choose & CZC_NOPOSTFIX) {
-			// Always drop a postfix.
-			postfix += lengthof(name_czech_subst_postfix);
-		}
-		if (postfix < lengthof(name_czech_subst_postfix)) {
-			choose |= CZC_POSTFIX;
-		} else {
-			choose |= CZC_NOPOSTFIX;
-		}
-
-		// Localize the array segment containing a good gender
-		for (ending = 0; ending < (int) lengthof(name_czech_subst_ending); ending++) {
-			const CzechNameSubst *e = &name_czech_subst_ending[ending];
-
-			if (gender == CZG_FREE ||
-					(gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) ||
-					gender == e->gender) {
-				if (ending_start < 0)
-					ending_start = ending;
-
-			} else if (ending_start >= 0) {
-				ending_stop = ending - 1;
-				break;
-			}
-		}
-		if (ending_stop < 0) {
-			// Whoa. All the endings matched.
-			ending_stop = ending - 1;
-		}
-
-		// Make a sequential map of the items with good mask
-		i = 0;
-		for (ending = ending_start; ending <= ending_stop; ending++) {
-			const CzechNameSubst *e = &name_czech_subst_ending[ending];
-
-			if ((e->choose & choose) == choose && (e->allow & allow) != 0)
-				map[i++] = ending;
-		}
-		assert(i > 0);
-
-		// Load the ending
-		ending = map[SeedModChance(16, i, seed)];
-		// Override possible CZG_*FREE; this must be a real gender,
-		// otherwise we get overflow when modifying the adjectivum.
-		gender = name_czech_subst_ending[ending].gender;
-		assert(gender != CZG_FREE && gender != CZG_NFREE);
-	}
-
-	if (do_prefix && (name_czech_adj[prefix].choose & choose) != choose) {
-		// Throw away non-matching prefix.
-		do_prefix = false;
-	}
-
-	// Now finally construct the name
-
-	if (do_prefix) {
-		CzechPattern pattern = name_czech_adj[prefix].pattern;
-		size_t endpos;
-
-		strecat(buf, name_czech_adj[prefix].name, last);
-		endpos = strlen(buf) - 1;
-		/* Find the first character in a UTF-8 sequence */
-		while (GB(buf[endpos], 6, 2) == 2) endpos--;
-		if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
-			/* -ovX -> -uv */
-			buf[endpos - 2] = 'u';
-			assert(buf[endpos - 1] == 'v');
-			buf[endpos] = '\0';
-		} else {
-			strecpy(buf + endpos, name_czech_patmod[gender][pattern], last);
-		}
-
-		strecat(buf, " ", last);
-	}
-
-	if (dynamic_subst) {
-		strecat(buf, name_czech_subst_stem[stem].name, last);
-		if (postfix < lengthof(name_czech_subst_postfix)) {
-			const char *poststr = name_czech_subst_postfix[postfix];
-			const char *endstr = name_czech_subst_ending[ending].name;
-			size_t postlen, endlen;
-
-			postlen = strlen(poststr);
-			endlen = strlen(endstr);
-			assert(postlen > 0 && endlen > 0);
-
-			// Kill the "avava" and "Jananna"-like cases
-			if (postlen < 2 || postlen > endlen || (
-						(poststr[1] != 'v' || poststr[1] != endstr[1]) &&
-						poststr[2] != endstr[1])
-					) {
-				size_t buflen;
-				strecat(buf, poststr, last);
-				buflen = strlen(buf);
-
-				// k-i -> c-i, h-i -> z-i
-				if (endstr[0] == 'i') {
-					switch (buf[buflen - 1]) {
-						case 'k': buf[buflen - 1] = 'c'; break;
-						case 'h': buf[buflen - 1] = 'z'; break;
-						default: break;
-					}
-				}
-			}
-		}
-		strecat(buf, name_czech_subst_ending[ending].name, last);
-	} else {
-		strecat(buf, name_czech_subst_full[stem].name, last);
-	}
-
-	if (do_suffix) {
-		strecat(buf, " ", last);
-		strecat(buf, name_czech_suffix[suffix], last);
-	}
-
-	return 0;
-}
-
-static byte MakeRomanianTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_romanian_real[SeedChance(0, lengthof(name_romanian_real), seed)], last);
-	return 0;
-}
-
-static byte MakeSlovakTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_slovak_real[SeedChance(0, lengthof(name_slovak_real), seed)], last);
-	return 0;
-}
-
-static byte MakeNorwegianTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, "", last);
-
-	// Use first 4 bit from seed to decide whether or not this town should
-	// have a real name 3/16 chance.  Bit 0-3
-	if (SeedChance(0, 15, seed) < 3) {
-		// Use 7bit for the realname table index.  Bit 4-10
-		strecat(buf, name_norwegian_real[SeedChance(4, lengthof(name_norwegian_real), seed)], last);
-	} else {
-		// Use 7bit for the first fake part.  Bit 4-10
-		strecat(buf, name_norwegian_1[SeedChance(4, lengthof(name_norwegian_1), seed)], last);
-		// Use 7bit for the last fake part.  Bit 11-17
-		strecat(buf, name_norwegian_2[SeedChance(11, lengthof(name_norwegian_2), seed)], last);
-	}
-
-	return 0;
-}
-
-static byte MakeHungarianTownName(char *buf, uint32 seed, const char *last)
-{
-	uint i;
-
-	//null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	if (SeedChance(12, 15, seed) < 3) {
-		strecat(buf, name_hungarian_real[SeedChance(0, lengthof(name_hungarian_real), seed)], last);
-	} else {
-		// optional first segment
-		i = SeedChance(3, lengthof(name_hungarian_1) * 3, seed);
-		if (i < lengthof(name_hungarian_1))
-			strecat(buf, name_hungarian_1[i], last);
-
-		// mandatory middle segments
-		strecat(buf, name_hungarian_2[SeedChance(3, lengthof(name_hungarian_2), seed)], last);
-		strecat(buf, name_hungarian_3[SeedChance(6, lengthof(name_hungarian_3), seed)], last);
-
-		// optional last segment
-		i = SeedChance(10, lengthof(name_hungarian_4) * 3, seed);
-		if (i < lengthof(name_hungarian_4)) {
-			strecat(buf, name_hungarian_4[i], last);
-		}
-	}
-
-	return 0;
-}
-
-static byte MakeSwissTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, name_swiss_real[SeedChance(0, lengthof(name_swiss_real), seed)], last);
-	return 0;
-}
-
-static byte MakeDanishTownName(char *buf, uint32 seed, const char *last)
-{
-	int i;
-
-	// null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	// optional first segment
-	i = SeedChanceBias(0, lengthof(name_danish_1), seed, 50);
-	if (i >= 0)
-		strecat(buf, name_danish_1[i], last);
-
-	// middle segments removed as this algorithm seems to create much more realistic names
-	strecat(buf, name_danish_2[SeedChance( 7, lengthof(name_danish_2), seed)], last);
-	strecat(buf, name_danish_3[SeedChance(16, lengthof(name_danish_3), seed)], last);
-
-	return 0;
-}
-
-static byte MakeTurkishTownName(char *buf, uint32 seed, const char *last)
-{
-	uint i;
-
-	// null terminates the string for strcat
-	strecpy(buf, "", last);
-
-	if ((i = SeedModChance(0, 5, seed)) == 0) {
-		strecat(buf, name_turkish_prefix[SeedModChance( 2, lengthof(name_turkish_prefix), seed)], last);
-
-		// middle segment
-		strecat(buf, name_turkish_middle[SeedModChance( 4, lengthof(name_turkish_middle), seed)], last);
-
-		// optional suffix
-		if (SeedModChance(0, 7, seed) == 0) {
-			strecat(buf, name_turkish_suffix[SeedModChance( 10, lengthof(name_turkish_suffix), seed)], last);
-		}
-	} else {
-		if (i == 1 || i == 2) {
-			strecat(buf, name_turkish_prefix[SeedModChance( 2, lengthof(name_turkish_prefix), seed)], last);
-			strecat(buf, name_turkish_suffix[SeedModChance( 4, lengthof(name_turkish_suffix), seed)], last);
-		} else {
-			strecat(buf, name_turkish_real[SeedModChance( 4, lengthof(name_turkish_real), seed)], last);
-		}
-	}
-	return 0;
-}
-
-static const char *mascul_femin_italian[] = {
-	"o",
-	"a",
-};
-
-static byte MakeItalianTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, "", last);
-
-	if (SeedModChance(0, 6, seed) == 0) { // real city names
-		strecat(buf, name_italian_real[SeedModChance(4, lengthof(name_italian_real), seed)], last);
-	} else {
-		uint i;
-
-		if (SeedModChance(0, 8, seed) == 0) { // prefix
-			strecat(buf, name_italian_pref[SeedModChance(11, lengthof(name_italian_pref), seed)], last);
-		}
-
-		i = SeedChance(0, 2, seed);
-		if (i == 0) { // masculine form
-			strecat(buf, name_italian_1m[SeedModChance(4, lengthof(name_italian_1m), seed)], last);
-		} else { // feminine form
-			strecat(buf, name_italian_1f[SeedModChance(4, lengthof(name_italian_1f), seed)], last);
-		}
-
-		if (SeedModChance(3, 3, seed) == 0) {
-			strecat(buf, name_italian_2[SeedModChance(11, lengthof(name_italian_2), seed)], last);
-			strecat(buf,mascul_femin_italian[i], last);
-		} else {
-			strecat(buf, name_italian_2i[SeedModChance(16, lengthof(name_italian_2i), seed)], last);
-		}
-
-		if (SeedModChance(15, 4, seed) == 0) {
-			if (SeedModChance(5, 2, seed) == 0) { // generic suffix
-				strecat(buf, name_italian_3[SeedModChance(4, lengthof(name_italian_3), seed)], last);
-			} else { // river name suffix
-				strecat(buf, name_italian_river1[SeedModChance(4, lengthof(name_italian_river1), seed)], last);
-				strecat(buf, name_italian_river2[SeedModChance(16, lengthof(name_italian_river2), seed)], last);
-			}
-		}
-	}
-
-	return 0;
-}
-
-static byte MakeCatalanTownName(char *buf, uint32 seed, const char *last)
-{
-	strecpy(buf, "", last);
-
-	if (SeedModChance(0, 3, seed) == 0) { // real city names
-		strecat(buf, name_catalan_real[SeedModChance(4, lengthof(name_catalan_real), seed)], last);
-	} else {
-		uint i;
-
-		if (SeedModChance(0, 2, seed) == 0) { // prefix
-			strecat(buf, name_catalan_pref[SeedModChance(11, lengthof(name_catalan_pref), seed)], last);
-		}
-
-		i = SeedChance(0, 2, seed);
-		if (i == 0) { // masculine form
-			strecat(buf, name_catalan_1m[SeedModChance(4, lengthof(name_catalan_1m), seed)], last);
-			strecat(buf, name_catalan_2m[SeedModChance(11, lengthof(name_catalan_2m), seed)], last);
-		} else { // feminine form
-			strecat(buf, name_catalan_1f[SeedModChance(4, lengthof(name_catalan_1f), seed)], last);
-			strecat(buf, name_catalan_2f[SeedModChance(11, lengthof(name_catalan_2f), seed)], last);
-		}
-
-
-		if (SeedModChance(15, 5, seed) == 0) {
-			if (SeedModChance(5, 2, seed) == 0) { // generic suffix
-				strecat(buf, name_catalan_3[SeedModChance(4, lengthof(name_catalan_3), seed)], last);
-			} else { // river name suffix
-				strecat(buf, name_catalan_river1[SeedModChance(4, lengthof(name_catalan_river1), seed)], last);
-			}
-		}
-	}
-
-	return 0;
-}
-
-
-
-TownNameGenerator * const _town_name_generators[] =
-{
-	MakeEnglishOriginalTownName,
-	MakeFrenchTownName,
-	MakeGermanTownName,
-	MakeEnglishAdditionalTownName,
-	MakeSpanishTownName,
-	MakeSillyTownName,
-	MakeSwedishTownName,
-	MakeDutchTownName,
-	MakeFinnishTownName,
-	MakePolishTownName,
-	MakeSlovakTownName,
-	MakeNorwegianTownName,
-	MakeHungarianTownName,
-	MakeAustrianTownName,
-	MakeRomanianTownName,
-	MakeCzechTownName,
-	MakeSwissTownName,
-	MakeDanishTownName,
-	MakeTurkishTownName,
-	MakeItalianTownName,
-	MakeCatalanTownName,
-};
-
-// DO WE NEED THIS ANY MORE?
-#define FIXNUM(x, y, z) (((((x) << 16) / (y)) + 1) << z)
-
-uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type)
-{
-	switch (old_town_name_type) {
-		case 0: case 3: /* English, American */
-			/* Already OK */
-			return townnameparts;
-
-		case 1: /* French */
-			/* For some reason 86 needs to be subtracted from townnameparts
-			 * 0000 0000 0000 0000 0000 0000 1111 1111 */
-			return FIXNUM(townnameparts - 86, lengthof(name_french_real), 0);
-
-		case 2: /* German */
-			DEBUG(misc, 0, "German Townnames are buggy (%d)", townnameparts);
-			return townnameparts;
-
-		case 4: /* Latin-American */
-			/* 0000 0000 0000 0000 0000 0000 1111 1111 */
-			return FIXNUM(townnameparts, lengthof(name_spanish_real), 0);
-
-		case 5: /* Silly */
-			/* NUM_SILLY_1 - lower 16 bits
-			 * NUM_SILLY_2 - upper 16 bits without leading 1 (first 8 bytes)
-			 * 1000 0000 2222 2222 0000 0000 1111 1111 */
-			return FIXNUM(townnameparts, lengthof(name_silly_1), 0) | FIXNUM(GB(townnameparts, 16, 8), lengthof(name_silly_2), 16);
-	}
-	return 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/namegen.cpp
@@ -0,0 +1,790 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "macros.h"
+#include "namegen.h"
+#include "table/namegen.h"
+#include "string.h"
+
+static inline uint32 SeedChance(int shift_by, int max, uint32 seed)
+{
+	return (GB(seed, shift_by, 16) * max) >> 16;
+}
+
+static inline uint32 SeedModChance(int shift_by, int max, uint32 seed)
+{
+	/* This actually gives *MUCH* more even distribution of the values
+	 * than SeedChance(), which is absolutely horrible in that. If
+	 * you do not believe me, try with i.e. the Czech town names,
+	 * compare the words (nicely visible on prefixes) generated by
+	 * SeedChance() and SeedModChance(). Do not get dicouraged by the
+	 * never-use-modulo myths, which hold true only for the linear
+	 * congruential generators (and Random() isn't such a generator).
+	 * --pasky */
+	// TODO: Perhaps we should use it for all the name generators? --pasky
+	return (seed >> shift_by) % max;
+}
+
+static inline int32 SeedChanceBias(int shift_by, int max, uint32 seed, int bias)
+{
+	return SeedChance(shift_by, max + bias, seed) - bias;
+}
+
+static void ReplaceWords(const char *org, const char *rep, char *buf)
+{
+	if (strncmp(buf, org, 4) == 0) strncpy(buf, rep, 4);
+}
+
+static byte MakeEnglishOriginalTownName(char *buf, uint32 seed, const char *last)
+{
+	int i;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChanceBias(0, lengthof(name_original_english_1), seed, 50);
+	if (i >= 0)
+		strecat(buf, name_original_english_1[i], last);
+
+	//mandatory middle segments
+	strecat(buf, name_original_english_2[SeedChance(4,  lengthof(name_original_english_2), seed)], last);
+	strecat(buf, name_original_english_3[SeedChance(7,  lengthof(name_original_english_3), seed)], last);
+	strecat(buf, name_original_english_4[SeedChance(10, lengthof(name_original_english_4), seed)], last);
+	strecat(buf, name_original_english_5[SeedChance(13, lengthof(name_original_english_5), seed)], last);
+
+	//optional last segment
+	i = SeedChanceBias(15, lengthof(name_original_english_6), seed, 60);
+	if (i >= 0)
+		strecat(buf, name_original_english_6[i], last);
+
+	if (buf[0] == 'C' && (buf[1] == 'e' || buf[1] == 'i'))
+		buf[0] = 'K';
+
+	ReplaceWords("Cunt", "East", buf);
+	ReplaceWords("Slag", "Pits", buf);
+	ReplaceWords("Slut", "Edin", buf);
+	//ReplaceWords("Fart", "Boot", buf);
+	ReplaceWords("Drar", "Quar", buf);
+	ReplaceWords("Dreh", "Bash", buf);
+	ReplaceWords("Frar", "Shor", buf);
+	ReplaceWords("Grar", "Aber", buf);
+	ReplaceWords("Brar", "Over", buf);
+	ReplaceWords("Wrar", "Inve", buf);
+
+	return 0;
+}
+
+
+static byte MakeEnglishAdditionalTownName(char *buf, uint32 seed, const char *last)
+{
+	int i;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChanceBias(0, lengthof(name_additional_english_prefix), seed, 50);
+	if (i >= 0)
+		strecat(buf,name_additional_english_prefix[i], last);
+
+	if (SeedChance(3, 20, seed) >= 14) {
+		strecat(buf, name_additional_english_1a[SeedChance(6, lengthof(name_additional_english_1a), seed)], last);
+	} else {
+		strecat(buf, name_additional_english_1b1[SeedChance(6, lengthof(name_additional_english_1b1), seed)], last);
+		strecat(buf, name_additional_english_1b2[SeedChance(9, lengthof(name_additional_english_1b2), seed)], last);
+		if (SeedChance(11, 20, seed) >= 4) {
+			strecat(buf, name_additional_english_1b3a[SeedChance(12, lengthof(name_additional_english_1b3a), seed)], last);
+		} else {
+			strecat(buf, name_additional_english_1b3b[SeedChance(12, lengthof(name_additional_english_1b3b), seed)], last);
+		}
+	}
+
+	strecat(buf, name_additional_english_2[SeedChance(14, lengthof(name_additional_english_2), seed)], last);
+
+	//optional last segment
+	i = SeedChanceBias(15, lengthof(name_additional_english_3), seed, 60);
+	if (i >= 0)
+		strecat(buf, name_additional_english_3[i], last);
+
+	ReplaceWords("Cunt", "East", buf);
+	ReplaceWords("Slag", "Pits", buf);
+	ReplaceWords("Slut", "Edin", buf);
+	ReplaceWords("Fart", "Boot", buf);
+	ReplaceWords("Drar", "Quar", buf);
+	ReplaceWords("Dreh", "Bash", buf);
+	ReplaceWords("Frar", "Shor", buf);
+	ReplaceWords("Grar", "Aber", buf);
+	ReplaceWords("Brar", "Over", buf);
+	ReplaceWords("Wrar", "Stan", buf);
+
+	return 0;
+}
+
+static byte MakeAustrianTownName(char *buf, uint32 seed, const char *last)
+{
+	int i, j = 0;
+	strecpy(buf, "", last);
+
+	// Bad, Maria, Gross, ...
+	i = SeedChanceBias(0, lengthof(name_austrian_a1), seed, 15);
+	if (i >= 0) strecat(buf, name_austrian_a1[i], last);
+
+	i = SeedChance(4, 6, seed);
+	if (i >= 4) {
+		// Kaisers-kirchen
+		strecat(buf, name_austrian_a2[SeedChance( 7, lengthof(name_austrian_a2), seed)], last);
+		strecat(buf, name_austrian_a3[SeedChance(13, lengthof(name_austrian_a3), seed)], last);
+	} else if (i >= 2) {
+		// St. Johann
+		strecat(buf, name_austrian_a5[SeedChance( 7, lengthof(name_austrian_a5), seed)], last);
+		strecat(buf, name_austrian_a6[SeedChance( 9, lengthof(name_austrian_a6), seed)], last);
+		j = 1; // More likely to have a " an der " or " am "
+	} else {
+		// Zell
+		strecat(buf, name_austrian_a4[SeedChance( 7, lengthof(name_austrian_a4), seed)], last);
+	}
+
+	i = SeedChance(1, 6, seed);
+	if (i >= 4 - j) {
+		// an der Donau (rivers)
+		strecat(buf, name_austrian_f1[SeedChance(4, lengthof(name_austrian_f1), seed)], last);
+		strecat(buf, name_austrian_f2[SeedChance(5, lengthof(name_austrian_f2), seed)], last);
+	} else if (i >= 2 - j) {
+		// am Dachstein (mountains)
+		strecat(buf, name_austrian_b1[SeedChance(4, lengthof(name_austrian_b1), seed)], last);
+		strecat(buf, name_austrian_b2[SeedChance(5, lengthof(name_austrian_b2), seed)], last);
+	}
+
+	return 0;
+}
+
+static byte MakeGermanTownName(char *buf, uint32 seed, const char *last)
+{
+	uint i;
+	uint seed_derivative;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	seed_derivative = SeedChance(7, 28, seed);
+
+	//optional prefix
+	if (seed_derivative == 12 || seed_derivative == 19) {
+		i = SeedChance(2, lengthof(name_german_pre), seed);
+		strecat(buf,name_german_pre[i], last);
+	}
+
+	// mandatory middle segments including option of hardcoded name
+	i = SeedChance(3, lengthof(name_german_real) + lengthof(name_german_1), seed);
+	if (i < lengthof(name_german_real)) {
+		strecat(buf,name_german_real[i], last);
+	} else {
+		strecat(buf, name_german_1[i - lengthof(name_german_real)], last);
+
+		i = SeedChance(5, lengthof(name_german_2), seed);
+		strecat(buf, name_german_2[i], last);
+	}
+
+	// optional suffix
+	if (seed_derivative == 24) {
+		i = SeedChance(9,
+			lengthof(name_german_4_an_der) + lengthof(name_german_4_am), seed);
+		if (i < lengthof(name_german_4_an_der)) {
+			strecat(buf, name_german_3_an_der[0], last);
+			strecat(buf, name_german_4_an_der[i], last);
+		} else {
+			strecat(buf, name_german_3_am[0], last);
+			strecat(buf, name_german_4_am[i - lengthof(name_german_4_an_der)], last);
+		}
+	}
+	return 0;
+}
+
+static byte MakeSpanishTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_spanish_real[SeedChance(0, lengthof(name_spanish_real), seed)], last);
+	return 0;
+}
+
+static byte MakeFrenchTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_french_real[SeedChance(0, lengthof(name_french_real), seed)], last);
+	return 0;
+}
+
+static byte MakeSillyTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_silly_1[SeedChance( 0, lengthof(name_silly_1), seed)], last);
+	strecat(buf, name_silly_2[SeedChance(16, lengthof(name_silly_2), seed)], last);
+	return 0;
+}
+
+static byte MakeSwedishTownName(char *buf, uint32 seed, const char *last)
+{
+	int i;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChanceBias(0, lengthof(name_swedish_1), seed, 50);
+	if (i >= 0)
+		strecat(buf, name_swedish_1[i], last);
+
+	// mandatory middle segments including option of hardcoded name
+	if (SeedChance(4, 5, seed) >= 3) {
+		strecat(buf, name_swedish_2[SeedChance( 7, lengthof(name_swedish_2), seed)], last);
+	} else {
+		strecat(buf, name_swedish_2a[SeedChance( 7, lengthof(name_swedish_2a), seed)], last);
+		strecat(buf, name_swedish_2b[SeedChance(10, lengthof(name_swedish_2b), seed)], last);
+		strecat(buf, name_swedish_2c[SeedChance(13, lengthof(name_swedish_2c), seed)], last);
+	}
+
+	strecat(buf, name_swedish_3[SeedChance(16, lengthof(name_swedish_3), seed)], last);
+
+	return 0;
+}
+
+static byte MakeDutchTownName(char *buf, uint32 seed, const char *last)
+{
+	int i;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChanceBias(0, lengthof(name_dutch_1), seed, 50);
+	if (i >= 0)
+		strecat(buf, name_dutch_1[i], last);
+
+	// mandatory middle segments including option of hardcoded name
+	if (SeedChance(6, 9, seed) > 4) {
+		strecat(buf, name_dutch_2[SeedChance( 9, lengthof(name_dutch_2), seed)], last);
+	} else {
+		strecat(buf, name_dutch_3[SeedChance( 9, lengthof(name_dutch_3), seed)], last);
+		strecat(buf, name_dutch_4[SeedChance(12, lengthof(name_dutch_4), seed)], last);
+	}
+	strecat(buf, name_dutch_5[SeedChance(15, lengthof(name_dutch_5), seed)], last);
+
+	return 0;
+}
+
+static byte MakeFinnishTownName(char *buf, uint32 seed, const char *last)
+{
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// Select randomly if town name should consists of one or two parts.
+	if (SeedChance(0, 15, seed) >= 10) {
+		strecat(buf, name_finnish_real[SeedChance(2, lengthof(name_finnish_real), seed)], last);
+	} else if (SeedChance(0, 15, seed) >= 5) {
+		// A two-part name by combining one of name_finnish_1 + "la"/"lä"
+		// The reason for not having the contents of name_finnish_{1,2} in the same table is
+		// that the ones in name_finnish_2 are not good for this purpose.
+		uint sel = SeedChance( 0, lengthof(name_finnish_1), seed);
+		char *end;
+		strecat(buf, name_finnish_1[sel], last);
+		end = &buf[strlen(buf)-1];
+		if (*end == 'i')
+			*end = 'e';
+		if (strstr(buf, "a") || strstr(buf, "o") || strstr(buf, "u") ||
+			strstr(buf, "A") || strstr(buf, "O") || strstr(buf, "U"))
+		{
+			strecat(buf, "la", last);
+		} else {
+			strecat(buf, "lä", last);
+		}
+	} else {
+		// A two-part name by combining one of name_finnish_{1,2} + name_finnish_3.
+		// Why aren't name_finnish_{1,2} just one table? See above.
+		uint sel = SeedChance(2,
+			lengthof(name_finnish_1) + lengthof(name_finnish_2), seed);
+		if (sel >= lengthof(name_finnish_1)) {
+			strecat(buf, name_finnish_2[sel-lengthof(name_finnish_1)], last);
+		} else {
+			strecat(buf, name_finnish_1[sel], last);
+		}
+		strecat(buf, name_finnish_3[SeedChance(10, lengthof(name_finnish_3), seed)], last);
+	}
+
+	return 0;
+}
+
+static byte MakePolishTownName(char *buf, uint32 seed, const char *last)
+{
+	uint i;
+	uint j;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChance(0,
+		lengthof(name_polish_2_o) + lengthof(name_polish_2_m) +
+		lengthof(name_polish_2_f) + lengthof(name_polish_2_n),
+		seed);
+	j = SeedChance(2, 20, seed);
+
+
+	if (i < lengthof(name_polish_2_o)) {
+		strecat(buf, name_polish_2_o[SeedChance(3, lengthof(name_polish_2_o), seed)], last);
+	} else if (i < lengthof(name_polish_2_m) + lengthof(name_polish_2_o)) {
+		if (j < 4)
+			strecat(buf, name_polish_1_m[SeedChance(5, lengthof(name_polish_1_m), seed)], last);
+
+		strecat(buf, name_polish_2_m[SeedChance(7, lengthof(name_polish_2_m), seed)], last);
+
+		if (j >= 4 && j < 16)
+			strecat(buf, name_polish_3_m[SeedChance(10, lengthof(name_polish_3_m), seed)], last);
+	} else if (i < lengthof(name_polish_2_f) + lengthof(name_polish_2_m) + lengthof(name_polish_2_o)) {
+		if (j < 4)
+			strecat(buf, name_polish_1_f[SeedChance(5, lengthof(name_polish_1_f), seed)], last);
+
+		strecat(buf, name_polish_2_f[SeedChance(7, lengthof(name_polish_2_f), seed)], last);
+
+		if (j >= 4 && j < 16)
+			strecat(buf, name_polish_3_f[SeedChance(10, lengthof(name_polish_3_f), seed)], last);
+	} else {
+		if (j < 4)
+			strecat(buf, name_polish_1_n[SeedChance(5, lengthof(name_polish_1_n), seed)], last);
+
+		strecat(buf, name_polish_2_n[SeedChance(7, lengthof(name_polish_2_n), seed)], last);
+
+		if (j >= 4 && j < 16)
+			strecat(buf, name_polish_3_n[SeedChance(10, lengthof(name_polish_3_n), seed)], last);
+	}
+	return 0;
+}
+
+static byte MakeCzechTownName(char *buf, uint32 seed, const char *last)
+{
+	/* Probability of prefixes/suffixes */
+	/* 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
+	int prob_tails;
+	bool do_prefix, do_suffix, dynamic_subst;
+	/* IDs of the respective parts */
+	int prefix = 0, ending = 0, suffix = 0;
+	uint postfix = 0;
+	uint stem;
+	/* The select criteria. */
+	CzechGender gender;
+	CzechChoose choose;
+	CzechAllow allow;
+
+	// 1:3 chance to use a real name.
+	if (SeedModChance(0, 4, seed) == 0) {
+		strecpy(buf, name_czech_real[SeedModChance(4, lengthof(name_czech_real), seed)], last);
+		return 0;
+	}
+
+	// NUL terminates the string for strcat()
+	strecpy(buf, "", last);
+
+	prob_tails = SeedModChance(2, 32, seed);
+	do_prefix = prob_tails < 12;
+	do_suffix = prob_tails > 11 && prob_tails < 17;
+
+	if (do_prefix) prefix = SeedModChance(5, lengthof(name_czech_adj) * 12, seed) / 12;
+	if (do_suffix) suffix = SeedModChance(7, lengthof(name_czech_suffix), seed);
+	// 3:1 chance 3:1 to use dynamic substantive
+	stem = SeedModChance(9,
+		lengthof(name_czech_subst_full) + 3 * lengthof(name_czech_subst_stem),
+		seed);
+	if (stem < lengthof(name_czech_subst_full)) {
+		// That was easy!
+		dynamic_subst = false;
+		gender = name_czech_subst_full[stem].gender;
+		choose = name_czech_subst_full[stem].choose;
+		allow = name_czech_subst_full[stem].allow;
+	} else {
+		unsigned int map[lengthof(name_czech_subst_ending)];
+		int ending_start = -1, ending_stop = -1;
+		int i;
+
+		// Load the substantive
+		dynamic_subst = true;
+		stem -= lengthof(name_czech_subst_full);
+		stem %= lengthof(name_czech_subst_stem);
+		gender = name_czech_subst_stem[stem].gender;
+		choose = name_czech_subst_stem[stem].choose;
+		allow = name_czech_subst_stem[stem].allow;
+
+		// Load the postfix (1:1 chance that a postfix will be inserted)
+		postfix = SeedModChance(14, lengthof(name_czech_subst_postfix) * 2, seed);
+
+		if (choose & CZC_POSTFIX) {
+			// Always get a real postfix.
+			postfix %= lengthof(name_czech_subst_postfix);
+		}
+		if (choose & CZC_NOPOSTFIX) {
+			// Always drop a postfix.
+			postfix += lengthof(name_czech_subst_postfix);
+		}
+		if (postfix < lengthof(name_czech_subst_postfix)) {
+			choose |= CZC_POSTFIX;
+		} else {
+			choose |= CZC_NOPOSTFIX;
+		}
+
+		// Localize the array segment containing a good gender
+		for (ending = 0; ending < (int) lengthof(name_czech_subst_ending); ending++) {
+			const CzechNameSubst *e = &name_czech_subst_ending[ending];
+
+			if (gender == CZG_FREE ||
+					(gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) ||
+					gender == e->gender) {
+				if (ending_start < 0)
+					ending_start = ending;
+
+			} else if (ending_start >= 0) {
+				ending_stop = ending - 1;
+				break;
+			}
+		}
+		if (ending_stop < 0) {
+			// Whoa. All the endings matched.
+			ending_stop = ending - 1;
+		}
+
+		// Make a sequential map of the items with good mask
+		i = 0;
+		for (ending = ending_start; ending <= ending_stop; ending++) {
+			const CzechNameSubst *e = &name_czech_subst_ending[ending];
+
+			if ((e->choose & choose) == choose && (e->allow & allow) != 0)
+				map[i++] = ending;
+		}
+		assert(i > 0);
+
+		// Load the ending
+		ending = map[SeedModChance(16, i, seed)];
+		// Override possible CZG_*FREE; this must be a real gender,
+		// otherwise we get overflow when modifying the adjectivum.
+		gender = name_czech_subst_ending[ending].gender;
+		assert(gender != CZG_FREE && gender != CZG_NFREE);
+	}
+
+	if (do_prefix && (name_czech_adj[prefix].choose & choose) != choose) {
+		// Throw away non-matching prefix.
+		do_prefix = false;
+	}
+
+	// Now finally construct the name
+
+	if (do_prefix) {
+		CzechPattern pattern = name_czech_adj[prefix].pattern;
+		size_t endpos;
+
+		strecat(buf, name_czech_adj[prefix].name, last);
+		endpos = strlen(buf) - 1;
+		/* Find the first character in a UTF-8 sequence */
+		while (GB(buf[endpos], 6, 2) == 2) endpos--;
+		if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
+			/* -ovX -> -uv */
+			buf[endpos - 2] = 'u';
+			assert(buf[endpos - 1] == 'v');
+			buf[endpos] = '\0';
+		} else {
+			strecpy(buf + endpos, name_czech_patmod[gender][pattern], last);
+		}
+
+		strecat(buf, " ", last);
+	}
+
+	if (dynamic_subst) {
+		strecat(buf, name_czech_subst_stem[stem].name, last);
+		if (postfix < lengthof(name_czech_subst_postfix)) {
+			const char *poststr = name_czech_subst_postfix[postfix];
+			const char *endstr = name_czech_subst_ending[ending].name;
+			size_t postlen, endlen;
+
+			postlen = strlen(poststr);
+			endlen = strlen(endstr);
+			assert(postlen > 0 && endlen > 0);
+
+			// Kill the "avava" and "Jananna"-like cases
+			if (postlen < 2 || postlen > endlen || (
+						(poststr[1] != 'v' || poststr[1] != endstr[1]) &&
+						poststr[2] != endstr[1])
+					) {
+				size_t buflen;
+				strecat(buf, poststr, last);
+				buflen = strlen(buf);
+
+				// k-i -> c-i, h-i -> z-i
+				if (endstr[0] == 'i') {
+					switch (buf[buflen - 1]) {
+						case 'k': buf[buflen - 1] = 'c'; break;
+						case 'h': buf[buflen - 1] = 'z'; break;
+						default: break;
+					}
+				}
+			}
+		}
+		strecat(buf, name_czech_subst_ending[ending].name, last);
+	} else {
+		strecat(buf, name_czech_subst_full[stem].name, last);
+	}
+
+	if (do_suffix) {
+		strecat(buf, " ", last);
+		strecat(buf, name_czech_suffix[suffix], last);
+	}
+
+	return 0;
+}
+
+static byte MakeRomanianTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_romanian_real[SeedChance(0, lengthof(name_romanian_real), seed)], last);
+	return 0;
+}
+
+static byte MakeSlovakTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_slovak_real[SeedChance(0, lengthof(name_slovak_real), seed)], last);
+	return 0;
+}
+
+static byte MakeNorwegianTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, "", last);
+
+	// Use first 4 bit from seed to decide whether or not this town should
+	// have a real name 3/16 chance.  Bit 0-3
+	if (SeedChance(0, 15, seed) < 3) {
+		// Use 7bit for the realname table index.  Bit 4-10
+		strecat(buf, name_norwegian_real[SeedChance(4, lengthof(name_norwegian_real), seed)], last);
+	} else {
+		// Use 7bit for the first fake part.  Bit 4-10
+		strecat(buf, name_norwegian_1[SeedChance(4, lengthof(name_norwegian_1), seed)], last);
+		// Use 7bit for the last fake part.  Bit 11-17
+		strecat(buf, name_norwegian_2[SeedChance(11, lengthof(name_norwegian_2), seed)], last);
+	}
+
+	return 0;
+}
+
+static byte MakeHungarianTownName(char *buf, uint32 seed, const char *last)
+{
+	uint i;
+
+	//null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	if (SeedChance(12, 15, seed) < 3) {
+		strecat(buf, name_hungarian_real[SeedChance(0, lengthof(name_hungarian_real), seed)], last);
+	} else {
+		// optional first segment
+		i = SeedChance(3, lengthof(name_hungarian_1) * 3, seed);
+		if (i < lengthof(name_hungarian_1))
+			strecat(buf, name_hungarian_1[i], last);
+
+		// mandatory middle segments
+		strecat(buf, name_hungarian_2[SeedChance(3, lengthof(name_hungarian_2), seed)], last);
+		strecat(buf, name_hungarian_3[SeedChance(6, lengthof(name_hungarian_3), seed)], last);
+
+		// optional last segment
+		i = SeedChance(10, lengthof(name_hungarian_4) * 3, seed);
+		if (i < lengthof(name_hungarian_4)) {
+			strecat(buf, name_hungarian_4[i], last);
+		}
+	}
+
+	return 0;
+}
+
+static byte MakeSwissTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, name_swiss_real[SeedChance(0, lengthof(name_swiss_real), seed)], last);
+	return 0;
+}
+
+static byte MakeDanishTownName(char *buf, uint32 seed, const char *last)
+{
+	int i;
+
+	// null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	// optional first segment
+	i = SeedChanceBias(0, lengthof(name_danish_1), seed, 50);
+	if (i >= 0)
+		strecat(buf, name_danish_1[i], last);
+
+	// middle segments removed as this algorithm seems to create much more realistic names
+	strecat(buf, name_danish_2[SeedChance( 7, lengthof(name_danish_2), seed)], last);
+	strecat(buf, name_danish_3[SeedChance(16, lengthof(name_danish_3), seed)], last);
+
+	return 0;
+}
+
+static byte MakeTurkishTownName(char *buf, uint32 seed, const char *last)
+{
+	uint i;
+
+	// null terminates the string for strcat
+	strecpy(buf, "", last);
+
+	if ((i = SeedModChance(0, 5, seed)) == 0) {
+		strecat(buf, name_turkish_prefix[SeedModChance( 2, lengthof(name_turkish_prefix), seed)], last);
+
+		// middle segment
+		strecat(buf, name_turkish_middle[SeedModChance( 4, lengthof(name_turkish_middle), seed)], last);
+
+		// optional suffix
+		if (SeedModChance(0, 7, seed) == 0) {
+			strecat(buf, name_turkish_suffix[SeedModChance( 10, lengthof(name_turkish_suffix), seed)], last);
+		}
+	} else {
+		if (i == 1 || i == 2) {
+			strecat(buf, name_turkish_prefix[SeedModChance( 2, lengthof(name_turkish_prefix), seed)], last);
+			strecat(buf, name_turkish_suffix[SeedModChance( 4, lengthof(name_turkish_suffix), seed)], last);
+		} else {
+			strecat(buf, name_turkish_real[SeedModChance( 4, lengthof(name_turkish_real), seed)], last);
+		}
+	}
+	return 0;
+}
+
+static const char *mascul_femin_italian[] = {
+	"o",
+	"a",
+};
+
+static byte MakeItalianTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, "", last);
+
+	if (SeedModChance(0, 6, seed) == 0) { // real city names
+		strecat(buf, name_italian_real[SeedModChance(4, lengthof(name_italian_real), seed)], last);
+	} else {
+		uint i;
+
+		if (SeedModChance(0, 8, seed) == 0) { // prefix
+			strecat(buf, name_italian_pref[SeedModChance(11, lengthof(name_italian_pref), seed)], last);
+		}
+
+		i = SeedChance(0, 2, seed);
+		if (i == 0) { // masculine form
+			strecat(buf, name_italian_1m[SeedModChance(4, lengthof(name_italian_1m), seed)], last);
+		} else { // feminine form
+			strecat(buf, name_italian_1f[SeedModChance(4, lengthof(name_italian_1f), seed)], last);
+		}
+
+		if (SeedModChance(3, 3, seed) == 0) {
+			strecat(buf, name_italian_2[SeedModChance(11, lengthof(name_italian_2), seed)], last);
+			strecat(buf,mascul_femin_italian[i], last);
+		} else {
+			strecat(buf, name_italian_2i[SeedModChance(16, lengthof(name_italian_2i), seed)], last);
+		}
+
+		if (SeedModChance(15, 4, seed) == 0) {
+			if (SeedModChance(5, 2, seed) == 0) { // generic suffix
+				strecat(buf, name_italian_3[SeedModChance(4, lengthof(name_italian_3), seed)], last);
+			} else { // river name suffix
+				strecat(buf, name_italian_river1[SeedModChance(4, lengthof(name_italian_river1), seed)], last);
+				strecat(buf, name_italian_river2[SeedModChance(16, lengthof(name_italian_river2), seed)], last);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static byte MakeCatalanTownName(char *buf, uint32 seed, const char *last)
+{
+	strecpy(buf, "", last);
+
+	if (SeedModChance(0, 3, seed) == 0) { // real city names
+		strecat(buf, name_catalan_real[SeedModChance(4, lengthof(name_catalan_real), seed)], last);
+	} else {
+		uint i;
+
+		if (SeedModChance(0, 2, seed) == 0) { // prefix
+			strecat(buf, name_catalan_pref[SeedModChance(11, lengthof(name_catalan_pref), seed)], last);
+		}
+
+		i = SeedChance(0, 2, seed);
+		if (i == 0) { // masculine form
+			strecat(buf, name_catalan_1m[SeedModChance(4, lengthof(name_catalan_1m), seed)], last);
+			strecat(buf, name_catalan_2m[SeedModChance(11, lengthof(name_catalan_2m), seed)], last);
+		} else { // feminine form
+			strecat(buf, name_catalan_1f[SeedModChance(4, lengthof(name_catalan_1f), seed)], last);
+			strecat(buf, name_catalan_2f[SeedModChance(11, lengthof(name_catalan_2f), seed)], last);
+		}
+
+
+		if (SeedModChance(15, 5, seed) == 0) {
+			if (SeedModChance(5, 2, seed) == 0) { // generic suffix
+				strecat(buf, name_catalan_3[SeedModChance(4, lengthof(name_catalan_3), seed)], last);
+			} else { // river name suffix
+				strecat(buf, name_catalan_river1[SeedModChance(4, lengthof(name_catalan_river1), seed)], last);
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+
+TownNameGenerator * const _town_name_generators[] =
+{
+	MakeEnglishOriginalTownName,
+	MakeFrenchTownName,
+	MakeGermanTownName,
+	MakeEnglishAdditionalTownName,
+	MakeSpanishTownName,
+	MakeSillyTownName,
+	MakeSwedishTownName,
+	MakeDutchTownName,
+	MakeFinnishTownName,
+	MakePolishTownName,
+	MakeSlovakTownName,
+	MakeNorwegianTownName,
+	MakeHungarianTownName,
+	MakeAustrianTownName,
+	MakeRomanianTownName,
+	MakeCzechTownName,
+	MakeSwissTownName,
+	MakeDanishTownName,
+	MakeTurkishTownName,
+	MakeItalianTownName,
+	MakeCatalanTownName,
+};
+
+// DO WE NEED THIS ANY MORE?
+#define FIXNUM(x, y, z) (((((x) << 16) / (y)) + 1) << z)
+
+uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type)
+{
+	switch (old_town_name_type) {
+		case 0: case 3: /* English, American */
+			/* Already OK */
+			return townnameparts;
+
+		case 1: /* French */
+			/* For some reason 86 needs to be subtracted from townnameparts
+			 * 0000 0000 0000 0000 0000 0000 1111 1111 */
+			return FIXNUM(townnameparts - 86, lengthof(name_french_real), 0);
+
+		case 2: /* German */
+			DEBUG(misc, 0, "German Townnames are buggy (%d)", townnameparts);
+			return townnameparts;
+
+		case 4: /* Latin-American */
+			/* 0000 0000 0000 0000 0000 0000 1111 1111 */
+			return FIXNUM(townnameparts, lengthof(name_spanish_real), 0);
+
+		case 5: /* Silly */
+			/* NUM_SILLY_1 - lower 16 bits
+			 * NUM_SILLY_2 - upper 16 bits without leading 1 (first 8 bytes)
+			 * 1000 0000 2222 2222 0000 0000 1111 1111 */
+			return FIXNUM(townnameparts, lengthof(name_silly_1), 0) | FIXNUM(GB(townnameparts, 16, 8), lengthof(name_silly_2), 16);
+	}
+	return 0;
+}
deleted file mode 100644
--- a/src/network/core/core.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../../stdafx.h"
-#include "../../debug.h"
-#include "os_abstraction.h"
-
-#ifdef __MORPHOS__
-/* the library base is required here */
-struct Library *SocketBase = NULL;
-#endif
-
-/**
- * Initializes the network core (as that is needed for some platforms
- */
-bool NetworkCoreInitialize(void)
-{
-#if defined(__MORPHOS__) || defined(__AMIGA__)
-	/*
-	 *  IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_
-	 *  network related function, else: crash.
-	 */
-	DEBUG(net, 3, "[core] loading bsd socket library");
-	SocketBase = OpenLibrary("bsdsocket.library", 4);
-	if (SocketBase == NULL) {
-		DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable");
-		return false;
-	}
-
-#if defined(__AMIGA__)
-	/* for usleep() implementation (only required for legacy AmigaOS builds) */
-	TimerPort = CreateMsgPort();
-	if (TimerPort != NULL) {
-		TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest);
-		if (TimerRequest != NULL) {
-			if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) {
-				TimerBase = TimerRequest->tr_node.io_Device;
-				if (TimerBase == NULL) {
-					/* free ressources... */
-					DEBUG(net, 0, "[core] can't initialize timer, network unavailable");
-					return false;
-				}
-			}
-		}
-	}
-#endif // __AMIGA__
-#endif // __MORPHOS__ / __AMIGA__
-
-/* Let's load the network in windows */
-#ifdef WIN32
-	{
-		WSADATA wsa;
-		DEBUG(net, 3, "[core] loading windows socket library");
-		if (WSAStartup(MAKEWORD(2, 0), &wsa) != 0) {
-			DEBUG(net, 0, "[core] WSAStartup failed, network unavailable");
-			return false;
-		}
-	}
-#endif /* WIN32 */
-
-	return true;
-}
-
-/**
- * Shuts down the network core (as that is needed for some platforms
- */
-void NetworkCoreShutdown(void)
-{
-#if defined(__MORPHOS__) || defined(__AMIGA__)
-	/* free allocated resources */
-#if defined(__AMIGA__)
-	if (TimerBase    != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong
-	if (TimerRequest != NULL) DeleteIORequest(TimerRequest);
-	if (TimerPort    != NULL) DeleteMsgPort(TimerPort);
-#endif
-
-	if (SocketBase != NULL) CloseLibrary(SocketBase);
-#endif
-
-#if defined(WIN32)
-	WSACleanup();
-#endif
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/core/core.cpp
@@ -0,0 +1,86 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "os_abstraction.h"
+
+#ifdef __MORPHOS__
+/* the library base is required here */
+struct Library *SocketBase = NULL;
+#endif
+
+/**
+ * Initializes the network core (as that is needed for some platforms
+ */
+bool NetworkCoreInitialize(void)
+{
+#if defined(__MORPHOS__) || defined(__AMIGA__)
+	/*
+	 *  IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_
+	 *  network related function, else: crash.
+	 */
+	DEBUG(net, 3, "[core] loading bsd socket library");
+	SocketBase = OpenLibrary("bsdsocket.library", 4);
+	if (SocketBase == NULL) {
+		DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable");
+		return false;
+	}
+
+#if defined(__AMIGA__)
+	/* for usleep() implementation (only required for legacy AmigaOS builds) */
+	TimerPort = CreateMsgPort();
+	if (TimerPort != NULL) {
+		TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest);
+		if (TimerRequest != NULL) {
+			if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) {
+				TimerBase = TimerRequest->tr_node.io_Device;
+				if (TimerBase == NULL) {
+					/* free ressources... */
+					DEBUG(net, 0, "[core] can't initialize timer, network unavailable");
+					return false;
+				}
+			}
+		}
+	}
+#endif // __AMIGA__
+#endif // __MORPHOS__ / __AMIGA__
+
+/* Let's load the network in windows */
+#ifdef WIN32
+	{
+		WSADATA wsa;
+		DEBUG(net, 3, "[core] loading windows socket library");
+		if (WSAStartup(MAKEWORD(2, 0), &wsa) != 0) {
+			DEBUG(net, 0, "[core] WSAStartup failed, network unavailable");
+			return false;
+		}
+	}
+#endif /* WIN32 */
+
+	return true;
+}
+
+/**
+ * Shuts down the network core (as that is needed for some platforms
+ */
+void NetworkCoreShutdown(void)
+{
+#if defined(__MORPHOS__) || defined(__AMIGA__)
+	/* free allocated resources */
+#if defined(__AMIGA__)
+	if (TimerBase    != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong
+	if (TimerRequest != NULL) DeleteIORequest(TimerRequest);
+	if (TimerPort    != NULL) DeleteMsgPort(TimerPort);
+#endif
+
+	if (SocketBase != NULL) CloseLibrary(SocketBase);
+#endif
+
+#if defined(WIN32)
+	WSACleanup();
+#endif
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/core/packet.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../../stdafx.h"
-#include "../../macros.h"
-#include "../../string.h"
-
-#include "packet.h"
-
-/**
- * @file packet.h Basic functions to create, fill and read packets.
- */
-
-
-/* Do not want to include functions.h and all required headers */
-extern void NORETURN CDECL error(const char *str, ...);
-
-
-/**
- * Create a packet for sending
- * @param type the of packet
- * @return the newly created packet
- */
-Packet *NetworkSend_Init(const PacketType type)
-{
-	Packet *packet = malloc(sizeof(Packet));
-	/* An error is inplace here, because it simply means we ran out of memory. */
-	if (packet == NULL) error("Failed to allocate Packet");
-
-	/* Skip the size so we can write that in before sending the packet */
-	packet->size = sizeof(packet->size);
-	packet->buffer[packet->size++] = type;
-	packet->pos = 0;
-
-	return packet;
-}
-
-/**
- * Writes the packet size from the raw packet from packet->size
- * @param packet the packet to write the size of
- */
-void NetworkSend_FillPacketSize(Packet *packet)
-{
-	packet->buffer[0] = GB(packet->size, 0, 8);
-	packet->buffer[1] = GB(packet->size, 8, 8);
-}
-
-/**
- * The next couple of functions make sure we can send
- *  uint8, uint16, uint32 and uint64 endian-safe
- *  over the network. The least significant bytes are
- *  sent first.
- *
- *  So 0x01234567 would be sent as 67 45 23 01.
- */
-
-void NetworkSend_uint8(Packet *packet, uint8 data)
-{
-	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
-	packet->buffer[packet->size++] = data;
-}
-
-void NetworkSend_uint16(Packet *packet, uint16 data)
-{
-	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
-	packet->buffer[packet->size++] = GB(data, 0, 8);
-	packet->buffer[packet->size++] = GB(data, 8, 8);
-}
-
-void NetworkSend_uint32(Packet *packet, uint32 data)
-{
-	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
-	packet->buffer[packet->size++] = GB(data,  0, 8);
-	packet->buffer[packet->size++] = GB(data,  8, 8);
-	packet->buffer[packet->size++] = GB(data, 16, 8);
-	packet->buffer[packet->size++] = GB(data, 24, 8);
-}
-
-void NetworkSend_uint64(Packet *packet, uint64 data)
-{
-	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
-	packet->buffer[packet->size++] = GB(data,  0, 8);
-	packet->buffer[packet->size++] = GB(data,  8, 8);
-	packet->buffer[packet->size++] = GB(data, 16, 8);
-	packet->buffer[packet->size++] = GB(data, 24, 8);
-	packet->buffer[packet->size++] = GB(data, 32, 8);
-	packet->buffer[packet->size++] = GB(data, 40, 8);
-	packet->buffer[packet->size++] = GB(data, 48, 8);
-	packet->buffer[packet->size++] = GB(data, 56, 8);
-}
-
-/**
- *  Sends a string over the network. It sends out
- *  the string + '\0'. No size-byte or something.
- */
-void NetworkSend_string(Packet *packet, const char* data)
-{
-	assert(data != NULL);
-	assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1);
-	while ((packet->buffer[packet->size++] = *data++) != '\0') {}
-}
-
-
-/**
- * Receiving commands
- * Again, the next couple of functions are endian-safe
- *  see the comment before NetworkSend_uint8 for more info.
- */
-
-
-extern uint CloseConnection(NetworkClientState *cs);
-
-/** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */
-static inline bool CanReadFromPacket(NetworkClientState *cs, const Packet *packet, const uint bytes_to_read)
-{
-	/* Don't allow reading from a closed socket */
-	if (HasClientQuit(cs)) return false;
-
-	/* Check if variable is within packet-size */
-	if (packet->pos + bytes_to_read > packet->size) {
-		CloseConnection(cs);
-		return false;
-	}
-
-	return true;
-}
-
-/**
- * Reads the packet size from the raw packet and stores it in the packet->size
- * @param packet the packet to read the size of
- */
-void NetworkRecv_ReadPacketSize(Packet *packet)
-{
-	packet->size  = (uint16)packet->buffer[0];
-	packet->size += (uint16)packet->buffer[1] << 8;
-}
-
-uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet)
-{
-	uint8 n;
-
-	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
-
-	n = packet->buffer[packet->pos++];
-	return n;
-}
-
-uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet)
-{
-	uint16 n;
-
-	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
-
-	n  = (uint16)packet->buffer[packet->pos++];
-	n += (uint16)packet->buffer[packet->pos++] << 8;
-	return n;
-}
-
-uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet)
-{
-	uint32 n;
-
-	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
-
-	n  = (uint32)packet->buffer[packet->pos++];
-	n += (uint32)packet->buffer[packet->pos++] << 8;
-	n += (uint32)packet->buffer[packet->pos++] << 16;
-	n += (uint32)packet->buffer[packet->pos++] << 24;
-	return n;
-}
-
-uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet)
-{
-	uint64 n;
-
-	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
-
-	n  = (uint64)packet->buffer[packet->pos++];
-	n += (uint64)packet->buffer[packet->pos++] << 8;
-	n += (uint64)packet->buffer[packet->pos++] << 16;
-	n += (uint64)packet->buffer[packet->pos++] << 24;
-	n += (uint64)packet->buffer[packet->pos++] << 32;
-	n += (uint64)packet->buffer[packet->pos++] << 40;
-	n += (uint64)packet->buffer[packet->pos++] << 48;
-	n += (uint64)packet->buffer[packet->pos++] << 56;
-	return n;
-}
-
-/** Reads a string till it finds a '\0' in the stream */
-void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size)
-{
-	PacketSize pos;
-	char *bufp = buffer;
-
-	/* Don't allow reading from a closed socket */
-	if (HasClientQuit(cs)) return;
-
-	pos = p->pos;
-	while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {}
-
-	if (size == 0 || pos == p->size) {
-		*buffer = '\0';
-		/* If size was sooner to zero then the string in the stream
-		 *  skip till the \0, so than packet can be read out correctly for the rest */
-		while (pos < p->size && p->buffer[pos] != '\0') pos++;
-		pos++;
-	}
-	p->pos = pos;
-
-	str_validate(bufp);
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/core/packet.cpp
@@ -0,0 +1,214 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../macros.h"
+#include "../../string.h"
+
+#include "packet.h"
+
+/**
+ * @file packet.h Basic functions to create, fill and read packets.
+ */
+
+
+/* Do not want to include functions.h and all required headers */
+extern void NORETURN CDECL error(const char *str, ...);
+
+
+/**
+ * Create a packet for sending
+ * @param type the of packet
+ * @return the newly created packet
+ */
+Packet *NetworkSend_Init(const PacketType type)
+{
+	Packet *packet = malloc(sizeof(Packet));
+	/* An error is inplace here, because it simply means we ran out of memory. */
+	if (packet == NULL) error("Failed to allocate Packet");
+
+	/* Skip the size so we can write that in before sending the packet */
+	packet->size = sizeof(packet->size);
+	packet->buffer[packet->size++] = type;
+	packet->pos = 0;
+
+	return packet;
+}
+
+/**
+ * Writes the packet size from the raw packet from packet->size
+ * @param packet the packet to write the size of
+ */
+void NetworkSend_FillPacketSize(Packet *packet)
+{
+	packet->buffer[0] = GB(packet->size, 0, 8);
+	packet->buffer[1] = GB(packet->size, 8, 8);
+}
+
+/**
+ * The next couple of functions make sure we can send
+ *  uint8, uint16, uint32 and uint64 endian-safe
+ *  over the network. The least significant bytes are
+ *  sent first.
+ *
+ *  So 0x01234567 would be sent as 67 45 23 01.
+ */
+
+void NetworkSend_uint8(Packet *packet, uint8 data)
+{
+	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
+	packet->buffer[packet->size++] = data;
+}
+
+void NetworkSend_uint16(Packet *packet, uint16 data)
+{
+	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
+	packet->buffer[packet->size++] = GB(data, 0, 8);
+	packet->buffer[packet->size++] = GB(data, 8, 8);
+}
+
+void NetworkSend_uint32(Packet *packet, uint32 data)
+{
+	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
+	packet->buffer[packet->size++] = GB(data,  0, 8);
+	packet->buffer[packet->size++] = GB(data,  8, 8);
+	packet->buffer[packet->size++] = GB(data, 16, 8);
+	packet->buffer[packet->size++] = GB(data, 24, 8);
+}
+
+void NetworkSend_uint64(Packet *packet, uint64 data)
+{
+	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
+	packet->buffer[packet->size++] = GB(data,  0, 8);
+	packet->buffer[packet->size++] = GB(data,  8, 8);
+	packet->buffer[packet->size++] = GB(data, 16, 8);
+	packet->buffer[packet->size++] = GB(data, 24, 8);
+	packet->buffer[packet->size++] = GB(data, 32, 8);
+	packet->buffer[packet->size++] = GB(data, 40, 8);
+	packet->buffer[packet->size++] = GB(data, 48, 8);
+	packet->buffer[packet->size++] = GB(data, 56, 8);
+}
+
+/**
+ *  Sends a string over the network. It sends out
+ *  the string + '\0'. No size-byte or something.
+ */
+void NetworkSend_string(Packet *packet, const char* data)
+{
+	assert(data != NULL);
+	assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1);
+	while ((packet->buffer[packet->size++] = *data++) != '\0') {}
+}
+
+
+/**
+ * Receiving commands
+ * Again, the next couple of functions are endian-safe
+ *  see the comment before NetworkSend_uint8 for more info.
+ */
+
+
+extern uint CloseConnection(NetworkClientState *cs);
+
+/** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */
+static inline bool CanReadFromPacket(NetworkClientState *cs, const Packet *packet, const uint bytes_to_read)
+{
+	/* Don't allow reading from a closed socket */
+	if (HasClientQuit(cs)) return false;
+
+	/* Check if variable is within packet-size */
+	if (packet->pos + bytes_to_read > packet->size) {
+		CloseConnection(cs);
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Reads the packet size from the raw packet and stores it in the packet->size
+ * @param packet the packet to read the size of
+ */
+void NetworkRecv_ReadPacketSize(Packet *packet)
+{
+	packet->size  = (uint16)packet->buffer[0];
+	packet->size += (uint16)packet->buffer[1] << 8;
+}
+
+uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet)
+{
+	uint8 n;
+
+	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
+
+	n = packet->buffer[packet->pos++];
+	return n;
+}
+
+uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet)
+{
+	uint16 n;
+
+	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
+
+	n  = (uint16)packet->buffer[packet->pos++];
+	n += (uint16)packet->buffer[packet->pos++] << 8;
+	return n;
+}
+
+uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet)
+{
+	uint32 n;
+
+	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
+
+	n  = (uint32)packet->buffer[packet->pos++];
+	n += (uint32)packet->buffer[packet->pos++] << 8;
+	n += (uint32)packet->buffer[packet->pos++] << 16;
+	n += (uint32)packet->buffer[packet->pos++] << 24;
+	return n;
+}
+
+uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet)
+{
+	uint64 n;
+
+	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
+
+	n  = (uint64)packet->buffer[packet->pos++];
+	n += (uint64)packet->buffer[packet->pos++] << 8;
+	n += (uint64)packet->buffer[packet->pos++] << 16;
+	n += (uint64)packet->buffer[packet->pos++] << 24;
+	n += (uint64)packet->buffer[packet->pos++] << 32;
+	n += (uint64)packet->buffer[packet->pos++] << 40;
+	n += (uint64)packet->buffer[packet->pos++] << 48;
+	n += (uint64)packet->buffer[packet->pos++] << 56;
+	return n;
+}
+
+/** Reads a string till it finds a '\0' in the stream */
+void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size)
+{
+	PacketSize pos;
+	char *bufp = buffer;
+
+	/* Don't allow reading from a closed socket */
+	if (HasClientQuit(cs)) return;
+
+	pos = p->pos;
+	while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {}
+
+	if (size == 0 || pos == p->size) {
+		*buffer = '\0';
+		/* If size was sooner to zero then the string in the stream
+		 *  skip till the \0, so than packet can be read out correctly for the rest */
+		while (pos < p->size && p->buffer[pos] != '\0') pos++;
+		pos++;
+	}
+	p->pos = pos;
+
+	str_validate(bufp);
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/core/tcp.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../../stdafx.h"
-#include "../../debug.h"
-#include "../../openttd.h"
-#include "../../variables.h"
-#include "table/strings.h"
-#include "../../functions.h"
-
-#include "../network_data.h"
-#include "packet.h"
-#include "tcp.h"
-
-/**
- * @file tcp.c Basic functions to receive and send TCP packets.
- */
-
-/**
- * Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit
- *  A socket can make errors. When that happens this handles what to do.
- * For clients: close connection and drop back to main-menu
- * For servers: close connection and that is it
- * @param cs the client to close the connection of
- * @return the new status
- */
-NetworkRecvStatus CloseConnection(NetworkClientState *cs)
-{
-	NetworkCloseClient(cs);
-
-	/* Clients drop back to the main menu */
-	if (!_network_server && _networking) {
-		_switch_mode = SM_MENU;
-		_networking = false;
-		_switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
-
-		return NETWORK_RECV_STATUS_CONN_LOST;
-	}
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-/**
- * Whether the client has quit or not (used in packet.c)
- * @param cs the client to check
- * @return true if the client has quit
- */
-bool HasClientQuit(const NetworkClientState *cs)
-{
-	return cs->has_quit;
-}
-
-/**
- * This function puts the packet in the send-queue and it is send as
- * soon as possible. This is the next tick, or maybe one tick later
- * if the OS-network-buffer is full)
- * @param packet the packet to send
- * @param cs     the client to send to
- */
-void NetworkSend_Packet(Packet *packet, NetworkClientState *cs)
-{
-	Packet *p;
-	assert(packet != NULL);
-
-	packet->pos = 0;
-	packet->next = NULL;
-
-	NetworkSend_FillPacketSize(packet);
-
-	/* Locate last packet buffered for the client */
-	p = cs->packet_queue;
-	if (p == NULL) {
-		/* No packets yet */
-		cs->packet_queue = packet;
-	} else {
-		/* Skip to the last packet */
-		while (p->next != NULL) p = p->next;
-		p->next = packet;
-	}
-}
-
-/**
- * Sends all the buffered packets out for this client. It stops when:
- *   1) all packets are send (queue is empty)
- *   2) the OS reports back that it can not send any more
- *      data right now (full network-buffer, it happens ;))
- *   3) sending took too long
- * @param cs the client to send the packets for
- */
-bool NetworkSend_Packets(NetworkClientState *cs)
-{
-	ssize_t res;
-	Packet *p;
-
-	/* We can not write to this socket!! */
-	if (!cs->writable) return false;
-	if (cs->socket == INVALID_SOCKET) return false;
-
-	p = cs->packet_queue;
-	while (p != NULL) {
-		res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0);
-		if (res == -1) {
-			int err = GET_LAST_ERROR();
-			if (err != EWOULDBLOCK) {
-				/* Something went wrong.. close client! */
-				DEBUG(net, 0, "send failed with error %d", err);
-				CloseConnection(cs);
-				return false;
-			}
-			return true;
-		}
-		if (res == 0) {
-			/* Client/server has left us :( */
-			CloseConnection(cs);
-			return false;
-		}
-
-		p->pos += res;
-
-		/* Is this packet sent? */
-		if (p->pos == p->size) {
-			/* Go to the next packet */
-			cs->packet_queue = p->next;
-			free(p);
-			p = cs->packet_queue;
-		} else {
-			return true;
-		}
-	}
-
-	return true;
-}
-
-/**
- * Receives a packet for the given client
- * @param cs     the client to (try to) receive a packet for
- * @param status the variable to store the status into
- * @return the received packet (or NULL when it didn't receive one)
- */
-Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status)
-{
-	ssize_t res;
-	Packet *p;
-
-	*status = NETWORK_RECV_STATUS_OKAY;
-
-	if (cs->socket == INVALID_SOCKET) return NULL;
-
-	if (cs->packet_recv == NULL) {
-		cs->packet_recv = malloc(sizeof(Packet));
-		if (cs->packet_recv == NULL) error("Failed to allocate packet");
-		/* Set pos to zero! */
-		cs->packet_recv->pos = 0;
-		cs->packet_recv->size = 0; // Can be ommited, just for safety reasons
-	}
-
-	p = cs->packet_recv;
-
-	/* Read packet size */
-	if (p->pos < sizeof(PacketSize)) {
-		while (p->pos < sizeof(PacketSize)) {
-			/* Read the size of the packet */
-			res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
-			if (res == -1) {
-				int err = GET_LAST_ERROR();
-				if (err != EWOULDBLOCK) {
-					/* Something went wrong... (104 is connection reset by peer) */
-					if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
-					*status = CloseConnection(cs);
-					return NULL;
-				}
-				/* Connection would block, so stop for now */
-				return NULL;
-			}
-			if (res == 0) {
-				/* Client/server has left */
-				*status = CloseConnection(cs);
-				return NULL;
-			}
-			p->pos += res;
-		}
-
-		NetworkRecv_ReadPacketSize(p);
-
-		if (p->size > SEND_MTU) {
-			*status = CloseConnection(cs);
-			return NULL;
-		}
-	}
-
-	/* Read rest of packet */
-	while (p->pos < p->size) {
-		res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0);
-		if (res == -1) {
-			int err = GET_LAST_ERROR();
-			if (err != EWOULDBLOCK) {
-				/* Something went wrong... (104 is connection reset by peer) */
-				if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
-				*status = CloseConnection(cs);
-				return NULL;
-			}
-			/* Connection would block */
-			return NULL;
-		}
-		if (res == 0) {
-			/* Client/server has left */
-			*status = CloseConnection(cs);
-			return NULL;
-		}
-
-		p->pos += res;
-	}
-
-	/* We have a complete packet, return it! */
-	p->pos = 2;
-	p->next = NULL; // Should not be needed, but who knows...
-
-	/* Prepare for receiving a new packet */
-	cs->packet_recv = NULL;
-
-	return p;
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/core/tcp.cpp
@@ -0,0 +1,225 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "../../openttd.h"
+#include "../../variables.h"
+#include "table/strings.h"
+#include "../../functions.h"
+
+#include "../network_data.h"
+#include "packet.h"
+#include "tcp.h"
+
+/**
+ * @file tcp.c Basic functions to receive and send TCP packets.
+ */
+
+/**
+ * Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit
+ *  A socket can make errors. When that happens this handles what to do.
+ * For clients: close connection and drop back to main-menu
+ * For servers: close connection and that is it
+ * @param cs the client to close the connection of
+ * @return the new status
+ */
+NetworkRecvStatus CloseConnection(NetworkClientState *cs)
+{
+	NetworkCloseClient(cs);
+
+	/* Clients drop back to the main menu */
+	if (!_network_server && _networking) {
+		_switch_mode = SM_MENU;
+		_networking = false;
+		_switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
+
+		return NETWORK_RECV_STATUS_CONN_LOST;
+	}
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+/**
+ * Whether the client has quit or not (used in packet.c)
+ * @param cs the client to check
+ * @return true if the client has quit
+ */
+bool HasClientQuit(const NetworkClientState *cs)
+{
+	return cs->has_quit;
+}
+
+/**
+ * This function puts the packet in the send-queue and it is send as
+ * soon as possible. This is the next tick, or maybe one tick later
+ * if the OS-network-buffer is full)
+ * @param packet the packet to send
+ * @param cs     the client to send to
+ */
+void NetworkSend_Packet(Packet *packet, NetworkClientState *cs)
+{
+	Packet *p;
+	assert(packet != NULL);
+
+	packet->pos = 0;
+	packet->next = NULL;
+
+	NetworkSend_FillPacketSize(packet);
+
+	/* Locate last packet buffered for the client */
+	p = cs->packet_queue;
+	if (p == NULL) {
+		/* No packets yet */
+		cs->packet_queue = packet;
+	} else {
+		/* Skip to the last packet */
+		while (p->next != NULL) p = p->next;
+		p->next = packet;
+	}
+}
+
+/**
+ * Sends all the buffered packets out for this client. It stops when:
+ *   1) all packets are send (queue is empty)
+ *   2) the OS reports back that it can not send any more
+ *      data right now (full network-buffer, it happens ;))
+ *   3) sending took too long
+ * @param cs the client to send the packets for
+ */
+bool NetworkSend_Packets(NetworkClientState *cs)
+{
+	ssize_t res;
+	Packet *p;
+
+	/* We can not write to this socket!! */
+	if (!cs->writable) return false;
+	if (cs->socket == INVALID_SOCKET) return false;
+
+	p = cs->packet_queue;
+	while (p != NULL) {
+		res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0);
+		if (res == -1) {
+			int err = GET_LAST_ERROR();
+			if (err != EWOULDBLOCK) {
+				/* Something went wrong.. close client! */
+				DEBUG(net, 0, "send failed with error %d", err);
+				CloseConnection(cs);
+				return false;
+			}
+			return true;
+		}
+		if (res == 0) {
+			/* Client/server has left us :( */
+			CloseConnection(cs);
+			return false;
+		}
+
+		p->pos += res;
+
+		/* Is this packet sent? */
+		if (p->pos == p->size) {
+			/* Go to the next packet */
+			cs->packet_queue = p->next;
+			free(p);
+			p = cs->packet_queue;
+		} else {
+			return true;
+		}
+	}
+
+	return true;
+}
+
+/**
+ * Receives a packet for the given client
+ * @param cs     the client to (try to) receive a packet for
+ * @param status the variable to store the status into
+ * @return the received packet (or NULL when it didn't receive one)
+ */
+Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status)
+{
+	ssize_t res;
+	Packet *p;
+
+	*status = NETWORK_RECV_STATUS_OKAY;
+
+	if (cs->socket == INVALID_SOCKET) return NULL;
+
+	if (cs->packet_recv == NULL) {
+		cs->packet_recv = malloc(sizeof(Packet));
+		if (cs->packet_recv == NULL) error("Failed to allocate packet");
+		/* Set pos to zero! */
+		cs->packet_recv->pos = 0;
+		cs->packet_recv->size = 0; // Can be ommited, just for safety reasons
+	}
+
+	p = cs->packet_recv;
+
+	/* Read packet size */
+	if (p->pos < sizeof(PacketSize)) {
+		while (p->pos < sizeof(PacketSize)) {
+			/* Read the size of the packet */
+			res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
+			if (res == -1) {
+				int err = GET_LAST_ERROR();
+				if (err != EWOULDBLOCK) {
+					/* Something went wrong... (104 is connection reset by peer) */
+					if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
+					*status = CloseConnection(cs);
+					return NULL;
+				}
+				/* Connection would block, so stop for now */
+				return NULL;
+			}
+			if (res == 0) {
+				/* Client/server has left */
+				*status = CloseConnection(cs);
+				return NULL;
+			}
+			p->pos += res;
+		}
+
+		NetworkRecv_ReadPacketSize(p);
+
+		if (p->size > SEND_MTU) {
+			*status = CloseConnection(cs);
+			return NULL;
+		}
+	}
+
+	/* Read rest of packet */
+	while (p->pos < p->size) {
+		res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0);
+		if (res == -1) {
+			int err = GET_LAST_ERROR();
+			if (err != EWOULDBLOCK) {
+				/* Something went wrong... (104 is connection reset by peer) */
+				if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
+				*status = CloseConnection(cs);
+				return NULL;
+			}
+			/* Connection would block */
+			return NULL;
+		}
+		if (res == 0) {
+			/* Client/server has left */
+			*status = CloseConnection(cs);
+			return NULL;
+		}
+
+		p->pos += res;
+	}
+
+	/* We have a complete packet, return it! */
+	p->pos = 2;
+	p->next = NULL; // Should not be needed, but who knows...
+
+	/* Prepare for receiving a new packet */
+	cs->packet_recv = NULL;
+
+	return p;
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/core/udp.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../../stdafx.h"
-#include "../../debug.h"
-#include "../../macros.h"
-#include "packet.h"
-#include "udp.h"
-
-/**
- * @file udp.c Basic functions to receive and send UDP packets.
- */
-
-/**
- * Start listening on the given host and port.
- * @param udp       the place where the (references to the) UDP are stored
- * @param host      the host (ip) to listen on
- * @param port      the port to listen on
- * @param broadcast whether to allow broadcast sending/receiving
- * @return true if the listening succeeded
- */
-bool NetworkUDPListen(SOCKET *udp, const uint32 host, const uint16 port, const bool broadcast)
-{
-	struct sockaddr_in sin;
-
-	/* Make sure socket is closed */
-	NetworkUDPClose(udp);
-
-	*udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	if (*udp == INVALID_SOCKET) {
-		DEBUG(net, 0, "[udp] failed to start UDP listener");
-		return false;
-	}
-
-	/* set nonblocking mode for socket */
-	{
-		unsigned long blocking = 1;
-#ifndef BEOS_NET_SERVER
-		ioctlsocket(*udp, FIONBIO, &blocking);
-#else
-		setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL);
-#endif
-	}
-
-	sin.sin_family = AF_INET;
-	/* Listen on all IPs */
-	sin.sin_addr.s_addr = host;
-	sin.sin_port = htons(port);
-
-	if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
-		DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port);
-		return false;
-	}
-
-	if (broadcast) {
-		/* Enable broadcast */
-		unsigned long val = 1;
-#ifndef BEOS_NET_SERVER // will work around this, some day; maybe.
-		setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val));
-#endif
-	}
-
-	DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port);
-
-	return true;
-}
-
-/**
- * Close the given UDP socket
- * @param udp the socket to close
- */
-void NetworkUDPClose(SOCKET *udp)
-{
-	if (*udp == INVALID_SOCKET) return;
-
-	closesocket(*udp);
-	*udp = INVALID_SOCKET;
-}
-
-
-/**
- * Send a packet over UDP
- * @param udp  the socket to send over
- * @param p    the packet to send
- * @param recv the receiver (target) of the packet
- */
-void NetworkSendUDP_Packet(const SOCKET udp, Packet *p, const struct sockaddr_in *recv)
-{
-	int res;
-
-	NetworkSend_FillPacketSize(p);
-
-	/* Send the buffer */
-	res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv));
-
-	/* Check for any errors, but ignore it otherwise */
-	if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR());
-}
-
-/**
- * Receive a packet at UDP level
- * @param udp the socket to receive the packet on
- */
-void NetworkUDPReceive(const SOCKET udp)
-{
-	struct sockaddr_in client_addr;
-	socklen_t client_len;
-	int nbytes;
-	Packet p;
-	int packet_len;
-
-	packet_len = sizeof(p.buffer);
-	client_len = sizeof(client_addr);
-
-	/* Try to receive anything */
-	nbytes = recvfrom(udp, p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
-
-	/* We got some bytes for the base header of the packet. */
-	if (nbytes > 2) {
-		NetworkRecv_ReadPacketSize(&p);
-
-		/* If the size does not match the packet must be corrupted.
-		 * Otherwise it will be marked as corrupted later on. */
-		if (nbytes != p.size) {
-			DEBUG(net, 1, "received a packet with mismatching size from %s:%d",
-					inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
-
-			return;
-		}
-
-		/* Put the position on the right place */
-		p.pos = 2;
-		p.next = NULL;
-
-		/* Handle the packet */
-		NetworkHandleUDPPacket(udp, &p, &client_addr);
-	}
-}
-
-
-/**
- * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
- * @param p the packet to write the data to
- * @param c the configuration to write the GRF ID and MD5 checksum from
- */
-void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c)
-{
-	uint j;
-	NetworkSend_uint32(p, c->grfid);
-	for (j = 0; j < sizeof(c->md5sum); j++) {
-		NetworkSend_uint8 (p, c->md5sum[j]);
-	}
-}
-
-/**
- * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
- * @param cs the client state (for closing connect on out-of-bounds reading etc)
- * @param p  the packet to read the data from
- * @param c  the configuration to write the GRF ID and MD5 checksum to
- */
-void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c)
-{
-	uint j;
-	c->grfid = NetworkRecv_uint32(cs, p);
-	for (j = 0; j < sizeof(c->md5sum); j++) {
-		c->md5sum[j] = NetworkRecv_uint8(cs, p);
-	}
-}
-
-
-/**
- * Serializes the NetworkGameInfo struct to the packet
- * @param p    the packet to write the data to
- * @param info the NetworkGameInfo struct to serialize
- */
-void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info)
-{
-	NetworkSend_uint8 (p, NETWORK_GAME_INFO_VERSION);
-
-	/*
-	 *              Please observe the order.
-	 * The parts must be read in the same order as they are sent!
-	 */
-
-	/* Update the documentation in udp.h on changes
-	 * to the NetworkGameInfo wire-protocol! */
-
-	/* NETWORK_GAME_INFO_VERSION = 4 */
-	{
-		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
-		 * the GRFs that are needed, i.e. the ones that the server has
-		 * selected in the NewGRF GUI and not the ones that are used due
-		 * to the fact that they are in [newgrf-static] in openttd.cfg */
-		const GRFConfig *c;
-		uint count = 0;
-
-		/* Count number of GRFs to send information about */
-		for (c = info->grfconfig; c != NULL; c = c->next) {
-			if (!HASBIT(c->flags, GCF_STATIC)) count++;
-		}
-		NetworkSend_uint8 (p, count); // Send number of GRFs
-
-		/* Send actual GRF Identifications */
-		for (c = info->grfconfig; c != NULL; c = c->next) {
-			if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(p, c);
-		}
-	}
-
-	/* NETWORK_GAME_INFO_VERSION = 3 */
-	NetworkSend_uint32(p, info->game_date);
-	NetworkSend_uint32(p, info->start_date);
-
-	/* NETWORK_GAME_INFO_VERSION = 2 */
-	NetworkSend_uint8 (p, info->companies_max);
-	NetworkSend_uint8 (p, info->companies_on);
-	NetworkSend_uint8 (p, info->spectators_max);
-
-	/* NETWORK_GAME_INFO_VERSION = 1 */
-	NetworkSend_string(p, info->server_name);
-	NetworkSend_string(p, info->server_revision);
-	NetworkSend_uint8 (p, info->server_lang);
-	NetworkSend_uint8 (p, info->use_password);
-	NetworkSend_uint8 (p, info->clients_max);
-	NetworkSend_uint8 (p, info->clients_on);
-	NetworkSend_uint8 (p, info->spectators_on);
-	NetworkSend_string(p, info->map_name);
-	NetworkSend_uint16(p, info->map_width);
-	NetworkSend_uint16(p, info->map_height);
-	NetworkSend_uint8 (p, info->map_set);
-	NetworkSend_uint8 (p, info->dedicated);
-}
-
-/**
- * Deserializes the NetworkGameInfo struct from the packet
- * @param cs   the client state (for closing connect on out-of-bounds reading etc)
- * @param p    the packet to read the data from
- * @param info the NetworkGameInfo to deserialize into
- */
-void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info)
-{
-	info->game_info_version = NetworkRecv_uint8(cs, p);
-
-	/*
-	 *              Please observe the order.
-	 * The parts must be read in the same order as they are sent!
-	 */
-
-	/* Update the documentation in udp.h on changes
-	 * to the NetworkGameInfo wire-protocol! */
-
-	switch (info->game_info_version) {
-		case 4: {
-			GRFConfig *c, **dst = &info->grfconfig;
-			uint i;
-			uint num_grfs = NetworkRecv_uint8(cs, p);
-
-			for (i = 0; i < num_grfs; i++) {
-				c = calloc(1, sizeof(*c));
-				NetworkRecv_GRFIdentifier(cs, p, c);
-				HandleIncomingNetworkGameInfoGRFConfig(c);
-
-				/* Append GRFConfig to the list */
-				*dst = c;
-				dst = &c->next;
-			}
-		} /* Fallthrough */
-		case 3:
-			info->game_date      = NetworkRecv_uint32(cs, p);
-			info->start_date     = NetworkRecv_uint32(cs, p);
-			/* Fallthrough */
-		case 2:
-			info->companies_max  = NetworkRecv_uint8 (cs, p);
-			info->companies_on   = NetworkRecv_uint8 (cs, p);
-			info->spectators_max = NetworkRecv_uint8 (cs, p);
-			/* Fallthrough */
-		case 1:
-			NetworkRecv_string(cs, p, info->server_name,     sizeof(info->server_name));
-			NetworkRecv_string(cs, p, info->server_revision, sizeof(info->server_revision));
-			info->server_lang    = NetworkRecv_uint8 (cs, p);
-			info->use_password   = NetworkRecv_uint8 (cs, p);
-			info->clients_max    = NetworkRecv_uint8 (cs, p);
-			info->clients_on     = NetworkRecv_uint8 (cs, p);
-			info->spectators_on  = NetworkRecv_uint8 (cs, p);
-			if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
-				info->game_date    = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
-				info->start_date   = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
-			}
-			NetworkRecv_string(cs, p, info->map_name, sizeof(info->map_name));
-			info->map_width      = NetworkRecv_uint16(cs, p);
-			info->map_height     = NetworkRecv_uint16(cs, p);
-			info->map_set        = NetworkRecv_uint8 (cs, p);
-			info->dedicated      = NetworkRecv_uint8 (cs, p);
-	}
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/core/udp.cpp
@@ -0,0 +1,297 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "../../macros.h"
+#include "packet.h"
+#include "udp.h"
+
+/**
+ * @file udp.c Basic functions to receive and send UDP packets.
+ */
+
+/**
+ * Start listening on the given host and port.
+ * @param udp       the place where the (references to the) UDP are stored
+ * @param host      the host (ip) to listen on
+ * @param port      the port to listen on
+ * @param broadcast whether to allow broadcast sending/receiving
+ * @return true if the listening succeeded
+ */
+bool NetworkUDPListen(SOCKET *udp, const uint32 host, const uint16 port, const bool broadcast)
+{
+	struct sockaddr_in sin;
+
+	/* Make sure socket is closed */
+	NetworkUDPClose(udp);
+
+	*udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (*udp == INVALID_SOCKET) {
+		DEBUG(net, 0, "[udp] failed to start UDP listener");
+		return false;
+	}
+
+	/* set nonblocking mode for socket */
+	{
+		unsigned long blocking = 1;
+#ifndef BEOS_NET_SERVER
+		ioctlsocket(*udp, FIONBIO, &blocking);
+#else
+		setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL);
+#endif
+	}
+
+	sin.sin_family = AF_INET;
+	/* Listen on all IPs */
+	sin.sin_addr.s_addr = host;
+	sin.sin_port = htons(port);
+
+	if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
+		DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port);
+		return false;
+	}
+
+	if (broadcast) {
+		/* Enable broadcast */
+		unsigned long val = 1;
+#ifndef BEOS_NET_SERVER // will work around this, some day; maybe.
+		setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val));
+#endif
+	}
+
+	DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port);
+
+	return true;
+}
+
+/**
+ * Close the given UDP socket
+ * @param udp the socket to close
+ */
+void NetworkUDPClose(SOCKET *udp)
+{
+	if (*udp == INVALID_SOCKET) return;
+
+	closesocket(*udp);
+	*udp = INVALID_SOCKET;
+}
+
+
+/**
+ * Send a packet over UDP
+ * @param udp  the socket to send over
+ * @param p    the packet to send
+ * @param recv the receiver (target) of the packet
+ */
+void NetworkSendUDP_Packet(const SOCKET udp, Packet *p, const struct sockaddr_in *recv)
+{
+	int res;
+
+	NetworkSend_FillPacketSize(p);
+
+	/* Send the buffer */
+	res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv));
+
+	/* Check for any errors, but ignore it otherwise */
+	if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR());
+}
+
+/**
+ * Receive a packet at UDP level
+ * @param udp the socket to receive the packet on
+ */
+void NetworkUDPReceive(const SOCKET udp)
+{
+	struct sockaddr_in client_addr;
+	socklen_t client_len;
+	int nbytes;
+	Packet p;
+	int packet_len;
+
+	packet_len = sizeof(p.buffer);
+	client_len = sizeof(client_addr);
+
+	/* Try to receive anything */
+	nbytes = recvfrom(udp, p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
+
+	/* We got some bytes for the base header of the packet. */
+	if (nbytes > 2) {
+		NetworkRecv_ReadPacketSize(&p);
+
+		/* If the size does not match the packet must be corrupted.
+		 * Otherwise it will be marked as corrupted later on. */
+		if (nbytes != p.size) {
+			DEBUG(net, 1, "received a packet with mismatching size from %s:%d",
+					inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
+
+			return;
+		}
+
+		/* Put the position on the right place */
+		p.pos = 2;
+		p.next = NULL;
+
+		/* Handle the packet */
+		NetworkHandleUDPPacket(udp, &p, &client_addr);
+	}
+}
+
+
+/**
+ * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
+ * @param p the packet to write the data to
+ * @param c the configuration to write the GRF ID and MD5 checksum from
+ */
+void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c)
+{
+	uint j;
+	NetworkSend_uint32(p, c->grfid);
+	for (j = 0; j < sizeof(c->md5sum); j++) {
+		NetworkSend_uint8 (p, c->md5sum[j]);
+	}
+}
+
+/**
+ * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
+ * @param cs the client state (for closing connect on out-of-bounds reading etc)
+ * @param p  the packet to read the data from
+ * @param c  the configuration to write the GRF ID and MD5 checksum to
+ */
+void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c)
+{
+	uint j;
+	c->grfid = NetworkRecv_uint32(cs, p);
+	for (j = 0; j < sizeof(c->md5sum); j++) {
+		c->md5sum[j] = NetworkRecv_uint8(cs, p);
+	}
+}
+
+
+/**
+ * Serializes the NetworkGameInfo struct to the packet
+ * @param p    the packet to write the data to
+ * @param info the NetworkGameInfo struct to serialize
+ */
+void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info)
+{
+	NetworkSend_uint8 (p, NETWORK_GAME_INFO_VERSION);
+
+	/*
+	 *              Please observe the order.
+	 * The parts must be read in the same order as they are sent!
+	 */
+
+	/* Update the documentation in udp.h on changes
+	 * to the NetworkGameInfo wire-protocol! */
+
+	/* NETWORK_GAME_INFO_VERSION = 4 */
+	{
+		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
+		 * the GRFs that are needed, i.e. the ones that the server has
+		 * selected in the NewGRF GUI and not the ones that are used due
+		 * to the fact that they are in [newgrf-static] in openttd.cfg */
+		const GRFConfig *c;
+		uint count = 0;
+
+		/* Count number of GRFs to send information about */
+		for (c = info->grfconfig; c != NULL; c = c->next) {
+			if (!HASBIT(c->flags, GCF_STATIC)) count++;
+		}
+		NetworkSend_uint8 (p, count); // Send number of GRFs
+
+		/* Send actual GRF Identifications */
+		for (c = info->grfconfig; c != NULL; c = c->next) {
+			if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(p, c);
+		}
+	}
+
+	/* NETWORK_GAME_INFO_VERSION = 3 */
+	NetworkSend_uint32(p, info->game_date);
+	NetworkSend_uint32(p, info->start_date);
+
+	/* NETWORK_GAME_INFO_VERSION = 2 */
+	NetworkSend_uint8 (p, info->companies_max);
+	NetworkSend_uint8 (p, info->companies_on);
+	NetworkSend_uint8 (p, info->spectators_max);
+
+	/* NETWORK_GAME_INFO_VERSION = 1 */
+	NetworkSend_string(p, info->server_name);
+	NetworkSend_string(p, info->server_revision);
+	NetworkSend_uint8 (p, info->server_lang);
+	NetworkSend_uint8 (p, info->use_password);
+	NetworkSend_uint8 (p, info->clients_max);
+	NetworkSend_uint8 (p, info->clients_on);
+	NetworkSend_uint8 (p, info->spectators_on);
+	NetworkSend_string(p, info->map_name);
+	NetworkSend_uint16(p, info->map_width);
+	NetworkSend_uint16(p, info->map_height);
+	NetworkSend_uint8 (p, info->map_set);
+	NetworkSend_uint8 (p, info->dedicated);
+}
+
+/**
+ * Deserializes the NetworkGameInfo struct from the packet
+ * @param cs   the client state (for closing connect on out-of-bounds reading etc)
+ * @param p    the packet to read the data from
+ * @param info the NetworkGameInfo to deserialize into
+ */
+void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info)
+{
+	info->game_info_version = NetworkRecv_uint8(cs, p);
+
+	/*
+	 *              Please observe the order.
+	 * The parts must be read in the same order as they are sent!
+	 */
+
+	/* Update the documentation in udp.h on changes
+	 * to the NetworkGameInfo wire-protocol! */
+
+	switch (info->game_info_version) {
+		case 4: {
+			GRFConfig *c, **dst = &info->grfconfig;
+			uint i;
+			uint num_grfs = NetworkRecv_uint8(cs, p);
+
+			for (i = 0; i < num_grfs; i++) {
+				c = calloc(1, sizeof(*c));
+				NetworkRecv_GRFIdentifier(cs, p, c);
+				HandleIncomingNetworkGameInfoGRFConfig(c);
+
+				/* Append GRFConfig to the list */
+				*dst = c;
+				dst = &c->next;
+			}
+		} /* Fallthrough */
+		case 3:
+			info->game_date      = NetworkRecv_uint32(cs, p);
+			info->start_date     = NetworkRecv_uint32(cs, p);
+			/* Fallthrough */
+		case 2:
+			info->companies_max  = NetworkRecv_uint8 (cs, p);
+			info->companies_on   = NetworkRecv_uint8 (cs, p);
+			info->spectators_max = NetworkRecv_uint8 (cs, p);
+			/* Fallthrough */
+		case 1:
+			NetworkRecv_string(cs, p, info->server_name,     sizeof(info->server_name));
+			NetworkRecv_string(cs, p, info->server_revision, sizeof(info->server_revision));
+			info->server_lang    = NetworkRecv_uint8 (cs, p);
+			info->use_password   = NetworkRecv_uint8 (cs, p);
+			info->clients_max    = NetworkRecv_uint8 (cs, p);
+			info->clients_on     = NetworkRecv_uint8 (cs, p);
+			info->spectators_on  = NetworkRecv_uint8 (cs, p);
+			if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
+				info->game_date    = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
+				info->start_date   = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
+			}
+			NetworkRecv_string(cs, p, info->map_name, sizeof(info->map_name));
+			info->map_width      = NetworkRecv_uint16(cs, p);
+			info->map_height     = NetworkRecv_uint16(cs, p);
+			info->map_set        = NetworkRecv_uint8 (cs, p);
+			info->dedicated      = NetworkRecv_uint8 (cs, p);
+	}
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network.c
+++ /dev/null
@@ -1,1389 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "network_data.h"
-
-#if defined(WITH_REV)
-	extern const char _openttd_revision[];
-#elif defined(WITH_REV_HACK)
-	#define WITH_REV
-	const char _openttd_revision[] = WITH_REV_HACK;
-#else
-	const char _openttd_revision[] = NOREV_STRING;
-#endif
-
-
-#ifdef ENABLE_NETWORK
-
-#include "../openttd.h"
-#include "../debug.h"
-#include "../functions.h"
-#include "../string.h"
-#include "../strings.h"
-#include "../map.h"
-#include "../command.h"
-#include "../variables.h"
-#include "../date.h"
-#include "../newgrf_config.h"
-#include "table/strings.h"
-#include "network_client.h"
-#include "network_server.h"
-#include "network_udp.h"
-#include "network_gamelist.h"
-#include "core/udp.h"
-#include "core/tcp.h"
-#include "core/core.h"
-#include "network_gui.h"
-#include "../console.h" /* IConsoleCmdExec */
-#include <stdarg.h> /* va_list */
-#include "../md5.h"
-
-// The listen socket for the server
-static SOCKET _listensocket;
-
-// The amount of clients connected
-static byte _network_clients_connected = 0;
-// The index counter for new clients (is never decreased)
-static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1;
-
-/* Some externs / forwards */
-extern void StateGameLoop(void);
-
-// Function that looks up the CI for a given client-index
-NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
-{
-	NetworkClientInfo *ci;
-
-	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
-		if (ci->client_index == client_index) return ci;
-	}
-
-	return NULL;
-}
-
-/** Return the CI for a given IP
- * @param ip IP of the client we are looking for. This must be in string-format
- * @return return a pointer to the corresponding NetworkClientInfo struct or NULL on failure */
-NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
-{
-	NetworkClientInfo *ci;
-	uint32 ip_number = inet_addr(ip);
-
-	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
-		if (ci->client_ip == ip_number) return ci;
-	}
-
-	return NULL;
-}
-
-// Function that looks up the CS for a given client-index
-NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index)
-{
-	NetworkClientState *cs;
-
-	for (cs = _clients; cs != endof(_clients); cs++) {
-		if (cs->index == client_index) return cs;
-	}
-
-	return NULL;
-}
-
-// NetworkGetClientName is a server-safe function to get the name of the client
-//  if the user did not send it yet, Client #<no> is used.
-void NetworkGetClientName(char *client_name, size_t size, const NetworkClientState *cs)
-{
-	const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
-
-	if (ci->client_name[0] == '\0') {
-		snprintf(client_name, size, "Client #%4d", cs->index);
-	} else {
-		ttd_strlcpy(client_name, ci->client_name, size);
-	}
-}
-
-byte NetworkSpectatorCount(void)
-{
-	const NetworkClientState *cs;
-	byte count = 0;
-
-	FOR_ALL_CLIENTS(cs) {
-		if (DEREF_CLIENT_INFO(cs)->client_playas == PLAYER_SPECTATOR) count++;
-	}
-
-	return count;
-}
-
-// This puts a text-message to the console, or in the future, the chat-box,
-//  (to keep it all a bit more general)
-// If 'self_send' is true, this is the client who is sending the message
-void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...)
-{
-	char buf[1024];
-	va_list va;
-	const int duration = 10; // Game days the messages stay visible
-	char message[1024];
-	char temp[1024];
-
-	va_start(va, str);
-	vsnprintf(buf, lengthof(buf), str, va);
-	va_end(va);
-
-	switch (action) {
-		case NETWORK_ACTION_SERVER_MESSAGE:
-			color = 1;
-			snprintf(message, sizeof(message), "*** %s", buf);
-			break;
-		case NETWORK_ACTION_JOIN:
-			color = 1;
-			GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp));
-			snprintf(message, sizeof(message), "*** %s %s", name, temp);
-			break;
-		case NETWORK_ACTION_LEAVE:
-			color = 1;
-			GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp));
-			snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf);
-			break;
-		case NETWORK_ACTION_GIVE_MONEY:
-			if (self_send) {
-				SetDParamStr(0, name);
-				SetDParam(1, atoi(buf));
-				GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp));
-				snprintf(message, sizeof(message), "*** %s", temp);
-			} else {
-				SetDParam(0, atoi(buf));
-				GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp));
-				snprintf(message, sizeof(message), "*** %s %s", name, temp);
-			}
-			break;
-		case NETWORK_ACTION_NAME_CHANGE:
-			GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp));
-			snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf);
-			break;
-		case NETWORK_ACTION_CHAT_COMPANY:
-			SetDParamStr(0, name);
-			SetDParamStr(1, buf);
-			GetString(temp, self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, lastof(temp));
-			ttd_strlcpy(message, temp, sizeof(message));
-			break;
-		case NETWORK_ACTION_CHAT_CLIENT:
-			SetDParamStr(0, name);
-			SetDParamStr(1, buf);
-			GetString(temp, self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, lastof(temp));
-			ttd_strlcpy(message, temp, sizeof(message));
-			break;
-		default:
-			SetDParamStr(0, name);
-			SetDParamStr(1, buf);
-			GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp));
-			ttd_strlcpy(message, temp, sizeof(message));
-			break;
-	}
-
-	IConsolePrintF(color, "%s", message);
-	AddTextMessage(color, duration, "%s", message);
-}
-
-// Calculate the frame-lag of a client
-uint NetworkCalculateLag(const NetworkClientState *cs)
-{
-	int lag = cs->last_frame_server - cs->last_frame;
-	// This client has missed his ACK packet after 1 DAY_TICKS..
-	//  so we increase his lag for every frame that passes!
-	// The packet can be out by a max of _net_frame_freq
-	if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter)
-		lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq);
-
-	return lag;
-}
-
-
-// There was a non-recoverable error, drop back to the main menu with a nice
-//  error
-static void NetworkError(StringID error_string)
-{
-	_switch_mode = SM_MENU;
-	_switch_mode_errorstr = error_string;
-}
-
-static void ClientStartError(const char *error)
-{
-	DEBUG(net, 0, "[client] could not start network: %s",error);
-	NetworkError(STR_NETWORK_ERR_CLIENT_START);
-}
-
-static void ServerStartError(const char *error)
-{
-	DEBUG(net, 0, "[server] could not start network: %s",error);
-	NetworkError(STR_NETWORK_ERR_SERVER_START);
-}
-
-static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs)
-{
-	// First, send a CLIENT_ERROR to the server, so he knows we are
-	//  disconnection (and why!)
-	NetworkErrorCode errorno;
-
-	// We just want to close the connection..
-	if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
-		cs->has_quit = true;
-		NetworkCloseClient(cs);
-		_networking = false;
-
-		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-		return;
-	}
-
-	switch (res) {
-		case NETWORK_RECV_STATUS_DESYNC:   errorno = NETWORK_ERROR_DESYNC; break;
-		case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
-		default:                           errorno = NETWORK_ERROR_GENERAL; break;
-	}
-	// This means we fucked up and the server closed the connection
-	if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
-			res != NETWORK_RECV_STATUS_SERVER_BANNED) {
-		SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
-
-		// Dequeue all commands before closing the socket
-		NetworkSend_Packets(DEREF_CLIENT(0));
-	}
-
-	_switch_mode = SM_MENU;
-	NetworkCloseClient(cs);
-	_networking = false;
-}
-
-/** Retrieve a string representation of an internal error number
- * @param buf buffer where the error message will be stored
- * @param err NetworkErrorCode
- * @return returns a pointer to the error message (buf) */
-char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last)
-{
-	/* List of possible network errors, used by
-	 * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */
-	static const StringID network_error_strings[] = {
-		STR_NETWORK_ERR_CLIENT_GENERAL,
-		STR_NETWORK_ERR_CLIENT_DESYNC,
-		STR_NETWORK_ERR_CLIENT_SAVEGAME,
-		STR_NETWORK_ERR_CLIENT_CONNECTION_LOST,
-		STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR,
-		STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED,
-		STR_NETWORK_ERR_CLIENT_NOT_EXPECTED,
-		STR_NETWORK_ERR_CLIENT_WRONG_REVISION,
-		STR_NETWORK_ERR_CLIENT_NAME_IN_USE,
-		STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD,
-		STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH,
-		STR_NETWORK_ERR_CLIENT_KICKED,
-		STR_NETWORK_ERR_CLIENT_CHEATER,
-		STR_NETWORK_ERR_CLIENT_SERVER_FULL
-	};
-
-	if (err >= lengthof(network_error_strings)) err = 0;
-
-	return GetString(buf, network_error_strings[err], last);
-}
-
-/* Count the number of active clients connected */
-static uint NetworkCountPlayers(void)
-{
-	const NetworkClientState *cs;
-	uint count = 0;
-
-	FOR_ALL_CLIENTS(cs) {
-		const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
-		if (IsValidPlayer(ci->client_playas)) count++;
-	}
-
-	return count;
-}
-
-static bool _min_players_paused = false;
-
-/* Check if the minimum number of players has been reached and pause or unpause the game as appropriate */
-void CheckMinPlayers(void)
-{
-	if (!_network_dedicated) return;
-
-	if (NetworkCountPlayers() < _network_min_players) {
-		if (_min_players_paused) return;
-
-		_min_players_paused = true;
-		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX);
-	} else {
-		if (!_min_players_paused) return;
-
-		_min_players_paused = false;
-		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
-		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX);
-	}
-}
-
-// Find all IP-aliases for this host
-static void NetworkFindIPs(void)
-{
-	int i;
-
-#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
-	/* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
-	int _netstat(int fd, char **output, int verbose);
-
-	int seek_past_header(char **pos, const char *header) {
-		char *new_pos = strstr(*pos, header);
-		if (new_pos == 0) {
-			return B_ERROR;
-		}
-		*pos += strlen(header) + new_pos - *pos + 1;
-		return B_OK;
-	}
-
-	int output_length;
-	char *output_pointer = NULL;
-	char **output;
-	int sock = socket(AF_INET, SOCK_DGRAM, 0);
-	i = 0;
-
-	// If something fails, make sure the list is empty
-	_broadcast_list[0] = 0;
-
-	if (sock < 0) {
-		DEBUG(net, 0, "[core] error creating socket");
-		return;
-	}
-
-	output_length = _netstat(sock, &output_pointer, 1);
-	if (output_length < 0) {
-		DEBUG(net, 0, "[core] error running _netstat");
-		return;
-	}
-
-	output = &output_pointer;
-	if (seek_past_header(output, "IP Interfaces:") == B_OK) {
-		for (;;) {
-			uint32 n, fields, read;
-			uint8 i1, i2, i3, i4, j1, j2, j3, j4;
-			struct in_addr inaddr;
-			uint32 ip;
-			uint32 netmask;
-
-			fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
-												&n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read);
-			read += 1;
-			if (fields != 9) {
-				break;
-			}
-
-			ip      = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
-			netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
-
-			if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
-				inaddr.s_addr = htonl(ip | ~netmask);
-				_broadcast_list[i] = inaddr.s_addr;
-				i++;
-			}
-			if (read < 0) {
-				break;
-			}
-			*output += read;
-		}
-		/* XXX - Using either one of these crashes openttd heavily? - wber */
-		/*free(output_pointer);*/
-		/*free(output);*/
-		closesocket(sock);
-	}
-#elif defined(HAVE_GETIFADDRS)
-	struct ifaddrs *ifap, *ifa;
-
-	// If something fails, make sure the list is empty
-	_broadcast_list[0] = 0;
-
-	if (getifaddrs(&ifap) != 0)
-		return;
-
-	i = 0;
-	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-		if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
-		if (ifa->ifa_broadaddr == NULL) continue;
-		if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
-		_broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr;
-		i++;
-	}
-	freeifaddrs(ifap);
-
-#else /* not HAVE_GETIFADDRS */
-	SOCKET sock;
-#ifdef WIN32
-	DWORD len = 0;
-	INTERFACE_INFO ifo[MAX_INTERFACES];
-	uint j;
-#else
-	char buf[4 * 1024]; // Arbitrary buffer size
-	struct ifconf ifconf;
-	const char* buf_end;
-	const char* p;
-#endif
-
-	// If something fails, make sure the list is empty
-	_broadcast_list[0] = 0;
-
-	sock = socket(AF_INET, SOCK_DGRAM, 0);
-	if (sock == INVALID_SOCKET) return;
-
-#ifdef WIN32
-	memset(&ifo[0], 0, sizeof(ifo));
-	if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) {
-		closesocket(sock);
-		return;
-	}
-
-	i = 0;
-	for (j = 0; j < len / sizeof(*ifo); j++) {
-		if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
-		if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
-		/* iiBroadcast is unusable, because it always seems to be set to
-		 * 255.255.255.255.
-		 */
-		_broadcast_list[i++] =
-			 ifo[j].iiAddress.AddressIn.sin_addr.s_addr |
-			~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
-	}
-#else
-	ifconf.ifc_len = sizeof(buf);
-	ifconf.ifc_buf = buf;
-	if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
-		closesocket(sock);
-		return;
-	}
-
-	i = 0;
-	buf_end = buf + ifconf.ifc_len;
-	for (p = buf; p < buf_end;) {
-		const struct ifreq* req = (const struct ifreq*)p;
-
-		if (req->ifr_addr.sa_family == AF_INET) {
-			struct ifreq r;
-
-			strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name));
-			if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
-					r.ifr_flags & IFF_BROADCAST &&
-					ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
-				_broadcast_list[i++] =
-					((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr;
-			}
-		}
-
-		p += sizeof(struct ifreq);
-#ifdef AF_LINK
-		p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
-#endif
-	}
-#endif
-
-	closesocket(sock);
-#endif /* not HAVE_GETIFADDRS */
-
-	_broadcast_list[i] = 0;
-
-	DEBUG(net, 3, "Detected broadcast addresses:");
-	// Now display to the debug all the detected ips
-	for (i = 0; _broadcast_list[i] != 0; i++) {
-		DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr));
-	}
-}
-
-// Resolve a hostname to a inet_addr
-unsigned long NetworkResolveHost(const char *hostname)
-{
-	in_addr_t ip;
-
-	// First try: is it an ip address?
-	ip = inet_addr(hostname);
-
-	// If not try to resolve the name
-	if (ip == INADDR_NONE) {
-		struct hostent *he = gethostbyname(hostname);
-		if (he == NULL) {
-			DEBUG(net, 0, "Cannot resolve '%s'", hostname);
-		} else {
-			struct in_addr addr = *(struct in_addr *)he->h_addr_list[0];
-			DEBUG(net, 1, "Resolved '%s' to %s", hostname, inet_ntoa(addr));
-			ip = addr.s_addr;
-		}
-	}
-	return ip;
-}
-
-// Converts a string to ip/port/player
-//  Format: IP#player:port
-//
-// connection_string will be re-terminated to seperate out the hostname, and player and port will
-// be set to the player and port strings given by the user, inside the memory area originally
-// occupied by connection_string.
-void ParseConnectionString(const char **player, const char **port, char *connection_string)
-{
-	char *p;
-	for (p = connection_string; *p != '\0'; p++) {
-		if (*p == '#') {
-			*p = '\0';
-			*player = ++p;
-			while (IsValidChar(*p, CS_NUMERAL)) p++;
-			if (*p == '\0') break;
-		} else if (*p == ':') {
-			*port = p + 1;
-			*p = '\0';
-		}
-	}
-}
-
-// Creates a new client from a socket
-//   Used both by the server and the client
-static NetworkClientState *NetworkAllocClient(SOCKET s)
-{
-	NetworkClientState *cs;
-	byte client_no = 0;
-
-	if (_network_server) {
-		// Can we handle a new client?
-		if (_network_clients_connected >= MAX_CLIENTS) return NULL;
-		if (_network_game_info.clients_on >= _network_game_info.clients_max) return NULL;
-
-		// Register the login
-		client_no = _network_clients_connected++;
-	}
-
-	cs = DEREF_CLIENT(client_no);
-	memset(cs, 0, sizeof(*cs));
-	cs->socket = s;
-	cs->last_frame = 0;
-	cs->has_quit = false;
-
-	cs->last_frame = _frame_counter;
-	cs->last_frame_server = _frame_counter;
-
-	if (_network_server) {
-		NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
-		memset(ci, 0, sizeof(*ci));
-
-		cs->index = _network_client_index++;
-		ci->client_index = cs->index;
-		ci->client_playas = PLAYER_INACTIVE_CLIENT;
-		ci->join_date = _date;
-
-		InvalidateWindow(WC_CLIENT_LIST, 0);
-	}
-
-	return cs;
-}
-
-// Close a connection
-void NetworkCloseClient(NetworkClientState *cs)
-{
-	NetworkClientInfo *ci;
-	// Socket is already dead
-	if (cs->socket == INVALID_SOCKET) {
-		cs->has_quit = true;
-		return;
-	}
-
-	DEBUG(net, 1, "Closed client connection %d", cs->index);
-
-	if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) {
-		// We did not receive a leave message from this client...
-		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
-		char str[100];
-		char client_name[NETWORK_CLIENT_NAME_LENGTH];
-		NetworkClientState *new_cs;
-
-		NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-		GetNetworkErrorMsg(str, errorno, lastof(str));
-
-		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
-
-		// Inform other clients of this... strange leaving ;)
-		FOR_ALL_CLIENTS(new_cs) {
-			if (new_cs->status > STATUS_AUTH && cs != new_cs) {
-				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
-			}
-		}
-	}
-
-	/* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */
-	if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) {
-		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
-		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
-	}
-
-	closesocket(cs->socket);
-	cs->writable = false;
-	cs->has_quit = true;
-
-	// Free all pending and partially received packets
-	while (cs->packet_queue != NULL) {
-		Packet *p = cs->packet_queue->next;
-		free(cs->packet_queue);
-		cs->packet_queue = p;
-	}
-	free(cs->packet_recv);
-	cs->packet_recv = NULL;
-
-	while (cs->command_queue != NULL) {
-		CommandPacket *p = cs->command_queue->next;
-		free(cs->command_queue);
-		cs->command_queue = p;
-	}
-
-	// Close the gap in the client-list
-	ci = DEREF_CLIENT_INFO(cs);
-
-	if (_network_server) {
-		// We just lost one client :(
-		if (cs->status > STATUS_INACTIVE) _network_game_info.clients_on--;
-		_network_clients_connected--;
-
-		while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) {
-			*cs = *(cs + 1);
-			*ci = *(ci + 1);
-			cs++;
-			ci++;
-		}
-
-		InvalidateWindow(WC_CLIENT_LIST, 0);
-	}
-
-	// Reset the status of the last socket
-	cs->socket = INVALID_SOCKET;
-	cs->status = STATUS_INACTIVE;
-	cs->index = NETWORK_EMPTY_INDEX;
-	ci->client_index = NETWORK_EMPTY_INDEX;
-
-	CheckMinPlayers();
-}
-
-// A client wants to connect to a server
-static bool NetworkConnect(const char *hostname, int port)
-{
-	SOCKET s;
-	struct sockaddr_in sin;
-
-	DEBUG(net, 1, "Connecting to %s %d", hostname, port);
-
-	s = socket(AF_INET, SOCK_STREAM, 0);
-	if (s == INVALID_SOCKET) {
-		ClientStartError("socket() failed");
-		return false;
-	}
-
-	if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed");
-
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = NetworkResolveHost(hostname);
-	sin.sin_port = htons(port);
-	_network_last_host_ip = sin.sin_addr.s_addr;
-
-	/* We failed to connect for which reason what so ever */
-	if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) return false;
-
-	if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
-
-	// in client mode, only the first client field is used. it's pointing to the server.
-	NetworkAllocClient(s);
-
-	_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
-	ShowJoinStatusWindow();
-
-	return true;
-}
-
-// For the server, to accept new clients
-static void NetworkAcceptClients(void)
-{
-	struct sockaddr_in sin;
-	NetworkClientState *cs;
-	uint i;
-	bool banned;
-
-	// Should never ever happen.. is it possible??
-	assert(_listensocket != INVALID_SOCKET);
-
-	for (;;) {
-		socklen_t sin_len = sizeof(sin);
-		SOCKET s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len);
-		if (s == INVALID_SOCKET) return;
-
-		SetNonBlocking(s); // XXX error handling?
-
-		DEBUG(net, 1, "Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter);
-
-		SetNoDelay(s); // XXX error handling?
-
-		/* Check if the client is banned */
-		banned = false;
-		for (i = 0; i < lengthof(_network_ban_list); i++) {
-			if (_network_ban_list[i] == NULL) continue;
-
-			if (sin.sin_addr.s_addr == inet_addr(_network_ban_list[i])) {
-				Packet *p = NetworkSend_Init(PACKET_SERVER_BANNED);
-
-				DEBUG(net, 1, "Banned ip tried to join (%s), refused", _network_ban_list[i]);
-
-				p->buffer[0] = p->size & 0xFF;
-				p->buffer[1] = p->size >> 8;
-
-				send(s, p->buffer, p->size, 0);
-				closesocket(s);
-
-				free(p);
-
-				banned = true;
-				break;
-			}
-		}
-		/* If this client is banned, continue with next client */
-		if (banned) continue;
-
-		cs = NetworkAllocClient(s);
-		if (cs == NULL) {
-			// no more clients allowed?
-			// Send to the client that we are full!
-			Packet *p = NetworkSend_Init(PACKET_SERVER_FULL);
-
-			p->buffer[0] = p->size & 0xFF;
-			p->buffer[1] = p->size >> 8;
-
-			send(s, p->buffer, p->size, 0);
-			closesocket(s);
-
-			free(p);
-
-			continue;
-		}
-
-		// a new client has connected. We set him at inactive for now
-		//  maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK
-		//  the client stays inactive
-		cs->status = STATUS_INACTIVE;
-
-		DEREF_CLIENT_INFO(cs)->client_ip = sin.sin_addr.s_addr; // Save the IP of the client
-	}
-}
-
-// Set up the listen socket for the server
-static bool NetworkListen(void)
-{
-	SOCKET ls;
-	struct sockaddr_in sin;
-
-	DEBUG(net, 1, "Listening on %s:%d", _network_server_bind_ip_host, _network_server_port);
-
-	ls = socket(AF_INET, SOCK_STREAM, 0);
-	if (ls == INVALID_SOCKET) {
-		ServerStartError("socket() on listen socket failed");
-		return false;
-	}
-
-	{ // reuse the socket
-		int reuse = 1;
-		// The (const char*) cast is needed for windows!!
-		if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) {
-			ServerStartError("setsockopt() on listen socket failed");
-			return false;
-		}
-	}
-
-	if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
-
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = _network_server_bind_ip;
-	sin.sin_port = htons(_network_server_port);
-
-	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
-		ServerStartError("bind() failed");
-		return false;
-	}
-
-	if (listen(ls, 1) != 0) {
-		ServerStartError("listen() failed");
-		return false;
-	}
-
-	_listensocket = ls;
-
-	return true;
-}
-
-// Close all current connections
-static void NetworkClose(void)
-{
-	NetworkClientState *cs;
-
-	FOR_ALL_CLIENTS(cs) {
-		if (!_network_server) {
-			SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
-			NetworkSend_Packets(cs);
-		}
-		NetworkCloseClient(cs);
-	}
-
-	if (_network_server) {
-		// We are a server, also close the listensocket
-		closesocket(_listensocket);
-		_listensocket = INVALID_SOCKET;
-		DEBUG(net, 1, "Closed listener");
-		NetworkUDPStop();
-	}
-}
-
-// Inits the network (cleans sockets and stuff)
-static void NetworkInitialize(void)
-{
-	NetworkClientState *cs;
-
-	_local_command_queue = NULL;
-
-	// Clean all client-sockets
-	memset(_clients, 0, sizeof(_clients));
-	for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) {
-		cs->socket = INVALID_SOCKET;
-		cs->status = STATUS_INACTIVE;
-		cs->command_queue = NULL;
-	}
-
-	// Clean the client_info memory
-	memset(&_network_client_info, 0, sizeof(_network_client_info));
-	memset(&_network_player_info, 0, sizeof(_network_player_info));
-
-	_sync_frame = 0;
-	_network_first_time = true;
-
-	_network_reconnect = 0;
-
-	NetworkUDPInitialize();
-}
-
-// Query a server to fetch his game-info
-//  If game_info is true, only the gameinfo is fetched,
-//   else only the client_info is fetched
-NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info)
-{
-	if (!_network_available) return NULL;
-
-	NetworkDisconnect();
-
-	if (game_info) return NetworkUDPQueryServer(host, port);
-
-	NetworkInitialize();
-
-	_network_server = false;
-
-	// Try to connect
-	_networking = NetworkConnect(host, port);
-
-	// We are connected
-	if (_networking) {
-		SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
-	} else { // No networking, close everything down again
-		NetworkDisconnect();
-	}
-
-	return NULL;
-}
-
-/* Validates an address entered as a string and adds the server to
- * the list. If you use this function, the games will be marked
- * as manually added. */
-void NetworkAddServer(const char *b)
-{
-	if (*b != '\0') {
-		NetworkGameList *item;
-		const char *port = NULL;
-		const char *player = NULL;
-		char host[NETWORK_HOSTNAME_LENGTH];
-		uint16 rport;
-
-		ttd_strlcpy(host, b, lengthof(host));
-
-		ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip));
-		rport = NETWORK_DEFAULT_PORT;
-
-		ParseConnectionString(&player, &port, host);
-		if (port != NULL) rport = atoi(port);
-
-		item = NetworkQueryServer(host, rport, true);
-		item->manually = true;
-	}
-}
-
-/* Generates the list of manually added hosts from NetworkGameList and
- * dumps them into the array _network_host_list. This array is needed
- * by the function that generates the config file. */
-void NetworkRebuildHostList(void)
-{
-	uint i = 0;
-	const NetworkGameList *item = _network_game_list;
-	while (item != NULL && i != lengthof(_network_host_list)) {
-		if (item->manually) {
-			free(_network_host_list[i]);
-			_network_host_list[i++] = str_fmt("%s:%i", item->info.hostname, item->port);
-		}
-		item = item->next;
-	}
-
-	for (; i < lengthof(_network_host_list); i++) {
-		free(_network_host_list[i]);
-		_network_host_list[i] = NULL;
-	}
-}
-
-// Used by clients, to connect to a server
-bool NetworkClientConnectGame(const char *host, uint16 port)
-{
-	if (!_network_available) return false;
-
-	if (port == 0) return false;
-
-	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
-	_network_last_port = port;
-
-	NetworkDisconnect();
-	NetworkUDPStop();
-	NetworkInitialize();
-
-	// Try to connect
-	_networking = NetworkConnect(host, port);
-
-	// We are connected
-	if (_networking) {
-		IConsoleCmdExec("exec scripts/on_client.scr 0");
-		NetworkClient_Connected();
-	} else {
-		// Connecting failed
-		NetworkError(STR_NETWORK_ERR_NOCONNECTION);
-	}
-
-	return _networking;
-}
-
-static void NetworkInitGameInfo(void)
-{
-	NetworkClientInfo *ci;
-
-	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
-	ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
-	ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_rcon_password));
-	if (_network_game_info.server_name[0] == '\0')
-		snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
-
-	ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
-
-	// The server is a client too ;)
-	if (_network_dedicated) {
-		_network_game_info.clients_on = 0;
-		_network_game_info.companies_on = 0;
-		_network_game_info.dedicated = true;
-	} else {
-		_network_game_info.clients_on = 1;
-		_network_game_info.companies_on = 1;
-		_network_game_info.dedicated = false;
-	}
-
-	_network_game_info.spectators_on = 0;
-
-	_network_game_info.game_date = _date;
-	_network_game_info.start_date = ConvertYMDToDate(_patches.starting_year, 0, 1);
-	_network_game_info.map_width = MapSizeX();
-	_network_game_info.map_height = MapSizeY();
-	_network_game_info.map_set = _opt.landscape;
-
-	_network_game_info.use_password = (_network_server_password[0] != '\0');
-
-	// We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it
-	//  The index is NETWORK_SERVER_INDEX ( = 1)
-	ci = &_network_client_info[MAX_CLIENT_INFO - 1];
-	memset(ci, 0, sizeof(*ci));
-
-	ci->client_index = NETWORK_SERVER_INDEX;
-	ci->client_playas = _network_dedicated ? PLAYER_SPECTATOR : _local_player;
-
-	ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
-	ttd_strlcpy(ci->unique_id, _network_unique_id, sizeof(ci->unique_id));
-}
-
-bool NetworkServerStart(void)
-{
-	if (!_network_available) return false;
-
-	/* Call the pre-scripts */
-	IConsoleCmdExec("exec scripts/pre_server.scr 0");
-	if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
-
-	NetworkInitialize();
-	if (!NetworkListen()) return false;
-
-	// Try to start UDP-server
-	_network_udp_server = true;
-	_network_udp_server = NetworkUDPListen(&_udp_server_socket, _network_server_bind_ip, _network_server_port, false);
-
-	_network_server = true;
-	_networking = true;
-	_frame_counter = 0;
-	_frame_counter_server = 0;
-	_frame_counter_max = 0;
-	_last_sync_frame = 0;
-	_network_own_client_index = NETWORK_SERVER_INDEX;
-
-	/* Non-dedicated server will always be player #1 */
-	if (!_network_dedicated) _network_playas = 0;
-
-	_network_clients_connected = 0;
-
-	NetworkInitGameInfo();
-
-	// execute server initialization script
-	IConsoleCmdExec("exec scripts/on_server.scr 0");
-	// if the server is dedicated ... add some other script
-	if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
-
-	_min_players_paused = false;
-	CheckMinPlayers();
-
-	/* Try to register us to the master server */
-	_network_last_advertise_frame = 0;
-	_network_need_advertise = true;
-	NetworkUDPAdvertise();
-	return true;
-}
-
-// The server is rebooting...
-// The only difference with NetworkDisconnect, is the packets that is sent
-void NetworkReboot(void)
-{
-	if (_network_server) {
-		NetworkClientState *cs;
-		FOR_ALL_CLIENTS(cs) {
-			SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
-			NetworkSend_Packets(cs);
-		}
-	}
-
-	NetworkClose();
-
-	// Free all queued commands
-	while (_local_command_queue != NULL) {
-		CommandPacket *p = _local_command_queue;
-		_local_command_queue = _local_command_queue->next;
-		free(p);
-	}
-
-	_networking = false;
-	_network_server = false;
-}
-
-// We want to disconnect from the host/clients
-void NetworkDisconnect(void)
-{
-	if (_network_server) {
-		NetworkClientState *cs;
-		FOR_ALL_CLIENTS(cs) {
-			SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
-			NetworkSend_Packets(cs);
-		}
-	}
-
-	if (_network_advertise) NetworkUDPRemoveAdvertise();
-
-	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-
-	NetworkClose();
-
-	// Free all queued commands
-	while (_local_command_queue != NULL) {
-		CommandPacket *p = _local_command_queue;
-		_local_command_queue = _local_command_queue->next;
-		free(p);
-	}
-
-	_networking = false;
-	_network_server = false;
-}
-
-// Receives something from the network
-static bool NetworkReceive(void)
-{
-	NetworkClientState *cs;
-	int n;
-	fd_set read_fd, write_fd;
-	struct timeval tv;
-
-	FD_ZERO(&read_fd);
-	FD_ZERO(&write_fd);
-
-	FOR_ALL_CLIENTS(cs) {
-		FD_SET(cs->socket, &read_fd);
-		FD_SET(cs->socket, &write_fd);
-	}
-
-	// take care of listener port
-	if (_network_server) FD_SET(_listensocket, &read_fd);
-
-	tv.tv_sec = tv.tv_usec = 0; // don't block at all.
-#if !defined(__MORPHOS__) && !defined(__AMIGA__)
-	n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
-#else
-	n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
-#endif
-	if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION);
-
-	// accept clients..
-	if (_network_server && FD_ISSET(_listensocket, &read_fd)) NetworkAcceptClients();
-
-	// read stuff from clients
-	FOR_ALL_CLIENTS(cs) {
-		cs->writable = !!FD_ISSET(cs->socket, &write_fd);
-		if (FD_ISSET(cs->socket, &read_fd)) {
-			if (_network_server) {
-				NetworkServer_ReadPackets(cs);
-			} else {
-				NetworkRecvStatus res;
-
-				// The client already was quiting!
-				if (cs->has_quit) return false;
-
-				res = NetworkClient_ReadPackets(cs);
-				if (res != NETWORK_RECV_STATUS_OKAY) {
-					// The client made an error of which we can not recover
-					//   close the client and drop back to main menu
-					NetworkClientError(res, cs);
-					return false;
-				}
-			}
-		}
-	}
-	return true;
-}
-
-// This sends all buffered commands (if possible)
-static void NetworkSend(void)
-{
-	NetworkClientState *cs;
-	FOR_ALL_CLIENTS(cs) {
-		if (cs->writable) {
-			NetworkSend_Packets(cs);
-
-			if (cs->status == STATUS_MAP) {
-				// This client is in the middle of a map-send, call the function for that
-				SEND_COMMAND(PACKET_SERVER_MAP)(cs);
-			}
-		}
-	}
-}
-
-// Handle the local-command-queue
-static void NetworkHandleLocalQueue(void)
-{
-	CommandPacket *cp, **cp_prev;
-
-	cp_prev = &_local_command_queue;
-
-	while ( (cp = *cp_prev) != NULL) {
-
-		// The queue is always in order, which means
-		// that the first element will be executed first.
-		if (_frame_counter < cp->frame) break;
-
-		if (_frame_counter > cp->frame) {
-			// If we reach here, it means for whatever reason, we've already executed
-			// past the command we need to execute.
-			DEBUG(net, 0, "Trying to execute a packet in the past!");
-			assert(0);
-		}
-
-		// We can execute this command
-		NetworkExecuteCommand(cp);
-
-		*cp_prev = cp->next;
-		free(cp);
-	}
-
-	// Just a safety check, to be removed in the future.
-	// Make sure that no older command appears towards the end of the queue
-	// In that case we missed executing it. This will never happen.
-	for (cp = _local_command_queue; cp; cp = cp->next) {
-		assert(_frame_counter < cp->frame);
-	}
-
-}
-
-static bool NetworkDoClientLoop(void)
-{
-	_frame_counter++;
-
-	NetworkHandleLocalQueue();
-
-	StateGameLoop();
-
-	// Check if we are in sync!
-	if (_sync_frame != 0) {
-		if (_sync_frame == _frame_counter) {
-#ifdef NETWORK_SEND_DOUBLE_SEED
-			if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) {
-#else
-			if (_sync_seed_1 != _random_seeds[0][0]) {
-#endif
-				NetworkError(STR_NETWORK_ERR_DESYNC);
-				DEBUG(net, 0, "Sync error detected!");
-				NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0));
-				return false;
-			}
-
-			// If this is the first time we have a sync-frame, we
-			//   need to let the server know that we are ready and at the same
-			//   frame as he is.. so we can start playing!
-			if (_network_first_time) {
-				_network_first_time = false;
-				SEND_COMMAND(PACKET_CLIENT_ACK)();
-			}
-
-			_sync_frame = 0;
-		} else if (_sync_frame < _frame_counter) {
-			DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
-			_sync_frame = 0;
-		}
-	}
-
-	return true;
-}
-
-// We have to do some UDP checking
-void NetworkUDPGameLoop(void)
-{
-	if (_network_udp_server) {
-		NetworkUDPReceive(_udp_server_socket);
-		if (_udp_master_socket != INVALID_SOCKET) {
-			NetworkUDPReceive(_udp_master_socket);
-		}
-	} else if (_udp_client_socket != INVALID_SOCKET) {
-		NetworkUDPReceive(_udp_client_socket);
-		if (_network_udp_broadcast > 0) _network_udp_broadcast--;
-	}
-}
-
-// The main loop called from ttd.c
-//  Here we also have to do StateGameLoop if needed!
-void NetworkGameLoop(void)
-{
-	if (!_networking) return;
-
-	if (!NetworkReceive()) return;
-
-	if (_network_server) {
-		bool send_frame = false;
-
-		// We first increase the _frame_counter
-		_frame_counter++;
-		// Update max-frame-counter
-		if (_frame_counter > _frame_counter_max) {
-			_frame_counter_max = _frame_counter + _network_frame_freq;
-			send_frame = true;
-		}
-
-		NetworkHandleLocalQueue();
-
-		// Then we make the frame
-		StateGameLoop();
-
-		_sync_seed_1 = _random_seeds[0][0];
-#ifdef NETWORK_SEND_DOUBLE_SEED
-		_sync_seed_2 = _random_seeds[0][1];
-#endif
-
-		NetworkServer_Tick(send_frame);
-	} else {
-		// Client
-
-		// Make sure we are at the frame were the server is (quick-frames)
-		if (_frame_counter_server > _frame_counter) {
-			while (_frame_counter_server > _frame_counter) {
-				if (!NetworkDoClientLoop()) break;
-			}
-		} else {
-			// Else, keep on going till _frame_counter_max
-			if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
-		}
-	}
-
-	NetworkSend();
-}
-
-static void NetworkGenerateUniqueId(void)
-{
-	md5_state_t state;
-	md5_byte_t digest[16];
-	char hex_output[16*2 + 1];
-	char coding_string[NETWORK_NAME_LENGTH];
-	int di;
-
-	snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
-
-	/* Generate the MD5 hash */
-	md5_init(&state);
-	md5_append(&state, (const md5_byte_t*)coding_string, strlen(coding_string));
-	md5_finish(&state, digest);
-
-	for (di = 0; di < 16; ++di)
-		sprintf(hex_output + di * 2, "%02x", digest[di]);
-
-	/* _network_unique_id is our id */
-	snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output);
-}
-
-/** This tries to launch the network for a given OS */
-void NetworkStartUp(void)
-{
-	DEBUG(net, 3, "[core] starting network...");
-
-	/* Network is available */
-	_network_available = NetworkCoreInitialize();;
-	_network_dedicated = false;
-	_network_last_advertise_frame = 0;
-	_network_need_advertise = true;
-	_network_advertise_retries = 0;
-
-	/* Load the ip from the openttd.cfg */
-	_network_server_bind_ip = inet_addr(_network_server_bind_ip_host);
-	/* And put the data back in it in case it was an invalid ip */
-	snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
-
-	/* Generate an unique id when there is none yet */
-	if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId();
-
-	{
-		byte cl_max = _network_game_info.clients_max;
-		byte cp_max = _network_game_info.companies_max;
-		byte sp_max = _network_game_info.spectators_max;
-
-		memset(&_network_game_info, 0, sizeof(_network_game_info));
-		_network_game_info.clients_max = cl_max;
-		_network_game_info.companies_max = cp_max;
-		_network_game_info.spectators_max = sp_max;
-	}
-
-
-	NetworkInitialize();
-	DEBUG(net, 3, "[core] network online, multiplayer available");
-	NetworkFindIPs();
-}
-
-/** This shuts the network down */
-void NetworkShutDown(void)
-{
-	NetworkDisconnect();
-	NetworkUDPStop();
-
-	DEBUG(net, 3, "[core] shutting down network");
-
-	_network_available = false;
-
-	NetworkCoreShutdown();
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network.cpp
@@ -0,0 +1,1389 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "network_data.h"
+
+#if defined(WITH_REV)
+	extern const char _openttd_revision[];
+#elif defined(WITH_REV_HACK)
+	#define WITH_REV
+	const char _openttd_revision[] = WITH_REV_HACK;
+#else
+	const char _openttd_revision[] = NOREV_STRING;
+#endif
+
+
+#ifdef ENABLE_NETWORK
+
+#include "../openttd.h"
+#include "../debug.h"
+#include "../functions.h"
+#include "../string.h"
+#include "../strings.h"
+#include "../map.h"
+#include "../command.h"
+#include "../variables.h"
+#include "../date.h"
+#include "../newgrf_config.h"
+#include "table/strings.h"
+#include "network_client.h"
+#include "network_server.h"
+#include "network_udp.h"
+#include "network_gamelist.h"
+#include "core/udp.h"
+#include "core/tcp.h"
+#include "core/core.h"
+#include "network_gui.h"
+#include "../console.h" /* IConsoleCmdExec */
+#include <stdarg.h> /* va_list */
+#include "../md5.h"
+
+// The listen socket for the server
+static SOCKET _listensocket;
+
+// The amount of clients connected
+static byte _network_clients_connected = 0;
+// The index counter for new clients (is never decreased)
+static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1;
+
+/* Some externs / forwards */
+extern void StateGameLoop(void);
+
+// Function that looks up the CI for a given client-index
+NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
+{
+	NetworkClientInfo *ci;
+
+	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
+		if (ci->client_index == client_index) return ci;
+	}
+
+	return NULL;
+}
+
+/** Return the CI for a given IP
+ * @param ip IP of the client we are looking for. This must be in string-format
+ * @return return a pointer to the corresponding NetworkClientInfo struct or NULL on failure */
+NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
+{
+	NetworkClientInfo *ci;
+	uint32 ip_number = inet_addr(ip);
+
+	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
+		if (ci->client_ip == ip_number) return ci;
+	}
+
+	return NULL;
+}
+
+// Function that looks up the CS for a given client-index
+NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index)
+{
+	NetworkClientState *cs;
+
+	for (cs = _clients; cs != endof(_clients); cs++) {
+		if (cs->index == client_index) return cs;
+	}
+
+	return NULL;
+}
+
+// NetworkGetClientName is a server-safe function to get the name of the client
+//  if the user did not send it yet, Client #<no> is used.
+void NetworkGetClientName(char *client_name, size_t size, const NetworkClientState *cs)
+{
+	const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
+
+	if (ci->client_name[0] == '\0') {
+		snprintf(client_name, size, "Client #%4d", cs->index);
+	} else {
+		ttd_strlcpy(client_name, ci->client_name, size);
+	}
+}
+
+byte NetworkSpectatorCount(void)
+{
+	const NetworkClientState *cs;
+	byte count = 0;
+
+	FOR_ALL_CLIENTS(cs) {
+		if (DEREF_CLIENT_INFO(cs)->client_playas == PLAYER_SPECTATOR) count++;
+	}
+
+	return count;
+}
+
+// This puts a text-message to the console, or in the future, the chat-box,
+//  (to keep it all a bit more general)
+// If 'self_send' is true, this is the client who is sending the message
+void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...)
+{
+	char buf[1024];
+	va_list va;
+	const int duration = 10; // Game days the messages stay visible
+	char message[1024];
+	char temp[1024];
+
+	va_start(va, str);
+	vsnprintf(buf, lengthof(buf), str, va);
+	va_end(va);
+
+	switch (action) {
+		case NETWORK_ACTION_SERVER_MESSAGE:
+			color = 1;
+			snprintf(message, sizeof(message), "*** %s", buf);
+			break;
+		case NETWORK_ACTION_JOIN:
+			color = 1;
+			GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp));
+			snprintf(message, sizeof(message), "*** %s %s", name, temp);
+			break;
+		case NETWORK_ACTION_LEAVE:
+			color = 1;
+			GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp));
+			snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf);
+			break;
+		case NETWORK_ACTION_GIVE_MONEY:
+			if (self_send) {
+				SetDParamStr(0, name);
+				SetDParam(1, atoi(buf));
+				GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp));
+				snprintf(message, sizeof(message), "*** %s", temp);
+			} else {
+				SetDParam(0, atoi(buf));
+				GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp));
+				snprintf(message, sizeof(message), "*** %s %s", name, temp);
+			}
+			break;
+		case NETWORK_ACTION_NAME_CHANGE:
+			GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp));
+			snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf);
+			break;
+		case NETWORK_ACTION_CHAT_COMPANY:
+			SetDParamStr(0, name);
+			SetDParamStr(1, buf);
+			GetString(temp, self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, lastof(temp));
+			ttd_strlcpy(message, temp, sizeof(message));
+			break;
+		case NETWORK_ACTION_CHAT_CLIENT:
+			SetDParamStr(0, name);
+			SetDParamStr(1, buf);
+			GetString(temp, self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, lastof(temp));
+			ttd_strlcpy(message, temp, sizeof(message));
+			break;
+		default:
+			SetDParamStr(0, name);
+			SetDParamStr(1, buf);
+			GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp));
+			ttd_strlcpy(message, temp, sizeof(message));
+			break;
+	}
+
+	IConsolePrintF(color, "%s", message);
+	AddTextMessage(color, duration, "%s", message);
+}
+
+// Calculate the frame-lag of a client
+uint NetworkCalculateLag(const NetworkClientState *cs)
+{
+	int lag = cs->last_frame_server - cs->last_frame;
+	// This client has missed his ACK packet after 1 DAY_TICKS..
+	//  so we increase his lag for every frame that passes!
+	// The packet can be out by a max of _net_frame_freq
+	if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter)
+		lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq);
+
+	return lag;
+}
+
+
+// There was a non-recoverable error, drop back to the main menu with a nice
+//  error
+static void NetworkError(StringID error_string)
+{
+	_switch_mode = SM_MENU;
+	_switch_mode_errorstr = error_string;
+}
+
+static void ClientStartError(const char *error)
+{
+	DEBUG(net, 0, "[client] could not start network: %s",error);
+	NetworkError(STR_NETWORK_ERR_CLIENT_START);
+}
+
+static void ServerStartError(const char *error)
+{
+	DEBUG(net, 0, "[server] could not start network: %s",error);
+	NetworkError(STR_NETWORK_ERR_SERVER_START);
+}
+
+static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs)
+{
+	// First, send a CLIENT_ERROR to the server, so he knows we are
+	//  disconnection (and why!)
+	NetworkErrorCode errorno;
+
+	// We just want to close the connection..
+	if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
+		cs->has_quit = true;
+		NetworkCloseClient(cs);
+		_networking = false;
+
+		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+		return;
+	}
+
+	switch (res) {
+		case NETWORK_RECV_STATUS_DESYNC:   errorno = NETWORK_ERROR_DESYNC; break;
+		case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
+		default:                           errorno = NETWORK_ERROR_GENERAL; break;
+	}
+	// This means we fucked up and the server closed the connection
+	if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
+			res != NETWORK_RECV_STATUS_SERVER_BANNED) {
+		SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
+
+		// Dequeue all commands before closing the socket
+		NetworkSend_Packets(DEREF_CLIENT(0));
+	}
+
+	_switch_mode = SM_MENU;
+	NetworkCloseClient(cs);
+	_networking = false;
+}
+
+/** Retrieve a string representation of an internal error number
+ * @param buf buffer where the error message will be stored
+ * @param err NetworkErrorCode
+ * @return returns a pointer to the error message (buf) */
+char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last)
+{
+	/* List of possible network errors, used by
+	 * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */
+	static const StringID network_error_strings[] = {
+		STR_NETWORK_ERR_CLIENT_GENERAL,
+		STR_NETWORK_ERR_CLIENT_DESYNC,
+		STR_NETWORK_ERR_CLIENT_SAVEGAME,
+		STR_NETWORK_ERR_CLIENT_CONNECTION_LOST,
+		STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR,
+		STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED,
+		STR_NETWORK_ERR_CLIENT_NOT_EXPECTED,
+		STR_NETWORK_ERR_CLIENT_WRONG_REVISION,
+		STR_NETWORK_ERR_CLIENT_NAME_IN_USE,
+		STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD,
+		STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH,
+		STR_NETWORK_ERR_CLIENT_KICKED,
+		STR_NETWORK_ERR_CLIENT_CHEATER,
+		STR_NETWORK_ERR_CLIENT_SERVER_FULL
+	};
+
+	if (err >= lengthof(network_error_strings)) err = 0;
+
+	return GetString(buf, network_error_strings[err], last);
+}
+
+/* Count the number of active clients connected */
+static uint NetworkCountPlayers(void)
+{
+	const NetworkClientState *cs;
+	uint count = 0;
+
+	FOR_ALL_CLIENTS(cs) {
+		const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
+		if (IsValidPlayer(ci->client_playas)) count++;
+	}
+
+	return count;
+}
+
+static bool _min_players_paused = false;
+
+/* Check if the minimum number of players has been reached and pause or unpause the game as appropriate */
+void CheckMinPlayers(void)
+{
+	if (!_network_dedicated) return;
+
+	if (NetworkCountPlayers() < _network_min_players) {
+		if (_min_players_paused) return;
+
+		_min_players_paused = true;
+		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX);
+	} else {
+		if (!_min_players_paused) return;
+
+		_min_players_paused = false;
+		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX);
+	}
+}
+
+// Find all IP-aliases for this host
+static void NetworkFindIPs(void)
+{
+	int i;
+
+#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
+	/* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
+	int _netstat(int fd, char **output, int verbose);
+
+	int seek_past_header(char **pos, const char *header) {
+		char *new_pos = strstr(*pos, header);
+		if (new_pos == 0) {
+			return B_ERROR;
+		}
+		*pos += strlen(header) + new_pos - *pos + 1;
+		return B_OK;
+	}
+
+	int output_length;
+	char *output_pointer = NULL;
+	char **output;
+	int sock = socket(AF_INET, SOCK_DGRAM, 0);
+	i = 0;
+
+	// If something fails, make sure the list is empty
+	_broadcast_list[0] = 0;
+
+	if (sock < 0) {
+		DEBUG(net, 0, "[core] error creating socket");
+		return;
+	}
+
+	output_length = _netstat(sock, &output_pointer, 1);
+	if (output_length < 0) {
+		DEBUG(net, 0, "[core] error running _netstat");
+		return;
+	}
+
+	output = &output_pointer;
+	if (seek_past_header(output, "IP Interfaces:") == B_OK) {
+		for (;;) {
+			uint32 n, fields, read;
+			uint8 i1, i2, i3, i4, j1, j2, j3, j4;
+			struct in_addr inaddr;
+			uint32 ip;
+			uint32 netmask;
+
+			fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
+												&n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read);
+			read += 1;
+			if (fields != 9) {
+				break;
+			}
+
+			ip      = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
+			netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
+
+			if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
+				inaddr.s_addr = htonl(ip | ~netmask);
+				_broadcast_list[i] = inaddr.s_addr;
+				i++;
+			}
+			if (read < 0) {
+				break;
+			}
+			*output += read;
+		}
+		/* XXX - Using either one of these crashes openttd heavily? - wber */
+		/*free(output_pointer);*/
+		/*free(output);*/
+		closesocket(sock);
+	}
+#elif defined(HAVE_GETIFADDRS)
+	struct ifaddrs *ifap, *ifa;
+
+	// If something fails, make sure the list is empty
+	_broadcast_list[0] = 0;
+
+	if (getifaddrs(&ifap) != 0)
+		return;
+
+	i = 0;
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+		if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
+		if (ifa->ifa_broadaddr == NULL) continue;
+		if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
+		_broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr;
+		i++;
+	}
+	freeifaddrs(ifap);
+
+#else /* not HAVE_GETIFADDRS */
+	SOCKET sock;
+#ifdef WIN32
+	DWORD len = 0;
+	INTERFACE_INFO ifo[MAX_INTERFACES];
+	uint j;
+#else
+	char buf[4 * 1024]; // Arbitrary buffer size
+	struct ifconf ifconf;
+	const char* buf_end;
+	const char* p;
+#endif
+
+	// If something fails, make sure the list is empty
+	_broadcast_list[0] = 0;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock == INVALID_SOCKET) return;
+
+#ifdef WIN32
+	memset(&ifo[0], 0, sizeof(ifo));
+	if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) {
+		closesocket(sock);
+		return;
+	}
+
+	i = 0;
+	for (j = 0; j < len / sizeof(*ifo); j++) {
+		if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
+		if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
+		/* iiBroadcast is unusable, because it always seems to be set to
+		 * 255.255.255.255.
+		 */
+		_broadcast_list[i++] =
+			 ifo[j].iiAddress.AddressIn.sin_addr.s_addr |
+			~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
+	}
+#else
+	ifconf.ifc_len = sizeof(buf);
+	ifconf.ifc_buf = buf;
+	if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
+		closesocket(sock);
+		return;
+	}
+
+	i = 0;
+	buf_end = buf + ifconf.ifc_len;
+	for (p = buf; p < buf_end;) {
+		const struct ifreq* req = (const struct ifreq*)p;
+
+		if (req->ifr_addr.sa_family == AF_INET) {
+			struct ifreq r;
+
+			strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name));
+			if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
+					r.ifr_flags & IFF_BROADCAST &&
+					ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
+				_broadcast_list[i++] =
+					((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr;
+			}
+		}
+
+		p += sizeof(struct ifreq);
+#ifdef AF_LINK
+		p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
+#endif
+	}
+#endif
+
+	closesocket(sock);
+#endif /* not HAVE_GETIFADDRS */
+
+	_broadcast_list[i] = 0;
+
+	DEBUG(net, 3, "Detected broadcast addresses:");
+	// Now display to the debug all the detected ips
+	for (i = 0; _broadcast_list[i] != 0; i++) {
+		DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr));
+	}
+}
+
+// Resolve a hostname to a inet_addr
+unsigned long NetworkResolveHost(const char *hostname)
+{
+	in_addr_t ip;
+
+	// First try: is it an ip address?
+	ip = inet_addr(hostname);
+
+	// If not try to resolve the name
+	if (ip == INADDR_NONE) {
+		struct hostent *he = gethostbyname(hostname);
+		if (he == NULL) {
+			DEBUG(net, 0, "Cannot resolve '%s'", hostname);
+		} else {
+			struct in_addr addr = *(struct in_addr *)he->h_addr_list[0];
+			DEBUG(net, 1, "Resolved '%s' to %s", hostname, inet_ntoa(addr));
+			ip = addr.s_addr;
+		}
+	}
+	return ip;
+}
+
+// Converts a string to ip/port/player
+//  Format: IP#player:port
+//
+// connection_string will be re-terminated to seperate out the hostname, and player and port will
+// be set to the player and port strings given by the user, inside the memory area originally
+// occupied by connection_string.
+void ParseConnectionString(const char **player, const char **port, char *connection_string)
+{
+	char *p;
+	for (p = connection_string; *p != '\0'; p++) {
+		if (*p == '#') {
+			*p = '\0';
+			*player = ++p;
+			while (IsValidChar(*p, CS_NUMERAL)) p++;
+			if (*p == '\0') break;
+		} else if (*p == ':') {
+			*port = p + 1;
+			*p = '\0';
+		}
+	}
+}
+
+// Creates a new client from a socket
+//   Used both by the server and the client
+static NetworkClientState *NetworkAllocClient(SOCKET s)
+{
+	NetworkClientState *cs;
+	byte client_no = 0;
+
+	if (_network_server) {
+		// Can we handle a new client?
+		if (_network_clients_connected >= MAX_CLIENTS) return NULL;
+		if (_network_game_info.clients_on >= _network_game_info.clients_max) return NULL;
+
+		// Register the login
+		client_no = _network_clients_connected++;
+	}
+
+	cs = DEREF_CLIENT(client_no);
+	memset(cs, 0, sizeof(*cs));
+	cs->socket = s;
+	cs->last_frame = 0;
+	cs->has_quit = false;
+
+	cs->last_frame = _frame_counter;
+	cs->last_frame_server = _frame_counter;
+
+	if (_network_server) {
+		NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
+		memset(ci, 0, sizeof(*ci));
+
+		cs->index = _network_client_index++;
+		ci->client_index = cs->index;
+		ci->client_playas = PLAYER_INACTIVE_CLIENT;
+		ci->join_date = _date;
+
+		InvalidateWindow(WC_CLIENT_LIST, 0);
+	}
+
+	return cs;
+}
+
+// Close a connection
+void NetworkCloseClient(NetworkClientState *cs)
+{
+	NetworkClientInfo *ci;
+	// Socket is already dead
+	if (cs->socket == INVALID_SOCKET) {
+		cs->has_quit = true;
+		return;
+	}
+
+	DEBUG(net, 1, "Closed client connection %d", cs->index);
+
+	if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) {
+		// We did not receive a leave message from this client...
+		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
+		char str[100];
+		char client_name[NETWORK_CLIENT_NAME_LENGTH];
+		NetworkClientState *new_cs;
+
+		NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+		GetNetworkErrorMsg(str, errorno, lastof(str));
+
+		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
+
+		// Inform other clients of this... strange leaving ;)
+		FOR_ALL_CLIENTS(new_cs) {
+			if (new_cs->status > STATUS_AUTH && cs != new_cs) {
+				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
+			}
+		}
+	}
+
+	/* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */
+	if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) {
+		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+		NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
+	}
+
+	closesocket(cs->socket);
+	cs->writable = false;
+	cs->has_quit = true;
+
+	// Free all pending and partially received packets
+	while (cs->packet_queue != NULL) {
+		Packet *p = cs->packet_queue->next;
+		free(cs->packet_queue);
+		cs->packet_queue = p;
+	}
+	free(cs->packet_recv);
+	cs->packet_recv = NULL;
+
+	while (cs->command_queue != NULL) {
+		CommandPacket *p = cs->command_queue->next;
+		free(cs->command_queue);
+		cs->command_queue = p;
+	}
+
+	// Close the gap in the client-list
+	ci = DEREF_CLIENT_INFO(cs);
+
+	if (_network_server) {
+		// We just lost one client :(
+		if (cs->status > STATUS_INACTIVE) _network_game_info.clients_on--;
+		_network_clients_connected--;
+
+		while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) {
+			*cs = *(cs + 1);
+			*ci = *(ci + 1);
+			cs++;
+			ci++;
+		}
+
+		InvalidateWindow(WC_CLIENT_LIST, 0);
+	}
+
+	// Reset the status of the last socket
+	cs->socket = INVALID_SOCKET;
+	cs->status = STATUS_INACTIVE;
+	cs->index = NETWORK_EMPTY_INDEX;
+	ci->client_index = NETWORK_EMPTY_INDEX;
+
+	CheckMinPlayers();
+}
+
+// A client wants to connect to a server
+static bool NetworkConnect(const char *hostname, int port)
+{
+	SOCKET s;
+	struct sockaddr_in sin;
+
+	DEBUG(net, 1, "Connecting to %s %d", hostname, port);
+
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s == INVALID_SOCKET) {
+		ClientStartError("socket() failed");
+		return false;
+	}
+
+	if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed");
+
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = NetworkResolveHost(hostname);
+	sin.sin_port = htons(port);
+	_network_last_host_ip = sin.sin_addr.s_addr;
+
+	/* We failed to connect for which reason what so ever */
+	if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) return false;
+
+	if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
+
+	// in client mode, only the first client field is used. it's pointing to the server.
+	NetworkAllocClient(s);
+
+	_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
+	ShowJoinStatusWindow();
+
+	return true;
+}
+
+// For the server, to accept new clients
+static void NetworkAcceptClients(void)
+{
+	struct sockaddr_in sin;
+	NetworkClientState *cs;
+	uint i;
+	bool banned;
+
+	// Should never ever happen.. is it possible??
+	assert(_listensocket != INVALID_SOCKET);
+
+	for (;;) {
+		socklen_t sin_len = sizeof(sin);
+		SOCKET s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len);
+		if (s == INVALID_SOCKET) return;
+
+		SetNonBlocking(s); // XXX error handling?
+
+		DEBUG(net, 1, "Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter);
+
+		SetNoDelay(s); // XXX error handling?
+
+		/* Check if the client is banned */
+		banned = false;
+		for (i = 0; i < lengthof(_network_ban_list); i++) {
+			if (_network_ban_list[i] == NULL) continue;
+
+			if (sin.sin_addr.s_addr == inet_addr(_network_ban_list[i])) {
+				Packet *p = NetworkSend_Init(PACKET_SERVER_BANNED);
+
+				DEBUG(net, 1, "Banned ip tried to join (%s), refused", _network_ban_list[i]);
+
+				p->buffer[0] = p->size & 0xFF;
+				p->buffer[1] = p->size >> 8;
+
+				send(s, p->buffer, p->size, 0);
+				closesocket(s);
+
+				free(p);
+
+				banned = true;
+				break;
+			}
+		}
+		/* If this client is banned, continue with next client */
+		if (banned) continue;
+
+		cs = NetworkAllocClient(s);
+		if (cs == NULL) {
+			// no more clients allowed?
+			// Send to the client that we are full!
+			Packet *p = NetworkSend_Init(PACKET_SERVER_FULL);
+
+			p->buffer[0] = p->size & 0xFF;
+			p->buffer[1] = p->size >> 8;
+
+			send(s, p->buffer, p->size, 0);
+			closesocket(s);
+
+			free(p);
+
+			continue;
+		}
+
+		// a new client has connected. We set him at inactive for now
+		//  maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK
+		//  the client stays inactive
+		cs->status = STATUS_INACTIVE;
+
+		DEREF_CLIENT_INFO(cs)->client_ip = sin.sin_addr.s_addr; // Save the IP of the client
+	}
+}
+
+// Set up the listen socket for the server
+static bool NetworkListen(void)
+{
+	SOCKET ls;
+	struct sockaddr_in sin;
+
+	DEBUG(net, 1, "Listening on %s:%d", _network_server_bind_ip_host, _network_server_port);
+
+	ls = socket(AF_INET, SOCK_STREAM, 0);
+	if (ls == INVALID_SOCKET) {
+		ServerStartError("socket() on listen socket failed");
+		return false;
+	}
+
+	{ // reuse the socket
+		int reuse = 1;
+		// The (const char*) cast is needed for windows!!
+		if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) {
+			ServerStartError("setsockopt() on listen socket failed");
+			return false;
+		}
+	}
+
+	if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
+
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = _network_server_bind_ip;
+	sin.sin_port = htons(_network_server_port);
+
+	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
+		ServerStartError("bind() failed");
+		return false;
+	}
+
+	if (listen(ls, 1) != 0) {
+		ServerStartError("listen() failed");
+		return false;
+	}
+
+	_listensocket = ls;
+
+	return true;
+}
+
+// Close all current connections
+static void NetworkClose(void)
+{
+	NetworkClientState *cs;
+
+	FOR_ALL_CLIENTS(cs) {
+		if (!_network_server) {
+			SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
+			NetworkSend_Packets(cs);
+		}
+		NetworkCloseClient(cs);
+	}
+
+	if (_network_server) {
+		// We are a server, also close the listensocket
+		closesocket(_listensocket);
+		_listensocket = INVALID_SOCKET;
+		DEBUG(net, 1, "Closed listener");
+		NetworkUDPStop();
+	}
+}
+
+// Inits the network (cleans sockets and stuff)
+static void NetworkInitialize(void)
+{
+	NetworkClientState *cs;
+
+	_local_command_queue = NULL;
+
+	// Clean all client-sockets
+	memset(_clients, 0, sizeof(_clients));
+	for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) {
+		cs->socket = INVALID_SOCKET;
+		cs->status = STATUS_INACTIVE;
+		cs->command_queue = NULL;
+	}
+
+	// Clean the client_info memory
+	memset(&_network_client_info, 0, sizeof(_network_client_info));
+	memset(&_network_player_info, 0, sizeof(_network_player_info));
+
+	_sync_frame = 0;
+	_network_first_time = true;
+
+	_network_reconnect = 0;
+
+	NetworkUDPInitialize();
+}
+
+// Query a server to fetch his game-info
+//  If game_info is true, only the gameinfo is fetched,
+//   else only the client_info is fetched
+NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info)
+{
+	if (!_network_available) return NULL;
+
+	NetworkDisconnect();
+
+	if (game_info) return NetworkUDPQueryServer(host, port);
+
+	NetworkInitialize();
+
+	_network_server = false;
+
+	// Try to connect
+	_networking = NetworkConnect(host, port);
+
+	// We are connected
+	if (_networking) {
+		SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
+	} else { // No networking, close everything down again
+		NetworkDisconnect();
+	}
+
+	return NULL;
+}
+
+/* Validates an address entered as a string and adds the server to
+ * the list. If you use this function, the games will be marked
+ * as manually added. */
+void NetworkAddServer(const char *b)
+{
+	if (*b != '\0') {
+		NetworkGameList *item;
+		const char *port = NULL;
+		const char *player = NULL;
+		char host[NETWORK_HOSTNAME_LENGTH];
+		uint16 rport;
+
+		ttd_strlcpy(host, b, lengthof(host));
+
+		ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip));
+		rport = NETWORK_DEFAULT_PORT;
+
+		ParseConnectionString(&player, &port, host);
+		if (port != NULL) rport = atoi(port);
+
+		item = NetworkQueryServer(host, rport, true);
+		item->manually = true;
+	}
+}
+
+/* Generates the list of manually added hosts from NetworkGameList and
+ * dumps them into the array _network_host_list. This array is needed
+ * by the function that generates the config file. */
+void NetworkRebuildHostList(void)
+{
+	uint i = 0;
+	const NetworkGameList *item = _network_game_list;
+	while (item != NULL && i != lengthof(_network_host_list)) {
+		if (item->manually) {
+			free(_network_host_list[i]);
+			_network_host_list[i++] = str_fmt("%s:%i", item->info.hostname, item->port);
+		}
+		item = item->next;
+	}
+
+	for (; i < lengthof(_network_host_list); i++) {
+		free(_network_host_list[i]);
+		_network_host_list[i] = NULL;
+	}
+}
+
+// Used by clients, to connect to a server
+bool NetworkClientConnectGame(const char *host, uint16 port)
+{
+	if (!_network_available) return false;
+
+	if (port == 0) return false;
+
+	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
+	_network_last_port = port;
+
+	NetworkDisconnect();
+	NetworkUDPStop();
+	NetworkInitialize();
+
+	// Try to connect
+	_networking = NetworkConnect(host, port);
+
+	// We are connected
+	if (_networking) {
+		IConsoleCmdExec("exec scripts/on_client.scr 0");
+		NetworkClient_Connected();
+	} else {
+		// Connecting failed
+		NetworkError(STR_NETWORK_ERR_NOCONNECTION);
+	}
+
+	return _networking;
+}
+
+static void NetworkInitGameInfo(void)
+{
+	NetworkClientInfo *ci;
+
+	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
+	ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
+	ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_rcon_password));
+	if (_network_game_info.server_name[0] == '\0')
+		snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
+
+	ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
+
+	// The server is a client too ;)
+	if (_network_dedicated) {
+		_network_game_info.clients_on = 0;
+		_network_game_info.companies_on = 0;
+		_network_game_info.dedicated = true;
+	} else {
+		_network_game_info.clients_on = 1;
+		_network_game_info.companies_on = 1;
+		_network_game_info.dedicated = false;
+	}
+
+	_network_game_info.spectators_on = 0;
+
+	_network_game_info.game_date = _date;
+	_network_game_info.start_date = ConvertYMDToDate(_patches.starting_year, 0, 1);
+	_network_game_info.map_width = MapSizeX();
+	_network_game_info.map_height = MapSizeY();
+	_network_game_info.map_set = _opt.landscape;
+
+	_network_game_info.use_password = (_network_server_password[0] != '\0');
+
+	// We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it
+	//  The index is NETWORK_SERVER_INDEX ( = 1)
+	ci = &_network_client_info[MAX_CLIENT_INFO - 1];
+	memset(ci, 0, sizeof(*ci));
+
+	ci->client_index = NETWORK_SERVER_INDEX;
+	ci->client_playas = _network_dedicated ? PLAYER_SPECTATOR : _local_player;
+
+	ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
+	ttd_strlcpy(ci->unique_id, _network_unique_id, sizeof(ci->unique_id));
+}
+
+bool NetworkServerStart(void)
+{
+	if (!_network_available) return false;
+
+	/* Call the pre-scripts */
+	IConsoleCmdExec("exec scripts/pre_server.scr 0");
+	if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
+
+	NetworkInitialize();
+	if (!NetworkListen()) return false;
+
+	// Try to start UDP-server
+	_network_udp_server = true;
+	_network_udp_server = NetworkUDPListen(&_udp_server_socket, _network_server_bind_ip, _network_server_port, false);
+
+	_network_server = true;
+	_networking = true;
+	_frame_counter = 0;
+	_frame_counter_server = 0;
+	_frame_counter_max = 0;
+	_last_sync_frame = 0;
+	_network_own_client_index = NETWORK_SERVER_INDEX;
+
+	/* Non-dedicated server will always be player #1 */
+	if (!_network_dedicated) _network_playas = 0;
+
+	_network_clients_connected = 0;
+
+	NetworkInitGameInfo();
+
+	// execute server initialization script
+	IConsoleCmdExec("exec scripts/on_server.scr 0");
+	// if the server is dedicated ... add some other script
+	if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
+
+	_min_players_paused = false;
+	CheckMinPlayers();
+
+	/* Try to register us to the master server */
+	_network_last_advertise_frame = 0;
+	_network_need_advertise = true;
+	NetworkUDPAdvertise();
+	return true;
+}
+
+// The server is rebooting...
+// The only difference with NetworkDisconnect, is the packets that is sent
+void NetworkReboot(void)
+{
+	if (_network_server) {
+		NetworkClientState *cs;
+		FOR_ALL_CLIENTS(cs) {
+			SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
+			NetworkSend_Packets(cs);
+		}
+	}
+
+	NetworkClose();
+
+	// Free all queued commands
+	while (_local_command_queue != NULL) {
+		CommandPacket *p = _local_command_queue;
+		_local_command_queue = _local_command_queue->next;
+		free(p);
+	}
+
+	_networking = false;
+	_network_server = false;
+}
+
+// We want to disconnect from the host/clients
+void NetworkDisconnect(void)
+{
+	if (_network_server) {
+		NetworkClientState *cs;
+		FOR_ALL_CLIENTS(cs) {
+			SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
+			NetworkSend_Packets(cs);
+		}
+	}
+
+	if (_network_advertise) NetworkUDPRemoveAdvertise();
+
+	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+
+	NetworkClose();
+
+	// Free all queued commands
+	while (_local_command_queue != NULL) {
+		CommandPacket *p = _local_command_queue;
+		_local_command_queue = _local_command_queue->next;
+		free(p);
+	}
+
+	_networking = false;
+	_network_server = false;
+}
+
+// Receives something from the network
+static bool NetworkReceive(void)
+{
+	NetworkClientState *cs;
+	int n;
+	fd_set read_fd, write_fd;
+	struct timeval tv;
+
+	FD_ZERO(&read_fd);
+	FD_ZERO(&write_fd);
+
+	FOR_ALL_CLIENTS(cs) {
+		FD_SET(cs->socket, &read_fd);
+		FD_SET(cs->socket, &write_fd);
+	}
+
+	// take care of listener port
+	if (_network_server) FD_SET(_listensocket, &read_fd);
+
+	tv.tv_sec = tv.tv_usec = 0; // don't block at all.
+#if !defined(__MORPHOS__) && !defined(__AMIGA__)
+	n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
+#else
+	n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
+#endif
+	if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION);
+
+	// accept clients..
+	if (_network_server && FD_ISSET(_listensocket, &read_fd)) NetworkAcceptClients();
+
+	// read stuff from clients
+	FOR_ALL_CLIENTS(cs) {
+		cs->writable = !!FD_ISSET(cs->socket, &write_fd);
+		if (FD_ISSET(cs->socket, &read_fd)) {
+			if (_network_server) {
+				NetworkServer_ReadPackets(cs);
+			} else {
+				NetworkRecvStatus res;
+
+				// The client already was quiting!
+				if (cs->has_quit) return false;
+
+				res = NetworkClient_ReadPackets(cs);
+				if (res != NETWORK_RECV_STATUS_OKAY) {
+					// The client made an error of which we can not recover
+					//   close the client and drop back to main menu
+					NetworkClientError(res, cs);
+					return false;
+				}
+			}
+		}
+	}
+	return true;
+}
+
+// This sends all buffered commands (if possible)
+static void NetworkSend(void)
+{
+	NetworkClientState *cs;
+	FOR_ALL_CLIENTS(cs) {
+		if (cs->writable) {
+			NetworkSend_Packets(cs);
+
+			if (cs->status == STATUS_MAP) {
+				// This client is in the middle of a map-send, call the function for that
+				SEND_COMMAND(PACKET_SERVER_MAP)(cs);
+			}
+		}
+	}
+}
+
+// Handle the local-command-queue
+static void NetworkHandleLocalQueue(void)
+{
+	CommandPacket *cp, **cp_prev;
+
+	cp_prev = &_local_command_queue;
+
+	while ( (cp = *cp_prev) != NULL) {
+
+		// The queue is always in order, which means
+		// that the first element will be executed first.
+		if (_frame_counter < cp->frame) break;
+
+		if (_frame_counter > cp->frame) {
+			// If we reach here, it means for whatever reason, we've already executed
+			// past the command we need to execute.
+			DEBUG(net, 0, "Trying to execute a packet in the past!");
+			assert(0);
+		}
+
+		// We can execute this command
+		NetworkExecuteCommand(cp);
+
+		*cp_prev = cp->next;
+		free(cp);
+	}
+
+	// Just a safety check, to be removed in the future.
+	// Make sure that no older command appears towards the end of the queue
+	// In that case we missed executing it. This will never happen.
+	for (cp = _local_command_queue; cp; cp = cp->next) {
+		assert(_frame_counter < cp->frame);
+	}
+
+}
+
+static bool NetworkDoClientLoop(void)
+{
+	_frame_counter++;
+
+	NetworkHandleLocalQueue();
+
+	StateGameLoop();
+
+	// Check if we are in sync!
+	if (_sync_frame != 0) {
+		if (_sync_frame == _frame_counter) {
+#ifdef NETWORK_SEND_DOUBLE_SEED
+			if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) {
+#else
+			if (_sync_seed_1 != _random_seeds[0][0]) {
+#endif
+				NetworkError(STR_NETWORK_ERR_DESYNC);
+				DEBUG(net, 0, "Sync error detected!");
+				NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0));
+				return false;
+			}
+
+			// If this is the first time we have a sync-frame, we
+			//   need to let the server know that we are ready and at the same
+			//   frame as he is.. so we can start playing!
+			if (_network_first_time) {
+				_network_first_time = false;
+				SEND_COMMAND(PACKET_CLIENT_ACK)();
+			}
+
+			_sync_frame = 0;
+		} else if (_sync_frame < _frame_counter) {
+			DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
+			_sync_frame = 0;
+		}
+	}
+
+	return true;
+}
+
+// We have to do some UDP checking
+void NetworkUDPGameLoop(void)
+{
+	if (_network_udp_server) {
+		NetworkUDPReceive(_udp_server_socket);
+		if (_udp_master_socket != INVALID_SOCKET) {
+			NetworkUDPReceive(_udp_master_socket);
+		}
+	} else if (_udp_client_socket != INVALID_SOCKET) {
+		NetworkUDPReceive(_udp_client_socket);
+		if (_network_udp_broadcast > 0) _network_udp_broadcast--;
+	}
+}
+
+// The main loop called from ttd.c
+//  Here we also have to do StateGameLoop if needed!
+void NetworkGameLoop(void)
+{
+	if (!_networking) return;
+
+	if (!NetworkReceive()) return;
+
+	if (_network_server) {
+		bool send_frame = false;
+
+		// We first increase the _frame_counter
+		_frame_counter++;
+		// Update max-frame-counter
+		if (_frame_counter > _frame_counter_max) {
+			_frame_counter_max = _frame_counter + _network_frame_freq;
+			send_frame = true;
+		}
+
+		NetworkHandleLocalQueue();
+
+		// Then we make the frame
+		StateGameLoop();
+
+		_sync_seed_1 = _random_seeds[0][0];
+#ifdef NETWORK_SEND_DOUBLE_SEED
+		_sync_seed_2 = _random_seeds[0][1];
+#endif
+
+		NetworkServer_Tick(send_frame);
+	} else {
+		// Client
+
+		// Make sure we are at the frame were the server is (quick-frames)
+		if (_frame_counter_server > _frame_counter) {
+			while (_frame_counter_server > _frame_counter) {
+				if (!NetworkDoClientLoop()) break;
+			}
+		} else {
+			// Else, keep on going till _frame_counter_max
+			if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
+		}
+	}
+
+	NetworkSend();
+}
+
+static void NetworkGenerateUniqueId(void)
+{
+	md5_state_t state;
+	md5_byte_t digest[16];
+	char hex_output[16*2 + 1];
+	char coding_string[NETWORK_NAME_LENGTH];
+	int di;
+
+	snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
+
+	/* Generate the MD5 hash */
+	md5_init(&state);
+	md5_append(&state, (const md5_byte_t*)coding_string, strlen(coding_string));
+	md5_finish(&state, digest);
+
+	for (di = 0; di < 16; ++di)
+		sprintf(hex_output + di * 2, "%02x", digest[di]);
+
+	/* _network_unique_id is our id */
+	snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output);
+}
+
+/** This tries to launch the network for a given OS */
+void NetworkStartUp(void)
+{
+	DEBUG(net, 3, "[core] starting network...");
+
+	/* Network is available */
+	_network_available = NetworkCoreInitialize();;
+	_network_dedicated = false;
+	_network_last_advertise_frame = 0;
+	_network_need_advertise = true;
+	_network_advertise_retries = 0;
+
+	/* Load the ip from the openttd.cfg */
+	_network_server_bind_ip = inet_addr(_network_server_bind_ip_host);
+	/* And put the data back in it in case it was an invalid ip */
+	snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
+
+	/* Generate an unique id when there is none yet */
+	if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId();
+
+	{
+		byte cl_max = _network_game_info.clients_max;
+		byte cp_max = _network_game_info.companies_max;
+		byte sp_max = _network_game_info.spectators_max;
+
+		memset(&_network_game_info, 0, sizeof(_network_game_info));
+		_network_game_info.clients_max = cl_max;
+		_network_game_info.companies_max = cp_max;
+		_network_game_info.spectators_max = sp_max;
+	}
+
+
+	NetworkInitialize();
+	DEBUG(net, 3, "[core] network online, multiplayer available");
+	NetworkFindIPs();
+}
+
+/** This shuts the network down */
+void NetworkShutDown(void)
+{
+	NetworkDisconnect();
+	NetworkUDPStop();
+
+	DEBUG(net, 3, "[core] shutting down network");
+
+	_network_available = false;
+
+	NetworkCoreShutdown();
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_client.c
+++ /dev/null
@@ -1,819 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../stdafx.h"
-#include "../debug.h"
-#include "../string.h"
-#include "../strings.h"
-#include "network_data.h"
-#include "core/tcp.h"
-#include "../date.h"
-#include "table/strings.h"
-#include "../functions.h"
-#include "network_client.h"
-#include "network_gamelist.h"
-#include "network_gui.h"
-#include "../saveload.h"
-#include "../command.h"
-#include "../window.h"
-#include "../console.h"
-#include "../variables.h"
-#include "../ai/ai.h"
-
-
-// This file handles all the client-commands
-
-
-// So we don't make too much typos ;)
-#define MY_CLIENT DEREF_CLIENT(0)
-
-static uint32 last_ack_frame;
-
-// **********
-// Sending functions
-//   DEF_CLIENT_SEND_COMMAND has no parameters
-// **********
-
-DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)
-{
-	//
-	// Packet: CLIENT_COMPANY_INFO
-	// Function: Request company-info (in detail)
-	// Data:
-	//    <none>
-	//
-	Packet *p;
-	_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
-	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-
-	p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN)
-{
-	//
-	// Packet: CLIENT_JOIN
-	// Function: Try to join the server
-	// Data:
-	//    String: OpenTTD Revision (norev000 if no revision)
-	//    String: Player Name (max NETWORK_NAME_LENGTH)
-	//    uint8:  Play as Player id (1..MAX_PLAYERS)
-	//    uint8:  Language ID
-	//    String: Unique id to find the player back in server-listing
-	//
-
-	extern const char _openttd_revision[];
-	Packet *p;
-	_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
-	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-
-	p = NetworkSend_Init(PACKET_CLIENT_JOIN);
-	NetworkSend_string(p, _openttd_revision);
-	NetworkSend_string(p, _network_player_name); // Player name
-	NetworkSend_uint8(p, _network_playas); // PlayAs
-	NetworkSend_uint8(p, NETLANG_ANY); // Language
-	NetworkSend_string(p, _network_unique_id);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password)
-{
-	//
-	// Packet: CLIENT_PASSWORD
-	// Function: Send a password to the server to authorize
-	// Data:
-	//    uint8:  NetworkPasswordType
-	//    String: Password
-	//
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD);
-	NetworkSend_uint8(p, type);
-	NetworkSend_string(p, password);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GETMAP)
-{
-	//
-	// Packet: CLIENT_GETMAP
-	// Function: Request the map from the server
-	// Data:
-	//    <none>
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_GETMAP);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_MAP_OK)
-{
-	//
-	// Packet: CLIENT_MAP_OK
-	// Function: Tell the server that we are done receiving/loading the map
-	// Data:
-	//    <none>
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_MAP_OK);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK)
-{
-	//
-	// Packet: CLIENT_ACK
-	// Function: Tell the server we are done with this frame
-	// Data:
-	//    uint32: current FrameCounter of the client
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_ACK);
-
-	NetworkSend_uint32(p, _frame_counter);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-// Send a command packet to the server
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp)
-{
-	//
-	// Packet: CLIENT_COMMAND
-	// Function: Send a DoCommand to the Server
-	// Data:
-	//    uint8:  PlayerID (0..MAX_PLAYERS-1)
-	//    uint32: CommandID (see command.h)
-	//    uint32: P1 (free variables used in DoCommand)
-	//    uint32: P2
-	//    uint32: Tile
-	//    string: text
-	//    uint8:  CallBackID (see callback_table.c)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_COMMAND);
-
-	NetworkSend_uint8(p, cp->player);
-	NetworkSend_uint32(p, cp->cmd);
-	NetworkSend_uint32(p, cp->p1);
-	NetworkSend_uint32(p, cp->p2);
-	NetworkSend_uint32(p, (uint32)cp->tile);
-	NetworkSend_string(p, cp->text);
-	NetworkSend_uint8(p, cp->callback);
-
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-// Send a chat-packet over the network
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType type, int dest, const char *msg)
-{
-	//
-	// Packet: CLIENT_CHAT
-	// Function: Send a chat-packet to the serve
-	// Data:
-	//    uint8:  ActionID (see network_data.h, NetworkAction)
-	//    uint8:  Destination Type (see network_data.h, DestType);
-	//    uint8:  Destination Player (1..MAX_PLAYERS)
-	//    String: Message (max MAX_TEXT_MSG_LEN)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_CHAT);
-
-	NetworkSend_uint8(p, action);
-	NetworkSend_uint8(p, type);
-	NetworkSend_uint8(p, dest);
-	NetworkSend_string(p, msg);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-// Send an error-packet over the network
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno)
-{
-	//
-	// Packet: CLIENT_ERROR
-	// Function: The client made an error and is quiting the game
-	// Data:
-	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
-	//
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_ERROR);
-
-	NetworkSend_uint8(p, errorno);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password)
-{
-	//
-	// Packet: PACKET_CLIENT_SET_PASSWORD
-	// Function: Set the password for the clients current company
-	// Data:
-	//    String: Password
-	//
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_PASSWORD);
-
-	NetworkSend_string(p, password);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name)
-{
-	//
-	// Packet: PACKET_CLIENT_SET_NAME
-	// Function: Gives the player a new name
-	// Data:
-	//    String: Name
-	//
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_NAME);
-
-	NetworkSend_string(p, name);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-// Send an quit-packet over the network
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg)
-{
-	//
-	// Packet: CLIENT_QUIT
-	// Function: The client is quiting the game
-	// Data:
-	//    String: leave-message
-	//
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_QUIT);
-
-	NetworkSend_string(p, leavemsg);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command)
-{
-	Packet *p = NetworkSend_Init(PACKET_CLIENT_RCON);
-	NetworkSend_string(p, pass);
-	NetworkSend_string(p, command);
-	NetworkSend_Packet(p, MY_CLIENT);
-}
-
-
-// **********
-// Receiving functions
-//   DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p
-// **********
-
-extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FULL)
-{
-	// We try to join a server which is full
-	_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL;
-	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-
-	return NETWORK_RECV_STATUS_SERVER_FULL;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_BANNED)
-{
-	// We try to join a server where we are banned
-	_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_BANNED;
-	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-
-	return NETWORK_RECV_STATUS_SERVER_BANNED;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO)
-{
-	byte company_info_version;
-	int i;
-
-	company_info_version = NetworkRecv_uint8(MY_CLIENT, p);
-
-	if (!MY_CLIENT->has_quit && company_info_version == NETWORK_COMPANY_INFO_VERSION) {
-		byte total;
-		byte current;
-
-		total = NetworkRecv_uint8(MY_CLIENT, p);
-
-		// There is no data at all..
-		if (total == 0) return NETWORK_RECV_STATUS_CLOSE_QUERY;
-
-		current = NetworkRecv_uint8(MY_CLIENT, p);
-		if (!IsValidPlayer(current)) return NETWORK_RECV_STATUS_CLOSE_QUERY;
-
-		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
-		_network_player_info[current].inaugurated_year = NetworkRecv_uint32(MY_CLIENT, p);
-		_network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p);
-		_network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p);
-		_network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p);
-		_network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p);
-		_network_player_info[current].use_password = NetworkRecv_uint8(MY_CLIENT, p);
-		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
-			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(MY_CLIENT, p);
-		for (i = 0; i < NETWORK_STATION_TYPES; i++)
-			_network_player_info[current].num_station[i] = NetworkRecv_uint16(MY_CLIENT, p);
-
-		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
-
-		InvalidateWindow(WC_NETWORK_WINDOW, 0);
-
-		return NETWORK_RECV_STATUS_OKAY;
-	}
-
-	return NETWORK_RECV_STATUS_CLOSE_QUERY;
-}
-
-// This packet contains info about the client (playas and name)
-//  as client we save this in NetworkClientInfo, linked via 'index'
-//  which is always an unique number on a server.
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
-{
-	NetworkClientInfo *ci;
-	uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
-	PlayerID playas = NetworkRecv_uint8(MY_CLIENT, p);
-	char name[NETWORK_NAME_LENGTH];
-	char unique_id[NETWORK_NAME_LENGTH];
-
-	NetworkRecv_string(MY_CLIENT, p, name, sizeof(name));
-	NetworkRecv_string(MY_CLIENT, p, unique_id, sizeof(unique_id));
-
-	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
-
-	/* Do we receive a change of data? Most likely we changed playas */
-	if (index == _network_own_client_index) _network_playas = playas;
-
-	ci = NetworkFindClientInfoFromIndex(index);
-	if (ci != NULL) {
-		if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
-			// Client name changed, display the change
-			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", name);
-		} else if (playas != ci->client_playas) {
-			// The player changed from client-player..
-			// Do not display that for now
-		}
-
-		ci->client_playas = playas;
-		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
-
-		InvalidateWindow(WC_CLIENT_LIST, 0);
-
-		return NETWORK_RECV_STATUS_OKAY;
-	}
-
-	// We don't have this index yet, find an empty index, and put the data there
-	ci = NetworkFindClientInfoFromIndex(NETWORK_EMPTY_INDEX);
-	if (ci != NULL) {
-		ci->client_index = index;
-		ci->client_playas = playas;
-
-		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
-		ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id));
-
-		InvalidateWindow(WC_CLIENT_LIST, 0);
-
-		return NETWORK_RECV_STATUS_OKAY;
-	}
-
-	// Here the program should never ever come.....
-	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
-{
-	NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p);
-
-	switch (error) {
-		/* We made an error in the protocol, and our connection is closed.... */
-		case NETWORK_ERROR_NOT_AUTHORIZED:
-		case NETWORK_ERROR_NOT_EXPECTED:
-		case NETWORK_ERROR_PLAYER_MISMATCH:
-			_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
-			break;
-		case NETWORK_ERROR_FULL:
-			_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL;
-			break;
-		case NETWORK_ERROR_WRONG_REVISION:
-			_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
-			break;
-		case NETWORK_ERROR_WRONG_PASSWORD:
-			_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
-			break;
-		case NETWORK_ERROR_KICKED:
-			_switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
-			break;
-		case NETWORK_ERROR_CHEATER:
-			_switch_mode_errorstr = STR_NETWORK_ERR_CHEATER;
-			break;
-		default:
-			_switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
-	}
-
-	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-
-	return NETWORK_RECV_STATUS_SERVER_ERROR;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
-{
-	NetworkPasswordType type = NetworkRecv_uint8(MY_CLIENT, p);
-
-	switch (type) {
-		case NETWORK_GAME_PASSWORD:
-		case NETWORK_COMPANY_PASSWORD:
-			ShowNetworkNeedPassword(type);
-			return NETWORK_RECV_STATUS_OKAY;
-
-		default: return NETWORK_RECV_STATUS_MALFORMED_PACKET;
-	}
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
-{
-	_network_own_client_index = NetworkRecv_uint16(MY_CLIENT, p);
-
-	// Start receiving the map
-	SEND_COMMAND(PACKET_CLIENT_GETMAP)();
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT)
-{
-	_network_join_status = NETWORK_JOIN_STATUS_WAITING;
-	_network_join_waiting = NetworkRecv_uint8(MY_CLIENT, p);
-	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-
-	// We are put on hold for receiving the map.. we need GUI for this ;)
-	DEBUG(net, 1, "The server is currently busy sending the map to someone else, please wait..." );
-	DEBUG(net, 1, "There are %d clients in front of you", _network_join_waiting);
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
-{
-	static char filename[256];
-	static FILE *file_pointer;
-
-	byte maptype;
-
-	maptype = NetworkRecv_uint8(MY_CLIENT, p);
-
-	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
-
-	// First packet, init some stuff
-	if (maptype == MAP_PACKET_START) {
-		// The name for the temp-map
-		snprintf(filename, lengthof(filename), "%s%snetwork_client.tmp",  _paths.autosave_dir, PATHSEP);
-
-		file_pointer = fopen(filename, "wb");
-		if (file_pointer == NULL) {
-			_switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR;
-			return NETWORK_RECV_STATUS_SAVEGAME;
-		}
-
-		_frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
-
-		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
-		_network_join_kbytes = 0;
-		_network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024;
-		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-
-		// The first packet does not contain any more data
-		return NETWORK_RECV_STATUS_OKAY;
-	}
-
-	if (maptype == MAP_PACKET_NORMAL) {
-		// We are still receiving data, put it to the file
-		fwrite(p->buffer + p->pos, 1, p->size - p->pos, file_pointer);
-
-		_network_join_kbytes = ftell(file_pointer) / 1024;
-		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-	}
-
-	// Check if this was the last packet
-	if (maptype == MAP_PACKET_END) {
-		fclose(file_pointer);
-
-		_network_join_status = NETWORK_JOIN_STATUS_PROCESSING;
-		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
-
-		/* The map is done downloading, load it */
-		if (!SafeSaveOrLoad(filename, SL_LOAD, GM_NORMAL)) {
-			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-			_switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR;
-			return NETWORK_RECV_STATUS_SAVEGAME;
-		}
-		/* If the savegame has successfully loaded, ALL windows have been removed,
-		 * only toolbar/statusbar and gamefield are visible */
-
-		_opt_ptr = &_opt; // during a network game you are always in-game
-
-		// Say we received the map and loaded it correctly!
-		SEND_COMMAND(PACKET_CLIENT_MAP_OK)();
-
-		/* New company/spectator (invalid player) or company we want to join is not active
-		 * Switch local player to spectator and await the server's judgement */
-		if (_network_playas == PLAYER_NEW_COMPANY || !IsValidPlayer(_network_playas) ||
-				!GetPlayer(_network_playas)->is_active) {
-
-			SetLocalPlayer(PLAYER_SPECTATOR);
-
-			if (_network_playas != PLAYER_SPECTATOR) {
-				/* We have arrived and ready to start playing; send a command to make a new player;
-				 * the server will give us a client-id and let us in */
-				_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
-				ShowJoinStatusWindow();
-				NetworkSend_Command(0, 0, 0, CMD_PLAYER_CTRL, NULL);
-			}
-		} else {
-			// take control over an existing company
-			SetLocalPlayer(_network_playas);
-		}
-	}
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
-{
-	_frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p);
-	_frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
-#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
-	// Test if the server supports this option
-	//  and if we are at the frame the server is
-	if (p->pos < p->size) {
-		_sync_frame = _frame_counter_server;
-		_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
-#ifdef NETWORK_SEND_DOUBLE_SEED
-		_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
-#endif
-	}
-#endif
-	DEBUG(net, 5, "Received FRAME %d", _frame_counter_server);
-
-	// Let the server know that we received this frame correctly
-	//  We do this only once per day, to save some bandwidth ;)
-	if (!_network_first_time && last_ack_frame < _frame_counter) {
-		last_ack_frame = _frame_counter + DAY_TICKS;
-		DEBUG(net, 4, "Sent ACK at %d", _frame_counter);
-		SEND_COMMAND(PACKET_CLIENT_ACK)();
-	}
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC)
-{
-	_sync_frame = NetworkRecv_uint32(MY_CLIENT, p);
-	_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
-#ifdef NETWORK_SEND_DOUBLE_SEED
-	_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
-#endif
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND)
-{
-	CommandPacket *cp = malloc(sizeof(CommandPacket));
-	cp->player = NetworkRecv_uint8(MY_CLIENT, p);
-	cp->cmd = NetworkRecv_uint32(MY_CLIENT, p);
-	cp->p1 = NetworkRecv_uint32(MY_CLIENT, p);
-	cp->p2 = NetworkRecv_uint32(MY_CLIENT, p);
-	cp->tile = NetworkRecv_uint32(MY_CLIENT, p);
-	NetworkRecv_string(MY_CLIENT, p, cp->text, sizeof(cp->text));
-	cp->callback = NetworkRecv_uint8(MY_CLIENT, p);
-	cp->frame = NetworkRecv_uint32(MY_CLIENT, p);
-	cp->next = NULL;
-
-	// The server did send us this command..
-	//  queue it in our own queue, so we can handle it in the upcoming frame!
-
-	if (_local_command_queue == NULL) {
-		_local_command_queue = cp;
-	} else {
-		// Find last packet
-		CommandPacket *c = _local_command_queue;
-		while (c->next != NULL) c = c->next;
-		c->next = cp;
-	}
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT)
-{
-	char name[NETWORK_NAME_LENGTH], msg[MAX_TEXT_MSG_LEN];
-	const NetworkClientInfo *ci = NULL, *ci_to;
-
-	NetworkAction action = NetworkRecv_uint8(MY_CLIENT, p);
-	uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
-	bool self_send = NetworkRecv_uint8(MY_CLIENT, p);
-	NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN);
-
-	ci_to = NetworkFindClientInfoFromIndex(index);
-	if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
-
-	/* Did we initiate the action locally? */
-	if (self_send) {
-		switch (action) {
-			case NETWORK_ACTION_CHAT_CLIENT:
-				/* For speaking to client we need the client-name */
-				snprintf(name, sizeof(name), "%s", ci_to->client_name);
-				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
-				break;
-
-			/* For speaking to company or giving money, we need the player-name */
-			case NETWORK_ACTION_GIVE_MONEY:
-				if (!IsValidPlayer(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY;
-				/* fallthrough */
-			case NETWORK_ACTION_CHAT_COMPANY: {
-				StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS;
-
-				GetString(name, str, lastof(name));
-				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
-			} break;
-
-			default: NOT_REACHED(); break;
-		}
-	} else {
-		/* Display message from somebody else */
-		snprintf(name, sizeof(name), "%s", ci_to->client_name);
-		ci = ci_to;
-	}
-
-	if (ci != NULL)
-		NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), self_send, name, "%s", msg);
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
-{
-	char str[100];
-	uint16 index;
-	NetworkClientInfo *ci;
-
-	index = NetworkRecv_uint16(MY_CLIENT, p);
-	GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p), lastof(str));
-
-	ci = NetworkFindClientInfoFromIndex(index);
-	if (ci != NULL) {
-		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str);
-
-		// The client is gone, give the NetworkClientInfo free
-		ci->client_index = NETWORK_EMPTY_INDEX;
-	}
-
-	InvalidateWindow(WC_CLIENT_LIST, 0);
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT)
-{
-	char str[100];
-	uint16 index;
-	NetworkClientInfo *ci;
-
-	index = NetworkRecv_uint16(MY_CLIENT, p);
-	NetworkRecv_string(MY_CLIENT, p, str, lengthof(str));
-
-	ci = NetworkFindClientInfoFromIndex(index);
-	if (ci != NULL) {
-		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str);
-
-		// The client is gone, give the NetworkClientInfo free
-		ci->client_index = NETWORK_EMPTY_INDEX;
-	} else {
-		DEBUG(net, 0, "Unknown client (%d) is leaving the game", index);
-	}
-
-	InvalidateWindow(WC_CLIENT_LIST, 0);
-
-	// If we come here it means we could not locate the client.. strange :s
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN)
-{
-	uint16 index;
-	NetworkClientInfo *ci;
-
-	index = NetworkRecv_uint16(MY_CLIENT, p);
-
-	ci = NetworkFindClientInfoFromIndex(index);
-	if (ci != NULL)
-		NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, ci->client_name, "");
-
-	InvalidateWindow(WC_CLIENT_LIST, 0);
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN)
-{
-	_switch_mode_errorstr = STR_NETWORK_SERVER_SHUTDOWN;
-
-	return NETWORK_RECV_STATUS_SERVER_ERROR;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEWGAME)
-{
-	// To trottle the reconnects a bit, every clients waits
-	//  his _local_player value before reconnecting
-	// PLAYER_SPECTATOR is currently 255, so to avoid long wait periods
-	//  set the max to 10.
-	_network_reconnect = min(_local_player + 1, 10);
-	_switch_mode_errorstr = STR_NETWORK_SERVER_REBOOT;
-
-	return NETWORK_RECV_STATUS_SERVER_ERROR;
-}
-
-DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_RCON)
-{
-	char rcon_out[NETWORK_RCONCOMMAND_LENGTH];
-	uint16 color_code;
-
-	color_code = NetworkRecv_uint16(MY_CLIENT, p);
-	NetworkRecv_string(MY_CLIENT, p, rcon_out, sizeof(rcon_out));
-
-	IConsolePrint(color_code, rcon_out);
-
-	return NETWORK_RECV_STATUS_OKAY;
-}
-
-
-
-// The layout for the receive-functions by the client
-typedef NetworkRecvStatus NetworkClientPacket(Packet *p);
-
-// This array matches PacketType. At an incoming
-//  packet it is matches against this array
-//  and that way the right function to handle that
-//  packet is found.
-static NetworkClientPacket* const _network_client_packet[] = {
-	RECEIVE_COMMAND(PACKET_SERVER_FULL),
-	RECEIVE_COMMAND(PACKET_SERVER_BANNED),
-	NULL, /*PACKET_CLIENT_JOIN,*/
-	RECEIVE_COMMAND(PACKET_SERVER_ERROR),
-	NULL, /*PACKET_CLIENT_COMPANY_INFO,*/
-	RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO),
-	RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO),
-	RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD),
-	NULL, /*PACKET_CLIENT_PASSWORD,*/
-	RECEIVE_COMMAND(PACKET_SERVER_WELCOME),
-	NULL, /*PACKET_CLIENT_GETMAP,*/
-	RECEIVE_COMMAND(PACKET_SERVER_WAIT),
-	RECEIVE_COMMAND(PACKET_SERVER_MAP),
-	NULL, /*PACKET_CLIENT_MAP_OK,*/
-	RECEIVE_COMMAND(PACKET_SERVER_JOIN),
-	RECEIVE_COMMAND(PACKET_SERVER_FRAME),
-	RECEIVE_COMMAND(PACKET_SERVER_SYNC),
-	NULL, /*PACKET_CLIENT_ACK,*/
-	NULL, /*PACKET_CLIENT_COMMAND,*/
-	RECEIVE_COMMAND(PACKET_SERVER_COMMAND),
-	NULL, /*PACKET_CLIENT_CHAT,*/
-	RECEIVE_COMMAND(PACKET_SERVER_CHAT),
-	NULL, /*PACKET_CLIENT_SET_PASSWORD,*/
-	NULL, /*PACKET_CLIENT_SET_NAME,*/
-	NULL, /*PACKET_CLIENT_QUIT,*/
-	NULL, /*PACKET_CLIENT_ERROR,*/
-	RECEIVE_COMMAND(PACKET_SERVER_QUIT),
-	RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT),
-	RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN),
-	RECEIVE_COMMAND(PACKET_SERVER_NEWGAME),
-	RECEIVE_COMMAND(PACKET_SERVER_RCON),
-	NULL, /*PACKET_CLIENT_RCON,*/
-};
-
-// If this fails, check the array above with network_data.h
-assert_compile(lengthof(_network_client_packet) == PACKET_END);
-
-// Is called after a client is connected to the server
-void NetworkClient_Connected(void)
-{
-	// Set the frame-counter to 0 so nothing happens till we are ready
-	_frame_counter = 0;
-	_frame_counter_server = 0;
-	last_ack_frame = 0;
-	// Request the game-info
-	SEND_COMMAND(PACKET_CLIENT_JOIN)();
-}
-
-// Reads the packets from the socket-stream, if available
-NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs)
-{
-	Packet *p;
-	NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY;
-
-	while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) {
-		byte type = NetworkRecv_uint8(MY_CLIENT, p);
-		if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->has_quit) {
-			res = _network_client_packet[type](p);
-		} else {
-			res = NETWORK_RECV_STATUS_MALFORMED_PACKET;
-			DEBUG(net, 0, "[client] received invalid packet type %d", type);
-		}
-
-		free(p);
-	}
-
-	return res;
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_client.cpp
@@ -0,0 +1,819 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "../string.h"
+#include "../strings.h"
+#include "network_data.h"
+#include "core/tcp.h"
+#include "../date.h"
+#include "table/strings.h"
+#include "../functions.h"
+#include "network_client.h"
+#include "network_gamelist.h"
+#include "network_gui.h"
+#include "../saveload.h"
+#include "../command.h"
+#include "../window.h"
+#include "../console.h"
+#include "../variables.h"
+#include "../ai/ai.h"
+
+
+// This file handles all the client-commands
+
+
+// So we don't make too much typos ;)
+#define MY_CLIENT DEREF_CLIENT(0)
+
+static uint32 last_ack_frame;
+
+// **********
+// Sending functions
+//   DEF_CLIENT_SEND_COMMAND has no parameters
+// **********
+
+DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)
+{
+	//
+	// Packet: CLIENT_COMPANY_INFO
+	// Function: Request company-info (in detail)
+	// Data:
+	//    <none>
+	//
+	Packet *p;
+	_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
+	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+
+	p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN)
+{
+	//
+	// Packet: CLIENT_JOIN
+	// Function: Try to join the server
+	// Data:
+	//    String: OpenTTD Revision (norev000 if no revision)
+	//    String: Player Name (max NETWORK_NAME_LENGTH)
+	//    uint8:  Play as Player id (1..MAX_PLAYERS)
+	//    uint8:  Language ID
+	//    String: Unique id to find the player back in server-listing
+	//
+
+	extern const char _openttd_revision[];
+	Packet *p;
+	_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
+	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+
+	p = NetworkSend_Init(PACKET_CLIENT_JOIN);
+	NetworkSend_string(p, _openttd_revision);
+	NetworkSend_string(p, _network_player_name); // Player name
+	NetworkSend_uint8(p, _network_playas); // PlayAs
+	NetworkSend_uint8(p, NETLANG_ANY); // Language
+	NetworkSend_string(p, _network_unique_id);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password)
+{
+	//
+	// Packet: CLIENT_PASSWORD
+	// Function: Send a password to the server to authorize
+	// Data:
+	//    uint8:  NetworkPasswordType
+	//    String: Password
+	//
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD);
+	NetworkSend_uint8(p, type);
+	NetworkSend_string(p, password);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GETMAP)
+{
+	//
+	// Packet: CLIENT_GETMAP
+	// Function: Request the map from the server
+	// Data:
+	//    <none>
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_GETMAP);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_MAP_OK)
+{
+	//
+	// Packet: CLIENT_MAP_OK
+	// Function: Tell the server that we are done receiving/loading the map
+	// Data:
+	//    <none>
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_MAP_OK);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK)
+{
+	//
+	// Packet: CLIENT_ACK
+	// Function: Tell the server we are done with this frame
+	// Data:
+	//    uint32: current FrameCounter of the client
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_ACK);
+
+	NetworkSend_uint32(p, _frame_counter);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+// Send a command packet to the server
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp)
+{
+	//
+	// Packet: CLIENT_COMMAND
+	// Function: Send a DoCommand to the Server
+	// Data:
+	//    uint8:  PlayerID (0..MAX_PLAYERS-1)
+	//    uint32: CommandID (see command.h)
+	//    uint32: P1 (free variables used in DoCommand)
+	//    uint32: P2
+	//    uint32: Tile
+	//    string: text
+	//    uint8:  CallBackID (see callback_table.c)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_COMMAND);
+
+	NetworkSend_uint8(p, cp->player);
+	NetworkSend_uint32(p, cp->cmd);
+	NetworkSend_uint32(p, cp->p1);
+	NetworkSend_uint32(p, cp->p2);
+	NetworkSend_uint32(p, (uint32)cp->tile);
+	NetworkSend_string(p, cp->text);
+	NetworkSend_uint8(p, cp->callback);
+
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+// Send a chat-packet over the network
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType type, int dest, const char *msg)
+{
+	//
+	// Packet: CLIENT_CHAT
+	// Function: Send a chat-packet to the serve
+	// Data:
+	//    uint8:  ActionID (see network_data.h, NetworkAction)
+	//    uint8:  Destination Type (see network_data.h, DestType);
+	//    uint8:  Destination Player (1..MAX_PLAYERS)
+	//    String: Message (max MAX_TEXT_MSG_LEN)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_CHAT);
+
+	NetworkSend_uint8(p, action);
+	NetworkSend_uint8(p, type);
+	NetworkSend_uint8(p, dest);
+	NetworkSend_string(p, msg);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+// Send an error-packet over the network
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno)
+{
+	//
+	// Packet: CLIENT_ERROR
+	// Function: The client made an error and is quiting the game
+	// Data:
+	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
+	//
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_ERROR);
+
+	NetworkSend_uint8(p, errorno);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password)
+{
+	//
+	// Packet: PACKET_CLIENT_SET_PASSWORD
+	// Function: Set the password for the clients current company
+	// Data:
+	//    String: Password
+	//
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_PASSWORD);
+
+	NetworkSend_string(p, password);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name)
+{
+	//
+	// Packet: PACKET_CLIENT_SET_NAME
+	// Function: Gives the player a new name
+	// Data:
+	//    String: Name
+	//
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_NAME);
+
+	NetworkSend_string(p, name);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+// Send an quit-packet over the network
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg)
+{
+	//
+	// Packet: CLIENT_QUIT
+	// Function: The client is quiting the game
+	// Data:
+	//    String: leave-message
+	//
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_QUIT);
+
+	NetworkSend_string(p, leavemsg);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command)
+{
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_RCON);
+	NetworkSend_string(p, pass);
+	NetworkSend_string(p, command);
+	NetworkSend_Packet(p, MY_CLIENT);
+}
+
+
+// **********
+// Receiving functions
+//   DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p
+// **********
+
+extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FULL)
+{
+	// We try to join a server which is full
+	_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL;
+	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+
+	return NETWORK_RECV_STATUS_SERVER_FULL;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_BANNED)
+{
+	// We try to join a server where we are banned
+	_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_BANNED;
+	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+
+	return NETWORK_RECV_STATUS_SERVER_BANNED;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO)
+{
+	byte company_info_version;
+	int i;
+
+	company_info_version = NetworkRecv_uint8(MY_CLIENT, p);
+
+	if (!MY_CLIENT->has_quit && company_info_version == NETWORK_COMPANY_INFO_VERSION) {
+		byte total;
+		byte current;
+
+		total = NetworkRecv_uint8(MY_CLIENT, p);
+
+		// There is no data at all..
+		if (total == 0) return NETWORK_RECV_STATUS_CLOSE_QUERY;
+
+		current = NetworkRecv_uint8(MY_CLIENT, p);
+		if (!IsValidPlayer(current)) return NETWORK_RECV_STATUS_CLOSE_QUERY;
+
+		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
+		_network_player_info[current].inaugurated_year = NetworkRecv_uint32(MY_CLIENT, p);
+		_network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p);
+		_network_player_info[current].use_password = NetworkRecv_uint8(MY_CLIENT, p);
+		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
+			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(MY_CLIENT, p);
+		for (i = 0; i < NETWORK_STATION_TYPES; i++)
+			_network_player_info[current].num_station[i] = NetworkRecv_uint16(MY_CLIENT, p);
+
+		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
+
+		InvalidateWindow(WC_NETWORK_WINDOW, 0);
+
+		return NETWORK_RECV_STATUS_OKAY;
+	}
+
+	return NETWORK_RECV_STATUS_CLOSE_QUERY;
+}
+
+// This packet contains info about the client (playas and name)
+//  as client we save this in NetworkClientInfo, linked via 'index'
+//  which is always an unique number on a server.
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
+{
+	NetworkClientInfo *ci;
+	uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
+	PlayerID playas = NetworkRecv_uint8(MY_CLIENT, p);
+	char name[NETWORK_NAME_LENGTH];
+	char unique_id[NETWORK_NAME_LENGTH];
+
+	NetworkRecv_string(MY_CLIENT, p, name, sizeof(name));
+	NetworkRecv_string(MY_CLIENT, p, unique_id, sizeof(unique_id));
+
+	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
+
+	/* Do we receive a change of data? Most likely we changed playas */
+	if (index == _network_own_client_index) _network_playas = playas;
+
+	ci = NetworkFindClientInfoFromIndex(index);
+	if (ci != NULL) {
+		if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
+			// Client name changed, display the change
+			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", name);
+		} else if (playas != ci->client_playas) {
+			// The player changed from client-player..
+			// Do not display that for now
+		}
+
+		ci->client_playas = playas;
+		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
+
+		InvalidateWindow(WC_CLIENT_LIST, 0);
+
+		return NETWORK_RECV_STATUS_OKAY;
+	}
+
+	// We don't have this index yet, find an empty index, and put the data there
+	ci = NetworkFindClientInfoFromIndex(NETWORK_EMPTY_INDEX);
+	if (ci != NULL) {
+		ci->client_index = index;
+		ci->client_playas = playas;
+
+		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
+		ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id));
+
+		InvalidateWindow(WC_CLIENT_LIST, 0);
+
+		return NETWORK_RECV_STATUS_OKAY;
+	}
+
+	// Here the program should never ever come.....
+	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
+{
+	NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p);
+
+	switch (error) {
+		/* We made an error in the protocol, and our connection is closed.... */
+		case NETWORK_ERROR_NOT_AUTHORIZED:
+		case NETWORK_ERROR_NOT_EXPECTED:
+		case NETWORK_ERROR_PLAYER_MISMATCH:
+			_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
+			break;
+		case NETWORK_ERROR_FULL:
+			_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL;
+			break;
+		case NETWORK_ERROR_WRONG_REVISION:
+			_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
+			break;
+		case NETWORK_ERROR_WRONG_PASSWORD:
+			_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
+			break;
+		case NETWORK_ERROR_KICKED:
+			_switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
+			break;
+		case NETWORK_ERROR_CHEATER:
+			_switch_mode_errorstr = STR_NETWORK_ERR_CHEATER;
+			break;
+		default:
+			_switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
+	}
+
+	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+
+	return NETWORK_RECV_STATUS_SERVER_ERROR;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
+{
+	NetworkPasswordType type = NetworkRecv_uint8(MY_CLIENT, p);
+
+	switch (type) {
+		case NETWORK_GAME_PASSWORD:
+		case NETWORK_COMPANY_PASSWORD:
+			ShowNetworkNeedPassword(type);
+			return NETWORK_RECV_STATUS_OKAY;
+
+		default: return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+	}
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
+{
+	_network_own_client_index = NetworkRecv_uint16(MY_CLIENT, p);
+
+	// Start receiving the map
+	SEND_COMMAND(PACKET_CLIENT_GETMAP)();
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT)
+{
+	_network_join_status = NETWORK_JOIN_STATUS_WAITING;
+	_network_join_waiting = NetworkRecv_uint8(MY_CLIENT, p);
+	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+
+	// We are put on hold for receiving the map.. we need GUI for this ;)
+	DEBUG(net, 1, "The server is currently busy sending the map to someone else, please wait..." );
+	DEBUG(net, 1, "There are %d clients in front of you", _network_join_waiting);
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
+{
+	static char filename[256];
+	static FILE *file_pointer;
+
+	byte maptype;
+
+	maptype = NetworkRecv_uint8(MY_CLIENT, p);
+
+	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
+
+	// First packet, init some stuff
+	if (maptype == MAP_PACKET_START) {
+		// The name for the temp-map
+		snprintf(filename, lengthof(filename), "%s%snetwork_client.tmp",  _paths.autosave_dir, PATHSEP);
+
+		file_pointer = fopen(filename, "wb");
+		if (file_pointer == NULL) {
+			_switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR;
+			return NETWORK_RECV_STATUS_SAVEGAME;
+		}
+
+		_frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
+
+		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
+		_network_join_kbytes = 0;
+		_network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024;
+		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+
+		// The first packet does not contain any more data
+		return NETWORK_RECV_STATUS_OKAY;
+	}
+
+	if (maptype == MAP_PACKET_NORMAL) {
+		// We are still receiving data, put it to the file
+		fwrite(p->buffer + p->pos, 1, p->size - p->pos, file_pointer);
+
+		_network_join_kbytes = ftell(file_pointer) / 1024;
+		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+	}
+
+	// Check if this was the last packet
+	if (maptype == MAP_PACKET_END) {
+		fclose(file_pointer);
+
+		_network_join_status = NETWORK_JOIN_STATUS_PROCESSING;
+		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
+
+		/* The map is done downloading, load it */
+		if (!SafeSaveOrLoad(filename, SL_LOAD, GM_NORMAL)) {
+			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+			_switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR;
+			return NETWORK_RECV_STATUS_SAVEGAME;
+		}
+		/* If the savegame has successfully loaded, ALL windows have been removed,
+		 * only toolbar/statusbar and gamefield are visible */
+
+		_opt_ptr = &_opt; // during a network game you are always in-game
+
+		// Say we received the map and loaded it correctly!
+		SEND_COMMAND(PACKET_CLIENT_MAP_OK)();
+
+		/* New company/spectator (invalid player) or company we want to join is not active
+		 * Switch local player to spectator and await the server's judgement */
+		if (_network_playas == PLAYER_NEW_COMPANY || !IsValidPlayer(_network_playas) ||
+				!GetPlayer(_network_playas)->is_active) {
+
+			SetLocalPlayer(PLAYER_SPECTATOR);
+
+			if (_network_playas != PLAYER_SPECTATOR) {
+				/* We have arrived and ready to start playing; send a command to make a new player;
+				 * the server will give us a client-id and let us in */
+				_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
+				ShowJoinStatusWindow();
+				NetworkSend_Command(0, 0, 0, CMD_PLAYER_CTRL, NULL);
+			}
+		} else {
+			// take control over an existing company
+			SetLocalPlayer(_network_playas);
+		}
+	}
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
+{
+	_frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p);
+	_frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
+#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
+	// Test if the server supports this option
+	//  and if we are at the frame the server is
+	if (p->pos < p->size) {
+		_sync_frame = _frame_counter_server;
+		_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
+#ifdef NETWORK_SEND_DOUBLE_SEED
+		_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
+#endif
+	}
+#endif
+	DEBUG(net, 5, "Received FRAME %d", _frame_counter_server);
+
+	// Let the server know that we received this frame correctly
+	//  We do this only once per day, to save some bandwidth ;)
+	if (!_network_first_time && last_ack_frame < _frame_counter) {
+		last_ack_frame = _frame_counter + DAY_TICKS;
+		DEBUG(net, 4, "Sent ACK at %d", _frame_counter);
+		SEND_COMMAND(PACKET_CLIENT_ACK)();
+	}
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC)
+{
+	_sync_frame = NetworkRecv_uint32(MY_CLIENT, p);
+	_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
+#ifdef NETWORK_SEND_DOUBLE_SEED
+	_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
+#endif
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND)
+{
+	CommandPacket *cp = malloc(sizeof(CommandPacket));
+	cp->player = NetworkRecv_uint8(MY_CLIENT, p);
+	cp->cmd = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->p1 = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->p2 = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->tile = NetworkRecv_uint32(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, cp->text, sizeof(cp->text));
+	cp->callback = NetworkRecv_uint8(MY_CLIENT, p);
+	cp->frame = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->next = NULL;
+
+	// The server did send us this command..
+	//  queue it in our own queue, so we can handle it in the upcoming frame!
+
+	if (_local_command_queue == NULL) {
+		_local_command_queue = cp;
+	} else {
+		// Find last packet
+		CommandPacket *c = _local_command_queue;
+		while (c->next != NULL) c = c->next;
+		c->next = cp;
+	}
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT)
+{
+	char name[NETWORK_NAME_LENGTH], msg[MAX_TEXT_MSG_LEN];
+	const NetworkClientInfo *ci = NULL, *ci_to;
+
+	NetworkAction action = NetworkRecv_uint8(MY_CLIENT, p);
+	uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
+	bool self_send = NetworkRecv_uint8(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN);
+
+	ci_to = NetworkFindClientInfoFromIndex(index);
+	if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
+
+	/* Did we initiate the action locally? */
+	if (self_send) {
+		switch (action) {
+			case NETWORK_ACTION_CHAT_CLIENT:
+				/* For speaking to client we need the client-name */
+				snprintf(name, sizeof(name), "%s", ci_to->client_name);
+				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
+				break;
+
+			/* For speaking to company or giving money, we need the player-name */
+			case NETWORK_ACTION_GIVE_MONEY:
+				if (!IsValidPlayer(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY;
+				/* fallthrough */
+			case NETWORK_ACTION_CHAT_COMPANY: {
+				StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS;
+
+				GetString(name, str, lastof(name));
+				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
+			} break;
+
+			default: NOT_REACHED(); break;
+		}
+	} else {
+		/* Display message from somebody else */
+		snprintf(name, sizeof(name), "%s", ci_to->client_name);
+		ci = ci_to;
+	}
+
+	if (ci != NULL)
+		NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), self_send, name, "%s", msg);
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
+{
+	char str[100];
+	uint16 index;
+	NetworkClientInfo *ci;
+
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+	GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p), lastof(str));
+
+	ci = NetworkFindClientInfoFromIndex(index);
+	if (ci != NULL) {
+		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str);
+
+		// The client is gone, give the NetworkClientInfo free
+		ci->client_index = NETWORK_EMPTY_INDEX;
+	}
+
+	InvalidateWindow(WC_CLIENT_LIST, 0);
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT)
+{
+	char str[100];
+	uint16 index;
+	NetworkClientInfo *ci;
+
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, str, lengthof(str));
+
+	ci = NetworkFindClientInfoFromIndex(index);
+	if (ci != NULL) {
+		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str);
+
+		// The client is gone, give the NetworkClientInfo free
+		ci->client_index = NETWORK_EMPTY_INDEX;
+	} else {
+		DEBUG(net, 0, "Unknown client (%d) is leaving the game", index);
+	}
+
+	InvalidateWindow(WC_CLIENT_LIST, 0);
+
+	// If we come here it means we could not locate the client.. strange :s
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN)
+{
+	uint16 index;
+	NetworkClientInfo *ci;
+
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+
+	ci = NetworkFindClientInfoFromIndex(index);
+	if (ci != NULL)
+		NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, ci->client_name, "");
+
+	InvalidateWindow(WC_CLIENT_LIST, 0);
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN)
+{
+	_switch_mode_errorstr = STR_NETWORK_SERVER_SHUTDOWN;
+
+	return NETWORK_RECV_STATUS_SERVER_ERROR;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEWGAME)
+{
+	// To trottle the reconnects a bit, every clients waits
+	//  his _local_player value before reconnecting
+	// PLAYER_SPECTATOR is currently 255, so to avoid long wait periods
+	//  set the max to 10.
+	_network_reconnect = min(_local_player + 1, 10);
+	_switch_mode_errorstr = STR_NETWORK_SERVER_REBOOT;
+
+	return NETWORK_RECV_STATUS_SERVER_ERROR;
+}
+
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_RCON)
+{
+	char rcon_out[NETWORK_RCONCOMMAND_LENGTH];
+	uint16 color_code;
+
+	color_code = NetworkRecv_uint16(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, rcon_out, sizeof(rcon_out));
+
+	IConsolePrint(color_code, rcon_out);
+
+	return NETWORK_RECV_STATUS_OKAY;
+}
+
+
+
+// The layout for the receive-functions by the client
+typedef NetworkRecvStatus NetworkClientPacket(Packet *p);
+
+// This array matches PacketType. At an incoming
+//  packet it is matches against this array
+//  and that way the right function to handle that
+//  packet is found.
+static NetworkClientPacket* const _network_client_packet[] = {
+	RECEIVE_COMMAND(PACKET_SERVER_FULL),
+	RECEIVE_COMMAND(PACKET_SERVER_BANNED),
+	NULL, /*PACKET_CLIENT_JOIN,*/
+	RECEIVE_COMMAND(PACKET_SERVER_ERROR),
+	NULL, /*PACKET_CLIENT_COMPANY_INFO,*/
+	RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO),
+	RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO),
+	RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD),
+	NULL, /*PACKET_CLIENT_PASSWORD,*/
+	RECEIVE_COMMAND(PACKET_SERVER_WELCOME),
+	NULL, /*PACKET_CLIENT_GETMAP,*/
+	RECEIVE_COMMAND(PACKET_SERVER_WAIT),
+	RECEIVE_COMMAND(PACKET_SERVER_MAP),
+	NULL, /*PACKET_CLIENT_MAP_OK,*/
+	RECEIVE_COMMAND(PACKET_SERVER_JOIN),
+	RECEIVE_COMMAND(PACKET_SERVER_FRAME),
+	RECEIVE_COMMAND(PACKET_SERVER_SYNC),
+	NULL, /*PACKET_CLIENT_ACK,*/
+	NULL, /*PACKET_CLIENT_COMMAND,*/
+	RECEIVE_COMMAND(PACKET_SERVER_COMMAND),
+	NULL, /*PACKET_CLIENT_CHAT,*/
+	RECEIVE_COMMAND(PACKET_SERVER_CHAT),
+	NULL, /*PACKET_CLIENT_SET_PASSWORD,*/
+	NULL, /*PACKET_CLIENT_SET_NAME,*/
+	NULL, /*PACKET_CLIENT_QUIT,*/
+	NULL, /*PACKET_CLIENT_ERROR,*/
+	RECEIVE_COMMAND(PACKET_SERVER_QUIT),
+	RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT),
+	RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN),
+	RECEIVE_COMMAND(PACKET_SERVER_NEWGAME),
+	RECEIVE_COMMAND(PACKET_SERVER_RCON),
+	NULL, /*PACKET_CLIENT_RCON,*/
+};
+
+// If this fails, check the array above with network_data.h
+assert_compile(lengthof(_network_client_packet) == PACKET_END);
+
+// Is called after a client is connected to the server
+void NetworkClient_Connected(void)
+{
+	// Set the frame-counter to 0 so nothing happens till we are ready
+	_frame_counter = 0;
+	_frame_counter_server = 0;
+	last_ack_frame = 0;
+	// Request the game-info
+	SEND_COMMAND(PACKET_CLIENT_JOIN)();
+}
+
+// Reads the packets from the socket-stream, if available
+NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs)
+{
+	Packet *p;
+	NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY;
+
+	while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) {
+		byte type = NetworkRecv_uint8(MY_CLIENT, p);
+		if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->has_quit) {
+			res = _network_client_packet[type](p);
+		} else {
+			res = NETWORK_RECV_STATUS_MALFORMED_PACKET;
+			DEBUG(net, 0, "[client] received invalid packet type %d", type);
+		}
+
+		free(p);
+	}
+
+	return res;
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_data.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../stdafx.h"
-#include "../debug.h"
-#include "network_data.h"
-#include "../string.h"
-#include "network_client.h"
-#include "../command.h"
-#include "../callback_table.h"
-
-// Add a command to the local command queue
-void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp)
-{
-	CommandPacket* new_cp = malloc(sizeof(*new_cp));
-
-	*new_cp = *cp;
-
-	if (cs->command_queue == NULL) {
-		cs->command_queue = new_cp;
-	} else {
-		CommandPacket *c = cs->command_queue;
-		while (c->next != NULL) c = c->next;
-		c->next = new_cp;
-	}
-}
-
-// Prepare a DoCommand to be send over the network
-void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback)
-{
-	CommandPacket *c = malloc(sizeof(CommandPacket));
-	byte temp_callback;
-
-	c->player = _local_player;
-	c->next = NULL;
-	c->tile = tile;
-	c->p1 = p1;
-	c->p2 = p2;
-	c->cmd = cmd;
-	c->callback = 0;
-
-	temp_callback = 0;
-
-	while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback)
-		temp_callback++;
-	if (temp_callback == _callback_table_count) {
-		DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback);
-		temp_callback = 0; /* _callback_table[0] == NULL */
-	}
-
-	if (_network_server) {
-		// We are the server, so set the command to be executed next possible frame
-		c->frame = _frame_counter_max + 1;
-	} else {
-		c->frame = 0; // The client can't tell which frame, so just make it 0
-	}
-
-	ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text));
-
-	if (_network_server) {
-		// If we are the server, we queue the command in our 'special' queue.
-		//   In theory, we could execute the command right away, but then the
-		//   client on the server can do everything 1 tick faster than others.
-		//   So to keep the game fair, we delay the command with 1 tick
-		//   which gives about the same speed as most clients.
-		NetworkClientState *cs;
-
-		// And we queue it for delivery to the clients
-		FOR_ALL_CLIENTS(cs) {
-			if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c);
-		}
-
-		// Only the server gets the callback, because clients should not get them
-		c->callback = temp_callback;
-		if (_local_command_queue == NULL) {
-			_local_command_queue = c;
-		} else {
-			// Find last packet
-			CommandPacket *cp = _local_command_queue;
-			while (cp->next != NULL) cp = cp->next;
-			cp->next = c;
-		}
-
-		return;
-	}
-
-	// Clients send their command to the server and forget all about the packet
-	c->callback = temp_callback;
-	SEND_COMMAND(PACKET_CLIENT_COMMAND)(c);
-}
-
-// Execute a DoCommand we received from the network
-void NetworkExecuteCommand(CommandPacket *cp)
-{
-	_current_player = cp->player;
-	_cmd_text = cp->text;
-	/* cp->callback is unsigned. so we don't need to do lower bounds checking. */
-	if (cp->callback > _callback_table_count) {
-		DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback);
-		cp->callback = 0;
-	}
-	DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND);
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_data.cpp
@@ -0,0 +1,106 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "network_data.h"
+#include "../string.h"
+#include "network_client.h"
+#include "../command.h"
+#include "../callback_table.h"
+
+// Add a command to the local command queue
+void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp)
+{
+	CommandPacket* new_cp = malloc(sizeof(*new_cp));
+
+	*new_cp = *cp;
+
+	if (cs->command_queue == NULL) {
+		cs->command_queue = new_cp;
+	} else {
+		CommandPacket *c = cs->command_queue;
+		while (c->next != NULL) c = c->next;
+		c->next = new_cp;
+	}
+}
+
+// Prepare a DoCommand to be send over the network
+void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback)
+{
+	CommandPacket *c = malloc(sizeof(CommandPacket));
+	byte temp_callback;
+
+	c->player = _local_player;
+	c->next = NULL;
+	c->tile = tile;
+	c->p1 = p1;
+	c->p2 = p2;
+	c->cmd = cmd;
+	c->callback = 0;
+
+	temp_callback = 0;
+
+	while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback)
+		temp_callback++;
+	if (temp_callback == _callback_table_count) {
+		DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback);
+		temp_callback = 0; /* _callback_table[0] == NULL */
+	}
+
+	if (_network_server) {
+		// We are the server, so set the command to be executed next possible frame
+		c->frame = _frame_counter_max + 1;
+	} else {
+		c->frame = 0; // The client can't tell which frame, so just make it 0
+	}
+
+	ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text));
+
+	if (_network_server) {
+		// If we are the server, we queue the command in our 'special' queue.
+		//   In theory, we could execute the command right away, but then the
+		//   client on the server can do everything 1 tick faster than others.
+		//   So to keep the game fair, we delay the command with 1 tick
+		//   which gives about the same speed as most clients.
+		NetworkClientState *cs;
+
+		// And we queue it for delivery to the clients
+		FOR_ALL_CLIENTS(cs) {
+			if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c);
+		}
+
+		// Only the server gets the callback, because clients should not get them
+		c->callback = temp_callback;
+		if (_local_command_queue == NULL) {
+			_local_command_queue = c;
+		} else {
+			// Find last packet
+			CommandPacket *cp = _local_command_queue;
+			while (cp->next != NULL) cp = cp->next;
+			cp->next = c;
+		}
+
+		return;
+	}
+
+	// Clients send their command to the server and forget all about the packet
+	c->callback = temp_callback;
+	SEND_COMMAND(PACKET_CLIENT_COMMAND)(c);
+}
+
+// Execute a DoCommand we received from the network
+void NetworkExecuteCommand(CommandPacket *cp)
+{
+	_current_player = cp->player;
+	_cmd_text = cp->text;
+	/* cp->callback is unsigned. so we don't need to do lower bounds checking. */
+	if (cp->callback > _callback_table_count) {
+		DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback);
+		cp->callback = 0;
+	}
+	DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND);
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_gamelist.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../stdafx.h"
-#include "../debug.h"
-#include "network_data.h"
-#include "../newgrf_config.h"
-
-// This file handles the GameList
-// Also, it handles the request to a server for data about the server
-
-/** Add a new item to the linked gamelist. If the IP and Port match
- * return the existing item instead of adding it again
- * @param ip the IP-address (inet_addr) of the to-be added item
- * @param port the port the server is running on
- * @return a point to the newly added or already existing item */
-NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port)
-{
-	NetworkGameList *item, *prev_item;
-
-	prev_item = NULL;
-	for (item = _network_game_list; item != NULL; item = item->next) {
-		if (item->ip == ip && item->port == port) return item;
-		prev_item = item;
-	}
-
-	item = malloc(sizeof(*item));
-	memset(item, 0, sizeof(*item));
-	item->next = NULL;
-	item->ip = ip;
-	item->port = port;
-
-	if (prev_item == NULL) {
-		_network_game_list = item;
-	} else {
-		prev_item->next = item;
-	}
-	DEBUG(net, 4, "[gamelist] added server to list");
-
-	UpdateNetworkGameWindow(false);
-
-	return item;
-}
-
-/** Remove an item from the gamelist linked list
- * @param remove pointer to the item to be removed */
-void NetworkGameListRemoveItem(NetworkGameList *remove)
-{
-	NetworkGameList *item, *prev_item;
-
-	prev_item = NULL;
-	for (item = _network_game_list; item != NULL; item = item->next) {
-		if (remove == item) {
-			if (prev_item == NULL) {
-				_network_game_list = remove->next;
-			} else {
-				prev_item->next = remove->next;
-			}
-
-			/* Remove GRFConfig information */
-			ClearGRFConfigList(&remove->info.grfconfig);
-			free(remove);
-			remove = NULL;
-
-			DEBUG(net, 4, "[gamelist] removed server from list");
-			UpdateNetworkGameWindow(false);
-			return;
-		}
-		prev_item = item;
-	}
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_gamelist.cpp
@@ -0,0 +1,74 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "network_data.h"
+#include "../newgrf_config.h"
+
+// This file handles the GameList
+// Also, it handles the request to a server for data about the server
+
+/** Add a new item to the linked gamelist. If the IP and Port match
+ * return the existing item instead of adding it again
+ * @param ip the IP-address (inet_addr) of the to-be added item
+ * @param port the port the server is running on
+ * @return a point to the newly added or already existing item */
+NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port)
+{
+	NetworkGameList *item, *prev_item;
+
+	prev_item = NULL;
+	for (item = _network_game_list; item != NULL; item = item->next) {
+		if (item->ip == ip && item->port == port) return item;
+		prev_item = item;
+	}
+
+	item = malloc(sizeof(*item));
+	memset(item, 0, sizeof(*item));
+	item->next = NULL;
+	item->ip = ip;
+	item->port = port;
+
+	if (prev_item == NULL) {
+		_network_game_list = item;
+	} else {
+		prev_item->next = item;
+	}
+	DEBUG(net, 4, "[gamelist] added server to list");
+
+	UpdateNetworkGameWindow(false);
+
+	return item;
+}
+
+/** Remove an item from the gamelist linked list
+ * @param remove pointer to the item to be removed */
+void NetworkGameListRemoveItem(NetworkGameList *remove)
+{
+	NetworkGameList *item, *prev_item;
+
+	prev_item = NULL;
+	for (item = _network_game_list; item != NULL; item = item->next) {
+		if (remove == item) {
+			if (prev_item == NULL) {
+				_network_game_list = remove->next;
+			} else {
+				prev_item->next = remove->next;
+			}
+
+			/* Remove GRFConfig information */
+			ClearGRFConfigList(&remove->info.grfconfig);
+			free(remove);
+			remove = NULL;
+
+			DEBUG(net, 4, "[gamelist] removed server from list");
+			UpdateNetworkGameWindow(false);
+			return;
+		}
+		prev_item = item;
+	}
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_gui.c
+++ /dev/null
@@ -1,1706 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../string.h"
-#include "../strings.h"
-#include "../table/sprites.h"
-#include "network.h"
-#include "../date.h"
-
-#include "../fios.h"
-#include "table/strings.h"
-#include "../functions.h"
-#include "network_data.h"
-#include "network_client.h"
-#include "network_gui.h"
-#include "network_gamelist.h"
-#include "../window.h"
-#include "../gui.h"
-#include "../gfx.h"
-#include "../command.h"
-#include "../variables.h"
-#include "network_server.h"
-#include "network_udp.h"
-#include "../settings.h"
-#include "../string.h"
-#include "../town.h"
-#include "../newgrf.h"
-
-#define BGC 5
-#define BTC 15
-
-typedef struct network_d {
-	PlayerID company;        // select company in network lobby
-	byte field;              // select text-field in start-server and game-listing
-	NetworkGameList *server; // selected server in lobby and game-listing
-	FiosItem *map;           // selected map in start-server
-} network_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_d));
-
-typedef struct network_ql_d {
-	network_d n;                 // see above; general stuff
-	querystr_d q;                // text-input in start-server and game-listing
-	NetworkGameList **sort_list; // list of games (sorted)
-	list_d l;                    // accompanying list-administration
-} network_ql_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_ql_d));
-
-/* Global to remember sorting after window has been closed */
-static Listing _ng_sorting;
-
-static char _edit_str_buf[150];
-static bool _chat_tab_completion_active;
-
-static void ShowNetworkStartServerWindow(void);
-static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
-extern void SwitchMode(int new_mode);
-
-static const StringID _connection_types_dropdown[] = {
-	STR_NETWORK_LAN_INTERNET,
-	STR_NETWORK_INTERNET_ADVERTISE,
-	INVALID_STRING_ID
-};
-
-static const StringID _lan_internet_types_dropdown[] = {
-	STR_NETWORK_LAN,
-	STR_NETWORK_INTERNET,
-	INVALID_STRING_ID
-};
-
-static const StringID _players_dropdown[] = {
-	STR_NETWORK_0_PLAYERS,
-	STR_NETWORK_1_PLAYERS,
-	STR_NETWORK_2_PLAYERS,
-	STR_NETWORK_3_PLAYERS,
-	STR_NETWORK_4_PLAYERS,
-	STR_NETWORK_5_PLAYERS,
-	STR_NETWORK_6_PLAYERS,
-	STR_NETWORK_7_PLAYERS,
-	STR_NETWORK_8_PLAYERS,
-	STR_NETWORK_9_PLAYERS,
-	STR_NETWORK_10_PLAYERS,
-	INVALID_STRING_ID
-};
-
-static const StringID _language_dropdown[] = {
-	STR_NETWORK_LANG_ANY,
-	STR_NETWORK_LANG_ENGLISH,
-	STR_NETWORK_LANG_GERMAN,
-	STR_NETWORK_LANG_FRENCH,
-	INVALID_STRING_ID
-};
-
-enum {
-	NET_PRC__OFFSET_TOP_WIDGET          = 54,
-	NET_PRC__OFFSET_TOP_WIDGET_COMPANY  = 52,
-	NET_PRC__SIZE_OF_ROW                = 14,
-};
-
-/** Update the network new window because a new server is
- * found on the network.
- * @param unselect unselect the currently selected item */
-void UpdateNetworkGameWindow(bool unselect)
-{
-	SendWindowMessage(WC_NETWORK_WINDOW, 0, unselect, 0, 0);
-}
-
-static bool _internal_sort_order; // Used for Qsort order-flipping
-typedef int CDECL NGameNameSortFunction(const void*, const void*);
-
-/** Qsort function to sort by name. */
-static int CDECL NGameNameSorter(const void *a, const void *b)
-{
-	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
-	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
-	int r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
-
-	return _internal_sort_order ? -r : r;
-}
-
-/** Qsort function to sort by the amount of clients online on a
- * server. If the two servers have the same amount, the one with the
- * higher maximum is preferred. */
-static int CDECL NGameClientSorter(const void *a, const void *b)
-{
-	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
-	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
-	/* Reverse as per default we are interested in most-clients first */
-	int r = cmp1->info.clients_on - cmp2->info.clients_on;
-
-	if (r == 0) r = cmp1->info.clients_max - cmp2->info.clients_max;
-	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
-
-	return _internal_sort_order ? -r : r;
-}
-
-/** Qsort function to sort by joinability. If both servers are the
- * same, prefer the non-passworded server first. */
-static int CDECL NGameAllowedSorter(const void *a, const void *b)
-{
-	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
-	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
-	/* Reverse default as we are interested in compatible clients first */
-	int r = cmp2->info.compatible - cmp1->info.compatible;
-
-	if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password;
-	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
-
-	return _internal_sort_order ? -r : r;
-}
-
-/** (Re)build the network game list as its amount has changed because
- * an item has been added or deleted for example
- * @param ngl list_d struct that contains all necessary information for sorting */
-static void BuildNetworkGameList(network_ql_d *nqld)
-{
-	NetworkGameList *ngl_temp;
-	uint n = 0;
-
-	if (!(nqld->l.flags & VL_REBUILD)) return;
-
-	/* Count the number of games in the list */
-	for (ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) n++;
-	if (n == 0) return;
-
-	/* Create temporary array of games to use for listing */
-	free(nqld->sort_list);
-	nqld->sort_list = malloc(n * sizeof(nqld->sort_list[0]));
-	if (nqld->sort_list == NULL) error("Could not allocate memory for the network-game-sorting-list");
-	nqld->l.list_length = n;
-
-	for (n = 0, ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) {
-		nqld->sort_list[n++] = ngl_temp;
-	}
-
-	/* Force resort */
-	nqld->l.flags &= ~VL_REBUILD;
-	nqld->l.flags |= VL_RESORT;
-}
-
-static void SortNetworkGameList(network_ql_d *nqld)
-{
-	static NGameNameSortFunction * const ngame_sorter[] = {
-		&NGameNameSorter,
-		&NGameClientSorter,
-		&NGameAllowedSorter
-	};
-
-	NetworkGameList *item;
-	uint i;
-
-	if (!(nqld->l.flags & VL_RESORT)) return;
-	if (nqld->l.list_length == 0) return;
-
-	_internal_sort_order = !!(nqld->l.flags & VL_DESC);
-	qsort(nqld->sort_list, nqld->l.list_length, sizeof(nqld->sort_list[0]), ngame_sorter[nqld->l.sort_type]);
-
-	/* After sorting ngl->sort_list contains the sorted items. Put these back
-	 * into the original list. Basically nothing has changed, we are only
-	 * shuffling the ->next pointers */
-	_network_game_list = nqld->sort_list[0];
-	for (item = _network_game_list, i = 1; i != nqld->l.list_length; i++) {
-		item->next = nqld->sort_list[i];
-		item = item->next;
-	}
-	item->next = NULL;
-
-	nqld->l.flags &= ~VL_RESORT;
-}
-
-/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */
-static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
-{
-	network_d *nd = &WP(w, network_ql_d).n;
-	list_d *ld = &WP(w, network_ql_d).l;
-
-	switch (e->event) {
-	case WE_CREATE: /* Focus input box */
-		nd->field = 3;
-		nd->server = NULL;
-
-		WP(w, network_ql_d).sort_list = NULL;
-		ld->flags = VL_REBUILD | (_ng_sorting.order << (VL_DESC - 1));
-		ld->sort_type = _ng_sorting.criteria;
-		break;
-
-	case WE_PAINT: {
-		const NetworkGameList *sel = nd->server;
-		const char *arrow = (ld->flags & VL_DESC) ? DOWNARROW : UPARROW;
-
-		if (ld->flags & VL_REBUILD) {
-			BuildNetworkGameList(&WP(w, network_ql_d));
-			SetVScrollCount(w, ld->list_length);
-		}
-		if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d));
-
-		SetWindowWidgetDisabledState(w, 17, sel == NULL);
-		/* Join Button disabling conditions */
-		SetWindowWidgetDisabledState(w, 16, sel == NULL || // no Selected Server
-				!sel->online || // Server offline
-				sel->info.clients_on >= sel->info.clients_max || // Server full
-				!sel->info.compatible); // Revision mismatch
-
-		SetWindowWidgetHiddenState(w, 18, sel == NULL ||
-				!sel->online ||
-				sel->info.grfconfig == NULL);
-
-		SetDParam(0, 0x00);
-		SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]);
-		DrawWindowWidgets(w);
-
-		DrawEditBox(w, &WP(w, network_ql_d).q, 3);
-
-		DrawString(9, 23, STR_NETWORK_CONNECTION, 2);
-		DrawString(210, 23, STR_NETWORK_PLAYER_NAME, 2);
-
-		/* Sort based on widgets: name, clients, compatibility */
-		switch (ld->sort_type) {
-			case 6 - 6: DoDrawString(arrow, w->widget[6].right - 10, 42, 0x10); break;
-			case 7 - 6: DoDrawString(arrow, w->widget[7].right - 10, 42, 0x10); break;
-			case 8 - 6: DoDrawString(arrow, w->widget[8].right - 10, 42, 0x10); break;
-		}
-
-		{ // draw list of games
-			uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
-			int32 n = 0;
-			int32 pos = w->vscroll.pos;
-			uint max_name_width = w->widget[6].right - w->widget[6].left - 5;
-			const NetworkGameList *cur_item = _network_game_list;
-
-			while (pos > 0 && cur_item != NULL) {
-				pos--;
-				cur_item = cur_item->next;
-			}
-
-			while (cur_item != NULL) {
-				// show highlighted item with a different colour
-				if (cur_item == sel) GfxFillRect(w->widget[6].left + 1, y - 2, w->widget[8].right - 1, y + 9, 10);
-
-				SetDParamStr(0, cur_item->info.server_name);
-				DrawStringTruncated(w->widget[6].left + 5, y, STR_02BD, 16, max_name_width);
-
-				SetDParam(0, cur_item->info.clients_on);
-				SetDParam(1, cur_item->info.clients_max);
-				SetDParam(2, cur_item->info.companies_on);
-				SetDParam(3, cur_item->info.companies_max);
-				DrawStringCentered(210, y, STR_NETWORK_GENERAL_ONLINE, 2);
-
-				// only draw icons if the server is online
-				if (cur_item->online) {
-					// draw a lock if the server is password protected.
-					if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1);
-
-					// draw red or green icon, depending on compatibility with server.
-					DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[8].left + 15, y);
-
-					// draw flag according to server language
-					DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y);
-				}
-
-				cur_item = cur_item->next;
-				y += NET_PRC__SIZE_OF_ROW;
-				if (++n == w->vscroll.cap) break; // max number of games in the window
-			}
-		}
-
-		/* Draw the right menu */
-		GfxFillRect(311, 43, 539, 92, 157);
-		if (sel == NULL) {
-			DrawStringCentered(425, 58, STR_NETWORK_GAME_INFO, 0);
-		} else if (!sel->online) {
-			SetDParamStr(0, sel->info.server_name);
-			DrawStringCentered(425, 68, STR_ORANGE, 0); // game name
-
-			DrawStringCentered(425, 132, STR_NETWORK_SERVER_OFFLINE, 0); // server offline
-		} else { // show game info
-			uint16 y = 100;
-			const uint16 x = w->widget[15].left + 5;
-
-			DrawStringCentered(425, 48, STR_NETWORK_GAME_INFO, 0);
-
-
-			SetDParamStr(0, sel->info.server_name);
-			DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 62, STR_ORANGE, 16); // game name
-
-			SetDParamStr(0, sel->info.map_name);
-			DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 74, STR_02BD, 16); // map name
-
-			SetDParam(0, sel->info.clients_on);
-			SetDParam(1, sel->info.clients_max);
-			SetDParam(2, sel->info.companies_on);
-			SetDParam(3, sel->info.companies_max);
-			DrawString(x, y, STR_NETWORK_CLIENTS, 2);
-			y += 10;
-
-			SetDParam(0, _language_dropdown[sel->info.server_lang]);
-			DrawString(x, y, STR_NETWORK_LANGUAGE, 2); // server language
-			y += 10;
-
-			SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
-			DrawString(x, y, STR_NETWORK_TILESET, 2); // tileset
-			y += 10;
-
-			SetDParam(0, sel->info.map_width);
-			SetDParam(1, sel->info.map_height);
-			DrawString(x, y, STR_NETWORK_MAP_SIZE, 2); // map size
-			y += 10;
-
-			SetDParamStr(0, sel->info.server_revision);
-			DrawString(x, y, STR_NETWORK_SERVER_VERSION, 2); // server version
-			y += 10;
-
-			SetDParamStr(0, sel->info.hostname);
-			SetDParam(1, sel->port);
-			DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, 2); // server address
-			y += 10;
-
-			SetDParam(0, sel->info.start_date);
-			DrawString(x, y, STR_NETWORK_START_DATE, 2); // start date
-			y += 10;
-
-			SetDParam(0, sel->info.game_date);
-			DrawString(x, y, STR_NETWORK_CURRENT_DATE, 2); // current date
-			y += 10;
-
-			y += 2;
-
-			if (!sel->info.compatible) {
-				DrawStringCentered(425, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch
-			} else if (sel->info.clients_on == sel->info.clients_max) {
-				// Show: server full, when clients_on == clients_max
-				DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full
-			} else if (sel->info.use_password) {
-				DrawStringCentered(425, y, STR_NETWORK_PASSWORD, 0); // password warning
-			}
-
-			y += 10;
-		}
-	}	break;
-
-	case WE_CLICK:
-		nd->field = e->we.click.widget;
-		switch (e->we.click.widget) {
-		case 0: case 14: /* Close 'X' | Cancel button */
-			DeleteWindowById(WC_NETWORK_WINDOW, 0);
-			break;
-		case 4: case 5:
-			ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5
-			break;
-		case 6: /* Sort by name */
-		case 7: /* Sort by connected clients */
-		case 8: /* Connectivity (green dot) */
-			if (ld->sort_type == e->we.click.widget - 6) ld->flags ^= VL_DESC;
-			ld->flags |= VL_RESORT;
-			ld->sort_type = e->we.click.widget - 6;
-
-			_ng_sorting.order = !!(ld->flags & VL_DESC);
-			_ng_sorting.criteria = ld->sort_type;
-			SetWindowDirty(w);
-			break;
-		case 9: { /* Matrix to show networkgames */
-			NetworkGameList *cur_item;
-			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
-
-			if (id_v >= w->vscroll.cap) return; // click out of bounds
-			id_v += w->vscroll.pos;
-
-			cur_item = _network_game_list;
-			for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next;
-
-			nd->server = cur_item;
-			SetWindowDirty(w);
-		} break;
-		case 11: /* Find server automatically */
-			switch (_network_lan_internet) {
-				case 0: NetworkUDPSearchGame(); break;
-				case 1: NetworkUDPQueryMasterServer(); break;
-			}
-			break;
-		case 12: { // Add a server
-				ShowQueryString(
-				BindCString(_network_default_ip),
-				STR_NETWORK_ENTER_IP,
-				31 | 0x1000,  // maximum number of characters OR
-				250, // characters up to this width pixels, whichever is satisfied first
-				w, CS_ALPHANUMERAL);
-		} break;
-		case 13: /* Start server */
-			ShowNetworkStartServerWindow();
-			break;
-		case 16: /* Join Game */
-			if (nd->server != NULL) {
-				snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip));
-				_network_last_port = nd->server->port;
-				ShowNetworkLobbyWindow(nd->server);
-			}
-			break;
-		case 17: // Refresh
-			if (nd->server != NULL)
-				NetworkQueryServer(nd->server->info.hostname, nd->server->port, true);
-			break;
-		case 18: // NewGRF Settings
-			if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig);
-			break;
-
-	}	break;
-
-	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		switch (e->we.dropdown.button) {
-			case 5:
-				_network_lan_internet = e->we.dropdown.index;
-				break;
-		}
-
-		SetWindowDirty(w);
-		break;
-
-	case WE_MOUSELOOP:
-		if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3);
-		break;
-
-	case WE_MESSAGE:
-		if (e->we.message.msg != 0) nd->server = NULL;
-		ld->flags |= VL_REBUILD;
-		SetWindowDirty(w);
-		break;
-
-	case WE_KEYPRESS:
-		if (nd->field != 3) {
-			if (nd->server != NULL) {
-				if (e->we.keypress.keycode == WKC_DELETE) { /* Press 'delete' to remove servers */
-					NetworkGameListRemoveItem(nd->server);
-					NetworkRebuildHostList();
-					nd->server = NULL;
-				}
-			}
-			break;
-		}
-
-		if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed
-
-		// The name is only allowed when it starts with a letter!
-		if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ') {
-			ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name));
-		} else {
-			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
-		}
-
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		NetworkAddServer(e->we.edittext.str);
-		NetworkRebuildHostList();
-		break;
-
-	case WE_DESTROY: /* Nicely clean up the sort-list */
-		free(WP(w, network_ql_d).sort_list);
-		break;
-	}
-}
-
-static const Widget _network_game_window_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   549,     0,    13, STR_NETWORK_MULTIPLAYER,     STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   549,    14,   263, 0x0,                         STR_NULL},
-
-/* LEFT SIDE */
-{      WWT_PANEL,   RESIZE_NONE,   BGC,   310,   461,    22,    33, 0x0,                         STR_NETWORK_ENTER_NAME_TIP},
-
-{      WWT_INSET,   RESIZE_NONE,   BGC,    90,   181,    22,    33, STR_NETWORK_COMBO1,          STR_NETWORK_CONNECTION_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   170,   180,    23,    32, STR_0225,                    STR_NETWORK_CONNECTION_TIP},
-
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   170,    42,    53, STR_NETWORK_GAME_NAME,       STR_NETWORK_GAME_NAME_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   171,   250,    42,    53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   251,   290,    42,    53, STR_EMPTY,                   STR_NETWORK_INFO_ICONS_TIP},
-
-{     WWT_MATRIX,   RESIZE_NONE,   BGC,    10,   290,    54,   236, (13 << 8) + 1,               STR_NETWORK_CLICK_GAME_TO_SELECT},
-{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   291,   302,    42,   236, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    30,   130,   246,   257, STR_NETWORK_FIND_SERVER,     STR_NETWORK_FIND_SERVER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   180,   280,   246,   257, STR_NETWORK_ADD_SERVER,      STR_NETWORK_ADD_SERVER_TIP},
-
-/* RIGHT SIDE */
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   315,   415,   246,   257, STR_NETWORK_START_SERVER,    STR_NETWORK_START_SERVER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   246,   257, STR_012E_CANCEL,             STR_NULL},
-
-{      WWT_PANEL,   RESIZE_NONE,   BGC,   310,   540,    42,   236, 0x0,                         STR_NULL},
-
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   315,   415,   215,   226, STR_NETWORK_JOIN_GAME,       STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   215,   226, STR_NETWORK_REFRESH,         STR_NETWORK_REFRESH_TIP},
-
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   197,   208, STR_NEWGRF_SETTINGS_BUTTON,  STR_NULL},
-
-{   WIDGETS_END},
-};
-
-static const WindowDesc _network_game_window_desc = {
-	WDP_CENTER, WDP_CENTER, 550, 264,
-	WC_NETWORK_WINDOW,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_network_game_window_widgets,
-	NetworkGameWindowWndProc,
-};
-
-void ShowNetworkGameWindow(void)
-{
-	static bool first = true;
-	Window *w;
-	DeleteWindowById(WC_NETWORK_WINDOW, 0);
-
-	/* Only show once */
-	if (first) {
-		char* const *srv;
-
-		first = false;
-		// add all servers from the config file to our list
-		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
-			NetworkAddServer(*srv);
-		}
-
-		_ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top)
-		_ng_sorting.order = 0;    // sort ascending by default
-	}
-
-	w = AllocateWindowDesc(&_network_game_window_desc);
-	if (w != NULL) {
-		querystr_d *querystr = &WP(w, network_ql_d).q;
-
-		ttd_strlcpy(_edit_str_buf, _network_player_name, lengthof(_edit_str_buf));
-		w->vscroll.cap = 13;
-
-		querystr->afilter = CS_ALPHANUMERAL;
-		InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120);
-
-		UpdateNetworkGameWindow(true);
-	}
-}
-
-enum {
-	NSSWND_START = 64,
-	NSSWND_ROWSIZE = 12
-};
-
-/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */
-static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
-{
-	network_d *nd = &WP(w, network_ql_d).n;
-
-	switch (e->event) {
-	case WE_CREATE: /* focus input box */
-		nd->field = 3;
-		_network_game_info.use_password = (_network_server_password[0] != '\0');
-		break;
-
-	case WE_PAINT: {
-		int y = NSSWND_START, pos;
-		const FiosItem *item;
-
-		SetDParam( 7, _connection_types_dropdown[_network_advertise]);
-		SetDParam( 9, _players_dropdown[_network_game_info.clients_max]);
-		SetDParam(11, _players_dropdown[_network_game_info.companies_max]);
-		SetDParam(13, _players_dropdown[_network_game_info.spectators_max]);
-		SetDParam(15, _language_dropdown[_network_game_info.server_lang]);
-		DrawWindowWidgets(w);
-
-		GfxFillRect(11, 63, 258, 215, 0xD7);
-		DrawEditBox(w, &WP(w, network_ql_d).q, 3);
-
-		DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2);
-
-		DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2);
-
-		DrawString(280,  63, STR_NETWORK_CONNECTION, 2);
-		DrawString(280,  95, STR_NETWORK_NUMBER_OF_CLIENTS, 2);
-		DrawString(280, 127, STR_NETWORK_NUMBER_OF_COMPANIES, 2);
-		DrawString(280, 159, STR_NETWORK_NUMBER_OF_SPECTATORS, 2);
-		DrawString(280, 191, STR_NETWORK_LANGUAGE_SPOKEN, 2);
-
-		if (_network_game_info.use_password) DoDrawString("*", 408, 23, 3);
-
-		// draw list of maps
-		pos = w->vscroll.pos;
-		while (pos < _fios_num + 1) {
-			item = _fios_list + pos - 1;
-			if (item == nd->map || (pos == 0 && nd->map == NULL))
-				GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
-
-			if (pos == 0) {
-				DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, 9);
-			} else {
-				DoDrawString(item->title, 14, y, _fios_colors[item->type] );
-			}
-			pos++;
-			y += NSSWND_ROWSIZE;
-
-			if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
-		}
-	}	break;
-
-	case WE_CLICK:
-		nd->field = e->we.click.widget;
-		switch (e->we.click.widget) {
-		case 0: /* Close 'X' */
-		case 19: /* Cancel button */
-			ShowNetworkGameWindow();
-			break;
-
-		case 4: /* Set password button */
-			ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL);
-			break;
-
-		case 5: { /* Select map */
-			int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE;
-
-			y += w->vscroll.pos;
-			if (y >= w->vscroll.count) return;
-
-			nd->map = (y == 0) ? NULL : _fios_list + y - 1;
-			SetWindowDirty(w);
-			} break;
-		case 7: case 8: /* Connection type */
-			ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8
-			break;
-		case 9: case 10: /* Number of Players (hide 0 and 1 players) */
-			ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max, 10, 0, 3);
-			break;
-		case 11: case 12: /* Number of Companies (hide 0, 9 and 10 companies; max is 8) */
-			ShowDropDownMenu(w, _players_dropdown, _network_game_info.companies_max, 12, 0, 1537);
-			break;
-		case 13: case 14: /* Number of Spectators */
-			ShowDropDownMenu(w, _players_dropdown, _network_game_info.spectators_max, 14, 0, 0);
-			break;
-		case 15: case 16: /* Language */
-			ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 16, 0, 0);
-			break;
-		case 17: /* Start game */
-			_is_network_server = true;
-
-			if (nd->map == NULL) { // start random new game
-				ShowGenerateLandscape();
-			} else { // load a scenario
-				char *name = FiosBrowseTo(nd->map);
-				if (name != NULL) {
-					SetFiosType(nd->map->type);
-					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
-					ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title));
-
-					DeleteWindow(w);
-					SwitchMode(SM_START_SCENARIO);
-				}
-			}
-			break;
-		case 18: /* Load game */
-			_is_network_server = true;
-			/* XXX - WC_NETWORK_WINDOW should stay, but if it stays, it gets
-			 * copied all the elements of 'load game' and upon closing that, it segfaults */
-			DeleteWindowById(WC_NETWORK_WINDOW, 0);
-			ShowSaveLoadDialog(SLD_LOAD_GAME);
-			break;
-		}
-		break;
-
-	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		switch (e->we.dropdown.button) {
-			case  8: _network_advertise                = (e->we.dropdown.index != 0); break;
-			case 10: _network_game_info.clients_max    = e->we.dropdown.index;        break;
-			case 12: _network_game_info.companies_max  = e->we.dropdown.index;        break;
-			case 14: _network_game_info.spectators_max = e->we.dropdown.index;        break;
-			case 16: _network_game_info.server_lang    = e->we.dropdown.index;        break;
-		}
-
-		SetWindowDirty(w);
-		break;
-
-	case WE_MOUSELOOP:
-		if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3);
-		break;
-
-	case WE_KEYPRESS:
-		if (nd->field == 3) {
-			if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed
-
-			ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name));
-			UpdateTextBufferSize(&WP(w, network_ql_d).q.text);
-		}
-		break;
-
-	case WE_ON_EDIT_TEXT: {
-		ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password));
-		_network_game_info.use_password = (_network_server_password[0] != '\0');
-		SetWindowDirty(w);
-	} break;
-	}
-}
-
-static const Widget _network_start_server_window_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                      STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   243, 0x0,                           STR_NULL},
-
-{      WWT_PANEL,   RESIZE_NONE,   BGC,   100,   272,    22,    33, 0x0,                           STR_NETWORK_NEW_GAME_NAME_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   285,   405,    22,    33, STR_NETWORK_SET_PASSWORD,      STR_NETWORK_PASSWORD_TIP},
-
-{      WWT_INSET,   RESIZE_NONE,   BGC,    10,   271,    62,   216, 0x0,                           STR_NETWORK_SELECT_MAP_TIP},
-{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   259,   270,    63,   215, 0x0,                           STR_0190_SCROLL_BAR_SCROLLS_LIST},
-/* Combo boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
-{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,    77,    88, STR_NETWORK_COMBO1,            STR_NETWORK_CONNECTION_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,    78,    87, STR_0225,                      STR_NETWORK_CONNECTION_TIP},
-{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   109,   120, STR_NETWORK_COMBO2,            STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   110,   119, STR_0225,                      STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
-{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   141,   152, STR_NETWORK_COMBO3,            STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   142,   151, STR_0225,                      STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
-{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   173,   184, STR_NETWORK_COMBO4,            STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   174,   183, STR_0225,                      STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
-{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   205,   216, STR_NETWORK_COMBO5,            STR_NETWORK_LANGUAGE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   206,   215, STR_0225,                      STR_NETWORK_LANGUAGE_TIP},
-
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    40,   140,   224,   235, STR_NETWORK_START_GAME,        STR_NETWORK_START_GAME_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   150,   250,   224,   235, STR_NETWORK_LOAD_GAME,         STR_NETWORK_LOAD_GAME_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   260,   360,   224,   235, STR_012E_CANCEL,               STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _network_start_server_window_desc = {
-	WDP_CENTER, WDP_CENTER, 420, 244,
-	WC_NETWORK_WINDOW,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_network_start_server_window_widgets,
-	NetworkStartServerWindowWndProc,
-};
-
-static void ShowNetworkStartServerWindow(void)
-{
-	Window *w;
-	DeleteWindowById(WC_NETWORK_WINDOW, 0);
-
-	w = AllocateWindowDesc(&_network_start_server_window_desc);
-	ttd_strlcpy(_edit_str_buf, _network_server_name, lengthof(_edit_str_buf));
-
-	_saveload_mode = SLD_NEW_GAME;
-	BuildFileList();
-	w->vscroll.cap = 12;
-	w->vscroll.count = _fios_num+1;
-
-	WP(w, network_ql_d).q.afilter = CS_ALPHANUMERAL;
-	InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_buf, lengthof(_edit_str_buf), 160);
-}
-
-static byte NetworkLobbyFindCompanyIndex(byte pos)
-{
-	byte i;
-
-	/* Scroll through all _network_player_info and get the 'pos' item
-	    that is not empty */
-	for (i = 0; i < MAX_PLAYERS; i++) {
-		if (_network_player_info[i].company_name[0] != '\0') {
-			if (pos-- == 0) return i;
-		}
-	}
-
-	return 0;
-}
-
-/* uses network_d WP macro */
-static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
-{
-	network_d *nd = &WP(w, network_d);
-
-	switch (e->event) {
-	case WE_CREATE:
-		nd->company = (byte)-1;
-		break;
-
-	case WE_PAINT: {
-		const NetworkGameInfo *gi = &nd->server->info;
-		int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
-
-		SetWindowWidgetDisabledState(w, 7, nd->company == (byte)-1);
-		SetWindowWidgetDisabledState(w, 8, gi->companies_on >= gi->companies_max);
-		/* You can not join a server as spectator when it has no companies active..
-		 * it causes some nasty crashes */
-		SetWindowWidgetDisabledState(w, 9, gi->spectators_on >= gi->spectators_max ||
-				gi->companies_on == 0);
-
-		DrawWindowWidgets(w);
-
-		SetDParamStr(0, gi->server_name);
-		DrawString(10, 22, STR_NETWORK_PREPARE_TO_JOIN, 2);
-
-		/* Draw company list */
-		pos = w->vscroll.pos;
-		while (pos < gi->companies_on) {
-			byte company = NetworkLobbyFindCompanyIndex(pos);
-			bool income = false;
-			if (nd->company == company)
-				GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour
-
-			DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, 16, 135 - 13);
-			if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, 135, y);
-
-			/* If the company's income was positive puts a green dot else a red dot */
-			if (_network_player_info[company].income >= 0) income = true;
-			DrawSprite(SPR_BLOT | (income ? PALETTE_TO_GREEN : PALETTE_TO_RED), 145, y);
-
-			pos++;
-			y += NET_PRC__SIZE_OF_ROW;
-			if (pos >= w->vscroll.cap) break;
-		}
-
-		/* Draw info about selected company when it is selected in the left window */
-		GfxFillRect(174, 39, 403, 75, 157);
-		DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, 0);
-		if (nd->company != (byte)-1) {
-			const uint x = 183;
-			const uint trunc_width = w->widget[6].right - x;
-			y = 80;
-
-			SetDParam(0, nd->server->info.clients_on);
-			SetDParam(1, nd->server->info.clients_max);
-			SetDParam(2, nd->server->info.companies_on);
-			SetDParam(3, nd->server->info.companies_max);
-			DrawString(x, y, STR_NETWORK_CLIENTS, 2);
-			y += 10;
-
-			SetDParamStr(0, _network_player_info[nd->company].company_name);
-			DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, 2, trunc_width);
-			y += 10;
-
-			SetDParam(0, _network_player_info[nd->company].inaugurated_year);
-			DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, 2); // inauguration year
-			y += 10;
-
-			SetDParam64(0, _network_player_info[nd->company].company_value);
-			DrawString(x, y, STR_NETWORK_VALUE, 2); // company value
-			y += 10;
-
-			SetDParam64(0, _network_player_info[nd->company].money);
-			DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, 2); // current balance
-			y += 10;
-
-			SetDParam64(0, _network_player_info[nd->company].income);
-			DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, 2); // last year's income
-			y += 10;
-
-			SetDParam(0, _network_player_info[nd->company].performance);
-			DrawString(x, y, STR_NETWORK_PERFORMANCE, 2); // performance
-			y += 10;
-
-			SetDParam(0, _network_player_info[nd->company].num_vehicle[0]);
-			SetDParam(1, _network_player_info[nd->company].num_vehicle[1]);
-			SetDParam(2, _network_player_info[nd->company].num_vehicle[2]);
-			SetDParam(3, _network_player_info[nd->company].num_vehicle[3]);
-			SetDParam(4, _network_player_info[nd->company].num_vehicle[4]);
-			DrawString(x, y, STR_NETWORK_VEHICLES, 2); // vehicles
-			y += 10;
-
-			SetDParam(0, _network_player_info[nd->company].num_station[0]);
-			SetDParam(1, _network_player_info[nd->company].num_station[1]);
-			SetDParam(2, _network_player_info[nd->company].num_station[2]);
-			SetDParam(3, _network_player_info[nd->company].num_station[3]);
-			SetDParam(4, _network_player_info[nd->company].num_station[4]);
-			DrawString(x, y, STR_NETWORK_STATIONS, 2); // stations
-			y += 10;
-
-			SetDParamStr(0, _network_player_info[nd->company].players);
-			DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, 2, trunc_width); // players
-		}
-	}	break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 0: case 11: /* Close 'X' | Cancel button */
-			ShowNetworkGameWindow();
-			break;
-		case 4: { /* Company list */
-			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
-
-			if (id_v >= w->vscroll.cap) return;
-
-			id_v += w->vscroll.pos;
-			nd->company = (id_v >= nd->server->info.companies_on) ? (byte)-1 : NetworkLobbyFindCompanyIndex(id_v);
-			SetWindowDirty(w);
-		}	break;
-		case 7: /* Join company */
-			if (nd->company != (byte)-1) {
-				_network_playas = nd->company;
-				NetworkClientConnectGame(_network_last_host, _network_last_port);
-			}
-			break;
-		case 8: /* New company */
-			_network_playas = PLAYER_NEW_COMPANY;
-			NetworkClientConnectGame(_network_last_host, _network_last_port);
-			break;
-		case 9: /* Spectate game */
-			_network_playas = PLAYER_SPECTATOR;
-			NetworkClientConnectGame(_network_last_host, _network_last_port);
-			break;
-		case 10: /* Refresh */
-			NetworkQueryServer(_network_last_host, _network_last_port, false); // company info
-			NetworkUDPQueryServer(_network_last_host, _network_last_port);     // general data
-			break;
-		}	break;
-
-	case WE_MESSAGE:
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const Widget _network_lobby_window_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_GAME_LOBBY,    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   234, 0x0,                       STR_NULL},
-
-// company list
-{      WWT_PANEL,   RESIZE_NONE,   BTC,    10,   155,    38,    49, 0x0,                       STR_NULL},
-{     WWT_MATRIX,   RESIZE_NONE,   BGC,    10,   155,    50,   190, (10 << 8) + 1,             STR_NETWORK_COMPANY_LIST_TIP},
-{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   156,   167,    38,   190, STR_NULL,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
-
-// company/player info
-{      WWT_PANEL,   RESIZE_NONE,   BGC,   173,   404,    38,   190, 0x0,                       STR_NULL},
-
-// buttons
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   151,   200,   211, STR_NETWORK_JOIN_COMPANY,  STR_NETWORK_JOIN_COMPANY_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   151,   215,   226, STR_NETWORK_NEW_COMPANY,   STR_NETWORK_NEW_COMPANY_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   158,   268,   200,   211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   158,   268,   215,   226, STR_NETWORK_REFRESH,       STR_NETWORK_REFRESH_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   278,   388,   200,   211, STR_012E_CANCEL,           STR_NULL},
-
-{   WIDGETS_END},
-};
-
-static const WindowDesc _network_lobby_window_desc = {
-	WDP_CENTER, WDP_CENTER, 420, 235,
-	WC_NETWORK_WINDOW,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_network_lobby_window_widgets,
-	NetworkLobbyWindowWndProc,
-};
-
-/* Show the networklobbywindow with the selected server
- * @param ngl Selected game pointer which is passed to the new window */
-static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
-{
-	Window *w;
-	DeleteWindowById(WC_NETWORK_WINDOW, 0);
-
-	NetworkQueryServer(_network_last_host, _network_last_port, false); // company info
-	NetworkUDPQueryServer(_network_last_host, _network_last_port);     // general data
-
-	w = AllocateWindowDesc(&_network_lobby_window_desc);
-	if (w != NULL) {
-		WP(w, network_ql_d).n.server = ngl;
-		strcpy(_edit_str_buf, "");
-		w->vscroll.cap = 10;
-	}
-}
-
-// The window below gives information about the connected clients
-//  and also makes able to give money to them, kick them (if server)
-//  and stuff like that.
-
-extern void DrawPlayerIcon(PlayerID pid, int x, int y);
-
-// Every action must be of this form
-typedef void ClientList_Action_Proc(byte client_no);
-
-// Max 10 actions per client
-#define MAX_CLIENTLIST_ACTION 10
-
-// Some standard bullshit.. defines variables ;)
-static void ClientListWndProc(Window *w, WindowEvent *e);
-static void ClientListPopupWndProc(Window *w, WindowEvent *e);
-static byte _selected_clientlist_item = 255;
-static byte _selected_clientlist_y = 0;
-static char _clientlist_action[MAX_CLIENTLIST_ACTION][50];
-static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION];
-
-enum {
-	CLNWND_OFFSET = 16,
-	CLNWND_ROWSIZE = 10
-};
-
-static const Widget _client_list_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_NETWORK_CLIENT_LIST,  STR_018C_WINDOW_TITLE_DRAG_THIS},
-
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,    14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const Widget _client_list_popup_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   99,     0,     0,     0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static WindowDesc _client_list_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 1,
-	WC_CLIENT_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_client_list_widgets,
-	ClientListWndProc
-};
-
-// Finds the Xth client-info that is active
-static const NetworkClientInfo *NetworkFindClientInfo(byte client_no)
-{
-	const NetworkClientInfo *ci;
-
-	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-		if (client_no == 0) return ci;
-		client_no--;
-	}
-
-	return NULL;
-}
-
-// 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);
-}
-
-static void ClientList_Ban(byte client_no)
-{
-	uint i;
-	uint32 ip = NetworkFindClientInfo(client_no)->client_ip;
-
-	for (i = 0; i < lengthof(_network_ban_list); i++) {
-		if (_network_ban_list[i] == NULL) {
-			_network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip));
-			break;
-		}
-	}
-
-	if (client_no < MAX_PLAYERS)
-		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
-}
-
-static void ClientList_GiveMoney(byte client_no)
-{
-	if (NetworkFindClientInfo(client_no) != NULL)
-		ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
-}
-
-static void ClientList_SpeakToClient(byte client_no)
-{
-	if (NetworkFindClientInfo(client_no) != NULL)
-		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index);
-}
-
-static void ClientList_SpeakToCompany(byte client_no)
-{
-	if (NetworkFindClientInfo(client_no) != NULL)
-		ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
-}
-
-static void ClientList_SpeakToAll(byte client_no)
-{
-	ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
-}
-
-static void ClientList_None(byte client_no)
-{
-	// No action ;)
-}
-
-
-
-// Help, a action is clicked! What do we do?
-static void HandleClientListPopupClick(byte index, byte clientno) {
-	// A click on the Popup of the ClientList.. handle the command
-	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
-		_clientlist_proc[index](clientno);
-	}
-}
-
-// Finds the amount of clients and set the height correct
-static bool CheckClientListHeight(Window *w)
-{
-	int num = 0;
-	const NetworkClientInfo *ci;
-
-	// Should be replaced with a loop through all clients
-	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-		num++;
-	}
-
-	num *= CLNWND_ROWSIZE;
-
-	// If height is changed
-	if (w->height != CLNWND_OFFSET + num + 1) {
-		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
-		SetWindowDirty(w);
-		w->widget[2].bottom = w->widget[2].top + num + 2;
-		w->height = CLNWND_OFFSET + num + 1;
-		SetWindowDirty(w);
-		return false;
-	}
-	return true;
-}
-
-// Finds the amount of actions in the popup and set the height correct
-static uint ClientListPopupHeigth(void) {
-	int i, num = 0;
-
-	// Find the amount of actions
-	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		if (_clientlist_action[i][0] == '\0') continue;
-		if (_clientlist_proc[i] == NULL) continue;
-		num++;
-	}
-
-	num *= CLNWND_ROWSIZE;
-
-	return num + 1;
-}
-
-// Show the popup (action list)
-static Window *PopupClientList(Window *w, int client_no, int x, int y)
-{
-	int i, h;
-	const NetworkClientInfo *ci;
-	DeleteWindowById(WC_TOOLBAR_MENU, 0);
-
-	// Clean the current actions
-	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		_clientlist_action[i][0] = '\0';
-		_clientlist_proc[i] = NULL;
-	}
-
-	// Fill the actions this client has
-	// Watch is, max 50 chars long!
-
-	ci = NetworkFindClientInfo(client_no);
-	if (ci == NULL) return NULL;
-
-	i = 0;
-	if (_network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToClient;
-	}
-
-	if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToCompany;
-	}
-	GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i]));
-	_clientlist_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 */
-		if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) {
-			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
-			_clientlist_proc[i++] = &ClientList_GiveMoney;
-		}
-	}
-
-	// A server can kick clients (but not himself)
-	if (_network_server && _network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_Kick;
-
-		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
-		_clientlist_proc[i++] = &ClientList_Ban;
-	}
-
-	if (i == 0) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_None;
-	}
-
-	/* Calculate the height */
-	h = ClientListPopupHeigth();
-
-	// Allocate the popup
-	w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
-	w->widget[0].bottom = w->widget[0].top + h;
-	w->widget[0].right = w->widget[0].left + 150;
-
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w,menu_d).item_count = 0;
-	// Save our client
-	WP(w,menu_d).main_button = client_no;
-	WP(w,menu_d).sel_index = 0;
-	// We are a popup
-	_popup_menu_active = true;
-
-	return w;
-}
-
-/** Main handle for the client popup list
- * uses menu_d WP macro */
-static void ClientListPopupWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int i, y, sel;
-		byte colour;
-		DrawWindowWidgets(w);
-
-		// Draw the actions
-		sel = WP(w,menu_d).sel_index;
-		y = 1;
-		for (i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
-			if (_clientlist_action[i][0] == '\0') continue;
-			if (_clientlist_proc[i] == NULL) continue;
-
-			if (sel-- == 0) { // Selected item, highlight it
-				GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
-				colour = 0xC;
-			} else {
-				colour = 0x10;
-			}
-
-			DoDrawString(_clientlist_action[i], 4, y, colour);
-		}
-	}	break;
-
-	case WE_POPUPMENU_SELECT: {
-		// We selected an action
-		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
-
-		if (index >= 0 && e->we.popupmenu.pt.y >= w->top)
-			HandleClientListPopupClick(index, WP(w,menu_d).main_button);
-
-		DeleteWindowById(WC_TOOLBAR_MENU, 0);
-	}	break;
-
-	case WE_POPUPMENU_OVER: {
-		// Our mouse hoovers over an action? Select it!
-		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
-
-		if (index == -1 || index == WP(w,menu_d).sel_index) return;
-
-		WP(w,menu_d).sel_index = index;
-		SetWindowDirty(w);
-	} break;
-
-	}
-}
-
-// Main handle for clientlist
-static void ClientListWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		NetworkClientInfo *ci;
-		int y, i = 0;
-		byte colour;
-
-		// Check if we need to reset the height
-		if (!CheckClientListHeight(w)) break;
-
-		DrawWindowWidgets(w);
-
-		y = CLNWND_OFFSET;
-
-		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-			if (_selected_clientlist_item == i++) { // Selected item, highlight it
-				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
-				colour = 0xC;
-			} else {
-				colour = 0x10;
-			}
-
-			if (ci->client_index == NETWORK_SERVER_INDEX) {
-				DrawString(4, y, STR_NETWORK_SERVER, colour);
-			} else {
-				DrawString(4, y, STR_NETWORK_CLIENT, colour);
-			}
-
-			// Filter out spectators
-			if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
-
-			DoDrawString(ci->client_name, 81, y, colour);
-
-			y += CLNWND_ROWSIZE;
-		}
-	}	break;
-
-	case WE_CLICK:
-		// Show the popup with option
-		if (_selected_clientlist_item != 255) {
-			PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
-		}
-
-		break;
-
-	case WE_MOUSEOVER:
-		// -1 means we left the current window
-		if (e->we.mouseover.pt.y == -1) {
-			_selected_clientlist_y = 0;
-			_selected_clientlist_item = 255;
-			SetWindowDirty(w);
-			break;
-		}
-		// It did not change.. no update!
-		if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
-
-		// Find the new selected item (if any)
-		_selected_clientlist_y = e->we.mouseover.pt.y;
-		if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
-			_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
-		} else {
-			_selected_clientlist_item = 255;
-		}
-
-		// Repaint
-		SetWindowDirty(w);
-		break;
-
-	case WE_DESTROY: case WE_CREATE:
-		// When created or destroyed, data is reset
-		_selected_clientlist_item = 255;
-		_selected_clientlist_y = 0;
-		break;
-	}
-}
-
-void ShowClientList(void)
-{
-	AllocateWindowDescFront(&_client_list_desc, 0);
-}
-
-
-static NetworkPasswordType pw_type;
-
-
-void ShowNetworkNeedPassword(NetworkPasswordType npt)
-{
-	StringID caption;
-
-	pw_type = npt;
-	switch (npt) {
-		default: NOT_REACHED();
-		case NETWORK_GAME_PASSWORD:    caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
-		case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
-	}
-	ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
-}
-
-
-static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		uint8 progress; // used for progress bar
-		DrawWindowWidgets(w);
-
-		DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, 14);
-		switch (_network_join_status) {
-			case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
-			case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
-				progress = 10; // first two stages 10%
-				break;
-			case NETWORK_JOIN_STATUS_WAITING:
-				SetDParam(0, _network_join_waiting);
-				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, 14);
-				progress = 15; // third stage is 15%
-				break;
-			case NETWORK_JOIN_STATUS_DOWNLOADING:
-				SetDParam(0, _network_join_kbytes);
-				SetDParam(1, _network_join_kbytes_total);
-				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, 14);
-				/* Fallthrough */
-			default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
-				progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
-		}
-
-		/* Draw nice progress bar :) */
-		DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, 0);
-	}	break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 2: /* Disconnect button */
-				NetworkDisconnect();
-				DeleteWindow(w);
-				SwitchMode(SM_MENU);
-				ShowNetworkGameWindow();
-				break;
-		}
-		break;
-
-		/* If the server asks for a password, we need to fill it in */
-		case WE_ON_EDIT_TEXT_CANCEL:
-			NetworkDisconnect();
-			ShowNetworkGameWindow();
-			break;
-
-		case WE_ON_EDIT_TEXT:
-			SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
-			break;
-	}
-}
-
-static const Widget _network_join_status_window_widget[] = {
-{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,    84, 0x0,                    STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    75,   175,    69,    80, STR_NETWORK_DISCONNECT, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _network_join_status_window_desc = {
-	WDP_CENTER, WDP_CENTER, 250, 85,
-	WC_NETWORK_STATUS_WINDOW, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
-	_network_join_status_window_widget,
-	NetworkJoinStatusWindowWndProc,
-};
-
-void ShowJoinStatusWindow(void)
-{
-	Window *w;
-	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-	w = AllocateWindowDesc(&_network_join_status_window_desc);
-	/* Parent the status window to the lobby */
-	if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
-}
-
-static void SendChat(const char *buf, DestType type, byte dest)
-{
-	if (buf[0] == '\0') return;
-	if (!_network_server) {
-		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT + type, type, dest, buf);
-	} else {
-		NetworkServer_HandleChat(NETWORK_ACTION_CHAT + type, type, dest, buf, NETWORK_SERVER_INDEX);
-	}
-}
-
-/**
- * Find the next item of the list of things that can be auto-completed.
- * @param item The current indexed item to return. This function can, and most
- *     likely will, alter item, to skip empty items in the arrays.
- * @return Returns the char that matched to the index.
- */
-static const char *ChatTabCompletionNextItem(uint *item)
-{
-	static char chat_tab_temp_buffer[64];
-
-	/* First, try clients */
-	if (*item < MAX_CLIENT_INFO) {
-		/* Skip inactive clients */
-		while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++;
-		if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name;
-	}
-
-	/* Then, try townnames */
-	/* Not that the following assumes all town indices are adjacent, ie no
-	 * towns have been deleted. */
-	if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) {
-		const Town *t;
-
-		FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
-			/* Get the town-name via the string-system */
-			SetDParam(0, t->townnameparts);
-			GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer));
-			return &chat_tab_temp_buffer[0];
-		}
-	}
-
-	return NULL;
-}
-
-/**
- * Find what text to complete. It scans for a space from the left and marks
- *  the word right from that as to complete. It also writes a \0 at the
- *  position of the space (if any). If nothing found, buf is returned.
- */
-static char *ChatTabCompletionFindText(char *buf)
-{
-	char *p = strrchr(buf, ' ');
-	if (p == NULL) return buf;
-
-	*p = '\0';
-	return p + 1;
-}
-
-/**
- * See if we can auto-complete the current text of the user.
- */
-static void ChatTabCompletion(Window *w)
-{
-	static char _chat_tab_completion_buf[lengthof(_edit_str_buf)];
-	Textbuf *tb = &WP(w, querystr_d).text;
-	uint len, tb_len;
-	uint item;
-	char *tb_buf, *pre_buf;
-	const char *cur_name;
-	bool second_scan = false;
-
-	item = 0;
-
-	/* Copy the buffer so we can modify it without damaging the real data */
-	pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf);
-
-	tb_buf  = ChatTabCompletionFindText(pre_buf);
-	tb_len  = strlen(tb_buf);
-
-	while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) {
-		item++;
-
-		if (_chat_tab_completion_active) {
-			/* We are pressing TAB again on the same name, is there an other name
-			 *  that starts with this? */
-			if (!second_scan) {
-				uint offset;
-				uint length;
-
-				/* If we are completing at the begin of the line, skip the ': ' we added */
-				if (tb_buf == pre_buf) {
-					offset = 0;
-					length = tb->length - 2;
-				} else {
-					/* Else, find the place we are completing at */
-					offset = strlen(pre_buf) + 1;
-					length = tb->length - offset;
-				}
-
-				/* Compare if we have a match */
-				if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
-
-				continue;
-			}
-
-			/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
-		}
-
-		len = strlen(cur_name);
-		if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
-			/* Save the data it was before completion */
-			if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf);
-			_chat_tab_completion_active = true;
-
-			/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
-			if (pre_buf == tb_buf) {
-				snprintf(tb->buf, lengthof(_edit_str_buf), "%s: ", cur_name);
-			} else {
-				snprintf(tb->buf, lengthof(_edit_str_buf), "%s %s", pre_buf, cur_name);
-			}
-
-			/* Update the textbuffer */
-			UpdateTextBufferSize(&WP(w, querystr_d).text);
-
-			SetWindowDirty(w);
-			free(pre_buf);
-			return;
-		}
-	}
-
-	if (second_scan) {
-		/* We walked all posibilities, and the user presses tab again.. revert to original text */
-		strcpy(tb->buf, _chat_tab_completion_buf);
-		_chat_tab_completion_active = false;
-
-		/* Update the textbuffer */
-		UpdateTextBufferSize(&WP(w, querystr_d).text);
-
-		SetWindowDirty(w);
-	}
-	free(pre_buf);
-}
-
-/* uses querystr_d WP macro
- * uses querystr_d->caption to store
- * - type of chat message (Private/Team/All) in bytes 0-7
- * - destination of chat message in the case of Team/Private in bytes 8-15 */
-static void ChatWindowWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0);
-		SETBIT(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
-		break;
-
-	case WE_PAINT: {
-		static const StringID chat_captions[] = {
-			STR_NETWORK_CHAT_ALL_CAPTION,
-			STR_NETWORK_CHAT_COMPANY_CAPTION,
-			STR_NETWORK_CHAT_CLIENT_CAPTION
-		};
-		StringID msg;
-
-		DrawWindowWidgets(w);
-
-		assert(GB(WP(w, querystr_d).caption, 0, 8) < lengthof(chat_captions));
-		msg = chat_captions[GB(WP(w, querystr_d).caption, 0, 8)];
-		DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, msg, 16);
-		DrawEditBox(w, &WP(w, querystr_d), 2);
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 3: { /* Send */
-				DestType type = GB(WP(w, querystr_d).caption, 0, 8);
-				byte dest = GB(WP(w, querystr_d).caption, 8, 8);
-				SendChat(WP(w, querystr_d).text.buf, type, dest);
-			} /* FALLTHROUGH */
-			case 0: /* Cancel */ DeleteWindow(w); break;
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		HandleEditBox(w, &WP(w, querystr_d), 2);
-		break;
-
-	case WE_KEYPRESS:
-		if (e->we.keypress.keycode == WKC_TAB) {
-			ChatTabCompletion(w);
-		} else {
-			_chat_tab_completion_active = false;
-			switch (HandleEditBoxKey(w, &WP(w, querystr_d), 2, e)) {
-				case 1: { /* Return */
-				DestType type = GB(WP(w, querystr_d).caption, 0, 8);
-				byte dest = GB(WP(w, querystr_d).caption, 8, 8);
-				SendChat(WP(w, querystr_d).text.buf, type, dest);
-			} /* FALLTHROUGH */
-				case 2: /* Escape */ DeleteWindow(w); break;
-			}
-		}
-		break;
-
-	case WE_DESTROY:
-		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0);
-		CLRBIT(_no_scroll, SCROLL_CHAT);
-		break;
-	}
-}
-
-static const Widget _chat_window_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,  0, 13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{      WWT_PANEL, RESIZE_NONE, 14,  11, 639,  0, 13, 0x0,              STR_NULL}, // background
-{      WWT_PANEL, RESIZE_NONE, 14,  75, 577,  1, 12, 0x0,              STR_NULL}, // text box
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 578, 639,  1, 12, STR_NETWORK_SEND, STR_NULL}, // send button
-{   WIDGETS_END},
-};
-
-static const WindowDesc _chat_window_desc = {
-	WDP_CENTER, -26, 640, 14, // x, y, width, height
-	WC_SEND_NETWORK_MSG,0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
-	_chat_window_widgets,
-	ChatWindowWndProc
-};
-
-void ShowNetworkChatQueryWindow(DestType type, byte dest)
-{
-	Window *w;
-
-	DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
-
-	_edit_str_buf[0] = '\0';
-	_chat_tab_completion_active = false;
-
-	w = AllocateWindowDesc(&_chat_window_desc);
-
-	LowerWindowWidget(w, 2);
-	WP(w, querystr_d).caption = GB(type, 0, 8) | (dest << 8); // Misuse of caption
-	WP(w, querystr_d).afilter = CS_ALPHANUMERAL;
-	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 0);
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_gui.cpp
@@ -0,0 +1,1706 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../string.h"
+#include "../strings.h"
+#include "../table/sprites.h"
+#include "network.h"
+#include "../date.h"
+
+#include "../fios.h"
+#include "table/strings.h"
+#include "../functions.h"
+#include "network_data.h"
+#include "network_client.h"
+#include "network_gui.h"
+#include "network_gamelist.h"
+#include "../window.h"
+#include "../gui.h"
+#include "../gfx.h"
+#include "../command.h"
+#include "../variables.h"
+#include "network_server.h"
+#include "network_udp.h"
+#include "../settings.h"
+#include "../string.h"
+#include "../town.h"
+#include "../newgrf.h"
+
+#define BGC 5
+#define BTC 15
+
+typedef struct network_d {
+	PlayerID company;        // select company in network lobby
+	byte field;              // select text-field in start-server and game-listing
+	NetworkGameList *server; // selected server in lobby and game-listing
+	FiosItem *map;           // selected map in start-server
+} network_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_d));
+
+typedef struct network_ql_d {
+	network_d n;                 // see above; general stuff
+	querystr_d q;                // text-input in start-server and game-listing
+	NetworkGameList **sort_list; // list of games (sorted)
+	list_d l;                    // accompanying list-administration
+} network_ql_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_ql_d));
+
+/* Global to remember sorting after window has been closed */
+static Listing _ng_sorting;
+
+static char _edit_str_buf[150];
+static bool _chat_tab_completion_active;
+
+static void ShowNetworkStartServerWindow(void);
+static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
+extern void SwitchMode(int new_mode);
+
+static const StringID _connection_types_dropdown[] = {
+	STR_NETWORK_LAN_INTERNET,
+	STR_NETWORK_INTERNET_ADVERTISE,
+	INVALID_STRING_ID
+};
+
+static const StringID _lan_internet_types_dropdown[] = {
+	STR_NETWORK_LAN,
+	STR_NETWORK_INTERNET,
+	INVALID_STRING_ID
+};
+
+static const StringID _players_dropdown[] = {
+	STR_NETWORK_0_PLAYERS,
+	STR_NETWORK_1_PLAYERS,
+	STR_NETWORK_2_PLAYERS,
+	STR_NETWORK_3_PLAYERS,
+	STR_NETWORK_4_PLAYERS,
+	STR_NETWORK_5_PLAYERS,
+	STR_NETWORK_6_PLAYERS,
+	STR_NETWORK_7_PLAYERS,
+	STR_NETWORK_8_PLAYERS,
+	STR_NETWORK_9_PLAYERS,
+	STR_NETWORK_10_PLAYERS,
+	INVALID_STRING_ID
+};
+
+static const StringID _language_dropdown[] = {
+	STR_NETWORK_LANG_ANY,
+	STR_NETWORK_LANG_ENGLISH,
+	STR_NETWORK_LANG_GERMAN,
+	STR_NETWORK_LANG_FRENCH,
+	INVALID_STRING_ID
+};
+
+enum {
+	NET_PRC__OFFSET_TOP_WIDGET          = 54,
+	NET_PRC__OFFSET_TOP_WIDGET_COMPANY  = 52,
+	NET_PRC__SIZE_OF_ROW                = 14,
+};
+
+/** Update the network new window because a new server is
+ * found on the network.
+ * @param unselect unselect the currently selected item */
+void UpdateNetworkGameWindow(bool unselect)
+{
+	SendWindowMessage(WC_NETWORK_WINDOW, 0, unselect, 0, 0);
+}
+
+static bool _internal_sort_order; // Used for Qsort order-flipping
+typedef int CDECL NGameNameSortFunction(const void*, const void*);
+
+/** Qsort function to sort by name. */
+static int CDECL NGameNameSorter(const void *a, const void *b)
+{
+	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
+	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
+	int r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
+
+	return _internal_sort_order ? -r : r;
+}
+
+/** Qsort function to sort by the amount of clients online on a
+ * server. If the two servers have the same amount, the one with the
+ * higher maximum is preferred. */
+static int CDECL NGameClientSorter(const void *a, const void *b)
+{
+	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
+	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
+	/* Reverse as per default we are interested in most-clients first */
+	int r = cmp1->info.clients_on - cmp2->info.clients_on;
+
+	if (r == 0) r = cmp1->info.clients_max - cmp2->info.clients_max;
+	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
+
+	return _internal_sort_order ? -r : r;
+}
+
+/** Qsort function to sort by joinability. If both servers are the
+ * same, prefer the non-passworded server first. */
+static int CDECL NGameAllowedSorter(const void *a, const void *b)
+{
+	const NetworkGameList *cmp1 = *(const NetworkGameList**)a;
+	const NetworkGameList *cmp2 = *(const NetworkGameList**)b;
+	/* Reverse default as we are interested in compatible clients first */
+	int r = cmp2->info.compatible - cmp1->info.compatible;
+
+	if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password;
+	if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name);
+
+	return _internal_sort_order ? -r : r;
+}
+
+/** (Re)build the network game list as its amount has changed because
+ * an item has been added or deleted for example
+ * @param ngl list_d struct that contains all necessary information for sorting */
+static void BuildNetworkGameList(network_ql_d *nqld)
+{
+	NetworkGameList *ngl_temp;
+	uint n = 0;
+
+	if (!(nqld->l.flags & VL_REBUILD)) return;
+
+	/* Count the number of games in the list */
+	for (ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) n++;
+	if (n == 0) return;
+
+	/* Create temporary array of games to use for listing */
+	free(nqld->sort_list);
+	nqld->sort_list = malloc(n * sizeof(nqld->sort_list[0]));
+	if (nqld->sort_list == NULL) error("Could not allocate memory for the network-game-sorting-list");
+	nqld->l.list_length = n;
+
+	for (n = 0, ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) {
+		nqld->sort_list[n++] = ngl_temp;
+	}
+
+	/* Force resort */
+	nqld->l.flags &= ~VL_REBUILD;
+	nqld->l.flags |= VL_RESORT;
+}
+
+static void SortNetworkGameList(network_ql_d *nqld)
+{
+	static NGameNameSortFunction * const ngame_sorter[] = {
+		&NGameNameSorter,
+		&NGameClientSorter,
+		&NGameAllowedSorter
+	};
+
+	NetworkGameList *item;
+	uint i;
+
+	if (!(nqld->l.flags & VL_RESORT)) return;
+	if (nqld->l.list_length == 0) return;
+
+	_internal_sort_order = !!(nqld->l.flags & VL_DESC);
+	qsort(nqld->sort_list, nqld->l.list_length, sizeof(nqld->sort_list[0]), ngame_sorter[nqld->l.sort_type]);
+
+	/* After sorting ngl->sort_list contains the sorted items. Put these back
+	 * into the original list. Basically nothing has changed, we are only
+	 * shuffling the ->next pointers */
+	_network_game_list = nqld->sort_list[0];
+	for (item = _network_game_list, i = 1; i != nqld->l.list_length; i++) {
+		item->next = nqld->sort_list[i];
+		item = item->next;
+	}
+	item->next = NULL;
+
+	nqld->l.flags &= ~VL_RESORT;
+}
+
+/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */
+static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
+{
+	network_d *nd = &WP(w, network_ql_d).n;
+	list_d *ld = &WP(w, network_ql_d).l;
+
+	switch (e->event) {
+	case WE_CREATE: /* Focus input box */
+		nd->field = 3;
+		nd->server = NULL;
+
+		WP(w, network_ql_d).sort_list = NULL;
+		ld->flags = VL_REBUILD | (_ng_sorting.order << (VL_DESC - 1));
+		ld->sort_type = _ng_sorting.criteria;
+		break;
+
+	case WE_PAINT: {
+		const NetworkGameList *sel = nd->server;
+		const char *arrow = (ld->flags & VL_DESC) ? DOWNARROW : UPARROW;
+
+		if (ld->flags & VL_REBUILD) {
+			BuildNetworkGameList(&WP(w, network_ql_d));
+			SetVScrollCount(w, ld->list_length);
+		}
+		if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d));
+
+		SetWindowWidgetDisabledState(w, 17, sel == NULL);
+		/* Join Button disabling conditions */
+		SetWindowWidgetDisabledState(w, 16, sel == NULL || // no Selected Server
+				!sel->online || // Server offline
+				sel->info.clients_on >= sel->info.clients_max || // Server full
+				!sel->info.compatible); // Revision mismatch
+
+		SetWindowWidgetHiddenState(w, 18, sel == NULL ||
+				!sel->online ||
+				sel->info.grfconfig == NULL);
+
+		SetDParam(0, 0x00);
+		SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]);
+		DrawWindowWidgets(w);
+
+		DrawEditBox(w, &WP(w, network_ql_d).q, 3);
+
+		DrawString(9, 23, STR_NETWORK_CONNECTION, 2);
+		DrawString(210, 23, STR_NETWORK_PLAYER_NAME, 2);
+
+		/* Sort based on widgets: name, clients, compatibility */
+		switch (ld->sort_type) {
+			case 6 - 6: DoDrawString(arrow, w->widget[6].right - 10, 42, 0x10); break;
+			case 7 - 6: DoDrawString(arrow, w->widget[7].right - 10, 42, 0x10); break;
+			case 8 - 6: DoDrawString(arrow, w->widget[8].right - 10, 42, 0x10); break;
+		}
+
+		{ // draw list of games
+			uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
+			int32 n = 0;
+			int32 pos = w->vscroll.pos;
+			uint max_name_width = w->widget[6].right - w->widget[6].left - 5;
+			const NetworkGameList *cur_item = _network_game_list;
+
+			while (pos > 0 && cur_item != NULL) {
+				pos--;
+				cur_item = cur_item->next;
+			}
+
+			while (cur_item != NULL) {
+				// show highlighted item with a different colour
+				if (cur_item == sel) GfxFillRect(w->widget[6].left + 1, y - 2, w->widget[8].right - 1, y + 9, 10);
+
+				SetDParamStr(0, cur_item->info.server_name);
+				DrawStringTruncated(w->widget[6].left + 5, y, STR_02BD, 16, max_name_width);
+
+				SetDParam(0, cur_item->info.clients_on);
+				SetDParam(1, cur_item->info.clients_max);
+				SetDParam(2, cur_item->info.companies_on);
+				SetDParam(3, cur_item->info.companies_max);
+				DrawStringCentered(210, y, STR_NETWORK_GENERAL_ONLINE, 2);
+
+				// only draw icons if the server is online
+				if (cur_item->online) {
+					// draw a lock if the server is password protected.
+					if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1);
+
+					// draw red or green icon, depending on compatibility with server.
+					DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[8].left + 15, y);
+
+					// draw flag according to server language
+					DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y);
+				}
+
+				cur_item = cur_item->next;
+				y += NET_PRC__SIZE_OF_ROW;
+				if (++n == w->vscroll.cap) break; // max number of games in the window
+			}
+		}
+
+		/* Draw the right menu */
+		GfxFillRect(311, 43, 539, 92, 157);
+		if (sel == NULL) {
+			DrawStringCentered(425, 58, STR_NETWORK_GAME_INFO, 0);
+		} else if (!sel->online) {
+			SetDParamStr(0, sel->info.server_name);
+			DrawStringCentered(425, 68, STR_ORANGE, 0); // game name
+
+			DrawStringCentered(425, 132, STR_NETWORK_SERVER_OFFLINE, 0); // server offline
+		} else { // show game info
+			uint16 y = 100;
+			const uint16 x = w->widget[15].left + 5;
+
+			DrawStringCentered(425, 48, STR_NETWORK_GAME_INFO, 0);
+
+
+			SetDParamStr(0, sel->info.server_name);
+			DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 62, STR_ORANGE, 16); // game name
+
+			SetDParamStr(0, sel->info.map_name);
+			DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 74, STR_02BD, 16); // map name
+
+			SetDParam(0, sel->info.clients_on);
+			SetDParam(1, sel->info.clients_max);
+			SetDParam(2, sel->info.companies_on);
+			SetDParam(3, sel->info.companies_max);
+			DrawString(x, y, STR_NETWORK_CLIENTS, 2);
+			y += 10;
+
+			SetDParam(0, _language_dropdown[sel->info.server_lang]);
+			DrawString(x, y, STR_NETWORK_LANGUAGE, 2); // server language
+			y += 10;
+
+			SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set);
+			DrawString(x, y, STR_NETWORK_TILESET, 2); // tileset
+			y += 10;
+
+			SetDParam(0, sel->info.map_width);
+			SetDParam(1, sel->info.map_height);
+			DrawString(x, y, STR_NETWORK_MAP_SIZE, 2); // map size
+			y += 10;
+
+			SetDParamStr(0, sel->info.server_revision);
+			DrawString(x, y, STR_NETWORK_SERVER_VERSION, 2); // server version
+			y += 10;
+
+			SetDParamStr(0, sel->info.hostname);
+			SetDParam(1, sel->port);
+			DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, 2); // server address
+			y += 10;
+
+			SetDParam(0, sel->info.start_date);
+			DrawString(x, y, STR_NETWORK_START_DATE, 2); // start date
+			y += 10;
+
+			SetDParam(0, sel->info.game_date);
+			DrawString(x, y, STR_NETWORK_CURRENT_DATE, 2); // current date
+			y += 10;
+
+			y += 2;
+
+			if (!sel->info.compatible) {
+				DrawStringCentered(425, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch
+			} else if (sel->info.clients_on == sel->info.clients_max) {
+				// Show: server full, when clients_on == clients_max
+				DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full
+			} else if (sel->info.use_password) {
+				DrawStringCentered(425, y, STR_NETWORK_PASSWORD, 0); // password warning
+			}
+
+			y += 10;
+		}
+	}	break;
+
+	case WE_CLICK:
+		nd->field = e->we.click.widget;
+		switch (e->we.click.widget) {
+		case 0: case 14: /* Close 'X' | Cancel button */
+			DeleteWindowById(WC_NETWORK_WINDOW, 0);
+			break;
+		case 4: case 5:
+			ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5
+			break;
+		case 6: /* Sort by name */
+		case 7: /* Sort by connected clients */
+		case 8: /* Connectivity (green dot) */
+			if (ld->sort_type == e->we.click.widget - 6) ld->flags ^= VL_DESC;
+			ld->flags |= VL_RESORT;
+			ld->sort_type = e->we.click.widget - 6;
+
+			_ng_sorting.order = !!(ld->flags & VL_DESC);
+			_ng_sorting.criteria = ld->sort_type;
+			SetWindowDirty(w);
+			break;
+		case 9: { /* Matrix to show networkgames */
+			NetworkGameList *cur_item;
+			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
+
+			if (id_v >= w->vscroll.cap) return; // click out of bounds
+			id_v += w->vscroll.pos;
+
+			cur_item = _network_game_list;
+			for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next;
+
+			nd->server = cur_item;
+			SetWindowDirty(w);
+		} break;
+		case 11: /* Find server automatically */
+			switch (_network_lan_internet) {
+				case 0: NetworkUDPSearchGame(); break;
+				case 1: NetworkUDPQueryMasterServer(); break;
+			}
+			break;
+		case 12: { // Add a server
+				ShowQueryString(
+				BindCString(_network_default_ip),
+				STR_NETWORK_ENTER_IP,
+				31 | 0x1000,  // maximum number of characters OR
+				250, // characters up to this width pixels, whichever is satisfied first
+				w, CS_ALPHANUMERAL);
+		} break;
+		case 13: /* Start server */
+			ShowNetworkStartServerWindow();
+			break;
+		case 16: /* Join Game */
+			if (nd->server != NULL) {
+				snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip));
+				_network_last_port = nd->server->port;
+				ShowNetworkLobbyWindow(nd->server);
+			}
+			break;
+		case 17: // Refresh
+			if (nd->server != NULL)
+				NetworkQueryServer(nd->server->info.hostname, nd->server->port, true);
+			break;
+		case 18: // NewGRF Settings
+			if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig);
+			break;
+
+	}	break;
+
+	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+		switch (e->we.dropdown.button) {
+			case 5:
+				_network_lan_internet = e->we.dropdown.index;
+				break;
+		}
+
+		SetWindowDirty(w);
+		break;
+
+	case WE_MOUSELOOP:
+		if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3);
+		break;
+
+	case WE_MESSAGE:
+		if (e->we.message.msg != 0) nd->server = NULL;
+		ld->flags |= VL_REBUILD;
+		SetWindowDirty(w);
+		break;
+
+	case WE_KEYPRESS:
+		if (nd->field != 3) {
+			if (nd->server != NULL) {
+				if (e->we.keypress.keycode == WKC_DELETE) { /* Press 'delete' to remove servers */
+					NetworkGameListRemoveItem(nd->server);
+					NetworkRebuildHostList();
+					nd->server = NULL;
+				}
+			}
+			break;
+		}
+
+		if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed
+
+		// The name is only allowed when it starts with a letter!
+		if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ') {
+			ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name));
+		} else {
+			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
+		}
+
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		NetworkAddServer(e->we.edittext.str);
+		NetworkRebuildHostList();
+		break;
+
+	case WE_DESTROY: /* Nicely clean up the sort-list */
+		free(WP(w, network_ql_d).sort_list);
+		break;
+	}
+}
+
+static const Widget _network_game_window_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   549,     0,    13, STR_NETWORK_MULTIPLAYER,     STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   549,    14,   263, 0x0,                         STR_NULL},
+
+/* LEFT SIDE */
+{      WWT_PANEL,   RESIZE_NONE,   BGC,   310,   461,    22,    33, 0x0,                         STR_NETWORK_ENTER_NAME_TIP},
+
+{      WWT_INSET,   RESIZE_NONE,   BGC,    90,   181,    22,    33, STR_NETWORK_COMBO1,          STR_NETWORK_CONNECTION_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   170,   180,    23,    32, STR_0225,                    STR_NETWORK_CONNECTION_TIP},
+
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   170,    42,    53, STR_NETWORK_GAME_NAME,       STR_NETWORK_GAME_NAME_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   171,   250,    42,    53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   251,   290,    42,    53, STR_EMPTY,                   STR_NETWORK_INFO_ICONS_TIP},
+
+{     WWT_MATRIX,   RESIZE_NONE,   BGC,    10,   290,    54,   236, (13 << 8) + 1,               STR_NETWORK_CLICK_GAME_TO_SELECT},
+{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   291,   302,    42,   236, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    30,   130,   246,   257, STR_NETWORK_FIND_SERVER,     STR_NETWORK_FIND_SERVER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   180,   280,   246,   257, STR_NETWORK_ADD_SERVER,      STR_NETWORK_ADD_SERVER_TIP},
+
+/* RIGHT SIDE */
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   315,   415,   246,   257, STR_NETWORK_START_SERVER,    STR_NETWORK_START_SERVER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   246,   257, STR_012E_CANCEL,             STR_NULL},
+
+{      WWT_PANEL,   RESIZE_NONE,   BGC,   310,   540,    42,   236, 0x0,                         STR_NULL},
+
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   315,   415,   215,   226, STR_NETWORK_JOIN_GAME,       STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   215,   226, STR_NETWORK_REFRESH,         STR_NETWORK_REFRESH_TIP},
+
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   430,   535,   197,   208, STR_NEWGRF_SETTINGS_BUTTON,  STR_NULL},
+
+{   WIDGETS_END},
+};
+
+static const WindowDesc _network_game_window_desc = {
+	WDP_CENTER, WDP_CENTER, 550, 264,
+	WC_NETWORK_WINDOW,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_network_game_window_widgets,
+	NetworkGameWindowWndProc,
+};
+
+void ShowNetworkGameWindow(void)
+{
+	static bool first = true;
+	Window *w;
+	DeleteWindowById(WC_NETWORK_WINDOW, 0);
+
+	/* Only show once */
+	if (first) {
+		char* const *srv;
+
+		first = false;
+		// add all servers from the config file to our list
+		for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) {
+			NetworkAddServer(*srv);
+		}
+
+		_ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top)
+		_ng_sorting.order = 0;    // sort ascending by default
+	}
+
+	w = AllocateWindowDesc(&_network_game_window_desc);
+	if (w != NULL) {
+		querystr_d *querystr = &WP(w, network_ql_d).q;
+
+		ttd_strlcpy(_edit_str_buf, _network_player_name, lengthof(_edit_str_buf));
+		w->vscroll.cap = 13;
+
+		querystr->afilter = CS_ALPHANUMERAL;
+		InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120);
+
+		UpdateNetworkGameWindow(true);
+	}
+}
+
+enum {
+	NSSWND_START = 64,
+	NSSWND_ROWSIZE = 12
+};
+
+/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */
+static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
+{
+	network_d *nd = &WP(w, network_ql_d).n;
+
+	switch (e->event) {
+	case WE_CREATE: /* focus input box */
+		nd->field = 3;
+		_network_game_info.use_password = (_network_server_password[0] != '\0');
+		break;
+
+	case WE_PAINT: {
+		int y = NSSWND_START, pos;
+		const FiosItem *item;
+
+		SetDParam( 7, _connection_types_dropdown[_network_advertise]);
+		SetDParam( 9, _players_dropdown[_network_game_info.clients_max]);
+		SetDParam(11, _players_dropdown[_network_game_info.companies_max]);
+		SetDParam(13, _players_dropdown[_network_game_info.spectators_max]);
+		SetDParam(15, _language_dropdown[_network_game_info.server_lang]);
+		DrawWindowWidgets(w);
+
+		GfxFillRect(11, 63, 258, 215, 0xD7);
+		DrawEditBox(w, &WP(w, network_ql_d).q, 3);
+
+		DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2);
+
+		DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2);
+
+		DrawString(280,  63, STR_NETWORK_CONNECTION, 2);
+		DrawString(280,  95, STR_NETWORK_NUMBER_OF_CLIENTS, 2);
+		DrawString(280, 127, STR_NETWORK_NUMBER_OF_COMPANIES, 2);
+		DrawString(280, 159, STR_NETWORK_NUMBER_OF_SPECTATORS, 2);
+		DrawString(280, 191, STR_NETWORK_LANGUAGE_SPOKEN, 2);
+
+		if (_network_game_info.use_password) DoDrawString("*", 408, 23, 3);
+
+		// draw list of maps
+		pos = w->vscroll.pos;
+		while (pos < _fios_num + 1) {
+			item = _fios_list + pos - 1;
+			if (item == nd->map || (pos == 0 && nd->map == NULL))
+				GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour
+
+			if (pos == 0) {
+				DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, 9);
+			} else {
+				DoDrawString(item->title, 14, y, _fios_colors[item->type] );
+			}
+			pos++;
+			y += NSSWND_ROWSIZE;
+
+			if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break;
+		}
+	}	break;
+
+	case WE_CLICK:
+		nd->field = e->we.click.widget;
+		switch (e->we.click.widget) {
+		case 0: /* Close 'X' */
+		case 19: /* Cancel button */
+			ShowNetworkGameWindow();
+			break;
+
+		case 4: /* Set password button */
+			ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL);
+			break;
+
+		case 5: { /* Select map */
+			int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE;
+
+			y += w->vscroll.pos;
+			if (y >= w->vscroll.count) return;
+
+			nd->map = (y == 0) ? NULL : _fios_list + y - 1;
+			SetWindowDirty(w);
+			} break;
+		case 7: case 8: /* Connection type */
+			ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8
+			break;
+		case 9: case 10: /* Number of Players (hide 0 and 1 players) */
+			ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max, 10, 0, 3);
+			break;
+		case 11: case 12: /* Number of Companies (hide 0, 9 and 10 companies; max is 8) */
+			ShowDropDownMenu(w, _players_dropdown, _network_game_info.companies_max, 12, 0, 1537);
+			break;
+		case 13: case 14: /* Number of Spectators */
+			ShowDropDownMenu(w, _players_dropdown, _network_game_info.spectators_max, 14, 0, 0);
+			break;
+		case 15: case 16: /* Language */
+			ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 16, 0, 0);
+			break;
+		case 17: /* Start game */
+			_is_network_server = true;
+
+			if (nd->map == NULL) { // start random new game
+				ShowGenerateLandscape();
+			} else { // load a scenario
+				char *name = FiosBrowseTo(nd->map);
+				if (name != NULL) {
+					SetFiosType(nd->map->type);
+					ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name));
+					ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title));
+
+					DeleteWindow(w);
+					SwitchMode(SM_START_SCENARIO);
+				}
+			}
+			break;
+		case 18: /* Load game */
+			_is_network_server = true;
+			/* XXX - WC_NETWORK_WINDOW should stay, but if it stays, it gets
+			 * copied all the elements of 'load game' and upon closing that, it segfaults */
+			DeleteWindowById(WC_NETWORK_WINDOW, 0);
+			ShowSaveLoadDialog(SLD_LOAD_GAME);
+			break;
+		}
+		break;
+
+	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+		switch (e->we.dropdown.button) {
+			case  8: _network_advertise                = (e->we.dropdown.index != 0); break;
+			case 10: _network_game_info.clients_max    = e->we.dropdown.index;        break;
+			case 12: _network_game_info.companies_max  = e->we.dropdown.index;        break;
+			case 14: _network_game_info.spectators_max = e->we.dropdown.index;        break;
+			case 16: _network_game_info.server_lang    = e->we.dropdown.index;        break;
+		}
+
+		SetWindowDirty(w);
+		break;
+
+	case WE_MOUSELOOP:
+		if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3);
+		break;
+
+	case WE_KEYPRESS:
+		if (nd->field == 3) {
+			if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed
+
+			ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name));
+			UpdateTextBufferSize(&WP(w, network_ql_d).q.text);
+		}
+		break;
+
+	case WE_ON_EDIT_TEXT: {
+		ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password));
+		_network_game_info.use_password = (_network_server_password[0] != '\0');
+		SetWindowDirty(w);
+	} break;
+	}
+}
+
+static const Widget _network_start_server_window_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                      STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_START_GAME_WINDOW, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   243, 0x0,                           STR_NULL},
+
+{      WWT_PANEL,   RESIZE_NONE,   BGC,   100,   272,    22,    33, 0x0,                           STR_NETWORK_NEW_GAME_NAME_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   285,   405,    22,    33, STR_NETWORK_SET_PASSWORD,      STR_NETWORK_PASSWORD_TIP},
+
+{      WWT_INSET,   RESIZE_NONE,   BGC,    10,   271,    62,   216, 0x0,                           STR_NETWORK_SELECT_MAP_TIP},
+{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   259,   270,    63,   215, 0x0,                           STR_0190_SCROLL_BAR_SCROLLS_LIST},
+/* Combo boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */
+{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,    77,    88, STR_NETWORK_COMBO1,            STR_NETWORK_CONNECTION_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,    78,    87, STR_0225,                      STR_NETWORK_CONNECTION_TIP},
+{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   109,   120, STR_NETWORK_COMBO2,            STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   110,   119, STR_0225,                      STR_NETWORK_NUMBER_OF_CLIENTS_TIP},
+{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   141,   152, STR_NETWORK_COMBO3,            STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   142,   151, STR_0225,                      STR_NETWORK_NUMBER_OF_COMPANIES_TIP},
+{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   173,   184, STR_NETWORK_COMBO4,            STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   174,   183, STR_0225,                      STR_NETWORK_NUMBER_OF_SPECTATORS_TIP},
+{      WWT_INSET,   RESIZE_NONE,   BGC,   280,   410,   205,   216, STR_NETWORK_COMBO5,            STR_NETWORK_LANGUAGE_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,   BGC,   399,   409,   206,   215, STR_0225,                      STR_NETWORK_LANGUAGE_TIP},
+
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    40,   140,   224,   235, STR_NETWORK_START_GAME,        STR_NETWORK_START_GAME_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   150,   250,   224,   235, STR_NETWORK_LOAD_GAME,         STR_NETWORK_LOAD_GAME_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   260,   360,   224,   235, STR_012E_CANCEL,               STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _network_start_server_window_desc = {
+	WDP_CENTER, WDP_CENTER, 420, 244,
+	WC_NETWORK_WINDOW,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_network_start_server_window_widgets,
+	NetworkStartServerWindowWndProc,
+};
+
+static void ShowNetworkStartServerWindow(void)
+{
+	Window *w;
+	DeleteWindowById(WC_NETWORK_WINDOW, 0);
+
+	w = AllocateWindowDesc(&_network_start_server_window_desc);
+	ttd_strlcpy(_edit_str_buf, _network_server_name, lengthof(_edit_str_buf));
+
+	_saveload_mode = SLD_NEW_GAME;
+	BuildFileList();
+	w->vscroll.cap = 12;
+	w->vscroll.count = _fios_num+1;
+
+	WP(w, network_ql_d).q.afilter = CS_ALPHANUMERAL;
+	InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_buf, lengthof(_edit_str_buf), 160);
+}
+
+static byte NetworkLobbyFindCompanyIndex(byte pos)
+{
+	byte i;
+
+	/* Scroll through all _network_player_info and get the 'pos' item
+	    that is not empty */
+	for (i = 0; i < MAX_PLAYERS; i++) {
+		if (_network_player_info[i].company_name[0] != '\0') {
+			if (pos-- == 0) return i;
+		}
+	}
+
+	return 0;
+}
+
+/* uses network_d WP macro */
+static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
+{
+	network_d *nd = &WP(w, network_d);
+
+	switch (e->event) {
+	case WE_CREATE:
+		nd->company = (byte)-1;
+		break;
+
+	case WE_PAINT: {
+		const NetworkGameInfo *gi = &nd->server->info;
+		int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos;
+
+		SetWindowWidgetDisabledState(w, 7, nd->company == (byte)-1);
+		SetWindowWidgetDisabledState(w, 8, gi->companies_on >= gi->companies_max);
+		/* You can not join a server as spectator when it has no companies active..
+		 * it causes some nasty crashes */
+		SetWindowWidgetDisabledState(w, 9, gi->spectators_on >= gi->spectators_max ||
+				gi->companies_on == 0);
+
+		DrawWindowWidgets(w);
+
+		SetDParamStr(0, gi->server_name);
+		DrawString(10, 22, STR_NETWORK_PREPARE_TO_JOIN, 2);
+
+		/* Draw company list */
+		pos = w->vscroll.pos;
+		while (pos < gi->companies_on) {
+			byte company = NetworkLobbyFindCompanyIndex(pos);
+			bool income = false;
+			if (nd->company == company)
+				GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour
+
+			DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, 16, 135 - 13);
+			if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, 135, y);
+
+			/* If the company's income was positive puts a green dot else a red dot */
+			if (_network_player_info[company].income >= 0) income = true;
+			DrawSprite(SPR_BLOT | (income ? PALETTE_TO_GREEN : PALETTE_TO_RED), 145, y);
+
+			pos++;
+			y += NET_PRC__SIZE_OF_ROW;
+			if (pos >= w->vscroll.cap) break;
+		}
+
+		/* Draw info about selected company when it is selected in the left window */
+		GfxFillRect(174, 39, 403, 75, 157);
+		DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, 0);
+		if (nd->company != (byte)-1) {
+			const uint x = 183;
+			const uint trunc_width = w->widget[6].right - x;
+			y = 80;
+
+			SetDParam(0, nd->server->info.clients_on);
+			SetDParam(1, nd->server->info.clients_max);
+			SetDParam(2, nd->server->info.companies_on);
+			SetDParam(3, nd->server->info.companies_max);
+			DrawString(x, y, STR_NETWORK_CLIENTS, 2);
+			y += 10;
+
+			SetDParamStr(0, _network_player_info[nd->company].company_name);
+			DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, 2, trunc_width);
+			y += 10;
+
+			SetDParam(0, _network_player_info[nd->company].inaugurated_year);
+			DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, 2); // inauguration year
+			y += 10;
+
+			SetDParam64(0, _network_player_info[nd->company].company_value);
+			DrawString(x, y, STR_NETWORK_VALUE, 2); // company value
+			y += 10;
+
+			SetDParam64(0, _network_player_info[nd->company].money);
+			DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, 2); // current balance
+			y += 10;
+
+			SetDParam64(0, _network_player_info[nd->company].income);
+			DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, 2); // last year's income
+			y += 10;
+
+			SetDParam(0, _network_player_info[nd->company].performance);
+			DrawString(x, y, STR_NETWORK_PERFORMANCE, 2); // performance
+			y += 10;
+
+			SetDParam(0, _network_player_info[nd->company].num_vehicle[0]);
+			SetDParam(1, _network_player_info[nd->company].num_vehicle[1]);
+			SetDParam(2, _network_player_info[nd->company].num_vehicle[2]);
+			SetDParam(3, _network_player_info[nd->company].num_vehicle[3]);
+			SetDParam(4, _network_player_info[nd->company].num_vehicle[4]);
+			DrawString(x, y, STR_NETWORK_VEHICLES, 2); // vehicles
+			y += 10;
+
+			SetDParam(0, _network_player_info[nd->company].num_station[0]);
+			SetDParam(1, _network_player_info[nd->company].num_station[1]);
+			SetDParam(2, _network_player_info[nd->company].num_station[2]);
+			SetDParam(3, _network_player_info[nd->company].num_station[3]);
+			SetDParam(4, _network_player_info[nd->company].num_station[4]);
+			DrawString(x, y, STR_NETWORK_STATIONS, 2); // stations
+			y += 10;
+
+			SetDParamStr(0, _network_player_info[nd->company].players);
+			DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, 2, trunc_width); // players
+		}
+	}	break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 0: case 11: /* Close 'X' | Cancel button */
+			ShowNetworkGameWindow();
+			break;
+		case 4: { /* Company list */
+			uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW;
+
+			if (id_v >= w->vscroll.cap) return;
+
+			id_v += w->vscroll.pos;
+			nd->company = (id_v >= nd->server->info.companies_on) ? (byte)-1 : NetworkLobbyFindCompanyIndex(id_v);
+			SetWindowDirty(w);
+		}	break;
+		case 7: /* Join company */
+			if (nd->company != (byte)-1) {
+				_network_playas = nd->company;
+				NetworkClientConnectGame(_network_last_host, _network_last_port);
+			}
+			break;
+		case 8: /* New company */
+			_network_playas = PLAYER_NEW_COMPANY;
+			NetworkClientConnectGame(_network_last_host, _network_last_port);
+			break;
+		case 9: /* Spectate game */
+			_network_playas = PLAYER_SPECTATOR;
+			NetworkClientConnectGame(_network_last_host, _network_last_port);
+			break;
+		case 10: /* Refresh */
+			NetworkQueryServer(_network_last_host, _network_last_port, false); // company info
+			NetworkUDPQueryServer(_network_last_host, _network_last_port);     // general data
+			break;
+		}	break;
+
+	case WE_MESSAGE:
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const Widget _network_lobby_window_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,   BGC,     0,    10,     0,    13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION,   RESIZE_NONE,   BGC,    11,   419,     0,    13, STR_NETWORK_GAME_LOBBY,    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,   BGC,     0,   419,    14,   234, 0x0,                       STR_NULL},
+
+// company list
+{      WWT_PANEL,   RESIZE_NONE,   BTC,    10,   155,    38,    49, 0x0,                       STR_NULL},
+{     WWT_MATRIX,   RESIZE_NONE,   BGC,    10,   155,    50,   190, (10 << 8) + 1,             STR_NETWORK_COMPANY_LIST_TIP},
+{  WWT_SCROLLBAR,   RESIZE_NONE,   BGC,   156,   167,    38,   190, STR_NULL,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
+
+// company/player info
+{      WWT_PANEL,   RESIZE_NONE,   BGC,   173,   404,    38,   190, 0x0,                       STR_NULL},
+
+// buttons
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   151,   200,   211, STR_NETWORK_JOIN_COMPANY,  STR_NETWORK_JOIN_COMPANY_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    10,   151,   215,   226, STR_NETWORK_NEW_COMPANY,   STR_NETWORK_NEW_COMPANY_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   158,   268,   200,   211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   158,   268,   215,   226, STR_NETWORK_REFRESH,       STR_NETWORK_REFRESH_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,   278,   388,   200,   211, STR_012E_CANCEL,           STR_NULL},
+
+{   WIDGETS_END},
+};
+
+static const WindowDesc _network_lobby_window_desc = {
+	WDP_CENTER, WDP_CENTER, 420, 235,
+	WC_NETWORK_WINDOW,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_network_lobby_window_widgets,
+	NetworkLobbyWindowWndProc,
+};
+
+/* Show the networklobbywindow with the selected server
+ * @param ngl Selected game pointer which is passed to the new window */
+static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
+{
+	Window *w;
+	DeleteWindowById(WC_NETWORK_WINDOW, 0);
+
+	NetworkQueryServer(_network_last_host, _network_last_port, false); // company info
+	NetworkUDPQueryServer(_network_last_host, _network_last_port);     // general data
+
+	w = AllocateWindowDesc(&_network_lobby_window_desc);
+	if (w != NULL) {
+		WP(w, network_ql_d).n.server = ngl;
+		strcpy(_edit_str_buf, "");
+		w->vscroll.cap = 10;
+	}
+}
+
+// The window below gives information about the connected clients
+//  and also makes able to give money to them, kick them (if server)
+//  and stuff like that.
+
+extern void DrawPlayerIcon(PlayerID pid, int x, int y);
+
+// Every action must be of this form
+typedef void ClientList_Action_Proc(byte client_no);
+
+// Max 10 actions per client
+#define MAX_CLIENTLIST_ACTION 10
+
+// Some standard bullshit.. defines variables ;)
+static void ClientListWndProc(Window *w, WindowEvent *e);
+static void ClientListPopupWndProc(Window *w, WindowEvent *e);
+static byte _selected_clientlist_item = 255;
+static byte _selected_clientlist_y = 0;
+static char _clientlist_action[MAX_CLIENTLIST_ACTION][50];
+static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION];
+
+enum {
+	CLNWND_OFFSET = 16,
+	CLNWND_ROWSIZE = 10
+};
+
+static const Widget _client_list_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_NETWORK_CLIENT_LIST,  STR_018C_WINDOW_TITLE_DRAG_THIS},
+
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,    14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const Widget _client_list_popup_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   99,     0,     0,     0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static WindowDesc _client_list_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 1,
+	WC_CLIENT_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_client_list_widgets,
+	ClientListWndProc
+};
+
+// Finds the Xth client-info that is active
+static const NetworkClientInfo *NetworkFindClientInfo(byte client_no)
+{
+	const NetworkClientInfo *ci;
+
+	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+		if (client_no == 0) return ci;
+		client_no--;
+	}
+
+	return NULL;
+}
+
+// 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);
+}
+
+static void ClientList_Ban(byte client_no)
+{
+	uint i;
+	uint32 ip = NetworkFindClientInfo(client_no)->client_ip;
+
+	for (i = 0; i < lengthof(_network_ban_list); i++) {
+		if (_network_ban_list[i] == NULL) {
+			_network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip));
+			break;
+		}
+	}
+
+	if (client_no < MAX_PLAYERS)
+		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
+}
+
+static void ClientList_GiveMoney(byte client_no)
+{
+	if (NetworkFindClientInfo(client_no) != NULL)
+		ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
+}
+
+static void ClientList_SpeakToClient(byte client_no)
+{
+	if (NetworkFindClientInfo(client_no) != NULL)
+		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index);
+}
+
+static void ClientList_SpeakToCompany(byte client_no)
+{
+	if (NetworkFindClientInfo(client_no) != NULL)
+		ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
+}
+
+static void ClientList_SpeakToAll(byte client_no)
+{
+	ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
+}
+
+static void ClientList_None(byte client_no)
+{
+	// No action ;)
+}
+
+
+
+// Help, a action is clicked! What do we do?
+static void HandleClientListPopupClick(byte index, byte clientno) {
+	// A click on the Popup of the ClientList.. handle the command
+	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
+		_clientlist_proc[index](clientno);
+	}
+}
+
+// Finds the amount of clients and set the height correct
+static bool CheckClientListHeight(Window *w)
+{
+	int num = 0;
+	const NetworkClientInfo *ci;
+
+	// Should be replaced with a loop through all clients
+	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+		num++;
+	}
+
+	num *= CLNWND_ROWSIZE;
+
+	// If height is changed
+	if (w->height != CLNWND_OFFSET + num + 1) {
+		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
+		SetWindowDirty(w);
+		w->widget[2].bottom = w->widget[2].top + num + 2;
+		w->height = CLNWND_OFFSET + num + 1;
+		SetWindowDirty(w);
+		return false;
+	}
+	return true;
+}
+
+// Finds the amount of actions in the popup and set the height correct
+static uint ClientListPopupHeigth(void) {
+	int i, num = 0;
+
+	// Find the amount of actions
+	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
+		if (_clientlist_action[i][0] == '\0') continue;
+		if (_clientlist_proc[i] == NULL) continue;
+		num++;
+	}
+
+	num *= CLNWND_ROWSIZE;
+
+	return num + 1;
+}
+
+// Show the popup (action list)
+static Window *PopupClientList(Window *w, int client_no, int x, int y)
+{
+	int i, h;
+	const NetworkClientInfo *ci;
+	DeleteWindowById(WC_TOOLBAR_MENU, 0);
+
+	// Clean the current actions
+	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
+		_clientlist_action[i][0] = '\0';
+		_clientlist_proc[i] = NULL;
+	}
+
+	// Fill the actions this client has
+	// Watch is, max 50 chars long!
+
+	ci = NetworkFindClientInfo(client_no);
+	if (ci == NULL) return NULL;
+
+	i = 0;
+	if (_network_own_client_index != ci->client_index) {
+		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i]));
+		_clientlist_proc[i++] = &ClientList_SpeakToClient;
+	}
+
+	if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
+		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i]));
+		_clientlist_proc[i++] = &ClientList_SpeakToCompany;
+	}
+	GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i]));
+	_clientlist_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 */
+		if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) {
+			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
+			_clientlist_proc[i++] = &ClientList_GiveMoney;
+		}
+	}
+
+	// A server can kick clients (but not himself)
+	if (_network_server && _network_own_client_index != ci->client_index) {
+		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
+		_clientlist_proc[i++] = &ClientList_Kick;
+
+		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
+		_clientlist_proc[i++] = &ClientList_Ban;
+	}
+
+	if (i == 0) {
+		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
+		_clientlist_proc[i++] = &ClientList_None;
+	}
+
+	/* Calculate the height */
+	h = ClientListPopupHeigth();
+
+	// Allocate the popup
+	w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
+	w->widget[0].bottom = w->widget[0].top + h;
+	w->widget[0].right = w->widget[0].left + 150;
+
+	w->flags4 &= ~WF_WHITE_BORDER_MASK;
+	WP(w,menu_d).item_count = 0;
+	// Save our client
+	WP(w,menu_d).main_button = client_no;
+	WP(w,menu_d).sel_index = 0;
+	// We are a popup
+	_popup_menu_active = true;
+
+	return w;
+}
+
+/** Main handle for the client popup list
+ * uses menu_d WP macro */
+static void ClientListPopupWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int i, y, sel;
+		byte colour;
+		DrawWindowWidgets(w);
+
+		// Draw the actions
+		sel = WP(w,menu_d).sel_index;
+		y = 1;
+		for (i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
+			if (_clientlist_action[i][0] == '\0') continue;
+			if (_clientlist_proc[i] == NULL) continue;
+
+			if (sel-- == 0) { // Selected item, highlight it
+				GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
+				colour = 0xC;
+			} else {
+				colour = 0x10;
+			}
+
+			DoDrawString(_clientlist_action[i], 4, y, colour);
+		}
+	}	break;
+
+	case WE_POPUPMENU_SELECT: {
+		// We selected an action
+		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
+
+		if (index >= 0 && e->we.popupmenu.pt.y >= w->top)
+			HandleClientListPopupClick(index, WP(w,menu_d).main_button);
+
+		DeleteWindowById(WC_TOOLBAR_MENU, 0);
+	}	break;
+
+	case WE_POPUPMENU_OVER: {
+		// Our mouse hoovers over an action? Select it!
+		int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE;
+
+		if (index == -1 || index == WP(w,menu_d).sel_index) return;
+
+		WP(w,menu_d).sel_index = index;
+		SetWindowDirty(w);
+	} break;
+
+	}
+}
+
+// Main handle for clientlist
+static void ClientListWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		NetworkClientInfo *ci;
+		int y, i = 0;
+		byte colour;
+
+		// Check if we need to reset the height
+		if (!CheckClientListHeight(w)) break;
+
+		DrawWindowWidgets(w);
+
+		y = CLNWND_OFFSET;
+
+		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+			if (_selected_clientlist_item == i++) { // Selected item, highlight it
+				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
+				colour = 0xC;
+			} else {
+				colour = 0x10;
+			}
+
+			if (ci->client_index == NETWORK_SERVER_INDEX) {
+				DrawString(4, y, STR_NETWORK_SERVER, colour);
+			} else {
+				DrawString(4, y, STR_NETWORK_CLIENT, colour);
+			}
+
+			// Filter out spectators
+			if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
+
+			DoDrawString(ci->client_name, 81, y, colour);
+
+			y += CLNWND_ROWSIZE;
+		}
+	}	break;
+
+	case WE_CLICK:
+		// Show the popup with option
+		if (_selected_clientlist_item != 255) {
+			PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
+		}
+
+		break;
+
+	case WE_MOUSEOVER:
+		// -1 means we left the current window
+		if (e->we.mouseover.pt.y == -1) {
+			_selected_clientlist_y = 0;
+			_selected_clientlist_item = 255;
+			SetWindowDirty(w);
+			break;
+		}
+		// It did not change.. no update!
+		if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
+
+		// Find the new selected item (if any)
+		_selected_clientlist_y = e->we.mouseover.pt.y;
+		if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
+			_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+		} else {
+			_selected_clientlist_item = 255;
+		}
+
+		// Repaint
+		SetWindowDirty(w);
+		break;
+
+	case WE_DESTROY: case WE_CREATE:
+		// When created or destroyed, data is reset
+		_selected_clientlist_item = 255;
+		_selected_clientlist_y = 0;
+		break;
+	}
+}
+
+void ShowClientList(void)
+{
+	AllocateWindowDescFront(&_client_list_desc, 0);
+}
+
+
+static NetworkPasswordType pw_type;
+
+
+void ShowNetworkNeedPassword(NetworkPasswordType npt)
+{
+	StringID caption;
+
+	pw_type = npt;
+	switch (npt) {
+		default: NOT_REACHED();
+		case NETWORK_GAME_PASSWORD:    caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break;
+		case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break;
+	}
+	ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
+}
+
+
+static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		uint8 progress; // used for progress bar
+		DrawWindowWidgets(w);
+
+		DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, 14);
+		switch (_network_join_status) {
+			case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
+			case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
+				progress = 10; // first two stages 10%
+				break;
+			case NETWORK_JOIN_STATUS_WAITING:
+				SetDParam(0, _network_join_waiting);
+				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, 14);
+				progress = 15; // third stage is 15%
+				break;
+			case NETWORK_JOIN_STATUS_DOWNLOADING:
+				SetDParam(0, _network_join_kbytes);
+				SetDParam(1, _network_join_kbytes_total);
+				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, 14);
+				/* Fallthrough */
+			default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
+				progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
+		}
+
+		/* Draw nice progress bar :) */
+		DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, 0);
+	}	break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 2: /* Disconnect button */
+				NetworkDisconnect();
+				DeleteWindow(w);
+				SwitchMode(SM_MENU);
+				ShowNetworkGameWindow();
+				break;
+		}
+		break;
+
+		/* If the server asks for a password, we need to fill it in */
+		case WE_ON_EDIT_TEXT_CANCEL:
+			NetworkDisconnect();
+			ShowNetworkGameWindow();
+			break;
+
+		case WE_ON_EDIT_TEXT:
+			SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
+			break;
+	}
+}
+
+static const Widget _network_join_status_window_widget[] = {
+{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,    84, 0x0,                    STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,   BTC,    75,   175,    69,    80, STR_NETWORK_DISCONNECT, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _network_join_status_window_desc = {
+	WDP_CENTER, WDP_CENTER, 250, 85,
+	WC_NETWORK_STATUS_WINDOW, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
+	_network_join_status_window_widget,
+	NetworkJoinStatusWindowWndProc,
+};
+
+void ShowJoinStatusWindow(void)
+{
+	Window *w;
+	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+	w = AllocateWindowDesc(&_network_join_status_window_desc);
+	/* Parent the status window to the lobby */
+	if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
+}
+
+static void SendChat(const char *buf, DestType type, byte dest)
+{
+	if (buf[0] == '\0') return;
+	if (!_network_server) {
+		SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT + type, type, dest, buf);
+	} else {
+		NetworkServer_HandleChat(NETWORK_ACTION_CHAT + type, type, dest, buf, NETWORK_SERVER_INDEX);
+	}
+}
+
+/**
+ * Find the next item of the list of things that can be auto-completed.
+ * @param item The current indexed item to return. This function can, and most
+ *     likely will, alter item, to skip empty items in the arrays.
+ * @return Returns the char that matched to the index.
+ */
+static const char *ChatTabCompletionNextItem(uint *item)
+{
+	static char chat_tab_temp_buffer[64];
+
+	/* First, try clients */
+	if (*item < MAX_CLIENT_INFO) {
+		/* Skip inactive clients */
+		while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++;
+		if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name;
+	}
+
+	/* Then, try townnames */
+	/* Not that the following assumes all town indices are adjacent, ie no
+	 * towns have been deleted. */
+	if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) {
+		const Town *t;
+
+		FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
+			/* Get the town-name via the string-system */
+			SetDParam(0, t->townnameparts);
+			GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer));
+			return &chat_tab_temp_buffer[0];
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Find what text to complete. It scans for a space from the left and marks
+ *  the word right from that as to complete. It also writes a \0 at the
+ *  position of the space (if any). If nothing found, buf is returned.
+ */
+static char *ChatTabCompletionFindText(char *buf)
+{
+	char *p = strrchr(buf, ' ');
+	if (p == NULL) return buf;
+
+	*p = '\0';
+	return p + 1;
+}
+
+/**
+ * See if we can auto-complete the current text of the user.
+ */
+static void ChatTabCompletion(Window *w)
+{
+	static char _chat_tab_completion_buf[lengthof(_edit_str_buf)];
+	Textbuf *tb = &WP(w, querystr_d).text;
+	uint len, tb_len;
+	uint item;
+	char *tb_buf, *pre_buf;
+	const char *cur_name;
+	bool second_scan = false;
+
+	item = 0;
+
+	/* Copy the buffer so we can modify it without damaging the real data */
+	pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf);
+
+	tb_buf  = ChatTabCompletionFindText(pre_buf);
+	tb_len  = strlen(tb_buf);
+
+	while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) {
+		item++;
+
+		if (_chat_tab_completion_active) {
+			/* We are pressing TAB again on the same name, is there an other name
+			 *  that starts with this? */
+			if (!second_scan) {
+				uint offset;
+				uint length;
+
+				/* If we are completing at the begin of the line, skip the ': ' we added */
+				if (tb_buf == pre_buf) {
+					offset = 0;
+					length = tb->length - 2;
+				} else {
+					/* Else, find the place we are completing at */
+					offset = strlen(pre_buf) + 1;
+					length = tb->length - offset;
+				}
+
+				/* Compare if we have a match */
+				if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
+
+				continue;
+			}
+
+			/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
+		}
+
+		len = strlen(cur_name);
+		if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
+			/* Save the data it was before completion */
+			if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf);
+			_chat_tab_completion_active = true;
+
+			/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
+			if (pre_buf == tb_buf) {
+				snprintf(tb->buf, lengthof(_edit_str_buf), "%s: ", cur_name);
+			} else {
+				snprintf(tb->buf, lengthof(_edit_str_buf), "%s %s", pre_buf, cur_name);
+			}
+
+			/* Update the textbuffer */
+			UpdateTextBufferSize(&WP(w, querystr_d).text);
+
+			SetWindowDirty(w);
+			free(pre_buf);
+			return;
+		}
+	}
+
+	if (second_scan) {
+		/* We walked all posibilities, and the user presses tab again.. revert to original text */
+		strcpy(tb->buf, _chat_tab_completion_buf);
+		_chat_tab_completion_active = false;
+
+		/* Update the textbuffer */
+		UpdateTextBufferSize(&WP(w, querystr_d).text);
+
+		SetWindowDirty(w);
+	}
+	free(pre_buf);
+}
+
+/* uses querystr_d WP macro
+ * uses querystr_d->caption to store
+ * - type of chat message (Private/Team/All) in bytes 0-7
+ * - destination of chat message in the case of Team/Private in bytes 8-15 */
+static void ChatWindowWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE:
+		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0);
+		SETBIT(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys
+		break;
+
+	case WE_PAINT: {
+		static const StringID chat_captions[] = {
+			STR_NETWORK_CHAT_ALL_CAPTION,
+			STR_NETWORK_CHAT_COMPANY_CAPTION,
+			STR_NETWORK_CHAT_CLIENT_CAPTION
+		};
+		StringID msg;
+
+		DrawWindowWidgets(w);
+
+		assert(GB(WP(w, querystr_d).caption, 0, 8) < lengthof(chat_captions));
+		msg = chat_captions[GB(WP(w, querystr_d).caption, 0, 8)];
+		DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, msg, 16);
+		DrawEditBox(w, &WP(w, querystr_d), 2);
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 3: { /* Send */
+				DestType type = GB(WP(w, querystr_d).caption, 0, 8);
+				byte dest = GB(WP(w, querystr_d).caption, 8, 8);
+				SendChat(WP(w, querystr_d).text.buf, type, dest);
+			} /* FALLTHROUGH */
+			case 0: /* Cancel */ DeleteWindow(w); break;
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		HandleEditBox(w, &WP(w, querystr_d), 2);
+		break;
+
+	case WE_KEYPRESS:
+		if (e->we.keypress.keycode == WKC_TAB) {
+			ChatTabCompletion(w);
+		} else {
+			_chat_tab_completion_active = false;
+			switch (HandleEditBoxKey(w, &WP(w, querystr_d), 2, e)) {
+				case 1: { /* Return */
+				DestType type = GB(WP(w, querystr_d).caption, 0, 8);
+				byte dest = GB(WP(w, querystr_d).caption, 8, 8);
+				SendChat(WP(w, querystr_d).text.buf, type, dest);
+			} /* FALLTHROUGH */
+				case 2: /* Escape */ DeleteWindow(w); break;
+			}
+		}
+		break;
+
+	case WE_DESTROY:
+		SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0);
+		CLRBIT(_no_scroll, SCROLL_CHAT);
+		break;
+	}
+}
+
+static const Widget _chat_window_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,  0, 13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{      WWT_PANEL, RESIZE_NONE, 14,  11, 639,  0, 13, 0x0,              STR_NULL}, // background
+{      WWT_PANEL, RESIZE_NONE, 14,  75, 577,  1, 12, 0x0,              STR_NULL}, // text box
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 578, 639,  1, 12, STR_NETWORK_SEND, STR_NULL}, // send button
+{   WIDGETS_END},
+};
+
+static const WindowDesc _chat_window_desc = {
+	WDP_CENTER, -26, 640, 14, // x, y, width, height
+	WC_SEND_NETWORK_MSG,0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
+	_chat_window_widgets,
+	ChatWindowWndProc
+};
+
+void ShowNetworkChatQueryWindow(DestType type, byte dest)
+{
+	Window *w;
+
+	DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
+
+	_edit_str_buf[0] = '\0';
+	_chat_tab_completion_active = false;
+
+	w = AllocateWindowDesc(&_chat_window_desc);
+
+	LowerWindowWidget(w, 2);
+	WP(w, querystr_d).caption = GB(type, 0, 8) | (dest << 8); // Misuse of caption
+	WP(w, querystr_d).afilter = CS_ALPHANUMERAL;
+	InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 0);
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_server.c
+++ /dev/null
@@ -1,1528 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../stdafx.h"
-#include "../openttd.h" // XXX StringID
-#include "../debug.h"
-#include "../string.h"
-#include "../strings.h"
-#include "network_data.h"
-#include "core/tcp.h"
-#include "../train.h"
-#include "../date.h"
-#include "table/strings.h"
-#include "../functions.h"
-#include "network_server.h"
-#include "network_udp.h"
-#include "../console.h"
-#include "../command.h"
-#include "../saveload.h"
-#include "../vehicle.h"
-#include "../station.h"
-#include "../variables.h"
-#include "../genworld.h"
-
-// This file handles all the server-commands
-
-static void NetworkHandleCommandQueue(NetworkClientState* cs);
-
-// **********
-// Sending functions
-//   DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs
-// **********
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci)
-{
-	//
-	// Packet: SERVER_CLIENT_INFO
-	// Function: Sends info about a client
-	// Data:
-	//    uint16:  The index of the client (always unique on a server. 1 = server)
-	//    uint8:  As which player the client is playing
-	//    String: The name of the client
-	//    String: The unique id of the client
-	//
-
-	if (ci->client_index != NETWORK_EMPTY_INDEX) {
-		Packet *p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO);
-		NetworkSend_uint16(p, ci->client_index);
-		NetworkSend_uint8 (p, ci->client_playas);
-		NetworkSend_string(p, ci->client_name);
-		NetworkSend_string(p, ci->unique_id);
-
-		NetworkSend_Packet(p, cs);
-	}
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)
-{
-//
-	// Packet: SERVER_COMPANY_INFO
-	// Function: Sends info about the companies
-	// Data:
-	//
-
-	int i;
-
-	Player *player;
-	Packet *p;
-
-	byte active = ActivePlayerCount();
-
-	if (active == 0) {
-		p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
-
-		NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
-		NetworkSend_uint8 (p, active);
-
-		NetworkSend_Packet(p, cs);
-		return;
-	}
-
-	NetworkPopulateCompanyInfo();
-
-	FOR_ALL_PLAYERS(player) {
-		if (!player->is_active) continue;
-
-		p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
-
-		NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
-		NetworkSend_uint8 (p, active);
-		NetworkSend_uint8 (p, player->index);
-
-		NetworkSend_string(p, _network_player_info[player->index].company_name);
-		NetworkSend_uint32(p, _network_player_info[player->index].inaugurated_year);
-		NetworkSend_uint64(p, _network_player_info[player->index].company_value);
-		NetworkSend_uint64(p, _network_player_info[player->index].money);
-		NetworkSend_uint64(p, _network_player_info[player->index].income);
-		NetworkSend_uint16(p, _network_player_info[player->index].performance);
-
-		/* Send 1 if there is a passord for the company else send 0 */
-		if (_network_player_info[player->index].password[0] != '\0') {
-			NetworkSend_uint8(p, 1);
-		} else {
-			NetworkSend_uint8(p, 0);
-		}
-
-		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) {
-			NetworkSend_uint16(p, _network_player_info[player->index].num_vehicle[i]);
-		}
-
-		for (i = 0; i < NETWORK_STATION_TYPES; i++) {
-			NetworkSend_uint16(p, _network_player_info[player->index].num_station[i]);
-		}
-
-		if (_network_player_info[player->index].players[0] == '\0') {
-			NetworkSend_string(p, "<none>");
-		} else {
-			NetworkSend_string(p, _network_player_info[player->index].players);
-		}
-
-		NetworkSend_Packet(p, cs);
-	}
-
-	p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
-
-	NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
-	NetworkSend_uint8 (p, 0);
-
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error)
-{
-	//
-	// Packet: SERVER_ERROR
-	// Function: The client made an error
-	// Data:
-	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
-	//
-
-	char str[100];
-	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR);
-
-	NetworkSend_uint8(p, error);
-	NetworkSend_Packet(p, cs);
-
-	GetNetworkErrorMsg(str, error, lastof(str));
-
-	// Only send when the current client was in game
-	if (cs->status > STATUS_AUTH) {
-		NetworkClientState *new_cs;
-		char client_name[NETWORK_CLIENT_NAME_LENGTH];
-
-		NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-		DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
-
-		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
-
-		FOR_ALL_CLIENTS(new_cs) {
-			if (new_cs->status > STATUS_AUTH && new_cs != cs) {
-				// Some errors we filter to a more general error. Clients don't have to know the real
-				//  reason a joining failed.
-				if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION)
-					error = NETWORK_ERROR_ILLEGAL_PACKET;
-
-				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, error);
-			}
-		}
-	} else {
-		DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->index, str);
-	}
-
-	cs->has_quit = true;
-
-	// Make sure the data get's there before we close the connection
-	NetworkSend_Packets(cs);
-
-	// The client made a mistake, so drop his connection now!
-	NetworkCloseClient(cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type)
-{
-	//
-	// Packet: SERVER_NEED_PASSWORD
-	// Function: Indication to the client that the server needs a password
-	// Data:
-	//    uint8:  Type of password
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD);
-	NetworkSend_uint8(p, type);
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME)
-{
-	//
-	// Packet: SERVER_WELCOME
-	// Function: The client is joined and ready to receive his map
-	// Data:
-	//    uint16:  Own ClientID
-	//
-
-	Packet *p;
-	const NetworkClientState *new_cs;
-
-	// Invalid packet when status is AUTH or higher
-	if (cs->status >= STATUS_AUTH) return;
-
-	cs->status = STATUS_AUTH;
-	_network_game_info.clients_on++;
-
-	p = NetworkSend_Init(PACKET_SERVER_WELCOME);
-	NetworkSend_uint16(p, cs->index);
-	NetworkSend_Packet(p, cs);
-
-		// Transmit info about all the active clients
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs != cs && new_cs->status > STATUS_AUTH)
-			SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, DEREF_CLIENT_INFO(new_cs));
-	}
-	// Also send the info of the server
-	SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX));
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WAIT)
-{
-	//
-	// Packet: PACKET_SERVER_WAIT
-	// Function: The client can not receive the map at the moment because
-	//             someone else is already receiving the map
-	// Data:
-	//    uint8:  Clients awaiting map
-	//
-	int waiting = 0;
-	NetworkClientState *new_cs;
-	Packet *p;
-
-	// Count how many players are waiting in the queue
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs->status == STATUS_MAP_WAIT) waiting++;
-	}
-
-	p = NetworkSend_Init(PACKET_SERVER_WAIT);
-	NetworkSend_uint8(p, waiting);
-	NetworkSend_Packet(p, cs);
-}
-
-// This sends the map to the client
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
-{
-	//
-	// Packet: SERVER_MAP
-	// Function: Sends the map to the client, or a part of it (it is splitted in
-	//   a lot of multiple packets)
-	// Data:
-	//    uint8:  packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END)
-	//  if MAP_PACKET_START:
-	//    uint32: The current FrameCounter
-	//  if MAP_PACKET_NORMAL:
-	//    piece of the map (till max-size of packet)
-	//  if MAP_PACKET_END:
-	//    uint32: seed0 of player
-	//    uint32: seed1 of player
-	//      last 2 are repeated MAX_PLAYERS time
-	//
-
-	static FILE *file_pointer;
-	static uint sent_packets; // How many packets we did send succecfully last time
-
-	if (cs->status < STATUS_AUTH) {
-		// Illegal call, return error and ignore the packet
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
-		return;
-	}
-
-	if (cs->status == STATUS_AUTH) {
-		char filename[256];
-		Packet *p;
-
-		// Make a dump of the current game
-		snprintf(filename, lengthof(filename), "%s%snetwork_server.tmp",  _paths.autosave_dir, PATHSEP);
-		if (SaveOrLoad(filename, SL_SAVE) != SL_OK) error("network savedump failed");
-
-		file_pointer = fopen(filename, "rb");
-		fseek(file_pointer, 0, SEEK_END);
-
-		// Now send the _frame_counter and how many packets are coming
-		p = NetworkSend_Init(PACKET_SERVER_MAP);
-		NetworkSend_uint8(p, MAP_PACKET_START);
-		NetworkSend_uint32(p, _frame_counter);
-		NetworkSend_uint32(p, ftell(file_pointer));
-		NetworkSend_Packet(p, cs);
-
-		fseek(file_pointer, 0, SEEK_SET);
-
-		sent_packets = 4; // We start with trying 4 packets
-
-		cs->status = STATUS_MAP;
-		/* Mark the start of download */
-		cs->last_frame = _frame_counter;
-		cs->last_frame_server = _frame_counter;
-	}
-
-	if (cs->status == STATUS_MAP) {
-		uint i;
-		int res;
-		for (i = 0; i < sent_packets; i++) {
-			Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
-			NetworkSend_uint8(p, MAP_PACKET_NORMAL);
-			res = (int)fread(p->buffer + p->size, 1, SEND_MTU - p->size, file_pointer);
-
-			if (ferror(file_pointer)) error("Error reading temporary network savegame!");
-
-			p->size += res;
-			NetworkSend_Packet(p, cs);
-			if (feof(file_pointer)) {
-				// Done reading!
-				Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
-				NetworkSend_uint8(p, MAP_PACKET_END);
-				NetworkSend_Packet(p, cs);
-
-				// Set the status to DONE_MAP, no we will wait for the client
-				//  to send it is ready (maybe that happens like never ;))
-				cs->status = STATUS_DONE_MAP;
-				fclose(file_pointer);
-
-				{
-					NetworkClientState *new_cs;
-					bool new_map_client = false;
-					// Check if there is a client waiting for receiving the map
-					//  and start sending him the map
-					FOR_ALL_CLIENTS(new_cs) {
-						if (new_cs->status == STATUS_MAP_WAIT) {
-							// Check if we already have a new client to send the map to
-							if (!new_map_client) {
-								// If not, this client will get the map
-								new_cs->status = STATUS_AUTH;
-								new_map_client = true;
-								SEND_COMMAND(PACKET_SERVER_MAP)(new_cs);
-							} else {
-								// Else, send the other clients how many clients are in front of them
-								SEND_COMMAND(PACKET_SERVER_WAIT)(new_cs);
-							}
-						}
-					}
-				}
-
-				// There is no more data, so break the for
-				break;
-			}
-		}
-
-		// Send all packets (forced) and check if we have send it all
-		NetworkSend_Packets(cs);
-		if (cs->packet_queue == NULL) {
-			// All are sent, increase the sent_packets
-			sent_packets *= 2;
-		} else {
-			// Not everything is sent, decrease the sent_packets
-			if (sent_packets > 1) sent_packets /= 2;
-		}
-	}
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index)
-{
-	//
-	// Packet: SERVER_JOIN
-	// Function: A client is joined (all active clients receive this after a
-	//     PACKET_CLIENT_MAP_OK) Mostly what directly follows is a
-	//     PACKET_SERVER_CLIENT_INFO
-	// Data:
-	//    uint16:  Client-Index
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN);
-
-	NetworkSend_uint16(p, client_index);
-
-	NetworkSend_Packet(p, cs);
-}
-
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME)
-{
-	//
-	// Packet: SERVER_FRAME
-	// Function: Sends the current frame-counter to the client
-	// Data:
-	//    uint32: Frame Counter
-	//    uint32: Frame Counter Max (how far may the client walk before the server?)
-	//    [uint32: general-seed-1]
-	//    [uint32: general-seed-2]
-	//      (last two depends on compile-settings, and are not default settings)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_FRAME);
-	NetworkSend_uint32(p, _frame_counter);
-	NetworkSend_uint32(p, _frame_counter_max);
-#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
-	NetworkSend_uint32(p, _sync_seed_1);
-#ifdef NETWORK_SEND_DOUBLE_SEED
-	NetworkSend_uint32(p, _sync_seed_2);
-#endif
-#endif
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SYNC)
-{
-	//
-	// Packet: SERVER_SYNC
-	// Function: Sends a sync-check to the client
-	// Data:
-	//    uint32: Frame Counter
-	//    uint32: General-seed-1
-	//    [uint32: general-seed-2]
-	//      (last one depends on compile-settings, and are not default settings)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_SYNC);
-	NetworkSend_uint32(p, _frame_counter);
-	NetworkSend_uint32(p, _sync_seed_1);
-
-#ifdef NETWORK_SEND_DOUBLE_SEED
-	NetworkSend_uint32(p, _sync_seed_2);
-#endif
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp)
-{
-	//
-	// Packet: SERVER_COMMAND
-	// Function: Sends a DoCommand to the client
-	// Data:
-	//    uint8:  PlayerID (0..MAX_PLAYERS-1)
-	//    uint32: CommandID (see command.h)
-	//    uint32: P1 (free variables used in DoCommand)
-	//    uint32: P2
-	//    uint32: Tile
-	//    string: text
-	//    uint8:  CallBackID (see callback_table.c)
-	//    uint32: Frame of execution
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_COMMAND);
-
-	NetworkSend_uint8(p, cp->player);
-	NetworkSend_uint32(p, cp->cmd);
-	NetworkSend_uint32(p, cp->p1);
-	NetworkSend_uint32(p, cp->p2);
-	NetworkSend_uint32(p, cp->tile);
-	NetworkSend_string(p, cp->text);
-	NetworkSend_uint8(p, cp->callback);
-	NetworkSend_uint32(p, cp->frame);
-
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, bool self_send, const char *msg)
-{
-	//
-	// Packet: SERVER_CHAT
-	// Function: Sends a chat-packet to the client
-	// Data:
-	//    uint8:  ActionID (see network_data.h, NetworkAction)
-	//    uint16:  Client-index
-	//    String: Message (max MAX_TEXT_MSG_LEN)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT);
-
-	NetworkSend_uint8(p, action);
-	NetworkSend_uint16(p, client_index);
-	NetworkSend_uint8(p, self_send);
-	NetworkSend_string(p, msg);
-
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno)
-{
-	//
-	// Packet: SERVER_ERROR_QUIT
-	// Function: One of the clients made an error and is quiting the game
-	//      This packet informs the other clients of that.
-	// Data:
-	//    uint16:  Client-index
-	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT);
-
-	NetworkSend_uint16(p, client_index);
-	NetworkSend_uint8(p, errorno);
-
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg)
-{
-	//
-	// Packet: SERVER_ERROR_QUIT
-	// Function: A client left the game, and this packets informs the other clients
-	//      of that.
-	// Data:
-	//    uint16:  Client-index
-	//    String: leave-message
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT);
-
-	NetworkSend_uint16(p, client_index);
-	NetworkSend_string(p, leavemsg);
-
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN)
-{
-	//
-	// Packet: SERVER_SHUTDOWN
-	// Function: Let the clients know that the server is closing
-	// Data:
-	//     <none>
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_SHUTDOWN);
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME)
-{
-	//
-	// Packet: PACKET_SERVER_NEWGAME
-	// Function: Let the clients know that the server is loading a new map
-	// Data:
-	//     <none>
-	//
-
-	Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME);
-	NetworkSend_Packet(p, cs);
-}
-
-DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command)
-{
-	Packet *p = NetworkSend_Init(PACKET_SERVER_RCON);
-
-	NetworkSend_uint16(p, color);
-	NetworkSend_string(p, command);
-	NetworkSend_Packet(p, cs);
-}
-
-// **********
-// Receiving functions
-//   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p
-// **********
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO)
-{
-	SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs);
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
-{
-	char name[NETWORK_CLIENT_NAME_LENGTH];
-	char unique_id[NETWORK_NAME_LENGTH];
-	NetworkClientInfo *ci;
-	byte playas;
-	NetworkLanguage client_lang;
-	char client_revision[NETWORK_REVISION_LENGTH];
-
-	NetworkRecv_string(cs, p, client_revision, sizeof(client_revision));
-
-#if defined(WITH_REV) || defined(WITH_REV_HACK)
-	// Check if the client has revision control enabled
-	if (strcmp(NOREV_STRING, client_revision) != 0 &&
-			strcmp(_network_game_info.server_revision, client_revision) != 0) {
-		// Different revisions!!
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_REVISION);
-		return;
-	}
-#endif
-
-	NetworkRecv_string(cs, p, name, sizeof(name));
-	playas = NetworkRecv_uint8(cs, p);
-	client_lang = NetworkRecv_uint8(cs, p);
-	NetworkRecv_string(cs, p, unique_id, sizeof(unique_id));
-
-	if (cs->has_quit) return;
-
-	// join another company does not affect these values
-	switch (playas) {
-		case PLAYER_NEW_COMPANY: /* New company */
-			if (ActivePlayerCount() >= _network_game_info.companies_max) {
-				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
-				return;
-			}
-			break;
-		case PLAYER_SPECTATOR: /* Spectator */
-			if (NetworkSpectatorCount() >= _network_game_info.spectators_max) {
-				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
-				return;
-			}
-			break;
-		default: /* Join another company (companies 1-8 (index 0-7)) */
-			if (!IsValidPlayer(playas)) {
-				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
-				return;
-			}
-			break;
-	}
-
-	// We need a valid name.. make it Player
-	if (*name == '\0') ttd_strlcpy(name, "Player", sizeof(name));
-
-	if (!NetworkFindName(name)) { // Change name if duplicate
-		// We could not create a name for this player
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NAME_IN_USE);
-		return;
-	}
-
-	ci = DEREF_CLIENT_INFO(cs);
-
-	ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
-	ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id));
-	ci->client_playas = playas;
-	ci->client_lang = client_lang;
-
-	// We now want a password from the client
-	//  else we do not allow him in!
-	if (_network_game_info.use_password) {
-		SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD);
-	} else {
-		if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') {
-			SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD);
-		} else {
-			SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
-		}
-	}
-
-	/* Make sure companies to which people try to join are not autocleaned */
-	if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0;
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD)
-{
-	NetworkPasswordType type;
-	char password[NETWORK_PASSWORD_LENGTH];
-	const NetworkClientInfo *ci;
-
-	type = NetworkRecv_uint8(cs, p);
-	NetworkRecv_string(cs, p, password, sizeof(password));
-
-	if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) {
-		// Check game-password
-		if (strcmp(password, _network_game_info.server_password) != 0) {
-			// Password is invalid
-			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD);
-			return;
-		}
-
-		ci = DEREF_CLIENT_INFO(cs);
-
-		if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') {
-			SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD);
-			return;
-		}
-
-		// Valid password, allow user
-		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
-		return;
-	} else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) {
-		ci = DEREF_CLIENT_INFO(cs);
-
-		if (strcmp(password, _network_player_info[ci->client_playas].password) != 0) {
-			// Password is invalid
-			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD);
-			return;
-		}
-
-		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
-		return;
-	}
-
-
-	SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
-	return;
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP)
-{
-	const NetworkClientState *new_cs;
-
-	// The client was never joined.. so this is impossible, right?
-	//  Ignore the packet, give the client a warning, and close his connection
-	if (cs->status < STATUS_AUTH || cs->has_quit) {
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
-		return;
-	}
-
-	// Check if someone else is receiving the map
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs->status == STATUS_MAP) {
-			// Tell the new client to wait
-			cs->status = STATUS_MAP_WAIT;
-			SEND_COMMAND(PACKET_SERVER_WAIT)(cs);
-			return;
-		}
-	}
-
-	// We receive a request to upload the map.. give it to the client!
-	SEND_COMMAND(PACKET_SERVER_MAP)(cs);
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK)
-{
-	// Client has the map, now start syncing
-	if (cs->status == STATUS_DONE_MAP && !cs->has_quit) {
-		char client_name[NETWORK_CLIENT_NAME_LENGTH];
-		NetworkClientState *new_cs;
-
-		NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-		NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, client_name, "");
-
-		// Mark the client as pre-active, and wait for an ACK
-		//  so we know he is done loading and in sync with us
-		cs->status = STATUS_PRE_ACTIVE;
-		NetworkHandleCommandQueue(cs);
-		SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
-		SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
-
-		// This is the frame the client receives
-		//  we need it later on to make sure the client is not too slow
-		cs->last_frame = _frame_counter;
-		cs->last_frame_server = _frame_counter;
-
-		FOR_ALL_CLIENTS(new_cs) {
-			if (new_cs->status > STATUS_AUTH) {
-				SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(new_cs, DEREF_CLIENT_INFO(cs));
-				SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index);
-			}
-		}
-
-		if (_network_pause_on_join) {
-			/* Now pause the game till the client is in sync */
-			DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-
-			NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX);
-		}
-	} else {
-		// Wrong status for this packet, give a warning to client, and close connection
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
-	}
-}
-
-/** Enforce the command flags.
- * Eg a server-only command can only be executed by a server, etc.
- * @param *cp the commandpacket that is going to be checked
- * @param *ci client information for debugging output to console
- */
-static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci)
-{
-	byte flags = GetCommandFlags(cp->cmd);
-
-	if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) {
-		IConsolePrintF(_icolour_err, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
-		return false;
-	}
-
-	if (flags & CMD_OFFLINE) {
-		IConsolePrintF(_icolour_err, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
-		return false;
-	}
-
-	return true;
-}
-
-/** The client has done a command and wants us to handle it
- * @param *cs the connected client that has sent the command
- * @param *p the packet in which the command was sent
- */
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
-{
-	NetworkClientState *new_cs;
-	const NetworkClientInfo *ci;
-	byte callback;
-
-	CommandPacket *cp = malloc(sizeof(CommandPacket));
-
-	// The client was never joined.. so this is impossible, right?
-	//  Ignore the packet, give the client a warning, and close his connection
-	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
-		return;
-	}
-
-	cp->player = NetworkRecv_uint8(cs, p);
-	cp->cmd    = NetworkRecv_uint32(cs, p);
-	cp->p1     = NetworkRecv_uint32(cs, p);
-	cp->p2     = NetworkRecv_uint32(cs, p);
-	cp->tile   = NetworkRecv_uint32(cs, p);
-	NetworkRecv_string(cs, p, cp->text, lengthof(cp->text));
-
-	callback = NetworkRecv_uint8(cs, p);
-
-	if (cs->has_quit) return;
-
-	ci = DEREF_CLIENT_INFO(cs);
-
-	/* Check if cp->cmd is valid */
-	if (!IsValidCommand(cp->cmd)) {
-		IConsolePrintF(_icolour_err, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci));
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
-		return;
-	}
-
-	if (!CheckCommandFlags(cp, ci)) {
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED);
-		return;
-	}
-
-	/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
-	 * to match the player in the packet. If it doesn't, the client has done
-	 * something pretty naughty (or a bug), and will be kicked
-	 */
-	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) {
-		IConsolePrintF(_icolour_err, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
-		               ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1);
-		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
-		return;
-	}
-
-	/** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the
-	 * player the correct ID, the server injects p2 and executes the command. Any other p1
-	 * is prohibited. Pretty ugly and should be redone together with its function.
-	 * @see CmdPlayerCtrl() players.c:655
-	 */
-	if (cp->cmd == CMD_PLAYER_CTRL) {
-		if (cp->p1 != 0) {
-			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER);
-			return;
-		}
-
-		/* XXX - Execute the command as a valid player. Normally this would be done by a
-		 * spectator, but that is not allowed any commands. So do an impersonation. The drawback
-		 * of this is that the first company's last_built_tile is also updated... */
-		cp->player = 0;
-		cp->p2 = cs - _clients; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
-	}
-
-	// The frame can be executed in the same frame as the next frame-packet
-	//  That frame just before that frame is saved in _frame_counter_max
-	cp->frame = _frame_counter_max + 1;
-	cp->next  = NULL;
-
-	// Queue the command for the clients (are send at the end of the frame
-	//   if they can handle it ;))
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs->status >= STATUS_MAP) {
-			// Callbacks are only send back to the client who sent them in the
-			//  first place. This filters that out.
-			cp->callback = (new_cs != cs) ? 0 : callback;
-			NetworkAddCommandQueue(new_cs, cp);
-		}
-	}
-
-	cp->callback = 0;
-	// Queue the command on the server
-	if (_local_command_queue == NULL) {
-		_local_command_queue = cp;
-	} else {
-		// Find last packet
-		CommandPacket *c = _local_command_queue;
-		while (c->next != NULL) c = c->next;
-		c->next = cp;
-	}
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
-{
-	// This packets means a client noticed an error and is reporting this
-	//  to us. Display the error and report it to the other clients
-	NetworkClientState *new_cs;
-	char str[100];
-	char client_name[NETWORK_CLIENT_NAME_LENGTH];
-	NetworkErrorCode errorno = NetworkRecv_uint8(cs, p);
-
-	// The client was never joined.. thank the client for the packet, but ignore it
-	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
-		cs->has_quit = true;
-		return;
-	}
-
-	NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-	GetNetworkErrorMsg(str, errorno, lastof(str));
-
-	DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
-
-	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
-
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs->status > STATUS_AUTH) {
-			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
-		}
-	}
-
-	cs->has_quit = true;
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
-{
-	// The client wants to leave. Display this and report it to the other
-	//  clients.
-	NetworkClientState *new_cs;
-	char str[100];
-	char client_name[NETWORK_CLIENT_NAME_LENGTH];
-
-	// The client was never joined.. thank the client for the packet, but ignore it
-	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
-		cs->has_quit = true;
-		return;
-	}
-
-	NetworkRecv_string(cs, p, str, lengthof(str));
-
-	NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
-
-	FOR_ALL_CLIENTS(new_cs) {
-		if (new_cs->status > STATUS_AUTH) {
-			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str);
-		}
-	}
-
-	cs->has_quit = true;
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
-{
-	uint32 frame = NetworkRecv_uint32(cs, p);
-
-	/* The client is trying to catch up with the server */
-	if (cs->status == STATUS_PRE_ACTIVE) {
-		/* The client is not yet catched up? */
-		if (frame + DAY_TICKS < _frame_counter) return;
-
-		/* Now he is! Unpause the game */
-		cs->status = STATUS_ACTIVE;
-
-		if (_network_pause_on_join) {
-			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
-			NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", NETWORK_SERVER_INDEX);
-		}
-
-		CheckMinPlayers();
-
-		/* Execute script for, e.g. MOTD */
-		IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
-	}
-
-	// The client received the frame, make note of it
-	cs->last_frame = frame;
-	// With those 2 values we can calculate the lag realtime
-	cs->last_frame_server = _frame_counter;
-}
-
-
-
-void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index)
-{
-	NetworkClientState *cs;
-	const NetworkClientInfo *ci, *ci_own, *ci_to;
-
-	switch (desttype) {
-	case DESTTYPE_CLIENT:
-		/* Are we sending to the server? */
-		if (dest == NETWORK_SERVER_INDEX) {
-			ci = NetworkFindClientInfoFromIndex(from_index);
-			/* Display the text locally, and that is it */
-			if (ci != NULL)
-				NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
-		} else {
-			/* Else find the client to send the message to */
-			FOR_ALL_CLIENTS(cs) {
-				if (cs->index == dest) {
-					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
-					break;
-				}
-			}
-		}
-
-		// Display the message locally (so you know you have sent it)
-		if (from_index != dest) {
-			if (from_index == NETWORK_SERVER_INDEX) {
-				ci = NetworkFindClientInfoFromIndex(from_index);
-				ci_to = NetworkFindClientInfoFromIndex(dest);
-				if (ci != NULL && ci_to != NULL)
-					NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg);
-			} else {
-				FOR_ALL_CLIENTS(cs) {
-					if (cs->index == from_index) {
-						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg);
-						break;
-					}
-				}
-			}
-		}
-		break;
-	case DESTTYPE_TEAM: {
-		bool show_local = true; // If this is false, the message is already displayed
-														// on the client who did sent it.
-		/* Find all clients that belong to this player */
-		ci_to = NULL;
-		FOR_ALL_CLIENTS(cs) {
-			ci = DEREF_CLIENT_INFO(cs);
-			if (ci->client_playas == dest) {
-				SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
-				if (cs->index == from_index) show_local = false;
-				ci_to = ci; // Remember a client that is in the company for company-name
-			}
-		}
-
-		ci = NetworkFindClientInfoFromIndex(from_index);
-		ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-		if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
-			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
-			if (from_index == NETWORK_SERVER_INDEX) show_local = false;
-			ci_to = ci_own;
-		}
-
-		/* There is no such player */
-		if (ci_to == NULL) break;
-
-		// Display the message locally (so you know you have sent it)
-		if (ci != NULL && show_local) {
-			if (from_index == NETWORK_SERVER_INDEX) {
-				char name[NETWORK_NAME_LENGTH];
-				StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS;
-				GetString(name, str, lastof(name));
-				NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg);
-			} else {
-				FOR_ALL_CLIENTS(cs) {
-					if (cs->index == from_index) {
-						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg);
-					}
-				}
-			}
-		}
-		}
-		break;
-	default:
-		DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
-		/* fall-through to next case */
-	case DESTTYPE_BROADCAST:
-		FOR_ALL_CLIENTS(cs) {
-			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
-		}
-		ci = NetworkFindClientInfoFromIndex(from_index);
-		if (ci != NULL)
-			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
-		break;
-	}
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
-{
-	NetworkAction action = NetworkRecv_uint8(cs, p);
-	DestType desttype = NetworkRecv_uint8(cs, p);
-	int dest = NetworkRecv_uint8(cs, p);
-	char msg[MAX_TEXT_MSG_LEN];
-
-	NetworkRecv_string(cs, p, msg, MAX_TEXT_MSG_LEN);
-
-	NetworkServer_HandleChat(action, desttype, dest, msg, cs->index);
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD)
-{
-	char password[NETWORK_PASSWORD_LENGTH];
-	const NetworkClientInfo *ci;
-
-	NetworkRecv_string(cs, p, password, sizeof(password));
-	ci = DEREF_CLIENT_INFO(cs);
-
-	if (IsValidPlayer(ci->client_playas)) {
-		ttd_strlcpy(_network_player_info[ci->client_playas].password, password, sizeof(_network_player_info[0].password));
-	}
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME)
-{
-	char client_name[NETWORK_CLIENT_NAME_LENGTH];
-	NetworkClientInfo *ci;
-
-	NetworkRecv_string(cs, p, client_name, sizeof(client_name));
-	ci = DEREF_CLIENT_INFO(cs);
-
-	if (cs->has_quit) return;
-
-	if (ci != NULL) {
-		// Display change
-		if (NetworkFindName(client_name)) {
-			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", client_name);
-			ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name));
-			NetworkUpdateClientInfo(ci->client_index);
-		}
-	}
-}
-
-DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON)
-{
-	char pass[NETWORK_PASSWORD_LENGTH];
-	char command[NETWORK_RCONCOMMAND_LENGTH];
-
-	if (_network_game_info.rcon_password[0] == '\0') return;
-
-	NetworkRecv_string(cs, p, pass, sizeof(pass));
-	NetworkRecv_string(cs, p, command, sizeof(command));
-
-	if (strcmp(pass, _network_game_info.rcon_password) != 0) {
-		DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->index);
-		return;
-	}
-
-	DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->index, command);
-
-	_redirect_console_to_client = cs->index;
-	IConsoleCmdExec(command);
-	_redirect_console_to_client = 0;
-	return;
-}
-
-// The layout for the receive-functions by the server
-typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p);
-
-
-// This array matches PacketType. At an incoming
-//  packet it is matches against this array
-//  and that way the right function to handle that
-//  packet is found.
-static NetworkServerPacket* const _network_server_packet[] = {
-	NULL, /*PACKET_SERVER_FULL,*/
-	NULL, /*PACKET_SERVER_BANNED,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_JOIN),
-	NULL, /*PACKET_SERVER_ERROR,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO),
-	NULL, /*PACKET_SERVER_COMPANY_INFO,*/
-	NULL, /*PACKET_SERVER_CLIENT_INFO,*/
-	NULL, /*PACKET_SERVER_NEED_PASSWORD,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD),
-	NULL, /*PACKET_SERVER_WELCOME,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_GETMAP),
-	NULL, /*PACKET_SERVER_WAIT,*/
-	NULL, /*PACKET_SERVER_MAP,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK),
-	NULL, /*PACKET_SERVER_JOIN,*/
-	NULL, /*PACKET_SERVER_FRAME,*/
-	NULL, /*PACKET_SERVER_SYNC,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_ACK),
-	RECEIVE_COMMAND(PACKET_CLIENT_COMMAND),
-	NULL, /*PACKET_SERVER_COMMAND,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_CHAT),
-	NULL, /*PACKET_SERVER_CHAT,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD),
-	RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME),
-	RECEIVE_COMMAND(PACKET_CLIENT_QUIT),
-	RECEIVE_COMMAND(PACKET_CLIENT_ERROR),
-	NULL, /*PACKET_SERVER_QUIT,*/
-	NULL, /*PACKET_SERVER_ERROR_QUIT,*/
-	NULL, /*PACKET_SERVER_SHUTDOWN,*/
-	NULL, /*PACKET_SERVER_NEWGAME,*/
-	NULL, /*PACKET_SERVER_RCON,*/
-	RECEIVE_COMMAND(PACKET_CLIENT_RCON),
-};
-
-// If this fails, check the array above with network_data.h
-assert_compile(lengthof(_network_server_packet) == PACKET_END);
-
-// This update the company_info-stuff
-void NetworkPopulateCompanyInfo(void)
-{
-	char password[NETWORK_PASSWORD_LENGTH];
-	const Player *p;
-	const Vehicle *v;
-	const Station *s;
-	const NetworkClientState *cs;
-	const NetworkClientInfo *ci;
-	uint i;
-	uint16 months_empty;
-
-	FOR_ALL_PLAYERS(p) {
-		if (!p->is_active) {
-			memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
-			continue;
-		}
-
-		// Clean the info but not the password
-		ttd_strlcpy(password, _network_player_info[p->index].password, sizeof(password));
-		months_empty = _network_player_info[p->index].months_empty;
-		memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
-		_network_player_info[p->index].months_empty = months_empty;
-		ttd_strlcpy(_network_player_info[p->index].password, password, sizeof(_network_player_info[p->index].password));
-
-		// Grap the company name
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		GetString(_network_player_info[p->index].company_name, STR_JUST_STRING, lastof(_network_player_info[p->index].company_name));
-
-		// Check the income
-		if (_cur_year - 1 == p->inaugurated_year) {
-			// The player is here just 1 year, so display [2], else display[1]
-			for (i = 0; i < lengthof(p->yearly_expenses[2]); i++) {
-				_network_player_info[p->index].income -= p->yearly_expenses[2][i];
-			}
-		} else {
-			for (i = 0; i < lengthof(p->yearly_expenses[1]); i++) {
-				_network_player_info[p->index].income -= p->yearly_expenses[1][i];
-			}
-		}
-
-		// Set some general stuff
-		_network_player_info[p->index].inaugurated_year = p->inaugurated_year;
-		_network_player_info[p->index].company_value = p->old_economy[0].company_value;
-		_network_player_info[p->index].money = p->money64;
-		_network_player_info[p->index].performance = p->old_economy[0].performance_history;
-	}
-
-	// Go through all vehicles and count the type of vehicles
-	FOR_ALL_VEHICLES(v) {
-		if (!IsValidPlayer(v->owner)) continue;
-
-		switch (v->type) {
-			case VEH_Train:
-				if (IsFrontEngine(v)) _network_player_info[v->owner].num_vehicle[0]++;
-				break;
-
-			case VEH_Road:
-				if (v->cargo_type != CT_PASSENGERS) {
-					_network_player_info[v->owner].num_vehicle[1]++;
-				} else {
-					_network_player_info[v->owner].num_vehicle[2]++;
-				}
-				break;
-
-			case VEH_Aircraft:
-				if (v->subtype <= 2) _network_player_info[v->owner].num_vehicle[3]++;
-				break;
-
-			case VEH_Ship:
-				_network_player_info[v->owner].num_vehicle[4]++;
-				break;
-
-			case VEH_Special:
-			case VEH_Disaster:
-				break;
-		}
-	}
-
-	// Go through all stations and count the types of stations
-	FOR_ALL_STATIONS(s) {
-		if (IsValidPlayer(s->owner)) {
-			NetworkPlayerInfo *npi = &_network_player_info[s->owner];
-
-			if (s->facilities & FACIL_TRAIN)      npi->num_station[0]++;
-			if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[1]++;
-			if (s->facilities & FACIL_BUS_STOP)   npi->num_station[2]++;
-			if (s->facilities & FACIL_AIRPORT)    npi->num_station[3]++;
-			if (s->facilities & FACIL_DOCK)       npi->num_station[4]++;
-		}
-	}
-
-	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-	// Register local player (if not dedicated)
-	if (ci != NULL && IsValidPlayer(ci->client_playas))
-		ttd_strlcpy(_network_player_info[ci->client_playas].players, ci->client_name, sizeof(_network_player_info[0].players));
-
-	FOR_ALL_CLIENTS(cs) {
-		char client_name[NETWORK_CLIENT_NAME_LENGTH];
-
-		NetworkGetClientName(client_name, sizeof(client_name), cs);
-
-		ci = DEREF_CLIENT_INFO(cs);
-		if (ci != NULL && IsValidPlayer(ci->client_playas)) {
-			if (strlen(_network_player_info[ci->client_playas].players) != 0)
-				ttd_strlcat(_network_player_info[ci->client_playas].players, ", ", lengthof(_network_player_info[0].players));
-
-			ttd_strlcat(_network_player_info[ci->client_playas].players, client_name, lengthof(_network_player_info[0].players));
-		}
-	}
-}
-
-// Send a packet to all clients with updated info about this client_index
-void NetworkUpdateClientInfo(uint16 client_index)
-{
-	NetworkClientState *cs;
-	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index);
-
-	if (ci == NULL) return;
-
-	FOR_ALL_CLIENTS(cs) {
-		SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci);
-	}
-}
-
-/* Check if we want to restart the map */
-static void NetworkCheckRestartMap(void)
-{
-	if (_network_restart_game_year != 0 && _cur_year >= _network_restart_game_year) {
-		DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
-
-		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
-	}
-}
-
-/* Check if the server has autoclean_companies activated
-    Two things happen:
-      1) If a company is not protected, it is closed after 1 year (for example)
-      2) If a company is protected, protection is disabled after 3 years (for example)
-           (and item 1. happens a year later) */
-static void NetworkAutoCleanCompanies(void)
-{
-	const NetworkClientState *cs;
-	const NetworkClientInfo *ci;
-	const Player *p;
-	bool clients_in_company[MAX_PLAYERS];
-
-	if (!_network_autoclean_companies) return;
-
-	memset(clients_in_company, 0, sizeof(clients_in_company));
-
-	/* Detect the active companies */
-	FOR_ALL_CLIENTS(cs) {
-		ci = DEREF_CLIENT_INFO(cs);
-		if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true;
-	}
-
-	if (!_network_dedicated) {
-		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-		if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true;
-	}
-
-	/* Go through all the comapnies */
-	FOR_ALL_PLAYERS(p) {
-		/* Skip the non-active once */
-		if (!p->is_active || p->is_ai) continue;
-
-		if (!clients_in_company[p->index]) {
-			/* The company is empty for one month more */
-			_network_player_info[p->index].months_empty++;
-
-			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
-			if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') {
-				/* Shut the company down */
-				DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL);
-				IConsolePrintF(_icolour_def, "Auto-cleaned company #%d", p->index + 1);
-			}
-			/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
-			if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') {
-				/* Unprotect the company */
-				_network_player_info[p->index].password[0] = '\0';
-				IConsolePrintF(_icolour_def, "Auto-removed protection from company #%d", p->index+1);
-				_network_player_info[p->index].months_empty = 0;
-			}
-		} else {
-			/* It is not empty, reset the date */
-			_network_player_info[p->index].months_empty = 0;
-		}
-	}
-}
-
-// This function changes new_name to a name that is unique (by adding #1 ...)
-//  and it returns true if that succeeded.
-bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH])
-{
-	NetworkClientState *new_cs;
-	bool found_name = false;
-	byte number = 0;
-	char original_name[NETWORK_CLIENT_NAME_LENGTH];
-
-	// We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer
-	ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH);
-
-	while (!found_name) {
-		const NetworkClientInfo *ci;
-
-		found_name = true;
-		FOR_ALL_CLIENTS(new_cs) {
-			ci = DEREF_CLIENT_INFO(new_cs);
-			if (strcmp(ci->client_name, new_name) == 0) {
-				// Name already in use
-				found_name = false;
-				break;
-			}
-		}
-		// Check if it is the same as the server-name
-		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-		if (ci != NULL) {
-			if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
-		}
-
-		if (!found_name) {
-			// Try a new name (<name> #1, <name> #2, and so on)
-
-			// Stop if we tried for more than 50 times..
-			if (number++ > 50) break;
-			snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number);
-		}
-	}
-
-	return found_name;
-}
-
-// Reads a packet from the stream
-bool NetworkServer_ReadPackets(NetworkClientState *cs)
-{
-	Packet *p;
-	NetworkRecvStatus res;
-	while ((p = NetworkRecv_Packet(cs, &res)) != NULL) {
-		byte type = NetworkRecv_uint8(cs, p);
-		if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->has_quit) {
-			_network_server_packet[type](cs, p);
-		} else {
-			DEBUG(net, 0, "[server] received invalid packet type %d", type);
-		}
-		free(p);
-	}
-
-	return true;
-}
-
-// Handle the local command-queue
-static void NetworkHandleCommandQueue(NetworkClientState* cs)
-{
-	CommandPacket *cp;
-
-	while ( (cp = cs->command_queue) != NULL) {
-		SEND_COMMAND(PACKET_SERVER_COMMAND)(cs, cp);
-
-		cs->command_queue = cp->next;
-		free(cp);
-	}
-}
-
-// This is called every tick if this is a _network_server
-void NetworkServer_Tick(bool send_frame)
-{
-	NetworkClientState *cs;
-#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
-	bool send_sync = false;
-#endif
-
-#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
-	if (_frame_counter >= _last_sync_frame + _network_sync_freq) {
-		_last_sync_frame = _frame_counter;
-		send_sync = true;
-	}
-#endif
-
-	// Now we are done with the frame, inform the clients that they can
-	//  do their frame!
-	FOR_ALL_CLIENTS(cs) {
-		// Check if the speed of the client is what we can expect from a client
-		if (cs->status == STATUS_ACTIVE) {
-			// 1 lag-point per day
-			int lag = NetworkCalculateLag(cs) / DAY_TICKS;
-			if (lag > 0) {
-				if (lag > 3) {
-					// Client did still not report in after 4 game-day, drop him
-					//  (that is, the 3 of above, + 1 before any lag is counted)
-					IConsolePrintF(_icolour_err,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index);
-					NetworkCloseClient(cs);
-					continue;
-				}
-
-				// Report once per time we detect the lag
-				if (cs->lag_test == 0) {
-					IConsolePrintF(_icolour_warn,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
-					cs->lag_test = 1;
-				}
-			} else {
-				cs->lag_test = 0;
-			}
-		} else if (cs->status == STATUS_PRE_ACTIVE) {
-			int lag = NetworkCalculateLag(cs);
-			if (lag > _network_max_join_time) {
-				IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time);
-				NetworkCloseClient(cs);
-			}
-		}
-
-		if (cs->status >= STATUS_PRE_ACTIVE) {
-			// Check if we can send command, and if we have anything in the queue
-			NetworkHandleCommandQueue(cs);
-
-			// Send an updated _frame_counter_max to the client
-			if (send_frame) SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
-
-#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
-			// Send a sync-check packet
-			if (send_sync) SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
-#endif
-		}
-	}
-
-	/* See if we need to advertise */
-	NetworkUDPAdvertise();
-}
-
-void NetworkServerYearlyLoop(void)
-{
-	NetworkCheckRestartMap();
-}
-
-void NetworkServerMonthlyLoop(void)
-{
-	NetworkAutoCleanCompanies();
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_server.cpp
@@ -0,0 +1,1528 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../stdafx.h"
+#include "../openttd.h" // XXX StringID
+#include "../debug.h"
+#include "../string.h"
+#include "../strings.h"
+#include "network_data.h"
+#include "core/tcp.h"
+#include "../train.h"
+#include "../date.h"
+#include "table/strings.h"
+#include "../functions.h"
+#include "network_server.h"
+#include "network_udp.h"
+#include "../console.h"
+#include "../command.h"
+#include "../saveload.h"
+#include "../vehicle.h"
+#include "../station.h"
+#include "../variables.h"
+#include "../genworld.h"
+
+// This file handles all the server-commands
+
+static void NetworkHandleCommandQueue(NetworkClientState* cs);
+
+// **********
+// Sending functions
+//   DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs
+// **********
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci)
+{
+	//
+	// Packet: SERVER_CLIENT_INFO
+	// Function: Sends info about a client
+	// Data:
+	//    uint16:  The index of the client (always unique on a server. 1 = server)
+	//    uint8:  As which player the client is playing
+	//    String: The name of the client
+	//    String: The unique id of the client
+	//
+
+	if (ci->client_index != NETWORK_EMPTY_INDEX) {
+		Packet *p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO);
+		NetworkSend_uint16(p, ci->client_index);
+		NetworkSend_uint8 (p, ci->client_playas);
+		NetworkSend_string(p, ci->client_name);
+		NetworkSend_string(p, ci->unique_id);
+
+		NetworkSend_Packet(p, cs);
+	}
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)
+{
+//
+	// Packet: SERVER_COMPANY_INFO
+	// Function: Sends info about the companies
+	// Data:
+	//
+
+	int i;
+
+	Player *player;
+	Packet *p;
+
+	byte active = ActivePlayerCount();
+
+	if (active == 0) {
+		p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
+
+		NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
+		NetworkSend_uint8 (p, active);
+
+		NetworkSend_Packet(p, cs);
+		return;
+	}
+
+	NetworkPopulateCompanyInfo();
+
+	FOR_ALL_PLAYERS(player) {
+		if (!player->is_active) continue;
+
+		p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
+
+		NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
+		NetworkSend_uint8 (p, active);
+		NetworkSend_uint8 (p, player->index);
+
+		NetworkSend_string(p, _network_player_info[player->index].company_name);
+		NetworkSend_uint32(p, _network_player_info[player->index].inaugurated_year);
+		NetworkSend_uint64(p, _network_player_info[player->index].company_value);
+		NetworkSend_uint64(p, _network_player_info[player->index].money);
+		NetworkSend_uint64(p, _network_player_info[player->index].income);
+		NetworkSend_uint16(p, _network_player_info[player->index].performance);
+
+		/* Send 1 if there is a passord for the company else send 0 */
+		if (_network_player_info[player->index].password[0] != '\0') {
+			NetworkSend_uint8(p, 1);
+		} else {
+			NetworkSend_uint8(p, 0);
+		}
+
+		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) {
+			NetworkSend_uint16(p, _network_player_info[player->index].num_vehicle[i]);
+		}
+
+		for (i = 0; i < NETWORK_STATION_TYPES; i++) {
+			NetworkSend_uint16(p, _network_player_info[player->index].num_station[i]);
+		}
+
+		if (_network_player_info[player->index].players[0] == '\0') {
+			NetworkSend_string(p, "<none>");
+		} else {
+			NetworkSend_string(p, _network_player_info[player->index].players);
+		}
+
+		NetworkSend_Packet(p, cs);
+	}
+
+	p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO);
+
+	NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION);
+	NetworkSend_uint8 (p, 0);
+
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error)
+{
+	//
+	// Packet: SERVER_ERROR
+	// Function: The client made an error
+	// Data:
+	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
+	//
+
+	char str[100];
+	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR);
+
+	NetworkSend_uint8(p, error);
+	NetworkSend_Packet(p, cs);
+
+	GetNetworkErrorMsg(str, error, lastof(str));
+
+	// Only send when the current client was in game
+	if (cs->status > STATUS_AUTH) {
+		NetworkClientState *new_cs;
+		char client_name[NETWORK_CLIENT_NAME_LENGTH];
+
+		NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+		DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
+
+		NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
+
+		FOR_ALL_CLIENTS(new_cs) {
+			if (new_cs->status > STATUS_AUTH && new_cs != cs) {
+				// Some errors we filter to a more general error. Clients don't have to know the real
+				//  reason a joining failed.
+				if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION)
+					error = NETWORK_ERROR_ILLEGAL_PACKET;
+
+				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, error);
+			}
+		}
+	} else {
+		DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->index, str);
+	}
+
+	cs->has_quit = true;
+
+	// Make sure the data get's there before we close the connection
+	NetworkSend_Packets(cs);
+
+	// The client made a mistake, so drop his connection now!
+	NetworkCloseClient(cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type)
+{
+	//
+	// Packet: SERVER_NEED_PASSWORD
+	// Function: Indication to the client that the server needs a password
+	// Data:
+	//    uint8:  Type of password
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD);
+	NetworkSend_uint8(p, type);
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME)
+{
+	//
+	// Packet: SERVER_WELCOME
+	// Function: The client is joined and ready to receive his map
+	// Data:
+	//    uint16:  Own ClientID
+	//
+
+	Packet *p;
+	const NetworkClientState *new_cs;
+
+	// Invalid packet when status is AUTH or higher
+	if (cs->status >= STATUS_AUTH) return;
+
+	cs->status = STATUS_AUTH;
+	_network_game_info.clients_on++;
+
+	p = NetworkSend_Init(PACKET_SERVER_WELCOME);
+	NetworkSend_uint16(p, cs->index);
+	NetworkSend_Packet(p, cs);
+
+		// Transmit info about all the active clients
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs != cs && new_cs->status > STATUS_AUTH)
+			SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, DEREF_CLIENT_INFO(new_cs));
+	}
+	// Also send the info of the server
+	SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX));
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WAIT)
+{
+	//
+	// Packet: PACKET_SERVER_WAIT
+	// Function: The client can not receive the map at the moment because
+	//             someone else is already receiving the map
+	// Data:
+	//    uint8:  Clients awaiting map
+	//
+	int waiting = 0;
+	NetworkClientState *new_cs;
+	Packet *p;
+
+	// Count how many players are waiting in the queue
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs->status == STATUS_MAP_WAIT) waiting++;
+	}
+
+	p = NetworkSend_Init(PACKET_SERVER_WAIT);
+	NetworkSend_uint8(p, waiting);
+	NetworkSend_Packet(p, cs);
+}
+
+// This sends the map to the client
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
+{
+	//
+	// Packet: SERVER_MAP
+	// Function: Sends the map to the client, or a part of it (it is splitted in
+	//   a lot of multiple packets)
+	// Data:
+	//    uint8:  packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END)
+	//  if MAP_PACKET_START:
+	//    uint32: The current FrameCounter
+	//  if MAP_PACKET_NORMAL:
+	//    piece of the map (till max-size of packet)
+	//  if MAP_PACKET_END:
+	//    uint32: seed0 of player
+	//    uint32: seed1 of player
+	//      last 2 are repeated MAX_PLAYERS time
+	//
+
+	static FILE *file_pointer;
+	static uint sent_packets; // How many packets we did send succecfully last time
+
+	if (cs->status < STATUS_AUTH) {
+		// Illegal call, return error and ignore the packet
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
+		return;
+	}
+
+	if (cs->status == STATUS_AUTH) {
+		char filename[256];
+		Packet *p;
+
+		// Make a dump of the current game
+		snprintf(filename, lengthof(filename), "%s%snetwork_server.tmp",  _paths.autosave_dir, PATHSEP);
+		if (SaveOrLoad(filename, SL_SAVE) != SL_OK) error("network savedump failed");
+
+		file_pointer = fopen(filename, "rb");
+		fseek(file_pointer, 0, SEEK_END);
+
+		// Now send the _frame_counter and how many packets are coming
+		p = NetworkSend_Init(PACKET_SERVER_MAP);
+		NetworkSend_uint8(p, MAP_PACKET_START);
+		NetworkSend_uint32(p, _frame_counter);
+		NetworkSend_uint32(p, ftell(file_pointer));
+		NetworkSend_Packet(p, cs);
+
+		fseek(file_pointer, 0, SEEK_SET);
+
+		sent_packets = 4; // We start with trying 4 packets
+
+		cs->status = STATUS_MAP;
+		/* Mark the start of download */
+		cs->last_frame = _frame_counter;
+		cs->last_frame_server = _frame_counter;
+	}
+
+	if (cs->status == STATUS_MAP) {
+		uint i;
+		int res;
+		for (i = 0; i < sent_packets; i++) {
+			Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
+			NetworkSend_uint8(p, MAP_PACKET_NORMAL);
+			res = (int)fread(p->buffer + p->size, 1, SEND_MTU - p->size, file_pointer);
+
+			if (ferror(file_pointer)) error("Error reading temporary network savegame!");
+
+			p->size += res;
+			NetworkSend_Packet(p, cs);
+			if (feof(file_pointer)) {
+				// Done reading!
+				Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
+				NetworkSend_uint8(p, MAP_PACKET_END);
+				NetworkSend_Packet(p, cs);
+
+				// Set the status to DONE_MAP, no we will wait for the client
+				//  to send it is ready (maybe that happens like never ;))
+				cs->status = STATUS_DONE_MAP;
+				fclose(file_pointer);
+
+				{
+					NetworkClientState *new_cs;
+					bool new_map_client = false;
+					// Check if there is a client waiting for receiving the map
+					//  and start sending him the map
+					FOR_ALL_CLIENTS(new_cs) {
+						if (new_cs->status == STATUS_MAP_WAIT) {
+							// Check if we already have a new client to send the map to
+							if (!new_map_client) {
+								// If not, this client will get the map
+								new_cs->status = STATUS_AUTH;
+								new_map_client = true;
+								SEND_COMMAND(PACKET_SERVER_MAP)(new_cs);
+							} else {
+								// Else, send the other clients how many clients are in front of them
+								SEND_COMMAND(PACKET_SERVER_WAIT)(new_cs);
+							}
+						}
+					}
+				}
+
+				// There is no more data, so break the for
+				break;
+			}
+		}
+
+		// Send all packets (forced) and check if we have send it all
+		NetworkSend_Packets(cs);
+		if (cs->packet_queue == NULL) {
+			// All are sent, increase the sent_packets
+			sent_packets *= 2;
+		} else {
+			// Not everything is sent, decrease the sent_packets
+			if (sent_packets > 1) sent_packets /= 2;
+		}
+	}
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index)
+{
+	//
+	// Packet: SERVER_JOIN
+	// Function: A client is joined (all active clients receive this after a
+	//     PACKET_CLIENT_MAP_OK) Mostly what directly follows is a
+	//     PACKET_SERVER_CLIENT_INFO
+	// Data:
+	//    uint16:  Client-Index
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN);
+
+	NetworkSend_uint16(p, client_index);
+
+	NetworkSend_Packet(p, cs);
+}
+
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME)
+{
+	//
+	// Packet: SERVER_FRAME
+	// Function: Sends the current frame-counter to the client
+	// Data:
+	//    uint32: Frame Counter
+	//    uint32: Frame Counter Max (how far may the client walk before the server?)
+	//    [uint32: general-seed-1]
+	//    [uint32: general-seed-2]
+	//      (last two depends on compile-settings, and are not default settings)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_FRAME);
+	NetworkSend_uint32(p, _frame_counter);
+	NetworkSend_uint32(p, _frame_counter_max);
+#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
+	NetworkSend_uint32(p, _sync_seed_1);
+#ifdef NETWORK_SEND_DOUBLE_SEED
+	NetworkSend_uint32(p, _sync_seed_2);
+#endif
+#endif
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SYNC)
+{
+	//
+	// Packet: SERVER_SYNC
+	// Function: Sends a sync-check to the client
+	// Data:
+	//    uint32: Frame Counter
+	//    uint32: General-seed-1
+	//    [uint32: general-seed-2]
+	//      (last one depends on compile-settings, and are not default settings)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_SYNC);
+	NetworkSend_uint32(p, _frame_counter);
+	NetworkSend_uint32(p, _sync_seed_1);
+
+#ifdef NETWORK_SEND_DOUBLE_SEED
+	NetworkSend_uint32(p, _sync_seed_2);
+#endif
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp)
+{
+	//
+	// Packet: SERVER_COMMAND
+	// Function: Sends a DoCommand to the client
+	// Data:
+	//    uint8:  PlayerID (0..MAX_PLAYERS-1)
+	//    uint32: CommandID (see command.h)
+	//    uint32: P1 (free variables used in DoCommand)
+	//    uint32: P2
+	//    uint32: Tile
+	//    string: text
+	//    uint8:  CallBackID (see callback_table.c)
+	//    uint32: Frame of execution
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_COMMAND);
+
+	NetworkSend_uint8(p, cp->player);
+	NetworkSend_uint32(p, cp->cmd);
+	NetworkSend_uint32(p, cp->p1);
+	NetworkSend_uint32(p, cp->p2);
+	NetworkSend_uint32(p, cp->tile);
+	NetworkSend_string(p, cp->text);
+	NetworkSend_uint8(p, cp->callback);
+	NetworkSend_uint32(p, cp->frame);
+
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, bool self_send, const char *msg)
+{
+	//
+	// Packet: SERVER_CHAT
+	// Function: Sends a chat-packet to the client
+	// Data:
+	//    uint8:  ActionID (see network_data.h, NetworkAction)
+	//    uint16:  Client-index
+	//    String: Message (max MAX_TEXT_MSG_LEN)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT);
+
+	NetworkSend_uint8(p, action);
+	NetworkSend_uint16(p, client_index);
+	NetworkSend_uint8(p, self_send);
+	NetworkSend_string(p, msg);
+
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno)
+{
+	//
+	// Packet: SERVER_ERROR_QUIT
+	// Function: One of the clients made an error and is quiting the game
+	//      This packet informs the other clients of that.
+	// Data:
+	//    uint16:  Client-index
+	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT);
+
+	NetworkSend_uint16(p, client_index);
+	NetworkSend_uint8(p, errorno);
+
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg)
+{
+	//
+	// Packet: SERVER_ERROR_QUIT
+	// Function: A client left the game, and this packets informs the other clients
+	//      of that.
+	// Data:
+	//    uint16:  Client-index
+	//    String: leave-message
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT);
+
+	NetworkSend_uint16(p, client_index);
+	NetworkSend_string(p, leavemsg);
+
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN)
+{
+	//
+	// Packet: SERVER_SHUTDOWN
+	// Function: Let the clients know that the server is closing
+	// Data:
+	//     <none>
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_SHUTDOWN);
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME)
+{
+	//
+	// Packet: PACKET_SERVER_NEWGAME
+	// Function: Let the clients know that the server is loading a new map
+	// Data:
+	//     <none>
+	//
+
+	Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME);
+	NetworkSend_Packet(p, cs);
+}
+
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command)
+{
+	Packet *p = NetworkSend_Init(PACKET_SERVER_RCON);
+
+	NetworkSend_uint16(p, color);
+	NetworkSend_string(p, command);
+	NetworkSend_Packet(p, cs);
+}
+
+// **********
+// Receiving functions
+//   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p
+// **********
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO)
+{
+	SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs);
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
+{
+	char name[NETWORK_CLIENT_NAME_LENGTH];
+	char unique_id[NETWORK_NAME_LENGTH];
+	NetworkClientInfo *ci;
+	byte playas;
+	NetworkLanguage client_lang;
+	char client_revision[NETWORK_REVISION_LENGTH];
+
+	NetworkRecv_string(cs, p, client_revision, sizeof(client_revision));
+
+#if defined(WITH_REV) || defined(WITH_REV_HACK)
+	// Check if the client has revision control enabled
+	if (strcmp(NOREV_STRING, client_revision) != 0 &&
+			strcmp(_network_game_info.server_revision, client_revision) != 0) {
+		// Different revisions!!
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_REVISION);
+		return;
+	}
+#endif
+
+	NetworkRecv_string(cs, p, name, sizeof(name));
+	playas = NetworkRecv_uint8(cs, p);
+	client_lang = NetworkRecv_uint8(cs, p);
+	NetworkRecv_string(cs, p, unique_id, sizeof(unique_id));
+
+	if (cs->has_quit) return;
+
+	// join another company does not affect these values
+	switch (playas) {
+		case PLAYER_NEW_COMPANY: /* New company */
+			if (ActivePlayerCount() >= _network_game_info.companies_max) {
+				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
+				return;
+			}
+			break;
+		case PLAYER_SPECTATOR: /* Spectator */
+			if (NetworkSpectatorCount() >= _network_game_info.spectators_max) {
+				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL);
+				return;
+			}
+			break;
+		default: /* Join another company (companies 1-8 (index 0-7)) */
+			if (!IsValidPlayer(playas)) {
+				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
+				return;
+			}
+			break;
+	}
+
+	// We need a valid name.. make it Player
+	if (*name == '\0') ttd_strlcpy(name, "Player", sizeof(name));
+
+	if (!NetworkFindName(name)) { // Change name if duplicate
+		// We could not create a name for this player
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NAME_IN_USE);
+		return;
+	}
+
+	ci = DEREF_CLIENT_INFO(cs);
+
+	ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
+	ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id));
+	ci->client_playas = playas;
+	ci->client_lang = client_lang;
+
+	// We now want a password from the client
+	//  else we do not allow him in!
+	if (_network_game_info.use_password) {
+		SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD);
+	} else {
+		if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') {
+			SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD);
+		} else {
+			SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
+		}
+	}
+
+	/* Make sure companies to which people try to join are not autocleaned */
+	if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0;
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD)
+{
+	NetworkPasswordType type;
+	char password[NETWORK_PASSWORD_LENGTH];
+	const NetworkClientInfo *ci;
+
+	type = NetworkRecv_uint8(cs, p);
+	NetworkRecv_string(cs, p, password, sizeof(password));
+
+	if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) {
+		// Check game-password
+		if (strcmp(password, _network_game_info.server_password) != 0) {
+			// Password is invalid
+			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD);
+			return;
+		}
+
+		ci = DEREF_CLIENT_INFO(cs);
+
+		if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') {
+			SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD);
+			return;
+		}
+
+		// Valid password, allow user
+		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
+		return;
+	} else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) {
+		ci = DEREF_CLIENT_INFO(cs);
+
+		if (strcmp(password, _network_player_info[ci->client_playas].password) != 0) {
+			// Password is invalid
+			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD);
+			return;
+		}
+
+		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
+		return;
+	}
+
+
+	SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
+	return;
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP)
+{
+	const NetworkClientState *new_cs;
+
+	// The client was never joined.. so this is impossible, right?
+	//  Ignore the packet, give the client a warning, and close his connection
+	if (cs->status < STATUS_AUTH || cs->has_quit) {
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
+		return;
+	}
+
+	// Check if someone else is receiving the map
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs->status == STATUS_MAP) {
+			// Tell the new client to wait
+			cs->status = STATUS_MAP_WAIT;
+			SEND_COMMAND(PACKET_SERVER_WAIT)(cs);
+			return;
+		}
+	}
+
+	// We receive a request to upload the map.. give it to the client!
+	SEND_COMMAND(PACKET_SERVER_MAP)(cs);
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK)
+{
+	// Client has the map, now start syncing
+	if (cs->status == STATUS_DONE_MAP && !cs->has_quit) {
+		char client_name[NETWORK_CLIENT_NAME_LENGTH];
+		NetworkClientState *new_cs;
+
+		NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+		NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, client_name, "");
+
+		// Mark the client as pre-active, and wait for an ACK
+		//  so we know he is done loading and in sync with us
+		cs->status = STATUS_PRE_ACTIVE;
+		NetworkHandleCommandQueue(cs);
+		SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
+		SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
+
+		// This is the frame the client receives
+		//  we need it later on to make sure the client is not too slow
+		cs->last_frame = _frame_counter;
+		cs->last_frame_server = _frame_counter;
+
+		FOR_ALL_CLIENTS(new_cs) {
+			if (new_cs->status > STATUS_AUTH) {
+				SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(new_cs, DEREF_CLIENT_INFO(cs));
+				SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index);
+			}
+		}
+
+		if (_network_pause_on_join) {
+			/* Now pause the game till the client is in sync */
+			DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+
+			NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX);
+		}
+	} else {
+		// Wrong status for this packet, give a warning to client, and close connection
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
+	}
+}
+
+/** Enforce the command flags.
+ * Eg a server-only command can only be executed by a server, etc.
+ * @param *cp the commandpacket that is going to be checked
+ * @param *ci client information for debugging output to console
+ */
+static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci)
+{
+	byte flags = GetCommandFlags(cp->cmd);
+
+	if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) {
+		IConsolePrintF(_icolour_err, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
+		return false;
+	}
+
+	if (flags & CMD_OFFLINE) {
+		IConsolePrintF(_icolour_err, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci));
+		return false;
+	}
+
+	return true;
+}
+
+/** The client has done a command and wants us to handle it
+ * @param *cs the connected client that has sent the command
+ * @param *p the packet in which the command was sent
+ */
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
+{
+	NetworkClientState *new_cs;
+	const NetworkClientInfo *ci;
+	byte callback;
+
+	CommandPacket *cp = malloc(sizeof(CommandPacket));
+
+	// The client was never joined.. so this is impossible, right?
+	//  Ignore the packet, give the client a warning, and close his connection
+	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
+		return;
+	}
+
+	cp->player = NetworkRecv_uint8(cs, p);
+	cp->cmd    = NetworkRecv_uint32(cs, p);
+	cp->p1     = NetworkRecv_uint32(cs, p);
+	cp->p2     = NetworkRecv_uint32(cs, p);
+	cp->tile   = NetworkRecv_uint32(cs, p);
+	NetworkRecv_string(cs, p, cp->text, lengthof(cp->text));
+
+	callback = NetworkRecv_uint8(cs, p);
+
+	if (cs->has_quit) return;
+
+	ci = DEREF_CLIENT_INFO(cs);
+
+	/* Check if cp->cmd is valid */
+	if (!IsValidCommand(cp->cmd)) {
+		IConsolePrintF(_icolour_err, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci));
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
+		return;
+	}
+
+	if (!CheckCommandFlags(cp, ci)) {
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED);
+		return;
+	}
+
+	/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
+	 * to match the player in the packet. If it doesn't, the client has done
+	 * something pretty naughty (or a bug), and will be kicked
+	 */
+	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) {
+		IConsolePrintF(_icolour_err, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
+		               ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1);
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
+		return;
+	}
+
+	/** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the
+	 * player the correct ID, the server injects p2 and executes the command. Any other p1
+	 * is prohibited. Pretty ugly and should be redone together with its function.
+	 * @see CmdPlayerCtrl() players.c:655
+	 */
+	if (cp->cmd == CMD_PLAYER_CTRL) {
+		if (cp->p1 != 0) {
+			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER);
+			return;
+		}
+
+		/* XXX - Execute the command as a valid player. Normally this would be done by a
+		 * spectator, but that is not allowed any commands. So do an impersonation. The drawback
+		 * of this is that the first company's last_built_tile is also updated... */
+		cp->player = 0;
+		cp->p2 = cs - _clients; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
+	}
+
+	// The frame can be executed in the same frame as the next frame-packet
+	//  That frame just before that frame is saved in _frame_counter_max
+	cp->frame = _frame_counter_max + 1;
+	cp->next  = NULL;
+
+	// Queue the command for the clients (are send at the end of the frame
+	//   if they can handle it ;))
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs->status >= STATUS_MAP) {
+			// Callbacks are only send back to the client who sent them in the
+			//  first place. This filters that out.
+			cp->callback = (new_cs != cs) ? 0 : callback;
+			NetworkAddCommandQueue(new_cs, cp);
+		}
+	}
+
+	cp->callback = 0;
+	// Queue the command on the server
+	if (_local_command_queue == NULL) {
+		_local_command_queue = cp;
+	} else {
+		// Find last packet
+		CommandPacket *c = _local_command_queue;
+		while (c->next != NULL) c = c->next;
+		c->next = cp;
+	}
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
+{
+	// This packets means a client noticed an error and is reporting this
+	//  to us. Display the error and report it to the other clients
+	NetworkClientState *new_cs;
+	char str[100];
+	char client_name[NETWORK_CLIENT_NAME_LENGTH];
+	NetworkErrorCode errorno = NetworkRecv_uint8(cs, p);
+
+	// The client was never joined.. thank the client for the packet, but ignore it
+	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
+		cs->has_quit = true;
+		return;
+	}
+
+	NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+	GetNetworkErrorMsg(str, errorno, lastof(str));
+
+	DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
+
+	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
+
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs->status > STATUS_AUTH) {
+			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
+		}
+	}
+
+	cs->has_quit = true;
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
+{
+	// The client wants to leave. Display this and report it to the other
+	//  clients.
+	NetworkClientState *new_cs;
+	char str[100];
+	char client_name[NETWORK_CLIENT_NAME_LENGTH];
+
+	// The client was never joined.. thank the client for the packet, but ignore it
+	if (cs->status < STATUS_DONE_MAP || cs->has_quit) {
+		cs->has_quit = true;
+		return;
+	}
+
+	NetworkRecv_string(cs, p, str, lengthof(str));
+
+	NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+	NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
+
+	FOR_ALL_CLIENTS(new_cs) {
+		if (new_cs->status > STATUS_AUTH) {
+			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str);
+		}
+	}
+
+	cs->has_quit = true;
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
+{
+	uint32 frame = NetworkRecv_uint32(cs, p);
+
+	/* The client is trying to catch up with the server */
+	if (cs->status == STATUS_PRE_ACTIVE) {
+		/* The client is not yet catched up? */
+		if (frame + DAY_TICKS < _frame_counter) return;
+
+		/* Now he is! Unpause the game */
+		cs->status = STATUS_ACTIVE;
+
+		if (_network_pause_on_join) {
+			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
+			NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", NETWORK_SERVER_INDEX);
+		}
+
+		CheckMinPlayers();
+
+		/* Execute script for, e.g. MOTD */
+		IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
+	}
+
+	// The client received the frame, make note of it
+	cs->last_frame = frame;
+	// With those 2 values we can calculate the lag realtime
+	cs->last_frame_server = _frame_counter;
+}
+
+
+
+void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index)
+{
+	NetworkClientState *cs;
+	const NetworkClientInfo *ci, *ci_own, *ci_to;
+
+	switch (desttype) {
+	case DESTTYPE_CLIENT:
+		/* Are we sending to the server? */
+		if (dest == NETWORK_SERVER_INDEX) {
+			ci = NetworkFindClientInfoFromIndex(from_index);
+			/* Display the text locally, and that is it */
+			if (ci != NULL)
+				NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
+		} else {
+			/* Else find the client to send the message to */
+			FOR_ALL_CLIENTS(cs) {
+				if (cs->index == dest) {
+					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
+					break;
+				}
+			}
+		}
+
+		// Display the message locally (so you know you have sent it)
+		if (from_index != dest) {
+			if (from_index == NETWORK_SERVER_INDEX) {
+				ci = NetworkFindClientInfoFromIndex(from_index);
+				ci_to = NetworkFindClientInfoFromIndex(dest);
+				if (ci != NULL && ci_to != NULL)
+					NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg);
+			} else {
+				FOR_ALL_CLIENTS(cs) {
+					if (cs->index == from_index) {
+						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg);
+						break;
+					}
+				}
+			}
+		}
+		break;
+	case DESTTYPE_TEAM: {
+		bool show_local = true; // If this is false, the message is already displayed
+														// on the client who did sent it.
+		/* Find all clients that belong to this player */
+		ci_to = NULL;
+		FOR_ALL_CLIENTS(cs) {
+			ci = DEREF_CLIENT_INFO(cs);
+			if (ci->client_playas == dest) {
+				SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
+				if (cs->index == from_index) show_local = false;
+				ci_to = ci; // Remember a client that is in the company for company-name
+			}
+		}
+
+		ci = NetworkFindClientInfoFromIndex(from_index);
+		ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+		if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
+			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
+			if (from_index == NETWORK_SERVER_INDEX) show_local = false;
+			ci_to = ci_own;
+		}
+
+		/* There is no such player */
+		if (ci_to == NULL) break;
+
+		// Display the message locally (so you know you have sent it)
+		if (ci != NULL && show_local) {
+			if (from_index == NETWORK_SERVER_INDEX) {
+				char name[NETWORK_NAME_LENGTH];
+				StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS;
+				GetString(name, str, lastof(name));
+				NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg);
+			} else {
+				FOR_ALL_CLIENTS(cs) {
+					if (cs->index == from_index) {
+						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg);
+					}
+				}
+			}
+		}
+		}
+		break;
+	default:
+		DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
+		/* fall-through to next case */
+	case DESTTYPE_BROADCAST:
+		FOR_ALL_CLIENTS(cs) {
+			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
+		}
+		ci = NetworkFindClientInfoFromIndex(from_index);
+		if (ci != NULL)
+			NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg);
+		break;
+	}
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
+{
+	NetworkAction action = NetworkRecv_uint8(cs, p);
+	DestType desttype = NetworkRecv_uint8(cs, p);
+	int dest = NetworkRecv_uint8(cs, p);
+	char msg[MAX_TEXT_MSG_LEN];
+
+	NetworkRecv_string(cs, p, msg, MAX_TEXT_MSG_LEN);
+
+	NetworkServer_HandleChat(action, desttype, dest, msg, cs->index);
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD)
+{
+	char password[NETWORK_PASSWORD_LENGTH];
+	const NetworkClientInfo *ci;
+
+	NetworkRecv_string(cs, p, password, sizeof(password));
+	ci = DEREF_CLIENT_INFO(cs);
+
+	if (IsValidPlayer(ci->client_playas)) {
+		ttd_strlcpy(_network_player_info[ci->client_playas].password, password, sizeof(_network_player_info[0].password));
+	}
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME)
+{
+	char client_name[NETWORK_CLIENT_NAME_LENGTH];
+	NetworkClientInfo *ci;
+
+	NetworkRecv_string(cs, p, client_name, sizeof(client_name));
+	ci = DEREF_CLIENT_INFO(cs);
+
+	if (cs->has_quit) return;
+
+	if (ci != NULL) {
+		// Display change
+		if (NetworkFindName(client_name)) {
+			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", client_name);
+			ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name));
+			NetworkUpdateClientInfo(ci->client_index);
+		}
+	}
+}
+
+DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON)
+{
+	char pass[NETWORK_PASSWORD_LENGTH];
+	char command[NETWORK_RCONCOMMAND_LENGTH];
+
+	if (_network_game_info.rcon_password[0] == '\0') return;
+
+	NetworkRecv_string(cs, p, pass, sizeof(pass));
+	NetworkRecv_string(cs, p, command, sizeof(command));
+
+	if (strcmp(pass, _network_game_info.rcon_password) != 0) {
+		DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->index);
+		return;
+	}
+
+	DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->index, command);
+
+	_redirect_console_to_client = cs->index;
+	IConsoleCmdExec(command);
+	_redirect_console_to_client = 0;
+	return;
+}
+
+// The layout for the receive-functions by the server
+typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p);
+
+
+// This array matches PacketType. At an incoming
+//  packet it is matches against this array
+//  and that way the right function to handle that
+//  packet is found.
+static NetworkServerPacket* const _network_server_packet[] = {
+	NULL, /*PACKET_SERVER_FULL,*/
+	NULL, /*PACKET_SERVER_BANNED,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_JOIN),
+	NULL, /*PACKET_SERVER_ERROR,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO),
+	NULL, /*PACKET_SERVER_COMPANY_INFO,*/
+	NULL, /*PACKET_SERVER_CLIENT_INFO,*/
+	NULL, /*PACKET_SERVER_NEED_PASSWORD,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD),
+	NULL, /*PACKET_SERVER_WELCOME,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_GETMAP),
+	NULL, /*PACKET_SERVER_WAIT,*/
+	NULL, /*PACKET_SERVER_MAP,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK),
+	NULL, /*PACKET_SERVER_JOIN,*/
+	NULL, /*PACKET_SERVER_FRAME,*/
+	NULL, /*PACKET_SERVER_SYNC,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_ACK),
+	RECEIVE_COMMAND(PACKET_CLIENT_COMMAND),
+	NULL, /*PACKET_SERVER_COMMAND,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_CHAT),
+	NULL, /*PACKET_SERVER_CHAT,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD),
+	RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME),
+	RECEIVE_COMMAND(PACKET_CLIENT_QUIT),
+	RECEIVE_COMMAND(PACKET_CLIENT_ERROR),
+	NULL, /*PACKET_SERVER_QUIT,*/
+	NULL, /*PACKET_SERVER_ERROR_QUIT,*/
+	NULL, /*PACKET_SERVER_SHUTDOWN,*/
+	NULL, /*PACKET_SERVER_NEWGAME,*/
+	NULL, /*PACKET_SERVER_RCON,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_RCON),
+};
+
+// If this fails, check the array above with network_data.h
+assert_compile(lengthof(_network_server_packet) == PACKET_END);
+
+// This update the company_info-stuff
+void NetworkPopulateCompanyInfo(void)
+{
+	char password[NETWORK_PASSWORD_LENGTH];
+	const Player *p;
+	const Vehicle *v;
+	const Station *s;
+	const NetworkClientState *cs;
+	const NetworkClientInfo *ci;
+	uint i;
+	uint16 months_empty;
+
+	FOR_ALL_PLAYERS(p) {
+		if (!p->is_active) {
+			memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
+			continue;
+		}
+
+		// Clean the info but not the password
+		ttd_strlcpy(password, _network_player_info[p->index].password, sizeof(password));
+		months_empty = _network_player_info[p->index].months_empty;
+		memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
+		_network_player_info[p->index].months_empty = months_empty;
+		ttd_strlcpy(_network_player_info[p->index].password, password, sizeof(_network_player_info[p->index].password));
+
+		// Grap the company name
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		GetString(_network_player_info[p->index].company_name, STR_JUST_STRING, lastof(_network_player_info[p->index].company_name));
+
+		// Check the income
+		if (_cur_year - 1 == p->inaugurated_year) {
+			// The player is here just 1 year, so display [2], else display[1]
+			for (i = 0; i < lengthof(p->yearly_expenses[2]); i++) {
+				_network_player_info[p->index].income -= p->yearly_expenses[2][i];
+			}
+		} else {
+			for (i = 0; i < lengthof(p->yearly_expenses[1]); i++) {
+				_network_player_info[p->index].income -= p->yearly_expenses[1][i];
+			}
+		}
+
+		// Set some general stuff
+		_network_player_info[p->index].inaugurated_year = p->inaugurated_year;
+		_network_player_info[p->index].company_value = p->old_economy[0].company_value;
+		_network_player_info[p->index].money = p->money64;
+		_network_player_info[p->index].performance = p->old_economy[0].performance_history;
+	}
+
+	// Go through all vehicles and count the type of vehicles
+	FOR_ALL_VEHICLES(v) {
+		if (!IsValidPlayer(v->owner)) continue;
+
+		switch (v->type) {
+			case VEH_Train:
+				if (IsFrontEngine(v)) _network_player_info[v->owner].num_vehicle[0]++;
+				break;
+
+			case VEH_Road:
+				if (v->cargo_type != CT_PASSENGERS) {
+					_network_player_info[v->owner].num_vehicle[1]++;
+				} else {
+					_network_player_info[v->owner].num_vehicle[2]++;
+				}
+				break;
+
+			case VEH_Aircraft:
+				if (v->subtype <= 2) _network_player_info[v->owner].num_vehicle[3]++;
+				break;
+
+			case VEH_Ship:
+				_network_player_info[v->owner].num_vehicle[4]++;
+				break;
+
+			case VEH_Special:
+			case VEH_Disaster:
+				break;
+		}
+	}
+
+	// Go through all stations and count the types of stations
+	FOR_ALL_STATIONS(s) {
+		if (IsValidPlayer(s->owner)) {
+			NetworkPlayerInfo *npi = &_network_player_info[s->owner];
+
+			if (s->facilities & FACIL_TRAIN)      npi->num_station[0]++;
+			if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[1]++;
+			if (s->facilities & FACIL_BUS_STOP)   npi->num_station[2]++;
+			if (s->facilities & FACIL_AIRPORT)    npi->num_station[3]++;
+			if (s->facilities & FACIL_DOCK)       npi->num_station[4]++;
+		}
+	}
+
+	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+	// Register local player (if not dedicated)
+	if (ci != NULL && IsValidPlayer(ci->client_playas))
+		ttd_strlcpy(_network_player_info[ci->client_playas].players, ci->client_name, sizeof(_network_player_info[0].players));
+
+	FOR_ALL_CLIENTS(cs) {
+		char client_name[NETWORK_CLIENT_NAME_LENGTH];
+
+		NetworkGetClientName(client_name, sizeof(client_name), cs);
+
+		ci = DEREF_CLIENT_INFO(cs);
+		if (ci != NULL && IsValidPlayer(ci->client_playas)) {
+			if (strlen(_network_player_info[ci->client_playas].players) != 0)
+				ttd_strlcat(_network_player_info[ci->client_playas].players, ", ", lengthof(_network_player_info[0].players));
+
+			ttd_strlcat(_network_player_info[ci->client_playas].players, client_name, lengthof(_network_player_info[0].players));
+		}
+	}
+}
+
+// Send a packet to all clients with updated info about this client_index
+void NetworkUpdateClientInfo(uint16 client_index)
+{
+	NetworkClientState *cs;
+	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index);
+
+	if (ci == NULL) return;
+
+	FOR_ALL_CLIENTS(cs) {
+		SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci);
+	}
+}
+
+/* Check if we want to restart the map */
+static void NetworkCheckRestartMap(void)
+{
+	if (_network_restart_game_year != 0 && _cur_year >= _network_restart_game_year) {
+		DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
+
+		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
+	}
+}
+
+/* Check if the server has autoclean_companies activated
+    Two things happen:
+      1) If a company is not protected, it is closed after 1 year (for example)
+      2) If a company is protected, protection is disabled after 3 years (for example)
+           (and item 1. happens a year later) */
+static void NetworkAutoCleanCompanies(void)
+{
+	const NetworkClientState *cs;
+	const NetworkClientInfo *ci;
+	const Player *p;
+	bool clients_in_company[MAX_PLAYERS];
+
+	if (!_network_autoclean_companies) return;
+
+	memset(clients_in_company, 0, sizeof(clients_in_company));
+
+	/* Detect the active companies */
+	FOR_ALL_CLIENTS(cs) {
+		ci = DEREF_CLIENT_INFO(cs);
+		if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true;
+	}
+
+	if (!_network_dedicated) {
+		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+		if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true;
+	}
+
+	/* Go through all the comapnies */
+	FOR_ALL_PLAYERS(p) {
+		/* Skip the non-active once */
+		if (!p->is_active || p->is_ai) continue;
+
+		if (!clients_in_company[p->index]) {
+			/* The company is empty for one month more */
+			_network_player_info[p->index].months_empty++;
+
+			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
+			if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') {
+				/* Shut the company down */
+				DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL);
+				IConsolePrintF(_icolour_def, "Auto-cleaned company #%d", p->index + 1);
+			}
+			/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
+			if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') {
+				/* Unprotect the company */
+				_network_player_info[p->index].password[0] = '\0';
+				IConsolePrintF(_icolour_def, "Auto-removed protection from company #%d", p->index+1);
+				_network_player_info[p->index].months_empty = 0;
+			}
+		} else {
+			/* It is not empty, reset the date */
+			_network_player_info[p->index].months_empty = 0;
+		}
+	}
+}
+
+// This function changes new_name to a name that is unique (by adding #1 ...)
+//  and it returns true if that succeeded.
+bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH])
+{
+	NetworkClientState *new_cs;
+	bool found_name = false;
+	byte number = 0;
+	char original_name[NETWORK_CLIENT_NAME_LENGTH];
+
+	// We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer
+	ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH);
+
+	while (!found_name) {
+		const NetworkClientInfo *ci;
+
+		found_name = true;
+		FOR_ALL_CLIENTS(new_cs) {
+			ci = DEREF_CLIENT_INFO(new_cs);
+			if (strcmp(ci->client_name, new_name) == 0) {
+				// Name already in use
+				found_name = false;
+				break;
+			}
+		}
+		// Check if it is the same as the server-name
+		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+		if (ci != NULL) {
+			if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
+		}
+
+		if (!found_name) {
+			// Try a new name (<name> #1, <name> #2, and so on)
+
+			// Stop if we tried for more than 50 times..
+			if (number++ > 50) break;
+			snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number);
+		}
+	}
+
+	return found_name;
+}
+
+// Reads a packet from the stream
+bool NetworkServer_ReadPackets(NetworkClientState *cs)
+{
+	Packet *p;
+	NetworkRecvStatus res;
+	while ((p = NetworkRecv_Packet(cs, &res)) != NULL) {
+		byte type = NetworkRecv_uint8(cs, p);
+		if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->has_quit) {
+			_network_server_packet[type](cs, p);
+		} else {
+			DEBUG(net, 0, "[server] received invalid packet type %d", type);
+		}
+		free(p);
+	}
+
+	return true;
+}
+
+// Handle the local command-queue
+static void NetworkHandleCommandQueue(NetworkClientState* cs)
+{
+	CommandPacket *cp;
+
+	while ( (cp = cs->command_queue) != NULL) {
+		SEND_COMMAND(PACKET_SERVER_COMMAND)(cs, cp);
+
+		cs->command_queue = cp->next;
+		free(cp);
+	}
+}
+
+// This is called every tick if this is a _network_server
+void NetworkServer_Tick(bool send_frame)
+{
+	NetworkClientState *cs;
+#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
+	bool send_sync = false;
+#endif
+
+#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
+	if (_frame_counter >= _last_sync_frame + _network_sync_freq) {
+		_last_sync_frame = _frame_counter;
+		send_sync = true;
+	}
+#endif
+
+	// Now we are done with the frame, inform the clients that they can
+	//  do their frame!
+	FOR_ALL_CLIENTS(cs) {
+		// Check if the speed of the client is what we can expect from a client
+		if (cs->status == STATUS_ACTIVE) {
+			// 1 lag-point per day
+			int lag = NetworkCalculateLag(cs) / DAY_TICKS;
+			if (lag > 0) {
+				if (lag > 3) {
+					// Client did still not report in after 4 game-day, drop him
+					//  (that is, the 3 of above, + 1 before any lag is counted)
+					IConsolePrintF(_icolour_err,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index);
+					NetworkCloseClient(cs);
+					continue;
+				}
+
+				// Report once per time we detect the lag
+				if (cs->lag_test == 0) {
+					IConsolePrintF(_icolour_warn,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
+					cs->lag_test = 1;
+				}
+			} else {
+				cs->lag_test = 0;
+			}
+		} else if (cs->status == STATUS_PRE_ACTIVE) {
+			int lag = NetworkCalculateLag(cs);
+			if (lag > _network_max_join_time) {
+				IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time);
+				NetworkCloseClient(cs);
+			}
+		}
+
+		if (cs->status >= STATUS_PRE_ACTIVE) {
+			// Check if we can send command, and if we have anything in the queue
+			NetworkHandleCommandQueue(cs);
+
+			// Send an updated _frame_counter_max to the client
+			if (send_frame) SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
+
+#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
+			// Send a sync-check packet
+			if (send_sync) SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
+#endif
+		}
+	}
+
+	/* See if we need to advertise */
+	NetworkUDPAdvertise();
+}
+
+void NetworkServerYearlyLoop(void)
+{
+	NetworkCheckRestartMap();
+}
+
+void NetworkServerMonthlyLoop(void)
+{
+	NetworkAutoCleanCompanies();
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/network/network_udp.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/* $Id$ */
-
-#ifdef ENABLE_NETWORK
-
-#include "../stdafx.h"
-#include "../debug.h"
-#include "../string.h"
-#include "network_data.h"
-#include "../date.h"
-#include "../map.h"
-#include "network_gamelist.h"
-#include "network_udp.h"
-#include "../variables.h"
-#include "../newgrf_config.h"
-
-#include "core/udp.h"
-
-/**
- * @file network_udp.c This file handles the UDP related communication.
- *
- * This is the GameServer <-> MasterServer and GameServer <-> GameClient
- * communication before the game is being joined.
- */
-
-enum {
-	ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes)
-	ADVERTISE_RETRY_INTERVAL  =   300, // readvertise when no response after this many ticks (9 seconds)
-	ADVERTISE_RETRY_TIMES     =     3  // give up readvertising after this much failed retries
-};
-
-#define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, const struct sockaddr_in *client_addr)
-
-static NetworkClientState _udp_cs;
-
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
-{
-	Packet *packet;
-	// Just a fail-safe.. should never happen
-	if (!_network_udp_server)
-		return;
-
-	packet = NetworkSend_Init(PACKET_UDP_SERVER_RESPONSE);
-
-	// Update some game_info
-	_network_game_info.game_date     = _date;
-	_network_game_info.map_width     = MapSizeX();
-	_network_game_info.map_height    = MapSizeY();
-	_network_game_info.map_set       = _opt.landscape;
-	_network_game_info.companies_on  = ActivePlayerCount();
-	_network_game_info.spectators_on = NetworkSpectatorCount();
-	_network_game_info.grfconfig     = _grfconfig;
-
-	NetworkSend_NetworkGameInfo(packet, &_network_game_info);
-
-	// Let the client know that we are here
-	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
-
-	free(packet);
-
-	DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr));
-}
-
-void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
-{
-	/* Find the matching GRF file */
-	const GRFConfig *f = FindGRFConfig(config->grfid, config->md5sum);
-	if (f == NULL) {
-		/* Don't know the GRF, so mark game incompatible and the (possibly)
-		 * already resolved name for this GRF (another server has sent the
-		 * name of the GRF already */
-		config->name     = FindUnknownGRFName(config->grfid, config->md5sum, true);
-		SETBIT(config->flags, GCF_NOT_FOUND);
-	} else {
-		config->filename = f->filename;
-		config->name     = f->name;
-		config->info     = f->info;
-	}
-	SETBIT(config->flags, GCF_COPY);
-}
-
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
-{
-	extern const char _openttd_revision[];
-	NetworkGameList *item;
-
-	// Just a fail-safe.. should never happen
-	if (_network_udp_server || _udp_cs.has_quit) return;
-
-	DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
-
-	// Find next item
-	item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
-
-	NetworkRecv_NetworkGameInfo(&_udp_cs, p, &item->info);
-
-	item->info.compatible = true;
-	{
-		/* Checks whether there needs to be a request for names of GRFs and makes
-		 * the request if necessary. GRFs that need to be requested are the GRFs
-		 * that do not exist on the clients system and we do not have the name
-		 * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER.
-		 * The in_request array and in_request_count are used so there is no need
-		 * to do a second loop over the GRF list, which can be relatively expensive
-		 * due to the string comparisons. */
-		const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT];
-		const GRFConfig *c;
-		uint in_request_count = 0;
-		struct sockaddr_in out_addr;
-
-		for (c = item->info.grfconfig; c != NULL; c = c->next) {
-			if (HASBIT(c->flags, GCF_NOT_FOUND)) item->info.compatible = false;
-			if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
-			in_request[in_request_count] = c;
-			in_request_count++;
-		}
-
-		if (in_request_count > 0) {
-			/* There are 'unknown' GRFs, now send a request for them */
-			uint i;
-			Packet *packet = NetworkSend_Init(PACKET_UDP_CLIENT_GET_NEWGRFS);
-
-			NetworkSend_uint8 (packet, in_request_count);
-			for (i = 0; i < in_request_count; i++) {
-				NetworkSend_GRFIdentifier(packet, in_request[i]);
-			}
-
-			out_addr.sin_family      = AF_INET;
-			out_addr.sin_port        = htons(item->port);
-			out_addr.sin_addr.s_addr = item->ip;
-			NetworkSendUDP_Packet(_udp_client_socket, packet, &out_addr);
-			free(packet);
-		}
-	}
-
-	if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0;
-	if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0;
-
-	if (item->info.hostname[0] == '\0')
-		snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
-
-	/* Check if we are allowed on this server based on the revision-match */
-	item->info.version_compatible =
-		strcmp(item->info.server_revision, _openttd_revision) == 0 ||
-		strcmp(item->info.server_revision, NOREV_STRING) == 0;
-	item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
-
-	item->online = true;
-
-	UpdateNetworkGameWindow(false);
-}
-
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO)
-{
-	NetworkClientState *cs;
-	NetworkClientInfo *ci;
-	Packet *packet;
-	Player *player;
-	byte current = 0;
-	int i;
-
-	// Just a fail-safe.. should never happen
-	if (!_network_udp_server) return;
-
-	packet = NetworkSend_Init(PACKET_UDP_SERVER_DETAIL_INFO);
-
-	/* Send the amount of active companies */
-	NetworkSend_uint8 (packet, NETWORK_COMPANY_INFO_VERSION);
-	NetworkSend_uint8 (packet, ActivePlayerCount());
-
-	/* Fetch the latest version of everything */
-	NetworkPopulateCompanyInfo();
-
-	/* Go through all the players */
-	FOR_ALL_PLAYERS(player) {
-		/* Skip non-active players */
-		if (!player->is_active) continue;
-
-		current++;
-
-		/* Send the information */
-		NetworkSend_uint8(packet, current);
-
-		NetworkSend_string(packet, _network_player_info[player->index].company_name);
-		NetworkSend_uint32(packet, _network_player_info[player->index].inaugurated_year);
-		NetworkSend_uint64(packet, _network_player_info[player->index].company_value);
-		NetworkSend_uint64(packet, _network_player_info[player->index].money);
-		NetworkSend_uint64(packet, _network_player_info[player->index].income);
-		NetworkSend_uint16(packet, _network_player_info[player->index].performance);
-
-		/* Send 1 if there is a passord for the company else send 0 */
-		if (_network_player_info[player->index].password[0] != '\0') {
-			NetworkSend_uint8(packet, 1);
-		} else {
-			NetworkSend_uint8(packet, 0);
-		}
-
-		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
-			NetworkSend_uint16(packet, _network_player_info[player->index].num_vehicle[i]);
-
-		for (i = 0; i < NETWORK_STATION_TYPES; i++)
-			NetworkSend_uint16(packet, _network_player_info[player->index].num_station[i]);
-
-		/* Find the clients that are connected to this player */
-		FOR_ALL_CLIENTS(cs) {
-			ci = DEREF_CLIENT_INFO(cs);
-			if (ci->client_playas == player->index) {
-				/* The uint8 == 1 indicates that a client is following */
-				NetworkSend_uint8(packet, 1);
-				NetworkSend_string(packet, ci->client_name);
-				NetworkSend_string(packet, ci->unique_id);
-				NetworkSend_uint32(packet, ci->join_date);
-			}
-		}
-		/* Also check for the server itself */
-		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-		if (ci->client_playas == player->index) {
-			/* The uint8 == 1 indicates that a client is following */
-			NetworkSend_uint8(packet, 1);
-			NetworkSend_string(packet, ci->client_name);
-			NetworkSend_string(packet, ci->unique_id);
-			NetworkSend_uint32(packet, ci->join_date);
-		}
-
-		/* Indicates end of client list */
-		NetworkSend_uint8(packet, 0);
-	}
-
-	/* And check if we have any spectators */
-	FOR_ALL_CLIENTS(cs) {
-		ci = DEREF_CLIENT_INFO(cs);
-		if (!IsValidPlayer(ci->client_playas)) {
-			/* The uint8 == 1 indicates that a client is following */
-			NetworkSend_uint8(packet, 1);
-			NetworkSend_string(packet, ci->client_name);
-			NetworkSend_string(packet, ci->unique_id);
-			NetworkSend_uint32(packet, ci->join_date);
-		}
-	}
-
-	/* Also check for the server itself */
-	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
-	if (!IsValidPlayer(ci->client_playas)) {
-		/* The uint8 == 1 indicates that a client is following */
-		NetworkSend_uint8(packet, 1);
-		NetworkSend_string(packet, ci->client_name);
-		NetworkSend_string(packet, ci->unique_id);
-		NetworkSend_uint32(packet, ci->join_date);
-	}
-
-	/* Indicates end of client list */
-	NetworkSend_uint8(packet, 0);
-
-	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
-
-	free(packet);
-}
-
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST)
-{
-	int i;
-	struct in_addr ip;
-	uint16 port;
-	uint8 ver;
-
-	/* packet begins with the protocol version (uint8)
-	 * then an uint16 which indicates how many
-	 * ip:port pairs are in this packet, after that
-	 * an uint32 (ip) and an uint16 (port) for each pair
-	 */
-
-	ver = NetworkRecv_uint8(&_udp_cs, p);
-
-	if (_udp_cs.has_quit) return;
-
-	if (ver == 1) {
-		for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) {
-			ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p));
-			port = NetworkRecv_uint16(&_udp_cs, p);
-			NetworkUDPQueryServer(inet_ntoa(ip), port);
-		}
-	}
-}
-
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER)
-{
-	_network_advertise_retries = 0;
-	DEBUG(net, 2, "[udp] advertising on master server successfull");
-
-	/* We are advertised, but we don't want to! */
-	if (!_network_advertise) NetworkUDPRemoveAdvertise();
-}
-
-/**
- * A client has requested the names of some NewGRFs.
- *
- * Replying this can be tricky as we have a limit of SEND_MTU bytes
- * in the reply packet and we can send up to 100 bytes per NewGRF
- * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name).
- * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it
- * could be that a packet overflows. To stop this we only reply
- * with the first N NewGRFs so that if the first N + 1 NewGRFs
- * would be sent, the packet overflows.
- * in_reply and in_reply_count are used to keep a list of GRFs to
- * send in the reply.
- */
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS)
-{
-	uint8 num_grfs;
-	uint i;
-
-	const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT];
-	Packet *packet;
-	uint8 in_reply_count = 0;
-	uint packet_len = 0;
-
-	/* Just a fail-safe.. should never happen */
-	if (_udp_cs.has_quit) return;
-
-	DEBUG(net, 6, "[udp] newgrf data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
-
-	num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
-	if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
-
-	for (i = 0; i < num_grfs; i++) {
-		GRFConfig c;
-		const GRFConfig *f;
-
-		NetworkRecv_GRFIdentifier(&_udp_cs, p, &c);
-
-		/* Find the matching GRF file */
-		f = FindGRFConfig(c.grfid, c.md5sum);
-		if (f == NULL) continue; // The GRF is unknown to this server
-
-		/* If the reply might exceed the size of the packet, only reply
-		 * the current list and do not send the other data.
-		 * The name could be an empty string, if so take the filename. */
-		packet_len += sizeof(c.grfid) + sizeof(c.md5sum) +
-				min(strlen((f->name != NULL && strlen(f->name) > 0) ? f->name : f->filename) + 1, NETWORK_GRF_NAME_LENGTH);
-		if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
-			break;
-		}
-		in_reply[in_reply_count] = f;
-		in_reply_count++;
-	}
-
-	if (in_reply_count == 0) return;
-
-	packet = NetworkSend_Init(PACKET_UDP_SERVER_NEWGRFS);
-	NetworkSend_uint8 (packet, in_reply_count);
-	for (i = 0; i < in_reply_count; i++) {
-		char name[NETWORK_GRF_NAME_LENGTH];
-
-		/* The name could be an empty string, if so take the filename */
-		ttd_strlcpy(name, (in_reply[i]->name != NULL && strlen(in_reply[i]->name) > 0) ?
-				in_reply[i]->name : in_reply[i]->filename, sizeof(name));
-	 	NetworkSend_GRFIdentifier(packet, in_reply[i]);
-		NetworkSend_string(packet, name);
-	}
-
-	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
-	free(packet);
-}
-
-/** The return of the client's request of the names of some NewGRFs */
-DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS)
-{
-	uint8 num_grfs;
-	uint i;
-
-	/* Just a fail-safe.. should never happen */
-	if (_udp_cs.has_quit) return;
-
-	DEBUG(net, 6, "[udp] newgrf data reply from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
-
-	num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
-	if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
-
-	for (i = 0; i < num_grfs; i++) {
-		char *unknown_name;
-		char name[NETWORK_GRF_NAME_LENGTH];
-		GRFConfig c;
-
-		NetworkRecv_GRFIdentifier(&_udp_cs, p, &c);
-		NetworkRecv_string(&_udp_cs, p, name, sizeof(name));
-
-		/* An empty name is not possible under normal circumstances
-		 * and causes problems when showing the NewGRF list. */
-		if (strlen(name) == 0) continue;
-
-		/* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple.
-		 * If it exists and not resolved yet, then name of the fake GRF is
-		 * overwritten with the name from the reply. */
-		unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
-		if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
-			ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH);
-		}
-	}
-}
-
-/**
- * Every type of UDP packet should only be received by a single socket;
- * The socket communicating with the masterserver should receive the
- * game information of some 'random' host.
- */
-typedef struct NetworkUDPPacketAndSocket {
-	void (*callback)(Packet *p, const struct sockaddr_in *client_addr);
-	SOCKET *incoming_socket;
-} NetworkUPDPacketAndSocket;
-
-static const NetworkUPDPacketAndSocket _network_udp_packet[PACKET_UDP_END] = {
-	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER),   &_udp_server_socket },
-	{ RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE),      &_udp_client_socket },
-	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO),   &_udp_server_socket },
-	{ NULL,                                             NULL                },
-	{ NULL,                                             NULL                },
-	{ RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER),  &_udp_master_socket },
-	{ NULL,                                             NULL                },
-	{ RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST), &_udp_client_socket },
-	{ NULL,                                             NULL                },
-	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS),   &_udp_server_socket },
-	{ RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS),       &_udp_client_socket },
-};
-
-void NetworkHandleUDPPacket(const SOCKET udp, Packet *p, const struct sockaddr_in *client_addr)
-{
-	byte type;
-
-	/* Fake a client, so we can see when there is an illegal packet */
-	_udp_cs.socket = INVALID_SOCKET;
-	_udp_cs.has_quit = false;
-
-	type = NetworkRecv_uint8(&_udp_cs, p);
-
-	if (type < PACKET_UDP_END && *_network_udp_packet[type].incoming_socket == udp && !_udp_cs.has_quit) {
-		_network_udp_packet[type].callback(p, client_addr);
-	} else {
-		if (*_network_udp_packet[type].incoming_socket != udp) {
-			DEBUG(net, 0, "[udp] received packet on wrong port from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
-		} else if (!_udp_cs.has_quit) {
-			DEBUG(net, 0, "[udp] received invalid packet type %d from %s:%d", type,  inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
-		} else {
-			DEBUG(net, 0, "[udp] received illegal packet from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
-		}
-	}
-}
-
-
-// Close UDP connection
-void NetworkUDPStop(void)
-{
-	DEBUG(net, 1, "[udp] closed listeners");
-
-	if (_network_udp_server) {
-		NetworkUDPClose(&_udp_server_socket);
-		NetworkUDPClose(&_udp_master_socket);
-	} else {
-		NetworkUDPClose(&_udp_client_socket);
-	}
-
-	_network_udp_server = false;
-	_network_udp_broadcast = 0;
-}
-
-// Broadcast to all ips
-static void NetworkUDPBroadCast(SOCKET udp)
-{
-	Packet* p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER);
-	uint i;
-
-	for (i = 0; _broadcast_list[i] != 0; i++) {
-		struct sockaddr_in out_addr;
-
-		out_addr.sin_family = AF_INET;
-		out_addr.sin_port = htons(_network_server_port);
-		out_addr.sin_addr.s_addr = _broadcast_list[i];
-
-		DEBUG(net, 4, "[udp] broadcasting to %s", inet_ntoa(out_addr.sin_addr));
-
-		NetworkSendUDP_Packet(udp, p, &out_addr);
-	}
-
-	free(p);
-}
-
-
-// Request the the server-list from the master server
-void NetworkUDPQueryMasterServer(void)
-{
-	struct sockaddr_in out_addr;
-	Packet *p;
-
-	if (_udp_client_socket == INVALID_SOCKET)
-		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
-			return;
-
-	p = NetworkSend_Init(PACKET_UDP_CLIENT_GET_LIST);
-
-	out_addr.sin_family = AF_INET;
-	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
-	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
-
-	// packet only contains protocol version
-	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
-
-	NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr);
-
-	DEBUG(net, 2, "[udp] master server queried at %s:%d", inet_ntoa(out_addr.sin_addr),ntohs(out_addr.sin_port));
-
-	free(p);
-}
-
-// Find all servers
-void NetworkUDPSearchGame(void)
-{
-	// We are still searching..
-	if (_network_udp_broadcast > 0) return;
-
-	// No UDP-socket yet..
-	if (_udp_client_socket == INVALID_SOCKET)
-		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
-			return;
-
-	DEBUG(net, 0, "[udp] searching server");
-
-	NetworkUDPBroadCast(_udp_client_socket);
-	_network_udp_broadcast = 300; // Stay searching for 300 ticks
-}
-
-NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port)
-{
-	struct sockaddr_in out_addr;
-	Packet *p;
-	NetworkGameList *item;
-
-	// No UDP-socket yet..
-	if (_udp_client_socket == INVALID_SOCKET)
-		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
-			return NULL;
-
-	out_addr.sin_family = AF_INET;
-	out_addr.sin_port = htons(port);
-	out_addr.sin_addr.s_addr = NetworkResolveHost(host);
-
-	// Clear item in gamelist
-	item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port));
-	memset(&item->info, 0, sizeof(item->info));
-	ttd_strlcpy(item->info.server_name, host, lengthof(item->info.server_name));
-	ttd_strlcpy(item->info.hostname, host, lengthof(item->info.hostname));
-	item->online = false;
-
-	// Init the packet
-	p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER);
-
-	NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr);
-
-	free(p);
-
-	UpdateNetworkGameWindow(false);
-	return item;
-}
-
-/* Remove our advertise from the master-server */
-void NetworkUDPRemoveAdvertise(void)
-{
-	struct sockaddr_in out_addr;
-	Packet *p;
-
-	/* Check if we are advertising */
-	if (!_networking || !_network_server || !_network_udp_server) return;
-
-	/* check for socket */
-	if (_udp_master_socket == INVALID_SOCKET)
-		if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false))
-			return;
-
-	DEBUG(net, 1, "[udp] removing advertise from master server");
-
-	/* Find somewhere to send */
-	out_addr.sin_family = AF_INET;
-	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
-	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
-
-	/* Send the packet */
-	p = NetworkSend_Init(PACKET_UDP_SERVER_UNREGISTER);
-	/* Packet is: Version, server_port */
-	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
-	NetworkSend_uint16(p, _network_server_port);
-	NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr);
-
-	free(p);
-}
-
-/* Register us to the master server
-     This function checks if it needs to send an advertise */
-void NetworkUDPAdvertise(void)
-{
-	struct sockaddr_in out_addr;
-	Packet *p;
-
-	/* Check if we should send an advertise */
-	if (!_networking || !_network_server || !_network_udp_server || !_network_advertise)
-		return;
-
-	/* check for socket */
-	if (_udp_master_socket == INVALID_SOCKET)
-		if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false))
-			return;
-
-	if (_network_need_advertise) {
-		_network_need_advertise = false;
-		_network_advertise_retries = ADVERTISE_RETRY_TIMES;
-	} else {
-		/* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */
-		if (_network_advertise_retries == 0) {
-			if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter)
-				return;
-			_network_advertise_retries = ADVERTISE_RETRY_TIMES;
-		}
-
-		if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter)
-			return;
-	}
-
-	_network_advertise_retries--;
-	_network_last_advertise_frame = _frame_counter;
-
-	/* Find somewhere to send */
-	out_addr.sin_family = AF_INET;
-	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
-	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
-
-	DEBUG(net, 1, "[udp] advertising to master server");
-
-	/* Send the packet */
-	p = NetworkSend_Init(PACKET_UDP_SERVER_REGISTER);
-	/* Packet is: WELCOME_MESSAGE, Version, server_port */
-	NetworkSend_string(p, NETWORK_MASTER_SERVER_WELCOME_MESSAGE);
-	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
-	NetworkSend_uint16(p, _network_server_port);
-	NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr);
-
-	free(p);
-}
-
-void NetworkUDPInitialize(void)
-{
-	_udp_client_socket = INVALID_SOCKET;
-	_udp_server_socket = INVALID_SOCKET;
-	_udp_master_socket = INVALID_SOCKET;
-
-	_network_udp_server = false;
-	_network_udp_broadcast = 0;
-}
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/network/network_udp.cpp
@@ -0,0 +1,655 @@
+/* $Id$ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../stdafx.h"
+#include "../debug.h"
+#include "../string.h"
+#include "network_data.h"
+#include "../date.h"
+#include "../map.h"
+#include "network_gamelist.h"
+#include "network_udp.h"
+#include "../variables.h"
+#include "../newgrf_config.h"
+
+#include "core/udp.h"
+
+/**
+ * @file network_udp.c This file handles the UDP related communication.
+ *
+ * This is the GameServer <-> MasterServer and GameServer <-> GameClient
+ * communication before the game is being joined.
+ */
+
+enum {
+	ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes)
+	ADVERTISE_RETRY_INTERVAL  =   300, // readvertise when no response after this many ticks (9 seconds)
+	ADVERTISE_RETRY_TIMES     =     3  // give up readvertising after this much failed retries
+};
+
+#define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, const struct sockaddr_in *client_addr)
+
+static NetworkClientState _udp_cs;
+
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
+{
+	Packet *packet;
+	// Just a fail-safe.. should never happen
+	if (!_network_udp_server)
+		return;
+
+	packet = NetworkSend_Init(PACKET_UDP_SERVER_RESPONSE);
+
+	// Update some game_info
+	_network_game_info.game_date     = _date;
+	_network_game_info.map_width     = MapSizeX();
+	_network_game_info.map_height    = MapSizeY();
+	_network_game_info.map_set       = _opt.landscape;
+	_network_game_info.companies_on  = ActivePlayerCount();
+	_network_game_info.spectators_on = NetworkSpectatorCount();
+	_network_game_info.grfconfig     = _grfconfig;
+
+	NetworkSend_NetworkGameInfo(packet, &_network_game_info);
+
+	// Let the client know that we are here
+	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
+
+	free(packet);
+
+	DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr));
+}
+
+void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
+{
+	/* Find the matching GRF file */
+	const GRFConfig *f = FindGRFConfig(config->grfid, config->md5sum);
+	if (f == NULL) {
+		/* Don't know the GRF, so mark game incompatible and the (possibly)
+		 * already resolved name for this GRF (another server has sent the
+		 * name of the GRF already */
+		config->name     = FindUnknownGRFName(config->grfid, config->md5sum, true);
+		SETBIT(config->flags, GCF_NOT_FOUND);
+	} else {
+		config->filename = f->filename;
+		config->name     = f->name;
+		config->info     = f->info;
+	}
+	SETBIT(config->flags, GCF_COPY);
+}
+
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
+{
+	extern const char _openttd_revision[];
+	NetworkGameList *item;
+
+	// Just a fail-safe.. should never happen
+	if (_network_udp_server || _udp_cs.has_quit) return;
+
+	DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
+
+	// Find next item
+	item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
+
+	NetworkRecv_NetworkGameInfo(&_udp_cs, p, &item->info);
+
+	item->info.compatible = true;
+	{
+		/* Checks whether there needs to be a request for names of GRFs and makes
+		 * the request if necessary. GRFs that need to be requested are the GRFs
+		 * that do not exist on the clients system and we do not have the name
+		 * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER.
+		 * The in_request array and in_request_count are used so there is no need
+		 * to do a second loop over the GRF list, which can be relatively expensive
+		 * due to the string comparisons. */
+		const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT];
+		const GRFConfig *c;
+		uint in_request_count = 0;
+		struct sockaddr_in out_addr;
+
+		for (c = item->info.grfconfig; c != NULL; c = c->next) {
+			if (HASBIT(c->flags, GCF_NOT_FOUND)) item->info.compatible = false;
+			if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
+			in_request[in_request_count] = c;
+			in_request_count++;
+		}
+
+		if (in_request_count > 0) {
+			/* There are 'unknown' GRFs, now send a request for them */
+			uint i;
+			Packet *packet = NetworkSend_Init(PACKET_UDP_CLIENT_GET_NEWGRFS);
+
+			NetworkSend_uint8 (packet, in_request_count);
+			for (i = 0; i < in_request_count; i++) {
+				NetworkSend_GRFIdentifier(packet, in_request[i]);
+			}
+
+			out_addr.sin_family      = AF_INET;
+			out_addr.sin_port        = htons(item->port);
+			out_addr.sin_addr.s_addr = item->ip;
+			NetworkSendUDP_Packet(_udp_client_socket, packet, &out_addr);
+			free(packet);
+		}
+	}
+
+	if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0;
+	if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0;
+
+	if (item->info.hostname[0] == '\0')
+		snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
+
+	/* Check if we are allowed on this server based on the revision-match */
+	item->info.version_compatible =
+		strcmp(item->info.server_revision, _openttd_revision) == 0 ||
+		strcmp(item->info.server_revision, NOREV_STRING) == 0;
+	item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
+
+	item->online = true;
+
+	UpdateNetworkGameWindow(false);
+}
+
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO)
+{
+	NetworkClientState *cs;
+	NetworkClientInfo *ci;
+	Packet *packet;
+	Player *player;
+	byte current = 0;
+	int i;
+
+	// Just a fail-safe.. should never happen
+	if (!_network_udp_server) return;
+
+	packet = NetworkSend_Init(PACKET_UDP_SERVER_DETAIL_INFO);
+
+	/* Send the amount of active companies */
+	NetworkSend_uint8 (packet, NETWORK_COMPANY_INFO_VERSION);
+	NetworkSend_uint8 (packet, ActivePlayerCount());
+
+	/* Fetch the latest version of everything */
+	NetworkPopulateCompanyInfo();
+
+	/* Go through all the players */
+	FOR_ALL_PLAYERS(player) {
+		/* Skip non-active players */
+		if (!player->is_active) continue;
+
+		current++;
+
+		/* Send the information */
+		NetworkSend_uint8(packet, current);
+
+		NetworkSend_string(packet, _network_player_info[player->index].company_name);
+		NetworkSend_uint32(packet, _network_player_info[player->index].inaugurated_year);
+		NetworkSend_uint64(packet, _network_player_info[player->index].company_value);
+		NetworkSend_uint64(packet, _network_player_info[player->index].money);
+		NetworkSend_uint64(packet, _network_player_info[player->index].income);
+		NetworkSend_uint16(packet, _network_player_info[player->index].performance);
+
+		/* Send 1 if there is a passord for the company else send 0 */
+		if (_network_player_info[player->index].password[0] != '\0') {
+			NetworkSend_uint8(packet, 1);
+		} else {
+			NetworkSend_uint8(packet, 0);
+		}
+
+		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
+			NetworkSend_uint16(packet, _network_player_info[player->index].num_vehicle[i]);
+
+		for (i = 0; i < NETWORK_STATION_TYPES; i++)
+			NetworkSend_uint16(packet, _network_player_info[player->index].num_station[i]);
+
+		/* Find the clients that are connected to this player */
+		FOR_ALL_CLIENTS(cs) {
+			ci = DEREF_CLIENT_INFO(cs);
+			if (ci->client_playas == player->index) {
+				/* The uint8 == 1 indicates that a client is following */
+				NetworkSend_uint8(packet, 1);
+				NetworkSend_string(packet, ci->client_name);
+				NetworkSend_string(packet, ci->unique_id);
+				NetworkSend_uint32(packet, ci->join_date);
+			}
+		}
+		/* Also check for the server itself */
+		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+		if (ci->client_playas == player->index) {
+			/* The uint8 == 1 indicates that a client is following */
+			NetworkSend_uint8(packet, 1);
+			NetworkSend_string(packet, ci->client_name);
+			NetworkSend_string(packet, ci->unique_id);
+			NetworkSend_uint32(packet, ci->join_date);
+		}
+
+		/* Indicates end of client list */
+		NetworkSend_uint8(packet, 0);
+	}
+
+	/* And check if we have any spectators */
+	FOR_ALL_CLIENTS(cs) {
+		ci = DEREF_CLIENT_INFO(cs);
+		if (!IsValidPlayer(ci->client_playas)) {
+			/* The uint8 == 1 indicates that a client is following */
+			NetworkSend_uint8(packet, 1);
+			NetworkSend_string(packet, ci->client_name);
+			NetworkSend_string(packet, ci->unique_id);
+			NetworkSend_uint32(packet, ci->join_date);
+		}
+	}
+
+	/* Also check for the server itself */
+	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
+	if (!IsValidPlayer(ci->client_playas)) {
+		/* The uint8 == 1 indicates that a client is following */
+		NetworkSend_uint8(packet, 1);
+		NetworkSend_string(packet, ci->client_name);
+		NetworkSend_string(packet, ci->unique_id);
+		NetworkSend_uint32(packet, ci->join_date);
+	}
+
+	/* Indicates end of client list */
+	NetworkSend_uint8(packet, 0);
+
+	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
+
+	free(packet);
+}
+
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST)
+{
+	int i;
+	struct in_addr ip;
+	uint16 port;
+	uint8 ver;
+
+	/* packet begins with the protocol version (uint8)
+	 * then an uint16 which indicates how many
+	 * ip:port pairs are in this packet, after that
+	 * an uint32 (ip) and an uint16 (port) for each pair
+	 */
+
+	ver = NetworkRecv_uint8(&_udp_cs, p);
+
+	if (_udp_cs.has_quit) return;
+
+	if (ver == 1) {
+		for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) {
+			ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p));
+			port = NetworkRecv_uint16(&_udp_cs, p);
+			NetworkUDPQueryServer(inet_ntoa(ip), port);
+		}
+	}
+}
+
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER)
+{
+	_network_advertise_retries = 0;
+	DEBUG(net, 2, "[udp] advertising on master server successfull");
+
+	/* We are advertised, but we don't want to! */
+	if (!_network_advertise) NetworkUDPRemoveAdvertise();
+}
+
+/**
+ * A client has requested the names of some NewGRFs.
+ *
+ * Replying this can be tricky as we have a limit of SEND_MTU bytes
+ * in the reply packet and we can send up to 100 bytes per NewGRF
+ * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name).
+ * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it
+ * could be that a packet overflows. To stop this we only reply
+ * with the first N NewGRFs so that if the first N + 1 NewGRFs
+ * would be sent, the packet overflows.
+ * in_reply and in_reply_count are used to keep a list of GRFs to
+ * send in the reply.
+ */
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS)
+{
+	uint8 num_grfs;
+	uint i;
+
+	const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT];
+	Packet *packet;
+	uint8 in_reply_count = 0;
+	uint packet_len = 0;
+
+	/* Just a fail-safe.. should never happen */
+	if (_udp_cs.has_quit) return;
+
+	DEBUG(net, 6, "[udp] newgrf data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
+
+	num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
+	if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
+
+	for (i = 0; i < num_grfs; i++) {
+		GRFConfig c;
+		const GRFConfig *f;
+
+		NetworkRecv_GRFIdentifier(&_udp_cs, p, &c);
+
+		/* Find the matching GRF file */
+		f = FindGRFConfig(c.grfid, c.md5sum);
+		if (f == NULL) continue; // The GRF is unknown to this server
+
+		/* If the reply might exceed the size of the packet, only reply
+		 * the current list and do not send the other data.
+		 * The name could be an empty string, if so take the filename. */
+		packet_len += sizeof(c.grfid) + sizeof(c.md5sum) +
+				min(strlen((f->name != NULL && strlen(f->name) > 0) ? f->name : f->filename) + 1, NETWORK_GRF_NAME_LENGTH);
+		if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
+			break;
+		}
+		in_reply[in_reply_count] = f;
+		in_reply_count++;
+	}
+
+	if (in_reply_count == 0) return;
+
+	packet = NetworkSend_Init(PACKET_UDP_SERVER_NEWGRFS);
+	NetworkSend_uint8 (packet, in_reply_count);
+	for (i = 0; i < in_reply_count; i++) {
+		char name[NETWORK_GRF_NAME_LENGTH];
+
+		/* The name could be an empty string, if so take the filename */
+		ttd_strlcpy(name, (in_reply[i]->name != NULL && strlen(in_reply[i]->name) > 0) ?
+				in_reply[i]->name : in_reply[i]->filename, sizeof(name));
+	 	NetworkSend_GRFIdentifier(packet, in_reply[i]);
+		NetworkSend_string(packet, name);
+	}
+
+	NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
+	free(packet);
+}
+
+/** The return of the client's request of the names of some NewGRFs */
+DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS)
+{
+	uint8 num_grfs;
+	uint i;
+
+	/* Just a fail-safe.. should never happen */
+	if (_udp_cs.has_quit) return;
+
+	DEBUG(net, 6, "[udp] newgrf data reply from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
+
+	num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
+	if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
+
+	for (i = 0; i < num_grfs; i++) {
+		char *unknown_name;
+		char name[NETWORK_GRF_NAME_LENGTH];
+		GRFConfig c;
+
+		NetworkRecv_GRFIdentifier(&_udp_cs, p, &c);
+		NetworkRecv_string(&_udp_cs, p, name, sizeof(name));
+
+		/* An empty name is not possible under normal circumstances
+		 * and causes problems when showing the NewGRF list. */
+		if (strlen(name) == 0) continue;
+
+		/* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple.
+		 * If it exists and not resolved yet, then name of the fake GRF is
+		 * overwritten with the name from the reply. */
+		unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
+		if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
+			ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH);
+		}
+	}
+}
+
+/**
+ * Every type of UDP packet should only be received by a single socket;
+ * The socket communicating with the masterserver should receive the
+ * game information of some 'random' host.
+ */
+typedef struct NetworkUDPPacketAndSocket {
+	void (*callback)(Packet *p, const struct sockaddr_in *client_addr);
+	SOCKET *incoming_socket;
+} NetworkUPDPacketAndSocket;
+
+static const NetworkUPDPacketAndSocket _network_udp_packet[PACKET_UDP_END] = {
+	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER),   &_udp_server_socket },
+	{ RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE),      &_udp_client_socket },
+	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO),   &_udp_server_socket },
+	{ NULL,                                             NULL                },
+	{ NULL,                                             NULL                },
+	{ RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER),  &_udp_master_socket },
+	{ NULL,                                             NULL                },
+	{ RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST), &_udp_client_socket },
+	{ NULL,                                             NULL                },
+	{ RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS),   &_udp_server_socket },
+	{ RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS),       &_udp_client_socket },
+};
+
+void NetworkHandleUDPPacket(const SOCKET udp, Packet *p, const struct sockaddr_in *client_addr)
+{
+	byte type;
+
+	/* Fake a client, so we can see when there is an illegal packet */
+	_udp_cs.socket = INVALID_SOCKET;
+	_udp_cs.has_quit = false;
+
+	type = NetworkRecv_uint8(&_udp_cs, p);
+
+	if (type < PACKET_UDP_END && *_network_udp_packet[type].incoming_socket == udp && !_udp_cs.has_quit) {
+		_network_udp_packet[type].callback(p, client_addr);
+	} else {
+		if (*_network_udp_packet[type].incoming_socket != udp) {
+			DEBUG(net, 0, "[udp] received packet on wrong port from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
+		} else if (!_udp_cs.has_quit) {
+			DEBUG(net, 0, "[udp] received invalid packet type %d from %s:%d", type,  inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
+		} else {
+			DEBUG(net, 0, "[udp] received illegal packet from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
+		}
+	}
+}
+
+
+// Close UDP connection
+void NetworkUDPStop(void)
+{
+	DEBUG(net, 1, "[udp] closed listeners");
+
+	if (_network_udp_server) {
+		NetworkUDPClose(&_udp_server_socket);
+		NetworkUDPClose(&_udp_master_socket);
+	} else {
+		NetworkUDPClose(&_udp_client_socket);
+	}
+
+	_network_udp_server = false;
+	_network_udp_broadcast = 0;
+}
+
+// Broadcast to all ips
+static void NetworkUDPBroadCast(SOCKET udp)
+{
+	Packet* p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER);
+	uint i;
+
+	for (i = 0; _broadcast_list[i] != 0; i++) {
+		struct sockaddr_in out_addr;
+
+		out_addr.sin_family = AF_INET;
+		out_addr.sin_port = htons(_network_server_port);
+		out_addr.sin_addr.s_addr = _broadcast_list[i];
+
+		DEBUG(net, 4, "[udp] broadcasting to %s", inet_ntoa(out_addr.sin_addr));
+
+		NetworkSendUDP_Packet(udp, p, &out_addr);
+	}
+
+	free(p);
+}
+
+
+// Request the the server-list from the master server
+void NetworkUDPQueryMasterServer(void)
+{
+	struct sockaddr_in out_addr;
+	Packet *p;
+
+	if (_udp_client_socket == INVALID_SOCKET)
+		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
+			return;
+
+	p = NetworkSend_Init(PACKET_UDP_CLIENT_GET_LIST);
+
+	out_addr.sin_family = AF_INET;
+	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
+	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
+
+	// packet only contains protocol version
+	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
+
+	NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr);
+
+	DEBUG(net, 2, "[udp] master server queried at %s:%d", inet_ntoa(out_addr.sin_addr),ntohs(out_addr.sin_port));
+
+	free(p);
+}
+
+// Find all servers
+void NetworkUDPSearchGame(void)
+{
+	// We are still searching..
+	if (_network_udp_broadcast > 0) return;
+
+	// No UDP-socket yet..
+	if (_udp_client_socket == INVALID_SOCKET)
+		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
+			return;
+
+	DEBUG(net, 0, "[udp] searching server");
+
+	NetworkUDPBroadCast(_udp_client_socket);
+	_network_udp_broadcast = 300; // Stay searching for 300 ticks
+}
+
+NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port)
+{
+	struct sockaddr_in out_addr;
+	Packet *p;
+	NetworkGameList *item;
+
+	// No UDP-socket yet..
+	if (_udp_client_socket == INVALID_SOCKET)
+		if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true))
+			return NULL;
+
+	out_addr.sin_family = AF_INET;
+	out_addr.sin_port = htons(port);
+	out_addr.sin_addr.s_addr = NetworkResolveHost(host);
+
+	// Clear item in gamelist
+	item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port));
+	memset(&item->info, 0, sizeof(item->info));
+	ttd_strlcpy(item->info.server_name, host, lengthof(item->info.server_name));
+	ttd_strlcpy(item->info.hostname, host, lengthof(item->info.hostname));
+	item->online = false;
+
+	// Init the packet
+	p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER);
+
+	NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr);
+
+	free(p);
+
+	UpdateNetworkGameWindow(false);
+	return item;
+}
+
+/* Remove our advertise from the master-server */
+void NetworkUDPRemoveAdvertise(void)
+{
+	struct sockaddr_in out_addr;
+	Packet *p;
+
+	/* Check if we are advertising */
+	if (!_networking || !_network_server || !_network_udp_server) return;
+
+	/* check for socket */
+	if (_udp_master_socket == INVALID_SOCKET)
+		if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false))
+			return;
+
+	DEBUG(net, 1, "[udp] removing advertise from master server");
+
+	/* Find somewhere to send */
+	out_addr.sin_family = AF_INET;
+	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
+	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
+
+	/* Send the packet */
+	p = NetworkSend_Init(PACKET_UDP_SERVER_UNREGISTER);
+	/* Packet is: Version, server_port */
+	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
+	NetworkSend_uint16(p, _network_server_port);
+	NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr);
+
+	free(p);
+}
+
+/* Register us to the master server
+     This function checks if it needs to send an advertise */
+void NetworkUDPAdvertise(void)
+{
+	struct sockaddr_in out_addr;
+	Packet *p;
+
+	/* Check if we should send an advertise */
+	if (!_networking || !_network_server || !_network_udp_server || !_network_advertise)
+		return;
+
+	/* check for socket */
+	if (_udp_master_socket == INVALID_SOCKET)
+		if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false))
+			return;
+
+	if (_network_need_advertise) {
+		_network_need_advertise = false;
+		_network_advertise_retries = ADVERTISE_RETRY_TIMES;
+	} else {
+		/* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */
+		if (_network_advertise_retries == 0) {
+			if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter)
+				return;
+			_network_advertise_retries = ADVERTISE_RETRY_TIMES;
+		}
+
+		if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter)
+			return;
+	}
+
+	_network_advertise_retries--;
+	_network_last_advertise_frame = _frame_counter;
+
+	/* Find somewhere to send */
+	out_addr.sin_family = AF_INET;
+	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
+	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
+
+	DEBUG(net, 1, "[udp] advertising to master server");
+
+	/* Send the packet */
+	p = NetworkSend_Init(PACKET_UDP_SERVER_REGISTER);
+	/* Packet is: WELCOME_MESSAGE, Version, server_port */
+	NetworkSend_string(p, NETWORK_MASTER_SERVER_WELCOME_MESSAGE);
+	NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION);
+	NetworkSend_uint16(p, _network_server_port);
+	NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr);
+
+	free(p);
+}
+
+void NetworkUDPInitialize(void)
+{
+	_udp_client_socket = INVALID_SOCKET;
+	_udp_server_socket = INVALID_SOCKET;
+	_udp_master_socket = INVALID_SOCKET;
+
+	_network_udp_server = false;
+	_network_udp_broadcast = 0;
+}
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/newgrf.c
+++ /dev/null
@@ -1,3772 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-
-#include <stdarg.h>
-
-#include "openttd.h"
-#include "debug.h"
-#include "gfx.h"
-#include "fileio.h"
-#include "functions.h"
-#include "engine.h"
-#include "spritecache.h"
-#include "station.h"
-#include "sprite.h"
-#include "newgrf.h"
-#include "variables.h"
-#include "string.h"
-#include "table/strings.h"
-#include "bridge.h"
-#include "economy.h"
-#include "newgrf_engine.h"
-#include "vehicle.h"
-#include "newgrf_text.h"
-#include "table/sprites.h"
-#include "fontcache.h"
-#include "date.h"
-#include "currency.h"
-#include "sound.h"
-#include "newgrf_config.h"
-#include "newgrf_sound.h"
-#include "newgrf_spritegroup.h"
-
-/* TTDPatch extended GRF format codec
- * (c) Petr Baudis 2004 (GPL'd)
- * Changes by Florian octo Forster are (c) by the OpenTTD development team.
- *
- * Contains portions of documentation by TTDPatch team.
- * Thanks especially to Josef Drexler for the documentation as well as a lot
- * of help at #tycoon. Also thanks to Michael Blunck for is GRF files which
- * served as subject to the initial testing of this codec. */
-
-
-static int _skip_sprites; // XXX
-static uint _file_index; // XXX
-SpriteID _signal_base;
-SpriteID _coast_base;
-
-static GRFFile *_cur_grffile;
-GRFFile *_first_grffile;
-static SpriteID _cur_spriteid;
-static GrfLoadingStage _cur_stage;
-static uint32 _nfo_line;
-
-static GRFConfig *_cur_grfconfig;
-
-/* Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
-static byte _misc_grf_features = 0;
-
-/* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
-static uint32 _ttdpatch_flags[8];
-
-/* Used by Action 0x06 to preload a pseudo sprite and modify its content */
-static byte *_preload_sprite = NULL;
-
-/* Set if any vehicle is loaded which uses 2cc (two company colours) */
-bool _have_2cc = false;
-
-
-typedef enum GrfDataType {
-	GDT_SOUND,
-} GrfDataType;
-
-static byte _grf_data_blocks;
-static GrfDataType _grf_data_type;
-
-
-typedef enum grfspec_feature {
-	GSF_TRAIN,
-	GSF_ROAD,
-	GSF_SHIP,
-	GSF_AIRCRAFT,
-	GSF_STATION,
-	GSF_CANAL,
-	GSF_BRIDGE,
-	GSF_TOWNHOUSE,
-	GSF_GLOBALVAR,
-	GSF_INDUSTRYTILES,
-	GSF_INDUSTRIES,
-	GSF_CARGOS,
-	GSF_SOUNDFX,
-} grfspec_feature;
-
-
-typedef void (*SpecialSpriteHandler)(byte *buf, int len);
-
-static const int _vehcounts[4] = {
-	/* GSF_TRAIN */    NUM_TRAIN_ENGINES,
-	/* GSF_ROAD */     NUM_ROAD_ENGINES,
-	/* GSF_SHIP */     NUM_SHIP_ENGINES,
-	/* GSF_AIRCRAFT */ NUM_AIRCRAFT_ENGINES
-};
-
-static const int _vehshifts[4] = {
-	/* GSF_TRAIN */    0,
-	/* GSF_ROAD */     ROAD_ENGINES_INDEX,
-	/* GSF_SHIP */     SHIP_ENGINES_INDEX,
-	/* GSF_AIRCRAFT */ AIRCRAFT_ENGINES_INDEX,
-};
-
-enum {
-	MAX_STATIONS = 256,
-};
-
-static uint16 cargo_allowed[TOTAL_NUM_ENGINES];
-static uint16 cargo_disallowed[TOTAL_NUM_ENGINES];
-
-/* Contains the GRF ID of the owner of a vehicle if it has been reserved */
-static uint32 _grm_engines[TOTAL_NUM_ENGINES];
-
-/** DEBUG() function dedicated to newGRF debugging messages
- * Function is essentialy the same as DEBUG(grf, severity, ...) with the
- * addition of file:line information when parsing grf files.
- * NOTE: for the above reason(s) grfmsg() should ONLY be used for
- * loading/parsing grf files, not for runtime debug messages as there
- * is no file information available during that time.
- * @param severity debugging severity level, see debug.h
- * @param debugging message in printf() format */
-void CDECL grfmsg(int severity, const char *str, ...)
-{
-	char buf[1024];
-	va_list va;
-
-	va_start(va, str);
-	vsnprintf(buf, sizeof(buf), str, va);
-	va_end(va);
-
-	DEBUG(grf, severity, "[%s:%d] %s", _cur_grfconfig->filename, _nfo_line, buf);
-}
-
-static inline void check_length(int real, int wanted, const char *str)
-{
-	if (real >= wanted) return;
-	grfmsg(0, "%s: Invalid pseudo sprite length %d (expected %d)!", str, real, wanted);
-}
-
-static inline byte grf_load_byte(byte **buf)
-{
-	return *(*buf)++;
-}
-
-static uint16 grf_load_word(byte **buf)
-{
-	uint16 val = grf_load_byte(buf);
-	return val | (grf_load_byte(buf) << 8);
-}
-
-static uint16 grf_load_extended(byte** buf)
-{
-	uint16 val;
-	val = grf_load_byte(buf);
-	if (val == 0xFF) val = grf_load_word(buf);
-	return val;
-}
-
-static uint32 grf_load_dword(byte **buf)
-{
-	uint32 val = grf_load_word(buf);
-	return val | (grf_load_word(buf) << 16);
-}
-
-static uint32 grf_load_var(byte size, byte **buf)
-{
-	switch (size) {
-		case 1: return grf_load_byte(buf);
-		case 2: return grf_load_word(buf);
-		case 4: return grf_load_dword(buf);
-		default:
-			NOT_REACHED();
-			return 0;
-	}
-}
-
-static GRFFile *GetFileByGRFID(uint32 grfid)
-{
-	GRFFile *file;
-
-	for (file = _first_grffile; file != NULL; file = file->next) {
-		if (file->grfid == grfid) break;
-	}
-	return file;
-}
-
-static GRFFile *GetFileByFilename(const char *filename)
-{
-	GRFFile *file;
-
-	for (file = _first_grffile; file != NULL; file = file->next) {
-		if (strcmp(file->filename, filename) == 0) break;
-	}
-	return file;
-}
-
-
-typedef bool (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
-
-#define FOR_EACH_OBJECT for (i = 0; i < numinfo; i++)
-
-static void dewagonize(int condition, int engine)
-{
-	EngineInfo *ei = &_engine_info[engine];
-	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
-
-	if (condition != 0) {
-		ei->unk2 &= ~0x80;
-		rvi->flags &= ~2;
-	} else {
-		ei->unk2 |= 0x80;
-		rvi->flags |= 2;
-	}
-}
-
-static bool RailVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
-{
-	EngineInfo *ei = &_engine_info[engine];
-	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	switch (prop) {
-		case 0x05: /* Track type */
-			FOR_EACH_OBJECT {
-				uint8 tracktype = grf_load_byte(&buf);
-
-				switch (tracktype) {
-					case 0: ei[i].railtype = rvi[i].engclass == 2 ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL; break;
-					case 1: ei[i].railtype = RAILTYPE_MONO; break;
-					case 2: ei[i].railtype = RAILTYPE_MAGLEV; break;
-					default:
-						grfmsg(1, "RailVehicleChangeInfo: Invalid track type %d specified, ignoring", tracktype);
-						break;
-				}
-			}
-			break;
-
-		case 0x08: /* AI passenger service */
-			/* TODO */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		case 0x09: /* Speed (1 unit is 1 kmh) */
-			FOR_EACH_OBJECT {
-				uint16 speed = grf_load_word(&buf);
-				if (speed == 0xFFFF) speed = 0;
-
-				rvi[i].max_speed = speed;
-			}
-			break;
-
-		case 0x0B: /* Power */
-			FOR_EACH_OBJECT {
-				uint16 power = grf_load_word(&buf);
-
-				if (rvi[i].flags & RVI_MULTIHEAD) power /= 2;
-
-				rvi[i].power = power;
-				dewagonize(power, engine + i);
-			}
-			break;
-
-		case 0x0D: /* Running cost factor */
-			FOR_EACH_OBJECT {
-				uint8 runcostfact = grf_load_byte(&buf);
-
-				if (rvi[i].flags & RVI_MULTIHEAD) runcostfact /= 2;
-
-				rvi[i].running_cost_base = runcostfact;
-			}
-			break;
-
-		case 0x0E: /* Running cost base */
-			FOR_EACH_OBJECT {
-				uint32 base = grf_load_dword(&buf);
-
-				switch (base) {
-					case 0x4C30: rvi[i].running_cost_class = 0; break;
-					case 0x4C36: rvi[i].running_cost_class = 1; break;
-					case 0x4C3C: rvi[i].running_cost_class = 2; break;
-					case 0: break; /* Used by wagons */
-					default:
-						grfmsg(1, "RailVehicleChangeInfo: Unsupported running cost base 0x%04X, ignoring", base);
-						break;
-				}
-			}
-			break;
-
-		case 0x12: /* Sprite ID */
-			FOR_EACH_OBJECT {
-				uint8 spriteid = grf_load_byte(&buf);
-
-				/* TTD sprite IDs point to a location in a 16bit array, but we use it
-				 * as an array index, so we need it to be half the original value. */
-				if (spriteid < 0xFD) spriteid >>= 1;
-
-				rvi[i].image_index = spriteid;
-			}
-			break;
-
-		case 0x13: /* Dual-headed */
-			FOR_EACH_OBJECT {
-				uint8 dual = grf_load_byte(&buf);
-
-				if (dual != 0) {
-					if (!(rvi[i].flags & RVI_MULTIHEAD)) {
-						// adjust power and running cost if needed
-						rvi[i].power /= 2;
-						rvi[i].running_cost_base /= 2;
-					}
-					rvi[i].flags |= RVI_MULTIHEAD;
-				} else {
-					if (rvi[i].flags & RVI_MULTIHEAD) {
-						// adjust power and running cost if needed
-						rvi[i].power *= 2;
-						rvi[i].running_cost_base *= 2;
-					}
-					rvi[i].flags &= ~RVI_MULTIHEAD;
-				}
-			}
-			break;
-
-		case 0x14: /* Cargo capacity */
-			FOR_EACH_OBJECT rvi[i].capacity = grf_load_byte(&buf);
-			break;
-
-		case 0x15: /* Cargo type */
-			FOR_EACH_OBJECT {
-				uint8 ctype = grf_load_byte(&buf);
-
-				if (ctype < NUM_CARGO) {
-					rvi[i].cargo_type = ctype;
-				} else {
-					grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, ignoring", ctype);
-				}
-			}
-			break;
-
-		case 0x16: /* Weight */
-			FOR_EACH_OBJECT SB(rvi[i].weight, 0, 8, grf_load_byte(&buf));
-			break;
-
-		case 0x17: /* Cost factor */
-			FOR_EACH_OBJECT rvi[i].base_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x18: /* AI rank */
-			FOR_EACH_OBJECT rvi[i].ai_rank = grf_load_byte(&buf);
-			break;
-
-		case 0x19: /* Engine traction type */
-			/* What do the individual numbers mean?
-			 * 0x00 .. 0x07: Steam
-			 * 0x08 .. 0x27: Diesel
-			 * 0x28 .. 0x31: Electric
-			 * 0x32 .. 0x37: Monorail
-			 * 0x38 .. 0x41: Maglev
-			 */
-			FOR_EACH_OBJECT {
-				uint8 traction = grf_load_byte(&buf);
-				int engclass;
-
-				if (traction <= 0x07) {
-					engclass = 0;
-				} else if (traction <= 0x27) {
-					engclass = 1;
-				} else if (traction <= 0x31) {
-					engclass = 2;
-				} else if (traction <= 0x41) {
-					engclass = 2;
-				} else {
-					break;
-				}
-				if (ei[i].railtype == RAILTYPE_RAIL     && engclass == 2) ei[i].railtype = RAILTYPE_ELECTRIC;
-				if (ei[i].railtype == RAILTYPE_ELECTRIC && engclass != 2) ei[i].railtype = RAILTYPE_RAIL;
-
-				rvi[i].engclass = engclass;
-			}
-			break;
-
-		case 0x1A: /* Alter purchase list sort order */
-			FOR_EACH_OBJECT {
-				EngineID pos = grf_load_byte(&buf);
-
-				if (pos < NUM_TRAIN_ENGINES) {
-					AlterRailVehListOrder(engine + i, pos);
-				} else {
-					grfmsg(2, "RailVehicleChangeInfo: Invalid train engine ID %d, ignoring", pos);
-				}
-			}
-			break;
-
-		case 0x1B: /* Powered wagons power bonus */
-			FOR_EACH_OBJECT rvi[i].pow_wag_power = grf_load_word(&buf);
-			break;
-
-		case 0x1C: /* Refit cost */
-			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x1D: /* Refit cargo */
-			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
-			break;
-
-		case 0x1E: /* Callback */
-			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
-			break;
-
-		case 0x1F: /* Tractive effort coefficient */
-			FOR_EACH_OBJECT rvi[i].tractive_effort = grf_load_byte(&buf);
-			break;
-
-		case 0x21: /* Shorter vehicle */
-			FOR_EACH_OBJECT rvi[i].shorten_factor = grf_load_byte(&buf);
-			break;
-
-		case 0x22: /* Visual effect */
-			// see note in engine.h about rvi->visual_effect
-			FOR_EACH_OBJECT rvi[i].visual_effect = grf_load_byte(&buf);
-			break;
-
-		case 0x23: /* Powered wagons weight bonus */
-			FOR_EACH_OBJECT rvi[i].pow_wag_weight = grf_load_byte(&buf);
-			break;
-
-		case 0x24: /* High byte of vehicle weight */
-			FOR_EACH_OBJECT {
-				byte weight = grf_load_byte(&buf);
-
-				if (weight > 4) {
-					grfmsg(2, "RailVehicleChangeInfo: Nonsensical weight of %d tons, ignoring", weight << 8);
-				} else {
-					SB(rvi[i].weight, 8, 8, weight);
-				}
-			}
-			break;
-
-		case 0x25: /* User-defined bit mask to set when checking veh. var. 42 */
-			FOR_EACH_OBJECT rvi[i].user_def_data = grf_load_byte(&buf);
-			break;
-
-		case 0x27: /* Miscellaneous flags */
-			FOR_EACH_OBJECT {
-				ei[i].misc_flags = grf_load_byte(&buf);
-				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
-			}
-			break;
-
-		case 0x28: /* Cargo classes allowed */
-			FOR_EACH_OBJECT cargo_allowed[engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x29: /* Cargo classes disallowed */
-			FOR_EACH_OBJECT cargo_disallowed[engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x2A: /* Long format introduction date (days since year 0) */
-			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
-			break;
-
-		/* TODO */
-		/* Fall-through for unimplemented one byte long properties. */
-		case 0x20: /* Air drag */
-		case 0x26: /* Retire vehicle early */
-			/* TODO */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		default:
-			ret = true;
-			break;
-	}
-	*bufp = buf;
-	return ret;
-}
-
-static bool RoadVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
-{
-	EngineInfo *ei = &_engine_info[ROAD_ENGINES_INDEX + engine];
-	RoadVehicleInfo *rvi = &_road_vehicle_info[engine];
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	switch (prop) {
-		case 0x08: /* Speed (1 unit is 0.5 kmh) */
-			FOR_EACH_OBJECT rvi[i].max_speed = grf_load_byte(&buf);
-			break;
-
-		case 0x09: /* Running cost factor */
-			FOR_EACH_OBJECT rvi[i].running_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x0A: /* Running cost base */
-			/* TODO: I have no idea. --pasky */
-			FOR_EACH_OBJECT grf_load_dword(&buf);
-			ret = true;
-			break;
-
-		case 0x0E: /* Sprite ID */
-			FOR_EACH_OBJECT {
-				uint8 spriteid = grf_load_byte(&buf);
-
-				// cars have different custom id in the GRF file
-				if (spriteid == 0xFF) spriteid = 0xFD;
-
-				if (spriteid < 0xFD) spriteid >>= 1;
-
-				rvi[i].image_index = spriteid;
-			}
-			break;
-
-		case 0x0F: /* Cargo capacity */
-			FOR_EACH_OBJECT rvi[i].capacity = grf_load_byte(&buf);
-			break;
-
-		case 0x10: /* Cargo type */
-			FOR_EACH_OBJECT {
-				uint8 cargo = grf_load_byte(&buf);
-
-				if (cargo < NUM_CARGO) {
-					rvi[i].cargo_type = cargo;
-				} else {
-					grfmsg(2, "RoadVehicleChangeInfo: Invalid cargo type %d, ignoring", cargo);
-				}
-			}
-			break;
-
-		case 0x11: /* Cost factor */
-			FOR_EACH_OBJECT rvi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
-			break;
-
-		case 0x12: /* SFX */
-			FOR_EACH_OBJECT rvi[i].sfx = grf_load_byte(&buf);
-			break;
-
-		case 0x13: /* Power in 10hp */
-		case 0x14: /* Weight in 1/4 tons */
-		case 0x15: /* Speed in mph*0.8 */
-			/* TODO: Support for road vehicles realistic power
-			 * computations (called rvpower in TTDPatch) is just
-			 * missing in OTTD yet. --pasky */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		case 0x16: /* Cargos available for refitting */
-			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
-			break;
-
-		case 0x17: /* Callback mask */
-			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
-			break;
-
-		case 0x1A: /* Refit cost */
-			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x1C: /* Miscellaneous flags */
-			FOR_EACH_OBJECT {
-				ei[i].misc_flags = grf_load_byte(&buf);
-				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
-			}
-			break;
-
-		case 0x1D: /* Cargo classes allowed */
-			FOR_EACH_OBJECT cargo_allowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x1E: /* Cargo classes disallowed */
-			FOR_EACH_OBJECT cargo_disallowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x1F: /* Long format introduction date (days since year 0) */
-			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
-			break;
-
-		case 0x18: /* Tractive effort */
-		case 0x19: /* Air drag */
-		case 0x1B: /* Retire vehicle early */
-			/* TODO */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		default:
-			ret = true;
-			break;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool ShipVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
-{
-	EngineInfo *ei = &_engine_info[SHIP_ENGINES_INDEX + engine];
-	ShipVehicleInfo *svi = &_ship_vehicle_info[engine];
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	//printf("e %x prop %x?\n", engine, prop);
-	switch (prop) {
-		case 0x08: /* Sprite ID */
-			FOR_EACH_OBJECT {
-				uint8 spriteid = grf_load_byte(&buf);
-
-				// ships have different custom id in the GRF file
-				if (spriteid == 0xFF) spriteid = 0xFD;
-
-				if (spriteid < 0xFD) spriteid >>= 1;
-
-				svi[i].image_index = spriteid;
-			}
-			break;
-
-		case 0x09: /* Refittable */
-			FOR_EACH_OBJECT svi[i].refittable = grf_load_byte(&buf);
-			break;
-
-		case 0x0A: /* Cost factor */
-			FOR_EACH_OBJECT svi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
-			break;
-
-		case 0x0B: /* Speed (1 unit is 0.5 kmh) */
-			FOR_EACH_OBJECT svi[i].max_speed = grf_load_byte(&buf);
-			break;
-
-		case 0x0C: /* Cargo type */
-			FOR_EACH_OBJECT {
-				uint8 cargo = grf_load_byte(&buf);
-
-				// XXX: Need to consult this with patchman yet.
-#if 0
-				// Documentation claims this is already the
-				// per-landscape cargo type id, but newships.grf
-				// assume otherwise.
-				cargo = local_cargo_id_ctype[cargo];
-#endif
-				if (cargo < NUM_CARGO) {
-					svi[i].cargo_type = cargo;
-				} else {
-					grfmsg(2, "ShipVehicleChangeInfo: Invalid cargo type %d, ignoring", cargo);
-				}
-			}
-			break;
-
-		case 0x0D: /* Cargo capacity */
-			FOR_EACH_OBJECT svi[i].capacity = grf_load_word(&buf);
-			break;
-
-		case 0x0F: /* Running cost factor */
-			FOR_EACH_OBJECT svi[i].running_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x10: /* SFX */
-			FOR_EACH_OBJECT svi[i].sfx = grf_load_byte(&buf);
-			break;
-
-		case 0x11: /* Cargos available for refitting */
-			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
-			break;
-
-		case 0x12: /* Callback mask */
-			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
-			break;
-
-		case 0x13: /* Refit cost */
-			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x17: /* Miscellaneous flags */
-			FOR_EACH_OBJECT {
-				ei[i].misc_flags = grf_load_byte(&buf);
-				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
-			}
-			break;
-
-		case 0x18: /* Cargo classes allowed */
-			FOR_EACH_OBJECT cargo_allowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x19: /* Cargo classes disallowed */
-			FOR_EACH_OBJECT cargo_disallowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x1A: /* Long format introduction date (days since year 0) */
-			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
-			break;
-
-		case 0x14: /* Ocean speed fraction */
-		case 0x15: /* Canal speed fraction */
-		case 0x16: /* Retire vehicle early */
-			/* TODO */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		default:
-			ret = true;
-			break;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
-{
-	EngineInfo *ei = &_engine_info[AIRCRAFT_ENGINES_INDEX + engine];
-	AircraftVehicleInfo *avi = &_aircraft_vehicle_info[engine];
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	//printf("e %x prop %x?\n", engine, prop);
-	switch (prop) {
-		case 0x08: /* Sprite ID */
-			FOR_EACH_OBJECT {
-				uint8 spriteid = grf_load_byte(&buf);
-
-				// aircraft have different custom id in the GRF file
-				if (spriteid == 0xFF) spriteid = 0xFD;
-
-				if (spriteid < 0xFD) spriteid >>= 1;
-
-				avi[i].image_index = spriteid;
-			}
-			break;
-
-		case 0x09: /* Helicopter */
-			FOR_EACH_OBJECT {
-				if (grf_load_byte(&buf) == 0) {
-					avi[i].subtype = 0;
-				} else {
-					SB(avi[i].subtype, 0, 1, 1);
-				}
-			}
-			break;
-
-		case 0x0A: /* Large */
-			FOR_EACH_OBJECT SB(avi[i].subtype, 1, 1, (grf_load_byte(&buf) != 0 ? 1 : 0));
-			break;
-
-		case 0x0B: /* Cost factor */
-			FOR_EACH_OBJECT avi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
-			break;
-
-		case 0x0C: /* Speed (1 unit is 8 mph) */
-			FOR_EACH_OBJECT avi[i].max_speed = grf_load_byte(&buf);
-			break;
-
-		case 0x0D: /* Acceleration */
-			FOR_EACH_OBJECT avi[i].acceleration = grf_load_byte(&buf);
-			break;
-
-		case 0x0E: /* Running cost factor */
-			FOR_EACH_OBJECT avi[i].running_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x0F: /* Passenger capacity */
-			FOR_EACH_OBJECT avi[i].passenger_capacity = grf_load_word(&buf);
-			break;
-
-		case 0x11: /* Mail capacity */
-			FOR_EACH_OBJECT avi[i].mail_capacity = grf_load_byte(&buf);
-			break;
-
-		case 0x12: /* SFX */
-			FOR_EACH_OBJECT avi[i].sfx = grf_load_byte(&buf);
-			break;
-
-		case 0x13: /* Cargos available for refitting */
-			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
-			break;
-
-		case 0x14: /* Callback mask */
-			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
-			break;
-
-		case 0x15: /* Refit cost */
-			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
-			break;
-
-		case 0x17: /* Miscellaneous flags */
-			FOR_EACH_OBJECT {
-				ei[i].misc_flags = grf_load_byte(&buf);
-				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
-			}
-			break;
-
-		case 0x18: /* Cargo classes allowed */
-			FOR_EACH_OBJECT cargo_allowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x19: /* Cargo classes disallowed */
-			FOR_EACH_OBJECT cargo_disallowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
-			break;
-
-		case 0x1A: /* Long format introduction date (days since year 0) */
-			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
-			break;
-
-		case 0x16: /* Retire vehicle early */
-			/* TODO */
-			FOR_EACH_OBJECT grf_load_byte(&buf);
-			ret = true;
-			break;
-
-		default:
-			ret = true;
-			break;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
-{
-	StationSpec **statspec;
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	if (stid + numinfo > MAX_STATIONS) {
-		grfmsg(1, "StationChangeInfo: Station %u is invalid, max %u, ignoring", stid + numinfo, MAX_STATIONS);
-		return false;
-	}
-
-	/* Allocate station specs if necessary */
-	if (_cur_grffile->stations == NULL) _cur_grffile->stations = calloc(MAX_STATIONS, sizeof(*_cur_grffile->stations));
-
-	statspec = &_cur_grffile->stations[stid];
-
-	if (prop != 0x08) {
-		/* Check that all stations we are modifying are defined. */
-		FOR_EACH_OBJECT {
-			if (statspec[i] == NULL) {
-				grfmsg(2, "StationChangeInfo: Attempt to modify undefined station %u, ignoring", stid + i);
-				return false;
-			}
-		}
-	}
-
-	switch (prop) {
-		case 0x08: /* Class ID */
-			FOR_EACH_OBJECT {
-				uint32 classid;
-
-				/* Property 0x08 is special; it is where the station is allocated */
-				if (statspec[i] == NULL) statspec[i] = calloc(1, sizeof(*statspec[i]));
-
-				/* Swap classid because we read it in BE meaning WAYP or DFLT */
-				classid = grf_load_dword(&buf);
-				statspec[i]->sclass = AllocateStationClass(BSWAP32(classid));
-			}
-			break;
-
-		case 0x09: /* Define sprite layout */
-			FOR_EACH_OBJECT {
-				StationSpec *statspec = _cur_grffile->stations[stid + i];
-				uint t;
-
-				statspec->tiles = grf_load_extended(&buf);
-				statspec->renderdata = calloc(statspec->tiles, sizeof(*statspec->renderdata));
-				statspec->copied_renderdata = false;
-
-				for (t = 0; t < statspec->tiles; t++) {
-					DrawTileSprites *dts = &statspec->renderdata[t];
-					uint seq_count = 0;
-
-					dts->seq = NULL;
-					dts->ground_sprite = grf_load_dword(&buf);
-					if (dts->ground_sprite == 0) continue;
-
-					while (buf < *bufp + len) {
-						DrawTileSeqStruct *dtss;
-
-						// no relative bounding box support
-						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
-						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
-
-						dtss->delta_x = grf_load_byte(&buf);
-						if ((byte) dtss->delta_x == 0x80) break;
-						dtss->delta_y = grf_load_byte(&buf);
-						dtss->delta_z = grf_load_byte(&buf);
-						dtss->size_x = grf_load_byte(&buf);
-						dtss->size_y = grf_load_byte(&buf);
-						dtss->size_z = grf_load_byte(&buf);
-						dtss->image = grf_load_dword(&buf);
-
-						/* Remap flags as ours collide */
-						if (HASBIT(dtss->image, 31)) {
-							CLRBIT(dtss->image, 31);
-							SETBIT(dtss->image, 30);
-						}
-						if (HASBIT(dtss->image, 14)) {
-							CLRBIT(dtss->image, 14);
-							SETBIT(dtss->image, 31);
-						}
-					}
-				}
-			}
-			break;
-
-		case 0x0A: /* Copy sprite layout */
-			FOR_EACH_OBJECT {
-				StationSpec *statspec = _cur_grffile->stations[stid + i];
-				byte srcid = grf_load_byte(&buf);
-				const StationSpec *srcstatspec = _cur_grffile->stations[srcid];
-
-				statspec->tiles = srcstatspec->tiles;
-				statspec->renderdata = srcstatspec->renderdata;
-				statspec->copied_renderdata = true;
-			}
-			break;
-
-		case 0x0B: /* Callback mask */
-			FOR_EACH_OBJECT statspec[i]->callbackmask = grf_load_byte(&buf);
-			break;
-
-		case 0x0C: /* Disallowed number of platforms */
-			FOR_EACH_OBJECT statspec[i]->disallowed_platforms = grf_load_byte(&buf);
-			break;
-
-		case 0x0D: /* Disallowed platform lengths */
-			FOR_EACH_OBJECT statspec[i]->disallowed_lengths = grf_load_byte(&buf);
-			break;
-
-		case 0x0E: /* Define custom layout */
-			FOR_EACH_OBJECT {
-				StationSpec *statspec = _cur_grffile->stations[stid + i];
-
-				statspec->copied_layouts = false;
-
-				while (buf < *bufp + len) {
-					byte length = grf_load_byte(&buf);
-					byte number = grf_load_byte(&buf);
-					StationLayout layout;
-					uint l, p;
-
-					if (length == 0 || number == 0) break;
-
-					//debug("l %d > %d ?", length, stat->lengths);
-					if (length > statspec->lengths) {
-						statspec->platforms = realloc(statspec->platforms, length);
-						memset(statspec->platforms + statspec->lengths, 0, length - statspec->lengths);
-
-						statspec->layouts = realloc(statspec->layouts, length * sizeof(*statspec->layouts));
-						memset(statspec->layouts + statspec->lengths, 0,
-						       (length - statspec->lengths) * sizeof(*statspec->layouts));
-
-						statspec->lengths = length;
-					}
-					l = length - 1; // index is zero-based
-
-					//debug("p %d > %d ?", number, stat->platforms[l]);
-					if (number > statspec->platforms[l]) {
-						statspec->layouts[l] = realloc(statspec->layouts[l],
-						                               number * sizeof(**statspec->layouts));
-						// We expect NULL being 0 here, but C99 guarantees that.
-						memset(statspec->layouts[l] + statspec->platforms[l], 0,
-						       (number - statspec->platforms[l]) * sizeof(**statspec->layouts));
-
-						statspec->platforms[l] = number;
-					}
-
-					p = 0;
-					layout = malloc(length * number);
-					for (l = 0; l < length; l++) {
-						for (p = 0; p < number; p++) {
-							layout[l * number + p] = grf_load_byte(&buf);
-						}
-					}
-
-					l--;
-					p--;
-					free(statspec->layouts[l][p]);
-					statspec->layouts[l][p] = layout;
-				}
-			}
-			break;
-
-		case 0x0F: /* Copy custom layout */
-			FOR_EACH_OBJECT {
-				StationSpec *statspec = _cur_grffile->stations[stid + i];
-				byte srcid = grf_load_byte(&buf);
-				const StationSpec *srcstatspec = _cur_grffile->stations[srcid];
-
-				statspec->lengths   = srcstatspec->lengths;
-				statspec->platforms = srcstatspec->platforms;
-				statspec->layouts   = srcstatspec->layouts;
-				statspec->copied_layouts = true;
-			}
-			break;
-
-		case 0x10: /* Little/lots cargo threshold */
-			FOR_EACH_OBJECT statspec[i]->cargo_threshold = grf_load_word(&buf);
-			break;
-
-		case 0x11: /* Pylon placement */
-			FOR_EACH_OBJECT statspec[i]->pylons = grf_load_byte(&buf);
-			break;
-
-		case 0x12: /* Cargo types for random triggers */
-			FOR_EACH_OBJECT statspec[i]->cargo_triggers = grf_load_dword(&buf);
-			break;
-
-		case 0x13: /* General flags */
-			FOR_EACH_OBJECT statspec[i]->flags = grf_load_byte(&buf);
-			break;
-
-		case 0x14: /* Overhead wire placement */
-			FOR_EACH_OBJECT statspec[i]->wires = grf_load_byte(&buf);
-			break;
-
-		case 0x15: /* Blocked tiles */
-			FOR_EACH_OBJECT statspec[i]->blocked = grf_load_byte(&buf);
-			break;
-
-		default:
-			ret = true;
-			break;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool BridgeChangeInfo(uint brid, int numinfo, int prop, byte **bufp, int len)
-{
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	switch (prop) {
-		case 0x08: /* Year of availability */
-			FOR_EACH_OBJECT _bridge[brid + i].avail_year = ORIGINAL_BASE_YEAR + grf_load_byte(&buf);
-			break;
-
-		case 0x09: /* Minimum length */
-			FOR_EACH_OBJECT _bridge[brid + i].min_length = grf_load_byte(&buf);
-			break;
-
-		case 0x0A: /* Maximum length */
-			FOR_EACH_OBJECT _bridge[brid + i].max_length = grf_load_byte(&buf);
-			break;
-
-		case 0x0B: /* Cost factor */
-			FOR_EACH_OBJECT _bridge[brid + i].price = grf_load_byte(&buf);
-			break;
-
-		case 0x0C: /* Maximum speed */
-			FOR_EACH_OBJECT _bridge[brid + i].speed = grf_load_word(&buf);
-			break;
-
-		case 0x0D: /* Bridge sprite tables */
-			FOR_EACH_OBJECT {
-				Bridge *bridge = &_bridge[brid + i];
-				byte tableid = grf_load_byte(&buf);
-				byte numtables = grf_load_byte(&buf);
-
-				if (bridge->sprite_table == NULL) {
-					/* Allocate memory for sprite table pointers and zero out */
-					bridge->sprite_table = calloc(7, sizeof(*bridge->sprite_table));
-				}
-
-				for (; numtables-- != 0; tableid++) {
-					byte sprite;
-
-					if (tableid >= 7) { // skip invalid data
-						grfmsg(1, "BridgeChangeInfo: Table %d >= 7, skipping", tableid);
-						for (sprite = 0; sprite < 32; sprite++) grf_load_dword(&buf);
-						continue;
-					}
-
-					if (bridge->sprite_table[tableid] == NULL) {
-						bridge->sprite_table[tableid] = malloc(32 * sizeof(**bridge->sprite_table));
-					}
-
-					for (sprite = 0; sprite < 32; sprite++)
-						bridge->sprite_table[tableid][sprite] = grf_load_dword(&buf);
-				}
-			}
-			break;
-
-		case 0x0E: /* Flags; bit 0 - disable far pillars */
-			FOR_EACH_OBJECT _bridge[brid + i].flags = grf_load_byte(&buf);
-			break;
-
-		case 0x0F: /* Long format year of availability (year since year 0) */
-			FOR_EACH_OBJECT _bridge[brid + i].avail_year = clamp(grf_load_dword(&buf), MIN_YEAR, MAX_YEAR);
-			break;
-
-		default:
-			ret = true;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, int len)
-{
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	switch (prop) {
-		case 0x08: /* Cost base factor */
-			FOR_EACH_OBJECT {
-				byte factor = grf_load_byte(&buf);
-				uint price = gvid + i;
-
-				if (price < NUM_PRICES) {
-					SetPriceBaseMultiplier(price, factor);
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Price %d out of range, ignoring", price);
-				}
-			}
-			break;
-
-		case 0x0A: // Currency display names
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				StringID newone = GetGRFStringID(_cur_grffile->grfid, grf_load_word(&buf));
-
-				if ((newone != STR_UNDEFINED) && (curidx < NUM_CURRENCY)) {
-					_currency_specs[curidx].name = newone;
-				}
-			}
-			break;
-
-		case 0x0B: // Currency multipliers
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				uint32 rate = grf_load_dword(&buf);
-
-				if (curidx < NUM_CURRENCY) {
-					/* TTDPatch uses a multiple of 1000 for its conversion calculations,
-					 * which OTTD does not. For this reason, divide grf value by 1000,
-					 * to be compatible */
-					_currency_specs[curidx].rate = rate / 1000;
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Currency multipliers %d out of range, ignoring", curidx);
-				}
-			}
-			break;
-
-		case 0x0C: // Currency options
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				uint16 options = grf_load_word(&buf);
-
-				if (curidx < NUM_CURRENCY) {
-					_currency_specs[curidx].separator = GB(options, 0, 8);
-					/* By specifying only one bit, we prevent errors,
-					 * since newgrf specs said that only 0 and 1 can be set for symbol_pos */
-					_currency_specs[curidx].symbol_pos = GB(options, 8, 1);
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Currency option %d out of range, ignoring", curidx);
-				}
-			}
-			break;
-
-		case 0x0D: // Currency prefix symbol
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				uint32 tempfix = grf_load_dword(&buf);
-
-				if (curidx < NUM_CURRENCY) {
-					memcpy(_currency_specs[curidx].prefix,&tempfix,4);
-					_currency_specs[curidx].prefix[4] = 0;
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
-				}
-			}
-			break;
-
-		case 0x0E: // Currency suffix symbol
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				uint32 tempfix = grf_load_dword(&buf);
-
-				if (curidx < NUM_CURRENCY) {
-					memcpy(&_currency_specs[curidx].suffix,&tempfix,4);
-					_currency_specs[curidx].suffix[4] = 0;
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
-				}
-			}
-			break;
-
-		case 0x0F: //  Euro introduction dates
-			FOR_EACH_OBJECT {
-				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
-				Year year_euro = grf_load_word(&buf);
-
-				if (curidx < NUM_CURRENCY) {
-					_currency_specs[curidx].to_euro = year_euro;
-				} else {
-					grfmsg(1, "GlobalVarChangeInfo: Euro intro date %d out of range, ignoring", curidx);
-				}
-			}
-			break;
-
-		case 0x09: // Cargo translation table
-		case 0x10: // 12 * 32 * B Snow line height table
-		default:
-			ret = true;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-static bool SoundEffectChangeInfo(uint sid, int numinfo, int prop, byte **bufp, int len)
-{
-	byte *buf = *bufp;
-	int i;
-	bool ret = false;
-
-	if (_cur_grffile->sound_offset == 0) {
-		grfmsg(1, "SoundEffectChangeInfo: No effects defined, skipping");
-		return false;
-	}
-
-	switch (prop) {
-		case 0x08: /* Relative volume */
-			FOR_EACH_OBJECT {
-				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
-
-				if (sound >= GetNumSounds()) {
-					grfmsg(1, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
-				} else {
-					GetSound(sound)->volume = grf_load_byte(&buf);
-				}
-			}
-			break;
-
-		case 0x09: /* Priority */
-			FOR_EACH_OBJECT {
-				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
-
-				if (sound >= GetNumSounds()) {
-					grfmsg(1, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
-				} else {
-					GetSound(sound)->priority = grf_load_byte(&buf);
-				}
-			}
-			break;
-
-		case 0x0A: /* Override old sound */
-			FOR_EACH_OBJECT {
-				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
-				uint orig_sound = grf_load_byte(&buf);
-
-				if (sound >= GetNumSounds() || orig_sound >= GetNumSounds()) {
-					grfmsg(1, "SoundEffectChangeInfo: Sound %d or %d not defined (max %d)", sound, orig_sound, GetNumSounds());
-				} else {
-					FileEntry *newfe = GetSound(sound);
-					FileEntry *oldfe = GetSound(orig_sound);
-
-					/* Literally copy the data of the new sound over the original */
-					*oldfe = *newfe;
-				}
-			}
-			break;
-
-		default:
-			ret = true;
-	}
-
-	*bufp = buf;
-	return ret;
-}
-
-/* Action 0x00 */
-static void FeatureChangeInfo(byte *buf, int len)
-{
-	byte *bufend = buf + len;
-	int i;
-
-	/* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
-	 *
-	 * B feature       0, 1, 2 or 3 for trains, road vehicles, ships or planes
-	 *                 4 for defining new train station sets
-	 * B num-props     how many properties to change per vehicle/station
-	 * B num-info      how many vehicles/stations to change
-	 * B id            ID of first vehicle/station to change, if num-info is
-	 *                 greater than one, this one and the following
-	 *                 vehicles/stations will be changed
-	 * B property      what property to change, depends on the feature
-	 * V new-info      new bytes of info (variable size; depends on properties) */
-	/* TODO: Bridges, town houses. */
-
-	static const VCI_Handler handler[] = {
-		/* GSF_TRAIN */        RailVehicleChangeInfo,
-		/* GSF_ROAD */         RoadVehicleChangeInfo,
-		/* GSF_SHIP */         ShipVehicleChangeInfo,
-		/* GSF_AIRCRAFT */     AircraftVehicleChangeInfo,
-		/* GSF_STATION */      StationChangeInfo,
-		/* GSF_CANAL */        NULL,
-		/* GSF_BRIDGE */       BridgeChangeInfo,
-		/* GSF_TOWNHOUSE */    NULL,
-		/* GSF_GLOBALVAR */    GlobalVarChangeInfo,
-		/* GSF_INDUSTRYTILES */NULL,
-		/* GSF_INDUSTRIES */   NULL,
-		/* GSF_CARGOS */       NULL,
-		/* GSF_SOUNDFX */      SoundEffectChangeInfo,
-	};
-
-	uint8 feature;
-	uint8 numprops;
-	uint8 numinfo;
-	byte engine;
-	EngineInfo *ei = NULL;
-
-	if (len == 1) {
-		grfmsg(8, "Silently ignoring one-byte special sprite 0x00");
-		return;
-	}
-
-	check_length(len, 6, "FeatureChangeInfo");
-	buf++;
-	feature  = grf_load_byte(&buf);
-	numprops = grf_load_byte(&buf);
-	numinfo  = grf_load_byte(&buf);
-	engine   = grf_load_byte(&buf);
-
-	grfmsg(6, "FeatureChangeInfo: feature %d, %d properties, to apply to %d+%d",
-	               feature, numprops, engine, numinfo);
-
-	if (feature >= lengthof(handler) || handler[feature] == NULL) {
-		grfmsg(1, "FeatureChangeInfo: Unsupported feature %d, skipping", feature);
-		return;
-	}
-
-	if (feature <= GSF_AIRCRAFT) {
-		if (engine + numinfo > _vehcounts[feature]) {
-			grfmsg(0, "FeatureChangeInfo: Last engine ID %d out of bounds (max %d), skipping", engine + numinfo, _vehcounts[feature]);
-			return;
-		}
-		ei = &_engine_info[engine + _vehshifts[feature]];
-	}
-
-	while (numprops-- && buf < bufend) {
-		uint8 prop = grf_load_byte(&buf);
-		bool ignoring = false;
-
-		switch (feature) {
-			case GSF_TRAIN:
-			case GSF_ROAD:
-			case GSF_SHIP:
-			case GSF_AIRCRAFT:
-				/* Common properties for vehicles */
-				switch (prop) {
-					case 0x00: /* Introduction date */
-						FOR_EACH_OBJECT ei[i].base_intro = grf_load_word(&buf) + DAYS_TILL_ORIGINAL_BASE_YEAR;
-						break;
-
-					case 0x02: /* Decay speed */
-						FOR_EACH_OBJECT SB(ei[i].unk2, 0, 7, grf_load_byte(&buf) & 0x7F);
-						break;
-
-					case 0x03: /* Vehicle life */
-						FOR_EACH_OBJECT ei[i].lifelength = grf_load_byte(&buf);
-						break;
-
-					case 0x04: /* Model life */
-						FOR_EACH_OBJECT ei[i].base_life = grf_load_byte(&buf);
-						break;
-
-					case 0x06: /* Climates available */
-						FOR_EACH_OBJECT ei[i].climates = grf_load_byte(&buf);
-						break;
-
-					case 0x07: /* Loading speed */
-						/* Hyronymus explained me what does
-						 * this mean and insists on having a
-						 * credit ;-). --pasky */
-						FOR_EACH_OBJECT ei[i].load_amount = grf_load_byte(&buf);
-						break;
-
-					default:
-						if (handler[feature](engine, numinfo, prop, &buf, bufend - buf))
-							ignoring = true;
-						break;
-				}
-				break;
-
-			default:
-				if (handler[feature](engine, numinfo, prop, &buf, bufend - buf))
-					ignoring = true;
-				break;
-		}
-
-		if (ignoring) grfmsg(2, "FeatureChangeInfo: Ignoring property 0x%02X (not implemented)", prop);
-	}
-}
-
-/* Action 0x00 (GLS_SAFETYSCAN) */
-static void SafeChangeInfo(byte *buf, int len)
-{
-	uint8 feature;
-	uint8 numprops;
-	uint8 numinfo;
-	uint8 index;
-
-	check_length(len, 6, "SafeChangeInfo");
-	buf++;
-	feature  = grf_load_byte(&buf);
-	numprops = grf_load_byte(&buf);
-	numinfo  = grf_load_byte(&buf);
-	index    = grf_load_byte(&buf);
-
-	if (feature == GSF_BRIDGE && numprops == 1) {
-		uint8 prop = grf_load_byte(&buf);
-		/* Bridge property 0x0D is redefinition of sprite layout tables, which
-		 * is considered safe. */
-		if (prop == 0x0D) return;
-	}
-
-	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
-
-	/* Skip remainder of GRF */
-	_skip_sprites = -1;
-}
-
-#undef FOR_EACH_OBJECT
-
-/**
- * Creates a spritegroup representing a callback result
- * @param value The value that was used to represent this callback result
- * @return A spritegroup representing that callback result
- */
-static const SpriteGroup* NewCallBackResultSpriteGroup(uint16 value)
-{
-	SpriteGroup *group = AllocateSpriteGroup();
-
-	group->type = SGT_CALLBACK;
-
-	// Old style callback results have the highest byte 0xFF so signify it is a callback result
-	// New style ones only have the highest bit set (allows 15-bit results, instead of just 8)
-	if ((value >> 8) == 0xFF) {
-		value &= ~0xFF00;
-	} else {
-		value &= ~0x8000;
-	}
-
-	group->g.callback.result = value;
-
-	return group;
-}
-
-/**
- * Creates a spritegroup representing a sprite number result.
- * @param value The sprite number.
- * @param sprites The number of sprites per set.
- * @return A spritegroup representing the sprite number result.
- */
-static const SpriteGroup* NewResultSpriteGroup(SpriteID sprite, byte num_sprites)
-{
-	SpriteGroup *group = AllocateSpriteGroup();
-	group->type = SGT_RESULT;
-	group->g.result.sprite = sprite;
-	group->g.result.num_sprites = num_sprites;
-	return group;
-}
-
-/* Action 0x01 */
-static void NewSpriteSet(byte *buf, int len)
-{
-	/* <01> <feature> <num-sets> <num-ent>
-	 *
-	 * B feature       feature to define sprites for
-	 *                 0, 1, 2, 3: veh-type, 4: train stations
-	 * B num-sets      number of sprite sets
-	 * E num-ent       how many entries per sprite set
-	 *                 For vehicles, this is the number of different
-	 *                         vehicle directions in each sprite set
-	 *                         Set num-dirs=8, unless your sprites are symmetric.
-	 *                         In that case, use num-dirs=4.
-	 *                 For stations, must be 12 (hex) for the eighteen
-	 *                         different sprites that make up a station */
-	/* TODO: No stations support. */
-	uint8 feature;
-	uint num_sets;
-	uint num_ents;
-	uint i;
-
-	check_length(len, 4, "NewSpriteSet");
-	buf++;
-	feature  = grf_load_byte(&buf);
-	num_sets = grf_load_byte(&buf);
-	num_ents = grf_load_extended(&buf);
-
-	_cur_grffile->spriteset_start = _cur_spriteid;
-	_cur_grffile->spriteset_feature = feature;
-	_cur_grffile->spriteset_numsets = num_sets;
-	_cur_grffile->spriteset_numents = num_ents;
-
-	grfmsg(7, "New sprite set at %d of type %d, consisting of %d sets with %d views each (total %d)",
-		_cur_spriteid, feature, num_sets, num_ents, num_sets * num_ents
-	);
-
-	for (i = 0; i < num_sets * num_ents; i++) {
-		LoadNextSprite(_cur_spriteid++, _file_index);
-		_nfo_line++;
-	}
-}
-
-/* Helper function to either create a callback or link to a previously
- * defined spritegroup. */
-static const SpriteGroup* GetGroupFromGroupID(byte setid, byte type, uint16 groupid)
-{
-	if (HASBIT(groupid, 15)) return NewCallBackResultSpriteGroup(groupid);
-
-	if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
-		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid);
-		return NULL;
-	}
-
-	return _cur_grffile->spritegroups[groupid];
-}
-
-/* Helper function to either create a callback or a result sprite group. */
-static const SpriteGroup* CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid, uint16 num_sprites)
-{
-	if (HASBIT(spriteid, 15)) return NewCallBackResultSpriteGroup(spriteid);
-
-	if (spriteid >= _cur_grffile->spriteset_numsets) {
-		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Sprite set %u invalid, max %u", setid, type, spriteid, _cur_grffile->spriteset_numsets);
-		return NULL;
-	}
-
-	/* Check if the sprite is within range. This can fail if the Action 0x01
-	 * is skipped, as TTDPatch mandates that Action 0x02s must be processed.
-	 * We don't have that rule, but must live by the Patch... */
-	if (_cur_grffile->spriteset_start + spriteid * num_sprites + num_sprites > _cur_spriteid) {
-		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Real Sprite IDs 0x%04X - 0x%04X do not (all) exist (max 0x%04X), leaving empty",
-				setid, type,
-				_cur_grffile->spriteset_start + spriteid * num_sprites,
-				_cur_grffile->spriteset_start + spriteid * num_sprites + num_sprites - 1, _cur_spriteid - 1);
-		return NULL;
-	}
-
-	if (feature != _cur_grffile->spriteset_feature) {
-		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Sprite set feature 0x%02X does not match action feature 0x%02X, skipping",
-				_cur_grffile->spriteset_feature, feature);
-		return NULL;
-	}
-
-	return NewResultSpriteGroup(_cur_grffile->spriteset_start + spriteid * num_sprites, num_sprites);
-}
-
-/* Action 0x02 */
-static void NewSpriteGroup(byte *buf, int len)
-{
-	/* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
-	 *
-	 * B feature       see action 1
-	 * B set-id        ID of this particular definition
-	 * B type/num-entries
-	 *                 if 80 or greater, this is a randomized or variational
-	 *                 list definition, see below
-	 *                 otherwise it specifies a number of entries, the exact
-	 *                 meaning depends on the feature
-	 * V feature-specific-data (huge mess, don't even look it up --pasky) */
-	uint8 feature;
-	uint8 setid;
-	uint8 type;
-	SpriteGroup *group = NULL;
-	byte *bufend = buf + len;
-
-	check_length(len, 5, "NewSpriteGroup");
-	buf++;
-
-	feature = grf_load_byte(&buf);
-	setid   = grf_load_byte(&buf);
-	type    = grf_load_byte(&buf);
-
-	if (setid >= _cur_grffile->spritegroups_count) {
-		// Allocate memory for new sprite group references.
-		_cur_grffile->spritegroups = realloc(_cur_grffile->spritegroups, (setid + 1) * sizeof(*_cur_grffile->spritegroups));
-		// Initialise new space to NULL
-		for (; _cur_grffile->spritegroups_count < (setid + 1); _cur_grffile->spritegroups_count++)
-			_cur_grffile->spritegroups[_cur_grffile->spritegroups_count] = NULL;
-	}
-
-	switch (type) {
-		/* Deterministic Sprite Group */
-		case 0x81: // Self scope, byte
-		case 0x82: // Parent scope, byte
-		case 0x85: // Self scope, word
-		case 0x86: // Parent scope, word
-		case 0x89: // Self scope, dword
-		case 0x8A: // Parent scope, dword
-		{
-			byte varadjust;
-			byte varsize;
-			uint i;
-
-			/* Check we can load the var size parameter */
-			check_length(bufend - buf, 1, "NewSpriteGroup (Deterministic) (1)");
-
-			group = AllocateSpriteGroup();
-			group->type = SGT_DETERMINISTIC;
-			group->g.determ.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
-
-			switch (GB(type, 2, 2)) {
-				default: NOT_REACHED();
-				case 0: group->g.determ.size = DSG_SIZE_BYTE;  varsize = 1; break;
-				case 1: group->g.determ.size = DSG_SIZE_WORD;  varsize = 2; break;
-				case 2: group->g.determ.size = DSG_SIZE_DWORD; varsize = 4; break;
-			}
-
-			check_length(bufend - buf, 5 + varsize, "NewSpriteGroup (Deterministic) (2)");
-
-			/* Loop through the var adjusts. Unfortunately we don't know how many we have
-			 * from the outset, so we shall have to keep reallocing. */
-			do {
-				DeterministicSpriteGroupAdjust *adjust;
-
-				if (group->g.determ.num_adjusts > 0) {
-					check_length(bufend - buf, 2 + varsize + 3, "NewSpriteGroup (Deterministic) (3)");
-				}
-
-				group->g.determ.num_adjusts++;
-				group->g.determ.adjusts = realloc(group->g.determ.adjusts, group->g.determ.num_adjusts * sizeof(*group->g.determ.adjusts));
-
-				adjust = &group->g.determ.adjusts[group->g.determ.num_adjusts - 1];
-
-				/* The first var adjust doesn't have an operation specified, so we set it to add. */
-				adjust->operation = group->g.determ.num_adjusts == 1 ? DSGA_OP_ADD : grf_load_byte(&buf);
-				adjust->variable  = grf_load_byte(&buf);
-				adjust->parameter = IS_BYTE_INSIDE(adjust->variable, 0x60, 0x80) ? grf_load_byte(&buf) : 0;
-
-				varadjust = grf_load_byte(&buf);
-				adjust->shift_num = GB(varadjust, 0, 5);
-				adjust->type      = GB(varadjust, 6, 2);
-				adjust->and_mask  = grf_load_var(varsize, &buf);
-
-				if (adjust->type != DSGA_TYPE_NONE) {
-					adjust->add_val    = grf_load_var(varsize, &buf);
-					adjust->divmod_val = grf_load_var(varsize, &buf);
-				} else {
-					adjust->add_val    = 0;
-					adjust->divmod_val = 0;
-				}
-
-				/* Continue reading var adjusts while bit 5 is set. */
-			} while (HASBIT(varadjust, 5));
-
-			group->g.determ.num_ranges = grf_load_byte(&buf);
-			group->g.determ.ranges = calloc(group->g.determ.num_ranges, sizeof(*group->g.determ.ranges));
-
-			check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->g.determ.num_ranges, "NewSpriteGroup (Deterministic)");
-
-			for (i = 0; i < group->g.determ.num_ranges; i++) {
-				group->g.determ.ranges[i].group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
-				group->g.determ.ranges[i].low   = grf_load_var(varsize, &buf);
-				group->g.determ.ranges[i].high  = grf_load_var(varsize, &buf);
-			}
-
-			group->g.determ.default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
-			break;
-		}
-
-		/* Randomized Sprite Group */
-		case 0x80: // Self scope
-		case 0x83: // Parent scope
-		{
-			byte triggers;
-			uint i;
-
-			check_length(bufend - buf, 7, "NewSpriteGroup (Randomized) (1)");
-
-			group = AllocateSpriteGroup();
-			group->type = SGT_RANDOMIZED;
-			group->g.random.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
-
-			triggers = grf_load_byte(&buf);
-			group->g.random.triggers       = GB(triggers, 0, 7);
-			group->g.random.cmp_mode       = HASBIT(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
-			group->g.random.lowest_randbit = grf_load_byte(&buf);
-			group->g.random.num_groups     = grf_load_byte(&buf);
-			group->g.random.groups = calloc(group->g.random.num_groups, sizeof(*group->g.random.groups));
-
-			check_length(bufend - buf, 2 * group->g.random.num_groups, "NewSpriteGroup (Randomized) (2)");
-
-			for (i = 0; i < group->g.random.num_groups; i++) {
-				group->g.random.groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
-			}
-
-			break;
-		}
-
-		/* Neither a variable or randomized sprite group... must be a real group */
-		default:
-		{
-
-
-			switch (feature) {
-				case GSF_TRAIN:
-				case GSF_ROAD:
-				case GSF_SHIP:
-				case GSF_AIRCRAFT:
-				case GSF_STATION:
-				{
-					byte sprites     = _cur_grffile->spriteset_numents;
-					byte num_loaded  = type;
-					byte num_loading = grf_load_byte(&buf);
-					uint i;
-
-					if (_cur_grffile->spriteset_start == 0) {
-						grfmsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
-						return;
-					}
-
-					check_length(bufend - buf, 2 * num_loaded + 2 * num_loading, "NewSpriteGroup (Real) (1)");
-
-					group = AllocateSpriteGroup();
-					group->type = SGT_REAL;
-
-					group->g.real.num_loaded  = num_loaded;
-					group->g.real.num_loading = num_loading;
-					if (num_loaded  > 0) group->g.real.loaded  = calloc(num_loaded,  sizeof(*group->g.real.loaded));
-					if (num_loading > 0) group->g.real.loading = calloc(num_loading, sizeof(*group->g.real.loading));
-
-					grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u views, %u loaded, %u loading",
-							setid, sprites, num_loaded, num_loading);
-
-					for (i = 0; i < num_loaded; i++) {
-						uint16 spriteid = grf_load_word(&buf);
-						group->g.real.loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
-						grfmsg(8, "NewSpriteGroup: + rg->loaded[%i]  = subset %u", i, spriteid);
-					}
-
-					for (i = 0; i < num_loading; i++) {
-						uint16 spriteid = grf_load_word(&buf);
-						group->g.real.loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
-						grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid);
-					}
-
-					break;
-				}
-
-				/* Loading of Tile Layout and Production Callback groups would happen here */
-				default: grfmsg(1, "NewSpriteGroup: Unsupported feature %d, skipping", feature);
-			}
-		}
-	}
-
-	_cur_grffile->spritegroups[setid] = group;
-}
-
-/* Action 0x03 */
-static void FeatureMapSpriteGroup(byte *buf, int len)
-{
-	/* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
-	 * id-list    := [<id>] [id-list]
-	 * cargo-list := <cargo-type> <cid> [cargo-list]
-	 *
-	 * B feature       see action 0
-	 * B n-id          bits 0-6: how many IDs this definition applies to
-	 *                 bit 7: if set, this is a wagon override definition (see below)
-	 * B ids           the IDs for which this definition applies
-	 * B num-cid       number of cargo IDs (sprite group IDs) in this definition
-	 *                 can be zero, in that case the def-cid is used always
-	 * B cargo-type    type of this cargo type (e.g. mail=2, wood=7, see below)
-	 * W cid           cargo ID (sprite group ID) for this type of cargo
-	 * W def-cid       default cargo ID (sprite group ID) */
-	/* TODO: Bridges, town houses. */
-	/* TODO: Multiple cargo support could be useful even for trains/cars -
-	 * cargo id 0xff is used for showing images in the build train list. */
-
-	static byte *last_engines;
-	static int last_engines_count;
-	uint8 feature;
-	uint8 idcount;
-	bool wagover;
-	uint8 cidcount;
-	int c, i;
-
-	check_length(len, 6, "FeatureMapSpriteGroup");
-	feature = buf[1];
-	idcount = buf[2] & 0x7F;
-	wagover = (buf[2] & 0x80) == 0x80;
-	check_length(len, 3 + idcount, "FeatureMapSpriteGroup");
-
-	/* If ``n-id'' (or ``idcount'') is zero, this is a ``feature
-	 * callback''. */
-	if (idcount == 0) {
-		grfmsg(2, "FeatureMapSpriteGroup: Feature callbacks not implemented yet");
-		return;
-	}
-
-	cidcount = buf[3 + idcount];
-	check_length(len, 4 + idcount + cidcount * 3, "FeatureMapSpriteGroup");
-
-	grfmsg(6, "FeatureMapSpriteGroup: Feature %d, %d ids, %d cids, wagon override %d",
-			feature, idcount, cidcount, wagover);
-
-	if (feature > GSF_STATION) {
-		grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %d, skipping", feature);
-		return;
-	}
-
-
-	if (feature == GSF_STATION) {
-		// We do things differently for stations.
-
-		for (i = 0; i < idcount; i++) {
-			uint8 stid = buf[3 + i];
-			StationSpec *statspec = _cur_grffile->stations[stid];
-			byte *bp = &buf[4 + idcount];
-
-			for (c = 0; c < cidcount; c++) {
-				uint8 ctype = grf_load_byte(&bp);
-				uint16 groupid = grf_load_word(&bp);
-
-				if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
-					grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping",
-					       groupid, _cur_grffile->spritegroups_count);
-					return;
-				}
-
-				if (ctype == 0xFE) ctype = GC_DEFAULT_NA;
-				if (ctype == 0xFF) ctype = GC_PURCHASE;
-
-				if (ctype >= NUM_GLOBAL_CID) {
-					grfmsg(1, "FeatureMapSpriteGroup: Cargo type %d out of range, skipping.", ctype);
-					continue;
-				}
-
-				statspec->spritegroup[ctype] = _cur_grffile->spritegroups[groupid];
-			}
-		}
-
-		{
-			byte *bp = buf + 4 + idcount + cidcount * 3;
-			uint16 groupid = grf_load_word(&bp);
-
-			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
-				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping",
-				       groupid, _cur_grffile->spritegroups_count);
-				return;
-			}
-
-			for (i = 0; i < idcount; i++) {
-				uint8 stid = buf[3 + i];
-				StationSpec *statspec = _cur_grffile->stations[stid];
-
-				statspec->spritegroup[GC_DEFAULT] = _cur_grffile->spritegroups[groupid];
-				statspec->grfid = _cur_grffile->grfid;
-				statspec->localidx = stid;
-				SetCustomStationSpec(statspec);
-			}
-		}
-		return;
-	}
-
-	// FIXME: Tropicset contains things like:
-	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
-	// what should we exactly do with that? --pasky
-
-	if (_cur_grffile->spriteset_start == 0 || _cur_grffile->spritegroups == 0) {
-		grfmsg(1, "FeatureMapSpriteGroup: No sprite set to work on! Skipping");
-		return;
-	}
-
-	if (!wagover && last_engines_count != idcount) {
-		last_engines = realloc(last_engines, idcount);
-		last_engines_count = idcount;
-	}
-
-	if (wagover) {
-		if (last_engines_count == 0) {
-			grfmsg(0, "FeatureMapSpriteGroup: WagonOverride: No engine to do override with");
-			return;
-		}
-		grfmsg(6, "FeatureMapSpriteGroup: WagonOverride: %u engines, %u wagons",
-				last_engines_count, idcount);
-	}
-
-
-	for (i = 0; i < idcount; i++) {
-		uint8 engine_id = buf[3 + i];
-		uint8 engine = engine_id + _vehshifts[feature];
-		byte *bp = &buf[4 + idcount];
-
-		if (engine_id > _vehcounts[feature]) {
-			grfmsg(0, "Id %u for feature 0x%02X is out of bounds", engine_id, feature);
-			return;
-		}
-
-		grfmsg(7, "FeatureMapSpriteGroup: [%d] Engine %d...", i, engine);
-
-		for (c = 0; c < cidcount; c++) {
-			uint8 ctype = grf_load_byte(&bp);
-			uint16 groupid = grf_load_word(&bp);
-
-			grfmsg(8, "FeatureMapSpriteGroup: * [%d] Cargo type 0x%X, group id 0x%02X", c, ctype, groupid);
-
-			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
-				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping", groupid, _cur_grffile->spritegroups_count);
-				return;
-			}
-
-			if (ctype == GC_INVALID) ctype = GC_PURCHASE;
-
-			if (ctype >= NUM_GLOBAL_CID) {
-				grfmsg(1, "FeatureMapSpriteGroup: Cargo type %d out of range, skipping.", ctype);
-				continue;
-			}
-
-			if (wagover) {
-				SetWagonOverrideSprites(engine, ctype, _cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
-			} else {
-				SetCustomEngineSprites(engine, ctype, _cur_grffile->spritegroups[groupid]);
-				last_engines[i] = engine;
-			}
-		}
-	}
-
-	{
-		byte *bp = buf + 4 + idcount + cidcount * 3;
-		uint16 groupid = grf_load_word(&bp);
-
-		grfmsg(8, "-- Default group id 0x%04X", groupid);
-
-		for (i = 0; i < idcount; i++) {
-			uint8 engine = buf[3 + i] + _vehshifts[feature];
-
-			// Don't tell me you don't love duplicated code!
-			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
-				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping", groupid, _cur_grffile->spritegroups_count);
-				return;
-			}
-
-			if (wagover) {
-				/* If the ID for this action 3 is the same as the vehicle ID,
-				 * this indicates we have a helicopter rotor override. */
-				if (feature == GSF_AIRCRAFT && engine == last_engines[i]) {
-					SetRotorOverrideSprites(engine, _cur_grffile->spritegroups[groupid]);
-				} else {
-					// TODO: No multiple cargo types per vehicle yet. --pasky
-					SetWagonOverrideSprites(engine, GC_DEFAULT, _cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
-				}
-			} else {
-				SetCustomEngineSprites(engine, GC_DEFAULT, _cur_grffile->spritegroups[groupid]);
-				SetEngineGRF(engine, _cur_grffile);
-				last_engines[i] = engine;
-			}
-		}
-	}
-}
-
-/* Action 0x04 */
-static void FeatureNewName(byte *buf, int len)
-{
-	/* <04> <veh-type> <language-id> <num-veh> <offset> <data...>
-	 *
-	 * B veh-type      see action 0 (as 00..07, + 0A
-	 *                 But IF veh-type = 48, then generic text
-	 * B language-id   If bit 6 is set, This is the extended language scheme,
-	                   with up to 64 language.
-	                   Otherwise, it is a mapping where set bits have meaning
-	                   0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish
-	                   Bit 7 set means this is a generic text, not a vehicle one (or else)
-	 * B num-veh       number of vehicles which are getting a new name
-	 * B/W offset      number of the first vehicle that gets a new name
-	 *                 Byte : ID of vehicle to change
-	 *                 Word : ID of string to change/add
-	 * S data          new texts, each of them zero-terminated, after
-	 *                 which the next name begins. */
-	/* TODO: No support for changing non-vehicle text. Perhaps we shouldn't
-	 * implement it at all, but it could be useful for some "modpacks"
-	 * (completely new scenarios changing all graphics and logically also
-	 * factory names etc). We should then also support all languages (by
-	 * name), not only the original four ones. --pasky
-	 * All of the above are coming.  In Time.  Some sooner than others :)*/
-
-	uint8 feature;
-	uint8 lang;
-	uint8 num;
-	uint16 id;
-	uint16 endid;
-	const char* name;
-	bool new_scheme = _cur_grffile->grf_version >= 7;
-	bool generic;
-
-	check_length(len, 6, "FeatureNewName");
-	buf++;
-	feature  = grf_load_byte(&buf);
-	lang     = grf_load_byte(&buf);
-	num      = grf_load_byte(&buf);
-	generic  = HASBIT(lang, 7);
-	id       = generic ? grf_load_word(&buf) : grf_load_byte(&buf);
-
-	CLRBIT(lang, 7);
-
-	if (feature <= GSF_AIRCRAFT && id < _vehcounts[feature]) {
-		id += _vehshifts[feature];
-	}
-	endid    = id + num;
-
-	grfmsg(6, "FeatureNewName: About to rename engines %d..%d (feature %d) in language 0x%02X",
-	               id, endid, feature, lang);
-
-	name = (const char*)buf; /*transfer read value*/
-	len -= generic ? 6 : 5;
-
-	for (; id < endid && len > 0; id++) {
-		size_t ofs = strlen(name) + 1;
-
-		if (ofs < 128) {
-			grfmsg(8, "FeatureNewName: %d <- %s", id, name);
-
-			switch (feature) {
-				case GSF_TRAIN:
-				case GSF_ROAD:
-				case GSF_SHIP:
-				case GSF_AIRCRAFT: {
-					if (id < TOTAL_NUM_ENGINES) {
-						StringID string = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_8000_KIRBY_PAUL_TANK_STEAM + id);
-						SetCustomEngineName(id, string);
-					} else {
-						AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, id);
-					}
-					break;
-				}
-
-				default:
-					switch (GB(id, 8, 8)) {
-						case 0xC4: /* Station class name */
-							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
-								grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8));
-							} else {
-								StationClassID sclass = _cur_grffile->stations[GB(id, 0, 8)]->sclass;
-								SetStationClassName(sclass, AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED));
-							}
-							break;
-
-						case 0xC5: /* Station name */
-							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
-								grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8));
-							} else {
-								_cur_grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
-							}
-							break;
-
-						case 0xC9:
-						case 0xD0:
-						case 0xDC:
-							AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
-							break;
-
-						default:
-							grfmsg(7, "FeatureNewName: Unsupported ID (0x%04X)", id);
-							break;
-					}
-					break;
-
-#if 0
-				case GSF_CANAL :
-				case GSF_BRIDGE :
-				case GSF_TOWNHOUSE :
-					AddGRFString(_cur_spriteid, id, lang, name);
-					switch (GB(id, 8,8)) {
-						case 0xC9: /* House name */
-						default:
-							grfmsg(7, "FeatureNewName: Unsupported ID (0x%04X)", id);
-					}
-					break;
-
-				case GSF_INDUSTRIES :
-				case 0x48 :   /* for generic strings */
-					AddGRFString(_cur_spriteid, id, lang, name);
-					break;
-				default :
-					grfmsg(7, "FeatureNewName: Unsupported feature (0x%02X)", feature);
-					break;
-#endif
-			}
-		} else {
-			/* ofs is the string length + 1, so if the string is empty, ofs
-			 * is 1 */
-			if (ofs == 1) {
-				grfmsg(7, "FeatureNewName: Can't add empty name");
-			} else {
-				grfmsg(7, "FeatureNewName: Too long a name (%d)", ofs);
-			}
-		}
-		name += ofs;
-		len -= (int)ofs;
-	}
-}
-
-/* Action 0x05 */
-static void GraphicsNew(byte *buf, int len)
-{
-	/* <05> <graphics-type> <num-sprites> <other data...>
-	 *
-	 * B graphics-type What set of graphics the sprites define.
-	 * E num-sprites   How many sprites are in this set?
-	 * V other data    Graphics type specific data.  Currently unused. */
-	/* TODO */
-
-	uint8 type;
-	uint16 num;
-	SpriteID replace = 0;
-
-	check_length(len, 2, "GraphicsNew");
-	buf++;
-	type = grf_load_byte(&buf);
-	num  = grf_load_extended(&buf);
-
-	switch (type) {
-		case 0x04: /* Signal graphics */
-			if (num != 112 && num != 240) {
-				grfmsg(1, "GraphicsNews: Signal graphics sprite count must be 112 or 240, skipping");
-				return;
-			}
-			_signal_base = _cur_spriteid;
-			break;
-
-		case 0x05: /* Catenary graphics */
-			if (num != 48) {
-				grfmsg(1, "GraphicsNews: Catenary graphics sprite count must be 48, skipping");
-				return;
-			}
-			replace = SPR_ELRAIL_BASE + 3;
-			break;
-
-		case 0x06: /* Foundations */
-			if (num != 74) {
-				grfmsg(1, "GraphicsNews: Foundation graphics sprite count must be 74, skipping");
-				return;
-			}
-			replace = SPR_SLOPES_BASE;
-			break;
-
-		case 0x08: /* Canal graphics */
-			if (num != 65) {
-				grfmsg(1, "GraphicsNews: Canal graphics sprite count must be 65, skipping");
-				return;
-			}
-			replace = SPR_CANALS_BASE + 5;
-			break;
-
-		case 0x0D: /* Coast graphics */
-			if (num != 16) {
-				grfmsg(1, "GraphicsNews: Coast graphics sprite count must be 16, skipping");
-				return;
-			}
-			_coast_base = _cur_spriteid;
-			break;
-
-		default:
-			grfmsg(2, "GraphicsNew: Custom graphics (type 0x%02X) sprite block of length %u (unimplemented, ignoring)",
-					type, num);
-			return;
-	}
-
-	if (replace == 0) {
-		grfmsg(2, "GraphicsNew: Loading %u sprites of type 0x%02X at SpriteID 0x%04X", num, type, _cur_spriteid);
-	} else {
-		grfmsg(2, "GraphicsNew: Replacing %u sprites of type 0x%02X at SpriteID 0x%04X", num, type, replace);
-	}
-
-	for (; num > 0; num--) {
-		LoadNextSprite(replace == 0 ? _cur_spriteid++ : replace++, _file_index);
-		_nfo_line++;
-	}
-}
-
-static uint32 GetParamVal(byte param, uint32 *cond_val)
-{
-	switch (param) {
-		case 0x81: /* current year */
-			return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
-
-		case 0x83: /* current climate, 0=temp, 1=arctic, 2=trop, 3=toyland */
-			return _opt.landscape;
-
-		case 0x84: /* GRF loading stage */
-			return (_cur_stage > GLS_INIT) | ((_cur_stage == GLS_ACTIVATION) << 9);
-
-		case 0x85: /* TTDPatch flags, only for bit tests */
-			if (cond_val == NULL) {
-				/* Supported in Action 0x07 and 0x09, not 0x0D */
-				return 0;
-			} else {
-				uint32 param_val = _ttdpatch_flags[*cond_val / 0x20];
-				*cond_val %= 0x20;
-				return param_val;
-			}
-
-		case 0x86: /* road traffic side, bit 4 clear=left, set=right */
-			return _opt.road_side << 4;
-
-		case 0x88: /* GRF ID check */
-			return 0;
-
-		case 0x8B: { /* TTDPatch version */
-			uint major    = 2;
-			uint minor    = 6;
-			uint revision = 0; // special case: 2.0.1 is 2.0.10
-			uint build    = 1168;
-			return (major << 24) | (minor << 20) | (revision << 16) | build;
-		}
-
-		case 0x8D: /* TTD Version, 00=DOS, 01=Windows */
-			return !_use_dos_palette;
-
-		case 0x8E: /* Y-offset for train sprites */
-			return _traininfo_vehicle_pitch;
-
-		case 0x92: /* Game mode */
-			return _game_mode;
-
-		case 0x9A: /* Always -1 */
-			return -1;
-
-		case 0x9D: /* TTD Platform, 00=TTDPatch, 01=OpenTTD */
-			return 1;
-
-		case 0x9E: /* Miscellaneous GRF features */
-			return _misc_grf_features;
-
-		default:
-			/* GRF Parameter */
-			if (param < 0x80) return _cur_grffile->param[param];
-
-			/* In-game variable. */
-			grfmsg(1, "Unsupported in-game variable 0x%02X", param);
-			return -1;
-	}
-}
-
-/* Action 0x06 */
-static void CfgApply(byte *buf, int len)
-{
-	/* <06> <param-num> <param-size> <offset> ... <FF>
-	 *
-	 * B param-num     Number of parameter to substitute (First = "zero")
-	 *                 Ignored if that parameter was not specified in newgrf.cfg
-	 * B param-size    How many bytes to replace.  If larger than 4, the
-	 *                 bytes of the following parameter are used.  In that
-	 *                 case, nothing is applied unless *all* parameters
-	 *                 were specified.
-	 * B offset        Offset into data from beginning of next sprite
-	 *                 to place where parameter is to be stored. */
-
-	/* Preload the next sprite */
-	uint32 pos = FioGetPos();
-	uint16 num = FioReadWord();
-	uint8 type = FioReadByte();
-
-	/* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
-	if (type == 0xFF) {
-		_preload_sprite = malloc(num);
-		FioReadBlock(_preload_sprite, num);
-	}
-
-	/* Reset the file position to the start of the next sprite */
-	FioSeekTo(pos, SEEK_SET);
-
-	if (type != 0xFF) {
-		grfmsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
-		return;
-	}
-
-	/* Now perform the Action 0x06 on our data. */
-	buf++;
-
-	for (;;) {
-		uint i;
-		uint param_num;
-		uint param_size;
-		uint offset;
-		bool add_value;
-
-		/* Read the parameter to apply. 0xFF indicates no more data to change. */
-		param_num = grf_load_byte(&buf);
-		if (param_num == 0xFF) break;
-
-		/* Get the size of the parameter to use. If the size covers multiple
-		 * double words, sequential parameter values are used. */
-		param_size = grf_load_byte(&buf);
-
-		/* Bit 7 of param_size indicates we should add to the original value
-		 * instead of replacing it. */
-		add_value  = HASBIT(param_size, 7);
-		param_size = GB(param_size, 0, 7);
-
-		/* Where to apply the data to within the pseudo sprite data. */
-		offset     = grf_load_extended(&buf);
-
-		/* If the parameter is a GRF parameter (not an internal variable) check
-		 * if it (and all further sequential parameters) has been defined. */
-		if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= _cur_grffile->param_end) {
-			grfmsg(2, "CfgApply: Ignoring (param %d not set)", (param_num + (param_size - 1) / 4));
-			break;
-		}
-
-		grfmsg(8, "CfgApply: Applying %u bytes from parameter 0x%02X at offset 0x%04X", param_size, param_num, offset);
-
-		for (i = 0; i < param_size; i++) {
-			uint32 value = GetParamVal(param_num + i / 4, NULL);
-
-			if (add_value) {
-				_preload_sprite[offset + i] += GB(value, (i % 4) * 8, 8);
-			} else {
-				_preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
-			}
-		}
-	}
-}
-
-/* Action 0x07 */
-/* Action 0x09 */
-static void SkipIf(byte *buf, int len)
-{
-	/* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
-	 *
-	 * B param-num
-	 * B param-size
-	 * B condition-type
-	 * V value
-	 * B num-sprites */
-	/* TODO: More params. More condition types. */
-	uint8 param;
-	uint8 paramsize;
-	uint8 condtype;
-	uint8 numsprites;
-	uint32 param_val = 0;
-	uint32 cond_val = 0;
-	uint32 mask = 0;
-	bool result;
-	GRFLabel *label;
-	GRFLabel *choice = NULL;
-
-	check_length(len, 6, "SkipIf");
-	buf++;
-	param     = grf_load_byte(&buf);
-	paramsize = grf_load_byte(&buf);
-	condtype  = grf_load_byte(&buf);
-
-	if (condtype < 2) {
-		/* Always 1 for bit tests, the given value should be ignored. */
-		paramsize = 1;
-	}
-
-	switch (paramsize) {
-		case 4: cond_val = grf_load_dword(&buf); mask = 0xFFFFFFFF; break;
-		case 2: cond_val = grf_load_word(&buf);  mask = 0x0000FFFF; break;
-		case 1: cond_val = grf_load_byte(&buf);  mask = 0x000000FF; break;
-		default: break;
-	}
-
-	if (param < 0x80 && _cur_grffile->param_end <= param) {
-		grfmsg(7, "Param %d undefined, skipping test", param);
-		return;
-	}
-
-	param_val = GetParamVal(param, &cond_val);
-
-	grfmsg(7, "Test condtype %d, param 0x%08X, condval 0x%08X", condtype, param_val, cond_val);
-
-	if (param == 0x88) {
-		/* GRF ID checks */
-
-		const GRFConfig *c = GetGRFConfig(cond_val);
-
-		if (condtype != 10 && c == NULL) {
-			grfmsg(7, "GRFID 0x%08X unknown, skipping test", BSWAP32(cond_val));
-			return;
-		}
-
-		switch (condtype) {
-			/* Tests 6 to 10 are only for param 0x88, GRFID checks */
-			case 6: /* Is GRFID active? */
-				result = HASBIT(c->flags, GCF_ACTIVATED);
-				break;
-
-			case 7: /* Is GRFID non-active? */
-				result = !HASBIT(c->flags, GCF_ACTIVATED);
-				break;
-
-			case 8: /* GRFID is not but will be active? */
-				result = !HASBIT(c->flags, GCF_ACTIVATED) && !HASBIT(c->flags, GCF_DISABLED);
-				break;
-
-			case 9: /* GRFID is or will be active? */
-				result = !HASBIT(c->flags, GCF_NOT_FOUND) && !HASBIT(c->flags, GCF_DISABLED);
-				break;
-
-			case 10: /* GRFID is not nor will be active */
-				/* This is the only condtype that doesn't get ignored if the GRFID is not found */
-				result = c == NULL || HASBIT(c->flags, GCF_DISABLED) || HASBIT(c->flags, GCF_NOT_FOUND);
-				break;
-
-			default: grfmsg(1, "Unsupported GRF test %d. Ignoring", condtype); return;
-		}
-	} else {
-		/* Parameter or variable tests */
-		switch (condtype) {
-			case 0: result = !!(param_val & (1 << cond_val));
-				break;
-			case 1: result = !(param_val & (1 << cond_val));
-				break;
-			case 2: result = (param_val & mask) == cond_val;
-				break;
-			case 3: result = (param_val & mask) != cond_val;
-				break;
-			case 4: result = (param_val & mask) < cond_val;
-				break;
-			case 5: result = (param_val & mask) > cond_val;
-				break;
-
-			default: grfmsg(1, "Unsupported test %d. Ignoring", condtype); return;
-		}
-	}
-
-	if (!result) {
-		grfmsg(2, "Not skipping sprites, test was false");
-		return;
-	}
-
-	numsprites = grf_load_byte(&buf);
-
-	/* numsprites can be a GOTO label if it has been defined in the GRF
-	 * file. The jump will always be the first matching label that follows
-	 * the current nfo_line. If no matching label is found, the first matching
-	 * label in the file is used. */
-	for (label = _cur_grffile->label; label != NULL; label = label->next) {
-		if (label->label != numsprites) continue;
-
-		/* Remember a goto before the current line */
-		if (choice == NULL) choice = label;
-		/* If we find a label here, this is definitely good */
-		if (label->nfo_line > _nfo_line) {
-			choice = label;
-			break;
-		}
-	}
-
-	if (choice != NULL) {
-		grfmsg(2, "Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line);
-		FioSeekTo(choice->pos, SEEK_SET);
-		_nfo_line = choice->nfo_line;
-		return;
-	}
-
-	grfmsg(2, "Skipping %d sprites, test was true", numsprites);
-	_skip_sprites = numsprites;
-	if (_skip_sprites == 0) {
-		/* Zero means there are no sprites to skip, so
-		 * we use -1 to indicate that all further
-		 * sprites should be skipped. */
-		_skip_sprites = -1;
-	}
-}
-
-
-/* Action 0x08 (GLS_FILESCAN) */
-static void ScanInfo(byte *buf, int len)
-{
-	uint8 version;
-	uint32 grfid;
-	const char *name;
-	const char *info;
-	int name_len;
-	int info_len;
-
-	check_length(len, 8, "Info"); buf++;
-	version = grf_load_byte(&buf);
-	grfid = grf_load_dword(&buf);
-
-	_cur_grfconfig->grfid = grfid;
-
-	/* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */
-	if (GB(grfid, 24, 8) == 0xFF) SETBIT(_cur_grfconfig->flags, GCF_SYSTEM);
-
-	len -= 6;
-	name = (const char*)buf;
-	name_len = ttd_strnlen(name, len);
-
-	if (name_len < len) {
-		_cur_grfconfig->name = TranslateTTDPatchCodes(name);
-
-		len -= name_len + 1;
-		info = name + name_len + 1;
-		info_len = ttd_strnlen(info, len);
-
-		if (info_len < len) _cur_grfconfig->info  = TranslateTTDPatchCodes(info);
-	}
-
-	/* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */
-	_skip_sprites = -1;
-}
-
-/* Action 0x08 */
-static void GRFInfo(byte *buf, int len)
-{
-	/* <08> <version> <grf-id> <name> <info>
-	 *
-	 * B version       newgrf version, currently 06
-	 * 4*B grf-id      globally unique ID of this .grf file
-	 * S name          name of this .grf set
-	 * S info          string describing the set, and e.g. author and copyright */
-	/* TODO: Check version. (We should have own versioning done somehow.) */
-	uint8 version;
-	uint32 grfid;
-	const char *name;
-
-	check_length(len, 8, "GRFInfo"); buf++;
-	version = grf_load_byte(&buf);
-	grfid = grf_load_dword(&buf);
-	name = (const char*)buf;
-
-	_cur_grffile->grfid = grfid;
-	_cur_grffile->grf_version = version;
-	SETBIT(_cur_grfconfig->flags, GCF_ACTIVATED);
-
-	/* Do swap the GRFID for displaying purposes since people expect that */
-	DEBUG(grf, 1, "Loaded GRFv%d set %08lX - %s", version, BSWAP32(grfid), name);
-}
-
-/* Action 0x0A */
-static void SpriteReplace(byte *buf, int len)
-{
-	/* <0A> <num-sets> <set1> [<set2> ...]
-	 * <set>: <num-sprites> <first-sprite>
-	 *
-	 * B num-sets      How many sets of sprites to replace.
-	 * Each set:
-	 * B num-sprites   How many sprites are in this set
-	 * W first-sprite  First sprite number to replace */
-	uint8 num_sets;
-	uint i;
-
-	buf++; /* skip action byte */
-	num_sets = grf_load_byte(&buf);
-
-	for (i = 0; i < num_sets; i++) {
-		uint8 num_sprites = grf_load_byte(&buf);
-		uint16 first_sprite = grf_load_word(&buf);
-		uint j;
-
-		grfmsg(2, "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d",
-			i, num_sprites, first_sprite
-		);
-
-		for (j = 0; j < num_sprites; j++) {
-			LoadNextSprite(first_sprite + j, _file_index); // XXX
-			_nfo_line++;
-		}
-	}
-}
-
-/* Action 0x0B */
-static void GRFError(byte *buf, int len)
-{
-	/* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
-	 *
-	 * B severity      00: notice, contine loading grf file
-	 *                 01: warning, continue loading grf file
-	 *                 02: error, but continue loading grf file, and attempt
-	 *                     loading grf again when loading or starting next game
-	 *                 03: error, abort loading and prevent loading again in
-	 *                     the future (only when restarting the patch)
-	 * B language-id   see action 4, use 1F for built-in error messages
-	 * B message-id    message to show, see below
-	 * S message       for custom messages (message-id FF), text of the message
-	 *                 not present for built-in messages.
-	 * V data          additional data for built-in (or custom) messages
-	 * B parnum        see action 6, only used with built-in message 03 */
-	/* TODO: For now we just show the message, sometimes incomplete and never translated. */
-
-	static const char *const msgstr[] = {
-		"%sRequires at least pseudo-TTDPatch version %s",
-		"%sThis file is for %s version of TTD",
-		"%sDesigned to be used with %s",
-		"%sInvalid parameter %s",
-		"%sMust be loaded before %s",
-		"%sMust be loaded after %s",
-		"%s%s"
-	};
-
-	static const char *const sevstr[] = {
-		"",
-		"Warning: ",
-		"Error: ",
-		"Fatal: ",
-	};
-	uint8 sevid;
-	uint8 msgid;
-
-	check_length(len, 6, "GRFError");
-	sevid = buf[1];
-	msgid = buf[3];
-
-	// Undocumented TTDPatch feature.
-	if (!HASBIT(sevid, 7) && _cur_stage < GLS_ACTIVATION) {
-		grfmsg(7, "Skipping non-fatal GRFError in stage 1");
-		return;
-	}
-
-	sevid = GB(sevid, 0, 2);
-	grfmsg(0,  msgstr[(msgid == 0xFF) ? lengthof(msgstr) - 1 : msgid], sevstr[sevid], &buf[4]);
-}
-
-/* Action 0x0C */
-static void GRFComment(byte *buf, int len)
-{
-	/* <0C> [<ignored...>]
-	 *
-	 * V ignored       Anything following the 0C is ignored */
-
-	static char comment[256];
-	if (len == 1) return;
-
-	ttd_strlcpy(comment, (char*)(buf + 1), minu(sizeof(comment), len));
-	grfmsg(2, "GRFComment: %s", comment);
-}
-
-/* Action 0x0D (GLS_SAFETYSCAN) */
-static void SafeParamSet(byte *buf, int len)
-{
-	uint8 target;
-
-	check_length(len, 5, "SafeParamSet");
-	buf++;
-	target = grf_load_byte(&buf);
-
-	/* Only writing GRF parameters is considered safe */
-	if (target < 0x80) return;
-
-	/* GRM could be unsafe, but as here it can only happen after other GRFs
-	 * are loaded, it should be okay. If the GRF tried to use the slots it
-	 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
-	 * sprites  is considered safe. */
-
-	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
-
-	/* Skip remainder of GRF */
-	_skip_sprites = -1;
-}
-
-/* Action 0x0D */
-static void ParamSet(byte *buf, int len)
-{
-	/* <0D> <target> <operation> <source1> <source2> [<data>]
-	 *
-	 * B target        parameter number where result is stored
-	 * B operation     operation to perform, see below
-	 * B source1       first source operand
-	 * B source2       second source operand
-	 * D data          data to use in the calculation, not necessary
-	 *                 if both source1 and source2 refer to actual parameters
-	 *
-	 * Operations
-	 * 00      Set parameter equal to source1
-	 * 01      Addition, source1 + source2
-	 * 02      Subtraction, source1 - source2
-	 * 03      Unsigned multiplication, source1 * source2 (both unsigned)
-	 * 04      Signed multiplication, source1 * source2 (both signed)
-	 * 05      Unsigned bit shift, source1 by source2 (source2 taken to be a
-	 *         signed quantity; left shift if positive and right shift if
-	 *         negative, source1 is unsigned)
-	 * 06      Signed bit shift, source1 by source2
-	 *         (source2 like in 05, and source1 as well)
-	 */
-
-	byte target;
-	byte oper;
-	uint32 src1;
-	uint32 src2;
-	uint32 data = 0;
-	uint32 res;
-
-	check_length(len, 5, "ParamSet");
-	buf++;
-	target = grf_load_byte(&buf);
-	oper = grf_load_byte(&buf);
-	src1 = grf_load_byte(&buf);
-	src2 = grf_load_byte(&buf);
-
-	if (len >= 8) data = grf_load_dword(&buf);
-
-	/* You can add 80 to the operation to make it apply only if the target
-	 * is not defined yet.  In this respect, a parameter is taken to be
-	 * defined if any of the following applies:
-	 * - it has been set to any value in the newgrf(w).cfg parameter list
-	 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
-	 *   an earlier action D */
-	if (oper & 0x80) {
-		if (target < 0x80 && target < _cur_grffile->param_end) {
-			grfmsg(7, "Param %u already defined, skipping", target);
-			return;
-		}
-
-		oper &= 0x7F;
-	}
-
-	if (src2 == 0xFE) {
-		if (GB(data, 0, 8) == 0xFF) {
-			if (data == 0x0000FFFF) {
-				/* Patch variables */
-				grfmsg(2, "ParamSet: Reading Patch variables unsupported");
-				return;
-			} else {
-				/* GRF Resource Management */
-				if (_cur_stage != GLS_ACTIVATION) {
-					/* Ignore GRM during initialization */
-					src1 = 0;
-				} else {
-					uint8  op      = src1;
-					uint8  feature = GB(data, 8, 8);
-					uint16 count   = GB(data, 16, 16);
-
-					switch (feature) {
-						case 0x00: /* Trains */
-						case 0x01: /* Road Vehicles */
-						case 0x02: /* Ships */
-						case 0x03: /* Aircraft */
-						{
-							uint start = 0;
-							uint size  = 0;
-							uint shift = _vehshifts[feature];
-							int i;
-
-							if (op == 6) {
-								/* Return GRFID of set that reserved ID */
-								src1 = _grm_engines[shift + _cur_grffile->param[target]];
-								break;
-							}
-
-							/* With an operation of 2 or 3, we want to reserve a specific block of IDs */
-							if (op == 2 || op == 3) start = _cur_grffile->param[target];
-
-							for (i = start; i < _vehcounts[feature]; i++) {
-								if (_grm_engines[shift + i] == 0) {
-									size++;
-								} else {
-									if (op == 2 || op == 3) break;
-									start = i + 1;
-									size = 0;
-								}
-
-								if (size == count) break;
-							}
-
-							if (size == count) {
-								/* Got the slot... */
-								if (op == 0 || op == 3) {
-									grfmsg(2, "GRM: Reserving %d vehicles at %d", count, start);
-									for (i = 0; i < count; i++) _grm_engines[shift + start + i] = _cur_grffile->grfid;
-								}
-								src1 = start;
-							} else {
-								/* Unable to allocate */
-								if (op != 4 && op != 5) {
-									/* Deactivate GRF */
-									grfmsg(0, "GRM: Unable to allocate %d vehicles, deactivating", count);
-									SETBIT(_cur_grfconfig->flags, GCF_DISABLED);
-									CLRBIT(_cur_grfconfig->flags, GCF_ACTIVATED);
-
-									_skip_sprites = -1;
-									return;
-								}
-
-								grfmsg(1, "GRM: Unable to allocate %d vehicles", count);
-								src1 = -1;
-							}
-							break;
-						}
-
-						case 0x08: /* General sprites */
-							switch (op) {
-								case 0:
-									/* 'Reserve' space at the current sprite ID */
-									src1 = _cur_spriteid;
-									_cur_spriteid += count;
-									break;
-
-								case 1:
-									src1 = _cur_spriteid;
-									break;
-
-								default:
-									grfmsg(1, "GRM: Unsupported operation %d for general sprites", op);
-									return;
-							}
-							break;
-
-						default: grfmsg(1, "GRM: Unsupported feature 0x%X", feature); return;
-					}
-				}
-			}
-		} else {
-			/* Read another GRF File's parameter */
-			const GRFFile *file = GetFileByGRFID(data);
-			if (file == NULL || src1 >= file->param_end) {
-				src1 = 0;
-			} else {
-				src1 = file->param[src1];
-			}
-		}
-	} else {
-		/* The source1 and source2 operands refer to the grf parameter number
-		 * like in action 6 and 7.  In addition, they can refer to the special
-		 * variables available in action 7, or they can be FF to use the value
-		 * of <data>.  If referring to parameters that are undefined, a value
-		 * of 0 is used instead.  */
-		src1 = (src1 == 0xFF) ? data : GetParamVal(src1, NULL);
-		src2 = (src2 == 0xFF) ? data : GetParamVal(src2, NULL);
-	}
-
-	/* TODO: You can access the parameters of another GRF file by using
-	 * source2=FE, source1=the other GRF's parameter number and data=GRF
-	 * ID.  This is only valid with operation 00 (set).  If the GRF ID
-	 * cannot be found, a value of 0 is used for the parameter value
-	 * instead. */
-
-	switch (oper) {
-		case 0x00:
-			res = src1;
-			break;
-
-		case 0x01:
-			res = src1 + src2;
-			break;
-
-		case 0x02:
-			res = src1 - src2;
-			break;
-
-		case 0x03:
-			res = src1 * src2;
-			break;
-
-		case 0x04:
-			res = (int32)src1 * (int32)src2;
-			break;
-
-		case 0x05:
-			if ((int32)src2 < 0) {
-				res = src1 >> -(int32)src2;
-			} else {
-				res = src1 << src2;
-			}
-			break;
-
-		case 0x06:
-			if ((int32)src2 < 0) {
-				res = (int32)src1 >> -(int32)src2;
-			} else {
-				res = (int32)src1 << src2;
-			}
-			break;
-
-		case 0x07: /* Bitwise AND */
-			res = src1 & src2;
-			break;
-
-		case 0x08: /* Bitwise OR */
-			res = src1 | src2;
-			break;
-
-		case 0x09: /* Unsigned division */
-			if (src2 == 0) {
-				res = src1;
-			} else {
-				res = src1 / src2;
-			}
-			break;
-
-		case 0x0A: /* Signed divison */
-			if (src2 == 0) {
-				res = src1;
-			} else {
-				res = (int32)src1 / (int32)src2;
-			}
-			break;
-
-		case 0x0B: /* Unsigned modulo */
-			if (src2 == 0) {
-				res = src1;
-			} else {
-				res = src1 % src2;
-			}
-			break;
-
-		case 0x0C: /* Signed modulo */
-			if (src2 == 0) {
-				res = src1;
-			} else {
-				res = (int32)src1 % (int32)src2;
-			}
-			break;
-
-		default: grfmsg(0, "ParamSet: Unknown operation %d, skipping", oper); return;
-	}
-
-	switch (target) {
-		case 0x8E: // Y-Offset for train sprites
-			_traininfo_vehicle_pitch = res;
-			break;
-
-		// TODO implement
-		case 0x8F: // Rail track type cost factors
-		case 0x93: // Tile refresh offset to left
-		case 0x94: // Tile refresh offset to right
-		case 0x95: // Tile refresh offset upwards
-		case 0x96: // Tile refresh offset downwards
-		case 0x97: // Snow line height
-		case 0x99: // Global ID offset
-			grfmsg(7, "ParamSet: Skipping unimplemented target 0x%02X", target);
-			break;
-
-		case 0x9E: /* Miscellaneous GRF features */
-			_misc_grf_features = res;
-			/* Set train list engine width */
-			_traininfo_vehicle_width = HASBIT(res, 3) ? 32 : 29;
-			break;
-
-		default:
-			if (target < 0x80) {
-				_cur_grffile->param[target] = res;
-				if (target + 1U > _cur_grffile->param_end) _cur_grffile->param_end = target + 1;
-			} else {
-				grfmsg(7, "ParamSet: Skipping unknown target 0x%02X", target);
-			}
-			break;
-	}
-}
-
-/* Action 0x0E (GLS_SAFETYSCAN) */
-static void SafeGRFInhibit(byte *buf, int len)
-{
-	/* <0E> <num> <grfids...>
-	 *
-	 * B num           Number of GRFIDs that follow
-	 * D grfids        GRFIDs of the files to deactivate */
-
-	byte num;
-	int i;
-
-	check_length(len, 1, "GRFInhibit");
-	buf++, len--;
-	num = grf_load_byte(&buf); len--;
-	check_length(len, 4 * num, "GRFInhibit");
-
-	for (i = 0; i < num; i++) {
-		uint32 grfid = grf_load_dword(&buf);
-
-		/* GRF is unsafe it if tries to deactivate other GRFs */
-		if (grfid != _cur_grfconfig->grfid) {
-			SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
-
-			/* Skip remainder of GRF */
-			_skip_sprites = -1;
-
-			return;
-		}
-	}
-}
-
-/* Action 0x0E */
-static void GRFInhibit(byte *buf, int len)
-{
-	/* <0E> <num> <grfids...>
-	 *
-	 * B num           Number of GRFIDs that follow
-	 * D grfids        GRFIDs of the files to deactivate */
-
-	byte num;
-	int i;
-
-	check_length(len, 1, "GRFInhibit");
-	buf++, len--;
-	num = grf_load_byte(&buf); len--;
-	check_length(len, 4 * num, "GRFInhibit");
-
-	for (i = 0; i < num; i++) {
-		uint32 grfid = grf_load_dword(&buf);
-		GRFConfig *file = GetGRFConfig(grfid);
-
-		/* Unset activation flag */
-		if (file != NULL && file != _cur_grfconfig) {
-			grfmsg(2, "GRFInhibit: Deactivating file '%s'", file->filename);
-			SETBIT(file->flags, GCF_DISABLED);
-			CLRBIT(file->flags, GCF_ACTIVATED);
-		}
-	}
-}
-
-/* Action 0x10 */
-static void DefineGotoLabel(byte *buf, int len)
-{
-	/* <10> <label> [<comment>]
-	 *
-	 * B label      The label to define
-	 * V comment    Optional comment - ignored */
-
-	GRFLabel *label;
-
-	check_length(len, 1, "DefineGotoLabel");
-	buf++; len--;
-
-	label = malloc(sizeof(*label));
-	label->label    = grf_load_byte(&buf);
-	label->nfo_line = _nfo_line;
-	label->pos      = FioGetPos();
-	label->next     = NULL;
-
-	/* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */
-	if (_cur_grffile->label == NULL) {
-		_cur_grffile->label = label;
-	} else {
-		/* Attach the label to the end of the list */
-		GRFLabel *l;
-		for (l = _cur_grffile->label; l->next != NULL; l = l->next);
-		l->next = label;
-	}
-
-	grfmsg(2, "DefineGotoLabel: GOTO target with label 0x%02X", label->label);
-}
-
-/* Action 0x11 */
-static void GRFSound(byte *buf, int len)
-{
-	/* <11> <num>
-	 *
-	 * W num      Number of sound files that follow */
-
-	uint16 num;
-
-	check_length(len, 1, "GRFSound");
-	buf++;
-	num = grf_load_word(&buf);
-
-	_grf_data_blocks = num;
-	_grf_data_type   = GDT_SOUND;
-
-	if (_cur_grffile->sound_offset == 0) _cur_grffile->sound_offset = GetNumSounds();
-}
-
-static void ImportGRFSound(byte *buf, int len)
-{
-	const GRFFile *file;
-	FileEntry *se = AllocateFileEntry();
-	uint32 grfid = grf_load_dword(&buf);
-	uint16 sound = grf_load_word(&buf);
-
-	file = GetFileByGRFID(grfid);
-	if (file == NULL || file->sound_offset == 0) {
-		grfmsg(1, "ImportGRFSound: Source file not available");
-		return;
-	}
-
-	if (file->sound_offset + sound >= GetNumSounds()) {
-		grfmsg(1, "ImportGRFSound: Sound effect %d is invalid", sound);
-		return;
-	}
-
-	grfmsg(2, "ImportGRFSound: Copying sound %d (%d) from file %X", sound, file->sound_offset + sound, grfid);
-
-	*se = *GetSound(file->sound_offset + sound);
-
-	/* Reset volume and priority, which TTDPatch doesn't copy */
-	se->volume   = 128;
-	se->priority = 0;
-}
-
-/* 'Action 0xFE' */
-static void GRFImportBlock(byte *buf, int len)
-{
-	if (_grf_data_blocks == 0) {
-		grfmsg(2, "GRFImportBlock: Unexpected import block, skipping");
-		return;
-	}
-
-	buf++;
-
-	_grf_data_blocks--;
-
-	/* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
-	 * importing sounds, so this is probably all wrong... */
-	if (grf_load_byte(&buf) != _grf_data_type) {
-		grfmsg(1, "GRFImportBlock: Import type mismatch");
-	}
-
-	switch (_grf_data_type) {
-		case GDT_SOUND: ImportGRFSound(buf, len - 1); break;
-		default: NOT_REACHED(); break;
-	}
-}
-
-static void LoadGRFSound(byte *buf, int len)
-{
-	byte *buf_start = buf;
-	FileEntry *se;
-
-	/* Allocate a sound entry. This is done even if the data is not loaded
-	 * so that the indices used elsewhere are still correct. */
-	se = AllocateFileEntry();
-
-	if (grf_load_dword(&buf) != BSWAP32('RIFF')) {
-		grfmsg(1, "LoadGRFSound: Missing RIFF header");
-		return;
-	}
-
-	/* Size of file -- we ignore this */
-	grf_load_dword(&buf);
-
-	if (grf_load_dword(&buf) != BSWAP32('WAVE')) {
-		grfmsg(1, "LoadGRFSound: Invalid RIFF type");
-		return;
-	}
-
-	for (;;) {
-		uint32 tag  = grf_load_dword(&buf);
-		uint32 size = grf_load_dword(&buf);
-
-		switch (tag) {
-			case ' tmf': /* 'fmt ' */
-				/* Audio format, must be 1 (PCM) */
-				if (grf_load_word(&buf) != 1) {
-					grfmsg(1, "LoadGRFSound: Invalid audio format");
-					return;
-				}
-				se->channels = grf_load_word(&buf);
-				se->rate = grf_load_dword(&buf);
-				grf_load_dword(&buf);
-				grf_load_word(&buf);
-				se->bits_per_sample = grf_load_word(&buf);
-
-				/* Consume any extra bytes */
-				for (; size > 16; size--) grf_load_byte(&buf);
-				break;
-
-			case 'atad': /* 'data' */
-				se->file_size    = size;
-				se->file_offset  = FioGetPos() - (len - (buf - buf_start)) + 1;
-				se->file_offset |= _file_index << 24;
-
-				/* Set default volume and priority */
-				se->volume = 0x80;
-				se->priority = 0;
-
-				grfmsg(2, "LoadGRFSound: channels %u, sample rate %u, bits per sample %u, length %u", se->channels, se->rate, se->bits_per_sample, size);
-				return;
-
-			default:
-				se->file_size = 0;
-				return;
-		}
-	}
-}
-
-/* Action 0x12 */
-static void LoadFontGlyph(byte *buf, int len)
-{
-	/* <12> <num_def> <font_size> <num_char> <base_char>
-	 *
-	 * B num_def      Number of definitions
-	 * B font_size    Size of font (0 = normal, 1 = small, 2 = large)
-	 * B num_char     Number of consecutive glyphs
-	 * W base_char    First character index */
-
-	uint8 num_def;
-	uint i;
-
-	buf++; len--;
-	check_length(len, 1, "LoadFontGlyph");
-
-	num_def = grf_load_byte(&buf);
-
-	check_length(len, 1 + num_def * 4, "LoadFontGlyph");
-
-	for (i = 0; i < num_def; i++) {
-		FontSize size    = grf_load_byte(&buf);
-		uint8  num_char  = grf_load_byte(&buf);
-		uint16 base_char = grf_load_word(&buf);
-		uint c;
-
-		grfmsg(7, "LoadFontGlyph: Loading %u glyph(s) at 0x%04X for size %u", num_char, base_char, size);
-
-		for (c = 0; c < num_char; c++) {
-			SetUnicodeGlyph(size, base_char + c, _cur_spriteid);
-			LoadNextSprite(_cur_spriteid++, _file_index);
-			_nfo_line++;
-		}
-	}
-}
-
-/* 'Action 0xFF' */
-static void GRFDataBlock(byte *buf, int len)
-{
-	byte name_len;
-	const char *name;
-
-	if (_grf_data_blocks == 0) {
-		grfmsg(2, "GRFDataBlock: unexpected data block, skipping");
-		return;
-	}
-
-	buf++;
-	name_len = grf_load_byte(&buf);
-	name = (const char *)buf;
-	buf += name_len + 1;
-
-	grfmsg(2, "GRFDataBlock: block name '%s'...", name);
-
-	_grf_data_blocks--;
-
-	switch (_grf_data_type) {
-		case GDT_SOUND: LoadGRFSound(buf, len - name_len - 2); break;
-		default: NOT_REACHED(); break;
-	}
-}
-
-
-/* Used during safety scan on unsafe actions */
-static void GRFUnsafe(byte *buf, int len)
-{
-	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
-
-	/* Skip remainder of GRF */
-	_skip_sprites = -1;
-}
-
-
-static void InitializeGRFSpecial(void)
-{
-	_ttdpatch_flags[0] =  ((_patches.always_small_airport ? 1 : 0) << 0x0C)  // keepsmallairport
-	                   |                                        (1 << 0x0D)  // newairports
-	                   |                                        (1 << 0x0E)  // largestations
-	                   |           ((_patches.longbridges ? 1 : 0) << 0x0F)  // longbridges
-	                   |                                        (0 << 0x10)  // loadtime
-	                   |                                        (1 << 0x12)  // presignals
-	                   |                                        (1 << 0x13)  // extpresignals
-	                   | ((_patches.never_expire_vehicles ? 1 : 0) << 0x16)  // enginespersist
-	                   |                                        (1 << 0x1B)  // multihead
-	                   |                                        (1 << 0x1D)  // lowmemory
-	                   |                                        (1 << 0x1E); // generalfixes
-
-	_ttdpatch_flags[1] =                                        (0 << 0x07)  // moreairports - based on units of noise
-	                   |        ((_patches.mammoth_trains ? 1 : 0) << 0x08)  // mammothtrains
-	                   |                                        (1 << 0x09)  // trainrefit
-	                   |                                        (0 << 0x0B)  // subsidiaries
-	                   |       ((_patches.gradual_loading ? 1 : 0) << 0x0C)  // gradualloading
-	                   |                                        (1 << 0x12)  // unifiedmaglevmode - set bit 0 mode. Not revelant to OTTD
-	                   |                                        (1 << 0x13)  // unifiedmaglevmode - set bit 1 mode
-	                   |                                        (1 << 0x14)  // bridgespeedlimits
-	                   |                                        (1 << 0x16)  // eternalgame
-	                   |                                        (1 << 0x17)  // newtrains
-	                   |                                        (1 << 0x18)  // newrvs
-	                   |                                        (1 << 0x19)  // newships
-	                   |                                        (1 << 0x1A)  // newplanes
-	                   |           ((_patches.signal_side ? 1 : 0) << 0x1B)  // signalsontrafficside
-	                   |                                        (1 << 0x1C); // electrifiedrailway
-
-	_ttdpatch_flags[2] =                                        (1 << 0x01)  // loadallgraphics - obsolote
-	                   |                                        (1 << 0x03)  // semaphores
-	                   |                                        (0 << 0x0B)  // enhancedgui
-	                   |                                        (0 << 0x0C)  // newagerating
-	                   |       ((_patches.build_on_slopes ? 1 : 0) << 0x0D)  // buildonslopes
-	                   |                                        (0 << 0x0F)  // planespeed
-	                   |                                        (0 << 0x10)  // moreindustriesperclimate - obsolete
-	                   |                                        (0 << 0x11)  // moretoylandfeatures
-	                   |                                        (1 << 0x12)  // newstations
-	                   |                                        (0 << 0x13)  // tracktypecostdiff
-	                   |                                        (0 << 0x14)  // manualconvert
-	                   |       ((_patches.build_on_slopes ? 1 : 0) << 0x15)  // buildoncoasts
-	                   |                                        (1 << 0x16)  // canals
-	                   |                                        (1 << 0x17)  // newstartyear
-	                   |                                        (0 << 0x18)  // freighttrains
-	                   |                                        (0 << 0x19)  // newhouses
-	                   |                                        (1 << 0x1A)  // newbridges
-	                   |                                        (0 << 0x1B)  // newtownnames
-	                   |                                        (0 << 0x1C)  // moreanimations
-	                   |    ((_patches.wagon_speed_limits ? 1 : 0) << 0x1D)  // wagonspeedlimits
-	                   |                                        (1 << 0x1E)  // newshistory
-	                   |                                        (0 << 0x1F); // custombridgeheads
-
-	_ttdpatch_flags[3] =                                        (0 << 0x00)  // newcargodistribution
-	                   |                                        (1 << 0x01)  // windowsnap
-	                   |                                        (0 << 0x02)  // townbuildnoroad
-	                   |                                        (0 << 0x03)  // pathbasedsignalling. To enable if ever pbs is back
-	                   |                                        (0 << 0x04)  // aichoosechance
-	                   |                                        (1 << 0x05)  // resolutionwidth
-	                   |                                        (1 << 0x06)  // resolutionheight
-	                   |                                        (0 << 0x07)  // newindustries
-	                   |                                        (0 << 0x08)  // fifoloading
-	                   |                                        (0 << 0x09)  // townroadbranchprob
-	                   |                                        (0 << 0x0A)  // tempsnowline
-	                   |                                        (0 << 0x0B)  // newcargo
-	                   |                                        (1 << 0x0C)  // enhancemultiplayer
-	                   |                                        (1 << 0x0D)  // onewayroads
-	                   |   ((_patches.nonuniform_stations ? 1 : 0) << 0x0E)  // irregularstations
-	                   |                                        (1 << 0x0F)  // statistics
-	                   |                                        (1 << 0x10)  // newsounds
-	                   |                                        (1 << 0x11)  // autoreplace
-	                   |                                        (1 << 0x12)  // autoslope
-	                   |                                        (0 << 0x13)  // followvehicle
-	                   |                                        (0 << 0x14)  // trams
-	                   |                                        (0 << 0x15)  // enhancetunnels
-	                   |                                        (0 << 0x16)  // shortrvs
-	                   |                                        (0 << 0x17); // articulatedrvs
-}
-
-static void ResetCustomStations(void)
-{
-	StationSpec *statspec;
-	GRFFile *file;
-	uint i;
-	uint t;
-
-	for (file = _first_grffile; file != NULL; file = file->next) {
-		if (file->stations == NULL) continue;
-		for (i = 0; i < MAX_STATIONS; i++) {
-			if (file->stations[i] == NULL) continue;
-			statspec = file->stations[i];
-
-			/* Release renderdata, if it wasn't copied from another custom station spec  */
-			if (!statspec->copied_renderdata) {
-				for (t = 0; t < statspec->tiles; t++) {
-					free((void*)statspec->renderdata[t].seq);
-				}
-				free(statspec->renderdata);
-			}
-
-			/* Release platforms and layouts */
-			if (!statspec->copied_layouts) {
-				uint l, p;
-				for (l = 0; l < statspec->lengths; l++) {
-					for (p = 0; p < statspec->platforms[l]; p++) {
-						free(statspec->layouts[l][p]);
-					}
-					free(statspec->layouts[l]);
-				}
-				free(statspec->layouts);
-				free(statspec->platforms);
-			}
-
-			/* Release this station */
-			free(statspec);
-		}
-
-		/* Free and reset the station data */
-		free(file->stations);
-		file->stations = NULL;
-	}
-}
-
-static void ResetNewGRF(void)
-{
-	GRFFile *f, *next;
-
-	for (f = _first_grffile; f != NULL; f = next) {
-		next = f->next;
-
-		free(f->filename);
-		free(f);
-	}
-
-	_first_grffile = NULL;
-	_cur_grffile   = NULL;
-}
-
-/**
- * Reset all NewGRF loaded data
- * TODO
- */
-static void ResetNewGRFData(void)
-{
-	uint i;
-
-	CleanUpStrings();
-
-	// Copy/reset original engine info data
-	memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info));
-	memcpy(&_rail_vehicle_info, &orig_rail_vehicle_info, sizeof(orig_rail_vehicle_info));
-	memcpy(&_ship_vehicle_info, &orig_ship_vehicle_info, sizeof(orig_ship_vehicle_info));
-	memcpy(&_aircraft_vehicle_info, &orig_aircraft_vehicle_info, sizeof(orig_aircraft_vehicle_info));
-	memcpy(&_road_vehicle_info, &orig_road_vehicle_info, sizeof(orig_road_vehicle_info));
-
-	// Copy/reset original bridge info data
-	// First, free sprite table data
-	for (i = 0; i < MAX_BRIDGES; i++) {
-		if (_bridge[i].sprite_table != NULL) {
-			uint j;
-
-			for (j = 0; j < 7; j++) free(_bridge[i].sprite_table[j]);
-			free(_bridge[i].sprite_table);
-		}
-	}
-	memcpy(&_bridge, &orig_bridge, sizeof(_bridge));
-
-	// Reset refit/cargo class data
-	memset(&cargo_allowed, 0, sizeof(cargo_allowed));
-	memset(&cargo_disallowed, 0, sizeof(cargo_disallowed));
-
-	// Reset GRM reservations
-	memset(&_grm_engines, 0, sizeof(_grm_engines));
-
-	// Unload sprite group data
-	UnloadWagonOverrides();
-	UnloadRotorOverrideSprites();
-	UnloadCustomEngineSprites();
-	UnloadCustomEngineNames();
-	ResetEngineListOrder();
-
-	// Reset price base data
-	ResetPriceBaseMultipliers();
-
-	/* Reset the curencies array */
-	ResetCurrencies();
-
-	// Reset station classes
-	ResetStationClasses();
-	ResetCustomStations();
-
-	/* Reset NewGRF files */
-	ResetNewGRF();
-
-	// Add engine type to engine data. This is needed for the refit precalculation.
-	AddTypeToEngines();
-
-	/* Reset misc GRF features and train list display variables */
-	_misc_grf_features = 0;
-	_traininfo_vehicle_pitch = 0;
-	_traininfo_vehicle_width = 29;
-	_have_2cc = false;
-	_signal_base = 0;
-	_coast_base = 0;
-
-	InitializeSoundPool();
-	InitializeSpriteGroupPool();
-}
-
-/** Reset all NewGRFData that was used only while processing data */
-static void ClearTemporaryNewGRFData(void)
-{
-	/* Clear the GOTO labels used for GRF processing */
-	GRFLabel *l;
-	for (l = _cur_grffile->label; l != NULL;) {
-		GRFLabel *l2 = l->next;
-		free(l);
-		l = l2;
-	}
-	_cur_grffile->label = NULL;
-
-	/* Clear the list of spritegroups */
-	free(_cur_grffile->spritegroups);
-	_cur_grffile->spritegroups = NULL;
-	_cur_grffile->spritegroups_count = 0;
-}
-
-static void InitNewGRFFile(const GRFConfig *config, int sprite_offset)
-{
-	GRFFile *newfile;
-
-	newfile = GetFileByFilename(config->filename);
-	if (newfile != NULL) {
-		/* We already loaded it once. */
-		newfile->sprite_offset = sprite_offset;
-		_cur_grffile = newfile;
-		return;
-	}
-
-	newfile = calloc(1, sizeof(*newfile));
-
-	if (newfile == NULL) error ("Out of memory");
-
-	newfile->filename = strdup(config->filename);
-	newfile->sprite_offset = sprite_offset;
-
-	/* Copy the initial parameter list */
-	assert(lengthof(newfile->param) == lengthof(config->param) && lengthof(config->param) == 0x80);
-	newfile->param_end = config->num_params;
-	memcpy(newfile->param, config->param, sizeof(newfile->param));
-
-	if (_first_grffile == NULL) {
-		_cur_grffile = newfile;
-		_first_grffile = newfile;
-	} else {
-		_cur_grffile->next = newfile;
-		_cur_grffile = newfile;
-	}
-}
-
-
-/** Bitmasked values of what type of cargo is refittable for the given vehicle-type.
- * This coupled with the landscape information (_landscape_global_cargo_mask) gives
- * us exactly what is refittable and what is not */
-#define MC(cargo) (1 << cargo)
-static const uint32 _default_refitmasks[NUM_VEHICLE_TYPES] = {
-	/* Trains */
-	MC(GC_PASSENGERS) | MC(GC_COAL)      | MC(GC_MAIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS)        | MC(GC_GRAIN)      | MC(GC_WOOD)    | MC(GC_IRON_ORE)    |
-	MC(GC_STEEL)      | MC(GC_VALUABLES) | MC(GC_PAPER)  | MC(GC_FOOD)      | MC(GC_FRUIT)        | MC(GC_COPPER_ORE) | MC(GC_WATER)   | MC(GC_SUGAR)       |
-	MC(GC_TOYS)       | MC(GC_CANDY)     | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES)    | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
-	/* Road vehicles (not refittable by default) */
-	0,
-	/* Ships */
-	MC(GC_COAL)  | MC(GC_MAIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS)        | MC(GC_GRAIN)   | MC(GC_WOOD)    | MC(GC_IRON_ORE) | MC(GC_STEEL) | MC(GC_VALUABLES) |
-	MC(GC_PAPER) | MC(GC_FOOD)   | MC(GC_FRUIT)     | MC(GC_COPPER_ORE)   | MC(GC_WATER)   | MC(GC_RUBBER)  | MC(GC_SUGAR)    | MC(GC_TOYS)  | MC(GC_BATTERIES) |
-	MC(GC_CANDY) | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES) | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
-	/* Aircraft */
-	MC(GC_PASSENGERS) | MC(GC_MAIL)  | MC(GC_GOODS)  | MC(GC_VALUABLES) | MC(GC_FOOD)         | MC(GC_FRUIT)   | MC(GC_SUGAR)   | MC(GC_TOYS) |
-	MC(GC_BATTERIES)  | MC(GC_CANDY) | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES) | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
-	/* Special/Disaster */
-	0,0
-};
-#undef MC
-
-
-/**
- * Precalculate refit masks from cargo classes for all vehicles.
- */
-static void CalculateRefitMasks(void)
-{
-	EngineID engine;
-
-	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
-		uint32 mask = 0;
-		uint32 not_mask = 0;
-		uint32 xor_mask = _engine_info[engine].refit_mask;
-		byte i;
-
-		if (cargo_allowed[engine] != 0) {
-			// Build up the list of cargo types from the set cargo classes.
-			for (i = 0; i < lengthof(cargo_classes); i++) {
-				if (HASBIT(cargo_allowed[engine], i)) mask |= cargo_classes[i];
-				if (HASBIT(cargo_disallowed[engine], i)) not_mask |= cargo_classes[i];
-			}
-		} else {
-			// Don't apply default refit mask to wagons or engines with no capacity
-			if (xor_mask == 0 && (
-						GetEngine(engine)->type != VEH_Train || (
-							RailVehInfo(engine)->capacity != 0 &&
-							!(RailVehInfo(engine)->flags & RVI_WAGON)
-						)
-					)) {
-				xor_mask = _default_refitmasks[GetEngine(engine)->type - VEH_Train];
-			}
-		}
-		_engine_info[engine].refit_mask = ((mask & ~not_mask) ^ xor_mask) & _landscape_global_cargo_mask[_opt.landscape];
-	}
-}
-
-/* Here we perform initial decoding of some special sprites (as are they
- * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
- * partial implementation yet). */
-/* XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
- * a crafted invalid GRF file. We should tell that to the user somehow, or
- * better make this more robust in the future. */
-static void DecodeSpecialSprite(uint num, GrfLoadingStage stage)
-{
-	/* XXX: There is a difference between staged loading in TTDPatch and
-	 * here.  In TTDPatch, for some reason actions 1 and 2 are carried out
-	 * during stage 1, whilst action 3 is carried out during stage 2 (to
-	 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
-	 * IDs are valid only within a given set (action 1) block, and may be
-	 * overwritten after action 3 associates them. But overwriting happens
-	 * in an earlier stage than associating, so...  We just process actions
-	 * 1 and 2 in stage 2 now, let's hope that won't get us into problems.
-	 * --pasky */
-	/* We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
-	 * is not in memory and scanning the file every time would be too expensive.
-	 * In other stages we skip action 0x10 since it's already dealt with. */
-	static const SpecialSpriteHandler handlers[][GLS_END] = {
-		/* 0x00 */ { NULL,     SafeChangeInfo, NULL,       NULL,       FeatureChangeInfo, },
-		/* 0x01 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteSet, },
-		/* 0x02 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteGroup, },
-		/* 0x03 */ { NULL,     GRFUnsafe, NULL,            NULL,       FeatureMapSpriteGroup, },
-		/* 0x04 */ { NULL,     NULL,      NULL,            NULL,       FeatureNewName, },
-		/* 0x05 */ { NULL,     NULL,      NULL,            NULL,       GraphicsNew, },
-		/* 0x06 */ { NULL,     NULL,      NULL,            CfgApply,   CfgApply, },
-		/* 0x07 */ { NULL,     NULL,      NULL,            NULL,       SkipIf, },
-		/* 0x08 */ { ScanInfo, NULL,      NULL,            GRFInfo,    GRFInfo, },
-		/* 0x09 */ { NULL,     NULL,      NULL,            SkipIf,     SkipIf, },
-		/* 0x0A */ { NULL,     NULL,      NULL,            NULL,       SpriteReplace, },
-		/* 0x0B */ { NULL,     NULL,      NULL,            GRFError,   GRFError, },
-		/* 0x0C */ { NULL,     NULL,      NULL,            GRFComment, GRFComment, },
-		/* 0x0D */ { NULL,     SafeParamSet, NULL,         ParamSet,   ParamSet, },
-		/* 0x0E */ { NULL,     SafeGRFInhibit, NULL,       GRFInhibit, GRFInhibit, },
-		/* 0x0F */ { NULL,     NULL,      NULL,            NULL,       NULL, },
-		/* 0x10 */ { NULL,     NULL,      DefineGotoLabel, NULL,       NULL, },
-		/* 0x11 */ { NULL,     GRFUnsafe, NULL,            NULL,       GRFSound, },
-		/* 0x12 */ { NULL,     NULL,      NULL,            NULL,       LoadFontGlyph, },
-	};
-
-	byte* buf;
-	byte action;
-
-	if (_preload_sprite == NULL) {
-		/* No preloaded sprite to work with; allocate and read the
-		 * pseudo sprite content. */
-		buf = malloc(num);
-		if (buf == NULL) error("DecodeSpecialSprite: Could not allocate memory");
-		FioReadBlock(buf, num);
-	} else {
-		/* Use the preloaded sprite data. */
-		buf = _preload_sprite;
-		_preload_sprite = NULL;
-		grfmsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
-
-		/* Skip the real (original) content of this action. */
-		FioSeekTo(num, SEEK_CUR);
-	}
-
-	action = buf[0];
-
-	if (action == 0xFF) {
-		grfmsg(7, "Handling data block in stage %d", stage);
-		GRFDataBlock(buf, num);
-	} else if (action == 0xFE) {
-		grfmsg(7, "Handling import block in stage %d", stage);
-		GRFImportBlock(buf, num);
-	} else if (action >= lengthof(handlers)) {
-		grfmsg(7, "Skipping unknown action 0x%02X", action);
-	} else if (handlers[action][stage] == NULL) {
-		grfmsg(7, "Skipping action 0x%02X in stage %d", action, stage);
-	} else {
-		grfmsg(7, "Handling action 0x%02X in stage %d", action, stage);
-		handlers[action][stage](buf, num);
-	}
-	free(buf);
-}
-
-
-void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage)
-{
-	const char *filename = config->filename;
-	uint16 num;
-
-	/* A .grf file is activated only if it was active when the game was
-	 * started.  If a game is loaded, only its active .grfs will be
-	 * reactivated, unless "loadallgraphics on" is used.  A .grf file is
-	 * considered active if its action 8 has been processed, i.e. its
-	 * action 8 hasn't been skipped using an action 7.
-	 *
-	 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
-	 * carried out.  All others are ignored, because they only need to be
-	 * processed once at initialization.  */
-	if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
-		_cur_grffile = GetFileByFilename(filename);
-		if (_cur_grffile == NULL) error("File '%s' lost in cache.\n", filename);
-		if (stage == GLS_ACTIVATION && !HASBIT(config->flags, GCF_ACTIVATED)) return;
-	}
-
-	FioOpenFile(file_index, filename);
-	_file_index = file_index; // XXX
-
-	_cur_grfconfig = config;
-
-	DEBUG(grf, 2, "Reading NewGRF-file '%s'", filename);
-
-	/* Skip the first sprite; we don't care about how many sprites this
-	 * does contain; newest TTDPatches and George's longvehicles don't
-	 * neither, apparently. */
-	if (FioReadWord() == 4 && FioReadByte() == 0xFF) {
-		FioReadDword();
-	} else {
-		DEBUG(grf, 7, "Custom .grf has invalid format");
-		return;
-	}
-
-	_skip_sprites = 0; // XXX
-	_nfo_line = 0;
-
-	while ((num = FioReadWord()) != 0) {
-		byte type = FioReadByte();
-		_nfo_line++;
-
-		if (type == 0xFF) {
-			if (_skip_sprites == 0) {
-				DecodeSpecialSprite(num, stage);
-
-				/* Stop all processing if we are to skip the remaining sprites */
-				if (_skip_sprites == -1) break;
-
-				continue;
-			} else {
-				FioSkipBytes(num);
-			}
-		} else {
-			if (_skip_sprites == 0) grfmsg(7, "Skipping unexpected sprite");
-
-			FioSkipBytes(7);
-			num -= 8;
-
-			if (type & 2) {
-				FioSkipBytes(num);
-			} else {
-				while (num > 0) {
-					int8 i = FioReadByte();
-					if (i >= 0) {
-						num -= i;
-						FioSkipBytes(i);
-					} else {
-						i = -(i >> 3);
-						num -= i;
-						FioReadByte();
-					}
-				}
-			}
-		}
-
-		if (_skip_sprites > 0) _skip_sprites--;
-	}
-}
-
-
-void LoadNewGRF(uint load_index, uint file_index)
-{
-	GrfLoadingStage stage;
-
-	InitializeGRFSpecial();
-
-	ResetNewGRFData();
-
-	/* Load newgrf sprites
-	 * in each loading stage, (try to) open each file specified in the config
-	 * and load information from it. */
-	for (stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) {
-		uint slot = file_index;
-		GRFConfig *c;
-
-		_cur_stage = stage;
-		_cur_spriteid = load_index;
-		for (c = _grfconfig; c != NULL; c = c->next) {
-			if (HASBIT(c->flags, GCF_DISABLED) || HASBIT(c->flags, GCF_NOT_FOUND)) continue;
-
-			// TODO usererror()
-			if (!FioCheckFileExists(c->filename)) error("NewGRF file is missing '%s'", c->filename);
-
-			if (stage == GLS_LABELSCAN) InitNewGRFFile(c, _cur_spriteid);
-			LoadNewGRFFile(c, slot++, stage);
-			if (stage == GLS_ACTIVATION) {
-				ClearTemporaryNewGRFData();
-				DEBUG(sprite, 2, "Currently %i sprites are loaded", _cur_spriteid);
-			}
-		}
-	}
-
-	// Pre-calculate all refit masks after loading GRF files
-	CalculateRefitMasks();
-}
-
-
new file mode 100644
--- /dev/null
+++ b/src/newgrf.cpp
@@ -0,0 +1,3772 @@
+/* $Id$ */
+
+#include "stdafx.h"
+
+#include <stdarg.h>
+
+#include "openttd.h"
+#include "debug.h"
+#include "gfx.h"
+#include "fileio.h"
+#include "functions.h"
+#include "engine.h"
+#include "spritecache.h"
+#include "station.h"
+#include "sprite.h"
+#include "newgrf.h"
+#include "variables.h"
+#include "string.h"
+#include "table/strings.h"
+#include "bridge.h"
+#include "economy.h"
+#include "newgrf_engine.h"
+#include "vehicle.h"
+#include "newgrf_text.h"
+#include "table/sprites.h"
+#include "fontcache.h"
+#include "date.h"
+#include "currency.h"
+#include "sound.h"
+#include "newgrf_config.h"
+#include "newgrf_sound.h"
+#include "newgrf_spritegroup.h"
+
+/* TTDPatch extended GRF format codec
+ * (c) Petr Baudis 2004 (GPL'd)
+ * Changes by Florian octo Forster are (c) by the OpenTTD development team.
+ *
+ * Contains portions of documentation by TTDPatch team.
+ * Thanks especially to Josef Drexler for the documentation as well as a lot
+ * of help at #tycoon. Also thanks to Michael Blunck for is GRF files which
+ * served as subject to the initial testing of this codec. */
+
+
+static int _skip_sprites; // XXX
+static uint _file_index; // XXX
+SpriteID _signal_base;
+SpriteID _coast_base;
+
+static GRFFile *_cur_grffile;
+GRFFile *_first_grffile;
+static SpriteID _cur_spriteid;
+static GrfLoadingStage _cur_stage;
+static uint32 _nfo_line;
+
+static GRFConfig *_cur_grfconfig;
+
+/* Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
+static byte _misc_grf_features = 0;
+
+/* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
+static uint32 _ttdpatch_flags[8];
+
+/* Used by Action 0x06 to preload a pseudo sprite and modify its content */
+static byte *_preload_sprite = NULL;
+
+/* Set if any vehicle is loaded which uses 2cc (two company colours) */
+bool _have_2cc = false;
+
+
+typedef enum GrfDataType {
+	GDT_SOUND,
+} GrfDataType;
+
+static byte _grf_data_blocks;
+static GrfDataType _grf_data_type;
+
+
+typedef enum grfspec_feature {
+	GSF_TRAIN,
+	GSF_ROAD,
+	GSF_SHIP,
+	GSF_AIRCRAFT,
+	GSF_STATION,
+	GSF_CANAL,
+	GSF_BRIDGE,
+	GSF_TOWNHOUSE,
+	GSF_GLOBALVAR,
+	GSF_INDUSTRYTILES,
+	GSF_INDUSTRIES,
+	GSF_CARGOS,
+	GSF_SOUNDFX,
+} grfspec_feature;
+
+
+typedef void (*SpecialSpriteHandler)(byte *buf, int len);
+
+static const int _vehcounts[4] = {
+	/* GSF_TRAIN */    NUM_TRAIN_ENGINES,
+	/* GSF_ROAD */     NUM_ROAD_ENGINES,
+	/* GSF_SHIP */     NUM_SHIP_ENGINES,
+	/* GSF_AIRCRAFT */ NUM_AIRCRAFT_ENGINES
+};
+
+static const int _vehshifts[4] = {
+	/* GSF_TRAIN */    0,
+	/* GSF_ROAD */     ROAD_ENGINES_INDEX,
+	/* GSF_SHIP */     SHIP_ENGINES_INDEX,
+	/* GSF_AIRCRAFT */ AIRCRAFT_ENGINES_INDEX,
+};
+
+enum {
+	MAX_STATIONS = 256,
+};
+
+static uint16 cargo_allowed[TOTAL_NUM_ENGINES];
+static uint16 cargo_disallowed[TOTAL_NUM_ENGINES];
+
+/* Contains the GRF ID of the owner of a vehicle if it has been reserved */
+static uint32 _grm_engines[TOTAL_NUM_ENGINES];
+
+/** DEBUG() function dedicated to newGRF debugging messages
+ * Function is essentialy the same as DEBUG(grf, severity, ...) with the
+ * addition of file:line information when parsing grf files.
+ * NOTE: for the above reason(s) grfmsg() should ONLY be used for
+ * loading/parsing grf files, not for runtime debug messages as there
+ * is no file information available during that time.
+ * @param severity debugging severity level, see debug.h
+ * @param debugging message in printf() format */
+void CDECL grfmsg(int severity, const char *str, ...)
+{
+	char buf[1024];
+	va_list va;
+
+	va_start(va, str);
+	vsnprintf(buf, sizeof(buf), str, va);
+	va_end(va);
+
+	DEBUG(grf, severity, "[%s:%d] %s", _cur_grfconfig->filename, _nfo_line, buf);
+}
+
+static inline void check_length(int real, int wanted, const char *str)
+{
+	if (real >= wanted) return;
+	grfmsg(0, "%s: Invalid pseudo sprite length %d (expected %d)!", str, real, wanted);
+}
+
+static inline byte grf_load_byte(byte **buf)
+{
+	return *(*buf)++;
+}
+
+static uint16 grf_load_word(byte **buf)
+{
+	uint16 val = grf_load_byte(buf);
+	return val | (grf_load_byte(buf) << 8);
+}
+
+static uint16 grf_load_extended(byte** buf)
+{
+	uint16 val;
+	val = grf_load_byte(buf);
+	if (val == 0xFF) val = grf_load_word(buf);
+	return val;
+}
+
+static uint32 grf_load_dword(byte **buf)
+{
+	uint32 val = grf_load_word(buf);
+	return val | (grf_load_word(buf) << 16);
+}
+
+static uint32 grf_load_var(byte size, byte **buf)
+{
+	switch (size) {
+		case 1: return grf_load_byte(buf);
+		case 2: return grf_load_word(buf);
+		case 4: return grf_load_dword(buf);
+		default:
+			NOT_REACHED();
+			return 0;
+	}
+}
+
+static GRFFile *GetFileByGRFID(uint32 grfid)
+{
+	GRFFile *file;
+
+	for (file = _first_grffile; file != NULL; file = file->next) {
+		if (file->grfid == grfid) break;
+	}
+	return file;
+}
+
+static GRFFile *GetFileByFilename(const char *filename)
+{
+	GRFFile *file;
+
+	for (file = _first_grffile; file != NULL; file = file->next) {
+		if (strcmp(file->filename, filename) == 0) break;
+	}
+	return file;
+}
+
+
+typedef bool (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
+
+#define FOR_EACH_OBJECT for (i = 0; i < numinfo; i++)
+
+static void dewagonize(int condition, int engine)
+{
+	EngineInfo *ei = &_engine_info[engine];
+	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
+
+	if (condition != 0) {
+		ei->unk2 &= ~0x80;
+		rvi->flags &= ~2;
+	} else {
+		ei->unk2 |= 0x80;
+		rvi->flags |= 2;
+	}
+}
+
+static bool RailVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+{
+	EngineInfo *ei = &_engine_info[engine];
+	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	switch (prop) {
+		case 0x05: /* Track type */
+			FOR_EACH_OBJECT {
+				uint8 tracktype = grf_load_byte(&buf);
+
+				switch (tracktype) {
+					case 0: ei[i].railtype = rvi[i].engclass == 2 ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL; break;
+					case 1: ei[i].railtype = RAILTYPE_MONO; break;
+					case 2: ei[i].railtype = RAILTYPE_MAGLEV; break;
+					default:
+						grfmsg(1, "RailVehicleChangeInfo: Invalid track type %d specified, ignoring", tracktype);
+						break;
+				}
+			}
+			break;
+
+		case 0x08: /* AI passenger service */
+			/* TODO */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		case 0x09: /* Speed (1 unit is 1 kmh) */
+			FOR_EACH_OBJECT {
+				uint16 speed = grf_load_word(&buf);
+				if (speed == 0xFFFF) speed = 0;
+
+				rvi[i].max_speed = speed;
+			}
+			break;
+
+		case 0x0B: /* Power */
+			FOR_EACH_OBJECT {
+				uint16 power = grf_load_word(&buf);
+
+				if (rvi[i].flags & RVI_MULTIHEAD) power /= 2;
+
+				rvi[i].power = power;
+				dewagonize(power, engine + i);
+			}
+			break;
+
+		case 0x0D: /* Running cost factor */
+			FOR_EACH_OBJECT {
+				uint8 runcostfact = grf_load_byte(&buf);
+
+				if (rvi[i].flags & RVI_MULTIHEAD) runcostfact /= 2;
+
+				rvi[i].running_cost_base = runcostfact;
+			}
+			break;
+
+		case 0x0E: /* Running cost base */
+			FOR_EACH_OBJECT {
+				uint32 base = grf_load_dword(&buf);
+
+				switch (base) {
+					case 0x4C30: rvi[i].running_cost_class = 0; break;
+					case 0x4C36: rvi[i].running_cost_class = 1; break;
+					case 0x4C3C: rvi[i].running_cost_class = 2; break;
+					case 0: break; /* Used by wagons */
+					default:
+						grfmsg(1, "RailVehicleChangeInfo: Unsupported running cost base 0x%04X, ignoring", base);
+						break;
+				}
+			}
+			break;
+
+		case 0x12: /* Sprite ID */
+			FOR_EACH_OBJECT {
+				uint8 spriteid = grf_load_byte(&buf);
+
+				/* TTD sprite IDs point to a location in a 16bit array, but we use it
+				 * as an array index, so we need it to be half the original value. */
+				if (spriteid < 0xFD) spriteid >>= 1;
+
+				rvi[i].image_index = spriteid;
+			}
+			break;
+
+		case 0x13: /* Dual-headed */
+			FOR_EACH_OBJECT {
+				uint8 dual = grf_load_byte(&buf);
+
+				if (dual != 0) {
+					if (!(rvi[i].flags & RVI_MULTIHEAD)) {
+						// adjust power and running cost if needed
+						rvi[i].power /= 2;
+						rvi[i].running_cost_base /= 2;
+					}
+					rvi[i].flags |= RVI_MULTIHEAD;
+				} else {
+					if (rvi[i].flags & RVI_MULTIHEAD) {
+						// adjust power and running cost if needed
+						rvi[i].power *= 2;
+						rvi[i].running_cost_base *= 2;
+					}
+					rvi[i].flags &= ~RVI_MULTIHEAD;
+				}
+			}
+			break;
+
+		case 0x14: /* Cargo capacity */
+			FOR_EACH_OBJECT rvi[i].capacity = grf_load_byte(&buf);
+			break;
+
+		case 0x15: /* Cargo type */
+			FOR_EACH_OBJECT {
+				uint8 ctype = grf_load_byte(&buf);
+
+				if (ctype < NUM_CARGO) {
+					rvi[i].cargo_type = ctype;
+				} else {
+					grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, ignoring", ctype);
+				}
+			}
+			break;
+
+		case 0x16: /* Weight */
+			FOR_EACH_OBJECT SB(rvi[i].weight, 0, 8, grf_load_byte(&buf));
+			break;
+
+		case 0x17: /* Cost factor */
+			FOR_EACH_OBJECT rvi[i].base_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x18: /* AI rank */
+			FOR_EACH_OBJECT rvi[i].ai_rank = grf_load_byte(&buf);
+			break;
+
+		case 0x19: /* Engine traction type */
+			/* What do the individual numbers mean?
+			 * 0x00 .. 0x07: Steam
+			 * 0x08 .. 0x27: Diesel
+			 * 0x28 .. 0x31: Electric
+			 * 0x32 .. 0x37: Monorail
+			 * 0x38 .. 0x41: Maglev
+			 */
+			FOR_EACH_OBJECT {
+				uint8 traction = grf_load_byte(&buf);
+				int engclass;
+
+				if (traction <= 0x07) {
+					engclass = 0;
+				} else if (traction <= 0x27) {
+					engclass = 1;
+				} else if (traction <= 0x31) {
+					engclass = 2;
+				} else if (traction <= 0x41) {
+					engclass = 2;
+				} else {
+					break;
+				}
+				if (ei[i].railtype == RAILTYPE_RAIL     && engclass == 2) ei[i].railtype = RAILTYPE_ELECTRIC;
+				if (ei[i].railtype == RAILTYPE_ELECTRIC && engclass != 2) ei[i].railtype = RAILTYPE_RAIL;
+
+				rvi[i].engclass = engclass;
+			}
+			break;
+
+		case 0x1A: /* Alter purchase list sort order */
+			FOR_EACH_OBJECT {
+				EngineID pos = grf_load_byte(&buf);
+
+				if (pos < NUM_TRAIN_ENGINES) {
+					AlterRailVehListOrder(engine + i, pos);
+				} else {
+					grfmsg(2, "RailVehicleChangeInfo: Invalid train engine ID %d, ignoring", pos);
+				}
+			}
+			break;
+
+		case 0x1B: /* Powered wagons power bonus */
+			FOR_EACH_OBJECT rvi[i].pow_wag_power = grf_load_word(&buf);
+			break;
+
+		case 0x1C: /* Refit cost */
+			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x1D: /* Refit cargo */
+			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
+			break;
+
+		case 0x1E: /* Callback */
+			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
+			break;
+
+		case 0x1F: /* Tractive effort coefficient */
+			FOR_EACH_OBJECT rvi[i].tractive_effort = grf_load_byte(&buf);
+			break;
+
+		case 0x21: /* Shorter vehicle */
+			FOR_EACH_OBJECT rvi[i].shorten_factor = grf_load_byte(&buf);
+			break;
+
+		case 0x22: /* Visual effect */
+			// see note in engine.h about rvi->visual_effect
+			FOR_EACH_OBJECT rvi[i].visual_effect = grf_load_byte(&buf);
+			break;
+
+		case 0x23: /* Powered wagons weight bonus */
+			FOR_EACH_OBJECT rvi[i].pow_wag_weight = grf_load_byte(&buf);
+			break;
+
+		case 0x24: /* High byte of vehicle weight */
+			FOR_EACH_OBJECT {
+				byte weight = grf_load_byte(&buf);
+
+				if (weight > 4) {
+					grfmsg(2, "RailVehicleChangeInfo: Nonsensical weight of %d tons, ignoring", weight << 8);
+				} else {
+					SB(rvi[i].weight, 8, 8, weight);
+				}
+			}
+			break;
+
+		case 0x25: /* User-defined bit mask to set when checking veh. var. 42 */
+			FOR_EACH_OBJECT rvi[i].user_def_data = grf_load_byte(&buf);
+			break;
+
+		case 0x27: /* Miscellaneous flags */
+			FOR_EACH_OBJECT {
+				ei[i].misc_flags = grf_load_byte(&buf);
+				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
+			}
+			break;
+
+		case 0x28: /* Cargo classes allowed */
+			FOR_EACH_OBJECT cargo_allowed[engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x29: /* Cargo classes disallowed */
+			FOR_EACH_OBJECT cargo_disallowed[engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x2A: /* Long format introduction date (days since year 0) */
+			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
+			break;
+
+		/* TODO */
+		/* Fall-through for unimplemented one byte long properties. */
+		case 0x20: /* Air drag */
+		case 0x26: /* Retire vehicle early */
+			/* TODO */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		default:
+			ret = true;
+			break;
+	}
+	*bufp = buf;
+	return ret;
+}
+
+static bool RoadVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+{
+	EngineInfo *ei = &_engine_info[ROAD_ENGINES_INDEX + engine];
+	RoadVehicleInfo *rvi = &_road_vehicle_info[engine];
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	switch (prop) {
+		case 0x08: /* Speed (1 unit is 0.5 kmh) */
+			FOR_EACH_OBJECT rvi[i].max_speed = grf_load_byte(&buf);
+			break;
+
+		case 0x09: /* Running cost factor */
+			FOR_EACH_OBJECT rvi[i].running_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x0A: /* Running cost base */
+			/* TODO: I have no idea. --pasky */
+			FOR_EACH_OBJECT grf_load_dword(&buf);
+			ret = true;
+			break;
+
+		case 0x0E: /* Sprite ID */
+			FOR_EACH_OBJECT {
+				uint8 spriteid = grf_load_byte(&buf);
+
+				// cars have different custom id in the GRF file
+				if (spriteid == 0xFF) spriteid = 0xFD;
+
+				if (spriteid < 0xFD) spriteid >>= 1;
+
+				rvi[i].image_index = spriteid;
+			}
+			break;
+
+		case 0x0F: /* Cargo capacity */
+			FOR_EACH_OBJECT rvi[i].capacity = grf_load_byte(&buf);
+			break;
+
+		case 0x10: /* Cargo type */
+			FOR_EACH_OBJECT {
+				uint8 cargo = grf_load_byte(&buf);
+
+				if (cargo < NUM_CARGO) {
+					rvi[i].cargo_type = cargo;
+				} else {
+					grfmsg(2, "RoadVehicleChangeInfo: Invalid cargo type %d, ignoring", cargo);
+				}
+			}
+			break;
+
+		case 0x11: /* Cost factor */
+			FOR_EACH_OBJECT rvi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
+			break;
+
+		case 0x12: /* SFX */
+			FOR_EACH_OBJECT rvi[i].sfx = grf_load_byte(&buf);
+			break;
+
+		case 0x13: /* Power in 10hp */
+		case 0x14: /* Weight in 1/4 tons */
+		case 0x15: /* Speed in mph*0.8 */
+			/* TODO: Support for road vehicles realistic power
+			 * computations (called rvpower in TTDPatch) is just
+			 * missing in OTTD yet. --pasky */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		case 0x16: /* Cargos available for refitting */
+			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
+			break;
+
+		case 0x17: /* Callback mask */
+			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
+			break;
+
+		case 0x1A: /* Refit cost */
+			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x1C: /* Miscellaneous flags */
+			FOR_EACH_OBJECT {
+				ei[i].misc_flags = grf_load_byte(&buf);
+				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
+			}
+			break;
+
+		case 0x1D: /* Cargo classes allowed */
+			FOR_EACH_OBJECT cargo_allowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x1E: /* Cargo classes disallowed */
+			FOR_EACH_OBJECT cargo_disallowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x1F: /* Long format introduction date (days since year 0) */
+			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
+			break;
+
+		case 0x18: /* Tractive effort */
+		case 0x19: /* Air drag */
+		case 0x1B: /* Retire vehicle early */
+			/* TODO */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		default:
+			ret = true;
+			break;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool ShipVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+{
+	EngineInfo *ei = &_engine_info[SHIP_ENGINES_INDEX + engine];
+	ShipVehicleInfo *svi = &_ship_vehicle_info[engine];
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	//printf("e %x prop %x?\n", engine, prop);
+	switch (prop) {
+		case 0x08: /* Sprite ID */
+			FOR_EACH_OBJECT {
+				uint8 spriteid = grf_load_byte(&buf);
+
+				// ships have different custom id in the GRF file
+				if (spriteid == 0xFF) spriteid = 0xFD;
+
+				if (spriteid < 0xFD) spriteid >>= 1;
+
+				svi[i].image_index = spriteid;
+			}
+			break;
+
+		case 0x09: /* Refittable */
+			FOR_EACH_OBJECT svi[i].refittable = grf_load_byte(&buf);
+			break;
+
+		case 0x0A: /* Cost factor */
+			FOR_EACH_OBJECT svi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
+			break;
+
+		case 0x0B: /* Speed (1 unit is 0.5 kmh) */
+			FOR_EACH_OBJECT svi[i].max_speed = grf_load_byte(&buf);
+			break;
+
+		case 0x0C: /* Cargo type */
+			FOR_EACH_OBJECT {
+				uint8 cargo = grf_load_byte(&buf);
+
+				// XXX: Need to consult this with patchman yet.
+#if 0
+				// Documentation claims this is already the
+				// per-landscape cargo type id, but newships.grf
+				// assume otherwise.
+				cargo = local_cargo_id_ctype[cargo];
+#endif
+				if (cargo < NUM_CARGO) {
+					svi[i].cargo_type = cargo;
+				} else {
+					grfmsg(2, "ShipVehicleChangeInfo: Invalid cargo type %d, ignoring", cargo);
+				}
+			}
+			break;
+
+		case 0x0D: /* Cargo capacity */
+			FOR_EACH_OBJECT svi[i].capacity = grf_load_word(&buf);
+			break;
+
+		case 0x0F: /* Running cost factor */
+			FOR_EACH_OBJECT svi[i].running_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x10: /* SFX */
+			FOR_EACH_OBJECT svi[i].sfx = grf_load_byte(&buf);
+			break;
+
+		case 0x11: /* Cargos available for refitting */
+			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
+			break;
+
+		case 0x12: /* Callback mask */
+			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
+			break;
+
+		case 0x13: /* Refit cost */
+			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x17: /* Miscellaneous flags */
+			FOR_EACH_OBJECT {
+				ei[i].misc_flags = grf_load_byte(&buf);
+				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
+			}
+			break;
+
+		case 0x18: /* Cargo classes allowed */
+			FOR_EACH_OBJECT cargo_allowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x19: /* Cargo classes disallowed */
+			FOR_EACH_OBJECT cargo_disallowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x1A: /* Long format introduction date (days since year 0) */
+			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
+			break;
+
+		case 0x14: /* Ocean speed fraction */
+		case 0x15: /* Canal speed fraction */
+		case 0x16: /* Retire vehicle early */
+			/* TODO */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		default:
+			ret = true;
+			break;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
+{
+	EngineInfo *ei = &_engine_info[AIRCRAFT_ENGINES_INDEX + engine];
+	AircraftVehicleInfo *avi = &_aircraft_vehicle_info[engine];
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	//printf("e %x prop %x?\n", engine, prop);
+	switch (prop) {
+		case 0x08: /* Sprite ID */
+			FOR_EACH_OBJECT {
+				uint8 spriteid = grf_load_byte(&buf);
+
+				// aircraft have different custom id in the GRF file
+				if (spriteid == 0xFF) spriteid = 0xFD;
+
+				if (spriteid < 0xFD) spriteid >>= 1;
+
+				avi[i].image_index = spriteid;
+			}
+			break;
+
+		case 0x09: /* Helicopter */
+			FOR_EACH_OBJECT {
+				if (grf_load_byte(&buf) == 0) {
+					avi[i].subtype = 0;
+				} else {
+					SB(avi[i].subtype, 0, 1, 1);
+				}
+			}
+			break;
+
+		case 0x0A: /* Large */
+			FOR_EACH_OBJECT SB(avi[i].subtype, 1, 1, (grf_load_byte(&buf) != 0 ? 1 : 0));
+			break;
+
+		case 0x0B: /* Cost factor */
+			FOR_EACH_OBJECT avi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
+			break;
+
+		case 0x0C: /* Speed (1 unit is 8 mph) */
+			FOR_EACH_OBJECT avi[i].max_speed = grf_load_byte(&buf);
+			break;
+
+		case 0x0D: /* Acceleration */
+			FOR_EACH_OBJECT avi[i].acceleration = grf_load_byte(&buf);
+			break;
+
+		case 0x0E: /* Running cost factor */
+			FOR_EACH_OBJECT avi[i].running_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x0F: /* Passenger capacity */
+			FOR_EACH_OBJECT avi[i].passenger_capacity = grf_load_word(&buf);
+			break;
+
+		case 0x11: /* Mail capacity */
+			FOR_EACH_OBJECT avi[i].mail_capacity = grf_load_byte(&buf);
+			break;
+
+		case 0x12: /* SFX */
+			FOR_EACH_OBJECT avi[i].sfx = grf_load_byte(&buf);
+			break;
+
+		case 0x13: /* Cargos available for refitting */
+			FOR_EACH_OBJECT ei[i].refit_mask = grf_load_dword(&buf);
+			break;
+
+		case 0x14: /* Callback mask */
+			FOR_EACH_OBJECT ei[i].callbackmask = grf_load_byte(&buf);
+			break;
+
+		case 0x15: /* Refit cost */
+			FOR_EACH_OBJECT ei[i].refit_cost = grf_load_byte(&buf);
+			break;
+
+		case 0x17: /* Miscellaneous flags */
+			FOR_EACH_OBJECT {
+				ei[i].misc_flags = grf_load_byte(&buf);
+				if (HASBIT(ei[i].misc_flags, EF_USES_2CC)) _have_2cc = true;
+			}
+			break;
+
+		case 0x18: /* Cargo classes allowed */
+			FOR_EACH_OBJECT cargo_allowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x19: /* Cargo classes disallowed */
+			FOR_EACH_OBJECT cargo_disallowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			break;
+
+		case 0x1A: /* Long format introduction date (days since year 0) */
+			FOR_EACH_OBJECT ei[i].base_intro = grf_load_dword(&buf);
+			break;
+
+		case 0x16: /* Retire vehicle early */
+			/* TODO */
+			FOR_EACH_OBJECT grf_load_byte(&buf);
+			ret = true;
+			break;
+
+		default:
+			ret = true;
+			break;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
+{
+	StationSpec **statspec;
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	if (stid + numinfo > MAX_STATIONS) {
+		grfmsg(1, "StationChangeInfo: Station %u is invalid, max %u, ignoring", stid + numinfo, MAX_STATIONS);
+		return false;
+	}
+
+	/* Allocate station specs if necessary */
+	if (_cur_grffile->stations == NULL) _cur_grffile->stations = calloc(MAX_STATIONS, sizeof(*_cur_grffile->stations));
+
+	statspec = &_cur_grffile->stations[stid];
+
+	if (prop != 0x08) {
+		/* Check that all stations we are modifying are defined. */
+		FOR_EACH_OBJECT {
+			if (statspec[i] == NULL) {
+				grfmsg(2, "StationChangeInfo: Attempt to modify undefined station %u, ignoring", stid + i);
+				return false;
+			}
+		}
+	}
+
+	switch (prop) {
+		case 0x08: /* Class ID */
+			FOR_EACH_OBJECT {
+				uint32 classid;
+
+				/* Property 0x08 is special; it is where the station is allocated */
+				if (statspec[i] == NULL) statspec[i] = calloc(1, sizeof(*statspec[i]));
+
+				/* Swap classid because we read it in BE meaning WAYP or DFLT */
+				classid = grf_load_dword(&buf);
+				statspec[i]->sclass = AllocateStationClass(BSWAP32(classid));
+			}
+			break;
+
+		case 0x09: /* Define sprite layout */
+			FOR_EACH_OBJECT {
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
+				uint t;
+
+				statspec->tiles = grf_load_extended(&buf);
+				statspec->renderdata = calloc(statspec->tiles, sizeof(*statspec->renderdata));
+				statspec->copied_renderdata = false;
+
+				for (t = 0; t < statspec->tiles; t++) {
+					DrawTileSprites *dts = &statspec->renderdata[t];
+					uint seq_count = 0;
+
+					dts->seq = NULL;
+					dts->ground_sprite = grf_load_dword(&buf);
+					if (dts->ground_sprite == 0) continue;
+
+					while (buf < *bufp + len) {
+						DrawTileSeqStruct *dtss;
+
+						// no relative bounding box support
+						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
+						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
+
+						dtss->delta_x = grf_load_byte(&buf);
+						if ((byte) dtss->delta_x == 0x80) break;
+						dtss->delta_y = grf_load_byte(&buf);
+						dtss->delta_z = grf_load_byte(&buf);
+						dtss->size_x = grf_load_byte(&buf);
+						dtss->size_y = grf_load_byte(&buf);
+						dtss->size_z = grf_load_byte(&buf);
+						dtss->image = grf_load_dword(&buf);
+
+						/* Remap flags as ours collide */
+						if (HASBIT(dtss->image, 31)) {
+							CLRBIT(dtss->image, 31);
+							SETBIT(dtss->image, 30);
+						}
+						if (HASBIT(dtss->image, 14)) {
+							CLRBIT(dtss->image, 14);
+							SETBIT(dtss->image, 31);
+						}
+					}
+				}
+			}
+			break;
+
+		case 0x0A: /* Copy sprite layout */
+			FOR_EACH_OBJECT {
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
+				byte srcid = grf_load_byte(&buf);
+				const StationSpec *srcstatspec = _cur_grffile->stations[srcid];
+
+				statspec->tiles = srcstatspec->tiles;
+				statspec->renderdata = srcstatspec->renderdata;
+				statspec->copied_renderdata = true;
+			}
+			break;
+
+		case 0x0B: /* Callback mask */
+			FOR_EACH_OBJECT statspec[i]->callbackmask = grf_load_byte(&buf);
+			break;
+
+		case 0x0C: /* Disallowed number of platforms */
+			FOR_EACH_OBJECT statspec[i]->disallowed_platforms = grf_load_byte(&buf);
+			break;
+
+		case 0x0D: /* Disallowed platform lengths */
+			FOR_EACH_OBJECT statspec[i]->disallowed_lengths = grf_load_byte(&buf);
+			break;
+
+		case 0x0E: /* Define custom layout */
+			FOR_EACH_OBJECT {
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
+
+				statspec->copied_layouts = false;
+
+				while (buf < *bufp + len) {
+					byte length = grf_load_byte(&buf);
+					byte number = grf_load_byte(&buf);
+					StationLayout layout;
+					uint l, p;
+
+					if (length == 0 || number == 0) break;
+
+					//debug("l %d > %d ?", length, stat->lengths);
+					if (length > statspec->lengths) {
+						statspec->platforms = realloc(statspec->platforms, length);
+						memset(statspec->platforms + statspec->lengths, 0, length - statspec->lengths);
+
+						statspec->layouts = realloc(statspec->layouts, length * sizeof(*statspec->layouts));
+						memset(statspec->layouts + statspec->lengths, 0,
+						       (length - statspec->lengths) * sizeof(*statspec->layouts));
+
+						statspec->lengths = length;
+					}
+					l = length - 1; // index is zero-based
+
+					//debug("p %d > %d ?", number, stat->platforms[l]);
+					if (number > statspec->platforms[l]) {
+						statspec->layouts[l] = realloc(statspec->layouts[l],
+						                               number * sizeof(**statspec->layouts));
+						// We expect NULL being 0 here, but C99 guarantees that.
+						memset(statspec->layouts[l] + statspec->platforms[l], 0,
+						       (number - statspec->platforms[l]) * sizeof(**statspec->layouts));
+
+						statspec->platforms[l] = number;
+					}
+
+					p = 0;
+					layout = malloc(length * number);
+					for (l = 0; l < length; l++) {
+						for (p = 0; p < number; p++) {
+							layout[l * number + p] = grf_load_byte(&buf);
+						}
+					}
+
+					l--;
+					p--;
+					free(statspec->layouts[l][p]);
+					statspec->layouts[l][p] = layout;
+				}
+			}
+			break;
+
+		case 0x0F: /* Copy custom layout */
+			FOR_EACH_OBJECT {
+				StationSpec *statspec = _cur_grffile->stations[stid + i];
+				byte srcid = grf_load_byte(&buf);
+				const StationSpec *srcstatspec = _cur_grffile->stations[srcid];
+
+				statspec->lengths   = srcstatspec->lengths;
+				statspec->platforms = srcstatspec->platforms;
+				statspec->layouts   = srcstatspec->layouts;
+				statspec->copied_layouts = true;
+			}
+			break;
+
+		case 0x10: /* Little/lots cargo threshold */
+			FOR_EACH_OBJECT statspec[i]->cargo_threshold = grf_load_word(&buf);
+			break;
+
+		case 0x11: /* Pylon placement */
+			FOR_EACH_OBJECT statspec[i]->pylons = grf_load_byte(&buf);
+			break;
+
+		case 0x12: /* Cargo types for random triggers */
+			FOR_EACH_OBJECT statspec[i]->cargo_triggers = grf_load_dword(&buf);
+			break;
+
+		case 0x13: /* General flags */
+			FOR_EACH_OBJECT statspec[i]->flags = grf_load_byte(&buf);
+			break;
+
+		case 0x14: /* Overhead wire placement */
+			FOR_EACH_OBJECT statspec[i]->wires = grf_load_byte(&buf);
+			break;
+
+		case 0x15: /* Blocked tiles */
+			FOR_EACH_OBJECT statspec[i]->blocked = grf_load_byte(&buf);
+			break;
+
+		default:
+			ret = true;
+			break;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool BridgeChangeInfo(uint brid, int numinfo, int prop, byte **bufp, int len)
+{
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	switch (prop) {
+		case 0x08: /* Year of availability */
+			FOR_EACH_OBJECT _bridge[brid + i].avail_year = ORIGINAL_BASE_YEAR + grf_load_byte(&buf);
+			break;
+
+		case 0x09: /* Minimum length */
+			FOR_EACH_OBJECT _bridge[brid + i].min_length = grf_load_byte(&buf);
+			break;
+
+		case 0x0A: /* Maximum length */
+			FOR_EACH_OBJECT _bridge[brid + i].max_length = grf_load_byte(&buf);
+			break;
+
+		case 0x0B: /* Cost factor */
+			FOR_EACH_OBJECT _bridge[brid + i].price = grf_load_byte(&buf);
+			break;
+
+		case 0x0C: /* Maximum speed */
+			FOR_EACH_OBJECT _bridge[brid + i].speed = grf_load_word(&buf);
+			break;
+
+		case 0x0D: /* Bridge sprite tables */
+			FOR_EACH_OBJECT {
+				Bridge *bridge = &_bridge[brid + i];
+				byte tableid = grf_load_byte(&buf);
+				byte numtables = grf_load_byte(&buf);
+
+				if (bridge->sprite_table == NULL) {
+					/* Allocate memory for sprite table pointers and zero out */
+					bridge->sprite_table = calloc(7, sizeof(*bridge->sprite_table));
+				}
+
+				for (; numtables-- != 0; tableid++) {
+					byte sprite;
+
+					if (tableid >= 7) { // skip invalid data
+						grfmsg(1, "BridgeChangeInfo: Table %d >= 7, skipping", tableid);
+						for (sprite = 0; sprite < 32; sprite++) grf_load_dword(&buf);
+						continue;
+					}
+
+					if (bridge->sprite_table[tableid] == NULL) {
+						bridge->sprite_table[tableid] = malloc(32 * sizeof(**bridge->sprite_table));
+					}
+
+					for (sprite = 0; sprite < 32; sprite++)
+						bridge->sprite_table[tableid][sprite] = grf_load_dword(&buf);
+				}
+			}
+			break;
+
+		case 0x0E: /* Flags; bit 0 - disable far pillars */
+			FOR_EACH_OBJECT _bridge[brid + i].flags = grf_load_byte(&buf);
+			break;
+
+		case 0x0F: /* Long format year of availability (year since year 0) */
+			FOR_EACH_OBJECT _bridge[brid + i].avail_year = clamp(grf_load_dword(&buf), MIN_YEAR, MAX_YEAR);
+			break;
+
+		default:
+			ret = true;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, int len)
+{
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	switch (prop) {
+		case 0x08: /* Cost base factor */
+			FOR_EACH_OBJECT {
+				byte factor = grf_load_byte(&buf);
+				uint price = gvid + i;
+
+				if (price < NUM_PRICES) {
+					SetPriceBaseMultiplier(price, factor);
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Price %d out of range, ignoring", price);
+				}
+			}
+			break;
+
+		case 0x0A: // Currency display names
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				StringID newone = GetGRFStringID(_cur_grffile->grfid, grf_load_word(&buf));
+
+				if ((newone != STR_UNDEFINED) && (curidx < NUM_CURRENCY)) {
+					_currency_specs[curidx].name = newone;
+				}
+			}
+			break;
+
+		case 0x0B: // Currency multipliers
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				uint32 rate = grf_load_dword(&buf);
+
+				if (curidx < NUM_CURRENCY) {
+					/* TTDPatch uses a multiple of 1000 for its conversion calculations,
+					 * which OTTD does not. For this reason, divide grf value by 1000,
+					 * to be compatible */
+					_currency_specs[curidx].rate = rate / 1000;
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Currency multipliers %d out of range, ignoring", curidx);
+				}
+			}
+			break;
+
+		case 0x0C: // Currency options
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				uint16 options = grf_load_word(&buf);
+
+				if (curidx < NUM_CURRENCY) {
+					_currency_specs[curidx].separator = GB(options, 0, 8);
+					/* By specifying only one bit, we prevent errors,
+					 * since newgrf specs said that only 0 and 1 can be set for symbol_pos */
+					_currency_specs[curidx].symbol_pos = GB(options, 8, 1);
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Currency option %d out of range, ignoring", curidx);
+				}
+			}
+			break;
+
+		case 0x0D: // Currency prefix symbol
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				uint32 tempfix = grf_load_dword(&buf);
+
+				if (curidx < NUM_CURRENCY) {
+					memcpy(_currency_specs[curidx].prefix,&tempfix,4);
+					_currency_specs[curidx].prefix[4] = 0;
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
+				}
+			}
+			break;
+
+		case 0x0E: // Currency suffix symbol
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				uint32 tempfix = grf_load_dword(&buf);
+
+				if (curidx < NUM_CURRENCY) {
+					memcpy(&_currency_specs[curidx].suffix,&tempfix,4);
+					_currency_specs[curidx].suffix[4] = 0;
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
+				}
+			}
+			break;
+
+		case 0x0F: //  Euro introduction dates
+			FOR_EACH_OBJECT {
+				uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
+				Year year_euro = grf_load_word(&buf);
+
+				if (curidx < NUM_CURRENCY) {
+					_currency_specs[curidx].to_euro = year_euro;
+				} else {
+					grfmsg(1, "GlobalVarChangeInfo: Euro intro date %d out of range, ignoring", curidx);
+				}
+			}
+			break;
+
+		case 0x09: // Cargo translation table
+		case 0x10: // 12 * 32 * B Snow line height table
+		default:
+			ret = true;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+static bool SoundEffectChangeInfo(uint sid, int numinfo, int prop, byte **bufp, int len)
+{
+	byte *buf = *bufp;
+	int i;
+	bool ret = false;
+
+	if (_cur_grffile->sound_offset == 0) {
+		grfmsg(1, "SoundEffectChangeInfo: No effects defined, skipping");
+		return false;
+	}
+
+	switch (prop) {
+		case 0x08: /* Relative volume */
+			FOR_EACH_OBJECT {
+				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
+
+				if (sound >= GetNumSounds()) {
+					grfmsg(1, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
+				} else {
+					GetSound(sound)->volume = grf_load_byte(&buf);
+				}
+			}
+			break;
+
+		case 0x09: /* Priority */
+			FOR_EACH_OBJECT {
+				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
+
+				if (sound >= GetNumSounds()) {
+					grfmsg(1, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
+				} else {
+					GetSound(sound)->priority = grf_load_byte(&buf);
+				}
+			}
+			break;
+
+		case 0x0A: /* Override old sound */
+			FOR_EACH_OBJECT {
+				uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
+				uint orig_sound = grf_load_byte(&buf);
+
+				if (sound >= GetNumSounds() || orig_sound >= GetNumSounds()) {
+					grfmsg(1, "SoundEffectChangeInfo: Sound %d or %d not defined (max %d)", sound, orig_sound, GetNumSounds());
+				} else {
+					FileEntry *newfe = GetSound(sound);
+					FileEntry *oldfe = GetSound(orig_sound);
+
+					/* Literally copy the data of the new sound over the original */
+					*oldfe = *newfe;
+				}
+			}
+			break;
+
+		default:
+			ret = true;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+/* Action 0x00 */
+static void FeatureChangeInfo(byte *buf, int len)
+{
+	byte *bufend = buf + len;
+	int i;
+
+	/* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
+	 *
+	 * B feature       0, 1, 2 or 3 for trains, road vehicles, ships or planes
+	 *                 4 for defining new train station sets
+	 * B num-props     how many properties to change per vehicle/station
+	 * B num-info      how many vehicles/stations to change
+	 * B id            ID of first vehicle/station to change, if num-info is
+	 *                 greater than one, this one and the following
+	 *                 vehicles/stations will be changed
+	 * B property      what property to change, depends on the feature
+	 * V new-info      new bytes of info (variable size; depends on properties) */
+	/* TODO: Bridges, town houses. */
+
+	static const VCI_Handler handler[] = {
+		/* GSF_TRAIN */        RailVehicleChangeInfo,
+		/* GSF_ROAD */         RoadVehicleChangeInfo,
+		/* GSF_SHIP */         ShipVehicleChangeInfo,
+		/* GSF_AIRCRAFT */     AircraftVehicleChangeInfo,
+		/* GSF_STATION */      StationChangeInfo,
+		/* GSF_CANAL */        NULL,
+		/* GSF_BRIDGE */       BridgeChangeInfo,
+		/* GSF_TOWNHOUSE */    NULL,
+		/* GSF_GLOBALVAR */    GlobalVarChangeInfo,
+		/* GSF_INDUSTRYTILES */NULL,
+		/* GSF_INDUSTRIES */   NULL,
+		/* GSF_CARGOS */       NULL,
+		/* GSF_SOUNDFX */      SoundEffectChangeInfo,
+	};
+
+	uint8 feature;
+	uint8 numprops;
+	uint8 numinfo;
+	byte engine;
+	EngineInfo *ei = NULL;
+
+	if (len == 1) {
+		grfmsg(8, "Silently ignoring one-byte special sprite 0x00");
+		return;
+	}
+
+	check_length(len, 6, "FeatureChangeInfo");
+	buf++;
+	feature  = grf_load_byte(&buf);
+	numprops = grf_load_byte(&buf);
+	numinfo  = grf_load_byte(&buf);
+	engine   = grf_load_byte(&buf);
+
+	grfmsg(6, "FeatureChangeInfo: feature %d, %d properties, to apply to %d+%d",
+	               feature, numprops, engine, numinfo);
+
+	if (feature >= lengthof(handler) || handler[feature] == NULL) {
+		grfmsg(1, "FeatureChangeInfo: Unsupported feature %d, skipping", feature);
+		return;
+	}
+
+	if (feature <= GSF_AIRCRAFT) {
+		if (engine + numinfo > _vehcounts[feature]) {
+			grfmsg(0, "FeatureChangeInfo: Last engine ID %d out of bounds (max %d), skipping", engine + numinfo, _vehcounts[feature]);
+			return;
+		}
+		ei = &_engine_info[engine + _vehshifts[feature]];
+	}
+
+	while (numprops-- && buf < bufend) {
+		uint8 prop = grf_load_byte(&buf);
+		bool ignoring = false;
+
+		switch (feature) {
+			case GSF_TRAIN:
+			case GSF_ROAD:
+			case GSF_SHIP:
+			case GSF_AIRCRAFT:
+				/* Common properties for vehicles */
+				switch (prop) {
+					case 0x00: /* Introduction date */
+						FOR_EACH_OBJECT ei[i].base_intro = grf_load_word(&buf) + DAYS_TILL_ORIGINAL_BASE_YEAR;
+						break;
+
+					case 0x02: /* Decay speed */
+						FOR_EACH_OBJECT SB(ei[i].unk2, 0, 7, grf_load_byte(&buf) & 0x7F);
+						break;
+
+					case 0x03: /* Vehicle life */
+						FOR_EACH_OBJECT ei[i].lifelength = grf_load_byte(&buf);
+						break;
+
+					case 0x04: /* Model life */
+						FOR_EACH_OBJECT ei[i].base_life = grf_load_byte(&buf);
+						break;
+
+					case 0x06: /* Climates available */
+						FOR_EACH_OBJECT ei[i].climates = grf_load_byte(&buf);
+						break;
+
+					case 0x07: /* Loading speed */
+						/* Hyronymus explained me what does
+						 * this mean and insists on having a
+						 * credit ;-). --pasky */
+						FOR_EACH_OBJECT ei[i].load_amount = grf_load_byte(&buf);
+						break;
+
+					default:
+						if (handler[feature](engine, numinfo, prop, &buf, bufend - buf))
+							ignoring = true;
+						break;
+				}
+				break;
+
+			default:
+				if (handler[feature](engine, numinfo, prop, &buf, bufend - buf))
+					ignoring = true;
+				break;
+		}
+
+		if (ignoring) grfmsg(2, "FeatureChangeInfo: Ignoring property 0x%02X (not implemented)", prop);
+	}
+}
+
+/* Action 0x00 (GLS_SAFETYSCAN) */
+static void SafeChangeInfo(byte *buf, int len)
+{
+	uint8 feature;
+	uint8 numprops;
+	uint8 numinfo;
+	uint8 index;
+
+	check_length(len, 6, "SafeChangeInfo");
+	buf++;
+	feature  = grf_load_byte(&buf);
+	numprops = grf_load_byte(&buf);
+	numinfo  = grf_load_byte(&buf);
+	index    = grf_load_byte(&buf);
+
+	if (feature == GSF_BRIDGE && numprops == 1) {
+		uint8 prop = grf_load_byte(&buf);
+		/* Bridge property 0x0D is redefinition of sprite layout tables, which
+		 * is considered safe. */
+		if (prop == 0x0D) return;
+	}
+
+	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
+
+	/* Skip remainder of GRF */
+	_skip_sprites = -1;
+}
+
+#undef FOR_EACH_OBJECT
+
+/**
+ * Creates a spritegroup representing a callback result
+ * @param value The value that was used to represent this callback result
+ * @return A spritegroup representing that callback result
+ */
+static const SpriteGroup* NewCallBackResultSpriteGroup(uint16 value)
+{
+	SpriteGroup *group = AllocateSpriteGroup();
+
+	group->type = SGT_CALLBACK;
+
+	// Old style callback results have the highest byte 0xFF so signify it is a callback result
+	// New style ones only have the highest bit set (allows 15-bit results, instead of just 8)
+	if ((value >> 8) == 0xFF) {
+		value &= ~0xFF00;
+	} else {
+		value &= ~0x8000;
+	}
+
+	group->g.callback.result = value;
+
+	return group;
+}
+
+/**
+ * Creates a spritegroup representing a sprite number result.
+ * @param value The sprite number.
+ * @param sprites The number of sprites per set.
+ * @return A spritegroup representing the sprite number result.
+ */
+static const SpriteGroup* NewResultSpriteGroup(SpriteID sprite, byte num_sprites)
+{
+	SpriteGroup *group = AllocateSpriteGroup();
+	group->type = SGT_RESULT;
+	group->g.result.sprite = sprite;
+	group->g.result.num_sprites = num_sprites;
+	return group;
+}
+
+/* Action 0x01 */
+static void NewSpriteSet(byte *buf, int len)
+{
+	/* <01> <feature> <num-sets> <num-ent>
+	 *
+	 * B feature       feature to define sprites for
+	 *                 0, 1, 2, 3: veh-type, 4: train stations
+	 * B num-sets      number of sprite sets
+	 * E num-ent       how many entries per sprite set
+	 *                 For vehicles, this is the number of different
+	 *                         vehicle directions in each sprite set
+	 *                         Set num-dirs=8, unless your sprites are symmetric.
+	 *                         In that case, use num-dirs=4.
+	 *                 For stations, must be 12 (hex) for the eighteen
+	 *                         different sprites that make up a station */
+	/* TODO: No stations support. */
+	uint8 feature;
+	uint num_sets;
+	uint num_ents;
+	uint i;
+
+	check_length(len, 4, "NewSpriteSet");
+	buf++;
+	feature  = grf_load_byte(&buf);
+	num_sets = grf_load_byte(&buf);
+	num_ents = grf_load_extended(&buf);
+
+	_cur_grffile->spriteset_start = _cur_spriteid;
+	_cur_grffile->spriteset_feature = feature;
+	_cur_grffile->spriteset_numsets = num_sets;
+	_cur_grffile->spriteset_numents = num_ents;
+
+	grfmsg(7, "New sprite set at %d of type %d, consisting of %d sets with %d views each (total %d)",
+		_cur_spriteid, feature, num_sets, num_ents, num_sets * num_ents
+	);
+
+	for (i = 0; i < num_sets * num_ents; i++) {
+		LoadNextSprite(_cur_spriteid++, _file_index);
+		_nfo_line++;
+	}
+}
+
+/* Helper function to either create a callback or link to a previously
+ * defined spritegroup. */
+static const SpriteGroup* GetGroupFromGroupID(byte setid, byte type, uint16 groupid)
+{
+	if (HASBIT(groupid, 15)) return NewCallBackResultSpriteGroup(groupid);
+
+	if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid);
+		return NULL;
+	}
+
+	return _cur_grffile->spritegroups[groupid];
+}
+
+/* Helper function to either create a callback or a result sprite group. */
+static const SpriteGroup* CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid, uint16 num_sprites)
+{
+	if (HASBIT(spriteid, 15)) return NewCallBackResultSpriteGroup(spriteid);
+
+	if (spriteid >= _cur_grffile->spriteset_numsets) {
+		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Sprite set %u invalid, max %u", setid, type, spriteid, _cur_grffile->spriteset_numsets);
+		return NULL;
+	}
+
+	/* Check if the sprite is within range. This can fail if the Action 0x01
+	 * is skipped, as TTDPatch mandates that Action 0x02s must be processed.
+	 * We don't have that rule, but must live by the Patch... */
+	if (_cur_grffile->spriteset_start + spriteid * num_sprites + num_sprites > _cur_spriteid) {
+		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Real Sprite IDs 0x%04X - 0x%04X do not (all) exist (max 0x%04X), leaving empty",
+				setid, type,
+				_cur_grffile->spriteset_start + spriteid * num_sprites,
+				_cur_grffile->spriteset_start + spriteid * num_sprites + num_sprites - 1, _cur_spriteid - 1);
+		return NULL;
+	}
+
+	if (feature != _cur_grffile->spriteset_feature) {
+		grfmsg(1, "NewSpriteGroup(0x%02X:0x%02X): Sprite set feature 0x%02X does not match action feature 0x%02X, skipping",
+				_cur_grffile->spriteset_feature, feature);
+		return NULL;
+	}
+
+	return NewResultSpriteGroup(_cur_grffile->spriteset_start + spriteid * num_sprites, num_sprites);
+}
+
+/* Action 0x02 */
+static void NewSpriteGroup(byte *buf, int len)
+{
+	/* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
+	 *
+	 * B feature       see action 1
+	 * B set-id        ID of this particular definition
+	 * B type/num-entries
+	 *                 if 80 or greater, this is a randomized or variational
+	 *                 list definition, see below
+	 *                 otherwise it specifies a number of entries, the exact
+	 *                 meaning depends on the feature
+	 * V feature-specific-data (huge mess, don't even look it up --pasky) */
+	uint8 feature;
+	uint8 setid;
+	uint8 type;
+	SpriteGroup *group = NULL;
+	byte *bufend = buf + len;
+
+	check_length(len, 5, "NewSpriteGroup");
+	buf++;
+
+	feature = grf_load_byte(&buf);
+	setid   = grf_load_byte(&buf);
+	type    = grf_load_byte(&buf);
+
+	if (setid >= _cur_grffile->spritegroups_count) {
+		// Allocate memory for new sprite group references.
+		_cur_grffile->spritegroups = realloc(_cur_grffile->spritegroups, (setid + 1) * sizeof(*_cur_grffile->spritegroups));
+		// Initialise new space to NULL
+		for (; _cur_grffile->spritegroups_count < (setid + 1); _cur_grffile->spritegroups_count++)
+			_cur_grffile->spritegroups[_cur_grffile->spritegroups_count] = NULL;
+	}
+
+	switch (type) {
+		/* Deterministic Sprite Group */
+		case 0x81: // Self scope, byte
+		case 0x82: // Parent scope, byte
+		case 0x85: // Self scope, word
+		case 0x86: // Parent scope, word
+		case 0x89: // Self scope, dword
+		case 0x8A: // Parent scope, dword
+		{
+			byte varadjust;
+			byte varsize;
+			uint i;
+
+			/* Check we can load the var size parameter */
+			check_length(bufend - buf, 1, "NewSpriteGroup (Deterministic) (1)");
+
+			group = AllocateSpriteGroup();
+			group->type = SGT_DETERMINISTIC;
+			group->g.determ.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
+
+			switch (GB(type, 2, 2)) {
+				default: NOT_REACHED();
+				case 0: group->g.determ.size = DSG_SIZE_BYTE;  varsize = 1; break;
+				case 1: group->g.determ.size = DSG_SIZE_WORD;  varsize = 2; break;
+				case 2: group->g.determ.size = DSG_SIZE_DWORD; varsize = 4; break;
+			}
+
+			check_length(bufend - buf, 5 + varsize, "NewSpriteGroup (Deterministic) (2)");
+
+			/* Loop through the var adjusts. Unfortunately we don't know how many we have
+			 * from the outset, so we shall have to keep reallocing. */
+			do {
+				DeterministicSpriteGroupAdjust *adjust;
+
+				if (group->g.determ.num_adjusts > 0) {
+					check_length(bufend - buf, 2 + varsize + 3, "NewSpriteGroup (Deterministic) (3)");
+				}
+
+				group->g.determ.num_adjusts++;
+				group->g.determ.adjusts = realloc(group->g.determ.adjusts, group->g.determ.num_adjusts * sizeof(*group->g.determ.adjusts));
+
+				adjust = &group->g.determ.adjusts[group->g.determ.num_adjusts - 1];
+
+				/* The first var adjust doesn't have an operation specified, so we set it to add. */
+				adjust->operation = group->g.determ.num_adjusts == 1 ? DSGA_OP_ADD : grf_load_byte(&buf);
+				adjust->variable  = grf_load_byte(&buf);
+				adjust->parameter = IS_BYTE_INSIDE(adjust->variable, 0x60, 0x80) ? grf_load_byte(&buf) : 0;
+
+				varadjust = grf_load_byte(&buf);
+				adjust->shift_num = GB(varadjust, 0, 5);
+				adjust->type      = GB(varadjust, 6, 2);
+				adjust->and_mask  = grf_load_var(varsize, &buf);
+
+				if (adjust->type != DSGA_TYPE_NONE) {
+					adjust->add_val    = grf_load_var(varsize, &buf);
+					adjust->divmod_val = grf_load_var(varsize, &buf);
+				} else {
+					adjust->add_val    = 0;
+					adjust->divmod_val = 0;
+				}
+
+				/* Continue reading var adjusts while bit 5 is set. */
+			} while (HASBIT(varadjust, 5));
+
+			group->g.determ.num_ranges = grf_load_byte(&buf);
+			group->g.determ.ranges = calloc(group->g.determ.num_ranges, sizeof(*group->g.determ.ranges));
+
+			check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->g.determ.num_ranges, "NewSpriteGroup (Deterministic)");
+
+			for (i = 0; i < group->g.determ.num_ranges; i++) {
+				group->g.determ.ranges[i].group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+				group->g.determ.ranges[i].low   = grf_load_var(varsize, &buf);
+				group->g.determ.ranges[i].high  = grf_load_var(varsize, &buf);
+			}
+
+			group->g.determ.default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+			break;
+		}
+
+		/* Randomized Sprite Group */
+		case 0x80: // Self scope
+		case 0x83: // Parent scope
+		{
+			byte triggers;
+			uint i;
+
+			check_length(bufend - buf, 7, "NewSpriteGroup (Randomized) (1)");
+
+			group = AllocateSpriteGroup();
+			group->type = SGT_RANDOMIZED;
+			group->g.random.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
+
+			triggers = grf_load_byte(&buf);
+			group->g.random.triggers       = GB(triggers, 0, 7);
+			group->g.random.cmp_mode       = HASBIT(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
+			group->g.random.lowest_randbit = grf_load_byte(&buf);
+			group->g.random.num_groups     = grf_load_byte(&buf);
+			group->g.random.groups = calloc(group->g.random.num_groups, sizeof(*group->g.random.groups));
+
+			check_length(bufend - buf, 2 * group->g.random.num_groups, "NewSpriteGroup (Randomized) (2)");
+
+			for (i = 0; i < group->g.random.num_groups; i++) {
+				group->g.random.groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+			}
+
+			break;
+		}
+
+		/* Neither a variable or randomized sprite group... must be a real group */
+		default:
+		{
+
+
+			switch (feature) {
+				case GSF_TRAIN:
+				case GSF_ROAD:
+				case GSF_SHIP:
+				case GSF_AIRCRAFT:
+				case GSF_STATION:
+				{
+					byte sprites     = _cur_grffile->spriteset_numents;
+					byte num_loaded  = type;
+					byte num_loading = grf_load_byte(&buf);
+					uint i;
+
+					if (_cur_grffile->spriteset_start == 0) {
+						grfmsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
+						return;
+					}
+
+					check_length(bufend - buf, 2 * num_loaded + 2 * num_loading, "NewSpriteGroup (Real) (1)");
+
+					group = AllocateSpriteGroup();
+					group->type = SGT_REAL;
+
+					group->g.real.num_loaded  = num_loaded;
+					group->g.real.num_loading = num_loading;
+					if (num_loaded  > 0) group->g.real.loaded  = calloc(num_loaded,  sizeof(*group->g.real.loaded));
+					if (num_loading > 0) group->g.real.loading = calloc(num_loading, sizeof(*group->g.real.loading));
+
+					grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u views, %u loaded, %u loading",
+							setid, sprites, num_loaded, num_loading);
+
+					for (i = 0; i < num_loaded; i++) {
+						uint16 spriteid = grf_load_word(&buf);
+						group->g.real.loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
+						grfmsg(8, "NewSpriteGroup: + rg->loaded[%i]  = subset %u", i, spriteid);
+					}
+
+					for (i = 0; i < num_loading; i++) {
+						uint16 spriteid = grf_load_word(&buf);
+						group->g.real.loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
+						grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid);
+					}
+
+					break;
+				}
+
+				/* Loading of Tile Layout and Production Callback groups would happen here */
+				default: grfmsg(1, "NewSpriteGroup: Unsupported feature %d, skipping", feature);
+			}
+		}
+	}
+
+	_cur_grffile->spritegroups[setid] = group;
+}
+
+/* Action 0x03 */
+static void FeatureMapSpriteGroup(byte *buf, int len)
+{
+	/* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
+	 * id-list    := [<id>] [id-list]
+	 * cargo-list := <cargo-type> <cid> [cargo-list]
+	 *
+	 * B feature       see action 0
+	 * B n-id          bits 0-6: how many IDs this definition applies to
+	 *                 bit 7: if set, this is a wagon override definition (see below)
+	 * B ids           the IDs for which this definition applies
+	 * B num-cid       number of cargo IDs (sprite group IDs) in this definition
+	 *                 can be zero, in that case the def-cid is used always
+	 * B cargo-type    type of this cargo type (e.g. mail=2, wood=7, see below)
+	 * W cid           cargo ID (sprite group ID) for this type of cargo
+	 * W def-cid       default cargo ID (sprite group ID) */
+	/* TODO: Bridges, town houses. */
+	/* TODO: Multiple cargo support could be useful even for trains/cars -
+	 * cargo id 0xff is used for showing images in the build train list. */
+
+	static byte *last_engines;
+	static int last_engines_count;
+	uint8 feature;
+	uint8 idcount;
+	bool wagover;
+	uint8 cidcount;
+	int c, i;
+
+	check_length(len, 6, "FeatureMapSpriteGroup");
+	feature = buf[1];
+	idcount = buf[2] & 0x7F;
+	wagover = (buf[2] & 0x80) == 0x80;
+	check_length(len, 3 + idcount, "FeatureMapSpriteGroup");
+
+	/* If ``n-id'' (or ``idcount'') is zero, this is a ``feature
+	 * callback''. */
+	if (idcount == 0) {
+		grfmsg(2, "FeatureMapSpriteGroup: Feature callbacks not implemented yet");
+		return;
+	}
+
+	cidcount = buf[3 + idcount];
+	check_length(len, 4 + idcount + cidcount * 3, "FeatureMapSpriteGroup");
+
+	grfmsg(6, "FeatureMapSpriteGroup: Feature %d, %d ids, %d cids, wagon override %d",
+			feature, idcount, cidcount, wagover);
+
+	if (feature > GSF_STATION) {
+		grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %d, skipping", feature);
+		return;
+	}
+
+
+	if (feature == GSF_STATION) {
+		// We do things differently for stations.
+
+		for (i = 0; i < idcount; i++) {
+			uint8 stid = buf[3 + i];
+			StationSpec *statspec = _cur_grffile->stations[stid];
+			byte *bp = &buf[4 + idcount];
+
+			for (c = 0; c < cidcount; c++) {
+				uint8 ctype = grf_load_byte(&bp);
+				uint16 groupid = grf_load_word(&bp);
+
+				if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+					grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping",
+					       groupid, _cur_grffile->spritegroups_count);
+					return;
+				}
+
+				if (ctype == 0xFE) ctype = GC_DEFAULT_NA;
+				if (ctype == 0xFF) ctype = GC_PURCHASE;
+
+				if (ctype >= NUM_GLOBAL_CID) {
+					grfmsg(1, "FeatureMapSpriteGroup: Cargo type %d out of range, skipping.", ctype);
+					continue;
+				}
+
+				statspec->spritegroup[ctype] = _cur_grffile->spritegroups[groupid];
+			}
+		}
+
+		{
+			byte *bp = buf + 4 + idcount + cidcount * 3;
+			uint16 groupid = grf_load_word(&bp);
+
+			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping",
+				       groupid, _cur_grffile->spritegroups_count);
+				return;
+			}
+
+			for (i = 0; i < idcount; i++) {
+				uint8 stid = buf[3 + i];
+				StationSpec *statspec = _cur_grffile->stations[stid];
+
+				statspec->spritegroup[GC_DEFAULT] = _cur_grffile->spritegroups[groupid];
+				statspec->grfid = _cur_grffile->grfid;
+				statspec->localidx = stid;
+				SetCustomStationSpec(statspec);
+			}
+		}
+		return;
+	}
+
+	// FIXME: Tropicset contains things like:
+	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
+	// what should we exactly do with that? --pasky
+
+	if (_cur_grffile->spriteset_start == 0 || _cur_grffile->spritegroups == 0) {
+		grfmsg(1, "FeatureMapSpriteGroup: No sprite set to work on! Skipping");
+		return;
+	}
+
+	if (!wagover && last_engines_count != idcount) {
+		last_engines = realloc(last_engines, idcount);
+		last_engines_count = idcount;
+	}
+
+	if (wagover) {
+		if (last_engines_count == 0) {
+			grfmsg(0, "FeatureMapSpriteGroup: WagonOverride: No engine to do override with");
+			return;
+		}
+		grfmsg(6, "FeatureMapSpriteGroup: WagonOverride: %u engines, %u wagons",
+				last_engines_count, idcount);
+	}
+
+
+	for (i = 0; i < idcount; i++) {
+		uint8 engine_id = buf[3 + i];
+		uint8 engine = engine_id + _vehshifts[feature];
+		byte *bp = &buf[4 + idcount];
+
+		if (engine_id > _vehcounts[feature]) {
+			grfmsg(0, "Id %u for feature 0x%02X is out of bounds", engine_id, feature);
+			return;
+		}
+
+		grfmsg(7, "FeatureMapSpriteGroup: [%d] Engine %d...", i, engine);
+
+		for (c = 0; c < cidcount; c++) {
+			uint8 ctype = grf_load_byte(&bp);
+			uint16 groupid = grf_load_word(&bp);
+
+			grfmsg(8, "FeatureMapSpriteGroup: * [%d] Cargo type 0x%X, group id 0x%02X", c, ctype, groupid);
+
+			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping", groupid, _cur_grffile->spritegroups_count);
+				return;
+			}
+
+			if (ctype == GC_INVALID) ctype = GC_PURCHASE;
+
+			if (ctype >= NUM_GLOBAL_CID) {
+				grfmsg(1, "FeatureMapSpriteGroup: Cargo type %d out of range, skipping.", ctype);
+				continue;
+			}
+
+			if (wagover) {
+				SetWagonOverrideSprites(engine, ctype, _cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
+			} else {
+				SetCustomEngineSprites(engine, ctype, _cur_grffile->spritegroups[groupid]);
+				last_engines[i] = engine;
+			}
+		}
+	}
+
+	{
+		byte *bp = buf + 4 + idcount + cidcount * 3;
+		uint16 groupid = grf_load_word(&bp);
+
+		grfmsg(8, "-- Default group id 0x%04X", groupid);
+
+		for (i = 0; i < idcount; i++) {
+			uint8 engine = buf[3 + i] + _vehshifts[feature];
+
+			// Don't tell me you don't love duplicated code!
+			if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
+				grfmsg(1, "FeatureMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping", groupid, _cur_grffile->spritegroups_count);
+				return;
+			}
+
+			if (wagover) {
+				/* If the ID for this action 3 is the same as the vehicle ID,
+				 * this indicates we have a helicopter rotor override. */
+				if (feature == GSF_AIRCRAFT && engine == last_engines[i]) {
+					SetRotorOverrideSprites(engine, _cur_grffile->spritegroups[groupid]);
+				} else {
+					// TODO: No multiple cargo types per vehicle yet. --pasky
+					SetWagonOverrideSprites(engine, GC_DEFAULT, _cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
+				}
+			} else {
+				SetCustomEngineSprites(engine, GC_DEFAULT, _cur_grffile->spritegroups[groupid]);
+				SetEngineGRF(engine, _cur_grffile);
+				last_engines[i] = engine;
+			}
+		}
+	}
+}
+
+/* Action 0x04 */
+static void FeatureNewName(byte *buf, int len)
+{
+	/* <04> <veh-type> <language-id> <num-veh> <offset> <data...>
+	 *
+	 * B veh-type      see action 0 (as 00..07, + 0A
+	 *                 But IF veh-type = 48, then generic text
+	 * B language-id   If bit 6 is set, This is the extended language scheme,
+	                   with up to 64 language.
+	                   Otherwise, it is a mapping where set bits have meaning
+	                   0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish
+	                   Bit 7 set means this is a generic text, not a vehicle one (or else)
+	 * B num-veh       number of vehicles which are getting a new name
+	 * B/W offset      number of the first vehicle that gets a new name
+	 *                 Byte : ID of vehicle to change
+	 *                 Word : ID of string to change/add
+	 * S data          new texts, each of them zero-terminated, after
+	 *                 which the next name begins. */
+	/* TODO: No support for changing non-vehicle text. Perhaps we shouldn't
+	 * implement it at all, but it could be useful for some "modpacks"
+	 * (completely new scenarios changing all graphics and logically also
+	 * factory names etc). We should then also support all languages (by
+	 * name), not only the original four ones. --pasky
+	 * All of the above are coming.  In Time.  Some sooner than others :)*/
+
+	uint8 feature;
+	uint8 lang;
+	uint8 num;
+	uint16 id;
+	uint16 endid;
+	const char* name;
+	bool new_scheme = _cur_grffile->grf_version >= 7;
+	bool generic;
+
+	check_length(len, 6, "FeatureNewName");
+	buf++;
+	feature  = grf_load_byte(&buf);
+	lang     = grf_load_byte(&buf);
+	num      = grf_load_byte(&buf);
+	generic  = HASBIT(lang, 7);
+	id       = generic ? grf_load_word(&buf) : grf_load_byte(&buf);
+
+	CLRBIT(lang, 7);
+
+	if (feature <= GSF_AIRCRAFT && id < _vehcounts[feature]) {
+		id += _vehshifts[feature];
+	}
+	endid    = id + num;
+
+	grfmsg(6, "FeatureNewName: About to rename engines %d..%d (feature %d) in language 0x%02X",
+	               id, endid, feature, lang);
+
+	name = (const char*)buf; /*transfer read value*/
+	len -= generic ? 6 : 5;
+
+	for (; id < endid && len > 0; id++) {
+		size_t ofs = strlen(name) + 1;
+
+		if (ofs < 128) {
+			grfmsg(8, "FeatureNewName: %d <- %s", id, name);
+
+			switch (feature) {
+				case GSF_TRAIN:
+				case GSF_ROAD:
+				case GSF_SHIP:
+				case GSF_AIRCRAFT: {
+					if (id < TOTAL_NUM_ENGINES) {
+						StringID string = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_8000_KIRBY_PAUL_TANK_STEAM + id);
+						SetCustomEngineName(id, string);
+					} else {
+						AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, id);
+					}
+					break;
+				}
+
+				default:
+					switch (GB(id, 8, 8)) {
+						case 0xC4: /* Station class name */
+							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
+								grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8));
+							} else {
+								StationClassID sclass = _cur_grffile->stations[GB(id, 0, 8)]->sclass;
+								SetStationClassName(sclass, AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED));
+							}
+							break;
+
+						case 0xC5: /* Station name */
+							if (_cur_grffile->stations == NULL || _cur_grffile->stations[GB(id, 0, 8)] == NULL) {
+								grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8));
+							} else {
+								_cur_grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
+							}
+							break;
+
+						case 0xC9:
+						case 0xD0:
+						case 0xDC:
+							AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_UNDEFINED);
+							break;
+
+						default:
+							grfmsg(7, "FeatureNewName: Unsupported ID (0x%04X)", id);
+							break;
+					}
+					break;
+
+#if 0
+				case GSF_CANAL :
+				case GSF_BRIDGE :
+				case GSF_TOWNHOUSE :
+					AddGRFString(_cur_spriteid, id, lang, name);
+					switch (GB(id, 8,8)) {
+						case 0xC9: /* House name */
+						default:
+							grfmsg(7, "FeatureNewName: Unsupported ID (0x%04X)", id);
+					}
+					break;
+
+				case GSF_INDUSTRIES :
+				case 0x48 :   /* for generic strings */
+					AddGRFString(_cur_spriteid, id, lang, name);
+					break;
+				default :
+					grfmsg(7, "FeatureNewName: Unsupported feature (0x%02X)", feature);
+					break;
+#endif
+			}
+		} else {
+			/* ofs is the string length + 1, so if the string is empty, ofs
+			 * is 1 */
+			if (ofs == 1) {
+				grfmsg(7, "FeatureNewName: Can't add empty name");
+			} else {
+				grfmsg(7, "FeatureNewName: Too long a name (%d)", ofs);
+			}
+		}
+		name += ofs;
+		len -= (int)ofs;
+	}
+}
+
+/* Action 0x05 */
+static void GraphicsNew(byte *buf, int len)
+{
+	/* <05> <graphics-type> <num-sprites> <other data...>
+	 *
+	 * B graphics-type What set of graphics the sprites define.
+	 * E num-sprites   How many sprites are in this set?
+	 * V other data    Graphics type specific data.  Currently unused. */
+	/* TODO */
+
+	uint8 type;
+	uint16 num;
+	SpriteID replace = 0;
+
+	check_length(len, 2, "GraphicsNew");
+	buf++;
+	type = grf_load_byte(&buf);
+	num  = grf_load_extended(&buf);
+
+	switch (type) {
+		case 0x04: /* Signal graphics */
+			if (num != 112 && num != 240) {
+				grfmsg(1, "GraphicsNews: Signal graphics sprite count must be 112 or 240, skipping");
+				return;
+			}
+			_signal_base = _cur_spriteid;
+			break;
+
+		case 0x05: /* Catenary graphics */
+			if (num != 48) {
+				grfmsg(1, "GraphicsNews: Catenary graphics sprite count must be 48, skipping");
+				return;
+			}
+			replace = SPR_ELRAIL_BASE + 3;
+			break;
+
+		case 0x06: /* Foundations */
+			if (num != 74) {
+				grfmsg(1, "GraphicsNews: Foundation graphics sprite count must be 74, skipping");
+				return;
+			}
+			replace = SPR_SLOPES_BASE;
+			break;
+
+		case 0x08: /* Canal graphics */
+			if (num != 65) {
+				grfmsg(1, "GraphicsNews: Canal graphics sprite count must be 65, skipping");
+				return;
+			}
+			replace = SPR_CANALS_BASE + 5;
+			break;
+
+		case 0x0D: /* Coast graphics */
+			if (num != 16) {
+				grfmsg(1, "GraphicsNews: Coast graphics sprite count must be 16, skipping");
+				return;
+			}
+			_coast_base = _cur_spriteid;
+			break;
+
+		default:
+			grfmsg(2, "GraphicsNew: Custom graphics (type 0x%02X) sprite block of length %u (unimplemented, ignoring)",
+					type, num);
+			return;
+	}
+
+	if (replace == 0) {
+		grfmsg(2, "GraphicsNew: Loading %u sprites of type 0x%02X at SpriteID 0x%04X", num, type, _cur_spriteid);
+	} else {
+		grfmsg(2, "GraphicsNew: Replacing %u sprites of type 0x%02X at SpriteID 0x%04X", num, type, replace);
+	}
+
+	for (; num > 0; num--) {
+		LoadNextSprite(replace == 0 ? _cur_spriteid++ : replace++, _file_index);
+		_nfo_line++;
+	}
+}
+
+static uint32 GetParamVal(byte param, uint32 *cond_val)
+{
+	switch (param) {
+		case 0x81: /* current year */
+			return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
+
+		case 0x83: /* current climate, 0=temp, 1=arctic, 2=trop, 3=toyland */
+			return _opt.landscape;
+
+		case 0x84: /* GRF loading stage */
+			return (_cur_stage > GLS_INIT) | ((_cur_stage == GLS_ACTIVATION) << 9);
+
+		case 0x85: /* TTDPatch flags, only for bit tests */
+			if (cond_val == NULL) {
+				/* Supported in Action 0x07 and 0x09, not 0x0D */
+				return 0;
+			} else {
+				uint32 param_val = _ttdpatch_flags[*cond_val / 0x20];
+				*cond_val %= 0x20;
+				return param_val;
+			}
+
+		case 0x86: /* road traffic side, bit 4 clear=left, set=right */
+			return _opt.road_side << 4;
+
+		case 0x88: /* GRF ID check */
+			return 0;
+
+		case 0x8B: { /* TTDPatch version */
+			uint major    = 2;
+			uint minor    = 6;
+			uint revision = 0; // special case: 2.0.1 is 2.0.10
+			uint build    = 1168;
+			return (major << 24) | (minor << 20) | (revision << 16) | build;
+		}
+
+		case 0x8D: /* TTD Version, 00=DOS, 01=Windows */
+			return !_use_dos_palette;
+
+		case 0x8E: /* Y-offset for train sprites */
+			return _traininfo_vehicle_pitch;
+
+		case 0x92: /* Game mode */
+			return _game_mode;
+
+		case 0x9A: /* Always -1 */
+			return -1;
+
+		case 0x9D: /* TTD Platform, 00=TTDPatch, 01=OpenTTD */
+			return 1;
+
+		case 0x9E: /* Miscellaneous GRF features */
+			return _misc_grf_features;
+
+		default:
+			/* GRF Parameter */
+			if (param < 0x80) return _cur_grffile->param[param];
+
+			/* In-game variable. */
+			grfmsg(1, "Unsupported in-game variable 0x%02X", param);
+			return -1;
+	}
+}
+
+/* Action 0x06 */
+static void CfgApply(byte *buf, int len)
+{
+	/* <06> <param-num> <param-size> <offset> ... <FF>
+	 *
+	 * B param-num     Number of parameter to substitute (First = "zero")
+	 *                 Ignored if that parameter was not specified in newgrf.cfg
+	 * B param-size    How many bytes to replace.  If larger than 4, the
+	 *                 bytes of the following parameter are used.  In that
+	 *                 case, nothing is applied unless *all* parameters
+	 *                 were specified.
+	 * B offset        Offset into data from beginning of next sprite
+	 *                 to place where parameter is to be stored. */
+
+	/* Preload the next sprite */
+	uint32 pos = FioGetPos();
+	uint16 num = FioReadWord();
+	uint8 type = FioReadByte();
+
+	/* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
+	if (type == 0xFF) {
+		_preload_sprite = malloc(num);
+		FioReadBlock(_preload_sprite, num);
+	}
+
+	/* Reset the file position to the start of the next sprite */
+	FioSeekTo(pos, SEEK_SET);
+
+	if (type != 0xFF) {
+		grfmsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
+		return;
+	}
+
+	/* Now perform the Action 0x06 on our data. */
+	buf++;
+
+	for (;;) {
+		uint i;
+		uint param_num;
+		uint param_size;
+		uint offset;
+		bool add_value;
+
+		/* Read the parameter to apply. 0xFF indicates no more data to change. */
+		param_num = grf_load_byte(&buf);
+		if (param_num == 0xFF) break;
+
+		/* Get the size of the parameter to use. If the size covers multiple
+		 * double words, sequential parameter values are used. */
+		param_size = grf_load_byte(&buf);
+
+		/* Bit 7 of param_size indicates we should add to the original value
+		 * instead of replacing it. */
+		add_value  = HASBIT(param_size, 7);
+		param_size = GB(param_size, 0, 7);
+
+		/* Where to apply the data to within the pseudo sprite data. */
+		offset     = grf_load_extended(&buf);
+
+		/* If the parameter is a GRF parameter (not an internal variable) check
+		 * if it (and all further sequential parameters) has been defined. */
+		if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= _cur_grffile->param_end) {
+			grfmsg(2, "CfgApply: Ignoring (param %d not set)", (param_num + (param_size - 1) / 4));
+			break;
+		}
+
+		grfmsg(8, "CfgApply: Applying %u bytes from parameter 0x%02X at offset 0x%04X", param_size, param_num, offset);
+
+		for (i = 0; i < param_size; i++) {
+			uint32 value = GetParamVal(param_num + i / 4, NULL);
+
+			if (add_value) {
+				_preload_sprite[offset + i] += GB(value, (i % 4) * 8, 8);
+			} else {
+				_preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
+			}
+		}
+	}
+}
+
+/* Action 0x07 */
+/* Action 0x09 */
+static void SkipIf(byte *buf, int len)
+{
+	/* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
+	 *
+	 * B param-num
+	 * B param-size
+	 * B condition-type
+	 * V value
+	 * B num-sprites */
+	/* TODO: More params. More condition types. */
+	uint8 param;
+	uint8 paramsize;
+	uint8 condtype;
+	uint8 numsprites;
+	uint32 param_val = 0;
+	uint32 cond_val = 0;
+	uint32 mask = 0;
+	bool result;
+	GRFLabel *label;
+	GRFLabel *choice = NULL;
+
+	check_length(len, 6, "SkipIf");
+	buf++;
+	param     = grf_load_byte(&buf);
+	paramsize = grf_load_byte(&buf);
+	condtype  = grf_load_byte(&buf);
+
+	if (condtype < 2) {
+		/* Always 1 for bit tests, the given value should be ignored. */
+		paramsize = 1;
+	}
+
+	switch (paramsize) {
+		case 4: cond_val = grf_load_dword(&buf); mask = 0xFFFFFFFF; break;
+		case 2: cond_val = grf_load_word(&buf);  mask = 0x0000FFFF; break;
+		case 1: cond_val = grf_load_byte(&buf);  mask = 0x000000FF; break;
+		default: break;
+	}
+
+	if (param < 0x80 && _cur_grffile->param_end <= param) {
+		grfmsg(7, "Param %d undefined, skipping test", param);
+		return;
+	}
+
+	param_val = GetParamVal(param, &cond_val);
+
+	grfmsg(7, "Test condtype %d, param 0x%08X, condval 0x%08X", condtype, param_val, cond_val);
+
+	if (param == 0x88) {
+		/* GRF ID checks */
+
+		const GRFConfig *c = GetGRFConfig(cond_val);
+
+		if (condtype != 10 && c == NULL) {
+			grfmsg(7, "GRFID 0x%08X unknown, skipping test", BSWAP32(cond_val));
+			return;
+		}
+
+		switch (condtype) {
+			/* Tests 6 to 10 are only for param 0x88, GRFID checks */
+			case 6: /* Is GRFID active? */
+				result = HASBIT(c->flags, GCF_ACTIVATED);
+				break;
+
+			case 7: /* Is GRFID non-active? */
+				result = !HASBIT(c->flags, GCF_ACTIVATED);
+				break;
+
+			case 8: /* GRFID is not but will be active? */
+				result = !HASBIT(c->flags, GCF_ACTIVATED) && !HASBIT(c->flags, GCF_DISABLED);
+				break;
+
+			case 9: /* GRFID is or will be active? */
+				result = !HASBIT(c->flags, GCF_NOT_FOUND) && !HASBIT(c->flags, GCF_DISABLED);
+				break;
+
+			case 10: /* GRFID is not nor will be active */
+				/* This is the only condtype that doesn't get ignored if the GRFID is not found */
+				result = c == NULL || HASBIT(c->flags, GCF_DISABLED) || HASBIT(c->flags, GCF_NOT_FOUND);
+				break;
+
+			default: grfmsg(1, "Unsupported GRF test %d. Ignoring", condtype); return;
+		}
+	} else {
+		/* Parameter or variable tests */
+		switch (condtype) {
+			case 0: result = !!(param_val & (1 << cond_val));
+				break;
+			case 1: result = !(param_val & (1 << cond_val));
+				break;
+			case 2: result = (param_val & mask) == cond_val;
+				break;
+			case 3: result = (param_val & mask) != cond_val;
+				break;
+			case 4: result = (param_val & mask) < cond_val;
+				break;
+			case 5: result = (param_val & mask) > cond_val;
+				break;
+
+			default: grfmsg(1, "Unsupported test %d. Ignoring", condtype); return;
+		}
+	}
+
+	if (!result) {
+		grfmsg(2, "Not skipping sprites, test was false");
+		return;
+	}
+
+	numsprites = grf_load_byte(&buf);
+
+	/* numsprites can be a GOTO label if it has been defined in the GRF
+	 * file. The jump will always be the first matching label that follows
+	 * the current nfo_line. If no matching label is found, the first matching
+	 * label in the file is used. */
+	for (label = _cur_grffile->label; label != NULL; label = label->next) {
+		if (label->label != numsprites) continue;
+
+		/* Remember a goto before the current line */
+		if (choice == NULL) choice = label;
+		/* If we find a label here, this is definitely good */
+		if (label->nfo_line > _nfo_line) {
+			choice = label;
+			break;
+		}
+	}
+
+	if (choice != NULL) {
+		grfmsg(2, "Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line);
+		FioSeekTo(choice->pos, SEEK_SET);
+		_nfo_line = choice->nfo_line;
+		return;
+	}
+
+	grfmsg(2, "Skipping %d sprites, test was true", numsprites);
+	_skip_sprites = numsprites;
+	if (_skip_sprites == 0) {
+		/* Zero means there are no sprites to skip, so
+		 * we use -1 to indicate that all further
+		 * sprites should be skipped. */
+		_skip_sprites = -1;
+	}
+}
+
+
+/* Action 0x08 (GLS_FILESCAN) */
+static void ScanInfo(byte *buf, int len)
+{
+	uint8 version;
+	uint32 grfid;
+	const char *name;
+	const char *info;
+	int name_len;
+	int info_len;
+
+	check_length(len, 8, "Info"); buf++;
+	version = grf_load_byte(&buf);
+	grfid = grf_load_dword(&buf);
+
+	_cur_grfconfig->grfid = grfid;
+
+	/* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */
+	if (GB(grfid, 24, 8) == 0xFF) SETBIT(_cur_grfconfig->flags, GCF_SYSTEM);
+
+	len -= 6;
+	name = (const char*)buf;
+	name_len = ttd_strnlen(name, len);
+
+	if (name_len < len) {
+		_cur_grfconfig->name = TranslateTTDPatchCodes(name);
+
+		len -= name_len + 1;
+		info = name + name_len + 1;
+		info_len = ttd_strnlen(info, len);
+
+		if (info_len < len) _cur_grfconfig->info  = TranslateTTDPatchCodes(info);
+	}
+
+	/* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */
+	_skip_sprites = -1;
+}
+
+/* Action 0x08 */
+static void GRFInfo(byte *buf, int len)
+{
+	/* <08> <version> <grf-id> <name> <info>
+	 *
+	 * B version       newgrf version, currently 06
+	 * 4*B grf-id      globally unique ID of this .grf file
+	 * S name          name of this .grf set
+	 * S info          string describing the set, and e.g. author and copyright */
+	/* TODO: Check version. (We should have own versioning done somehow.) */
+	uint8 version;
+	uint32 grfid;
+	const char *name;
+
+	check_length(len, 8, "GRFInfo"); buf++;
+	version = grf_load_byte(&buf);
+	grfid = grf_load_dword(&buf);
+	name = (const char*)buf;
+
+	_cur_grffile->grfid = grfid;
+	_cur_grffile->grf_version = version;
+	SETBIT(_cur_grfconfig->flags, GCF_ACTIVATED);
+
+	/* Do swap the GRFID for displaying purposes since people expect that */
+	DEBUG(grf, 1, "Loaded GRFv%d set %08lX - %s", version, BSWAP32(grfid), name);
+}
+
+/* Action 0x0A */
+static void SpriteReplace(byte *buf, int len)
+{
+	/* <0A> <num-sets> <set1> [<set2> ...]
+	 * <set>: <num-sprites> <first-sprite>
+	 *
+	 * B num-sets      How many sets of sprites to replace.
+	 * Each set:
+	 * B num-sprites   How many sprites are in this set
+	 * W first-sprite  First sprite number to replace */
+	uint8 num_sets;
+	uint i;
+
+	buf++; /* skip action byte */
+	num_sets = grf_load_byte(&buf);
+
+	for (i = 0; i < num_sets; i++) {
+		uint8 num_sprites = grf_load_byte(&buf);
+		uint16 first_sprite = grf_load_word(&buf);
+		uint j;
+
+		grfmsg(2, "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d",
+			i, num_sprites, first_sprite
+		);
+
+		for (j = 0; j < num_sprites; j++) {
+			LoadNextSprite(first_sprite + j, _file_index); // XXX
+			_nfo_line++;
+		}
+	}
+}
+
+/* Action 0x0B */
+static void GRFError(byte *buf, int len)
+{
+	/* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
+	 *
+	 * B severity      00: notice, contine loading grf file
+	 *                 01: warning, continue loading grf file
+	 *                 02: error, but continue loading grf file, and attempt
+	 *                     loading grf again when loading or starting next game
+	 *                 03: error, abort loading and prevent loading again in
+	 *                     the future (only when restarting the patch)
+	 * B language-id   see action 4, use 1F for built-in error messages
+	 * B message-id    message to show, see below
+	 * S message       for custom messages (message-id FF), text of the message
+	 *                 not present for built-in messages.
+	 * V data          additional data for built-in (or custom) messages
+	 * B parnum        see action 6, only used with built-in message 03 */
+	/* TODO: For now we just show the message, sometimes incomplete and never translated. */
+
+	static const char *const msgstr[] = {
+		"%sRequires at least pseudo-TTDPatch version %s",
+		"%sThis file is for %s version of TTD",
+		"%sDesigned to be used with %s",
+		"%sInvalid parameter %s",
+		"%sMust be loaded before %s",
+		"%sMust be loaded after %s",
+		"%s%s"
+	};
+
+	static const char *const sevstr[] = {
+		"",
+		"Warning: ",
+		"Error: ",
+		"Fatal: ",
+	};
+	uint8 sevid;
+	uint8 msgid;
+
+	check_length(len, 6, "GRFError");
+	sevid = buf[1];
+	msgid = buf[3];
+
+	// Undocumented TTDPatch feature.
+	if (!HASBIT(sevid, 7) && _cur_stage < GLS_ACTIVATION) {
+		grfmsg(7, "Skipping non-fatal GRFError in stage 1");
+		return;
+	}
+
+	sevid = GB(sevid, 0, 2);
+	grfmsg(0,  msgstr[(msgid == 0xFF) ? lengthof(msgstr) - 1 : msgid], sevstr[sevid], &buf[4]);
+}
+
+/* Action 0x0C */
+static void GRFComment(byte *buf, int len)
+{
+	/* <0C> [<ignored...>]
+	 *
+	 * V ignored       Anything following the 0C is ignored */
+
+	static char comment[256];
+	if (len == 1) return;
+
+	ttd_strlcpy(comment, (char*)(buf + 1), minu(sizeof(comment), len));
+	grfmsg(2, "GRFComment: %s", comment);
+}
+
+/* Action 0x0D (GLS_SAFETYSCAN) */
+static void SafeParamSet(byte *buf, int len)
+{
+	uint8 target;
+
+	check_length(len, 5, "SafeParamSet");
+	buf++;
+	target = grf_load_byte(&buf);
+
+	/* Only writing GRF parameters is considered safe */
+	if (target < 0x80) return;
+
+	/* GRM could be unsafe, but as here it can only happen after other GRFs
+	 * are loaded, it should be okay. If the GRF tried to use the slots it
+	 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
+	 * sprites  is considered safe. */
+
+	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
+
+	/* Skip remainder of GRF */
+	_skip_sprites = -1;
+}
+
+/* Action 0x0D */
+static void ParamSet(byte *buf, int len)
+{
+	/* <0D> <target> <operation> <source1> <source2> [<data>]
+	 *
+	 * B target        parameter number where result is stored
+	 * B operation     operation to perform, see below
+	 * B source1       first source operand
+	 * B source2       second source operand
+	 * D data          data to use in the calculation, not necessary
+	 *                 if both source1 and source2 refer to actual parameters
+	 *
+	 * Operations
+	 * 00      Set parameter equal to source1
+	 * 01      Addition, source1 + source2
+	 * 02      Subtraction, source1 - source2
+	 * 03      Unsigned multiplication, source1 * source2 (both unsigned)
+	 * 04      Signed multiplication, source1 * source2 (both signed)
+	 * 05      Unsigned bit shift, source1 by source2 (source2 taken to be a
+	 *         signed quantity; left shift if positive and right shift if
+	 *         negative, source1 is unsigned)
+	 * 06      Signed bit shift, source1 by source2
+	 *         (source2 like in 05, and source1 as well)
+	 */
+
+	byte target;
+	byte oper;
+	uint32 src1;
+	uint32 src2;
+	uint32 data = 0;
+	uint32 res;
+
+	check_length(len, 5, "ParamSet");
+	buf++;
+	target = grf_load_byte(&buf);
+	oper = grf_load_byte(&buf);
+	src1 = grf_load_byte(&buf);
+	src2 = grf_load_byte(&buf);
+
+	if (len >= 8) data = grf_load_dword(&buf);
+
+	/* You can add 80 to the operation to make it apply only if the target
+	 * is not defined yet.  In this respect, a parameter is taken to be
+	 * defined if any of the following applies:
+	 * - it has been set to any value in the newgrf(w).cfg parameter list
+	 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
+	 *   an earlier action D */
+	if (oper & 0x80) {
+		if (target < 0x80 && target < _cur_grffile->param_end) {
+			grfmsg(7, "Param %u already defined, skipping", target);
+			return;
+		}
+
+		oper &= 0x7F;
+	}
+
+	if (src2 == 0xFE) {
+		if (GB(data, 0, 8) == 0xFF) {
+			if (data == 0x0000FFFF) {
+				/* Patch variables */
+				grfmsg(2, "ParamSet: Reading Patch variables unsupported");
+				return;
+			} else {
+				/* GRF Resource Management */
+				if (_cur_stage != GLS_ACTIVATION) {
+					/* Ignore GRM during initialization */
+					src1 = 0;
+				} else {
+					uint8  op      = src1;
+					uint8  feature = GB(data, 8, 8);
+					uint16 count   = GB(data, 16, 16);
+
+					switch (feature) {
+						case 0x00: /* Trains */
+						case 0x01: /* Road Vehicles */
+						case 0x02: /* Ships */
+						case 0x03: /* Aircraft */
+						{
+							uint start = 0;
+							uint size  = 0;
+							uint shift = _vehshifts[feature];
+							int i;
+
+							if (op == 6) {
+								/* Return GRFID of set that reserved ID */
+								src1 = _grm_engines[shift + _cur_grffile->param[target]];
+								break;
+							}
+
+							/* With an operation of 2 or 3, we want to reserve a specific block of IDs */
+							if (op == 2 || op == 3) start = _cur_grffile->param[target];
+
+							for (i = start; i < _vehcounts[feature]; i++) {
+								if (_grm_engines[shift + i] == 0) {
+									size++;
+								} else {
+									if (op == 2 || op == 3) break;
+									start = i + 1;
+									size = 0;
+								}
+
+								if (size == count) break;
+							}
+
+							if (size == count) {
+								/* Got the slot... */
+								if (op == 0 || op == 3) {
+									grfmsg(2, "GRM: Reserving %d vehicles at %d", count, start);
+									for (i = 0; i < count; i++) _grm_engines[shift + start + i] = _cur_grffile->grfid;
+								}
+								src1 = start;
+							} else {
+								/* Unable to allocate */
+								if (op != 4 && op != 5) {
+									/* Deactivate GRF */
+									grfmsg(0, "GRM: Unable to allocate %d vehicles, deactivating", count);
+									SETBIT(_cur_grfconfig->flags, GCF_DISABLED);
+									CLRBIT(_cur_grfconfig->flags, GCF_ACTIVATED);
+
+									_skip_sprites = -1;
+									return;
+								}
+
+								grfmsg(1, "GRM: Unable to allocate %d vehicles", count);
+								src1 = -1;
+							}
+							break;
+						}
+
+						case 0x08: /* General sprites */
+							switch (op) {
+								case 0:
+									/* 'Reserve' space at the current sprite ID */
+									src1 = _cur_spriteid;
+									_cur_spriteid += count;
+									break;
+
+								case 1:
+									src1 = _cur_spriteid;
+									break;
+
+								default:
+									grfmsg(1, "GRM: Unsupported operation %d for general sprites", op);
+									return;
+							}
+							break;
+
+						default: grfmsg(1, "GRM: Unsupported feature 0x%X", feature); return;
+					}
+				}
+			}
+		} else {
+			/* Read another GRF File's parameter */
+			const GRFFile *file = GetFileByGRFID(data);
+			if (file == NULL || src1 >= file->param_end) {
+				src1 = 0;
+			} else {
+				src1 = file->param[src1];
+			}
+		}
+	} else {
+		/* The source1 and source2 operands refer to the grf parameter number
+		 * like in action 6 and 7.  In addition, they can refer to the special
+		 * variables available in action 7, or they can be FF to use the value
+		 * of <data>.  If referring to parameters that are undefined, a value
+		 * of 0 is used instead.  */
+		src1 = (src1 == 0xFF) ? data : GetParamVal(src1, NULL);
+		src2 = (src2 == 0xFF) ? data : GetParamVal(src2, NULL);
+	}
+
+	/* TODO: You can access the parameters of another GRF file by using
+	 * source2=FE, source1=the other GRF's parameter number and data=GRF
+	 * ID.  This is only valid with operation 00 (set).  If the GRF ID
+	 * cannot be found, a value of 0 is used for the parameter value
+	 * instead. */
+
+	switch (oper) {
+		case 0x00:
+			res = src1;
+			break;
+
+		case 0x01:
+			res = src1 + src2;
+			break;
+
+		case 0x02:
+			res = src1 - src2;
+			break;
+
+		case 0x03:
+			res = src1 * src2;
+			break;
+
+		case 0x04:
+			res = (int32)src1 * (int32)src2;
+			break;
+
+		case 0x05:
+			if ((int32)src2 < 0) {
+				res = src1 >> -(int32)src2;
+			} else {
+				res = src1 << src2;
+			}
+			break;
+
+		case 0x06:
+			if ((int32)src2 < 0) {
+				res = (int32)src1 >> -(int32)src2;
+			} else {
+				res = (int32)src1 << src2;
+			}
+			break;
+
+		case 0x07: /* Bitwise AND */
+			res = src1 & src2;
+			break;
+
+		case 0x08: /* Bitwise OR */
+			res = src1 | src2;
+			break;
+
+		case 0x09: /* Unsigned division */
+			if (src2 == 0) {
+				res = src1;
+			} else {
+				res = src1 / src2;
+			}
+			break;
+
+		case 0x0A: /* Signed divison */
+			if (src2 == 0) {
+				res = src1;
+			} else {
+				res = (int32)src1 / (int32)src2;
+			}
+			break;
+
+		case 0x0B: /* Unsigned modulo */
+			if (src2 == 0) {
+				res = src1;
+			} else {
+				res = src1 % src2;
+			}
+			break;
+
+		case 0x0C: /* Signed modulo */
+			if (src2 == 0) {
+				res = src1;
+			} else {
+				res = (int32)src1 % (int32)src2;
+			}
+			break;
+
+		default: grfmsg(0, "ParamSet: Unknown operation %d, skipping", oper); return;
+	}
+
+	switch (target) {
+		case 0x8E: // Y-Offset for train sprites
+			_traininfo_vehicle_pitch = res;
+			break;
+
+		// TODO implement
+		case 0x8F: // Rail track type cost factors
+		case 0x93: // Tile refresh offset to left
+		case 0x94: // Tile refresh offset to right
+		case 0x95: // Tile refresh offset upwards
+		case 0x96: // Tile refresh offset downwards
+		case 0x97: // Snow line height
+		case 0x99: // Global ID offset
+			grfmsg(7, "ParamSet: Skipping unimplemented target 0x%02X", target);
+			break;
+
+		case 0x9E: /* Miscellaneous GRF features */
+			_misc_grf_features = res;
+			/* Set train list engine width */
+			_traininfo_vehicle_width = HASBIT(res, 3) ? 32 : 29;
+			break;
+
+		default:
+			if (target < 0x80) {
+				_cur_grffile->param[target] = res;
+				if (target + 1U > _cur_grffile->param_end) _cur_grffile->param_end = target + 1;
+			} else {
+				grfmsg(7, "ParamSet: Skipping unknown target 0x%02X", target);
+			}
+			break;
+	}
+}
+
+/* Action 0x0E (GLS_SAFETYSCAN) */
+static void SafeGRFInhibit(byte *buf, int len)
+{
+	/* <0E> <num> <grfids...>
+	 *
+	 * B num           Number of GRFIDs that follow
+	 * D grfids        GRFIDs of the files to deactivate */
+
+	byte num;
+	int i;
+
+	check_length(len, 1, "GRFInhibit");
+	buf++, len--;
+	num = grf_load_byte(&buf); len--;
+	check_length(len, 4 * num, "GRFInhibit");
+
+	for (i = 0; i < num; i++) {
+		uint32 grfid = grf_load_dword(&buf);
+
+		/* GRF is unsafe it if tries to deactivate other GRFs */
+		if (grfid != _cur_grfconfig->grfid) {
+			SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
+
+			/* Skip remainder of GRF */
+			_skip_sprites = -1;
+
+			return;
+		}
+	}
+}
+
+/* Action 0x0E */
+static void GRFInhibit(byte *buf, int len)
+{
+	/* <0E> <num> <grfids...>
+	 *
+	 * B num           Number of GRFIDs that follow
+	 * D grfids        GRFIDs of the files to deactivate */
+
+	byte num;
+	int i;
+
+	check_length(len, 1, "GRFInhibit");
+	buf++, len--;
+	num = grf_load_byte(&buf); len--;
+	check_length(len, 4 * num, "GRFInhibit");
+
+	for (i = 0; i < num; i++) {
+		uint32 grfid = grf_load_dword(&buf);
+		GRFConfig *file = GetGRFConfig(grfid);
+
+		/* Unset activation flag */
+		if (file != NULL && file != _cur_grfconfig) {
+			grfmsg(2, "GRFInhibit: Deactivating file '%s'", file->filename);
+			SETBIT(file->flags, GCF_DISABLED);
+			CLRBIT(file->flags, GCF_ACTIVATED);
+		}
+	}
+}
+
+/* Action 0x10 */
+static void DefineGotoLabel(byte *buf, int len)
+{
+	/* <10> <label> [<comment>]
+	 *
+	 * B label      The label to define
+	 * V comment    Optional comment - ignored */
+
+	GRFLabel *label;
+
+	check_length(len, 1, "DefineGotoLabel");
+	buf++; len--;
+
+	label = malloc(sizeof(*label));
+	label->label    = grf_load_byte(&buf);
+	label->nfo_line = _nfo_line;
+	label->pos      = FioGetPos();
+	label->next     = NULL;
+
+	/* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */
+	if (_cur_grffile->label == NULL) {
+		_cur_grffile->label = label;
+	} else {
+		/* Attach the label to the end of the list */
+		GRFLabel *l;
+		for (l = _cur_grffile->label; l->next != NULL; l = l->next);
+		l->next = label;
+	}
+
+	grfmsg(2, "DefineGotoLabel: GOTO target with label 0x%02X", label->label);
+}
+
+/* Action 0x11 */
+static void GRFSound(byte *buf, int len)
+{
+	/* <11> <num>
+	 *
+	 * W num      Number of sound files that follow */
+
+	uint16 num;
+
+	check_length(len, 1, "GRFSound");
+	buf++;
+	num = grf_load_word(&buf);
+
+	_grf_data_blocks = num;
+	_grf_data_type   = GDT_SOUND;
+
+	if (_cur_grffile->sound_offset == 0) _cur_grffile->sound_offset = GetNumSounds();
+}
+
+static void ImportGRFSound(byte *buf, int len)
+{
+	const GRFFile *file;
+	FileEntry *se = AllocateFileEntry();
+	uint32 grfid = grf_load_dword(&buf);
+	uint16 sound = grf_load_word(&buf);
+
+	file = GetFileByGRFID(grfid);
+	if (file == NULL || file->sound_offset == 0) {
+		grfmsg(1, "ImportGRFSound: Source file not available");
+		return;
+	}
+
+	if (file->sound_offset + sound >= GetNumSounds()) {
+		grfmsg(1, "ImportGRFSound: Sound effect %d is invalid", sound);
+		return;
+	}
+
+	grfmsg(2, "ImportGRFSound: Copying sound %d (%d) from file %X", sound, file->sound_offset + sound, grfid);
+
+	*se = *GetSound(file->sound_offset + sound);
+
+	/* Reset volume and priority, which TTDPatch doesn't copy */
+	se->volume   = 128;
+	se->priority = 0;
+}
+
+/* 'Action 0xFE' */
+static void GRFImportBlock(byte *buf, int len)
+{
+	if (_grf_data_blocks == 0) {
+		grfmsg(2, "GRFImportBlock: Unexpected import block, skipping");
+		return;
+	}
+
+	buf++;
+
+	_grf_data_blocks--;
+
+	/* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
+	 * importing sounds, so this is probably all wrong... */
+	if (grf_load_byte(&buf) != _grf_data_type) {
+		grfmsg(1, "GRFImportBlock: Import type mismatch");
+	}
+
+	switch (_grf_data_type) {
+		case GDT_SOUND: ImportGRFSound(buf, len - 1); break;
+		default: NOT_REACHED(); break;
+	}
+}
+
+static void LoadGRFSound(byte *buf, int len)
+{
+	byte *buf_start = buf;
+	FileEntry *se;
+
+	/* Allocate a sound entry. This is done even if the data is not loaded
+	 * so that the indices used elsewhere are still correct. */
+	se = AllocateFileEntry();
+
+	if (grf_load_dword(&buf) != BSWAP32('RIFF')) {
+		grfmsg(1, "LoadGRFSound: Missing RIFF header");
+		return;
+	}
+
+	/* Size of file -- we ignore this */
+	grf_load_dword(&buf);
+
+	if (grf_load_dword(&buf) != BSWAP32('WAVE')) {
+		grfmsg(1, "LoadGRFSound: Invalid RIFF type");
+		return;
+	}
+
+	for (;;) {
+		uint32 tag  = grf_load_dword(&buf);
+		uint32 size = grf_load_dword(&buf);
+
+		switch (tag) {
+			case ' tmf': /* 'fmt ' */
+				/* Audio format, must be 1 (PCM) */
+				if (grf_load_word(&buf) != 1) {
+					grfmsg(1, "LoadGRFSound: Invalid audio format");
+					return;
+				}
+				se->channels = grf_load_word(&buf);
+				se->rate = grf_load_dword(&buf);
+				grf_load_dword(&buf);
+				grf_load_word(&buf);
+				se->bits_per_sample = grf_load_word(&buf);
+
+				/* Consume any extra bytes */
+				for (; size > 16; size--) grf_load_byte(&buf);
+				break;
+
+			case 'atad': /* 'data' */
+				se->file_size    = size;
+				se->file_offset  = FioGetPos() - (len - (buf - buf_start)) + 1;
+				se->file_offset |= _file_index << 24;
+
+				/* Set default volume and priority */
+				se->volume = 0x80;
+				se->priority = 0;
+
+				grfmsg(2, "LoadGRFSound: channels %u, sample rate %u, bits per sample %u, length %u", se->channels, se->rate, se->bits_per_sample, size);
+				return;
+
+			default:
+				se->file_size = 0;
+				return;
+		}
+	}
+}
+
+/* Action 0x12 */
+static void LoadFontGlyph(byte *buf, int len)
+{
+	/* <12> <num_def> <font_size> <num_char> <base_char>
+	 *
+	 * B num_def      Number of definitions
+	 * B font_size    Size of font (0 = normal, 1 = small, 2 = large)
+	 * B num_char     Number of consecutive glyphs
+	 * W base_char    First character index */
+
+	uint8 num_def;
+	uint i;
+
+	buf++; len--;
+	check_length(len, 1, "LoadFontGlyph");
+
+	num_def = grf_load_byte(&buf);
+
+	check_length(len, 1 + num_def * 4, "LoadFontGlyph");
+
+	for (i = 0; i < num_def; i++) {
+		FontSize size    = grf_load_byte(&buf);
+		uint8  num_char  = grf_load_byte(&buf);
+		uint16 base_char = grf_load_word(&buf);
+		uint c;
+
+		grfmsg(7, "LoadFontGlyph: Loading %u glyph(s) at 0x%04X for size %u", num_char, base_char, size);
+
+		for (c = 0; c < num_char; c++) {
+			SetUnicodeGlyph(size, base_char + c, _cur_spriteid);
+			LoadNextSprite(_cur_spriteid++, _file_index);
+			_nfo_line++;
+		}
+	}
+}
+
+/* 'Action 0xFF' */
+static void GRFDataBlock(byte *buf, int len)
+{
+	byte name_len;
+	const char *name;
+
+	if (_grf_data_blocks == 0) {
+		grfmsg(2, "GRFDataBlock: unexpected data block, skipping");
+		return;
+	}
+
+	buf++;
+	name_len = grf_load_byte(&buf);
+	name = (const char *)buf;
+	buf += name_len + 1;
+
+	grfmsg(2, "GRFDataBlock: block name '%s'...", name);
+
+	_grf_data_blocks--;
+
+	switch (_grf_data_type) {
+		case GDT_SOUND: LoadGRFSound(buf, len - name_len - 2); break;
+		default: NOT_REACHED(); break;
+	}
+}
+
+
+/* Used during safety scan on unsafe actions */
+static void GRFUnsafe(byte *buf, int len)
+{
+	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
+
+	/* Skip remainder of GRF */
+	_skip_sprites = -1;
+}
+
+
+static void InitializeGRFSpecial(void)
+{
+	_ttdpatch_flags[0] =  ((_patches.always_small_airport ? 1 : 0) << 0x0C)  // keepsmallairport
+	                   |                                        (1 << 0x0D)  // newairports
+	                   |                                        (1 << 0x0E)  // largestations
+	                   |           ((_patches.longbridges ? 1 : 0) << 0x0F)  // longbridges
+	                   |                                        (0 << 0x10)  // loadtime
+	                   |                                        (1 << 0x12)  // presignals
+	                   |                                        (1 << 0x13)  // extpresignals
+	                   | ((_patches.never_expire_vehicles ? 1 : 0) << 0x16)  // enginespersist
+	                   |                                        (1 << 0x1B)  // multihead
+	                   |                                        (1 << 0x1D)  // lowmemory
+	                   |                                        (1 << 0x1E); // generalfixes
+
+	_ttdpatch_flags[1] =                                        (0 << 0x07)  // moreairports - based on units of noise
+	                   |        ((_patches.mammoth_trains ? 1 : 0) << 0x08)  // mammothtrains
+	                   |                                        (1 << 0x09)  // trainrefit
+	                   |                                        (0 << 0x0B)  // subsidiaries
+	                   |       ((_patches.gradual_loading ? 1 : 0) << 0x0C)  // gradualloading
+	                   |                                        (1 << 0x12)  // unifiedmaglevmode - set bit 0 mode. Not revelant to OTTD
+	                   |                                        (1 << 0x13)  // unifiedmaglevmode - set bit 1 mode
+	                   |                                        (1 << 0x14)  // bridgespeedlimits
+	                   |                                        (1 << 0x16)  // eternalgame
+	                   |                                        (1 << 0x17)  // newtrains
+	                   |                                        (1 << 0x18)  // newrvs
+	                   |                                        (1 << 0x19)  // newships
+	                   |                                        (1 << 0x1A)  // newplanes
+	                   |           ((_patches.signal_side ? 1 : 0) << 0x1B)  // signalsontrafficside
+	                   |                                        (1 << 0x1C); // electrifiedrailway
+
+	_ttdpatch_flags[2] =                                        (1 << 0x01)  // loadallgraphics - obsolote
+	                   |                                        (1 << 0x03)  // semaphores
+	                   |                                        (0 << 0x0B)  // enhancedgui
+	                   |                                        (0 << 0x0C)  // newagerating
+	                   |       ((_patches.build_on_slopes ? 1 : 0) << 0x0D)  // buildonslopes
+	                   |                                        (0 << 0x0F)  // planespeed
+	                   |                                        (0 << 0x10)  // moreindustriesperclimate - obsolete
+	                   |                                        (0 << 0x11)  // moretoylandfeatures
+	                   |                                        (1 << 0x12)  // newstations
+	                   |                                        (0 << 0x13)  // tracktypecostdiff
+	                   |                                        (0 << 0x14)  // manualconvert
+	                   |       ((_patches.build_on_slopes ? 1 : 0) << 0x15)  // buildoncoasts
+	                   |                                        (1 << 0x16)  // canals
+	                   |                                        (1 << 0x17)  // newstartyear
+	                   |                                        (0 << 0x18)  // freighttrains
+	                   |                                        (0 << 0x19)  // newhouses
+	                   |                                        (1 << 0x1A)  // newbridges
+	                   |                                        (0 << 0x1B)  // newtownnames
+	                   |                                        (0 << 0x1C)  // moreanimations
+	                   |    ((_patches.wagon_speed_limits ? 1 : 0) << 0x1D)  // wagonspeedlimits
+	                   |                                        (1 << 0x1E)  // newshistory
+	                   |                                        (0 << 0x1F); // custombridgeheads
+
+	_ttdpatch_flags[3] =                                        (0 << 0x00)  // newcargodistribution
+	                   |                                        (1 << 0x01)  // windowsnap
+	                   |                                        (0 << 0x02)  // townbuildnoroad
+	                   |                                        (0 << 0x03)  // pathbasedsignalling. To enable if ever pbs is back
+	                   |                                        (0 << 0x04)  // aichoosechance
+	                   |                                        (1 << 0x05)  // resolutionwidth
+	                   |                                        (1 << 0x06)  // resolutionheight
+	                   |                                        (0 << 0x07)  // newindustries
+	                   |                                        (0 << 0x08)  // fifoloading
+	                   |                                        (0 << 0x09)  // townroadbranchprob
+	                   |                                        (0 << 0x0A)  // tempsnowline
+	                   |                                        (0 << 0x0B)  // newcargo
+	                   |                                        (1 << 0x0C)  // enhancemultiplayer
+	                   |                                        (1 << 0x0D)  // onewayroads
+	                   |   ((_patches.nonuniform_stations ? 1 : 0) << 0x0E)  // irregularstations
+	                   |                                        (1 << 0x0F)  // statistics
+	                   |                                        (1 << 0x10)  // newsounds
+	                   |                                        (1 << 0x11)  // autoreplace
+	                   |                                        (1 << 0x12)  // autoslope
+	                   |                                        (0 << 0x13)  // followvehicle
+	                   |                                        (0 << 0x14)  // trams
+	                   |                                        (0 << 0x15)  // enhancetunnels
+	                   |                                        (0 << 0x16)  // shortrvs
+	                   |                                        (0 << 0x17); // articulatedrvs
+}
+
+static void ResetCustomStations(void)
+{
+	StationSpec *statspec;
+	GRFFile *file;
+	uint i;
+	uint t;
+
+	for (file = _first_grffile; file != NULL; file = file->next) {
+		if (file->stations == NULL) continue;
+		for (i = 0; i < MAX_STATIONS; i++) {
+			if (file->stations[i] == NULL) continue;
+			statspec = file->stations[i];
+
+			/* Release renderdata, if it wasn't copied from another custom station spec  */
+			if (!statspec->copied_renderdata) {
+				for (t = 0; t < statspec->tiles; t++) {
+					free((void*)statspec->renderdata[t].seq);
+				}
+				free(statspec->renderdata);
+			}
+
+			/* Release platforms and layouts */
+			if (!statspec->copied_layouts) {
+				uint l, p;
+				for (l = 0; l < statspec->lengths; l++) {
+					for (p = 0; p < statspec->platforms[l]; p++) {
+						free(statspec->layouts[l][p]);
+					}
+					free(statspec->layouts[l]);
+				}
+				free(statspec->layouts);
+				free(statspec->platforms);
+			}
+
+			/* Release this station */
+			free(statspec);
+		}
+
+		/* Free and reset the station data */
+		free(file->stations);
+		file->stations = NULL;
+	}
+}
+
+static void ResetNewGRF(void)
+{
+	GRFFile *f, *next;
+
+	for (f = _first_grffile; f != NULL; f = next) {
+		next = f->next;
+
+		free(f->filename);
+		free(f);
+	}
+
+	_first_grffile = NULL;
+	_cur_grffile   = NULL;
+}
+
+/**
+ * Reset all NewGRF loaded data
+ * TODO
+ */
+static void ResetNewGRFData(void)
+{
+	uint i;
+
+	CleanUpStrings();
+
+	// Copy/reset original engine info data
+	memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info));
+	memcpy(&_rail_vehicle_info, &orig_rail_vehicle_info, sizeof(orig_rail_vehicle_info));
+	memcpy(&_ship_vehicle_info, &orig_ship_vehicle_info, sizeof(orig_ship_vehicle_info));
+	memcpy(&_aircraft_vehicle_info, &orig_aircraft_vehicle_info, sizeof(orig_aircraft_vehicle_info));
+	memcpy(&_road_vehicle_info, &orig_road_vehicle_info, sizeof(orig_road_vehicle_info));
+
+	// Copy/reset original bridge info data
+	// First, free sprite table data
+	for (i = 0; i < MAX_BRIDGES; i++) {
+		if (_bridge[i].sprite_table != NULL) {
+			uint j;
+
+			for (j = 0; j < 7; j++) free(_bridge[i].sprite_table[j]);
+			free(_bridge[i].sprite_table);
+		}
+	}
+	memcpy(&_bridge, &orig_bridge, sizeof(_bridge));
+
+	// Reset refit/cargo class data
+	memset(&cargo_allowed, 0, sizeof(cargo_allowed));
+	memset(&cargo_disallowed, 0, sizeof(cargo_disallowed));
+
+	// Reset GRM reservations
+	memset(&_grm_engines, 0, sizeof(_grm_engines));
+
+	// Unload sprite group data
+	UnloadWagonOverrides();
+	UnloadRotorOverrideSprites();
+	UnloadCustomEngineSprites();
+	UnloadCustomEngineNames();
+	ResetEngineListOrder();
+
+	// Reset price base data
+	ResetPriceBaseMultipliers();
+
+	/* Reset the curencies array */
+	ResetCurrencies();
+
+	// Reset station classes
+	ResetStationClasses();
+	ResetCustomStations();
+
+	/* Reset NewGRF files */
+	ResetNewGRF();
+
+	// Add engine type to engine data. This is needed for the refit precalculation.
+	AddTypeToEngines();
+
+	/* Reset misc GRF features and train list display variables */
+	_misc_grf_features = 0;
+	_traininfo_vehicle_pitch = 0;
+	_traininfo_vehicle_width = 29;
+	_have_2cc = false;
+	_signal_base = 0;
+	_coast_base = 0;
+
+	InitializeSoundPool();
+	InitializeSpriteGroupPool();
+}
+
+/** Reset all NewGRFData that was used only while processing data */
+static void ClearTemporaryNewGRFData(void)
+{
+	/* Clear the GOTO labels used for GRF processing */
+	GRFLabel *l;
+	for (l = _cur_grffile->label; l != NULL;) {
+		GRFLabel *l2 = l->next;
+		free(l);
+		l = l2;
+	}
+	_cur_grffile->label = NULL;
+
+	/* Clear the list of spritegroups */
+	free(_cur_grffile->spritegroups);
+	_cur_grffile->spritegroups = NULL;
+	_cur_grffile->spritegroups_count = 0;
+}
+
+static void InitNewGRFFile(const GRFConfig *config, int sprite_offset)
+{
+	GRFFile *newfile;
+
+	newfile = GetFileByFilename(config->filename);
+	if (newfile != NULL) {
+		/* We already loaded it once. */
+		newfile->sprite_offset = sprite_offset;
+		_cur_grffile = newfile;
+		return;
+	}
+
+	newfile = calloc(1, sizeof(*newfile));
+
+	if (newfile == NULL) error ("Out of memory");
+
+	newfile->filename = strdup(config->filename);
+	newfile->sprite_offset = sprite_offset;
+
+	/* Copy the initial parameter list */
+	assert(lengthof(newfile->param) == lengthof(config->param) && lengthof(config->param) == 0x80);
+	newfile->param_end = config->num_params;
+	memcpy(newfile->param, config->param, sizeof(newfile->param));
+
+	if (_first_grffile == NULL) {
+		_cur_grffile = newfile;
+		_first_grffile = newfile;
+	} else {
+		_cur_grffile->next = newfile;
+		_cur_grffile = newfile;
+	}
+}
+
+
+/** Bitmasked values of what type of cargo is refittable for the given vehicle-type.
+ * This coupled with the landscape information (_landscape_global_cargo_mask) gives
+ * us exactly what is refittable and what is not */
+#define MC(cargo) (1 << cargo)
+static const uint32 _default_refitmasks[NUM_VEHICLE_TYPES] = {
+	/* Trains */
+	MC(GC_PASSENGERS) | MC(GC_COAL)      | MC(GC_MAIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS)        | MC(GC_GRAIN)      | MC(GC_WOOD)    | MC(GC_IRON_ORE)    |
+	MC(GC_STEEL)      | MC(GC_VALUABLES) | MC(GC_PAPER)  | MC(GC_FOOD)      | MC(GC_FRUIT)        | MC(GC_COPPER_ORE) | MC(GC_WATER)   | MC(GC_SUGAR)       |
+	MC(GC_TOYS)       | MC(GC_CANDY)     | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES)    | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
+	/* Road vehicles (not refittable by default) */
+	0,
+	/* Ships */
+	MC(GC_COAL)  | MC(GC_MAIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS)        | MC(GC_GRAIN)   | MC(GC_WOOD)    | MC(GC_IRON_ORE) | MC(GC_STEEL) | MC(GC_VALUABLES) |
+	MC(GC_PAPER) | MC(GC_FOOD)   | MC(GC_FRUIT)     | MC(GC_COPPER_ORE)   | MC(GC_WATER)   | MC(GC_RUBBER)  | MC(GC_SUGAR)    | MC(GC_TOYS)  | MC(GC_BATTERIES) |
+	MC(GC_CANDY) | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES) | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
+	/* Aircraft */
+	MC(GC_PASSENGERS) | MC(GC_MAIL)  | MC(GC_GOODS)  | MC(GC_VALUABLES) | MC(GC_FOOD)         | MC(GC_FRUIT)   | MC(GC_SUGAR)   | MC(GC_TOYS) |
+	MC(GC_BATTERIES)  | MC(GC_CANDY) | MC(GC_TOFFEE) | MC(GC_COLA)      | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES) | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS),
+	/* Special/Disaster */
+	0,0
+};
+#undef MC
+
+
+/**
+ * Precalculate refit masks from cargo classes for all vehicles.
+ */
+static void CalculateRefitMasks(void)
+{
+	EngineID engine;
+
+	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
+		uint32 mask = 0;
+		uint32 not_mask = 0;
+		uint32 xor_mask = _engine_info[engine].refit_mask;
+		byte i;
+
+		if (cargo_allowed[engine] != 0) {
+			// Build up the list of cargo types from the set cargo classes.
+			for (i = 0; i < lengthof(cargo_classes); i++) {
+				if (HASBIT(cargo_allowed[engine], i)) mask |= cargo_classes[i];
+				if (HASBIT(cargo_disallowed[engine], i)) not_mask |= cargo_classes[i];
+			}
+		} else {
+			// Don't apply default refit mask to wagons or engines with no capacity
+			if (xor_mask == 0 && (
+						GetEngine(engine)->type != VEH_Train || (
+							RailVehInfo(engine)->capacity != 0 &&
+							!(RailVehInfo(engine)->flags & RVI_WAGON)
+						)
+					)) {
+				xor_mask = _default_refitmasks[GetEngine(engine)->type - VEH_Train];
+			}
+		}
+		_engine_info[engine].refit_mask = ((mask & ~not_mask) ^ xor_mask) & _landscape_global_cargo_mask[_opt.landscape];
+	}
+}
+
+/* Here we perform initial decoding of some special sprites (as are they
+ * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
+ * partial implementation yet). */
+/* XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
+ * a crafted invalid GRF file. We should tell that to the user somehow, or
+ * better make this more robust in the future. */
+static void DecodeSpecialSprite(uint num, GrfLoadingStage stage)
+{
+	/* XXX: There is a difference between staged loading in TTDPatch and
+	 * here.  In TTDPatch, for some reason actions 1 and 2 are carried out
+	 * during stage 1, whilst action 3 is carried out during stage 2 (to
+	 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
+	 * IDs are valid only within a given set (action 1) block, and may be
+	 * overwritten after action 3 associates them. But overwriting happens
+	 * in an earlier stage than associating, so...  We just process actions
+	 * 1 and 2 in stage 2 now, let's hope that won't get us into problems.
+	 * --pasky */
+	/* We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
+	 * is not in memory and scanning the file every time would be too expensive.
+	 * In other stages we skip action 0x10 since it's already dealt with. */
+	static const SpecialSpriteHandler handlers[][GLS_END] = {
+		/* 0x00 */ { NULL,     SafeChangeInfo, NULL,       NULL,       FeatureChangeInfo, },
+		/* 0x01 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteSet, },
+		/* 0x02 */ { NULL,     GRFUnsafe, NULL,            NULL,       NewSpriteGroup, },
+		/* 0x03 */ { NULL,     GRFUnsafe, NULL,            NULL,       FeatureMapSpriteGroup, },
+		/* 0x04 */ { NULL,     NULL,      NULL,            NULL,       FeatureNewName, },
+		/* 0x05 */ { NULL,     NULL,      NULL,            NULL,       GraphicsNew, },
+		/* 0x06 */ { NULL,     NULL,      NULL,            CfgApply,   CfgApply, },
+		/* 0x07 */ { NULL,     NULL,      NULL,            NULL,       SkipIf, },
+		/* 0x08 */ { ScanInfo, NULL,      NULL,            GRFInfo,    GRFInfo, },
+		/* 0x09 */ { NULL,     NULL,      NULL,            SkipIf,     SkipIf, },
+		/* 0x0A */ { NULL,     NULL,      NULL,            NULL,       SpriteReplace, },
+		/* 0x0B */ { NULL,     NULL,      NULL,            GRFError,   GRFError, },
+		/* 0x0C */ { NULL,     NULL,      NULL,            GRFComment, GRFComment, },
+		/* 0x0D */ { NULL,     SafeParamSet, NULL,         ParamSet,   ParamSet, },
+		/* 0x0E */ { NULL,     SafeGRFInhibit, NULL,       GRFInhibit, GRFInhibit, },
+		/* 0x0F */ { NULL,     NULL,      NULL,            NULL,       NULL, },
+		/* 0x10 */ { NULL,     NULL,      DefineGotoLabel, NULL,       NULL, },
+		/* 0x11 */ { NULL,     GRFUnsafe, NULL,            NULL,       GRFSound, },
+		/* 0x12 */ { NULL,     NULL,      NULL,            NULL,       LoadFontGlyph, },
+	};
+
+	byte* buf;
+	byte action;
+
+	if (_preload_sprite == NULL) {
+		/* No preloaded sprite to work with; allocate and read the
+		 * pseudo sprite content. */
+		buf = malloc(num);
+		if (buf == NULL) error("DecodeSpecialSprite: Could not allocate memory");
+		FioReadBlock(buf, num);
+	} else {
+		/* Use the preloaded sprite data. */
+		buf = _preload_sprite;
+		_preload_sprite = NULL;
+		grfmsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
+
+		/* Skip the real (original) content of this action. */
+		FioSeekTo(num, SEEK_CUR);
+	}
+
+	action = buf[0];
+
+	if (action == 0xFF) {
+		grfmsg(7, "Handling data block in stage %d", stage);
+		GRFDataBlock(buf, num);
+	} else if (action == 0xFE) {
+		grfmsg(7, "Handling import block in stage %d", stage);
+		GRFImportBlock(buf, num);
+	} else if (action >= lengthof(handlers)) {
+		grfmsg(7, "Skipping unknown action 0x%02X", action);
+	} else if (handlers[action][stage] == NULL) {
+		grfmsg(7, "Skipping action 0x%02X in stage %d", action, stage);
+	} else {
+		grfmsg(7, "Handling action 0x%02X in stage %d", action, stage);
+		handlers[action][stage](buf, num);
+	}
+	free(buf);
+}
+
+
+void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage)
+{
+	const char *filename = config->filename;
+	uint16 num;
+
+	/* A .grf file is activated only if it was active when the game was
+	 * started.  If a game is loaded, only its active .grfs will be
+	 * reactivated, unless "loadallgraphics on" is used.  A .grf file is
+	 * considered active if its action 8 has been processed, i.e. its
+	 * action 8 hasn't been skipped using an action 7.
+	 *
+	 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
+	 * carried out.  All others are ignored, because they only need to be
+	 * processed once at initialization.  */
+	if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
+		_cur_grffile = GetFileByFilename(filename);
+		if (_cur_grffile == NULL) error("File '%s' lost in cache.\n", filename);
+		if (stage == GLS_ACTIVATION && !HASBIT(config->flags, GCF_ACTIVATED)) return;
+	}
+
+	FioOpenFile(file_index, filename);
+	_file_index = file_index; // XXX
+
+	_cur_grfconfig = config;
+
+	DEBUG(grf, 2, "Reading NewGRF-file '%s'", filename);
+
+	/* Skip the first sprite; we don't care about how many sprites this
+	 * does contain; newest TTDPatches and George's longvehicles don't
+	 * neither, apparently. */
+	if (FioReadWord() == 4 && FioReadByte() == 0xFF) {
+		FioReadDword();
+	} else {
+		DEBUG(grf, 7, "Custom .grf has invalid format");
+		return;
+	}
+
+	_skip_sprites = 0; // XXX
+	_nfo_line = 0;
+
+	while ((num = FioReadWord()) != 0) {
+		byte type = FioReadByte();
+		_nfo_line++;
+
+		if (type == 0xFF) {
+			if (_skip_sprites == 0) {
+				DecodeSpecialSprite(num, stage);
+
+				/* Stop all processing if we are to skip the remaining sprites */
+				if (_skip_sprites == -1) break;
+
+				continue;
+			} else {
+				FioSkipBytes(num);
+			}
+		} else {
+			if (_skip_sprites == 0) grfmsg(7, "Skipping unexpected sprite");
+
+			FioSkipBytes(7);
+			num -= 8;
+
+			if (type & 2) {
+				FioSkipBytes(num);
+			} else {
+				while (num > 0) {
+					int8 i = FioReadByte();
+					if (i >= 0) {
+						num -= i;
+						FioSkipBytes(i);
+					} else {
+						i = -(i >> 3);
+						num -= i;
+						FioReadByte();
+					}
+				}
+			}
+		}
+
+		if (_skip_sprites > 0) _skip_sprites--;
+	}
+}
+
+
+void LoadNewGRF(uint load_index, uint file_index)
+{
+	GrfLoadingStage stage;
+
+	InitializeGRFSpecial();
+
+	ResetNewGRFData();
+
+	/* Load newgrf sprites
+	 * in each loading stage, (try to) open each file specified in the config
+	 * and load information from it. */
+	for (stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) {
+		uint slot = file_index;
+		GRFConfig *c;
+
+		_cur_stage = stage;
+		_cur_spriteid = load_index;
+		for (c = _grfconfig; c != NULL; c = c->next) {
+			if (HASBIT(c->flags, GCF_DISABLED) || HASBIT(c->flags, GCF_NOT_FOUND)) continue;
+
+			// TODO usererror()
+			if (!FioCheckFileExists(c->filename)) error("NewGRF file is missing '%s'", c->filename);
+
+			if (stage == GLS_LABELSCAN) InitNewGRFFile(c, _cur_spriteid);
+			LoadNewGRFFile(c, slot++, stage);
+			if (stage == GLS_ACTIVATION) {
+				ClearTemporaryNewGRFData();
+				DEBUG(sprite, 2, "Currently %i sprites are loaded", _cur_spriteid);
+			}
+		}
+	}
+
+	// Pre-calculate all refit masks after loading GRF files
+	CalculateRefitMasks();
+}
+
+
deleted file mode 100644
--- a/src/newgrf_cargo.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "newgrf_cargo.h"
-
-/** TRANSLATE FROM LOCAL CARGO TO GLOBAL CARGO ID'S.
- * This maps the per-landscape cargo ID's to globally unique cargo ID's usable ie. in
- * the custom GRF  files. It is basically just a transcribed table from TTDPatch's newgrf.txt.
- */
-const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
-	/* LT_NORMAL */ {GC_PASSENGERS, GC_COAL,   GC_MAIL, GC_OIL,  GC_LIVESTOCK, GC_GOODS, GC_GRAIN,  GC_WOOD, GC_IRON_ORE,     GC_STEEL,   GC_VALUABLES, GC_PAPER_TEMP},
-	/* LT_HILLY */  {GC_PASSENGERS, GC_COAL,   GC_MAIL, GC_OIL,  GC_LIVESTOCK, GC_GOODS, GC_GRAIN,  GC_WOOD, GC_INVALID,      GC_PAPER,   GC_VALUABLES, GC_FOOD },
-	/* LT_DESERT */ {GC_PASSENGERS, GC_RUBBER, GC_MAIL, GC_OIL,  GC_FRUIT,     GC_GOODS, GC_GRAIN,  GC_WOOD, GC_COPPER_ORE,   GC_WATER,   GC_VALUABLES, GC_FOOD },
-	/* LT_CANDY */  {GC_PASSENGERS, GC_SUGAR,  GC_MAIL, GC_TOYS, GC_BATTERIES, GC_CANDY, GC_TOFFEE, GC_COLA, GC_COTTON_CANDY, GC_BUBBLES, GC_PLASTIC,   GC_FIZZY_DRINKS },
-	/**
-	 * - GC_INVALID (255) means that  cargo is not available for that climate
-	 * - GC_PAPER_TEMP (27) is paper in  temperate climate in TTDPatch
-	 * Following can  be renumbered:
-	 * - GC_DEFAULT (29) is the defa ult cargo for the purpose of spritesets
-	 * - GC_PURCHASE (30) is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
-	 */
-};
-
-/** BEGIN --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
-/** Map global cargo ID's to local-cargo ID's */
-const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID] = {
-	CT_PASSENGERS, CT_COAL,    CT_MAIL,         CT_OIL,       CT_LIVESTOCK, CT_GOODS,  CT_GRAIN,      CT_WOOD,         /*  0- 7 */
-	CT_IRON_ORE,   CT_STEEL,   CT_VALUABLES,    CT_PAPER,     CT_FOOD,      CT_FRUIT,  CT_COPPER_ORE, CT_WATER,        /*  8-15 */
-	CT_RUBBER,     CT_SUGAR,   CT_TOYS,         CT_BATTERIES, CT_CANDY,     CT_TOFFEE, CT_COLA,       CT_COTTON_CANDY, /* 16-23 */
-	CT_BUBBLES,    CT_PLASTIC, CT_FIZZY_DRINKS, CT_PAPER      /* unsup. */, CT_HILLY_UNUSED,                           /* 24-28 */
-	CT_INVALID,    CT_INVALID                                                                                          /* 29-30 */
-};
-
-/** Bitmasked value where the global cargo ID is available in landscape
- * 0: LT_NORMAL, 1: LT_HILLY, 2: LT_DESERT, 3: LT_CANDY */
-#define MC(cargo) (1 << cargo)
-const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE] =
-{ /* LT_NORMAL: temperate */
-	MC(GC_PASSENGERS) | MC(GC_COAL) | MC(GC_MAIL)  | MC(GC_OIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD) | MC(GC_IRON_ORE)     | MC(GC_STEEL)      | MC(GC_VALUABLES),
-	/* LT_HILLY: arctic */
-	MC(GC_PASSENGERS) | MC(GC_COAL) | MC(GC_MAIL)  | MC(GC_OIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD) | MC(GC_VALUABLES)    | MC(GC_PAPER)      | MC(GC_FOOD),
-	/* LT_DESERT: rainforest/desert */
-	MC(GC_PASSENGERS) | MC(GC_MAIL) | MC(GC_OIL)   | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD)  | MC(GC_VALUABLES) | MC(GC_FOOD) | MC(GC_FRUIT)        | MC(GC_COPPER_ORE) | MC(GC_WATER)   | MC(GC_RUBBER),
-	/* LT_CANDY: toyland */
-	MC(GC_PASSENGERS) | MC(GC_MAIL) | MC(GC_SUGAR) | MC(GC_TOYS)  | MC(GC_BATTERIES) | MC(GC_CANDY) | MC(GC_TOFFEE)    | MC(GC_COLA) | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES)    | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS)
-};
-/** END   --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
-
-/**
- * Bitmask of classes for cargo types.
- */
-const uint32 cargo_classes[16] = {
-	/* Passengers */ MC(GC_PASSENGERS),
-	/* Mail       */ MC(GC_MAIL),
-	/* Express    */ MC(GC_GOODS)     | MC(GC_FOOD)  | MC(GC_CANDY),
-	/* Armoured   */ MC(GC_VALUABLES),
-	/* Bulk       */ MC(GC_COAL)      | MC(GC_GRAIN) | MC(GC_IRON_ORE) | MC(GC_COPPER_ORE) | MC(GC_FRUIT)   | MC(GC_SUGAR)     | MC(GC_TOFFEE)  | MC(GC_COTTON_CANDY),
-	/* Piece      */ MC(GC_LIVESTOCK) | MC(GC_WOOD)  | MC(GC_STEEL)    | MC(GC_PAPER)      | MC(GC_TOYS)    | MC(GC_BATTERIES) | MC(GC_BUBBLES) | MC(GC_FIZZY_DRINKS),
-	/* Liquids    */ MC(GC_OIL)       | MC(GC_WATER) | MC(GC_RUBBER)   | MC(GC_COLA)       | MC(GC_PLASTIC),
-	/* Chilled    */ MC(GC_FOOD)      | MC(GC_FRUIT),
-	/* Undefined  */ 0, 0, 0, 0, 0, 0, 0, 0
-};
-#undef MC
-
-/**
- *there are 32 slots available per climate with newcargo.*/
-#define MAXSLOTS 32
new file mode 100644
--- /dev/null
+++ b/src/newgrf_cargo.cpp
@@ -0,0 +1,68 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "newgrf_cargo.h"
+
+/** TRANSLATE FROM LOCAL CARGO TO GLOBAL CARGO ID'S.
+ * This maps the per-landscape cargo ID's to globally unique cargo ID's usable ie. in
+ * the custom GRF  files. It is basically just a transcribed table from TTDPatch's newgrf.txt.
+ */
+const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
+	/* LT_NORMAL */ {GC_PASSENGERS, GC_COAL,   GC_MAIL, GC_OIL,  GC_LIVESTOCK, GC_GOODS, GC_GRAIN,  GC_WOOD, GC_IRON_ORE,     GC_STEEL,   GC_VALUABLES, GC_PAPER_TEMP},
+	/* LT_HILLY */  {GC_PASSENGERS, GC_COAL,   GC_MAIL, GC_OIL,  GC_LIVESTOCK, GC_GOODS, GC_GRAIN,  GC_WOOD, GC_INVALID,      GC_PAPER,   GC_VALUABLES, GC_FOOD },
+	/* LT_DESERT */ {GC_PASSENGERS, GC_RUBBER, GC_MAIL, GC_OIL,  GC_FRUIT,     GC_GOODS, GC_GRAIN,  GC_WOOD, GC_COPPER_ORE,   GC_WATER,   GC_VALUABLES, GC_FOOD },
+	/* LT_CANDY */  {GC_PASSENGERS, GC_SUGAR,  GC_MAIL, GC_TOYS, GC_BATTERIES, GC_CANDY, GC_TOFFEE, GC_COLA, GC_COTTON_CANDY, GC_BUBBLES, GC_PLASTIC,   GC_FIZZY_DRINKS },
+	/**
+	 * - GC_INVALID (255) means that  cargo is not available for that climate
+	 * - GC_PAPER_TEMP (27) is paper in  temperate climate in TTDPatch
+	 * Following can  be renumbered:
+	 * - GC_DEFAULT (29) is the defa ult cargo for the purpose of spritesets
+	 * - GC_PURCHASE (30) is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
+	 */
+};
+
+/** BEGIN --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
+/** Map global cargo ID's to local-cargo ID's */
+const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID] = {
+	CT_PASSENGERS, CT_COAL,    CT_MAIL,         CT_OIL,       CT_LIVESTOCK, CT_GOODS,  CT_GRAIN,      CT_WOOD,         /*  0- 7 */
+	CT_IRON_ORE,   CT_STEEL,   CT_VALUABLES,    CT_PAPER,     CT_FOOD,      CT_FRUIT,  CT_COPPER_ORE, CT_WATER,        /*  8-15 */
+	CT_RUBBER,     CT_SUGAR,   CT_TOYS,         CT_BATTERIES, CT_CANDY,     CT_TOFFEE, CT_COLA,       CT_COTTON_CANDY, /* 16-23 */
+	CT_BUBBLES,    CT_PLASTIC, CT_FIZZY_DRINKS, CT_PAPER      /* unsup. */, CT_HILLY_UNUSED,                           /* 24-28 */
+	CT_INVALID,    CT_INVALID                                                                                          /* 29-30 */
+};
+
+/** Bitmasked value where the global cargo ID is available in landscape
+ * 0: LT_NORMAL, 1: LT_HILLY, 2: LT_DESERT, 3: LT_CANDY */
+#define MC(cargo) (1 << cargo)
+const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE] =
+{ /* LT_NORMAL: temperate */
+	MC(GC_PASSENGERS) | MC(GC_COAL) | MC(GC_MAIL)  | MC(GC_OIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD) | MC(GC_IRON_ORE)     | MC(GC_STEEL)      | MC(GC_VALUABLES),
+	/* LT_HILLY: arctic */
+	MC(GC_PASSENGERS) | MC(GC_COAL) | MC(GC_MAIL)  | MC(GC_OIL)   | MC(GC_LIVESTOCK) | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD) | MC(GC_VALUABLES)    | MC(GC_PAPER)      | MC(GC_FOOD),
+	/* LT_DESERT: rainforest/desert */
+	MC(GC_PASSENGERS) | MC(GC_MAIL) | MC(GC_OIL)   | MC(GC_GOODS) | MC(GC_GRAIN)     | MC(GC_WOOD)  | MC(GC_VALUABLES) | MC(GC_FOOD) | MC(GC_FRUIT)        | MC(GC_COPPER_ORE) | MC(GC_WATER)   | MC(GC_RUBBER),
+	/* LT_CANDY: toyland */
+	MC(GC_PASSENGERS) | MC(GC_MAIL) | MC(GC_SUGAR) | MC(GC_TOYS)  | MC(GC_BATTERIES) | MC(GC_CANDY) | MC(GC_TOFFEE)    | MC(GC_COLA) | MC(GC_COTTON_CANDY) | MC(GC_BUBBLES)    | MC(GC_PLASTIC) | MC(GC_FIZZY_DRINKS)
+};
+/** END   --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
+
+/**
+ * Bitmask of classes for cargo types.
+ */
+const uint32 cargo_classes[16] = {
+	/* Passengers */ MC(GC_PASSENGERS),
+	/* Mail       */ MC(GC_MAIL),
+	/* Express    */ MC(GC_GOODS)     | MC(GC_FOOD)  | MC(GC_CANDY),
+	/* Armoured   */ MC(GC_VALUABLES),
+	/* Bulk       */ MC(GC_COAL)      | MC(GC_GRAIN) | MC(GC_IRON_ORE) | MC(GC_COPPER_ORE) | MC(GC_FRUIT)   | MC(GC_SUGAR)     | MC(GC_TOFFEE)  | MC(GC_COTTON_CANDY),
+	/* Piece      */ MC(GC_LIVESTOCK) | MC(GC_WOOD)  | MC(GC_STEEL)    | MC(GC_PAPER)      | MC(GC_TOYS)    | MC(GC_BATTERIES) | MC(GC_BUBBLES) | MC(GC_FIZZY_DRINKS),
+	/* Liquids    */ MC(GC_OIL)       | MC(GC_WATER) | MC(GC_RUBBER)   | MC(GC_COLA)       | MC(GC_PLASTIC),
+	/* Chilled    */ MC(GC_FOOD)      | MC(GC_FRUIT),
+	/* Undefined  */ 0, 0, 0, 0, 0, 0, 0, 0
+};
+#undef MC
+
+/**
+ *there are 32 slots available per climate with newcargo.*/
+#define MAXSLOTS 32
deleted file mode 100644
--- a/src/newgrf_config.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "macros.h"
-#include "debug.h"
-#include "variables.h"
-#include "string.h"
-#include "saveload.h"
-#include "md5.h"
-#include "network/network_data.h"
-#include "newgrf.h"
-#include "newgrf_config.h"
-
-#include "fileio.h"
-#include "fios.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef WIN32
-# include <io.h>
-#else
-# include <unistd.h>
-# include <dirent.h>
-#endif /* WIN32 */
-
-
-GRFConfig *_all_grfs;
-GRFConfig *_grfconfig;
-GRFConfig *_grfconfig_newgame;
-GRFConfig *_grfconfig_static;
-
-
-/* Calculate the MD5 Sum for a GRF */
-static bool CalcGRFMD5Sum(GRFConfig *config)
-{
-	FILE *f;
-	char filename[MAX_PATH];
-	md5_state_t md5state;
-	md5_byte_t buffer[1024];
-	size_t len;
-
-	/* open the file */
-	snprintf(filename, lengthof(filename), "%s%s", _paths.data_dir, config->filename);
-	f = fopen(filename, "rb");
-	if (f == NULL) return false;
-
-	/* calculate md5sum */
-	md5_init(&md5state);
-	while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) {
-		md5_append(&md5state, buffer, len);
-	}
-	md5_finish(&md5state, config->md5sum);
-
-	fclose(f);
-
-	return true;
-}
-
-
-/* Find the GRFID and calculate the md5sum */
-bool FillGRFDetails(GRFConfig *config, bool is_static)
-{
-	if (!FioCheckFileExists(config->filename)) {
-		SETBIT(config->flags, GCF_NOT_FOUND);
-		return false;
-	}
-
-	/* Find and load the Action 8 information */
-	/* 62 is the last file slot before sample.cat.
-	 * Should perhaps be some "don't care" value */
-	LoadNewGRFFile(config, 62, GLS_FILESCAN);
-
-	/* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */
-	if (config->grfid == 0 || config->grfid == 0xFFFFFFFF) return false;
-
-	if (is_static) {
-		/* Perform a 'safety scan' for static GRFs */
-		LoadNewGRFFile(config, 62, GLS_SAFETYSCAN);
-
-		/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
-		if (HASBIT(config->flags, GCF_UNSAFE)) return false;
-	}
-
-	return CalcGRFMD5Sum(config);
-}
-
-
-void ClearGRFConfig(GRFConfig **config)
-{
-	/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
-	if (!HASBIT((*config)->flags, GCF_COPY)) {
-		free((*config)->filename);
-		free((*config)->name);
-		free((*config)->info);
-	}
-	free(*config);
-	*config = NULL;
-}
-
-
-/* Clear a GRF Config list */
-void ClearGRFConfigList(GRFConfig **config)
-{
-	GRFConfig *c, *next;
-	for (c = *config; c != NULL; c = next) {
-		next = c->next;
-		ClearGRFConfig(&c);
-	}
-	*config = NULL;
-}
-
-
-/** Copy a GRF Config list
- * @param dst pointer to destination list
- * @param srt pointer to source list values
- * @return pointer to the last value added to the destination list */
-GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src)
-{
-	GRFConfig *c;
-
-	/* Clear destination as it will be overwritten */
-	ClearGRFConfigList(dst);
-	for (; src != NULL; src = src->next) {
-		c = calloc(1, sizeof(*c));
-		*c = *src;
-		if (src->filename != NULL) c->filename = strdup(src->filename);
-		if (src->name     != NULL) c->name     = strdup(src->name);
-		if (src->info     != NULL) c->info     = strdup(src->info);
-
-		*dst = c;
-		dst = &c->next;
-	}
-
-	return dst;
-}
-
-/**
- * Removes duplicates from lists of GRFConfigs. These duplicates
- * are introduced when the _grfconfig_static GRFs are appended
- * to the _grfconfig on a newgame or savegame. As the parameters
- * of the static GRFs could be different that the parameters of
- * the ones used non-statically. This can result in desyncs in
- * multiplayers, so the duplicate static GRFs have to be removed.
- *
- * This function _assumes_ that all static GRFs are placed after
- * the non-static GRFs.
- *
- * @param list the list to remove the duplicates from
- */
-static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
-{
-	GRFConfig *prev;
-	GRFConfig *cur;
-
-	if (list == NULL) return;
-
-	for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
-		if (cur->grfid != list->grfid) continue;
-		assert(HASBIT(cur->flags, GCF_STATIC));
-		prev->next = cur->next;
-		ClearGRFConfig(&cur);
-		cur = prev; // Just go back one so it continues as normal later on
-	}
-
-	RemoveDuplicatesFromGRFConfigList(list->next);
-}
-
-/**
- * Appends the static GRFs to a list of GRFs
- * @param dst the head of the list to add to
- */
-void AppendStaticGRFConfigs(GRFConfig **dst)
-{
-	GRFConfig **tail = dst;
-	while (*tail != NULL) tail = &(*tail)->next;
-
-	CopyGRFConfigList(tail, _grfconfig_static);
-	RemoveDuplicatesFromGRFConfigList(*dst);
-}
-
-
-/* Reset the current GRF Config to either blank or newgame settings */
-void ResetGRFConfig(bool defaults)
-{
-	GRFConfig **c = &_grfconfig;
-
-	if (defaults) {
-		c = CopyGRFConfigList(c, _grfconfig_newgame);
-	} else {
-		ClearGRFConfigList(c);
-	}
-
-	AppendStaticGRFConfigs(&_grfconfig);
-}
-
-
-/* Check if all GRFs in the GRF Config can be loaded */
-bool IsGoodGRFConfigList(void)
-{
-	bool res = true;
-	GRFConfig *c;
-
-	for (c = _grfconfig; c != NULL; c = c->next) {
-		const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
-		if (f == NULL) {
-			char buf[512], *p = buf;
-			uint i;
-
-			p += snprintf(p, lastof(buf) - p, "Couldn't find NewGRF %08X (%s) checksum ", BSWAP32(c->grfid), c->filename);
-			for (i = 0; i < lengthof(c->md5sum); i++) {
-				p += snprintf(p, lastof(buf) - p, "%02X", c->md5sum[i]);
-			}
-			ShowInfo(buf);
-
-			res = false;
-		} else {
-			DEBUG(grf, 1, "Loading GRF %08X from '%s'", BSWAP32(c->grfid), f->filename);
-			/* The filename could be the filename as in the savegame. As we need
-			 * to load the GRF here, we need the correct filename, so overwrite that
-			 * in any case and set the name and info when it is not set already.
-			 * When the GCF_COPY flag is set, it is certain that the filename is
-			 * already a local one, so there is no need to replace it. */
-			if (!HASBIT(c->flags, GCF_COPY)) {
-				free(c->filename);
-				c->filename = strdup(f->filename);
-				if (c->name == NULL) c->name = strdup(f->name);
-				if (c->info == NULL) c->info = strdup(f->info);
-			}
-		}
-	}
-
-	return res;
-}
-
-
-extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
-
-/* Scan a path for NewGRFs */
-static uint ScanPath(const char *path)
-{
-	uint num = 0;
-	struct stat sb;
-	struct dirent *dirent;
-	DIR *dir;
-	GRFConfig *c;
-
-	if ((dir = opendir(path)) == NULL) return 0;
-
-	while ((dirent = readdir(dir)) != NULL) {
-		const char *d_name = FS2OTTD(dirent->d_name);
-		char filename[MAX_PATH];
-
-		if (!FiosIsValidFile(path, dirent, &sb)) continue;
-
-		snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, d_name);
-
-		if (sb.st_mode & S_IFDIR) {
-			/* Directory */
-			if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
-			num += ScanPath(filename);
-		} else if (sb.st_mode & S_IFREG) {
-			/* File */
-			char *ext = strrchr(filename, '.');
-			char *file = filename + strlen(_paths.data_dir) + 1; // Crop base path
-
-			/* If no extension or extension isn't .grf, skip the file */
-			if (ext == NULL) continue;
-			if (strcasecmp(ext, ".grf") != 0) continue;
-
-			c = calloc(1, sizeof(*c));
-			c->filename = strdup(file);
-
-			if (FillGRFDetails(c, false)) {
-				if (_all_grfs == NULL) {
-					_all_grfs = c;
-				} else {
-					/* Insert file into list at a position determined by its
-					 * name, so the list is sorted as we go along */
-					GRFConfig **pd, *d;
-					for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) {
-						if (strcasecmp(c->name, d->name) <= 0) break;
-					}
-					c->next = d;
-					*pd = c;
-				}
-
-				num++;
-			} else {
-				/* File couldn't be opened, or is either not a NewGRF or is a
-				 * 'system' NewGRF, so forget about it. */
-				free(c->filename);
-				free(c->name);
-				free(c->info);
-				free(c);
-			}
-		}
-	}
-
-	closedir(dir);
-
-	return num;
-}
-
-
-/* Scan for all NewGRFs */
-void ScanNewGRFFiles(void)
-{
-	uint num;
-
-	ClearGRFConfigList(&_all_grfs);
-
-	DEBUG(grf, 1, "Scanning for NewGRFs");
-	num = ScanPath(_paths.data_dir);
-	DEBUG(grf, 1, "Scan complete, found %d files", num);
-}
-
-
-/* Find a NewGRF in the scanned list */
-const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum)
-{
-	GRFConfig *c;
-	static const uint8 blanksum[sizeof(c->md5sum)] = { 0 };
-
-	for (c = _all_grfs; c != NULL; c = c->next) {
-		if (c->grfid == grfid) {
-			if (memcmp(blanksum, c->md5sum, sizeof(c->md5sum)) == 0) CalcGRFMD5Sum(c);
-			if (memcmp(md5sum, c->md5sum, sizeof(c->md5sum)) == 0) return c;
-		}
-	}
-
-	return NULL;
-}
-
-#ifdef ENABLE_NETWORK
-
-/** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */
-typedef struct UnknownGRF UnknownGRF;
-struct UnknownGRF {
-	UnknownGRF *next;
-	uint32 grfid;
-	uint8  md5sum[16];
-	char   name[NETWORK_GRF_NAME_LENGTH];
-};
-
-/**
- * Finds the name of a NewGRF in the list of names for unknown GRFs. An
- * unknown GRF is a GRF where the .grf is not found during scanning.
- *
- * The names are resolved via UDP calls to servers that should know the name,
- * though the replies may not come. This leaves "<Unknown>" as name, though
- * that shouldn't matter _very_ much as they need GRF crawler or so to look
- * up the GRF anyway and that works better with the GRF ID.
- *
- * @param grfid  the GRF ID part of the 'unique' GRF identifier
- * @param md5sum the MD5 checksum part of the 'unique' GRF identifier
- * @param create whether to create a new GRFConfig if the GRFConfig did not
- *               exist in the fake list of GRFConfigs.
- * @return the GRFConfig with the given GRF ID and MD5 checksum or NULL when
- *         it does not exist and create is false. This value must NEVER be
- *         freed by the caller.
- */
-char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create)
-{
-	UnknownGRF *grf;
-	static UnknownGRF *unknown_grfs = NULL;
-
-	for (grf = unknown_grfs; grf != NULL; grf = grf->next) {
-		if (grf->grfid == grfid) {
-			if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name;
-		}
-	}
-
-	if (!create) return NULL;
-
-	grf = calloc(1, sizeof(*grf));
-	grf->grfid = grfid;
-	grf->next  = unknown_grfs;
-	ttd_strlcpy(grf->name, UNKNOWN_GRF_NAME_PLACEHOLDER, sizeof(grf->name));
-	memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum));
-
-	unknown_grfs = grf;
-	return grf->name;
-}
-
-#endif /* ENABLE_NETWORK */
-
-
-/* Retrieve a NewGRF from the current config by its grfid */
-GRFConfig *GetGRFConfig(uint32 grfid)
-{
-	GRFConfig *c;
-
-	for (c = _grfconfig; c != NULL; c = c->next) {
-		if (c->grfid == grfid) return c;
-	}
-
-	return NULL;
-}
-
-
-/* Build a space separated list of parameters, and terminate */
-char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last)
-{
-	uint i;
-
-	/* Return an empty string if there are no parameters */
-	if (c->num_params == 0) return strecpy(dst, "", last);
-
-	for (i = 0; i < c->num_params; i++) {
-		if (i > 0) dst = strecpy(dst, " ", last);
-		dst += snprintf(dst, last - dst, "%d", c->param[i]);
-	}
-	return dst;
-}
-
-
-static const SaveLoad _grfconfig_desc[] = {
-	SLE_STR(GRFConfig, filename,   SLE_STR, 0x40),
-	SLE_VAR(GRFConfig, grfid,      SLE_UINT32),
-	SLE_ARR(GRFConfig, md5sum,     SLE_UINT8, 16),
-	SLE_ARR(GRFConfig, param,      SLE_UINT32, 0x80),
-	SLE_VAR(GRFConfig, num_params, SLE_UINT8),
-	SLE_END()
-};
-
-
-static void Save_NGRF(void)
-{
-	GRFConfig *c;
-	int index = 0;
-
-	for (c = _grfconfig; c != NULL; c = c->next) {
-		if (HASBIT(c->flags, GCF_STATIC)) continue;
-		SlSetArrayIndex(index++);
-		SlObject(c, _grfconfig_desc);
-	}
-}
-
-
-static void Load_NGRF(void)
-{
-	GRFConfig *first = NULL;
-	GRFConfig **last = &first;
-
-	while (SlIterateArray() != -1) {
-		GRFConfig *c = calloc(1, sizeof(*c));
-		SlObject(c, _grfconfig_desc);
-
-		/* Append our configuration to the list */
-		*last = c;
-		last = &c->next;
-	}
-
-	/* Append static NewGRF configuration */
-	CopyGRFConfigList(last, _grfconfig_static);
-
-	ClearGRFConfigList(&_grfconfig);
-	_grfconfig = first;
-	AppendStaticGRFConfigs(&_grfconfig);
-}
-
-const ChunkHandler _newgrf_chunk_handlers[] = {
-	{ 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
-};
-
-
new file mode 100644
--- /dev/null
+++ b/src/newgrf_config.cpp
@@ -0,0 +1,468 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "macros.h"
+#include "debug.h"
+#include "variables.h"
+#include "string.h"
+#include "saveload.h"
+#include "md5.h"
+#include "network/network_data.h"
+#include "newgrf.h"
+#include "newgrf_config.h"
+
+#include "fileio.h"
+#include "fios.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <dirent.h>
+#endif /* WIN32 */
+
+
+GRFConfig *_all_grfs;
+GRFConfig *_grfconfig;
+GRFConfig *_grfconfig_newgame;
+GRFConfig *_grfconfig_static;
+
+
+/* Calculate the MD5 Sum for a GRF */
+static bool CalcGRFMD5Sum(GRFConfig *config)
+{
+	FILE *f;
+	char filename[MAX_PATH];
+	md5_state_t md5state;
+	md5_byte_t buffer[1024];
+	size_t len;
+
+	/* open the file */
+	snprintf(filename, lengthof(filename), "%s%s", _paths.data_dir, config->filename);
+	f = fopen(filename, "rb");
+	if (f == NULL) return false;
+
+	/* calculate md5sum */
+	md5_init(&md5state);
+	while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) {
+		md5_append(&md5state, buffer, len);
+	}
+	md5_finish(&md5state, config->md5sum);
+
+	fclose(f);
+
+	return true;
+}
+
+
+/* Find the GRFID and calculate the md5sum */
+bool FillGRFDetails(GRFConfig *config, bool is_static)
+{
+	if (!FioCheckFileExists(config->filename)) {
+		SETBIT(config->flags, GCF_NOT_FOUND);
+		return false;
+	}
+
+	/* Find and load the Action 8 information */
+	/* 62 is the last file slot before sample.cat.
+	 * Should perhaps be some "don't care" value */
+	LoadNewGRFFile(config, 62, GLS_FILESCAN);
+
+	/* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */
+	if (config->grfid == 0 || config->grfid == 0xFFFFFFFF) return false;
+
+	if (is_static) {
+		/* Perform a 'safety scan' for static GRFs */
+		LoadNewGRFFile(config, 62, GLS_SAFETYSCAN);
+
+		/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
+		if (HASBIT(config->flags, GCF_UNSAFE)) return false;
+	}
+
+	return CalcGRFMD5Sum(config);
+}
+
+
+void ClearGRFConfig(GRFConfig **config)
+{
+	/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
+	if (!HASBIT((*config)->flags, GCF_COPY)) {
+		free((*config)->filename);
+		free((*config)->name);
+		free((*config)->info);
+	}
+	free(*config);
+	*config = NULL;
+}
+
+
+/* Clear a GRF Config list */
+void ClearGRFConfigList(GRFConfig **config)
+{
+	GRFConfig *c, *next;
+	for (c = *config; c != NULL; c = next) {
+		next = c->next;
+		ClearGRFConfig(&c);
+	}
+	*config = NULL;
+}
+
+
+/** Copy a GRF Config list
+ * @param dst pointer to destination list
+ * @param srt pointer to source list values
+ * @return pointer to the last value added to the destination list */
+GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src)
+{
+	GRFConfig *c;
+
+	/* Clear destination as it will be overwritten */
+	ClearGRFConfigList(dst);
+	for (; src != NULL; src = src->next) {
+		c = calloc(1, sizeof(*c));
+		*c = *src;
+		if (src->filename != NULL) c->filename = strdup(src->filename);
+		if (src->name     != NULL) c->name     = strdup(src->name);
+		if (src->info     != NULL) c->info     = strdup(src->info);
+
+		*dst = c;
+		dst = &c->next;
+	}
+
+	return dst;
+}
+
+/**
+ * Removes duplicates from lists of GRFConfigs. These duplicates
+ * are introduced when the _grfconfig_static GRFs are appended
+ * to the _grfconfig on a newgame or savegame. As the parameters
+ * of the static GRFs could be different that the parameters of
+ * the ones used non-statically. This can result in desyncs in
+ * multiplayers, so the duplicate static GRFs have to be removed.
+ *
+ * This function _assumes_ that all static GRFs are placed after
+ * the non-static GRFs.
+ *
+ * @param list the list to remove the duplicates from
+ */
+static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
+{
+	GRFConfig *prev;
+	GRFConfig *cur;
+
+	if (list == NULL) return;
+
+	for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
+		if (cur->grfid != list->grfid) continue;
+		assert(HASBIT(cur->flags, GCF_STATIC));
+		prev->next = cur->next;
+		ClearGRFConfig(&cur);
+		cur = prev; // Just go back one so it continues as normal later on
+	}
+
+	RemoveDuplicatesFromGRFConfigList(list->next);
+}
+
+/**
+ * Appends the static GRFs to a list of GRFs
+ * @param dst the head of the list to add to
+ */
+void AppendStaticGRFConfigs(GRFConfig **dst)
+{
+	GRFConfig **tail = dst;
+	while (*tail != NULL) tail = &(*tail)->next;
+
+	CopyGRFConfigList(tail, _grfconfig_static);
+	RemoveDuplicatesFromGRFConfigList(*dst);
+}
+
+
+/* Reset the current GRF Config to either blank or newgame settings */
+void ResetGRFConfig(bool defaults)
+{
+	GRFConfig **c = &_grfconfig;
+
+	if (defaults) {
+		c = CopyGRFConfigList(c, _grfconfig_newgame);
+	} else {
+		ClearGRFConfigList(c);
+	}
+
+	AppendStaticGRFConfigs(&_grfconfig);
+}
+
+
+/* Check if all GRFs in the GRF Config can be loaded */
+bool IsGoodGRFConfigList(void)
+{
+	bool res = true;
+	GRFConfig *c;
+
+	for (c = _grfconfig; c != NULL; c = c->next) {
+		const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
+		if (f == NULL) {
+			char buf[512], *p = buf;
+			uint i;
+
+			p += snprintf(p, lastof(buf) - p, "Couldn't find NewGRF %08X (%s) checksum ", BSWAP32(c->grfid), c->filename);
+			for (i = 0; i < lengthof(c->md5sum); i++) {
+				p += snprintf(p, lastof(buf) - p, "%02X", c->md5sum[i]);
+			}
+			ShowInfo(buf);
+
+			res = false;
+		} else {
+			DEBUG(grf, 1, "Loading GRF %08X from '%s'", BSWAP32(c->grfid), f->filename);
+			/* The filename could be the filename as in the savegame. As we need
+			 * to load the GRF here, we need the correct filename, so overwrite that
+			 * in any case and set the name and info when it is not set already.
+			 * When the GCF_COPY flag is set, it is certain that the filename is
+			 * already a local one, so there is no need to replace it. */
+			if (!HASBIT(c->flags, GCF_COPY)) {
+				free(c->filename);
+				c->filename = strdup(f->filename);
+				if (c->name == NULL) c->name = strdup(f->name);
+				if (c->info == NULL) c->info = strdup(f->info);
+			}
+		}
+	}
+
+	return res;
+}
+
+
+extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
+
+/* Scan a path for NewGRFs */
+static uint ScanPath(const char *path)
+{
+	uint num = 0;
+	struct stat sb;
+	struct dirent *dirent;
+	DIR *dir;
+	GRFConfig *c;
+
+	if ((dir = opendir(path)) == NULL) return 0;
+
+	while ((dirent = readdir(dir)) != NULL) {
+		const char *d_name = FS2OTTD(dirent->d_name);
+		char filename[MAX_PATH];
+
+		if (!FiosIsValidFile(path, dirent, &sb)) continue;
+
+		snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, d_name);
+
+		if (sb.st_mode & S_IFDIR) {
+			/* Directory */
+			if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
+			num += ScanPath(filename);
+		} else if (sb.st_mode & S_IFREG) {
+			/* File */
+			char *ext = strrchr(filename, '.');
+			char *file = filename + strlen(_paths.data_dir) + 1; // Crop base path
+
+			/* If no extension or extension isn't .grf, skip the file */
+			if (ext == NULL) continue;
+			if (strcasecmp(ext, ".grf") != 0) continue;
+
+			c = calloc(1, sizeof(*c));
+			c->filename = strdup(file);
+
+			if (FillGRFDetails(c, false)) {
+				if (_all_grfs == NULL) {
+					_all_grfs = c;
+				} else {
+					/* Insert file into list at a position determined by its
+					 * name, so the list is sorted as we go along */
+					GRFConfig **pd, *d;
+					for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) {
+						if (strcasecmp(c->name, d->name) <= 0) break;
+					}
+					c->next = d;
+					*pd = c;
+				}
+
+				num++;
+			} else {
+				/* File couldn't be opened, or is either not a NewGRF or is a
+				 * 'system' NewGRF, so forget about it. */
+				free(c->filename);
+				free(c->name);
+				free(c->info);
+				free(c);
+			}
+		}
+	}
+
+	closedir(dir);
+
+	return num;
+}
+
+
+/* Scan for all NewGRFs */
+void ScanNewGRFFiles(void)
+{
+	uint num;
+
+	ClearGRFConfigList(&_all_grfs);
+
+	DEBUG(grf, 1, "Scanning for NewGRFs");
+	num = ScanPath(_paths.data_dir);
+	DEBUG(grf, 1, "Scan complete, found %d files", num);
+}
+
+
+/* Find a NewGRF in the scanned list */
+const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum)
+{
+	GRFConfig *c;
+	static const uint8 blanksum[sizeof(c->md5sum)] = { 0 };
+
+	for (c = _all_grfs; c != NULL; c = c->next) {
+		if (c->grfid == grfid) {
+			if (memcmp(blanksum, c->md5sum, sizeof(c->md5sum)) == 0) CalcGRFMD5Sum(c);
+			if (memcmp(md5sum, c->md5sum, sizeof(c->md5sum)) == 0) return c;
+		}
+	}
+
+	return NULL;
+}
+
+#ifdef ENABLE_NETWORK
+
+/** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */
+typedef struct UnknownGRF UnknownGRF;
+struct UnknownGRF {
+	UnknownGRF *next;
+	uint32 grfid;
+	uint8  md5sum[16];
+	char   name[NETWORK_GRF_NAME_LENGTH];
+};
+
+/**
+ * Finds the name of a NewGRF in the list of names for unknown GRFs. An
+ * unknown GRF is a GRF where the .grf is not found during scanning.
+ *
+ * The names are resolved via UDP calls to servers that should know the name,
+ * though the replies may not come. This leaves "<Unknown>" as name, though
+ * that shouldn't matter _very_ much as they need GRF crawler or so to look
+ * up the GRF anyway and that works better with the GRF ID.
+ *
+ * @param grfid  the GRF ID part of the 'unique' GRF identifier
+ * @param md5sum the MD5 checksum part of the 'unique' GRF identifier
+ * @param create whether to create a new GRFConfig if the GRFConfig did not
+ *               exist in the fake list of GRFConfigs.
+ * @return the GRFConfig with the given GRF ID and MD5 checksum or NULL when
+ *         it does not exist and create is false. This value must NEVER be
+ *         freed by the caller.
+ */
+char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create)
+{
+	UnknownGRF *grf;
+	static UnknownGRF *unknown_grfs = NULL;
+
+	for (grf = unknown_grfs; grf != NULL; grf = grf->next) {
+		if (grf->grfid == grfid) {
+			if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name;
+		}
+	}
+
+	if (!create) return NULL;
+
+	grf = calloc(1, sizeof(*grf));
+	grf->grfid = grfid;
+	grf->next  = unknown_grfs;
+	ttd_strlcpy(grf->name, UNKNOWN_GRF_NAME_PLACEHOLDER, sizeof(grf->name));
+	memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum));
+
+	unknown_grfs = grf;
+	return grf->name;
+}
+
+#endif /* ENABLE_NETWORK */
+
+
+/* Retrieve a NewGRF from the current config by its grfid */
+GRFConfig *GetGRFConfig(uint32 grfid)
+{
+	GRFConfig *c;
+
+	for (c = _grfconfig; c != NULL; c = c->next) {
+		if (c->grfid == grfid) return c;
+	}
+
+	return NULL;
+}
+
+
+/* Build a space separated list of parameters, and terminate */
+char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last)
+{
+	uint i;
+
+	/* Return an empty string if there are no parameters */
+	if (c->num_params == 0) return strecpy(dst, "", last);
+
+	for (i = 0; i < c->num_params; i++) {
+		if (i > 0) dst = strecpy(dst, " ", last);
+		dst += snprintf(dst, last - dst, "%d", c->param[i]);
+	}
+	return dst;
+}
+
+
+static const SaveLoad _grfconfig_desc[] = {
+	SLE_STR(GRFConfig, filename,   SLE_STR, 0x40),
+	SLE_VAR(GRFConfig, grfid,      SLE_UINT32),
+	SLE_ARR(GRFConfig, md5sum,     SLE_UINT8, 16),
+	SLE_ARR(GRFConfig, param,      SLE_UINT32, 0x80),
+	SLE_VAR(GRFConfig, num_params, SLE_UINT8),
+	SLE_END()
+};
+
+
+static void Save_NGRF(void)
+{
+	GRFConfig *c;
+	int index = 0;
+
+	for (c = _grfconfig; c != NULL; c = c->next) {
+		if (HASBIT(c->flags, GCF_STATIC)) continue;
+		SlSetArrayIndex(index++);
+		SlObject(c, _grfconfig_desc);
+	}
+}
+
+
+static void Load_NGRF(void)
+{
+	GRFConfig *first = NULL;
+	GRFConfig **last = &first;
+
+	while (SlIterateArray() != -1) {
+		GRFConfig *c = calloc(1, sizeof(*c));
+		SlObject(c, _grfconfig_desc);
+
+		/* Append our configuration to the list */
+		*last = c;
+		last = &c->next;
+	}
+
+	/* Append static NewGRF configuration */
+	CopyGRFConfigList(last, _grfconfig_static);
+
+	ClearGRFConfigList(&_grfconfig);
+	_grfconfig = first;
+	AppendStaticGRFConfigs(&_grfconfig);
+}
+
+const ChunkHandler _newgrf_chunk_handlers[] = {
+	{ 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
+};
+
+
deleted file mode 100644
--- a/src/newgrf_engine.c
+++ /dev/null
@@ -1,1157 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "variables.h"
-#include "debug.h"
-#include "functions.h"
-#include "engine.h"
-#include "train.h"
-#include "player.h"
-#include "station.h"
-#include "airport.h"
-#include "newgrf.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_engine.h"
-#include "newgrf_station.h"
-#include "newgrf_spritegroup.h"
-#include "newgrf_cargo.h"
-#include "date.h"
-
-
-
-/* Default cargo classes */
-static const uint16 _cargo_classes[NUM_GLOBAL_CID] = {
-	CC_PASSENGERS,
-	CC_BULK,
-	CC_MAIL,
-	CC_LIQUID,
-	CC_PIECE_GOODS,
-	CC_EXPRESS,
-	CC_BULK,
-	CC_PIECE_GOODS,
-	CC_BULK,
-	CC_PIECE_GOODS,
-	CC_ARMOURED,
-	CC_PIECE_GOODS,
-	CC_REFRIGERATED | CC_EXPRESS,
-	CC_REFRIGERATED | CC_EXPRESS,
-	CC_BULK,
-	CC_LIQUID,
-	CC_LIQUID,
-	CC_BULK,
-	CC_PIECE_GOODS,
-	CC_PIECE_GOODS,
-	CC_EXPRESS,
-	CC_BULK,
-	CC_LIQUID,
-	CC_BULK,
-	CC_PIECE_GOODS,
-	CC_LIQUID,
-	CC_PIECE_GOODS,
-	CC_PIECE_GOODS,
-	CC_NOAVAILABLE,
-	CC_NOAVAILABLE,
-	CC_NOAVAILABLE,
-};
-
-int _traininfo_vehicle_pitch = 0;
-int _traininfo_vehicle_width = 29;
-
-typedef struct WagonOverride {
-	byte *train_id;
-	int trains;
-	CargoID cargo;
-	const SpriteGroup *group;
-} WagonOverride;
-
-typedef struct WagonOverrides {
-	int overrides_count;
-	WagonOverride *overrides;
-} WagonOverrides;
-
-static WagonOverrides _engine_wagon_overrides[TOTAL_NUM_ENGINES];
-
-void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, byte *train_id, int trains)
-{
-	WagonOverrides *wos;
-	WagonOverride *wo;
-
-	assert(engine < TOTAL_NUM_ENGINES);
-	assert(cargo < NUM_GLOBAL_CID);
-
-	wos = &_engine_wagon_overrides[engine];
-	wos->overrides_count++;
-	wos->overrides = realloc(wos->overrides,
-		wos->overrides_count * sizeof(*wos->overrides));
-
-	wo = &wos->overrides[wos->overrides_count - 1];
-	/* FIXME: If we are replacing an override, release original SpriteGroup
-	 * to prevent leaks. But first we need to refcount the SpriteGroup.
-	 * --pasky */
-	wo->group = group;
-	wo->cargo = cargo;
-	wo->trains = trains;
-	wo->train_id = malloc(trains);
-	memcpy(wo->train_id, train_id, trains);
-}
-
-static const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, byte overriding_engine)
-{
-	const WagonOverrides *wos = &_engine_wagon_overrides[engine];
-	int i;
-
-	// XXX: This could turn out to be a timesink on profiles. We could
-	// always just dedicate 65535 bytes for an [engine][train] trampoline
-	// for O(1). Or O(logMlogN) and searching binary tree or smt. like
-	// that. --pasky
-
-	for (i = 0; i < wos->overrides_count; i++) {
-		const WagonOverride *wo = &wos->overrides[i];
-		int j;
-
-		for (j = 0; j < wo->trains; j++) {
-			if (wo->train_id[j] == overriding_engine && (wo->cargo == cargo || wo->cargo == GC_DEFAULT)) return wo->group;
-		}
-	}
-	return NULL;
-}
-
-/**
- * Unload all wagon override sprite groups.
- */
-void UnloadWagonOverrides(void)
-{
-	WagonOverrides *wos;
-	WagonOverride *wo;
-	EngineID engine;
-	int i;
-
-	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
-		wos = &_engine_wagon_overrides[engine];
-		for (i = 0; i < wos->overrides_count; i++) {
-			wo = &wos->overrides[i];
-			wo->group = NULL;
-			free(wo->train_id);
-		}
-		free(wos->overrides);
-		wos->overrides_count = 0;
-		wos->overrides = NULL;
-	}
-}
-
-// 0 - 28 are cargos, 29 is default, 30 is the advert (purchase list)
-// (It isn't and shouldn't be like this in the GRF files since new cargo types
-// may appear in future - however it's more convenient to store it like this in
-// memory. --pasky)
-static const SpriteGroup *engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID];
-static const GRFFile *_engine_grf[TOTAL_NUM_ENGINES];
-
-void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group)
-{
-	assert(engine < TOTAL_NUM_ENGINES);
-	assert(cargo < NUM_GLOBAL_CID);
-
-	if (engine_custom_sprites[engine][cargo] != NULL) {
-		grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo);
-	}
-	engine_custom_sprites[engine][cargo] = group;
-}
-
-/**
- * Unload all engine sprite groups.
- */
-void UnloadCustomEngineSprites(void)
-{
-	EngineID engine;
-	CargoID cargo;
-
-	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
-		for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
-			engine_custom_sprites[engine][cargo] = NULL;
-		}
-		_engine_grf[engine] = 0;
-	}
-}
-
-static const SpriteGroup *heli_rotor_custom_sprites[NUM_AIRCRAFT_ENGINES];
-
-/** Load a rotor override sprite group for an aircraft */
-void SetRotorOverrideSprites(EngineID engine, const SpriteGroup *group)
-{
-	assert(engine >= AIRCRAFT_ENGINES_INDEX);
-	assert(engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES);
-
-	if (heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] != NULL) {
-		grfmsg(6, "SetRotorOverrideSprites: engine %d already has group -- replacing.", engine);
-	}
-	heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] = group;
-}
-
-/** Unload all rotor override sprite groups */
-void UnloadRotorOverrideSprites(void)
-{
-	EngineID engine;
-
-	/* Starting at AIRCRAFT_ENGINES_INDEX may seem pointless, but it means
-	 * the context of EngineID is correct */
-	for (engine = AIRCRAFT_ENGINES_INDEX; engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; engine++) {
-		heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] = NULL;
-	}
-}
-
-
-/**
- * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters
- * etc during a game.
- * @param engine Engine ID to tie the GRFFile to.
- * @param file   Pointer of GRFFile to tie.
- */
-void SetEngineGRF(EngineID engine, const GRFFile *file)
-{
-	assert(engine < TOTAL_NUM_ENGINES);
-	_engine_grf[engine] = file;
-}
-
-
-/**
- * Retrieve the GRFFile tied to an engine
- * @param engine Engine ID to retrieve.
- * @return Pointer to GRFFile.
- */
-const GRFFile *GetEngineGRF(EngineID engine)
-{
-	assert(engine < TOTAL_NUM_ENGINES);
-	return _engine_grf[engine];
-}
-
-
-/**
- * Retrieve the GRF ID of the GRFFile tied to an engine
- * @param engine Engine ID to retrieve.
- * @return 32 bit GRFID value.
- */
-uint32 GetEngineGRFID(EngineID engine)
-{
-	assert(engine < TOTAL_NUM_ENGINES);
-	return _engine_grf[engine]->grfid;
-}
-
-
-static int MapOldSubType(const Vehicle *v)
-{
-	if (v->type != VEH_Train) return v->subtype;
-	if (IsTrainEngine(v)) return 0;
-	if (IsFreeWagon(v)) return 4;
-	return 2;
-}
-
-
-/* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
-enum {
-	AMS_TTDP_HANGAR,
-	AMS_TTDP_TO_HANGAR,
-	AMS_TTDP_TO_PAD1,
-	AMS_TTDP_TO_PAD2,
-	AMS_TTDP_TO_PAD3,
-	AMS_TTDP_TO_ENTRY_2_AND_3,
-	AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
-	AMS_TTDP_TO_JUNCTION,
-	AMS_TTDP_LEAVE_RUNWAY,
-	AMS_TTDP_TO_INWAY,
-	AMS_TTDP_TO_RUNWAY,
-	AMS_TTDP_TO_OUTWAY,
-	AMS_TTDP_WAITING,
-	AMS_TTDP_TAKEOFF,
-	AMS_TTDP_TO_TAKEOFF,
-	AMS_TTDP_CLIMBING,
-	AMS_TTDP_FLIGHT_APPROACH,
-	AMS_TTDP_UNUSED_0x11,
-	AMS_TTDP_FLIGHT_TO_TOWER,
-	AMS_TTDP_UNUSED_0x13,
-	AMS_TTDP_FLIGHT_FINAL,
-	AMS_TTDP_FLIGHT_DESCENT,
-	AMS_TTDP_BRAKING,
-	AMS_TTDP_HELI_TAKEOFF_AIRPORT,
-	AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
-	AMS_TTDP_HELI_LAND_AIRPORT,
-	AMS_TTDP_HELI_TAKEOFF_HELIPORT,
-	AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
-	AMS_TTDP_HELI_LAND_HELIPORT,
-};
-
-
-/**
- * Map OTTD aircraft movement states to TTDPatch style movement states
- * (VarAction 2 Variable 0xE2)
- */
-static byte MapAircraftMovementState(const Vehicle *v)
-{
-	const Station *st = GetStation(v->u.air.targetairport);
-	byte amdflag = GetAirportMovingData(st->airport_type, v->u.air.pos)->flag;
-
-	switch (v->u.air.state) {
-		case HANGAR:
-			/* The international airport is a special case as helicopters can land in
-			 * front of the hanger. Helicopters also change their air.state to
-			 * AMED_HELI_LOWER some time before actually descending. */
-
-			/* This condition only occurs for helicopters, during descent,
-			 * to a landing by the hanger of an international airport. */
-			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
-
-			/* This condition only occurs for helicopters, before starting descent,
-			 * to a landing by the hanger of an international airport. */
-			if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
-
-			// The final two conditions apply to helicopters or aircraft.
-			/* Has reached hanger? */
-			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR;
-
-			// Still moving towards hanger.
-			return AMS_TTDP_TO_HANGAR;
-
-		case TERM1:
-			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD1;
-			return AMS_TTDP_TO_JUNCTION;
-
-		case TERM2:
-			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD2;
-			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
-
-		case TERM3:
-		case TERM4:
-		case TERM5:
-		case TERM6:
-		case TERM7:
-		case TERM8:
-			/* TTDPatch only has 3 terminals, so treat these states the same */
-			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD3;
-			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
-
-		case HELIPAD1:
-		case HELIPAD2:
-		case HELIPAD3:
-		case HELIPAD4: // Will only occur for helicopters.
-			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
-			if (amdflag & AMED_SLOWTURN)   return AMS_TTDP_FLIGHT_TO_TOWER;   // Still hasn't started descent.
-			return AMS_TTDP_TO_JUNCTION; // On the ground.
-
-		case TAKEOFF: // Moving to takeoff position.
-			return AMS_TTDP_TO_OUTWAY;
-
-		case STARTTAKEOFF: // Accelerating down runway.
-			return AMS_TTDP_TAKEOFF;
-
-		case ENDTAKEOFF: // Ascent
-			return AMS_TTDP_CLIMBING;
-
-		case HELITAKEOFF: // Helicopter is moving to take off position.
-			switch (st->airport_type) {
-				case AT_SMALL:
-				case AT_LARGE:
-				case AT_METROPOLITAN:
-				case AT_INTERNATIONAL:
-				case AT_COMMUTER:
-				case AT_INTERCON:
-				/* Note, Helidepot and Helistation are treated as airports as
-				 * helicopters are taking off from ground level. */
-				case AT_HELIDEPOT:
-				case AT_HELISTATION:
-					if (amdflag & AMED_HELI_RAISE) return AMS_TTDP_HELI_TAKEOFF_AIRPORT;
-					return AMS_TTDP_TO_JUNCTION;
-
-				case AT_HELIPORT:
-				case AT_OILRIG:
-					return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
-
-				default:
-					return AMS_TTDP_HELI_TAKEOFF_AIRPORT;
-			}
-
-		case FLYING:
-			return AMS_TTDP_FLIGHT_TO_TOWER;
-
-		case LANDING: // Descent
-			return AMS_TTDP_FLIGHT_DESCENT;
-
-		case ENDLANDING: // On the runway braking
-			if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING;
-			// Landed - moving off runway
-			return AMS_TTDP_TO_INWAY;
-
-		case HELILANDING:
-		case HELIENDLANDING: // Helicoptor is decending.
-			if (amdflag & AMED_HELI_LOWER) {
-				switch (st->airport_type) {
-					case AT_HELIPORT:
-					case AT_OILRIG:
-						return AMS_TTDP_HELI_LAND_HELIPORT;
-
-					default:
-						/* Note, Helidepot and Helistation are treated as airports as
-						 * helicopters are landing at ground level. */
-						return AMS_TTDP_HELI_LAND_AIRPORT;
-				}
-			}
-			return AMS_TTDP_FLIGHT_TO_TOWER;
-
-		default:
-			return AMS_TTDP_HANGAR;
-	}
-}
-
-
-/* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
-enum {
-	AMA_TTDP_IN_HANGAR,
-	AMA_TTDP_ON_PAD1,
-	AMA_TTDP_ON_PAD2,
-	AMA_TTDP_ON_PAD3,
-	AMA_TTDP_HANGAR_TO_PAD1,
-	AMA_TTDP_HANGAR_TO_PAD2,
-	AMA_TTDP_HANGAR_TO_PAD3,
-	AMA_TTDP_LANDING_TO_PAD1,
-	AMA_TTDP_LANDING_TO_PAD2,
-	AMA_TTDP_LANDING_TO_PAD3,
-	AMA_TTDP_PAD1_TO_HANGAR,
-	AMA_TTDP_PAD2_TO_HANGAR,
-	AMA_TTDP_PAD3_TO_HANGAR,
-	AMA_TTDP_PAD1_TO_TAKEOFF,
-	AMA_TTDP_PAD2_TO_TAKEOFF,
-	AMA_TTDP_PAD3_TO_TAKEOFF,
-	AMA_TTDP_HANGAR_TO_TAKOFF,
-	AMA_TTDP_LANDING_TO_HANGAR,
-	AMA_TTDP_IN_FLIGHT,
-};
-
-
-/**
- * Map OTTD aircraft movement states to TTDPatch style movement actions
- * (VarAction 2 Variable 0xE6)
- * This is not fully supported yet but it's enough for Planeset.
- */
-static byte MapAircraftMovementAction(const Vehicle *v)
-{
-	switch (v->u.air.state) {
-		case HANGAR:
-			return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
-
-		case TERM1:
-		case HELIPAD1:
-			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
-
-		case TERM2:
-		case HELIPAD2:
-			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
-
-		case TERM3:
-		case TERM4:
-		case TERM5:
-		case TERM6:
-		case TERM7:
-		case TERM8:
-		case HELIPAD3:
-		case HELIPAD4:
-			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
-
-		case TAKEOFF:      // Moving to takeoff position
-		case STARTTAKEOFF: // Accelerating down runway
-		case ENDTAKEOFF:   // Ascent
-		case HELITAKEOFF:
-			// TODO Need to find which terminal (or hanger) we've come from. How?
-			return AMA_TTDP_PAD1_TO_TAKEOFF;
-
-		case FLYING:
-			return AMA_TTDP_IN_FLIGHT;
-
-		case LANDING:    // Descent
-		case ENDLANDING: // On the runway braking
-		case HELILANDING:
-		case HELIENDLANDING:
-			// TODO Need to check terminal we're landing to. Is it known yet?
-			return (v->current_order.type == OT_GOTO_DEPOT) ?
-				AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
-
-		default:
-			return AMA_TTDP_IN_HANGAR;
-	}
-}
-
-
-/* TTDP airport types. Used to map our types to TTDPatch's */
-enum {
-	ATP_TTDP_SMALL,
-	ATP_TTDP_LARGE,
-	ATP_TTDP_HELIPORT,
-	ATP_TTDP_OILRIG,
-};
-
-
-/* Vehicle Resolver Functions */
-static inline const Vehicle *GRV(const ResolverObject *object)
-{
-	return object->scope == VSG_SCOPE_SELF ? object->u.vehicle.self : object->u.vehicle.parent;
-}
-
-
-static uint32 VehicleGetRandomBits(const ResolverObject *object)
-{
-	return GRV(object) == NULL ? 0 : GRV(object)->random_bits;
-}
-
-
-static uint32 VehicleGetTriggers(const ResolverObject *object)
-{
-	return GRV(object) == NULL ? 0 : GRV(object)->waiting_triggers;
-}
-
-
-static void VehicleSetTriggers(const ResolverObject *object, int triggers)
-{
-	/* Evil cast to get around const-ness. This used to be achieved by an
-	 * innocent looking function pointer cast... Currently I cannot see a
-	 * way of avoiding this without removing consts deep within gui code.
-	 */
-	Vehicle *v = (Vehicle*)GRV(object);
-
-	/* This function must only be called when processing triggers -- any
-	 * other time is an error. */
-	assert(object->trigger != 0);
-
-	if (v != NULL) v->waiting_triggers = triggers;
-}
-
-
-static uint32 GetVehicleTypeInfo(EngineID engine_type)
-{
-	/* Bit 0  Vehicle type is available on the market
-	 * Bit 1  Vehicle type is in the testing phase
-	 * Bit 2  Exclusive testing offer for a human player active */
-	const Engine *e = GetEngine(engine_type);
-	uint32 var = 0;
-
-	if (e->player_avail == 0xFF) SETBIT(var, 0);
-	if (e->age < e->duration_phase_1) SETBIT(var, 1);
-	if (e->player_avail > 0 && e->player_avail != 0xFF) SETBIT(var, 2);
-	return var;
-}
-
-
-static uint32 GetGRFParameter(EngineID engine_type, byte parameter)
-{
-	const GRFFile *file = GetEngineGRF(engine_type);
-
-	if (parameter >= file->param_end) return 0;
-	return file->param[parameter];
-}
-
-
-static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
-{
-	const Vehicle *v = GRV(object);
-
-	if (v == NULL) {
-		/* Vehicle does not exist, so we're in a purchase list */
-		switch (variable) {
-			case 0x43: return _current_player; /* Owner information */
-			case 0x46: return 0;               /* Motion counter */
-			case 0x48: return GetVehicleTypeInfo(object->u.vehicle.self_type); /* Vehicle Type Info */
-			case 0xC4: return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; /* Build year */
-			case 0xDA: return INVALID_VEHICLE; /* Next vehicle */
-			case 0x7F: return GetGRFParameter(object->u.vehicle.self_type, parameter); /* Read GRF parameter */
-		}
-
-		*available = false;
-		return -1;
-	}
-
-	/* Calculated vehicle parameters */
-	switch (variable) {
-		case 0x40: /* Get length of consist */
-		case 0x41: /* Get length of same consecutive wagons */
-			if (v->type != VEH_Train) return 1;
-
-			{
-				const Vehicle* u;
-				byte chain_before = 0;
-				byte chain_after  = 0;
-
-				for (u = GetFirstVehicleInChain(v); u != v; u = u->next) {
-					chain_before++;
-					if (variable == 0x41 && u->engine_type != v->engine_type) chain_before = 0;
-				}
-
-				while (u->next != NULL && (variable == 0x40 || u->next->engine_type == v->engine_type)) {
-					chain_after++;
-					u = u->next;
-				}
-
-				return chain_before | chain_after << 8 | (chain_before + chain_after + (variable == 0x41)) << 16;
-			}
-
-		case 0x42: { /* Consist cargo information */
-			/* XXX Missing support for common refit cycle and property 25 */
-			const Vehicle *u;
-			byte cargo_classes = 0;
-			uint common_cargo_best = 0;
-			uint common_cargos[NUM_GLOBAL_CID];
-			byte user_def_data = 0;
-			CargoID cargo;
-			CargoID common_cargo_type = GC_PASSENGERS;
-
-			/* Reset our arrays */
-			memset(common_cargos, 0, sizeof(common_cargos));
-
-			for (u = v; u != NULL; u = u->next) {
-				/* Skip empty engines */
-				if (u->cargo_cap == 0) continue;
-				/* Map from climate to global cargo ID */
-				cargo = _global_cargo_id[_opt.landscape][u->cargo_type];
-				cargo_classes |= _cargo_classes[cargo];
-				common_cargos[cargo]++;
-				user_def_data |= RailVehInfo(u->engine_type)->user_def_data;
-			}
-
-			/* Pick the most common cargo type */
-			for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
-				if (common_cargos[cargo] > common_cargo_best) {
-					common_cargo_best = common_cargos[cargo];
-					common_cargo_type = cargo;
-				}
-			}
-
-			return cargo_classes | (common_cargo_type << 8) | (user_def_data << 24);
-		}
-
-		case 0x43: /* Player information */
-			return v->owner;
-
-		case 0x44: /* Aircraft information */
-			if (v->type != VEH_Aircraft) return -1;
-
-			{
-				const Vehicle *w = v->next;
-				uint16 altitude = v->z_pos - w->z_pos; /* Aircraft height - shadow height */
-				byte airporttype;
-
-				switch (GetStation(v->u.air.targetairport)->airport_type) {
-					/* Note, Helidepot and Helistation are treated as small airports
-					 * as they are at ground level. */
-					case AT_HELIDEPOT:
-					case AT_HELISTATION:
-					case AT_COMMUTER:
-					case AT_SMALL:         airporttype = ATP_TTDP_SMALL; break;
-					case AT_METROPOLITAN:
-					case AT_INTERNATIONAL:
-					case AT_INTERCON:
-					case AT_LARGE:         airporttype = ATP_TTDP_LARGE; break;
-					case AT_HELIPORT:      airporttype = ATP_TTDP_HELIPORT; break;
-					case AT_OILRIG:        airporttype = ATP_TTDP_OILRIG; break;
-					default:               airporttype = ATP_TTDP_LARGE; break;
-				}
-
-				return (altitude << 8) | airporttype;
-			}
-
-		case 0x46: /* Motion counter */
-			return v->motion_counter;
-
-		case 0x47: { /* Vehicle cargo info */
-			/* Format: ccccwwtt
-			 * tt - the cargo type transported by the vehicle,
-			 *     translated if a translation table has been installed.
-			 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
-			 * cccc - the cargo class value of the cargo transported by the vehicle.
-			 */
-			CargoID cid = _global_cargo_id[_opt.landscape][v->cargo_type];
-
-			return (_cargo_classes[cid] << 16) | (_cargoc.weights[v->cargo_type] << 8) | cid;
-		}
-
-		case 0x48: return GetVehicleTypeInfo(v->engine_type); /* Vehicle Type Info */
-
-		/* Variables which use the parameter */
-		case 0x60: /* Count consist's engine ID occurance */
-			if (v->type != VEH_Train) return v->engine_type == parameter;
-
-			{
-				uint count = 0;
-				for (; v != NULL; v = v->next) {
-					if (v->engine_type == parameter) count++;
-				}
-				return count;
-			}
-
-		case 0x7F: return GetGRFParameter(v->engine_type, parameter); /* Read GRF parameter */
-	}
-
-	/* General vehicle properties */
-	switch (variable - 0x80) {
-		case 0x00: return v->type;
-		case 0x01: return MapOldSubType(v);
-		case 0x04: return v->index;
-		case 0x05: return GB(v->index, 8, 8);
-		case 0x0A: return PackOrder(&v->current_order);
-		case 0x0B: return GB(PackOrder(&v->current_order), 8, 8);
-		case 0x0C: return v->num_orders;
-		case 0x0D: return v->cur_order_index;
-		case 0x10: return v->load_unload_time_rem;
-		case 0x11: return GB(v->load_unload_time_rem, 8, 8);
-		case 0x12: return max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
-		case 0x13: return GB(max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0), 8, 8);
-		case 0x14: return v->service_interval;
-		case 0x15: return GB(v->service_interval, 8, 8);
-		case 0x16: return v->last_station_visited;
-		case 0x17: return v->tick_counter;
-		case 0x18: return v->max_speed;
-		case 0x19: return GB(v->max_speed, 8, 8);
-		case 0x1A: return v->x_pos;
-		case 0x1B: return GB(v->x_pos, 8, 8);
-		case 0x1C: return v->y_pos;
-		case 0x1D: return GB(v->y_pos, 8, 8);
-		case 0x1E: return v->z_pos;
-		case 0x1F: return object->info_view ? DIR_W : v->direction;
-		case 0x28: return v->cur_image;
-		case 0x29: return GB(v->cur_image, 8, 8);
-		case 0x32: return v->vehstatus;
-		case 0x33: return 0; // non-existent high byte of vehstatus
-		case 0x34: return v->cur_speed;
-		case 0x35: return GB(v->cur_speed, 8, 8);
-		case 0x36: return v->subspeed;
-		case 0x37: return v->acceleration;
-		case 0x39: return v->cargo_type;
-		case 0x3A: return v->cargo_cap;
-		case 0x3B: return GB(v->cargo_cap, 8, 8);
-		case 0x3C: return v->cargo_count;
-		case 0x3D: return GB(v->cargo_count, 8, 8);
-		case 0x3E: return v->cargo_source;
-		case 0x3F: return v->cargo_days;
-		case 0x40: return v->age;
-		case 0x41: return GB(v->age, 8, 8);
-		case 0x42: return v->max_age;
-		case 0x43: return GB(v->max_age, 8, 8);
-		case 0x44: return clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
-		case 0x45: return v->unitnumber;
-		case 0x46: return v->engine_type;
-		case 0x47: return GB(v->engine_type, 8, 8);
-		case 0x48: return v->spritenum;
-		case 0x49: return v->day_counter;
-		case 0x4A: return v->breakdowns_since_last_service;
-		case 0x4B: return v->breakdown_ctr;
-		case 0x4C: return v->breakdown_delay;
-		case 0x4D: return v->breakdown_chance;
-		case 0x4E: return v->reliability;
-		case 0x4F: return GB(v->reliability, 8, 8);
-		case 0x50: return v->reliability_spd_dec;
-		case 0x51: return GB(v->reliability_spd_dec, 8, 8);
-		case 0x52: return v->profit_this_year;
-		case 0x53: return GB(v->profit_this_year,  8, 24);
-		case 0x54: return GB(v->profit_this_year, 16, 16);
-		case 0x55: return GB(v->profit_this_year, 24,  8);
-		case 0x56: return v->profit_last_year;
-		case 0x57: return GB(v->profit_last_year,  8, 24);
-		case 0x58: return GB(v->profit_last_year, 16, 16);
-		case 0x59: return GB(v->profit_last_year, 24,  8);
-		case 0x5A: return v->next == NULL ? INVALID_VEHICLE : v->next->index;
-		case 0x5C: return v->value;
-		case 0x5D: return GB(v->value,  8, 24);
-		case 0x5E: return GB(v->value, 16, 16);
-		case 0x5F: return GB(v->value, 24,  8);
-		case 0x60: return v->string_id;
-		case 0x61: return GB(v->string_id, 8, 8);
-		case 0x72: return v->cargo_subtype;
-		case 0x7A: return v->random_bits;
-		case 0x7B: return v->waiting_triggers;
-	}
-
-	/* Vehicle specific properties */
-	switch (v->type) {
-		case VEH_Train:
-			switch (variable - 0x80) {
-				case 0x62: return v->u.rail.track;
-				case 0x66: return v->u.rail.railtype;
-				case 0x73: return v->u.rail.cached_veh_length;
-				case 0x74: return v->u.rail.cached_power;
-				case 0x75: return GB(v->u.rail.cached_power,  8, 24);
-				case 0x76: return GB(v->u.rail.cached_power, 16, 16);
-				case 0x77: return GB(v->u.rail.cached_power, 24,  8);
-				case 0x7C: return v->first->index;
-				case 0x7D: return GB(v->first->index, 8, 8);
-				case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
-			}
-			break;
-
-		case VEH_Road:
-			switch (variable - 0x80) {
-				case 0x62: return v->u.road.state;
-				case 0x64: return v->u.road.blocked_ctr;
-				case 0x65: return GB(v->u.road.blocked_ctr, 8, 8);
-				case 0x66: return v->u.road.overtaking;
-				case 0x67: return v->u.road.overtaking_ctr;
-				case 0x68: return v->u.road.crashed_ctr;
-				case 0x69: return GB(v->u.road.crashed_ctr, 8, 8);
-			}
-			break;
-
-		case VEH_Aircraft:
-			switch (variable - 0x80) {
-				case 0x62: return MapAircraftMovementState(v);  // Current movement state
-				case 0x63: return v->u.air.targetairport;       // Airport to which the action refers
-				case 0x66: return MapAircraftMovementAction(v); // Current movement action
-			}
-			break;
-	}
-
-	DEBUG(grf, 1, "Unhandled vehicle property 0x%X, type 0x%X", variable, v->type);
-
-	*available = false;
-	return -1;
-}
-
-
-static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const SpriteGroup *group)
-{
-	const Vehicle *v = object->u.vehicle.self;
-	uint totalsets;
-	uint set;
-	bool in_motion;
-
-	if (v == NULL) return group->g.real.loading[0];
-
-	if (v->type == VEH_Train) {
-		in_motion = GetFirstVehicleInChain(v)->current_order.type != OT_LOADING;
-	} else {
-		in_motion = v->current_order.type != OT_LOADING;
-	}
-
-	totalsets = in_motion ? group->g.real.num_loaded : group->g.real.num_loading;
-
-	if (v->cargo_count == v->cargo_cap || totalsets == 1) {
-		set = totalsets - 1;
-	} else if (v->cargo_count == 0 || totalsets == 2) {
-		set = 0;
-	} else {
-		set = v->cargo_count * (totalsets - 2) / max(1, v->cargo_cap) + 1;
-	}
-
-	return in_motion ? group->g.real.loaded[set] : group->g.real.loading[set];
-}
-
-
-static inline void NewVehicleResolver(ResolverObject *res, EngineID engine_type, const Vehicle *v)
-{
-	res->GetRandomBits = &VehicleGetRandomBits;
-	res->GetTriggers   = &VehicleGetTriggers;
-	res->SetTriggers   = &VehicleSetTriggers;
-	res->GetVariable   = &VehicleGetVariable;
-	res->ResolveReal   = &VehicleResolveReal;
-
-	res->u.vehicle.self   = v;
-	res->u.vehicle.parent = (v != NULL && v->type == VEH_Train) ? GetFirstVehicleInChain(v) : v;
-
-	res->u.vehicle.self_type = engine_type;
-
-	res->info_view = false;
-
-	res->callback        = 0;
-	res->callback_param1 = 0;
-	res->callback_param2 = 0;
-	res->last_value      = 0;
-	res->trigger         = 0;
-	res->reseed          = 0;
-}
-
-
-/** Retrieve the SpriteGroup for the specified vehicle.
- * If the vehicle is not specified, the purchase list group for the engine is
- * chosen. For trains, an additional engine override lookup is performed.
- * @param engine Engine type of the vehicle.
- * @param v      The vehicle itself.
- * @returns      The selected SpriteGroup for the vehicle.
- */
-static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *v)
-{
-	const SpriteGroup *group;
-	CargoID cargo;
-
-	if (v == NULL) {
-		cargo = GC_PURCHASE;
-	} else {
-		cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
-		assert(cargo != GC_INVALID);
-
-		if (v->type == VEH_Train) {
-			group = GetWagonOverrideSpriteSet(engine, cargo, v->u.rail.first_engine);
-
-			if (group != NULL) return group;
-		}
-	}
-
-	group = engine_custom_sprites[engine][cargo];
-	if (group != NULL) return group;
-
-	/* Fall back to the default set if the selected cargo type is not defined */
-	return engine_custom_sprites[engine][GC_DEFAULT];
-}
-
-
-SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewVehicleResolver(&object, engine, v);
-
-	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
-	if (group == NULL || group->type != SGT_RESULT) return 0;
-
-	return group->g.result.sprite + (direction % group->g.result.num_sprites);
-}
-
-
-SpriteID GetRotorOverrideSprite(EngineID engine, const Vehicle *v, bool info_view)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	assert(engine >= AIRCRAFT_ENGINES_INDEX);
-	assert(engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES);
-
-	/* Only valid for helicopters */
-	assert(!(AircraftVehInfo(engine)->subtype & AIR_CTOL));
-
-	NewVehicleResolver(&object, engine, v);
-
-	object.info_view = info_view;
-
-	group = heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX];
-	group = Resolve(group, &object);
-
-	if (group == NULL || group->type != SGT_RESULT) return 0;
-
-	if (v == NULL) return group->g.result.sprite;
-
-	return group->g.result.sprite + (info_view ? 0 : (v->next->next->u.air.state % group->g.result.num_sprites));
-}
-
-
-/**
- * Check if a wagon is currently using a wagon override
- * @param v The wagon to check
- * @return true if it is using an override, false otherwise
- */
-bool UsesWagonOverride(const Vehicle* v)
-{
-	assert(v->type == VEH_Train);
-	return GetWagonOverrideSpriteSet(v->engine_type, _global_cargo_id[_opt.landscape][v->cargo_type], v->u.rail.first_engine) != NULL;
-}
-
-/**
- * Evaluate a newgrf callback for vehicles
- * @param callback The callback to evalute
- * @param param1   First parameter of the callback
- * @param param2   Second parameter of the callback
- * @param engine   Engine type of the vehicle to evaluate the callback for
- * @param vehicle  The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
- * @return The value the callback returned, or CALLBACK_FAILED if it failed
- */
-uint16 GetVehicleCallback(uint16 callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewVehicleResolver(&object, engine, v);
-
-	object.callback        = callback;
-	object.callback_param1 = param1;
-	object.callback_param2 = param2;
-
-	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
-
-	return group->g.callback.result;
-}
-
-/**
- * Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
- * @param callback The callback to evalute
- * @param param1   First parameter of the callback
- * @param param2   Second parameter of the callback
- * @param engine   Engine type of the vehicle to evaluate the callback for
- * @param v        The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
- * @param parent   The vehicle to use for parent scope
- * @return The value the callback returned, or CALLBACK_FAILED if it failed
- */
-uint16 GetVehicleCallbackParent(uint16 callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewVehicleResolver(&object, engine, v);
-
-	object.callback        = callback;
-	object.callback_param1 = param1;
-	object.callback_param2 = param2;
-
-	object.u.vehicle.parent = parent;
-
-	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
-
-	return group->g.callback.result;
-}
-
-static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_random_bits, bool first)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-	byte new_random_bits;
-
-	/* We can't trigger a non-existent vehicle... */
-	assert(v != NULL);
-
-	NewVehicleResolver(&object, v->engine_type, v);
-
-	object.trigger = trigger;
-
-	group = Resolve(GetVehicleSpriteGroup(v->engine_type, v), &object);
-
-	new_random_bits = Random();
-	v->random_bits &= ~object.reseed;
-	v->random_bits |= (first ? new_random_bits : base_random_bits) & object.reseed;
-
-	switch (trigger) {
-		case VEHICLE_TRIGGER_NEW_CARGO:
-			/* All vehicles in chain get ANY_NEW_CARGO trigger now.
-			 * So we call it for the first one and they will recurse. */
-			/* Indexing part of vehicle random bits needs to be
-			 * same for all triggered vehicles in the chain (to get
-			 * all the random-cargo wagons carry the same cargo,
-			 * i.e.), so we give them all the NEW_CARGO triggered
-			 * vehicle's portion of random bits. */
-			assert(first);
-			DoTriggerVehicle(GetFirstVehicleInChain(v), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false);
-			break;
-
-		case VEHICLE_TRIGGER_DEPOT:
-			/* We now trigger the next vehicle in chain recursively.
-			 * The random bits portions may be different for each
-			 * vehicle in chain. */
-			if (v->next != NULL) DoTriggerVehicle(v->next, trigger, 0, true);
-			break;
-
-		case VEHICLE_TRIGGER_EMPTY:
-			/* We now trigger the next vehicle in chain
-			 * recursively.  The random bits portions must be same
-			 * for each vehicle in chain, so we give them all
-			 * first chained vehicle's portion of random bits. */
-			if (v->next != NULL) DoTriggerVehicle(v->next, trigger, first ? new_random_bits : base_random_bits, false);
-			break;
-
-		case VEHICLE_TRIGGER_ANY_NEW_CARGO:
-			/* Now pass the trigger recursively to the next vehicle
-			 * in chain. */
-			assert(!first);
-			if (v->next != NULL) DoTriggerVehicle(v->next, VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false);
-			break;
-	}
-}
-
-void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
-{
-	if (trigger == VEHICLE_TRIGGER_DEPOT) {
-		// store that the vehicle entered a depot this tick
-		VehicleEnteredDepotThisTick(v);
-	}
-
-	DoTriggerVehicle(v, trigger, 0, true);
-}
-
-StringID _engine_custom_names[TOTAL_NUM_ENGINES];
-
-void SetCustomEngineName(EngineID engine, StringID name)
-{
-	assert(engine < lengthof(_engine_custom_names));
-	_engine_custom_names[engine] = name;
-}
-
-void UnloadCustomEngineNames(void)
-{
-	EngineID i;
-	for (i = 0; i < TOTAL_NUM_ENGINES; i++) {
-		_engine_custom_names[i] = 0;
-	}
-}
-
-StringID GetCustomEngineName(EngineID engine)
-{
-	return _engine_custom_names[engine] == 0 ? _engine_name_strings[engine] : _engine_custom_names[engine];
-}
-
-// Functions for changing the order of vehicle purchase lists
-// This is currently only implemented for rail vehicles.
-static EngineID _engine_list_order[NUM_TRAIN_ENGINES];
-static byte _engine_list_position[NUM_TRAIN_ENGINES];
-
-void ResetEngineListOrder(void)
-{
-	EngineID i;
-
-	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
-		_engine_list_order[i] = i;
-		_engine_list_position[i] = i;
-	}
-}
-
-/**
- * Get the EngineID at position pos.
- * Used when drawing a(n unsorted) list of engines.
- * @param pos List position/
- * @return The EngineID at the requested position.
- */
-EngineID GetRailVehAtPosition(EngineID pos)
-{
-	if (pos < NUM_TRAIN_ENGINES) return _engine_list_order[pos];
-	return pos;
-}
-
-/**
- * Get the list position of an engine.
- * Used when sorting a list of engines.
- * @param engine ID of the engine.
- * @return The list position of the engine.
- */
-uint16 ListPositionOfEngine(EngineID engine)
-{
-	if (engine < NUM_TRAIN_ENGINES) return _engine_list_position[engine];
-	return engine;
-}
-
-void AlterRailVehListOrder(EngineID engine, EngineID target)
-{
-	EngineID i;
-	bool moving = false;
-
-	if (engine == target) return;
-
-	// First, remove our ID from the list.
-	for (i = 0; i < NUM_TRAIN_ENGINES - 1; i++) {
-		if (_engine_list_order[i] == engine) moving = true;
-		if (moving) _engine_list_order[i] = _engine_list_order[i + 1];
-	}
-
-	// Now, insert it again, before the target engine.
-	for (i = NUM_TRAIN_ENGINES - 1; i > 0; i--) {
-		_engine_list_order[i] = _engine_list_order[i - 1];
-		if (_engine_list_order[i] == target) {
-			_engine_list_order[i - 1] = engine;
-			break;
-		}
-	}
-
-	// Update the engine list position (a reverse of engine list order)
-	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
-		_engine_list_position[_engine_list_order[i]] = i;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_engine.cpp
@@ -0,0 +1,1157 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "variables.h"
+#include "debug.h"
+#include "functions.h"
+#include "engine.h"
+#include "train.h"
+#include "player.h"
+#include "station.h"
+#include "airport.h"
+#include "newgrf.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_station.h"
+#include "newgrf_spritegroup.h"
+#include "newgrf_cargo.h"
+#include "date.h"
+
+
+
+/* Default cargo classes */
+static const uint16 _cargo_classes[NUM_GLOBAL_CID] = {
+	CC_PASSENGERS,
+	CC_BULK,
+	CC_MAIL,
+	CC_LIQUID,
+	CC_PIECE_GOODS,
+	CC_EXPRESS,
+	CC_BULK,
+	CC_PIECE_GOODS,
+	CC_BULK,
+	CC_PIECE_GOODS,
+	CC_ARMOURED,
+	CC_PIECE_GOODS,
+	CC_REFRIGERATED | CC_EXPRESS,
+	CC_REFRIGERATED | CC_EXPRESS,
+	CC_BULK,
+	CC_LIQUID,
+	CC_LIQUID,
+	CC_BULK,
+	CC_PIECE_GOODS,
+	CC_PIECE_GOODS,
+	CC_EXPRESS,
+	CC_BULK,
+	CC_LIQUID,
+	CC_BULK,
+	CC_PIECE_GOODS,
+	CC_LIQUID,
+	CC_PIECE_GOODS,
+	CC_PIECE_GOODS,
+	CC_NOAVAILABLE,
+	CC_NOAVAILABLE,
+	CC_NOAVAILABLE,
+};
+
+int _traininfo_vehicle_pitch = 0;
+int _traininfo_vehicle_width = 29;
+
+typedef struct WagonOverride {
+	byte *train_id;
+	int trains;
+	CargoID cargo;
+	const SpriteGroup *group;
+} WagonOverride;
+
+typedef struct WagonOverrides {
+	int overrides_count;
+	WagonOverride *overrides;
+} WagonOverrides;
+
+static WagonOverrides _engine_wagon_overrides[TOTAL_NUM_ENGINES];
+
+void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, byte *train_id, int trains)
+{
+	WagonOverrides *wos;
+	WagonOverride *wo;
+
+	assert(engine < TOTAL_NUM_ENGINES);
+	assert(cargo < NUM_GLOBAL_CID);
+
+	wos = &_engine_wagon_overrides[engine];
+	wos->overrides_count++;
+	wos->overrides = realloc(wos->overrides,
+		wos->overrides_count * sizeof(*wos->overrides));
+
+	wo = &wos->overrides[wos->overrides_count - 1];
+	/* FIXME: If we are replacing an override, release original SpriteGroup
+	 * to prevent leaks. But first we need to refcount the SpriteGroup.
+	 * --pasky */
+	wo->group = group;
+	wo->cargo = cargo;
+	wo->trains = trains;
+	wo->train_id = malloc(trains);
+	memcpy(wo->train_id, train_id, trains);
+}
+
+static const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, byte overriding_engine)
+{
+	const WagonOverrides *wos = &_engine_wagon_overrides[engine];
+	int i;
+
+	// XXX: This could turn out to be a timesink on profiles. We could
+	// always just dedicate 65535 bytes for an [engine][train] trampoline
+	// for O(1). Or O(logMlogN) and searching binary tree or smt. like
+	// that. --pasky
+
+	for (i = 0; i < wos->overrides_count; i++) {
+		const WagonOverride *wo = &wos->overrides[i];
+		int j;
+
+		for (j = 0; j < wo->trains; j++) {
+			if (wo->train_id[j] == overriding_engine && (wo->cargo == cargo || wo->cargo == GC_DEFAULT)) return wo->group;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Unload all wagon override sprite groups.
+ */
+void UnloadWagonOverrides(void)
+{
+	WagonOverrides *wos;
+	WagonOverride *wo;
+	EngineID engine;
+	int i;
+
+	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
+		wos = &_engine_wagon_overrides[engine];
+		for (i = 0; i < wos->overrides_count; i++) {
+			wo = &wos->overrides[i];
+			wo->group = NULL;
+			free(wo->train_id);
+		}
+		free(wos->overrides);
+		wos->overrides_count = 0;
+		wos->overrides = NULL;
+	}
+}
+
+// 0 - 28 are cargos, 29 is default, 30 is the advert (purchase list)
+// (It isn't and shouldn't be like this in the GRF files since new cargo types
+// may appear in future - however it's more convenient to store it like this in
+// memory. --pasky)
+static const SpriteGroup *engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID];
+static const GRFFile *_engine_grf[TOTAL_NUM_ENGINES];
+
+void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group)
+{
+	assert(engine < TOTAL_NUM_ENGINES);
+	assert(cargo < NUM_GLOBAL_CID);
+
+	if (engine_custom_sprites[engine][cargo] != NULL) {
+		grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo);
+	}
+	engine_custom_sprites[engine][cargo] = group;
+}
+
+/**
+ * Unload all engine sprite groups.
+ */
+void UnloadCustomEngineSprites(void)
+{
+	EngineID engine;
+	CargoID cargo;
+
+	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
+		for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
+			engine_custom_sprites[engine][cargo] = NULL;
+		}
+		_engine_grf[engine] = 0;
+	}
+}
+
+static const SpriteGroup *heli_rotor_custom_sprites[NUM_AIRCRAFT_ENGINES];
+
+/** Load a rotor override sprite group for an aircraft */
+void SetRotorOverrideSprites(EngineID engine, const SpriteGroup *group)
+{
+	assert(engine >= AIRCRAFT_ENGINES_INDEX);
+	assert(engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES);
+
+	if (heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] != NULL) {
+		grfmsg(6, "SetRotorOverrideSprites: engine %d already has group -- replacing.", engine);
+	}
+	heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] = group;
+}
+
+/** Unload all rotor override sprite groups */
+void UnloadRotorOverrideSprites(void)
+{
+	EngineID engine;
+
+	/* Starting at AIRCRAFT_ENGINES_INDEX may seem pointless, but it means
+	 * the context of EngineID is correct */
+	for (engine = AIRCRAFT_ENGINES_INDEX; engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; engine++) {
+		heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX] = NULL;
+	}
+}
+
+
+/**
+ * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters
+ * etc during a game.
+ * @param engine Engine ID to tie the GRFFile to.
+ * @param file   Pointer of GRFFile to tie.
+ */
+void SetEngineGRF(EngineID engine, const GRFFile *file)
+{
+	assert(engine < TOTAL_NUM_ENGINES);
+	_engine_grf[engine] = file;
+}
+
+
+/**
+ * Retrieve the GRFFile tied to an engine
+ * @param engine Engine ID to retrieve.
+ * @return Pointer to GRFFile.
+ */
+const GRFFile *GetEngineGRF(EngineID engine)
+{
+	assert(engine < TOTAL_NUM_ENGINES);
+	return _engine_grf[engine];
+}
+
+
+/**
+ * Retrieve the GRF ID of the GRFFile tied to an engine
+ * @param engine Engine ID to retrieve.
+ * @return 32 bit GRFID value.
+ */
+uint32 GetEngineGRFID(EngineID engine)
+{
+	assert(engine < TOTAL_NUM_ENGINES);
+	return _engine_grf[engine]->grfid;
+}
+
+
+static int MapOldSubType(const Vehicle *v)
+{
+	if (v->type != VEH_Train) return v->subtype;
+	if (IsTrainEngine(v)) return 0;
+	if (IsFreeWagon(v)) return 4;
+	return 2;
+}
+
+
+/* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
+enum {
+	AMS_TTDP_HANGAR,
+	AMS_TTDP_TO_HANGAR,
+	AMS_TTDP_TO_PAD1,
+	AMS_TTDP_TO_PAD2,
+	AMS_TTDP_TO_PAD3,
+	AMS_TTDP_TO_ENTRY_2_AND_3,
+	AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
+	AMS_TTDP_TO_JUNCTION,
+	AMS_TTDP_LEAVE_RUNWAY,
+	AMS_TTDP_TO_INWAY,
+	AMS_TTDP_TO_RUNWAY,
+	AMS_TTDP_TO_OUTWAY,
+	AMS_TTDP_WAITING,
+	AMS_TTDP_TAKEOFF,
+	AMS_TTDP_TO_TAKEOFF,
+	AMS_TTDP_CLIMBING,
+	AMS_TTDP_FLIGHT_APPROACH,
+	AMS_TTDP_UNUSED_0x11,
+	AMS_TTDP_FLIGHT_TO_TOWER,
+	AMS_TTDP_UNUSED_0x13,
+	AMS_TTDP_FLIGHT_FINAL,
+	AMS_TTDP_FLIGHT_DESCENT,
+	AMS_TTDP_BRAKING,
+	AMS_TTDP_HELI_TAKEOFF_AIRPORT,
+	AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
+	AMS_TTDP_HELI_LAND_AIRPORT,
+	AMS_TTDP_HELI_TAKEOFF_HELIPORT,
+	AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
+	AMS_TTDP_HELI_LAND_HELIPORT,
+};
+
+
+/**
+ * Map OTTD aircraft movement states to TTDPatch style movement states
+ * (VarAction 2 Variable 0xE2)
+ */
+static byte MapAircraftMovementState(const Vehicle *v)
+{
+	const Station *st = GetStation(v->u.air.targetairport);
+	byte amdflag = GetAirportMovingData(st->airport_type, v->u.air.pos)->flag;
+
+	switch (v->u.air.state) {
+		case HANGAR:
+			/* The international airport is a special case as helicopters can land in
+			 * front of the hanger. Helicopters also change their air.state to
+			 * AMED_HELI_LOWER some time before actually descending. */
+
+			/* This condition only occurs for helicopters, during descent,
+			 * to a landing by the hanger of an international airport. */
+			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT;
+
+			/* This condition only occurs for helicopters, before starting descent,
+			 * to a landing by the hanger of an international airport. */
+			if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER;
+
+			// The final two conditions apply to helicopters or aircraft.
+			/* Has reached hanger? */
+			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR;
+
+			// Still moving towards hanger.
+			return AMS_TTDP_TO_HANGAR;
+
+		case TERM1:
+			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD1;
+			return AMS_TTDP_TO_JUNCTION;
+
+		case TERM2:
+			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD2;
+			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
+
+		case TERM3:
+		case TERM4:
+		case TERM5:
+		case TERM6:
+		case TERM7:
+		case TERM8:
+			/* TTDPatch only has 3 terminals, so treat these states the same */
+			if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD3;
+			return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
+
+		case HELIPAD1:
+		case HELIPAD2:
+		case HELIPAD3:
+		case HELIPAD4: // Will only occur for helicopters.
+			if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
+			if (amdflag & AMED_SLOWTURN)   return AMS_TTDP_FLIGHT_TO_TOWER;   // Still hasn't started descent.
+			return AMS_TTDP_TO_JUNCTION; // On the ground.
+
+		case TAKEOFF: // Moving to takeoff position.
+			return AMS_TTDP_TO_OUTWAY;
+
+		case STARTTAKEOFF: // Accelerating down runway.
+			return AMS_TTDP_TAKEOFF;
+
+		case ENDTAKEOFF: // Ascent
+			return AMS_TTDP_CLIMBING;
+
+		case HELITAKEOFF: // Helicopter is moving to take off position.
+			switch (st->airport_type) {
+				case AT_SMALL:
+				case AT_LARGE:
+				case AT_METROPOLITAN:
+				case AT_INTERNATIONAL:
+				case AT_COMMUTER:
+				case AT_INTERCON:
+				/* Note, Helidepot and Helistation are treated as airports as
+				 * helicopters are taking off from ground level. */
+				case AT_HELIDEPOT:
+				case AT_HELISTATION:
+					if (amdflag & AMED_HELI_RAISE) return AMS_TTDP_HELI_TAKEOFF_AIRPORT;
+					return AMS_TTDP_TO_JUNCTION;
+
+				case AT_HELIPORT:
+				case AT_OILRIG:
+					return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
+
+				default:
+					return AMS_TTDP_HELI_TAKEOFF_AIRPORT;
+			}
+
+		case FLYING:
+			return AMS_TTDP_FLIGHT_TO_TOWER;
+
+		case LANDING: // Descent
+			return AMS_TTDP_FLIGHT_DESCENT;
+
+		case ENDLANDING: // On the runway braking
+			if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING;
+			// Landed - moving off runway
+			return AMS_TTDP_TO_INWAY;
+
+		case HELILANDING:
+		case HELIENDLANDING: // Helicoptor is decending.
+			if (amdflag & AMED_HELI_LOWER) {
+				switch (st->airport_type) {
+					case AT_HELIPORT:
+					case AT_OILRIG:
+						return AMS_TTDP_HELI_LAND_HELIPORT;
+
+					default:
+						/* Note, Helidepot and Helistation are treated as airports as
+						 * helicopters are landing at ground level. */
+						return AMS_TTDP_HELI_LAND_AIRPORT;
+				}
+			}
+			return AMS_TTDP_FLIGHT_TO_TOWER;
+
+		default:
+			return AMS_TTDP_HANGAR;
+	}
+}
+
+
+/* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
+enum {
+	AMA_TTDP_IN_HANGAR,
+	AMA_TTDP_ON_PAD1,
+	AMA_TTDP_ON_PAD2,
+	AMA_TTDP_ON_PAD3,
+	AMA_TTDP_HANGAR_TO_PAD1,
+	AMA_TTDP_HANGAR_TO_PAD2,
+	AMA_TTDP_HANGAR_TO_PAD3,
+	AMA_TTDP_LANDING_TO_PAD1,
+	AMA_TTDP_LANDING_TO_PAD2,
+	AMA_TTDP_LANDING_TO_PAD3,
+	AMA_TTDP_PAD1_TO_HANGAR,
+	AMA_TTDP_PAD2_TO_HANGAR,
+	AMA_TTDP_PAD3_TO_HANGAR,
+	AMA_TTDP_PAD1_TO_TAKEOFF,
+	AMA_TTDP_PAD2_TO_TAKEOFF,
+	AMA_TTDP_PAD3_TO_TAKEOFF,
+	AMA_TTDP_HANGAR_TO_TAKOFF,
+	AMA_TTDP_LANDING_TO_HANGAR,
+	AMA_TTDP_IN_FLIGHT,
+};
+
+
+/**
+ * Map OTTD aircraft movement states to TTDPatch style movement actions
+ * (VarAction 2 Variable 0xE6)
+ * This is not fully supported yet but it's enough for Planeset.
+ */
+static byte MapAircraftMovementAction(const Vehicle *v)
+{
+	switch (v->u.air.state) {
+		case HANGAR:
+			return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
+
+		case TERM1:
+		case HELIPAD1:
+			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
+
+		case TERM2:
+		case HELIPAD2:
+			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
+
+		case TERM3:
+		case TERM4:
+		case TERM5:
+		case TERM6:
+		case TERM7:
+		case TERM8:
+		case HELIPAD3:
+		case HELIPAD4:
+			return (v->current_order.type == OT_LOADING) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
+
+		case TAKEOFF:      // Moving to takeoff position
+		case STARTTAKEOFF: // Accelerating down runway
+		case ENDTAKEOFF:   // Ascent
+		case HELITAKEOFF:
+			// TODO Need to find which terminal (or hanger) we've come from. How?
+			return AMA_TTDP_PAD1_TO_TAKEOFF;
+
+		case FLYING:
+			return AMA_TTDP_IN_FLIGHT;
+
+		case LANDING:    // Descent
+		case ENDLANDING: // On the runway braking
+		case HELILANDING:
+		case HELIENDLANDING:
+			// TODO Need to check terminal we're landing to. Is it known yet?
+			return (v->current_order.type == OT_GOTO_DEPOT) ?
+				AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
+
+		default:
+			return AMA_TTDP_IN_HANGAR;
+	}
+}
+
+
+/* TTDP airport types. Used to map our types to TTDPatch's */
+enum {
+	ATP_TTDP_SMALL,
+	ATP_TTDP_LARGE,
+	ATP_TTDP_HELIPORT,
+	ATP_TTDP_OILRIG,
+};
+
+
+/* Vehicle Resolver Functions */
+static inline const Vehicle *GRV(const ResolverObject *object)
+{
+	return object->scope == VSG_SCOPE_SELF ? object->u.vehicle.self : object->u.vehicle.parent;
+}
+
+
+static uint32 VehicleGetRandomBits(const ResolverObject *object)
+{
+	return GRV(object) == NULL ? 0 : GRV(object)->random_bits;
+}
+
+
+static uint32 VehicleGetTriggers(const ResolverObject *object)
+{
+	return GRV(object) == NULL ? 0 : GRV(object)->waiting_triggers;
+}
+
+
+static void VehicleSetTriggers(const ResolverObject *object, int triggers)
+{
+	/* Evil cast to get around const-ness. This used to be achieved by an
+	 * innocent looking function pointer cast... Currently I cannot see a
+	 * way of avoiding this without removing consts deep within gui code.
+	 */
+	Vehicle *v = (Vehicle*)GRV(object);
+
+	/* This function must only be called when processing triggers -- any
+	 * other time is an error. */
+	assert(object->trigger != 0);
+
+	if (v != NULL) v->waiting_triggers = triggers;
+}
+
+
+static uint32 GetVehicleTypeInfo(EngineID engine_type)
+{
+	/* Bit 0  Vehicle type is available on the market
+	 * Bit 1  Vehicle type is in the testing phase
+	 * Bit 2  Exclusive testing offer for a human player active */
+	const Engine *e = GetEngine(engine_type);
+	uint32 var = 0;
+
+	if (e->player_avail == 0xFF) SETBIT(var, 0);
+	if (e->age < e->duration_phase_1) SETBIT(var, 1);
+	if (e->player_avail > 0 && e->player_avail != 0xFF) SETBIT(var, 2);
+	return var;
+}
+
+
+static uint32 GetGRFParameter(EngineID engine_type, byte parameter)
+{
+	const GRFFile *file = GetEngineGRF(engine_type);
+
+	if (parameter >= file->param_end) return 0;
+	return file->param[parameter];
+}
+
+
+static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
+{
+	const Vehicle *v = GRV(object);
+
+	if (v == NULL) {
+		/* Vehicle does not exist, so we're in a purchase list */
+		switch (variable) {
+			case 0x43: return _current_player; /* Owner information */
+			case 0x46: return 0;               /* Motion counter */
+			case 0x48: return GetVehicleTypeInfo(object->u.vehicle.self_type); /* Vehicle Type Info */
+			case 0xC4: return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; /* Build year */
+			case 0xDA: return INVALID_VEHICLE; /* Next vehicle */
+			case 0x7F: return GetGRFParameter(object->u.vehicle.self_type, parameter); /* Read GRF parameter */
+		}
+
+		*available = false;
+		return -1;
+	}
+
+	/* Calculated vehicle parameters */
+	switch (variable) {
+		case 0x40: /* Get length of consist */
+		case 0x41: /* Get length of same consecutive wagons */
+			if (v->type != VEH_Train) return 1;
+
+			{
+				const Vehicle* u;
+				byte chain_before = 0;
+				byte chain_after  = 0;
+
+				for (u = GetFirstVehicleInChain(v); u != v; u = u->next) {
+					chain_before++;
+					if (variable == 0x41 && u->engine_type != v->engine_type) chain_before = 0;
+				}
+
+				while (u->next != NULL && (variable == 0x40 || u->next->engine_type == v->engine_type)) {
+					chain_after++;
+					u = u->next;
+				}
+
+				return chain_before | chain_after << 8 | (chain_before + chain_after + (variable == 0x41)) << 16;
+			}
+
+		case 0x42: { /* Consist cargo information */
+			/* XXX Missing support for common refit cycle and property 25 */
+			const Vehicle *u;
+			byte cargo_classes = 0;
+			uint common_cargo_best = 0;
+			uint common_cargos[NUM_GLOBAL_CID];
+			byte user_def_data = 0;
+			CargoID cargo;
+			CargoID common_cargo_type = GC_PASSENGERS;
+
+			/* Reset our arrays */
+			memset(common_cargos, 0, sizeof(common_cargos));
+
+			for (u = v; u != NULL; u = u->next) {
+				/* Skip empty engines */
+				if (u->cargo_cap == 0) continue;
+				/* Map from climate to global cargo ID */
+				cargo = _global_cargo_id[_opt.landscape][u->cargo_type];
+				cargo_classes |= _cargo_classes[cargo];
+				common_cargos[cargo]++;
+				user_def_data |= RailVehInfo(u->engine_type)->user_def_data;
+			}
+
+			/* Pick the most common cargo type */
+			for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
+				if (common_cargos[cargo] > common_cargo_best) {
+					common_cargo_best = common_cargos[cargo];
+					common_cargo_type = cargo;
+				}
+			}
+
+			return cargo_classes | (common_cargo_type << 8) | (user_def_data << 24);
+		}
+
+		case 0x43: /* Player information */
+			return v->owner;
+
+		case 0x44: /* Aircraft information */
+			if (v->type != VEH_Aircraft) return -1;
+
+			{
+				const Vehicle *w = v->next;
+				uint16 altitude = v->z_pos - w->z_pos; /* Aircraft height - shadow height */
+				byte airporttype;
+
+				switch (GetStation(v->u.air.targetairport)->airport_type) {
+					/* Note, Helidepot and Helistation are treated as small airports
+					 * as they are at ground level. */
+					case AT_HELIDEPOT:
+					case AT_HELISTATION:
+					case AT_COMMUTER:
+					case AT_SMALL:         airporttype = ATP_TTDP_SMALL; break;
+					case AT_METROPOLITAN:
+					case AT_INTERNATIONAL:
+					case AT_INTERCON:
+					case AT_LARGE:         airporttype = ATP_TTDP_LARGE; break;
+					case AT_HELIPORT:      airporttype = ATP_TTDP_HELIPORT; break;
+					case AT_OILRIG:        airporttype = ATP_TTDP_OILRIG; break;
+					default:               airporttype = ATP_TTDP_LARGE; break;
+				}
+
+				return (altitude << 8) | airporttype;
+			}
+
+		case 0x46: /* Motion counter */
+			return v->motion_counter;
+
+		case 0x47: { /* Vehicle cargo info */
+			/* Format: ccccwwtt
+			 * tt - the cargo type transported by the vehicle,
+			 *     translated if a translation table has been installed.
+			 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
+			 * cccc - the cargo class value of the cargo transported by the vehicle.
+			 */
+			CargoID cid = _global_cargo_id[_opt.landscape][v->cargo_type];
+
+			return (_cargo_classes[cid] << 16) | (_cargoc.weights[v->cargo_type] << 8) | cid;
+		}
+
+		case 0x48: return GetVehicleTypeInfo(v->engine_type); /* Vehicle Type Info */
+
+		/* Variables which use the parameter */
+		case 0x60: /* Count consist's engine ID occurance */
+			if (v->type != VEH_Train) return v->engine_type == parameter;
+
+			{
+				uint count = 0;
+				for (; v != NULL; v = v->next) {
+					if (v->engine_type == parameter) count++;
+				}
+				return count;
+			}
+
+		case 0x7F: return GetGRFParameter(v->engine_type, parameter); /* Read GRF parameter */
+	}
+
+	/* General vehicle properties */
+	switch (variable - 0x80) {
+		case 0x00: return v->type;
+		case 0x01: return MapOldSubType(v);
+		case 0x04: return v->index;
+		case 0x05: return GB(v->index, 8, 8);
+		case 0x0A: return PackOrder(&v->current_order);
+		case 0x0B: return GB(PackOrder(&v->current_order), 8, 8);
+		case 0x0C: return v->num_orders;
+		case 0x0D: return v->cur_order_index;
+		case 0x10: return v->load_unload_time_rem;
+		case 0x11: return GB(v->load_unload_time_rem, 8, 8);
+		case 0x12: return max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
+		case 0x13: return GB(max(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0), 8, 8);
+		case 0x14: return v->service_interval;
+		case 0x15: return GB(v->service_interval, 8, 8);
+		case 0x16: return v->last_station_visited;
+		case 0x17: return v->tick_counter;
+		case 0x18: return v->max_speed;
+		case 0x19: return GB(v->max_speed, 8, 8);
+		case 0x1A: return v->x_pos;
+		case 0x1B: return GB(v->x_pos, 8, 8);
+		case 0x1C: return v->y_pos;
+		case 0x1D: return GB(v->y_pos, 8, 8);
+		case 0x1E: return v->z_pos;
+		case 0x1F: return object->info_view ? DIR_W : v->direction;
+		case 0x28: return v->cur_image;
+		case 0x29: return GB(v->cur_image, 8, 8);
+		case 0x32: return v->vehstatus;
+		case 0x33: return 0; // non-existent high byte of vehstatus
+		case 0x34: return v->cur_speed;
+		case 0x35: return GB(v->cur_speed, 8, 8);
+		case 0x36: return v->subspeed;
+		case 0x37: return v->acceleration;
+		case 0x39: return v->cargo_type;
+		case 0x3A: return v->cargo_cap;
+		case 0x3B: return GB(v->cargo_cap, 8, 8);
+		case 0x3C: return v->cargo_count;
+		case 0x3D: return GB(v->cargo_count, 8, 8);
+		case 0x3E: return v->cargo_source;
+		case 0x3F: return v->cargo_days;
+		case 0x40: return v->age;
+		case 0x41: return GB(v->age, 8, 8);
+		case 0x42: return v->max_age;
+		case 0x43: return GB(v->max_age, 8, 8);
+		case 0x44: return clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
+		case 0x45: return v->unitnumber;
+		case 0x46: return v->engine_type;
+		case 0x47: return GB(v->engine_type, 8, 8);
+		case 0x48: return v->spritenum;
+		case 0x49: return v->day_counter;
+		case 0x4A: return v->breakdowns_since_last_service;
+		case 0x4B: return v->breakdown_ctr;
+		case 0x4C: return v->breakdown_delay;
+		case 0x4D: return v->breakdown_chance;
+		case 0x4E: return v->reliability;
+		case 0x4F: return GB(v->reliability, 8, 8);
+		case 0x50: return v->reliability_spd_dec;
+		case 0x51: return GB(v->reliability_spd_dec, 8, 8);
+		case 0x52: return v->profit_this_year;
+		case 0x53: return GB(v->profit_this_year,  8, 24);
+		case 0x54: return GB(v->profit_this_year, 16, 16);
+		case 0x55: return GB(v->profit_this_year, 24,  8);
+		case 0x56: return v->profit_last_year;
+		case 0x57: return GB(v->profit_last_year,  8, 24);
+		case 0x58: return GB(v->profit_last_year, 16, 16);
+		case 0x59: return GB(v->profit_last_year, 24,  8);
+		case 0x5A: return v->next == NULL ? INVALID_VEHICLE : v->next->index;
+		case 0x5C: return v->value;
+		case 0x5D: return GB(v->value,  8, 24);
+		case 0x5E: return GB(v->value, 16, 16);
+		case 0x5F: return GB(v->value, 24,  8);
+		case 0x60: return v->string_id;
+		case 0x61: return GB(v->string_id, 8, 8);
+		case 0x72: return v->cargo_subtype;
+		case 0x7A: return v->random_bits;
+		case 0x7B: return v->waiting_triggers;
+	}
+
+	/* Vehicle specific properties */
+	switch (v->type) {
+		case VEH_Train:
+			switch (variable - 0x80) {
+				case 0x62: return v->u.rail.track;
+				case 0x66: return v->u.rail.railtype;
+				case 0x73: return v->u.rail.cached_veh_length;
+				case 0x74: return v->u.rail.cached_power;
+				case 0x75: return GB(v->u.rail.cached_power,  8, 24);
+				case 0x76: return GB(v->u.rail.cached_power, 16, 16);
+				case 0x77: return GB(v->u.rail.cached_power, 24,  8);
+				case 0x7C: return v->first->index;
+				case 0x7D: return GB(v->first->index, 8, 8);
+				case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
+			}
+			break;
+
+		case VEH_Road:
+			switch (variable - 0x80) {
+				case 0x62: return v->u.road.state;
+				case 0x64: return v->u.road.blocked_ctr;
+				case 0x65: return GB(v->u.road.blocked_ctr, 8, 8);
+				case 0x66: return v->u.road.overtaking;
+				case 0x67: return v->u.road.overtaking_ctr;
+				case 0x68: return v->u.road.crashed_ctr;
+				case 0x69: return GB(v->u.road.crashed_ctr, 8, 8);
+			}
+			break;
+
+		case VEH_Aircraft:
+			switch (variable - 0x80) {
+				case 0x62: return MapAircraftMovementState(v);  // Current movement state
+				case 0x63: return v->u.air.targetairport;       // Airport to which the action refers
+				case 0x66: return MapAircraftMovementAction(v); // Current movement action
+			}
+			break;
+	}
+
+	DEBUG(grf, 1, "Unhandled vehicle property 0x%X, type 0x%X", variable, v->type);
+
+	*available = false;
+	return -1;
+}
+
+
+static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const SpriteGroup *group)
+{
+	const Vehicle *v = object->u.vehicle.self;
+	uint totalsets;
+	uint set;
+	bool in_motion;
+
+	if (v == NULL) return group->g.real.loading[0];
+
+	if (v->type == VEH_Train) {
+		in_motion = GetFirstVehicleInChain(v)->current_order.type != OT_LOADING;
+	} else {
+		in_motion = v->current_order.type != OT_LOADING;
+	}
+
+	totalsets = in_motion ? group->g.real.num_loaded : group->g.real.num_loading;
+
+	if (v->cargo_count == v->cargo_cap || totalsets == 1) {
+		set = totalsets - 1;
+	} else if (v->cargo_count == 0 || totalsets == 2) {
+		set = 0;
+	} else {
+		set = v->cargo_count * (totalsets - 2) / max(1, v->cargo_cap) + 1;
+	}
+
+	return in_motion ? group->g.real.loaded[set] : group->g.real.loading[set];
+}
+
+
+static inline void NewVehicleResolver(ResolverObject *res, EngineID engine_type, const Vehicle *v)
+{
+	res->GetRandomBits = &VehicleGetRandomBits;
+	res->GetTriggers   = &VehicleGetTriggers;
+	res->SetTriggers   = &VehicleSetTriggers;
+	res->GetVariable   = &VehicleGetVariable;
+	res->ResolveReal   = &VehicleResolveReal;
+
+	res->u.vehicle.self   = v;
+	res->u.vehicle.parent = (v != NULL && v->type == VEH_Train) ? GetFirstVehicleInChain(v) : v;
+
+	res->u.vehicle.self_type = engine_type;
+
+	res->info_view = false;
+
+	res->callback        = 0;
+	res->callback_param1 = 0;
+	res->callback_param2 = 0;
+	res->last_value      = 0;
+	res->trigger         = 0;
+	res->reseed          = 0;
+}
+
+
+/** Retrieve the SpriteGroup for the specified vehicle.
+ * If the vehicle is not specified, the purchase list group for the engine is
+ * chosen. For trains, an additional engine override lookup is performed.
+ * @param engine Engine type of the vehicle.
+ * @param v      The vehicle itself.
+ * @returns      The selected SpriteGroup for the vehicle.
+ */
+static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *v)
+{
+	const SpriteGroup *group;
+	CargoID cargo;
+
+	if (v == NULL) {
+		cargo = GC_PURCHASE;
+	} else {
+		cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
+		assert(cargo != GC_INVALID);
+
+		if (v->type == VEH_Train) {
+			group = GetWagonOverrideSpriteSet(engine, cargo, v->u.rail.first_engine);
+
+			if (group != NULL) return group;
+		}
+	}
+
+	group = engine_custom_sprites[engine][cargo];
+	if (group != NULL) return group;
+
+	/* Fall back to the default set if the selected cargo type is not defined */
+	return engine_custom_sprites[engine][GC_DEFAULT];
+}
+
+
+SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewVehicleResolver(&object, engine, v);
+
+	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
+	if (group == NULL || group->type != SGT_RESULT) return 0;
+
+	return group->g.result.sprite + (direction % group->g.result.num_sprites);
+}
+
+
+SpriteID GetRotorOverrideSprite(EngineID engine, const Vehicle *v, bool info_view)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	assert(engine >= AIRCRAFT_ENGINES_INDEX);
+	assert(engine < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES);
+
+	/* Only valid for helicopters */
+	assert(!(AircraftVehInfo(engine)->subtype & AIR_CTOL));
+
+	NewVehicleResolver(&object, engine, v);
+
+	object.info_view = info_view;
+
+	group = heli_rotor_custom_sprites[engine - AIRCRAFT_ENGINES_INDEX];
+	group = Resolve(group, &object);
+
+	if (group == NULL || group->type != SGT_RESULT) return 0;
+
+	if (v == NULL) return group->g.result.sprite;
+
+	return group->g.result.sprite + (info_view ? 0 : (v->next->next->u.air.state % group->g.result.num_sprites));
+}
+
+
+/**
+ * Check if a wagon is currently using a wagon override
+ * @param v The wagon to check
+ * @return true if it is using an override, false otherwise
+ */
+bool UsesWagonOverride(const Vehicle* v)
+{
+	assert(v->type == VEH_Train);
+	return GetWagonOverrideSpriteSet(v->engine_type, _global_cargo_id[_opt.landscape][v->cargo_type], v->u.rail.first_engine) != NULL;
+}
+
+/**
+ * Evaluate a newgrf callback for vehicles
+ * @param callback The callback to evalute
+ * @param param1   First parameter of the callback
+ * @param param2   Second parameter of the callback
+ * @param engine   Engine type of the vehicle to evaluate the callback for
+ * @param vehicle  The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
+ * @return The value the callback returned, or CALLBACK_FAILED if it failed
+ */
+uint16 GetVehicleCallback(uint16 callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewVehicleResolver(&object, engine, v);
+
+	object.callback        = callback;
+	object.callback_param1 = param1;
+	object.callback_param2 = param2;
+
+	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
+	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+
+	return group->g.callback.result;
+}
+
+/**
+ * Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
+ * @param callback The callback to evalute
+ * @param param1   First parameter of the callback
+ * @param param2   Second parameter of the callback
+ * @param engine   Engine type of the vehicle to evaluate the callback for
+ * @param v        The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
+ * @param parent   The vehicle to use for parent scope
+ * @return The value the callback returned, or CALLBACK_FAILED if it failed
+ */
+uint16 GetVehicleCallbackParent(uint16 callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewVehicleResolver(&object, engine, v);
+
+	object.callback        = callback;
+	object.callback_param1 = param1;
+	object.callback_param2 = param2;
+
+	object.u.vehicle.parent = parent;
+
+	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
+	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+
+	return group->g.callback.result;
+}
+
+static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_random_bits, bool first)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+	byte new_random_bits;
+
+	/* We can't trigger a non-existent vehicle... */
+	assert(v != NULL);
+
+	NewVehicleResolver(&object, v->engine_type, v);
+
+	object.trigger = trigger;
+
+	group = Resolve(GetVehicleSpriteGroup(v->engine_type, v), &object);
+
+	new_random_bits = Random();
+	v->random_bits &= ~object.reseed;
+	v->random_bits |= (first ? new_random_bits : base_random_bits) & object.reseed;
+
+	switch (trigger) {
+		case VEHICLE_TRIGGER_NEW_CARGO:
+			/* All vehicles in chain get ANY_NEW_CARGO trigger now.
+			 * So we call it for the first one and they will recurse. */
+			/* Indexing part of vehicle random bits needs to be
+			 * same for all triggered vehicles in the chain (to get
+			 * all the random-cargo wagons carry the same cargo,
+			 * i.e.), so we give them all the NEW_CARGO triggered
+			 * vehicle's portion of random bits. */
+			assert(first);
+			DoTriggerVehicle(GetFirstVehicleInChain(v), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false);
+			break;
+
+		case VEHICLE_TRIGGER_DEPOT:
+			/* We now trigger the next vehicle in chain recursively.
+			 * The random bits portions may be different for each
+			 * vehicle in chain. */
+			if (v->next != NULL) DoTriggerVehicle(v->next, trigger, 0, true);
+			break;
+
+		case VEHICLE_TRIGGER_EMPTY:
+			/* We now trigger the next vehicle in chain
+			 * recursively.  The random bits portions must be same
+			 * for each vehicle in chain, so we give them all
+			 * first chained vehicle's portion of random bits. */
+			if (v->next != NULL) DoTriggerVehicle(v->next, trigger, first ? new_random_bits : base_random_bits, false);
+			break;
+
+		case VEHICLE_TRIGGER_ANY_NEW_CARGO:
+			/* Now pass the trigger recursively to the next vehicle
+			 * in chain. */
+			assert(!first);
+			if (v->next != NULL) DoTriggerVehicle(v->next, VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false);
+			break;
+	}
+}
+
+void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
+{
+	if (trigger == VEHICLE_TRIGGER_DEPOT) {
+		// store that the vehicle entered a depot this tick
+		VehicleEnteredDepotThisTick(v);
+	}
+
+	DoTriggerVehicle(v, trigger, 0, true);
+}
+
+StringID _engine_custom_names[TOTAL_NUM_ENGINES];
+
+void SetCustomEngineName(EngineID engine, StringID name)
+{
+	assert(engine < lengthof(_engine_custom_names));
+	_engine_custom_names[engine] = name;
+}
+
+void UnloadCustomEngineNames(void)
+{
+	EngineID i;
+	for (i = 0; i < TOTAL_NUM_ENGINES; i++) {
+		_engine_custom_names[i] = 0;
+	}
+}
+
+StringID GetCustomEngineName(EngineID engine)
+{
+	return _engine_custom_names[engine] == 0 ? _engine_name_strings[engine] : _engine_custom_names[engine];
+}
+
+// Functions for changing the order of vehicle purchase lists
+// This is currently only implemented for rail vehicles.
+static EngineID _engine_list_order[NUM_TRAIN_ENGINES];
+static byte _engine_list_position[NUM_TRAIN_ENGINES];
+
+void ResetEngineListOrder(void)
+{
+	EngineID i;
+
+	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
+		_engine_list_order[i] = i;
+		_engine_list_position[i] = i;
+	}
+}
+
+/**
+ * Get the EngineID at position pos.
+ * Used when drawing a(n unsorted) list of engines.
+ * @param pos List position/
+ * @return The EngineID at the requested position.
+ */
+EngineID GetRailVehAtPosition(EngineID pos)
+{
+	if (pos < NUM_TRAIN_ENGINES) return _engine_list_order[pos];
+	return pos;
+}
+
+/**
+ * Get the list position of an engine.
+ * Used when sorting a list of engines.
+ * @param engine ID of the engine.
+ * @return The list position of the engine.
+ */
+uint16 ListPositionOfEngine(EngineID engine)
+{
+	if (engine < NUM_TRAIN_ENGINES) return _engine_list_position[engine];
+	return engine;
+}
+
+void AlterRailVehListOrder(EngineID engine, EngineID target)
+{
+	EngineID i;
+	bool moving = false;
+
+	if (engine == target) return;
+
+	// First, remove our ID from the list.
+	for (i = 0; i < NUM_TRAIN_ENGINES - 1; i++) {
+		if (_engine_list_order[i] == engine) moving = true;
+		if (moving) _engine_list_order[i] = _engine_list_order[i + 1];
+	}
+
+	// Now, insert it again, before the target engine.
+	for (i = NUM_TRAIN_ENGINES - 1; i > 0; i--) {
+		_engine_list_order[i] = _engine_list_order[i - 1];
+		if (_engine_list_order[i] == target) {
+			_engine_list_order[i - 1] = engine;
+			break;
+		}
+	}
+
+	// Update the engine list position (a reverse of engine list order)
+	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
+		_engine_list_position[_engine_list_order[i]] = i;
+	}
+}
deleted file mode 100644
--- a/src/newgrf_gui.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "variables.h"
-#include "gfx.h"
-#include "gui.h"
-#include "window.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "newgrf.h"
-#include "newgrf_config.h"
-
-
-/** Parse an integerlist string and set each found value
- * @param p the string to be parsed. Each element in the list is seperated by a
- * comma or a space character
- * @param items pointer to the integerlist-array that will be filled with values
- * @param maxitems the maximum number of elements the integerlist-array has
- * @return returns the number of items found, or -1 on an error */
-static int parse_intlist(const char *p, int *items, int maxitems)
-{
-	int n = 0, v;
-	char *end;
-
-	for (;;) {
-		v = strtol(p, &end, 0);
-		if (p == end || n == maxitems) return -1;
-		p = end;
-		items[n++] = v;
-		if (*p == '\0') break;
-		if (*p != ',' && *p != ' ') return -1;
-		p++;
-	}
-
-	return n;
-}
-
-
-static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint w, bool show_params)
-{
-	char buff[512];
-	char *s;
-	uint i;
-
-	/* Draw filename or not if it is not known (GRF sent over internet) */
-	if (c->filename != NULL) {
-		SetDParamStr(0, c->filename);
-		y += DrawStringMultiLine(x, y, STR_NEWGRF_FILENAME, w);
-	}
-
-	/* Prepare and draw GRF ID */
-	snprintf(buff, lengthof(buff), "%08X", (uint32)BSWAP32(c->grfid));
-	SetDParamStr(0, buff);
-	y += DrawStringMultiLine(x, y, STR_NEWGRF_GRF_ID, w);
-
-	/* Prepare and draw MD5 sum */
-	s = buff;
-	for (i = 0; i < lengthof(c->md5sum); i++) {
-		s += snprintf(s, lastof(buff) - s, "%02X", c->md5sum[i]);
-	}
-	SetDParamStr(0, buff);
-	y += DrawStringMultiLine(x, y, STR_NEWGRF_MD5SUM, w);
-
-	/* Show GRF parameter list */
-	if (show_params) {
-		if (c->num_params > 0) {
-			GRFBuildParamList(buff, c, lastof(buff));
-			SetDParamStr(0, buff);
-		} else {
-			SetDParam(0, STR_01A9_NONE);
-		}
-		y += DrawStringMultiLine(x, y, STR_NEWGRF_PARAMETER, w);
-	}
-
-	/* Show flags */
-	if (HASBIT(c->flags, GCF_NOT_FOUND)) y += DrawStringMultiLine(x, y, STR_NEWGRF_NOT_FOUND, w);
-	if (HASBIT(c->flags, GCF_DISABLED))  y += DrawStringMultiLine(x, y, STR_NEWGRF_DISABLED, w);
-
-	/* Draw GRF info if it exists */
-	if (c->info != NULL && strlen(c->info) != 0) {
-		SetDParamStr(0, c->info);
-		y += DrawStringMultiLine(x, y, STR_02BD, w);
-	} else {
-		y += DrawStringMultiLine(x, y, STR_NEWGRF_NO_INFO, w);
-	}
-}
-
-
-/* Dialogue for adding NewGRF files to the selection */
-typedef struct newgrf_add_d {
-	GRFConfig **list;
-	const GRFConfig *sel;
-} newgrf_add_d;
-
-
-static void NewGRFAddDlgWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const GRFConfig *c;
-			int y;
-			int n = 0;
-
-			/* Count the number of GRFs */
-			for (c = _all_grfs; c != NULL; c = c->next) n++;
-
-			w->vscroll.cap = (w->widget[3].bottom - w->widget[3].top) / 10;
-			SetVScrollCount(w, n);
-
-			SetWindowWidgetDisabledState(w, 6, WP(w, newgrf_add_d).sel == NULL);
-			DrawWindowWidgets(w);
-
-			GfxFillRect(w->widget[3].left + 1, w->widget[3].top + 1, w->widget[3].right, w->widget[3].bottom, 0xD7);
-
-			n = 0;
-			y = w->widget[3].top + 1;
-
-			for (c = _all_grfs; c != NULL; c = c->next) {
-				if (n >= w->vscroll.pos && n < w->vscroll.pos + w->vscroll.cap) {
-					bool h = c == WP(w, newgrf_add_d).sel;
-					const char *text = (c->name != NULL && strlen(c->name) != 0) ? c->name : c->filename;
-
-					/* Draw selection background */
-					if (h) GfxFillRect(3, y, w->width - 15, y + 9, 156);
-					DoDrawStringTruncated(text, 4, y, h ? 0xC : 0x6, w->width - 18);
-					y += 10;
-				}
-				n++;
-			}
-
-			if (WP(w, newgrf_add_d).sel != NULL) {
-				const Widget *wi = &w->widget[5];
-				ShowNewGRFInfo(WP(w, newgrf_add_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, false);
-			}
-			break;
-		}
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3: {
-					// Get row...
-					const GRFConfig *c;
-					uint i = (e->we.click.pt.y - w->widget[3].top) / 10 + w->vscroll.pos;
-
-					for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--);
-					WP(w, newgrf_add_d).sel = c;
-					SetWindowDirty(w);
-					break;
-				}
-
-				case 6: /* Add selection to list */
-					if (WP(w, newgrf_add_d).sel != NULL) {
-						const GRFConfig *src = WP(w, newgrf_add_d).sel;
-						GRFConfig **list, *c;
-
-						/* Find last entry in the list, checking for duplicate grfid on the way */
-						for (list = WP(w, newgrf_add_d).list; *list != NULL; list = &(*list)->next) {
-							if ((*list)->grfid == src->grfid) {
-								ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
-								return;
-							}
-						}
-
-						/* Copy GRF details from scanned list */
-						c = calloc(1, sizeof(*c));
-						*c = *src;
-						c->filename = strdup(src->filename);
-						if (src->name != NULL) c->name = strdup(src->name);
-						if (src->info != NULL) c->info = strdup(src->info);
-						c->next = NULL;
-
-						/* Append GRF config to configuration list */
-						*list = c;
-
-						DeleteWindowByClass(WC_SAVELOAD);
-						InvalidateWindowData(WC_GAME_OPTIONS, 0);
-					}
-					break;
-
-				case 7: /* Rescan list */
-					WP(w, newgrf_add_d).sel = NULL;
-					ScanNewGRFFiles();
-					SetWindowDirty(w);
-					break;
-			}
-			break;
-	}
-}
-
-
-static const Widget _newgrf_add_dlg_widgets[] = {
-{   WWT_CLOSEBOX,    RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION,   RESIZE_RIGHT, 14,  11, 306,   0,  13, STR_NEWGRF_ADD_CAPTION,  STR_018C_WINDOW_TITLE_DRAG_THIS },
-
-/* List of files */
-{      WWT_PANEL,      RESIZE_RB, 14,   0, 294,  14, 221, 0x0,                     STR_NULL },
-{      WWT_INSET,      RESIZE_RB, 14,   2, 292,  16, 219, 0x0,                     STR_NULL },
-{  WWT_SCROLLBAR,     RESIZE_LRB, 14, 295, 306,  14, 221, 0x0,                     STR_NULL },
-
-/* NewGRF file info */
-{      WWT_PANEL,     RESIZE_RTB, 14,   0, 306, 222, 324, 0x0,                     STR_NULL },
-
-{ WWT_PUSHTXTBTN,     RESIZE_RTB, 14,   0, 146, 325, 336, STR_NEWGRF_ADD_FILE,     STR_NEWGRF_ADD_FILE_TIP },
-{ WWT_PUSHTXTBTN,    RESIZE_LRTB, 14, 147, 294, 325, 336, STR_NEWGRF_RESCAN_FILES, STR_NEWGRF_RESCAN_FILES_TIP },
-{  WWT_RESIZEBOX,    RESIZE_LRTB, 14, 295, 306, 325, 336, 0x0,                     STR_RESIZE_BUTTON },
-{   WIDGETS_END },
-};
-
-
-static const WindowDesc _newgrf_add_dlg_desc = {
-	WDP_CENTER, WDP_CENTER, 307, 337,
-	WC_SAVELOAD, 0,
-	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_newgrf_add_dlg_widgets,
-	NewGRFAddDlgWndProc,
-};
-
-
-/* 'NewGRF Settings' dialogue */
-typedef struct newgrf_d {
-	GRFConfig **orig_list; ///< grf list the window is shown with
-	GRFConfig **list;      ///< temporary grf list to which changes are made
-	GRFConfig *sel;        ///< selected grf item
-	bool editable;         ///< is the window editable
-	bool show_params;      ///< are the grf-parameters shown in the info-panel
-	bool execute;          ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated
-} newgrf_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_d));
-
-
-enum ShowNewGRFStateWidgets {
-	SNGRFS_ADD = 3,
-	SNGRFS_REMOVE,
-	SNGRFS_MOVE_UP,
-	SNGRFS_MOVE_DOWN,
-	SNGRFS_FILE_LIST = 7,
-	SNGRFS_NEWGRF_INFO = 9,
-	SNGRFS_SET_PARAMETERS,
-	SNGRFS_APPLY_CHANGES,
-};
-
-
-static void SetupNewGRFState(Window *w)
-{
-	bool disable_all = WP(w, newgrf_d).sel == NULL || !WP(w, newgrf_d).editable;
-
-	SetWindowWidgetDisabledState(w, 3, !WP(w, newgrf_d).editable);
-	SetWindowWidgetsDisabledState(w, disable_all,
-		SNGRFS_REMOVE,
-		SNGRFS_MOVE_UP,
-		SNGRFS_MOVE_DOWN,
-		WIDGET_LIST_END
-	);
-	SetWindowWidgetDisabledState(w, SNGRFS_SET_PARAMETERS, !WP(w, newgrf_d).show_params || disable_all);
-
-	if (!disable_all) {
-		/* All widgets are now enabled, so disable widgets we can't use */
-		if (WP(w, newgrf_d).sel == *WP(w, newgrf_d).list) DisableWindowWidget(w, SNGRFS_MOVE_UP);
-		if (WP(w, newgrf_d).sel->next == NULL) DisableWindowWidget(w, SNGRFS_MOVE_DOWN);
-	}
-}
-
-
-static void SetupNewGRFWindow(Window *w)
-{
-	const GRFConfig *c;
-	int i;
-
-	for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++);
-
-	w->vscroll.cap = (w->widget[SNGRFS_FILE_LIST].bottom - w->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
-	SetVScrollCount(w, i);
-	SetWindowWidgetDisabledState(w, SNGRFS_APPLY_CHANGES, !WP(w, newgrf_d).editable);
-}
-
-
-/** Callback function for the newgrf 'apply changes' confirmation window
- * @param yes_clicked boolean value, true when yes was clicked, false otherwise */
-static void NewGRFConfirmationCallback(Window *w, bool confirmed)
-{
-	if (confirmed) {
-		newgrf_d *nd = &WP(w, newgrf_d);
-
-		CopyGRFConfigList(nd->orig_list, *nd->list);
-		ReloadNewGRFData();
-	}
-}
-
-
-static void NewGRFWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const GRFConfig *c;
-			int i, y;
-
-			SetupNewGRFState(w);
-
-			DrawWindowWidgets(w);
-
-			/* Draw NewGRF list */
-			y = w->widget[SNGRFS_FILE_LIST].top;
-			for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {
-				if (i >= w->vscroll.pos && i < w->vscroll.pos + w->vscroll.cap) {
-					const char *text = (c->name != NULL && strlen(c->name) != 0) ? c->name : c->filename;
-					PalSpriteID pal;
-
-					/* Pick a colour */
-					if (HASBIT(c->flags, GCF_NOT_FOUND) || HASBIT(c->flags, GCF_DISABLED)) {
-						pal = PALETTE_TO_RED;
-					} else if (HASBIT(c->flags, GCF_STATIC)) {
-						pal = PALETTE_TO_YELLOW;
-					} else if (HASBIT(c->flags, GCF_ACTIVATED)) {
-						pal = PALETTE_TO_GREEN;
-					} else {
-						pal = PALETTE_TO_BLUE;
-					}
-
-					DrawSprite(SPRITE_PALETTE(SPR_SQUARE | pal), 5, y + 2);
-					DoDrawString(text, 25, y + 3, WP(w, newgrf_d).sel == c ? 0xC : 0x10);
-					y += 14;
-				}
-			}
-
-			if (WP(w, newgrf_d).sel != NULL) {
-				/* Draw NewGRF file info */
-				const Widget *wi = &w->widget[SNGRFS_NEWGRF_INFO];
-				ShowNewGRFInfo(WP(w, newgrf_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, WP(w, newgrf_d).show_params);
-			}
-
-			break;
-		}
-
-		case WE_INVALIDATE_DATA:
-			SetupNewGRFWindow(w);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case SNGRFS_ADD: { /* Add GRF */
-					GRFConfig **list = WP(w, newgrf_d).list;
-					Window *w;
-
-					DeleteWindowByClass(WC_SAVELOAD);
-					w = AllocateWindowDesc(&_newgrf_add_dlg_desc);
-					w->resize.step_height = 10;
-
-					WP(w, newgrf_add_d).list = list;
-					break;
-				}
-
-				case SNGRFS_REMOVE: { /* Remove GRF */
-					GRFConfig **pc, *c, *newsel;
-
-					/* Choose the next GRF file to be the selected file */
-					newsel = WP(w, newgrf_d).sel->next;
-
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						/* If the new selection is empty (i.e. we're deleting the last item
-						 * in the list, pick the file just before the selected file */
-						if (newsel == NULL && c->next == WP(w, newgrf_d).sel) newsel = c;
-
-						if (c == WP(w, newgrf_d).sel) {
-							*pc = c->next;
-							free(c);
-							break;
-						}
-					}
-
-					WP(w, newgrf_d).sel = newsel;
-					SetupNewGRFWindow(w);
-					SetWindowDirty(w);
-					break;
-				}
-
-				case SNGRFS_MOVE_UP: { /* Move GRF up */
-					GRFConfig **pc, *c;
-					if (WP(w, newgrf_d).sel == NULL) break;
-
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						if (c->next == WP(w, newgrf_d).sel) {
-							c->next = WP(w, newgrf_d).sel->next;
-							WP(w, newgrf_d).sel->next = c;
-							*pc = WP(w, newgrf_d).sel;
-							break;
-						}
-					}
-					SetWindowDirty(w);
-					break;
-				}
-
-				case SNGRFS_MOVE_DOWN: { /* Move GRF down */
-					GRFConfig **pc, *c;
-					if (WP(w, newgrf_d).sel == NULL) break;
-
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						if (c == WP(w, newgrf_d).sel) {
-							*pc = c->next;
-							c->next = c->next->next;
-							(*pc)->next = c;
-							break;
-						}
-					}
-					SetWindowDirty(w);
-					break;
-				}
-
-				case SNGRFS_FILE_LIST: { /* Select a GRF */
-					GRFConfig *c;
-					uint i = (e->we.click.pt.y - w->widget[SNGRFS_FILE_LIST].top) / 14 + w->vscroll.pos;
-
-					for (c = *WP(w, newgrf_d).list; c != NULL && i > 0; c = c->next, i--);
-					WP(w, newgrf_d).sel = c;
-
-					SetWindowDirty(w);
-					break;
-				}
-
-				case SNGRFS_APPLY_CHANGES: /* Apply changes made to GRF list */
-					if (WP(w, newgrf_d).execute) {
-						ShowQuery(
-							STR_POPUP_CAUTION_CAPTION,
-							STR_NEWGRF_CONFIRMATION_TEXT,
-							w,
-							NewGRFConfirmationCallback
-						);
-					} else {
-						CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list);
-					}
-					break;
-
-				case SNGRFS_SET_PARAMETERS: { /* Edit parameters */
-					char buff[512];
-					if (WP(w, newgrf_d).sel == NULL) break;
-
-					GRFBuildParamList(buff, WP(w, newgrf_d).sel, lastof(buff));
-					ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, w, CS_ALPHANUMERAL);
-					break;
-				}
-			}
-			break;
-
-		case WE_ON_EDIT_TEXT:
-			if (e->we.edittext.str != NULL) {
-				/* Parse our new "int list" */
-				GRFConfig *c = WP(w, newgrf_d).sel;
-				c->num_params = parse_intlist(e->we.edittext.str, (int*)c->param, lengthof(c->param));
-
-				/* parse_intlist returns -1 on error */
-				if (c->num_params == (byte)-1) c->num_params = 0;
-			}
-			SetWindowDirty(w);
-			break;
-
-		case WE_DESTROY:
-			/* Remove the temporary copy of grf-list used in window */
-			ClearGRFConfigList(WP(w, newgrf_d).list);
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 14;
-			w->widget[SNGRFS_FILE_LIST].data = (w->vscroll.cap << 8) + 1;
-			break;
-	}
-}
-
-
-static const Widget _newgrf_widgets[] = {
-{   WWT_CLOSEBOX,  RESIZE_NONE, 10,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION, RESIZE_RIGHT, 10,  11, 299,   0,  13, STR_NEWGRF_SETTINGS_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS },
-
-/* NewGRF file Add, Remove, Move up, Move down */
-{      WWT_PANEL, RESIZE_RIGHT, 10,   0, 299,  14,  29, STR_NULL,                    STR_NULL },
-{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3,  10,  79,  16,  27, STR_NEWGRF_ADD,              STR_NEWGRF_ADD_TIP },
-{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3,  80, 149,  16,  27, STR_NEWGRF_REMOVE,           STR_NEWGRF_REMOVE_TIP },
-{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3, 150, 219,  16,  27, STR_NEWGRF_MOVEUP,           STR_NEWGRF_MOVEUP_TIP },
-{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3, 220, 289,  16,  27, STR_NEWGRF_MOVEDOWN,         STR_NEWGRF_MOVEDOWN_TIP },
-
-/* NewGRF file list */
-{     WWT_MATRIX,    RESIZE_RB, 10,   0, 287,  30,  99, 0x501,                       STR_NEWGRF_FILE_TIP },
-{  WWT_SCROLLBAR,   RESIZE_LRB, 10, 288, 299,  30,  99, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST },
-
-/* NewGRF file info */
-{      WWT_PANEL,   RESIZE_RTB, 10,   0, 299, 100, 212, STR_NULL,                    STR_NULL },
-
-/* Edit parameter and apply changes button... */
-{ WWT_PUSHTXTBTN,    RESIZE_TB, 10,   0, 143, 213, 224, STR_NEWGRF_SET_PARAMETERS,   STR_NULL },
-{ WWT_PUSHTXTBTN,   RESIZE_RTB, 10, 144, 287, 213, 224, STR_NEWGRF_APPLY_CHANGES,    STR_NULL },
-
-{  WWT_RESIZEBOX,  RESIZE_LRTB, 10, 288, 299, 213, 224, 0x0,                         STR_RESIZE_BUTTON },
-
-{ WIDGETS_END },
-};
-
-
-static const WindowDesc _newgrf_desc = {
-	WDP_CENTER, WDP_CENTER, 300, 225,
-	WC_GAME_OPTIONS, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_newgrf_widgets,
-	NewGRFWndProc,
-};
-
-
-/** Setup the NewGRF gui
- * @param editable allow the user to make changes to the grfconfig in the window
- * @param show_params show information about what parameters are set for the grf files
- * @param exec_changes if changes are made to the list (editable is true), apply these
- *        changes immediately or only update the list
- * @param config pointer to a linked-list of grfconfig's that will be shown */
-void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
-{
-	static GRFConfig *local = NULL;
-	Window *w;
-
-	DeleteWindowByClass(WC_GAME_OPTIONS);
-	w = AllocateWindowDesc(&_newgrf_desc);
-	if (w == NULL) return;
-
-	w->resize.step_height = 14;
-	CopyGRFConfigList(&local, *config);
-
-	/* Clear selections */
-	WP(w, newgrf_d).sel         = NULL;
-	WP(w, newgrf_d).list        = &local;
-	WP(w, newgrf_d).orig_list   = config;
-	WP(w, newgrf_d).editable    = editable;
-	WP(w, newgrf_d).execute     = exec_changes;
-	WP(w, newgrf_d).show_params = show_params;
-
-	SetupNewGRFWindow(w);
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_gui.cpp
@@ -0,0 +1,534 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "variables.h"
+#include "gfx.h"
+#include "gui.h"
+#include "window.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "newgrf.h"
+#include "newgrf_config.h"
+
+
+/** Parse an integerlist string and set each found value
+ * @param p the string to be parsed. Each element in the list is seperated by a
+ * comma or a space character
+ * @param items pointer to the integerlist-array that will be filled with values
+ * @param maxitems the maximum number of elements the integerlist-array has
+ * @return returns the number of items found, or -1 on an error */
+static int parse_intlist(const char *p, int *items, int maxitems)
+{
+	int n = 0, v;
+	char *end;
+
+	for (;;) {
+		v = strtol(p, &end, 0);
+		if (p == end || n == maxitems) return -1;
+		p = end;
+		items[n++] = v;
+		if (*p == '\0') break;
+		if (*p != ',' && *p != ' ') return -1;
+		p++;
+	}
+
+	return n;
+}
+
+
+static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint w, bool show_params)
+{
+	char buff[512];
+	char *s;
+	uint i;
+
+	/* Draw filename or not if it is not known (GRF sent over internet) */
+	if (c->filename != NULL) {
+		SetDParamStr(0, c->filename);
+		y += DrawStringMultiLine(x, y, STR_NEWGRF_FILENAME, w);
+	}
+
+	/* Prepare and draw GRF ID */
+	snprintf(buff, lengthof(buff), "%08X", (uint32)BSWAP32(c->grfid));
+	SetDParamStr(0, buff);
+	y += DrawStringMultiLine(x, y, STR_NEWGRF_GRF_ID, w);
+
+	/* Prepare and draw MD5 sum */
+	s = buff;
+	for (i = 0; i < lengthof(c->md5sum); i++) {
+		s += snprintf(s, lastof(buff) - s, "%02X", c->md5sum[i]);
+	}
+	SetDParamStr(0, buff);
+	y += DrawStringMultiLine(x, y, STR_NEWGRF_MD5SUM, w);
+
+	/* Show GRF parameter list */
+	if (show_params) {
+		if (c->num_params > 0) {
+			GRFBuildParamList(buff, c, lastof(buff));
+			SetDParamStr(0, buff);
+		} else {
+			SetDParam(0, STR_01A9_NONE);
+		}
+		y += DrawStringMultiLine(x, y, STR_NEWGRF_PARAMETER, w);
+	}
+
+	/* Show flags */
+	if (HASBIT(c->flags, GCF_NOT_FOUND)) y += DrawStringMultiLine(x, y, STR_NEWGRF_NOT_FOUND, w);
+	if (HASBIT(c->flags, GCF_DISABLED))  y += DrawStringMultiLine(x, y, STR_NEWGRF_DISABLED, w);
+
+	/* Draw GRF info if it exists */
+	if (c->info != NULL && strlen(c->info) != 0) {
+		SetDParamStr(0, c->info);
+		y += DrawStringMultiLine(x, y, STR_02BD, w);
+	} else {
+		y += DrawStringMultiLine(x, y, STR_NEWGRF_NO_INFO, w);
+	}
+}
+
+
+/* Dialogue for adding NewGRF files to the selection */
+typedef struct newgrf_add_d {
+	GRFConfig **list;
+	const GRFConfig *sel;
+} newgrf_add_d;
+
+
+static void NewGRFAddDlgWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			const GRFConfig *c;
+			int y;
+			int n = 0;
+
+			/* Count the number of GRFs */
+			for (c = _all_grfs; c != NULL; c = c->next) n++;
+
+			w->vscroll.cap = (w->widget[3].bottom - w->widget[3].top) / 10;
+			SetVScrollCount(w, n);
+
+			SetWindowWidgetDisabledState(w, 6, WP(w, newgrf_add_d).sel == NULL);
+			DrawWindowWidgets(w);
+
+			GfxFillRect(w->widget[3].left + 1, w->widget[3].top + 1, w->widget[3].right, w->widget[3].bottom, 0xD7);
+
+			n = 0;
+			y = w->widget[3].top + 1;
+
+			for (c = _all_grfs; c != NULL; c = c->next) {
+				if (n >= w->vscroll.pos && n < w->vscroll.pos + w->vscroll.cap) {
+					bool h = c == WP(w, newgrf_add_d).sel;
+					const char *text = (c->name != NULL && strlen(c->name) != 0) ? c->name : c->filename;
+
+					/* Draw selection background */
+					if (h) GfxFillRect(3, y, w->width - 15, y + 9, 156);
+					DoDrawStringTruncated(text, 4, y, h ? 0xC : 0x6, w->width - 18);
+					y += 10;
+				}
+				n++;
+			}
+
+			if (WP(w, newgrf_add_d).sel != NULL) {
+				const Widget *wi = &w->widget[5];
+				ShowNewGRFInfo(WP(w, newgrf_add_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, false);
+			}
+			break;
+		}
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case 3: {
+					// Get row...
+					const GRFConfig *c;
+					uint i = (e->we.click.pt.y - w->widget[3].top) / 10 + w->vscroll.pos;
+
+					for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--);
+					WP(w, newgrf_add_d).sel = c;
+					SetWindowDirty(w);
+					break;
+				}
+
+				case 6: /* Add selection to list */
+					if (WP(w, newgrf_add_d).sel != NULL) {
+						const GRFConfig *src = WP(w, newgrf_add_d).sel;
+						GRFConfig **list, *c;
+
+						/* Find last entry in the list, checking for duplicate grfid on the way */
+						for (list = WP(w, newgrf_add_d).list; *list != NULL; list = &(*list)->next) {
+							if ((*list)->grfid == src->grfid) {
+								ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
+								return;
+							}
+						}
+
+						/* Copy GRF details from scanned list */
+						c = calloc(1, sizeof(*c));
+						*c = *src;
+						c->filename = strdup(src->filename);
+						if (src->name != NULL) c->name = strdup(src->name);
+						if (src->info != NULL) c->info = strdup(src->info);
+						c->next = NULL;
+
+						/* Append GRF config to configuration list */
+						*list = c;
+
+						DeleteWindowByClass(WC_SAVELOAD);
+						InvalidateWindowData(WC_GAME_OPTIONS, 0);
+					}
+					break;
+
+				case 7: /* Rescan list */
+					WP(w, newgrf_add_d).sel = NULL;
+					ScanNewGRFFiles();
+					SetWindowDirty(w);
+					break;
+			}
+			break;
+	}
+}
+
+
+static const Widget _newgrf_add_dlg_widgets[] = {
+{   WWT_CLOSEBOX,    RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION,   RESIZE_RIGHT, 14,  11, 306,   0,  13, STR_NEWGRF_ADD_CAPTION,  STR_018C_WINDOW_TITLE_DRAG_THIS },
+
+/* List of files */
+{      WWT_PANEL,      RESIZE_RB, 14,   0, 294,  14, 221, 0x0,                     STR_NULL },
+{      WWT_INSET,      RESIZE_RB, 14,   2, 292,  16, 219, 0x0,                     STR_NULL },
+{  WWT_SCROLLBAR,     RESIZE_LRB, 14, 295, 306,  14, 221, 0x0,                     STR_NULL },
+
+/* NewGRF file info */
+{      WWT_PANEL,     RESIZE_RTB, 14,   0, 306, 222, 324, 0x0,                     STR_NULL },
+
+{ WWT_PUSHTXTBTN,     RESIZE_RTB, 14,   0, 146, 325, 336, STR_NEWGRF_ADD_FILE,     STR_NEWGRF_ADD_FILE_TIP },
+{ WWT_PUSHTXTBTN,    RESIZE_LRTB, 14, 147, 294, 325, 336, STR_NEWGRF_RESCAN_FILES, STR_NEWGRF_RESCAN_FILES_TIP },
+{  WWT_RESIZEBOX,    RESIZE_LRTB, 14, 295, 306, 325, 336, 0x0,                     STR_RESIZE_BUTTON },
+{   WIDGETS_END },
+};
+
+
+static const WindowDesc _newgrf_add_dlg_desc = {
+	WDP_CENTER, WDP_CENTER, 307, 337,
+	WC_SAVELOAD, 0,
+	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_newgrf_add_dlg_widgets,
+	NewGRFAddDlgWndProc,
+};
+
+
+/* 'NewGRF Settings' dialogue */
+typedef struct newgrf_d {
+	GRFConfig **orig_list; ///< grf list the window is shown with
+	GRFConfig **list;      ///< temporary grf list to which changes are made
+	GRFConfig *sel;        ///< selected grf item
+	bool editable;         ///< is the window editable
+	bool show_params;      ///< are the grf-parameters shown in the info-panel
+	bool execute;          ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated
+} newgrf_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_d));
+
+
+enum ShowNewGRFStateWidgets {
+	SNGRFS_ADD = 3,
+	SNGRFS_REMOVE,
+	SNGRFS_MOVE_UP,
+	SNGRFS_MOVE_DOWN,
+	SNGRFS_FILE_LIST = 7,
+	SNGRFS_NEWGRF_INFO = 9,
+	SNGRFS_SET_PARAMETERS,
+	SNGRFS_APPLY_CHANGES,
+};
+
+
+static void SetupNewGRFState(Window *w)
+{
+	bool disable_all = WP(w, newgrf_d).sel == NULL || !WP(w, newgrf_d).editable;
+
+	SetWindowWidgetDisabledState(w, 3, !WP(w, newgrf_d).editable);
+	SetWindowWidgetsDisabledState(w, disable_all,
+		SNGRFS_REMOVE,
+		SNGRFS_MOVE_UP,
+		SNGRFS_MOVE_DOWN,
+		WIDGET_LIST_END
+	);
+	SetWindowWidgetDisabledState(w, SNGRFS_SET_PARAMETERS, !WP(w, newgrf_d).show_params || disable_all);
+
+	if (!disable_all) {
+		/* All widgets are now enabled, so disable widgets we can't use */
+		if (WP(w, newgrf_d).sel == *WP(w, newgrf_d).list) DisableWindowWidget(w, SNGRFS_MOVE_UP);
+		if (WP(w, newgrf_d).sel->next == NULL) DisableWindowWidget(w, SNGRFS_MOVE_DOWN);
+	}
+}
+
+
+static void SetupNewGRFWindow(Window *w)
+{
+	const GRFConfig *c;
+	int i;
+
+	for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++);
+
+	w->vscroll.cap = (w->widget[SNGRFS_FILE_LIST].bottom - w->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
+	SetVScrollCount(w, i);
+	SetWindowWidgetDisabledState(w, SNGRFS_APPLY_CHANGES, !WP(w, newgrf_d).editable);
+}
+
+
+/** Callback function for the newgrf 'apply changes' confirmation window
+ * @param yes_clicked boolean value, true when yes was clicked, false otherwise */
+static void NewGRFConfirmationCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		newgrf_d *nd = &WP(w, newgrf_d);
+
+		CopyGRFConfigList(nd->orig_list, *nd->list);
+		ReloadNewGRFData();
+	}
+}
+
+
+static void NewGRFWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			const GRFConfig *c;
+			int i, y;
+
+			SetupNewGRFState(w);
+
+			DrawWindowWidgets(w);
+
+			/* Draw NewGRF list */
+			y = w->widget[SNGRFS_FILE_LIST].top;
+			for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {
+				if (i >= w->vscroll.pos && i < w->vscroll.pos + w->vscroll.cap) {
+					const char *text = (c->name != NULL && strlen(c->name) != 0) ? c->name : c->filename;
+					PalSpriteID pal;
+
+					/* Pick a colour */
+					if (HASBIT(c->flags, GCF_NOT_FOUND) || HASBIT(c->flags, GCF_DISABLED)) {
+						pal = PALETTE_TO_RED;
+					} else if (HASBIT(c->flags, GCF_STATIC)) {
+						pal = PALETTE_TO_YELLOW;
+					} else if (HASBIT(c->flags, GCF_ACTIVATED)) {
+						pal = PALETTE_TO_GREEN;
+					} else {
+						pal = PALETTE_TO_BLUE;
+					}
+
+					DrawSprite(SPRITE_PALETTE(SPR_SQUARE | pal), 5, y + 2);
+					DoDrawString(text, 25, y + 3, WP(w, newgrf_d).sel == c ? 0xC : 0x10);
+					y += 14;
+				}
+			}
+
+			if (WP(w, newgrf_d).sel != NULL) {
+				/* Draw NewGRF file info */
+				const Widget *wi = &w->widget[SNGRFS_NEWGRF_INFO];
+				ShowNewGRFInfo(WP(w, newgrf_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, WP(w, newgrf_d).show_params);
+			}
+
+			break;
+		}
+
+		case WE_INVALIDATE_DATA:
+			SetupNewGRFWindow(w);
+			break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case SNGRFS_ADD: { /* Add GRF */
+					GRFConfig **list = WP(w, newgrf_d).list;
+					Window *w;
+
+					DeleteWindowByClass(WC_SAVELOAD);
+					w = AllocateWindowDesc(&_newgrf_add_dlg_desc);
+					w->resize.step_height = 10;
+
+					WP(w, newgrf_add_d).list = list;
+					break;
+				}
+
+				case SNGRFS_REMOVE: { /* Remove GRF */
+					GRFConfig **pc, *c, *newsel;
+
+					/* Choose the next GRF file to be the selected file */
+					newsel = WP(w, newgrf_d).sel->next;
+
+					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
+						/* If the new selection is empty (i.e. we're deleting the last item
+						 * in the list, pick the file just before the selected file */
+						if (newsel == NULL && c->next == WP(w, newgrf_d).sel) newsel = c;
+
+						if (c == WP(w, newgrf_d).sel) {
+							*pc = c->next;
+							free(c);
+							break;
+						}
+					}
+
+					WP(w, newgrf_d).sel = newsel;
+					SetupNewGRFWindow(w);
+					SetWindowDirty(w);
+					break;
+				}
+
+				case SNGRFS_MOVE_UP: { /* Move GRF up */
+					GRFConfig **pc, *c;
+					if (WP(w, newgrf_d).sel == NULL) break;
+
+					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
+						if (c->next == WP(w, newgrf_d).sel) {
+							c->next = WP(w, newgrf_d).sel->next;
+							WP(w, newgrf_d).sel->next = c;
+							*pc = WP(w, newgrf_d).sel;
+							break;
+						}
+					}
+					SetWindowDirty(w);
+					break;
+				}
+
+				case SNGRFS_MOVE_DOWN: { /* Move GRF down */
+					GRFConfig **pc, *c;
+					if (WP(w, newgrf_d).sel == NULL) break;
+
+					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
+						if (c == WP(w, newgrf_d).sel) {
+							*pc = c->next;
+							c->next = c->next->next;
+							(*pc)->next = c;
+							break;
+						}
+					}
+					SetWindowDirty(w);
+					break;
+				}
+
+				case SNGRFS_FILE_LIST: { /* Select a GRF */
+					GRFConfig *c;
+					uint i = (e->we.click.pt.y - w->widget[SNGRFS_FILE_LIST].top) / 14 + w->vscroll.pos;
+
+					for (c = *WP(w, newgrf_d).list; c != NULL && i > 0; c = c->next, i--);
+					WP(w, newgrf_d).sel = c;
+
+					SetWindowDirty(w);
+					break;
+				}
+
+				case SNGRFS_APPLY_CHANGES: /* Apply changes made to GRF list */
+					if (WP(w, newgrf_d).execute) {
+						ShowQuery(
+							STR_POPUP_CAUTION_CAPTION,
+							STR_NEWGRF_CONFIRMATION_TEXT,
+							w,
+							NewGRFConfirmationCallback
+						);
+					} else {
+						CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list);
+					}
+					break;
+
+				case SNGRFS_SET_PARAMETERS: { /* Edit parameters */
+					char buff[512];
+					if (WP(w, newgrf_d).sel == NULL) break;
+
+					GRFBuildParamList(buff, WP(w, newgrf_d).sel, lastof(buff));
+					ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, w, CS_ALPHANUMERAL);
+					break;
+				}
+			}
+			break;
+
+		case WE_ON_EDIT_TEXT:
+			if (e->we.edittext.str != NULL) {
+				/* Parse our new "int list" */
+				GRFConfig *c = WP(w, newgrf_d).sel;
+				c->num_params = parse_intlist(e->we.edittext.str, (int*)c->param, lengthof(c->param));
+
+				/* parse_intlist returns -1 on error */
+				if (c->num_params == (byte)-1) c->num_params = 0;
+			}
+			SetWindowDirty(w);
+			break;
+
+		case WE_DESTROY:
+			/* Remove the temporary copy of grf-list used in window */
+			ClearGRFConfigList(WP(w, newgrf_d).list);
+			break;
+
+		case WE_RESIZE:
+			w->vscroll.cap += e->we.sizing.diff.y / 14;
+			w->widget[SNGRFS_FILE_LIST].data = (w->vscroll.cap << 8) + 1;
+			break;
+	}
+}
+
+
+static const Widget _newgrf_widgets[] = {
+{   WWT_CLOSEBOX,  RESIZE_NONE, 10,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION, RESIZE_RIGHT, 10,  11, 299,   0,  13, STR_NEWGRF_SETTINGS_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS },
+
+/* NewGRF file Add, Remove, Move up, Move down */
+{      WWT_PANEL, RESIZE_RIGHT, 10,   0, 299,  14,  29, STR_NULL,                    STR_NULL },
+{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3,  10,  79,  16,  27, STR_NEWGRF_ADD,              STR_NEWGRF_ADD_TIP },
+{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3,  80, 149,  16,  27, STR_NEWGRF_REMOVE,           STR_NEWGRF_REMOVE_TIP },
+{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3, 150, 219,  16,  27, STR_NEWGRF_MOVEUP,           STR_NEWGRF_MOVEUP_TIP },
+{ WWT_PUSHTXTBTN,  RESIZE_NONE,  3, 220, 289,  16,  27, STR_NEWGRF_MOVEDOWN,         STR_NEWGRF_MOVEDOWN_TIP },
+
+/* NewGRF file list */
+{     WWT_MATRIX,    RESIZE_RB, 10,   0, 287,  30,  99, 0x501,                       STR_NEWGRF_FILE_TIP },
+{  WWT_SCROLLBAR,   RESIZE_LRB, 10, 288, 299,  30,  99, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST },
+
+/* NewGRF file info */
+{      WWT_PANEL,   RESIZE_RTB, 10,   0, 299, 100, 212, STR_NULL,                    STR_NULL },
+
+/* Edit parameter and apply changes button... */
+{ WWT_PUSHTXTBTN,    RESIZE_TB, 10,   0, 143, 213, 224, STR_NEWGRF_SET_PARAMETERS,   STR_NULL },
+{ WWT_PUSHTXTBTN,   RESIZE_RTB, 10, 144, 287, 213, 224, STR_NEWGRF_APPLY_CHANGES,    STR_NULL },
+
+{  WWT_RESIZEBOX,  RESIZE_LRTB, 10, 288, 299, 213, 224, 0x0,                         STR_RESIZE_BUTTON },
+
+{ WIDGETS_END },
+};
+
+
+static const WindowDesc _newgrf_desc = {
+	WDP_CENTER, WDP_CENTER, 300, 225,
+	WC_GAME_OPTIONS, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_newgrf_widgets,
+	NewGRFWndProc,
+};
+
+
+/** Setup the NewGRF gui
+ * @param editable allow the user to make changes to the grfconfig in the window
+ * @param show_params show information about what parameters are set for the grf files
+ * @param exec_changes if changes are made to the list (editable is true), apply these
+ *        changes immediately or only update the list
+ * @param config pointer to a linked-list of grfconfig's that will be shown */
+void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
+{
+	static GRFConfig *local = NULL;
+	Window *w;
+
+	DeleteWindowByClass(WC_GAME_OPTIONS);
+	w = AllocateWindowDesc(&_newgrf_desc);
+	if (w == NULL) return;
+
+	w->resize.step_height = 14;
+	CopyGRFConfigList(&local, *config);
+
+	/* Clear selections */
+	WP(w, newgrf_d).sel         = NULL;
+	WP(w, newgrf_d).list        = &local;
+	WP(w, newgrf_d).orig_list   = config;
+	WP(w, newgrf_d).editable    = editable;
+	WP(w, newgrf_d).execute     = exec_changes;
+	WP(w, newgrf_d).show_params = show_params;
+
+	SetupNewGRFWindow(w);
+}
deleted file mode 100644
--- a/src/newgrf_sound.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "oldpool.h"
-#include "sound.h"
-#include "engine.h"
-#include "vehicle.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_engine.h"
-#include "newgrf_sound.h"
-
-static uint _sound_count = 0;
-STATIC_OLD_POOL(SoundInternal, FileEntry, 3, 1000, NULL, NULL)
-
-
-/* Allocate a new FileEntry */
-FileEntry *AllocateFileEntry(void)
-{
-	if (_sound_count == GetSoundInternalPoolSize()) {
-		if (!AddBlockToPool(&_SoundInternal_pool)) return NULL;
-	}
-
-	return GetSoundInternal(_sound_count++);
-}
-
-
-void InitializeSoundPool(void)
-{
-	CleanPool(&_SoundInternal_pool);
-	_sound_count = 0;
-
-	/* Copy original sound data to the pool */
-	SndCopyToPool();
-}
-
-
-FileEntry *GetSound(uint index)
-{
-	if (index >= _sound_count) return NULL;
-	return GetSoundInternal(index);
-}
-
-
-uint GetNumSounds(void)
-{
-	return _sound_count;
-}
-
-
-bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
-{
-	const GRFFile *file = GetEngineGRF(v->engine_type);
-	uint16 callback;
-
-	/* If the engine has no GRF ID associated it can't ever play any new sounds */
-	if (file == NULL) return false;
-
-	/* Check that the vehicle type uses the sound effect callback */
-	if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_SOUND_EFFECT)) return false;
-
-	callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
-	if (callback == CALLBACK_FAILED) return false;
-	if (callback >= GetNumOriginalSounds()) callback += file->sound_offset - GetNumOriginalSounds();
-
-	if (callback < GetNumSounds()) SndPlayVehicleFx(callback, v);
-	return true;
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_sound.cpp
@@ -0,0 +1,68 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "oldpool.h"
+#include "sound.h"
+#include "engine.h"
+#include "vehicle.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+
+static uint _sound_count = 0;
+STATIC_OLD_POOL(SoundInternal, FileEntry, 3, 1000, NULL, NULL)
+
+
+/* Allocate a new FileEntry */
+FileEntry *AllocateFileEntry(void)
+{
+	if (_sound_count == GetSoundInternalPoolSize()) {
+		if (!AddBlockToPool(&_SoundInternal_pool)) return NULL;
+	}
+
+	return GetSoundInternal(_sound_count++);
+}
+
+
+void InitializeSoundPool(void)
+{
+	CleanPool(&_SoundInternal_pool);
+	_sound_count = 0;
+
+	/* Copy original sound data to the pool */
+	SndCopyToPool();
+}
+
+
+FileEntry *GetSound(uint index)
+{
+	if (index >= _sound_count) return NULL;
+	return GetSoundInternal(index);
+}
+
+
+uint GetNumSounds(void)
+{
+	return _sound_count;
+}
+
+
+bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
+{
+	const GRFFile *file = GetEngineGRF(v->engine_type);
+	uint16 callback;
+
+	/* If the engine has no GRF ID associated it can't ever play any new sounds */
+	if (file == NULL) return false;
+
+	/* Check that the vehicle type uses the sound effect callback */
+	if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_SOUND_EFFECT)) return false;
+
+	callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
+	if (callback == CALLBACK_FAILED) return false;
+	if (callback >= GetNumOriginalSounds()) callback += file->sound_offset - GetNumOriginalSounds();
+
+	if (callback < GetNumSounds()) SndPlayVehicleFx(callback, v);
+	return true;
+}
deleted file mode 100644
--- a/src/newgrf_spritegroup.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "variables.h"
-#include "macros.h"
-#include "oldpool.h"
-#include "newgrf_spritegroup.h"
-#include "date.h"
-
-static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item);
-
-static uint _spritegroup_count = 0;
-STATIC_OLD_POOL(SpriteGroup, SpriteGroup, 9, 250, NULL, SpriteGroupPoolCleanBlock)
-
-static void DestroySpriteGroup(SpriteGroup *group)
-{
-	/* Free dynamically allocated memory */
-	/* XXX Cast away the consts due to MSVC being buggy... */
-	switch (group->type) {
-		case SGT_REAL:
-			free((SpriteGroup**)group->g.real.loaded);
-			free((SpriteGroup**)group->g.real.loading);
-			break;
-
-		case SGT_DETERMINISTIC:
-			free(group->g.determ.adjusts);
-			free(group->g.determ.ranges);
-			break;
-
-		case SGT_RANDOMIZED:
-			free((SpriteGroup**)group->g.random.groups);
-			break;
-
-		default:
-			break;
-	}
-}
-
-static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item)
-{
-	uint i;
-
-	for (i = start_item; i <= end_item; i++) {
-		DestroySpriteGroup(GetSpriteGroup(i));
-	}
-}
-
-
-/* Allocate a new SpriteGroup */
-SpriteGroup *AllocateSpriteGroup(void)
-{
-	/* This is totally different to the other pool allocators, as we never remove an item from the pool. */
-	if (_spritegroup_count == GetSpriteGroupPoolSize()) {
-		if (!AddBlockToPool(&_SpriteGroup_pool)) return NULL;
-	}
-
-	return GetSpriteGroup(_spritegroup_count++);
-}
-
-
-void InitializeSpriteGroupPool(void)
-{
-	CleanPool(&_SpriteGroup_pool);
-
-	_spritegroup_count = 0;
-}
-
-
-static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
-{
-	/* Return common variables */
-	switch (variable) {
-		case 0x00: return max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
-		case 0x01: return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
-		case 0x02: return _cur_month;
-		case 0x03: return _opt.landscape;
-		case 0x09: return _date_fract;
-		case 0x0A: return _tick_counter;
-		case 0x0C: return object->callback;
-		case 0x10: return object->callback_param1;
-		case 0x11: return 0;
-		case 0x18: return object->callback_param2;
-		case 0x1A: return -1;
-		case 0x1B: return GB(_display_opt, 0, 6);
-		case 0x1C: return object->last_value;
-		case 0x20: return _opt.landscape == LT_HILLY ? _opt.snow_line : 0xFF;
-
-		/* Not a common variable, so evalute the feature specific variables */
-		default: return object->GetVariable(object, variable, parameter, available);
-	}
-}
-
-
-/* Evaluate an adjustment for a variable of the given size. This is a bit of
- * an unwieldy macro, but it saves triplicating the code. */
-#define BUILD_EVAL_ADJUST(size, usize) \
-static inline usize EvalAdjust_ ## size(const DeterministicSpriteGroupAdjust *adjust, usize last_value, int32 value) \
-{ \
-	value >>= adjust->shift_num; \
-	value  &= adjust->and_mask; \
-\
-	if (adjust->type != DSGA_TYPE_NONE) value += (size)adjust->add_val; \
-\
-	switch (adjust->type) { \
-		case DSGA_TYPE_DIV:  value /= (size)adjust->divmod_val; break; \
-		case DSGA_TYPE_MOD:  value %= (usize)adjust->divmod_val; break; \
-		case DSGA_TYPE_NONE: break; \
-	} \
-\
-	/* Get our value to the correct range */ \
-	value = (usize)value; \
-\
-	switch (adjust->operation) { \
-		case DSGA_OP_ADD:  return last_value + value; \
-		case DSGA_OP_SUB:  return last_value - value; \
-		case DSGA_OP_SMIN: return min(last_value, value); \
-		case DSGA_OP_SMAX: return max(last_value, value); \
-		case DSGA_OP_UMIN: return min((usize)last_value, (usize)value); \
-		case DSGA_OP_UMAX: return max((usize)last_value, (usize)value); \
-		case DSGA_OP_SDIV: return last_value / value; \
-		case DSGA_OP_SMOD: return last_value % value; \
-		case DSGA_OP_UDIV: return (usize)last_value / (usize)value; \
-		case DSGA_OP_UMOD: return (usize)last_value % (usize)value; \
-		case DSGA_OP_MUL:  return last_value * value; \
-		case DSGA_OP_AND:  return last_value & value; \
-		case DSGA_OP_OR:   return last_value | value; \
-		case DSGA_OP_XOR:  return last_value ^ value; \
-		default:           return value; \
-	} \
-}
-
-
-BUILD_EVAL_ADJUST(int8, uint8)
-BUILD_EVAL_ADJUST(int16, uint16)
-BUILD_EVAL_ADJUST(int32, uint32)
-
-
-static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, ResolverObject *object)
-{
-	static SpriteGroup nvarzero;
-	int32 last_value = object->last_value;
-	int32 value = -1;
-	uint i;
-
-	object->scope = group->g.determ.var_scope;
-
-	for (i = 0; i < group->g.determ.num_adjusts; i++) {
-		DeterministicSpriteGroupAdjust *adjust = &group->g.determ.adjusts[i];
-
-		/* Try to get the variable. We shall assume it is available, unless told otherwise. */
-		bool available = true;
-		value = GetVariable(object, adjust->variable, adjust->parameter, &available);
-
-		if (!available) {
-			/* Unsupported property: skip further processing and return either
-			 * the group from the first range or the default group. */
-			return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object);
-		}
-
-		switch (group->g.determ.size) {
-			case DSG_SIZE_BYTE:  value = EvalAdjust_int8(adjust, last_value, value); break;
-			case DSG_SIZE_WORD:  value = EvalAdjust_int16(adjust, last_value, value); break;
-			case DSG_SIZE_DWORD: value = EvalAdjust_int32(adjust, last_value, value); break;
-			default: NOT_REACHED(); break;
-		}
-		last_value = value;
-	}
-
-	if (group->g.determ.num_ranges == 0) {
-		/* nvar == 0 is a special case -- we turn our value into a callback result */
-		nvarzero.type = SGT_CALLBACK;
-		nvarzero.g.callback.result = GB(value, 0, 15);
-		return &nvarzero;
-	}
-
-	for (i = 0; i < group->g.determ.num_ranges; i++) {
-		if (group->g.determ.ranges[i].low <= (uint32)value && (uint32)value <= group->g.determ.ranges[i].high) {
-			return Resolve(group->g.determ.ranges[i].group, object);
-		}
-	}
-
-	return Resolve(group->g.determ.default_group, object);
-}
-
-
-static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, ResolverObject *object)
-{
-	uint32 mask;
-	byte index;
-
-	object->scope = group->g.random.var_scope;
-
-	if (object->trigger != 0) {
-		/* Handle triggers */
-		/* Magic code that may or may not do the right things... */
-		byte waiting_triggers = object->GetTriggers(object);
-		byte match = group->g.random.triggers & (waiting_triggers | object->trigger);
-		bool res;
-
-		res = (group->g.random.cmp_mode == RSG_CMP_ANY) ?
-			(match != 0) : (match == group->g.random.triggers);
-
-		if (res) {
-			waiting_triggers &= ~match;
-			object->reseed |= (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
-		} else {
-			waiting_triggers |= object->trigger;
-		}
-
-		object->SetTriggers(object, waiting_triggers);
-	}
-
-	mask  = (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
-	index = (object->GetRandomBits(object) & mask) >> group->g.random.lowest_randbit;
-
-	return Resolve(group->g.random.groups[index], object);
-}
-
-
-/* ResolverObject (re)entry point */
-const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object)
-{
-	/* We're called even if there is no group, so quietly return nothing */
-	if (group == NULL) return NULL;
-
-	switch (group->type) {
-		case SGT_REAL:          return object->ResolveReal(object, group);
-		case SGT_DETERMINISTIC: return ResolveVariable(group, object);
-		case SGT_RANDOMIZED:    return ResolveRandom(group, object);
-		default:                return group;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_spritegroup.cpp
@@ -0,0 +1,233 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "variables.h"
+#include "macros.h"
+#include "oldpool.h"
+#include "newgrf_spritegroup.h"
+#include "date.h"
+
+static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item);
+
+static uint _spritegroup_count = 0;
+STATIC_OLD_POOL(SpriteGroup, SpriteGroup, 9, 250, NULL, SpriteGroupPoolCleanBlock)
+
+static void DestroySpriteGroup(SpriteGroup *group)
+{
+	/* Free dynamically allocated memory */
+	/* XXX Cast away the consts due to MSVC being buggy... */
+	switch (group->type) {
+		case SGT_REAL:
+			free((SpriteGroup**)group->g.real.loaded);
+			free((SpriteGroup**)group->g.real.loading);
+			break;
+
+		case SGT_DETERMINISTIC:
+			free(group->g.determ.adjusts);
+			free(group->g.determ.ranges);
+			break;
+
+		case SGT_RANDOMIZED:
+			free((SpriteGroup**)group->g.random.groups);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item)
+{
+	uint i;
+
+	for (i = start_item; i <= end_item; i++) {
+		DestroySpriteGroup(GetSpriteGroup(i));
+	}
+}
+
+
+/* Allocate a new SpriteGroup */
+SpriteGroup *AllocateSpriteGroup(void)
+{
+	/* This is totally different to the other pool allocators, as we never remove an item from the pool. */
+	if (_spritegroup_count == GetSpriteGroupPoolSize()) {
+		if (!AddBlockToPool(&_SpriteGroup_pool)) return NULL;
+	}
+
+	return GetSpriteGroup(_spritegroup_count++);
+}
+
+
+void InitializeSpriteGroupPool(void)
+{
+	CleanPool(&_SpriteGroup_pool);
+
+	_spritegroup_count = 0;
+}
+
+
+static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
+{
+	/* Return common variables */
+	switch (variable) {
+		case 0x00: return max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
+		case 0x01: return clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
+		case 0x02: return _cur_month;
+		case 0x03: return _opt.landscape;
+		case 0x09: return _date_fract;
+		case 0x0A: return _tick_counter;
+		case 0x0C: return object->callback;
+		case 0x10: return object->callback_param1;
+		case 0x11: return 0;
+		case 0x18: return object->callback_param2;
+		case 0x1A: return -1;
+		case 0x1B: return GB(_display_opt, 0, 6);
+		case 0x1C: return object->last_value;
+		case 0x20: return _opt.landscape == LT_HILLY ? _opt.snow_line : 0xFF;
+
+		/* Not a common variable, so evalute the feature specific variables */
+		default: return object->GetVariable(object, variable, parameter, available);
+	}
+}
+
+
+/* Evaluate an adjustment for a variable of the given size. This is a bit of
+ * an unwieldy macro, but it saves triplicating the code. */
+#define BUILD_EVAL_ADJUST(size, usize) \
+static inline usize EvalAdjust_ ## size(const DeterministicSpriteGroupAdjust *adjust, usize last_value, int32 value) \
+{ \
+	value >>= adjust->shift_num; \
+	value  &= adjust->and_mask; \
+\
+	if (adjust->type != DSGA_TYPE_NONE) value += (size)adjust->add_val; \
+\
+	switch (adjust->type) { \
+		case DSGA_TYPE_DIV:  value /= (size)adjust->divmod_val; break; \
+		case DSGA_TYPE_MOD:  value %= (usize)adjust->divmod_val; break; \
+		case DSGA_TYPE_NONE: break; \
+	} \
+\
+	/* Get our value to the correct range */ \
+	value = (usize)value; \
+\
+	switch (adjust->operation) { \
+		case DSGA_OP_ADD:  return last_value + value; \
+		case DSGA_OP_SUB:  return last_value - value; \
+		case DSGA_OP_SMIN: return min(last_value, value); \
+		case DSGA_OP_SMAX: return max(last_value, value); \
+		case DSGA_OP_UMIN: return min((usize)last_value, (usize)value); \
+		case DSGA_OP_UMAX: return max((usize)last_value, (usize)value); \
+		case DSGA_OP_SDIV: return last_value / value; \
+		case DSGA_OP_SMOD: return last_value % value; \
+		case DSGA_OP_UDIV: return (usize)last_value / (usize)value; \
+		case DSGA_OP_UMOD: return (usize)last_value % (usize)value; \
+		case DSGA_OP_MUL:  return last_value * value; \
+		case DSGA_OP_AND:  return last_value & value; \
+		case DSGA_OP_OR:   return last_value | value; \
+		case DSGA_OP_XOR:  return last_value ^ value; \
+		default:           return value; \
+	} \
+}
+
+
+BUILD_EVAL_ADJUST(int8, uint8)
+BUILD_EVAL_ADJUST(int16, uint16)
+BUILD_EVAL_ADJUST(int32, uint32)
+
+
+static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, ResolverObject *object)
+{
+	static SpriteGroup nvarzero;
+	int32 last_value = object->last_value;
+	int32 value = -1;
+	uint i;
+
+	object->scope = group->g.determ.var_scope;
+
+	for (i = 0; i < group->g.determ.num_adjusts; i++) {
+		DeterministicSpriteGroupAdjust *adjust = &group->g.determ.adjusts[i];
+
+		/* Try to get the variable. We shall assume it is available, unless told otherwise. */
+		bool available = true;
+		value = GetVariable(object, adjust->variable, adjust->parameter, &available);
+
+		if (!available) {
+			/* Unsupported property: skip further processing and return either
+			 * the group from the first range or the default group. */
+			return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object);
+		}
+
+		switch (group->g.determ.size) {
+			case DSG_SIZE_BYTE:  value = EvalAdjust_int8(adjust, last_value, value); break;
+			case DSG_SIZE_WORD:  value = EvalAdjust_int16(adjust, last_value, value); break;
+			case DSG_SIZE_DWORD: value = EvalAdjust_int32(adjust, last_value, value); break;
+			default: NOT_REACHED(); break;
+		}
+		last_value = value;
+	}
+
+	if (group->g.determ.num_ranges == 0) {
+		/* nvar == 0 is a special case -- we turn our value into a callback result */
+		nvarzero.type = SGT_CALLBACK;
+		nvarzero.g.callback.result = GB(value, 0, 15);
+		return &nvarzero;
+	}
+
+	for (i = 0; i < group->g.determ.num_ranges; i++) {
+		if (group->g.determ.ranges[i].low <= (uint32)value && (uint32)value <= group->g.determ.ranges[i].high) {
+			return Resolve(group->g.determ.ranges[i].group, object);
+		}
+	}
+
+	return Resolve(group->g.determ.default_group, object);
+}
+
+
+static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, ResolverObject *object)
+{
+	uint32 mask;
+	byte index;
+
+	object->scope = group->g.random.var_scope;
+
+	if (object->trigger != 0) {
+		/* Handle triggers */
+		/* Magic code that may or may not do the right things... */
+		byte waiting_triggers = object->GetTriggers(object);
+		byte match = group->g.random.triggers & (waiting_triggers | object->trigger);
+		bool res;
+
+		res = (group->g.random.cmp_mode == RSG_CMP_ANY) ?
+			(match != 0) : (match == group->g.random.triggers);
+
+		if (res) {
+			waiting_triggers &= ~match;
+			object->reseed |= (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
+		} else {
+			waiting_triggers |= object->trigger;
+		}
+
+		object->SetTriggers(object, waiting_triggers);
+	}
+
+	mask  = (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
+	index = (object->GetRandomBits(object) & mask) >> group->g.random.lowest_randbit;
+
+	return Resolve(group->g.random.groups[index], object);
+}
+
+
+/* ResolverObject (re)entry point */
+const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object)
+{
+	/* We're called even if there is no group, so quietly return nothing */
+	if (group == NULL) return NULL;
+
+	switch (group->type) {
+		case SGT_REAL:          return object->ResolveReal(object, group);
+		case SGT_DETERMINISTIC: return ResolveVariable(group, object);
+		case SGT_RANDOMIZED:    return ResolveRandom(group, object);
+		default:                return group;
+	}
+}
deleted file mode 100644
--- a/src/newgrf_station.c
+++ /dev/null
@@ -1,766 +0,0 @@
-/* $Id$ */
-
-/** @file newgrf_station.c Functions for dealing with station classes and custom stations. */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "variables.h"
-#include "functions.h"
-#include "debug.h"
-#include "sprite.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "station.h"
-#include "station_map.h"
-#include "newgrf.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_station.h"
-#include "newgrf_spritegroup.h"
-#include "date.h"
-
-static StationClass station_classes[STAT_CLASS_MAX];
-
-enum {
-	MAX_SPECLIST = 255,
-};
-
-/**
- * Reset station classes to their default state.
- * This includes initialising the Default and Waypoint classes with an empty
- * entry, for standard stations and waypoints.
- */
-void ResetStationClasses(void)
-{
-	StationClassID i;
-	for (i = 0; i < STAT_CLASS_MAX; i++) {
-		station_classes[i].id = 0;
-		station_classes[i].name = STR_EMPTY;
-		station_classes[i].stations = 0;
-
-		free(station_classes[i].spec);
-		station_classes[i].spec = NULL;
-	}
-
-	// Set up initial data
-	station_classes[0].id = 'DFLT';
-	station_classes[0].name = STR_STAT_CLASS_DFLT;
-	station_classes[0].stations = 1;
-	station_classes[0].spec = malloc(sizeof(*station_classes[0].spec));
-	station_classes[0].spec[0] = NULL;
-
-	station_classes[1].id = 'WAYP';
-	station_classes[1].name = STR_STAT_CLASS_WAYP;
-	station_classes[1].stations = 1;
-	station_classes[1].spec = malloc(sizeof(*station_classes[1].spec));
-	station_classes[1].spec[0] = NULL;
-}
-
-/**
- * Allocate a station class for the given class id.
- * @param classid A 32 bit value identifying the class.
- * @return Index into station_classes of allocated class.
- */
-StationClassID AllocateStationClass(uint32 class)
-{
-	StationClassID i;
-
-	for (i = 0; i < STAT_CLASS_MAX; i++) {
-		if (station_classes[i].id == class) {
-			// ClassID is already allocated, so reuse it.
-			return i;
-		} else if (station_classes[i].id == 0) {
-			// This class is empty, so allocate it to the ClassID.
-			station_classes[i].id = class;
-			return i;
-		}
-	}
-
-	grfmsg(2, "StationClassAllocate: already allocated %d classes, using default", STAT_CLASS_MAX);
-	return STAT_CLASS_DFLT;
-}
-
-/** Set the name of a custom station class */
-void SetStationClassName(StationClassID sclass, StringID name)
-{
-	assert(sclass < STAT_CLASS_MAX);
-	station_classes[sclass].name = name;
-}
-
-/** Retrieve the name of a custom station class */
-StringID GetStationClassName(StationClassID sclass)
-{
-	assert(sclass < STAT_CLASS_MAX);
-	return station_classes[sclass].name;
-}
-
-/** Build a list of station class name StringIDs to use in a dropdown list
- * @return Pointer to a (static) array of StringIDs
- */
-StringID *BuildStationClassDropdown(void)
-{
-	/* Allow room for all station classes, plus a terminator entry */
-	static StringID names[STAT_CLASS_MAX + 1];
-	uint i;
-
-	/* Add each name */
-	for (i = 0; i < STAT_CLASS_MAX && station_classes[i].id != 0; i++) {
-		names[i] = station_classes[i].name;
-	}
-	/* Terminate the list */
-	names[i] = INVALID_STRING_ID;
-
-	return names;
-}
-
-/**
- * Get the number of station classes in use.
- * @return Number of station classes.
- */
-uint GetNumStationClasses(void)
-{
-	uint i;
-	for (i = 0; i < STAT_CLASS_MAX && station_classes[i].id != 0; i++);
-	return i;
-}
-
-/**
- * Return the number of stations for the given station class.
- * @param sclass Index of the station class.
- * @return Number of stations in the class.
- */
-uint GetNumCustomStations(StationClassID sclass)
-{
-	assert(sclass < STAT_CLASS_MAX);
-	return station_classes[sclass].stations;
-}
-
-/**
- * Tie a station spec to its station class.
- * @param spec The station spec.
- */
-void SetCustomStationSpec(StationSpec *statspec)
-{
-	StationClass *station_class;
-	int i;
-
-	/* If the station has already been allocated, don't reallocate it. */
-	if (statspec->allocated) return;
-
-	assert(statspec->sclass < STAT_CLASS_MAX);
-	station_class = &station_classes[statspec->sclass];
-
-	i = station_class->stations++;
-	station_class->spec = realloc(station_class->spec, station_class->stations * sizeof(*station_class->spec));
-
-	station_class->spec[i] = statspec;
-	statspec->allocated = true;
-}
-
-/**
- * Retrieve a station spec from a class.
- * @param sclass Index of the station class.
- * @param station The station index with the class.
- * @return The station spec.
- */
-const StationSpec *GetCustomStationSpec(StationClassID sclass, uint station)
-{
-	assert(sclass < STAT_CLASS_MAX);
-	if (station < station_classes[sclass].stations)
-		return station_classes[sclass].spec[station];
-
-	// If the custom station isn't defined any more, then the GRF file
-	// probably was not loaded.
-	return NULL;
-}
-
-
-const StationSpec *GetCustomStationSpecByGrf(uint32 grfid, byte localidx)
-{
-	StationClassID i;
-	uint j;
-
-	for (i = STAT_CLASS_DFLT; i < STAT_CLASS_MAX; i++) {
-		for (j = 0; j < station_classes[i].stations; j++) {
-			const StationSpec *statspec = station_classes[i].spec[j];
-			if (statspec == NULL) continue;
-			if (statspec->grfid == grfid && statspec->localidx == localidx) return statspec;
-		}
-	}
-
-	return NULL;
-}
-
-
-/* Evaluate a tile's position within a station, and return the result a bitstuffed format.
- * if not centred: .TNLcCpP, if centred: .TNL..CP
- * T = Tile layout number (GetStationGfx), N = Number of platforms, L = Length of platforms
- * C = Current platform number from start, c = from end
- * P = Position along platform from start, p = from end
- * if centred, C/P start from the centre and c/p are not available.
- */
-uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred)
-{
-	uint32 retval = 0;
-
-	if (axis == AXIS_X) {
-		intswap(platforms, length);
-		intswap(x, y);
-	}
-
-	/* Limit our sizes to 4 bits */
-	platforms = min(15, platforms);
-	length    = min(15, length);
-	x = min(15, x);
-	y = min(15, y);
-	if (centred) {
-		x -= platforms / 2;
-		y -= length / 2;
-		SB(retval,  0, 4, y & 0xF);
-		SB(retval,  4, 4, x & 0xF);
-	} else {
-		SB(retval,  0, 4, y);
-		SB(retval,  4, 4, length - y - 1);
-		SB(retval,  8, 4, x);
-		SB(retval, 12, 4, platforms - x - 1);
-	}
-	SB(retval, 16, 4, length);
-	SB(retval, 20, 4, platforms);
-	SB(retval, 24, 4, tile);
-
-	return retval;
-}
-
-
-/* Find the end of a railway station, from the tile, in the direction of delta.
- * If check_type is set, we stop if the custom station type changes.
- * If check_axis is set, we stop if the station direction changes.
- */
-static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
-{
-	bool waypoint;
-	byte orig_type = 0;
-	Axis orig_axis = AXIS_X;
-
-	waypoint = IsTileType(tile, MP_RAILWAY);
-
-	if (waypoint) {
-		if (check_axis) orig_axis = GetWaypointAxis(tile);
-	} else {
-		if (check_type) orig_type = GetCustomStationSpecIndex(tile);
-		if (check_axis) orig_axis = GetRailStationAxis(tile);
-	}
-
-	while (true) {
-		TileIndex new_tile = TILE_ADD(tile, delta);
-
-		if (waypoint) {
-			if (!IsTileType(new_tile, MP_RAILWAY)) break;
-			if (!IsRailWaypoint(new_tile)) break;
-			if (check_axis && GetWaypointAxis(new_tile) != orig_axis) break;
-		} else {
-			if (!IsRailwayStationTile(new_tile)) break;
-			if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
-			if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
-		}
-
-		tile = new_tile;
-	}
-	return tile;
-}
-
-
-static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred)
-{
-	int tx = TileX(tile);
-	int ty = TileY(tile);
-	int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1,  0), check_type, check_axis));
-	int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis));
-	int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1,  0), check_type, check_axis)) + 1;
-	int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0,  1), check_type, check_axis)) + 1;
-	Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
-
-	tx -= sx; ex -= sx;
-	ty -= sy; ey -= sy;
-
-	return GetPlatformInfo(axis, IsTileType(tile, MP_RAILWAY) ? 2 : GetStationGfx(tile), ex, ey, tx, ty, centred);
-}
-
-
-static uint32 GetRailContinuationInfo(TileIndex tile)
-{
-	/* Tile offsets and exit dirs for X axis */
-	static Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N };
-	static DiagDirection x_exits[8] = { DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SW, DIAGDIR_NE };
-
-	/* Tile offsets and exit dirs for Y axis */
-	static Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N };
-	static DiagDirection y_exits[8] = { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NW };
-
-	Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
-
-	/* Choose appropriate lookup table to use */
-	Direction *dir = axis == AXIS_X ? x_dir : y_dir;
-	DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits;
-
-	uint32 res = 0;
-	uint i;
-
-	for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) {
-		uint32 ts = GetTileTrackStatus(tile + TileOffsByDir(*dir), TRANSPORT_RAIL);
-		if (ts != 0) {
-			/* If there is any track on the tile, set the bit in the second byte */
-			SETBIT(res, i + 8);
-
-			/* If any track reaches our exit direction, set the bit in the lower byte */
-			if (ts & DiagdirReachesTracks(*diagdir)) SETBIT(res, i);
-		}
-	}
-
-	return res;
-}
-
-
-/* Station Resolver Functions */
-static uint32 StationGetRandomBits(const ResolverObject *object)
-{
-	const Station *st = object->u.station.st;
-	const TileIndex tile = object->u.station.tile;
-	return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16);
-}
-
-
-static uint32 StationGetTriggers(const ResolverObject *object)
-{
-	const Station *st = object->u.station.st;
-	return st == NULL ? 0 : st->waiting_triggers;
-}
-
-
-static void StationSetTriggers(const ResolverObject *object, int triggers)
-{
-	Station *st = (Station*)object->u.station.st;
-	assert(st != NULL);
-	st->waiting_triggers = triggers;
-}
-
-
-static uint32 StationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
-{
-	const Station *st = object->u.station.st;
-	TileIndex tile = object->u.station.tile;
-
-	if (st == NULL) {
-		/* Station does not exist, so we're in a purchase list */
-		switch (variable) {
-			case 0x40:
-			case 0x41:
-			case 0x46:
-			case 0x47:
-			case 0x49: return 0x2110000;       /* Platforms, tracks & position */
-			case 0x42: return 0;               /* Rail type (XXX Get current type from GUI?) */
-			case 0x43: return _current_player; /* Station owner */
-			case 0x44: return 2;               /* PBS status */
-			case 0xFA: return max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0); /* Build date */
-		}
-
-		*available = false;
-		return -1;
-	}
-
-	switch (variable) {
-		/* Calculated station variables */
-		case 0x40: return GetPlatformInfoHelper(tile, false, false, false);
-		case 0x41: return GetPlatformInfoHelper(tile, true,  false, false);
-		case 0x42: /* Terrain and rail type */
-			return ((_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) ? 4 : 0) |
-			       (GetRailType(tile) << 8);
-		case 0x43: return st->owner; /* Station owner */
-		case 0x44: return 2;         /* PBS status */
-		case 0x45: return GetRailContinuationInfo(tile);
-		case 0x46: return GetPlatformInfoHelper(tile, false, false, true);
-		case 0x47: return GetPlatformInfoHelper(tile, true,  false, true);
-		case 0x48: { /* Accepted cargo types */
-			CargoID cargo_type;
-			uint32 value = 0;
-
-			for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
-				if (HASBIT(st->goods[cargo_type].waiting_acceptance, 15)) SETBIT(value, cargo_type);
-			}
-			return value;
-		}
-		case 0x49: return GetPlatformInfoHelper(tile, false, true, false);
-
-		/* Variables which use the parameter */
-		case 0x60: return GB(st->goods[parameter].waiting_acceptance, 0, 12);
-		case 0x61: return st->goods[parameter].days_since_pickup;
-		case 0x62: return st->goods[parameter].rating;
-		case 0x63: return st->goods[parameter].enroute_time;
-		case 0x64: return st->goods[parameter].last_speed | (st->goods[parameter].last_age << 8);
-		case 0x65: return GB(st->goods[parameter].waiting_acceptance, 12, 4);
-
-		/* General station properties */
-		case 0x82: return 50;
-		case 0x84: return st->string_id;
-		case 0x86: return 0;
-		case 0x8A: return st->had_vehicle_of_type;
-		case 0xF0: return st->facilities;
-		case 0xF1: return st->airport_type;
-		case 0xF2: return st->truck_stops->status;
-		case 0xF3: return st->bus_stops->status;
-		case 0xF6: return st->airport_flags;
-		case 0xF7: return GB(st->airport_flags, 8, 8);
-		case 0xFA: return max(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
-	}
-
-	/* Handle cargo variables (deprecated) */
-	if (variable >= 0x8C && variable <= 0xEC) {
-		const GoodsEntry *g = &st->goods[GB(variable - 0x8C, 3, 4)];
-		switch (GB(variable - 0x8C, 0, 3)) {
-			case 0: return g->waiting_acceptance;
-			case 1: return GB(g->waiting_acceptance, 8, 8);
-			case 2: return g->days_since_pickup;
-			case 3: return g->rating;
-			case 4: return g->enroute_from;
-			case 5: return g->enroute_time;
-			case 6: return g->last_speed;
-			case 7: return g->last_age;
-		}
-	}
-
-	DEBUG(grf, 1, "Unhandled station property 0x%X", variable);
-
-	*available = false;
-	return -1;
-}
-
-
-static const SpriteGroup *StationResolveReal(const ResolverObject *object, const SpriteGroup *group)
-{
-	const Station *st = object->u.station.st;
-	const StationSpec *statspec = object->u.station.statspec;
-	uint set;
-
-	uint cargo = 0;
-	CargoID cargo_type = object->u.station.cargo_type;
-
-	if (st == NULL || statspec->sclass == STAT_CLASS_WAYP) {
-		return group->g.real.loading[0];
-	}
-
-	switch (cargo_type) {
-		case GC_INVALID:
-		case GC_DEFAULT_NA:
-		case GC_PURCHASE:
-			cargo = 0;
-			break;
-
-		case GC_DEFAULT:
-			for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
-				cargo += GB(st->goods[cargo_type].waiting_acceptance, 0, 12);
-			}
-			break;
-
-		default:
-			cargo = GB(st->goods[_local_cargo_id_ctype[cargo_type]].waiting_acceptance, 0, 12);
-			break;
-	}
-
-	if (HASBIT(statspec->flags, 1)) cargo /= (st->trainst_w + st->trainst_h);
-	cargo = min(0xfff, cargo);
-
-	if (cargo > statspec->cargo_threshold) {
-		if (group->g.real.num_loading > 0) {
-			set = ((cargo - statspec->cargo_threshold) * group->g.real.num_loading) / (4096 - statspec->cargo_threshold);
-			return group->g.real.loading[set];
-		}
-	} else {
-		if (group->g.real.num_loaded > 0) {
-			set = (cargo * group->g.real.num_loaded) / (statspec->cargo_threshold + 1);
-			return group->g.real.loaded[set];
-		}
-	}
-
-	return group->g.real.loading[0];
-}
-
-
-static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, const Station *st, TileIndex tile)
-{
-	res->GetRandomBits = StationGetRandomBits;
-	res->GetTriggers   = StationGetTriggers;
-	res->SetTriggers   = StationSetTriggers;
-	res->GetVariable   = StationGetVariable;
-	res->ResolveReal   = StationResolveReal;
-
-	res->u.station.st       = st;
-	res->u.station.statspec = statspec;
-	res->u.station.tile     = tile;
-
-	res->callback        = 0;
-	res->callback_param1 = 0;
-	res->callback_param2 = 0;
-	res->last_value      = 0;
-	res->trigger         = 0;
-	res->reseed          = 0;
-}
-
-static const SpriteGroup *ResolveStation(const StationSpec *statspec, const Station *st, ResolverObject *object)
-{
-	const SpriteGroup *group;
-	CargoID ctype = GC_DEFAULT_NA;
-
-	if (st == NULL) {
-		/* No station, so we are in a purchase list */
-		ctype = GC_PURCHASE;
-	} else {
-		CargoID cargo;
-
-		/* Pick the first cargo that we have waiting */
-		for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
-			CargoID lcid = _local_cargo_id_ctype[cargo];
-			if (lcid != CT_INVALID && statspec->spritegroup[cargo] != NULL && GB(st->goods[lcid].waiting_acceptance, 0, 12) != 0) {
-				ctype = cargo;
-				break;
-			}
-		}
-	}
-
-	group = statspec->spritegroup[ctype];
-	if (group == NULL) {
-		ctype = GC_DEFAULT;
-		group = statspec->spritegroup[ctype];
-	}
-
-	if (group == NULL) return NULL;
-
-	/* Remember the cargo type we've picked */
-	object->u.station.cargo_type = ctype;
-
-	return Resolve(group, object);
-}
-
-SpriteID GetCustomStationRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewStationResolver(&object, statspec, st, tile);
-
-	group = ResolveStation(statspec, st, &object);
-	if (group == NULL || group->type != SGT_RESULT) return 0;
-	return group->g.result.sprite - 0x42D;
-}
-
-
-SpriteID GetCustomStationGroundRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewStationResolver(&object, statspec, st, tile);
-	object.callback_param1 = 1; /* Indicate we are resolving the ground sprite */
-
-	group = ResolveStation(statspec, st, &object);
-	if (group == NULL || group->type != SGT_RESULT) return 0;
-	return group->g.result.sprite - 0x42D;
-}
-
-
-uint16 GetStationCallback(uint16 callback, uint32 param1, uint32 param2, const StationSpec *statspec, const Station *st, TileIndex tile)
-{
-	const SpriteGroup *group;
-	ResolverObject object;
-
-	NewStationResolver(&object, statspec, st, tile);
-
-	object.callback        = callback;
-	object.callback_param1 = param1;
-	object.callback_param2 = param2;
-
-	group = ResolveStation(statspec, st, &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
-	return group->g.callback.result;
-}
-
-
-/**
- * Allocate a StationSpec to a Station. This is called once per build operation.
- * @param spec StationSpec to allocate.
- * @param st Station to allocate it to.
- * @param exec Whether to actually allocate the spec.
- * @return Index within the Station's spec list, or -1 if the allocation failed.
- */
-int AllocateSpecToStation(const StationSpec *statspec, Station *st, bool exec)
-{
-	uint i;
-
-	if (statspec == NULL) return 0;
-
-	/* Check if this spec has already been allocated */
-	for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
-		if (st->speclist[i].spec == statspec) return i;
-	}
-
-	for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
-		if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break;
-	}
-
-	if (i == MAX_SPECLIST) return -1;
-
-	if (exec) {
-		if (i >= st->num_specs) {
-			st->num_specs = i + 1;
-			st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist));
-
-			if (st->num_specs == 2) {
-				/* Initial allocation */
-				st->speclist[0].spec     = NULL;
-				st->speclist[0].grfid    = 0;
-				st->speclist[0].localidx = 0;
-			}
-		}
-
-		st->speclist[i].spec     = statspec;
-		st->speclist[i].grfid    = statspec->grfid;
-		st->speclist[i].localidx = statspec->localidx;
-	}
-
-	return i;
-}
-
-
-/** Deallocate a StationSpec from a Station. Called when removing a single station tile.
- * @param st Station to work with.
- * @param specindex Index of the custom station within the Station's spec list.
- * @return Indicates whether the StationSpec was deallocated.
- */
-void DeallocateSpecFromStation(Station* st, byte specindex)
-{
-	/* specindex of 0 (default) is never freeable */
-	if (specindex == 0) return;
-
-	/* Check all tiles over the station to check if the specindex is still in use */
-	BEGIN_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile) {
-		if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile) && GetCustomStationSpecIndex(tile) == specindex) {
-			return;
-		}
-	} END_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile)
-
-	/* This specindex is no longer in use, so deallocate it */
-	st->speclist[specindex].spec     = NULL;
-	st->speclist[specindex].grfid    = 0;
-	st->speclist[specindex].localidx = 0;
-
-	/* If this was the highest spec index, reallocate */
-	if (specindex == st->num_specs - 1) {
-		for (; st->speclist[st->num_specs - 1].grfid == 0 && st->num_specs > 1; st->num_specs--);
-
-		if (st->num_specs > 1) {
-			st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist));
-		} else {
-			free(st->speclist);
-			st->num_specs = 0;
-			st->speclist  = NULL;
-		}
-	}
-}
-
-/** Draw representation of a station tile for GUI purposes.
- * @param x, y Position of image.
- * @param dir Direction.
- * @param railtype Rail type.
- * @param sclass, station Type of station.
- * @return True if the tile was drawn (allows for fallback to default graphic)
- */
-bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
-{
-	const StationSpec *statspec;
-	const DrawTileSprites *sprites;
-	const DrawTileSeqStruct *seq;
-	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
-	SpriteID relocation;
-	PalSpriteID image;
-	PalSpriteID colourmod = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player));
-	uint tile = 2;
-
-	statspec = GetCustomStationSpec(sclass, station);
-	if (statspec == NULL) return false;
-
-	relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE);
-
-	if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
-		uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, NULL, INVALID_TILE);
-		if (callback != CALLBACK_FAILED) tile = callback;
-	}
-
-	if (statspec->renderdata == NULL) {
-		sprites = GetStationTileLayout(tile + axis);
-	} else {
-		sprites = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : axis];
-	}
-
-	image = sprites->ground_sprite;
-	if (HASBIT(image, 31)) {
-		CLRBIT(image, 31);
-		image += GetCustomStationGroundRelocation(statspec, NULL, INVALID_TILE);
-		image += rti->custom_ground_offset;
-	} else {
-		image += rti->total_offset;
-	}
-
-	if (image & PALETTE_MODIFIER_COLOR) image &= SPRITE_MASK;
-	DrawSprite(image, x, y);
-
-	foreach_draw_tile_seq(seq, sprites->seq) {
-		Point pt;
-		image = seq->image;
-		if (HASBIT(image, 30)) {
-			CLRBIT(image, 30);
-			image += rti->total_offset;
-		} else {
-			image += relocation;
-		}
-
-		if ((byte)seq->delta_z != 0x80) {
-			pt = RemapCoords(seq->delta_x, seq->delta_y, seq->delta_z);
-			DrawSprite((image & SPRITE_MASK) | colourmod, x + pt.x, y + pt.y);
-		}
-	}
-
-	return true;
-}
-
-
-static const StationSpec* GetStationSpec(TileIndex t)
-{
-	const Station* st;
-	uint specindex;
-
-	if (!IsCustomStationSpecIndex(t)) return NULL;
-
-	st = GetStationByTile(t);
-	specindex = GetCustomStationSpecIndex(t);
-	return specindex < st->num_specs ? st->speclist[specindex].spec : NULL;
-}
-
-
-/* Check if a rail station tile is traversable.
- * XXX This could be cached (during build) in the map array to save on all the dereferencing */
-bool IsStationTileBlocked(TileIndex tile)
-{
-	const StationSpec* statspec = GetStationSpec(tile);
-
-	return statspec != NULL && HASBIT(statspec->blocked, GetStationGfx(tile));
-}
-
-/* Check if a rail station tile is electrifiable.
- * XXX This could be cached (during build) in the map array to save on all the dereferencing */
-bool IsStationTileElectrifiable(TileIndex tile)
-{
-	const StationSpec* statspec = GetStationSpec(tile);
-
-	return
-		statspec == NULL ||
-		HASBIT(statspec->pylons, GetStationGfx(tile)) ||
-		!HASBIT(statspec->wires, GetStationGfx(tile));
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_station.cpp
@@ -0,0 +1,766 @@
+/* $Id$ */
+
+/** @file newgrf_station.c Functions for dealing with station classes and custom stations. */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "variables.h"
+#include "functions.h"
+#include "debug.h"
+#include "sprite.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "station.h"
+#include "station_map.h"
+#include "newgrf.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_station.h"
+#include "newgrf_spritegroup.h"
+#include "date.h"
+
+static StationClass station_classes[STAT_CLASS_MAX];
+
+enum {
+	MAX_SPECLIST = 255,
+};
+
+/**
+ * Reset station classes to their default state.
+ * This includes initialising the Default and Waypoint classes with an empty
+ * entry, for standard stations and waypoints.
+ */
+void ResetStationClasses(void)
+{
+	StationClassID i;
+	for (i = 0; i < STAT_CLASS_MAX; i++) {
+		station_classes[i].id = 0;
+		station_classes[i].name = STR_EMPTY;
+		station_classes[i].stations = 0;
+
+		free(station_classes[i].spec);
+		station_classes[i].spec = NULL;
+	}
+
+	// Set up initial data
+	station_classes[0].id = 'DFLT';
+	station_classes[0].name = STR_STAT_CLASS_DFLT;
+	station_classes[0].stations = 1;
+	station_classes[0].spec = malloc(sizeof(*station_classes[0].spec));
+	station_classes[0].spec[0] = NULL;
+
+	station_classes[1].id = 'WAYP';
+	station_classes[1].name = STR_STAT_CLASS_WAYP;
+	station_classes[1].stations = 1;
+	station_classes[1].spec = malloc(sizeof(*station_classes[1].spec));
+	station_classes[1].spec[0] = NULL;
+}
+
+/**
+ * Allocate a station class for the given class id.
+ * @param classid A 32 bit value identifying the class.
+ * @return Index into station_classes of allocated class.
+ */
+StationClassID AllocateStationClass(uint32 class)
+{
+	StationClassID i;
+
+	for (i = 0; i < STAT_CLASS_MAX; i++) {
+		if (station_classes[i].id == class) {
+			// ClassID is already allocated, so reuse it.
+			return i;
+		} else if (station_classes[i].id == 0) {
+			// This class is empty, so allocate it to the ClassID.
+			station_classes[i].id = class;
+			return i;
+		}
+	}
+
+	grfmsg(2, "StationClassAllocate: already allocated %d classes, using default", STAT_CLASS_MAX);
+	return STAT_CLASS_DFLT;
+}
+
+/** Set the name of a custom station class */
+void SetStationClassName(StationClassID sclass, StringID name)
+{
+	assert(sclass < STAT_CLASS_MAX);
+	station_classes[sclass].name = name;
+}
+
+/** Retrieve the name of a custom station class */
+StringID GetStationClassName(StationClassID sclass)
+{
+	assert(sclass < STAT_CLASS_MAX);
+	return station_classes[sclass].name;
+}
+
+/** Build a list of station class name StringIDs to use in a dropdown list
+ * @return Pointer to a (static) array of StringIDs
+ */
+StringID *BuildStationClassDropdown(void)
+{
+	/* Allow room for all station classes, plus a terminator entry */
+	static StringID names[STAT_CLASS_MAX + 1];
+	uint i;
+
+	/* Add each name */
+	for (i = 0; i < STAT_CLASS_MAX && station_classes[i].id != 0; i++) {
+		names[i] = station_classes[i].name;
+	}
+	/* Terminate the list */
+	names[i] = INVALID_STRING_ID;
+
+	return names;
+}
+
+/**
+ * Get the number of station classes in use.
+ * @return Number of station classes.
+ */
+uint GetNumStationClasses(void)
+{
+	uint i;
+	for (i = 0; i < STAT_CLASS_MAX && station_classes[i].id != 0; i++);
+	return i;
+}
+
+/**
+ * Return the number of stations for the given station class.
+ * @param sclass Index of the station class.
+ * @return Number of stations in the class.
+ */
+uint GetNumCustomStations(StationClassID sclass)
+{
+	assert(sclass < STAT_CLASS_MAX);
+	return station_classes[sclass].stations;
+}
+
+/**
+ * Tie a station spec to its station class.
+ * @param spec The station spec.
+ */
+void SetCustomStationSpec(StationSpec *statspec)
+{
+	StationClass *station_class;
+	int i;
+
+	/* If the station has already been allocated, don't reallocate it. */
+	if (statspec->allocated) return;
+
+	assert(statspec->sclass < STAT_CLASS_MAX);
+	station_class = &station_classes[statspec->sclass];
+
+	i = station_class->stations++;
+	station_class->spec = realloc(station_class->spec, station_class->stations * sizeof(*station_class->spec));
+
+	station_class->spec[i] = statspec;
+	statspec->allocated = true;
+}
+
+/**
+ * Retrieve a station spec from a class.
+ * @param sclass Index of the station class.
+ * @param station The station index with the class.
+ * @return The station spec.
+ */
+const StationSpec *GetCustomStationSpec(StationClassID sclass, uint station)
+{
+	assert(sclass < STAT_CLASS_MAX);
+	if (station < station_classes[sclass].stations)
+		return station_classes[sclass].spec[station];
+
+	// If the custom station isn't defined any more, then the GRF file
+	// probably was not loaded.
+	return NULL;
+}
+
+
+const StationSpec *GetCustomStationSpecByGrf(uint32 grfid, byte localidx)
+{
+	StationClassID i;
+	uint j;
+
+	for (i = STAT_CLASS_DFLT; i < STAT_CLASS_MAX; i++) {
+		for (j = 0; j < station_classes[i].stations; j++) {
+			const StationSpec *statspec = station_classes[i].spec[j];
+			if (statspec == NULL) continue;
+			if (statspec->grfid == grfid && statspec->localidx == localidx) return statspec;
+		}
+	}
+
+	return NULL;
+}
+
+
+/* Evaluate a tile's position within a station, and return the result a bitstuffed format.
+ * if not centred: .TNLcCpP, if centred: .TNL..CP
+ * T = Tile layout number (GetStationGfx), N = Number of platforms, L = Length of platforms
+ * C = Current platform number from start, c = from end
+ * P = Position along platform from start, p = from end
+ * if centred, C/P start from the centre and c/p are not available.
+ */
+uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred)
+{
+	uint32 retval = 0;
+
+	if (axis == AXIS_X) {
+		intswap(platforms, length);
+		intswap(x, y);
+	}
+
+	/* Limit our sizes to 4 bits */
+	platforms = min(15, platforms);
+	length    = min(15, length);
+	x = min(15, x);
+	y = min(15, y);
+	if (centred) {
+		x -= platforms / 2;
+		y -= length / 2;
+		SB(retval,  0, 4, y & 0xF);
+		SB(retval,  4, 4, x & 0xF);
+	} else {
+		SB(retval,  0, 4, y);
+		SB(retval,  4, 4, length - y - 1);
+		SB(retval,  8, 4, x);
+		SB(retval, 12, 4, platforms - x - 1);
+	}
+	SB(retval, 16, 4, length);
+	SB(retval, 20, 4, platforms);
+	SB(retval, 24, 4, tile);
+
+	return retval;
+}
+
+
+/* Find the end of a railway station, from the tile, in the direction of delta.
+ * If check_type is set, we stop if the custom station type changes.
+ * If check_axis is set, we stop if the station direction changes.
+ */
+static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
+{
+	bool waypoint;
+	byte orig_type = 0;
+	Axis orig_axis = AXIS_X;
+
+	waypoint = IsTileType(tile, MP_RAILWAY);
+
+	if (waypoint) {
+		if (check_axis) orig_axis = GetWaypointAxis(tile);
+	} else {
+		if (check_type) orig_type = GetCustomStationSpecIndex(tile);
+		if (check_axis) orig_axis = GetRailStationAxis(tile);
+	}
+
+	while (true) {
+		TileIndex new_tile = TILE_ADD(tile, delta);
+
+		if (waypoint) {
+			if (!IsTileType(new_tile, MP_RAILWAY)) break;
+			if (!IsRailWaypoint(new_tile)) break;
+			if (check_axis && GetWaypointAxis(new_tile) != orig_axis) break;
+		} else {
+			if (!IsRailwayStationTile(new_tile)) break;
+			if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
+			if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
+		}
+
+		tile = new_tile;
+	}
+	return tile;
+}
+
+
+static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred)
+{
+	int tx = TileX(tile);
+	int ty = TileY(tile);
+	int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1,  0), check_type, check_axis));
+	int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis));
+	int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1,  0), check_type, check_axis)) + 1;
+	int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0,  1), check_type, check_axis)) + 1;
+	Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
+
+	tx -= sx; ex -= sx;
+	ty -= sy; ey -= sy;
+
+	return GetPlatformInfo(axis, IsTileType(tile, MP_RAILWAY) ? 2 : GetStationGfx(tile), ex, ey, tx, ty, centred);
+}
+
+
+static uint32 GetRailContinuationInfo(TileIndex tile)
+{
+	/* Tile offsets and exit dirs for X axis */
+	static Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N };
+	static DiagDirection x_exits[8] = { DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SW, DIAGDIR_NE };
+
+	/* Tile offsets and exit dirs for Y axis */
+	static Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N };
+	static DiagDirection y_exits[8] = { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NW };
+
+	Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile);
+
+	/* Choose appropriate lookup table to use */
+	Direction *dir = axis == AXIS_X ? x_dir : y_dir;
+	DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits;
+
+	uint32 res = 0;
+	uint i;
+
+	for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) {
+		uint32 ts = GetTileTrackStatus(tile + TileOffsByDir(*dir), TRANSPORT_RAIL);
+		if (ts != 0) {
+			/* If there is any track on the tile, set the bit in the second byte */
+			SETBIT(res, i + 8);
+
+			/* If any track reaches our exit direction, set the bit in the lower byte */
+			if (ts & DiagdirReachesTracks(*diagdir)) SETBIT(res, i);
+		}
+	}
+
+	return res;
+}
+
+
+/* Station Resolver Functions */
+static uint32 StationGetRandomBits(const ResolverObject *object)
+{
+	const Station *st = object->u.station.st;
+	const TileIndex tile = object->u.station.tile;
+	return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16);
+}
+
+
+static uint32 StationGetTriggers(const ResolverObject *object)
+{
+	const Station *st = object->u.station.st;
+	return st == NULL ? 0 : st->waiting_triggers;
+}
+
+
+static void StationSetTriggers(const ResolverObject *object, int triggers)
+{
+	Station *st = (Station*)object->u.station.st;
+	assert(st != NULL);
+	st->waiting_triggers = triggers;
+}
+
+
+static uint32 StationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
+{
+	const Station *st = object->u.station.st;
+	TileIndex tile = object->u.station.tile;
+
+	if (st == NULL) {
+		/* Station does not exist, so we're in a purchase list */
+		switch (variable) {
+			case 0x40:
+			case 0x41:
+			case 0x46:
+			case 0x47:
+			case 0x49: return 0x2110000;       /* Platforms, tracks & position */
+			case 0x42: return 0;               /* Rail type (XXX Get current type from GUI?) */
+			case 0x43: return _current_player; /* Station owner */
+			case 0x44: return 2;               /* PBS status */
+			case 0xFA: return max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0); /* Build date */
+		}
+
+		*available = false;
+		return -1;
+	}
+
+	switch (variable) {
+		/* Calculated station variables */
+		case 0x40: return GetPlatformInfoHelper(tile, false, false, false);
+		case 0x41: return GetPlatformInfoHelper(tile, true,  false, false);
+		case 0x42: /* Terrain and rail type */
+			return ((_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) ? 4 : 0) |
+			       (GetRailType(tile) << 8);
+		case 0x43: return st->owner; /* Station owner */
+		case 0x44: return 2;         /* PBS status */
+		case 0x45: return GetRailContinuationInfo(tile);
+		case 0x46: return GetPlatformInfoHelper(tile, false, false, true);
+		case 0x47: return GetPlatformInfoHelper(tile, true,  false, true);
+		case 0x48: { /* Accepted cargo types */
+			CargoID cargo_type;
+			uint32 value = 0;
+
+			for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
+				if (HASBIT(st->goods[cargo_type].waiting_acceptance, 15)) SETBIT(value, cargo_type);
+			}
+			return value;
+		}
+		case 0x49: return GetPlatformInfoHelper(tile, false, true, false);
+
+		/* Variables which use the parameter */
+		case 0x60: return GB(st->goods[parameter].waiting_acceptance, 0, 12);
+		case 0x61: return st->goods[parameter].days_since_pickup;
+		case 0x62: return st->goods[parameter].rating;
+		case 0x63: return st->goods[parameter].enroute_time;
+		case 0x64: return st->goods[parameter].last_speed | (st->goods[parameter].last_age << 8);
+		case 0x65: return GB(st->goods[parameter].waiting_acceptance, 12, 4);
+
+		/* General station properties */
+		case 0x82: return 50;
+		case 0x84: return st->string_id;
+		case 0x86: return 0;
+		case 0x8A: return st->had_vehicle_of_type;
+		case 0xF0: return st->facilities;
+		case 0xF1: return st->airport_type;
+		case 0xF2: return st->truck_stops->status;
+		case 0xF3: return st->bus_stops->status;
+		case 0xF6: return st->airport_flags;
+		case 0xF7: return GB(st->airport_flags, 8, 8);
+		case 0xFA: return max(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
+	}
+
+	/* Handle cargo variables (deprecated) */
+	if (variable >= 0x8C && variable <= 0xEC) {
+		const GoodsEntry *g = &st->goods[GB(variable - 0x8C, 3, 4)];
+		switch (GB(variable - 0x8C, 0, 3)) {
+			case 0: return g->waiting_acceptance;
+			case 1: return GB(g->waiting_acceptance, 8, 8);
+			case 2: return g->days_since_pickup;
+			case 3: return g->rating;
+			case 4: return g->enroute_from;
+			case 5: return g->enroute_time;
+			case 6: return g->last_speed;
+			case 7: return g->last_age;
+		}
+	}
+
+	DEBUG(grf, 1, "Unhandled station property 0x%X", variable);
+
+	*available = false;
+	return -1;
+}
+
+
+static const SpriteGroup *StationResolveReal(const ResolverObject *object, const SpriteGroup *group)
+{
+	const Station *st = object->u.station.st;
+	const StationSpec *statspec = object->u.station.statspec;
+	uint set;
+
+	uint cargo = 0;
+	CargoID cargo_type = object->u.station.cargo_type;
+
+	if (st == NULL || statspec->sclass == STAT_CLASS_WAYP) {
+		return group->g.real.loading[0];
+	}
+
+	switch (cargo_type) {
+		case GC_INVALID:
+		case GC_DEFAULT_NA:
+		case GC_PURCHASE:
+			cargo = 0;
+			break;
+
+		case GC_DEFAULT:
+			for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
+				cargo += GB(st->goods[cargo_type].waiting_acceptance, 0, 12);
+			}
+			break;
+
+		default:
+			cargo = GB(st->goods[_local_cargo_id_ctype[cargo_type]].waiting_acceptance, 0, 12);
+			break;
+	}
+
+	if (HASBIT(statspec->flags, 1)) cargo /= (st->trainst_w + st->trainst_h);
+	cargo = min(0xfff, cargo);
+
+	if (cargo > statspec->cargo_threshold) {
+		if (group->g.real.num_loading > 0) {
+			set = ((cargo - statspec->cargo_threshold) * group->g.real.num_loading) / (4096 - statspec->cargo_threshold);
+			return group->g.real.loading[set];
+		}
+	} else {
+		if (group->g.real.num_loaded > 0) {
+			set = (cargo * group->g.real.num_loaded) / (statspec->cargo_threshold + 1);
+			return group->g.real.loaded[set];
+		}
+	}
+
+	return group->g.real.loading[0];
+}
+
+
+static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, const Station *st, TileIndex tile)
+{
+	res->GetRandomBits = StationGetRandomBits;
+	res->GetTriggers   = StationGetTriggers;
+	res->SetTriggers   = StationSetTriggers;
+	res->GetVariable   = StationGetVariable;
+	res->ResolveReal   = StationResolveReal;
+
+	res->u.station.st       = st;
+	res->u.station.statspec = statspec;
+	res->u.station.tile     = tile;
+
+	res->callback        = 0;
+	res->callback_param1 = 0;
+	res->callback_param2 = 0;
+	res->last_value      = 0;
+	res->trigger         = 0;
+	res->reseed          = 0;
+}
+
+static const SpriteGroup *ResolveStation(const StationSpec *statspec, const Station *st, ResolverObject *object)
+{
+	const SpriteGroup *group;
+	CargoID ctype = GC_DEFAULT_NA;
+
+	if (st == NULL) {
+		/* No station, so we are in a purchase list */
+		ctype = GC_PURCHASE;
+	} else {
+		CargoID cargo;
+
+		/* Pick the first cargo that we have waiting */
+		for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) {
+			CargoID lcid = _local_cargo_id_ctype[cargo];
+			if (lcid != CT_INVALID && statspec->spritegroup[cargo] != NULL && GB(st->goods[lcid].waiting_acceptance, 0, 12) != 0) {
+				ctype = cargo;
+				break;
+			}
+		}
+	}
+
+	group = statspec->spritegroup[ctype];
+	if (group == NULL) {
+		ctype = GC_DEFAULT;
+		group = statspec->spritegroup[ctype];
+	}
+
+	if (group == NULL) return NULL;
+
+	/* Remember the cargo type we've picked */
+	object->u.station.cargo_type = ctype;
+
+	return Resolve(group, object);
+}
+
+SpriteID GetCustomStationRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewStationResolver(&object, statspec, st, tile);
+
+	group = ResolveStation(statspec, st, &object);
+	if (group == NULL || group->type != SGT_RESULT) return 0;
+	return group->g.result.sprite - 0x42D;
+}
+
+
+SpriteID GetCustomStationGroundRelocation(const StationSpec *statspec, const Station *st, TileIndex tile)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewStationResolver(&object, statspec, st, tile);
+	object.callback_param1 = 1; /* Indicate we are resolving the ground sprite */
+
+	group = ResolveStation(statspec, st, &object);
+	if (group == NULL || group->type != SGT_RESULT) return 0;
+	return group->g.result.sprite - 0x42D;
+}
+
+
+uint16 GetStationCallback(uint16 callback, uint32 param1, uint32 param2, const StationSpec *statspec, const Station *st, TileIndex tile)
+{
+	const SpriteGroup *group;
+	ResolverObject object;
+
+	NewStationResolver(&object, statspec, st, tile);
+
+	object.callback        = callback;
+	object.callback_param1 = param1;
+	object.callback_param2 = param2;
+
+	group = ResolveStation(statspec, st, &object);
+	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	return group->g.callback.result;
+}
+
+
+/**
+ * Allocate a StationSpec to a Station. This is called once per build operation.
+ * @param spec StationSpec to allocate.
+ * @param st Station to allocate it to.
+ * @param exec Whether to actually allocate the spec.
+ * @return Index within the Station's spec list, or -1 if the allocation failed.
+ */
+int AllocateSpecToStation(const StationSpec *statspec, Station *st, bool exec)
+{
+	uint i;
+
+	if (statspec == NULL) return 0;
+
+	/* Check if this spec has already been allocated */
+	for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
+		if (st->speclist[i].spec == statspec) return i;
+	}
+
+	for (i = 1; i < st->num_specs && i < MAX_SPECLIST; i++) {
+		if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break;
+	}
+
+	if (i == MAX_SPECLIST) return -1;
+
+	if (exec) {
+		if (i >= st->num_specs) {
+			st->num_specs = i + 1;
+			st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist));
+
+			if (st->num_specs == 2) {
+				/* Initial allocation */
+				st->speclist[0].spec     = NULL;
+				st->speclist[0].grfid    = 0;
+				st->speclist[0].localidx = 0;
+			}
+		}
+
+		st->speclist[i].spec     = statspec;
+		st->speclist[i].grfid    = statspec->grfid;
+		st->speclist[i].localidx = statspec->localidx;
+	}
+
+	return i;
+}
+
+
+/** Deallocate a StationSpec from a Station. Called when removing a single station tile.
+ * @param st Station to work with.
+ * @param specindex Index of the custom station within the Station's spec list.
+ * @return Indicates whether the StationSpec was deallocated.
+ */
+void DeallocateSpecFromStation(Station* st, byte specindex)
+{
+	/* specindex of 0 (default) is never freeable */
+	if (specindex == 0) return;
+
+	/* Check all tiles over the station to check if the specindex is still in use */
+	BEGIN_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile) {
+		if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile) && GetCustomStationSpecIndex(tile) == specindex) {
+			return;
+		}
+	} END_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile)
+
+	/* This specindex is no longer in use, so deallocate it */
+	st->speclist[specindex].spec     = NULL;
+	st->speclist[specindex].grfid    = 0;
+	st->speclist[specindex].localidx = 0;
+
+	/* If this was the highest spec index, reallocate */
+	if (specindex == st->num_specs - 1) {
+		for (; st->speclist[st->num_specs - 1].grfid == 0 && st->num_specs > 1; st->num_specs--);
+
+		if (st->num_specs > 1) {
+			st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist));
+		} else {
+			free(st->speclist);
+			st->num_specs = 0;
+			st->speclist  = NULL;
+		}
+	}
+}
+
+/** Draw representation of a station tile for GUI purposes.
+ * @param x, y Position of image.
+ * @param dir Direction.
+ * @param railtype Rail type.
+ * @param sclass, station Type of station.
+ * @return True if the tile was drawn (allows for fallback to default graphic)
+ */
+bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
+{
+	const StationSpec *statspec;
+	const DrawTileSprites *sprites;
+	const DrawTileSeqStruct *seq;
+	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
+	SpriteID relocation;
+	PalSpriteID image;
+	PalSpriteID colourmod = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player));
+	uint tile = 2;
+
+	statspec = GetCustomStationSpec(sclass, station);
+	if (statspec == NULL) return false;
+
+	relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE);
+
+	if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
+		uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, NULL, INVALID_TILE);
+		if (callback != CALLBACK_FAILED) tile = callback;
+	}
+
+	if (statspec->renderdata == NULL) {
+		sprites = GetStationTileLayout(tile + axis);
+	} else {
+		sprites = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : axis];
+	}
+
+	image = sprites->ground_sprite;
+	if (HASBIT(image, 31)) {
+		CLRBIT(image, 31);
+		image += GetCustomStationGroundRelocation(statspec, NULL, INVALID_TILE);
+		image += rti->custom_ground_offset;
+	} else {
+		image += rti->total_offset;
+	}
+
+	if (image & PALETTE_MODIFIER_COLOR) image &= SPRITE_MASK;
+	DrawSprite(image, x, y);
+
+	foreach_draw_tile_seq(seq, sprites->seq) {
+		Point pt;
+		image = seq->image;
+		if (HASBIT(image, 30)) {
+			CLRBIT(image, 30);
+			image += rti->total_offset;
+		} else {
+			image += relocation;
+		}
+
+		if ((byte)seq->delta_z != 0x80) {
+			pt = RemapCoords(seq->delta_x, seq->delta_y, seq->delta_z);
+			DrawSprite((image & SPRITE_MASK) | colourmod, x + pt.x, y + pt.y);
+		}
+	}
+
+	return true;
+}
+
+
+static const StationSpec* GetStationSpec(TileIndex t)
+{
+	const Station* st;
+	uint specindex;
+
+	if (!IsCustomStationSpecIndex(t)) return NULL;
+
+	st = GetStationByTile(t);
+	specindex = GetCustomStationSpecIndex(t);
+	return specindex < st->num_specs ? st->speclist[specindex].spec : NULL;
+}
+
+
+/* Check if a rail station tile is traversable.
+ * XXX This could be cached (during build) in the map array to save on all the dereferencing */
+bool IsStationTileBlocked(TileIndex tile)
+{
+	const StationSpec* statspec = GetStationSpec(tile);
+
+	return statspec != NULL && HASBIT(statspec->blocked, GetStationGfx(tile));
+}
+
+/* Check if a rail station tile is electrifiable.
+ * XXX This could be cached (during build) in the map array to save on all the dereferencing */
+bool IsStationTileElectrifiable(TileIndex tile)
+{
+	const StationSpec* statspec = GetStationSpec(tile);
+
+	return
+		statspec == NULL ||
+		HASBIT(statspec->pylons, GetStationGfx(tile)) ||
+		!HASBIT(statspec->wires, GetStationGfx(tile));
+}
deleted file mode 100644
--- a/src/newgrf_text.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/* $Id$ */
-
-/** @file
- * Implementation of  Action 04 "universal holder" structure and functions.
- * This file implements a linked-lists of strings,
- * holding everything that the newgrf action 04 will send over to OpenTTD.
- * One of the biggest problems is that Dynamic lang Array uses ISO codes
- * as way to identifying current user lang, while newgrf uses bit shift codes
- * not related to ISO.  So equivalence functionnality had to be set.
- */
-
-#include "stdafx.h"
-#include "debug.h"
-#include "openttd.h"
-#include "string.h"
-#include "strings.h"
-#include "variables.h"
-#include "macros.h"
-#include "table/strings.h"
-#include "newgrf.h"
-#include "newgrf_text.h"
-#include "table/control_codes.h"
-
-#define GRFTAB  28
-#define TABSIZE 11
-
-/**
- * Explains the newgrf shift bit positionning.
- * the grf base will not be used in order to find the string, but rather for
- * jumping from standard langID scheme to the new one.
- */
-typedef enum grf_base_languages {
-	GRFLB_AMERICAN    = 0x01,
-	GRFLB_ENGLISH     = 0x02,
-	GRFLB_GERMAN      = 0x04,
-	GRFLB_FRENCH      = 0x08,
-	GRFLB_SPANISH     = 0x10,
-	GRFLB_GENERIC     = 0x80,
-} grf_base_language;
-
-typedef enum grf_extended_languages {
-	GRFLX_AMERICAN    = 0x00,
-	GRFLX_ENGLISH     = 0x01,
-	GRFLX_GERMAN      = 0x02,
-	GRFLX_FRENCH      = 0x03,
-	GRFLX_SPANISH     = 0x04,
-	GRFLX_RUSSIAN     = 0x07,
-	GRFLX_CZECH       = 0x15,
-	GRFLX_SLOVAK      = 0x16,
-	GRFLX_AFRIKAANS   = 0x1B,
-	GRFLX_GREEK       = 0x1E,
-	GRFLX_DUTCH       = 0x1F,
-	GRFLX_CATALAN     = 0x22,
-	GRFLX_HUNGARIAN   = 0x24,
-	GRFLX_ITALIAN     = 0x27,
-	GRFLX_ROMANIAN    = 0x28,
-	GRFLX_ICELANDIC   = 0x29,
-	GRFLX_LATVIAN     = 0x2A,
-	GRFLX_LITHUANIAN  = 0x2B,
-	GRFLX_SLOVENIAN   = 0x2C,
-	GRFLX_DANISH      = 0x2D,
-	GRFLX_SWEDISH     = 0x2E,
-	GRFLX_NORWEGIAN   = 0x2F,
-	GRFLX_POLISH      = 0x30,
-	GRFLX_GALICIAN    = 0x31,
-	GRFLX_FRISIAN     = 0x32,
-	GRFLX_UKRAINIAN   = 0x33,
-	GRFLX_ESTONIAN    = 0x34,
-	GRFLX_FINNISH     = 0x35,
-	GRFLX_PORTUGUESE  = 0x36,
-	GRFLX_BRAZILIAN   = 0x37,
-	GRFLX_CROATIAN    = 0x38,
-	GRFLX_TURKISH     = 0x3E,
-	GRFLX_UNSPECIFIED = 0x7F,
-} grf_language;
-
-
-typedef struct iso_grf {
-	char code[6];
-	byte grfLangID;
-} iso_grf;
-
-/**
- * ISO code VS NewGrf langID conversion array.
- * This array is used in two ways:
- * 1-its ISO part is matching OpenTTD dynamic language id
- *   with newgrf bit positionning language id
- * 2-its shift part is used to know what is the shift to
- *   watch for when inserting new strings, hence analysing newgrf langid
- */
-const iso_grf iso_codes[] = {
-	{"en_US", GRFLX_AMERICAN},
-	{"en_GB", GRFLX_ENGLISH},
-	{"de_DE", GRFLX_GERMAN},
-	{"fr_FR", GRFLX_FRENCH},
-	{"es_ES", GRFLX_SPANISH},
-	{"af_ZA", GRFLX_AFRIKAANS},
-	{"hr_HR", GRFLX_CROATIAN},
-	{"cs_CS", GRFLX_CZECH},
-	{"ca_ES", GRFLX_CATALAN},
-	{"da_DA", GRFLX_DANISH},
-	{"nl_NL", GRFLX_DUTCH},
-	{"et_ET", GRFLX_ESTONIAN},
-	{"fi_FI", GRFLX_FINNISH},
-	{"fy_NL", GRFLX_FRISIAN},
-	{"gl_ES", GRFLX_GALICIAN},
-	{"el_GR", GRFLX_GREEK},
-	{"hu_HU", GRFLX_HUNGARIAN},
-	{"is_IS", GRFLX_ICELANDIC},
-	{"it_IT", GRFLX_ITALIAN},
-	{"lv_LV", GRFLX_LATVIAN},
-	{"lt_LT", GRFLX_LITHUANIAN},
-	{"nb_NO", GRFLX_NORWEGIAN},
-	{"pl_PL", GRFLX_POLISH},
-	{"pt_PT", GRFLX_PORTUGUESE},
-	{"pt_BR", GRFLX_BRAZILIAN},
-	{"ro_RO", GRFLX_ROMANIAN},
-	{"ru_RU", GRFLX_RUSSIAN},
-	{"sk_SK", GRFLX_SLOVAK},
-	{"sl_SL", GRFLX_SLOVENIAN},
-	{"sv_SE", GRFLX_SWEDISH},
-	{"tr_TR", GRFLX_TURKISH},
-	{"uk_UA", GRFLX_UKRAINIAN},
-	{"gen",   GRFLB_GENERIC}   //this is not iso code, but there has to be something...
-};
-
-
-/**
- * Element of the linked list.
- * Each of those elements represent the string,
- * but according to a different lang.
- */
-typedef struct GRFText {
-	struct GRFText *next;
-	byte langid;
-	char text[VARARRAY_SIZE];
-} GRFText;
-
-
-/**
- * Holder of the above structure.
- * Putting both grfid and stringid together allows us to avoid duplicates,
- * since it is NOT SUPPOSED to happen.
- */
-typedef struct GRFTextEntry {
-	uint32 grfid;
-	uint16 stringid;
-	StringID def_string;
-	GRFText *textholder;
-} GRFTextEntry;
-
-
-static uint _num_grf_texts = 0;
-static GRFTextEntry _grf_text[(1 << TABSIZE) * 3];
-static byte _currentLangID = GRFLX_ENGLISH;  //by default, english is used.
-
-
-char *TranslateTTDPatchCodes(const char *str)
-{
-	char *tmp = malloc(strlen(str) * 10 + 1); /* Allocate space to allow for expansion */
-	char *d = tmp;
-	bool unicode = false;
-	WChar c;
-	size_t len = Utf8Decode(&c, str);
-
-	if (c == 0x00DE) {
-		/* The thorn ('þ') indicates a unicode string to TTDPatch */
-		unicode = true;
-		str += len;
-	}
-
-	for (;;) {
-		const char *tmp = str; /* Used for UTF-8 decoding */
-
-		c = (byte)*str++;
-		if (c == 0) break;
-
-		switch (c) {
-			case 0x01:
-				d += Utf8Encode(d, SCC_SETX);
-				*d++ = *str++;
-				break;
-			case 0x0A: break;
-			case 0x0D: *d++ = 0x0A; break;
-			case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break;
-			case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break;
-			case 0x1F:
-				d += Utf8Encode(d, SCC_SETXY);
-				*d++ = *str++;
-				*d++ = *str++;
-				break;
-			case 0x7B:
-			case 0x7C:
-			case 0x7D:
-			case 0x7E: d += Utf8Encode(d, SCC_NUM); break;
-			case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break;
-			case 0x80: d += Utf8Encode(d, SCC_STRING); break;
-			case 0x81: {
-				StringID string;
-				string  = *str++;
-				string |= *str++ << 8;
-				d += Utf8Encode(d, SCC_STRING_ID);
-				d += Utf8Encode(d, string);
-				break;
-			}
-			case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break;
-			case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break;
-			case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break;
-			case 0x85: d += Utf8Encode(d, SCC_SKIP);    break;
-			case 0x86: /* "Rotate down top 4 words on stack" */ break;
-			case 0x87: d += Utf8Encode(d, SCC_VOLUME);  break;
-			case 0x88: d += Utf8Encode(d, SCC_BLUE);    break;
-			case 0x89: d += Utf8Encode(d, SCC_SILVER);  break;
-			case 0x8A: d += Utf8Encode(d, SCC_GOLD);    break;
-			case 0x8B: d += Utf8Encode(d, SCC_RED);     break;
-			case 0x8C: d += Utf8Encode(d, SCC_PURPLE);  break;
-			case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break;
-			case 0x8E: d += Utf8Encode(d, SCC_ORANGE);  break;
-			case 0x8F: d += Utf8Encode(d, SCC_GREEN);   break;
-			case 0x90: d += Utf8Encode(d, SCC_YELLOW);  break;
-			case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break;
-			case 0x92: d += Utf8Encode(d, SCC_CREAM);   break;
-			case 0x93: d += Utf8Encode(d, SCC_BROWN);   break;
-			case 0x94: d += Utf8Encode(d, SCC_WHITE);   break;
-			case 0x95: d += Utf8Encode(d, SCC_LTBLUE);  break;
-			case 0x96: d += Utf8Encode(d, SCC_GRAY);    break;
-			case 0x97: d += Utf8Encode(d, SCC_DKBLUE);  break;
-			case 0x98: d += Utf8Encode(d, SCC_BLACK);   break;
-			case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro
-			case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis
-			case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break;
-			case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break;
-			case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break;
-			case 0xAD: d += Utf8Encode(d, SCC_CROSS); break;
-			case 0xAF: d += Utf8Encode(d, SCC_RIGHTARROW); break;
-			case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break;
-			case 0xB5: d += Utf8Encode(d, SCC_LORRY); break;
-			case 0xB6: d += Utf8Encode(d, SCC_BUS); break;
-			case 0xB7: d += Utf8Encode(d, SCC_PLANE); break;
-			case 0xB8: d += Utf8Encode(d, SCC_SHIP); break;
-			default:
-				if (unicode) {
-					d += Utf8Encode(d, Utf8Consume(&tmp));
-					str = tmp;
-					break;
-				}
-
-				/* Validate any unhandled character */
-				if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
-				d += Utf8Encode(d, c);
-				break;
-		}
-	}
-
-	*d = '\0';
-	return realloc(tmp, strlen(tmp) + 1);
-}
-
-
-/**
- * Add the new read string into our structure.
- */
-StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, const char *text_to_add, StringID def_string)
-{
-	char *translatedtext;
-	GRFText *newtext;
-	uint id;
-
-	/* When working with the old language scheme (grf_version is less than 7) and
-	 * English or American is among the set bits, simply add it as English in
-	 * the new scheme, i.e. as langid = 1.
-	 * If English is set, it is pretty safe to assume the translations are not
-	 * actually translated.
-	 */
-	if (!new_scheme) {
-		if (HASBITS(langid_to_add, GRFLB_AMERICAN | GRFLB_ENGLISH)) {
-			langid_to_add = GRFLX_ENGLISH;
-		} else {
-			StringID ret = STR_EMPTY;
-			if (langid_to_add & GRFLB_GERMAN)  ret = AddGRFString(grfid, stringid, GRFLX_GERMAN,  true, text_to_add, def_string);
-			if (langid_to_add & GRFLB_FRENCH)  ret = AddGRFString(grfid, stringid, GRFLX_FRENCH,  true, text_to_add, def_string);
-			if (langid_to_add & GRFLB_SPANISH) ret = AddGRFString(grfid, stringid, GRFLX_SPANISH, true, text_to_add, def_string);
-			return ret;
-		}
-	}
-
-	for (id = 0; id < _num_grf_texts; id++) {
-		if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
-			break;
-		}
-	}
-
-	/* Too many strings allocated, return empty */
-	if (id == lengthof(_grf_text)) return STR_EMPTY;
-
-	translatedtext = TranslateTTDPatchCodes(text_to_add);
-
-	newtext = malloc(sizeof(*newtext) + strlen(translatedtext) + 1);
-	newtext->next   = NULL;
-	newtext->langid = langid_to_add;
-	strcpy(newtext->text, translatedtext);
-
-	free(translatedtext);
-
-	/* If we didn't find our stringid and grfid in the list, allocate a new id */
-	if (id == _num_grf_texts) _num_grf_texts++;
-
-	if (_grf_text[id].textholder == NULL) {
-		_grf_text[id].grfid      = grfid;
-		_grf_text[id].stringid   = stringid;
-		_grf_text[id].def_string = def_string;
-		_grf_text[id].textholder = newtext;
-	} else {
-		GRFText **ptext, *text;
-		bool replaced = false;
-
-		/* Loop through all languages and see if we can replace a string */
-		for (ptext = &_grf_text[id].textholder; (text = *ptext) != NULL; ptext = &text->next) {
-			if (text->langid != langid_to_add) continue;
-			newtext->next = text->next;
-			*ptext = newtext;
-			free(text);
-			replaced = true;
-			break;
-		}
-
-		/* If a string wasn't replaced, then we must append the new string */
-		if (!replaced) *ptext = newtext;
-	}
-
-	grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'", id, grfid, stringid, newtext->langid, newtext->text);
-
-	return (GRFTAB << TABSIZE) + id;
-}
-
-/* Used to remember the grfid that the last retrieved string came from */
-static uint32 _last_grfid = 0;
-
-/**
- * Returns the index for this stringid associated with its grfID
- */
-StringID GetGRFStringID(uint32 grfid, uint16 stringid)
-{
-	uint id;
-
-	/* grfid is zero when we're being called via an include */
-	if (grfid == 0) grfid = _last_grfid;
-
-	for (id = 0; id < _num_grf_texts; id++) {
-		if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
-			return (GRFTAB << TABSIZE) + id;
-		}
-	}
-
-	return STR_UNDEFINED;
-}
-
-
-char *GetGRFString(char *buff, uint16 stringid, const char* last)
-{
-	const GRFText *default_text = NULL;
-	const GRFText *search_text;
-
-	assert(_grf_text[stringid].grfid != 0);
-
-	/* Remember this grfid in case the string has included text */
-	_last_grfid = _grf_text[stringid].grfid;
-
-	/*Search the list of lang-strings of this stringid for current lang */
-	for (search_text = _grf_text[stringid].textholder; search_text != NULL; search_text = search_text->next) {
-		if (search_text->langid == _currentLangID) {
-			return strecpy(buff, search_text->text, last);
-		}
-
-		/* If the current string is English or American, set it as the
-		 * fallback language if the specific language isn't available. */
-		if (search_text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (search_text->langid == GRFLX_ENGLISH || search_text->langid == GRFLX_AMERICAN))) {
-			default_text = search_text;
-		}
-	}
-
-	/* If there is a fallback string, return that */
-	if (default_text != NULL) return strecpy(buff, default_text->text, last);
-
-	/* Use the default string ID if the fallback string isn't available */
-	return GetString(buff, _grf_text[stringid].def_string, last);
-}
-
-/**
- * Equivalence Setter function between game and newgrf langID.
- * This function will adjust _currentLangID as to what is the LangID
- * of the current language set by the user.
- * The array iso_codes will be used to find that match.
- * If not found, it will have to be standard english
- * This function is called after the user changed language,
- * from strings.c:ReadLanguagePack
- * @param iso code of current selection
- */
-void SetCurrentGrfLangID(const char *iso_name)
-{
-	/* Use English by default, if we can't match up the iso_code. */
-	byte ret = GRFLX_ENGLISH;
-	byte i;
-
-	for (i=0; i < lengthof(iso_codes); i++) {
-		if (strncmp(iso_codes[i].code, iso_name, strlen(iso_codes[i].code)) == 0) {
-			/* We found a match, so let's use it. */
-			ret = i;
-			break;
-		}
-	}
-	_currentLangID = ret;
-}
-
-/**
- * House cleaning.
- * Remove all strings and reset the text counter.
- */
-void CleanUpStrings(void)
-{
-	uint id;
-
-	for (id = 0; id < _num_grf_texts; id++) {
-		GRFText *grftext = _grf_text[id].textholder;
-		while (grftext != NULL) {
-			GRFText *grftext2 = grftext->next;
-			free(grftext);
-			grftext = grftext2;
-		}
-		_grf_text[id].grfid      = 0;
-		_grf_text[id].stringid   = 0;
-		_grf_text[id].textholder = NULL;
-	}
-
-	_num_grf_texts = 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/newgrf_text.cpp
@@ -0,0 +1,436 @@
+/* $Id$ */
+
+/** @file
+ * Implementation of  Action 04 "universal holder" structure and functions.
+ * This file implements a linked-lists of strings,
+ * holding everything that the newgrf action 04 will send over to OpenTTD.
+ * One of the biggest problems is that Dynamic lang Array uses ISO codes
+ * as way to identifying current user lang, while newgrf uses bit shift codes
+ * not related to ISO.  So equivalence functionnality had to be set.
+ */
+
+#include "stdafx.h"
+#include "debug.h"
+#include "openttd.h"
+#include "string.h"
+#include "strings.h"
+#include "variables.h"
+#include "macros.h"
+#include "table/strings.h"
+#include "newgrf.h"
+#include "newgrf_text.h"
+#include "table/control_codes.h"
+
+#define GRFTAB  28
+#define TABSIZE 11
+
+/**
+ * Explains the newgrf shift bit positionning.
+ * the grf base will not be used in order to find the string, but rather for
+ * jumping from standard langID scheme to the new one.
+ */
+typedef enum grf_base_languages {
+	GRFLB_AMERICAN    = 0x01,
+	GRFLB_ENGLISH     = 0x02,
+	GRFLB_GERMAN      = 0x04,
+	GRFLB_FRENCH      = 0x08,
+	GRFLB_SPANISH     = 0x10,
+	GRFLB_GENERIC     = 0x80,
+} grf_base_language;
+
+typedef enum grf_extended_languages {
+	GRFLX_AMERICAN    = 0x00,
+	GRFLX_ENGLISH     = 0x01,
+	GRFLX_GERMAN      = 0x02,
+	GRFLX_FRENCH      = 0x03,
+	GRFLX_SPANISH     = 0x04,
+	GRFLX_RUSSIAN     = 0x07,
+	GRFLX_CZECH       = 0x15,
+	GRFLX_SLOVAK      = 0x16,
+	GRFLX_AFRIKAANS   = 0x1B,
+	GRFLX_GREEK       = 0x1E,
+	GRFLX_DUTCH       = 0x1F,
+	GRFLX_CATALAN     = 0x22,
+	GRFLX_HUNGARIAN   = 0x24,
+	GRFLX_ITALIAN     = 0x27,
+	GRFLX_ROMANIAN    = 0x28,
+	GRFLX_ICELANDIC   = 0x29,
+	GRFLX_LATVIAN     = 0x2A,
+	GRFLX_LITHUANIAN  = 0x2B,
+	GRFLX_SLOVENIAN   = 0x2C,
+	GRFLX_DANISH      = 0x2D,
+	GRFLX_SWEDISH     = 0x2E,
+	GRFLX_NORWEGIAN   = 0x2F,
+	GRFLX_POLISH      = 0x30,
+	GRFLX_GALICIAN    = 0x31,
+	GRFLX_FRISIAN     = 0x32,
+	GRFLX_UKRAINIAN   = 0x33,
+	GRFLX_ESTONIAN    = 0x34,
+	GRFLX_FINNISH     = 0x35,
+	GRFLX_PORTUGUESE  = 0x36,
+	GRFLX_BRAZILIAN   = 0x37,
+	GRFLX_CROATIAN    = 0x38,
+	GRFLX_TURKISH     = 0x3E,
+	GRFLX_UNSPECIFIED = 0x7F,
+} grf_language;
+
+
+typedef struct iso_grf {
+	char code[6];
+	byte grfLangID;
+} iso_grf;
+
+/**
+ * ISO code VS NewGrf langID conversion array.
+ * This array is used in two ways:
+ * 1-its ISO part is matching OpenTTD dynamic language id
+ *   with newgrf bit positionning language id
+ * 2-its shift part is used to know what is the shift to
+ *   watch for when inserting new strings, hence analysing newgrf langid
+ */
+const iso_grf iso_codes[] = {
+	{"en_US", GRFLX_AMERICAN},
+	{"en_GB", GRFLX_ENGLISH},
+	{"de_DE", GRFLX_GERMAN},
+	{"fr_FR", GRFLX_FRENCH},
+	{"es_ES", GRFLX_SPANISH},
+	{"af_ZA", GRFLX_AFRIKAANS},
+	{"hr_HR", GRFLX_CROATIAN},
+	{"cs_CS", GRFLX_CZECH},
+	{"ca_ES", GRFLX_CATALAN},
+	{"da_DA", GRFLX_DANISH},
+	{"nl_NL", GRFLX_DUTCH},
+	{"et_ET", GRFLX_ESTONIAN},
+	{"fi_FI", GRFLX_FINNISH},
+	{"fy_NL", GRFLX_FRISIAN},
+	{"gl_ES", GRFLX_GALICIAN},
+	{"el_GR", GRFLX_GREEK},
+	{"hu_HU", GRFLX_HUNGARIAN},
+	{"is_IS", GRFLX_ICELANDIC},
+	{"it_IT", GRFLX_ITALIAN},
+	{"lv_LV", GRFLX_LATVIAN},
+	{"lt_LT", GRFLX_LITHUANIAN},
+	{"nb_NO", GRFLX_NORWEGIAN},
+	{"pl_PL", GRFLX_POLISH},
+	{"pt_PT", GRFLX_PORTUGUESE},
+	{"pt_BR", GRFLX_BRAZILIAN},
+	{"ro_RO", GRFLX_ROMANIAN},
+	{"ru_RU", GRFLX_RUSSIAN},
+	{"sk_SK", GRFLX_SLOVAK},
+	{"sl_SL", GRFLX_SLOVENIAN},
+	{"sv_SE", GRFLX_SWEDISH},
+	{"tr_TR", GRFLX_TURKISH},
+	{"uk_UA", GRFLX_UKRAINIAN},
+	{"gen",   GRFLB_GENERIC}   //this is not iso code, but there has to be something...
+};
+
+
+/**
+ * Element of the linked list.
+ * Each of those elements represent the string,
+ * but according to a different lang.
+ */
+typedef struct GRFText {
+	struct GRFText *next;
+	byte langid;
+	char text[VARARRAY_SIZE];
+} GRFText;
+
+
+/**
+ * Holder of the above structure.
+ * Putting both grfid and stringid together allows us to avoid duplicates,
+ * since it is NOT SUPPOSED to happen.
+ */
+typedef struct GRFTextEntry {
+	uint32 grfid;
+	uint16 stringid;
+	StringID def_string;
+	GRFText *textholder;
+} GRFTextEntry;
+
+
+static uint _num_grf_texts = 0;
+static GRFTextEntry _grf_text[(1 << TABSIZE) * 3];
+static byte _currentLangID = GRFLX_ENGLISH;  //by default, english is used.
+
+
+char *TranslateTTDPatchCodes(const char *str)
+{
+	char *tmp = malloc(strlen(str) * 10 + 1); /* Allocate space to allow for expansion */
+	char *d = tmp;
+	bool unicode = false;
+	WChar c;
+	size_t len = Utf8Decode(&c, str);
+
+	if (c == 0x00DE) {
+		/* The thorn ('þ') indicates a unicode string to TTDPatch */
+		unicode = true;
+		str += len;
+	}
+
+	for (;;) {
+		const char *tmp = str; /* Used for UTF-8 decoding */
+
+		c = (byte)*str++;
+		if (c == 0) break;
+
+		switch (c) {
+			case 0x01:
+				d += Utf8Encode(d, SCC_SETX);
+				*d++ = *str++;
+				break;
+			case 0x0A: break;
+			case 0x0D: *d++ = 0x0A; break;
+			case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break;
+			case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break;
+			case 0x1F:
+				d += Utf8Encode(d, SCC_SETXY);
+				*d++ = *str++;
+				*d++ = *str++;
+				break;
+			case 0x7B:
+			case 0x7C:
+			case 0x7D:
+			case 0x7E: d += Utf8Encode(d, SCC_NUM); break;
+			case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break;
+			case 0x80: d += Utf8Encode(d, SCC_STRING); break;
+			case 0x81: {
+				StringID string;
+				string  = *str++;
+				string |= *str++ << 8;
+				d += Utf8Encode(d, SCC_STRING_ID);
+				d += Utf8Encode(d, string);
+				break;
+			}
+			case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break;
+			case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break;
+			case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break;
+			case 0x85: d += Utf8Encode(d, SCC_SKIP);    break;
+			case 0x86: /* "Rotate down top 4 words on stack" */ break;
+			case 0x87: d += Utf8Encode(d, SCC_VOLUME);  break;
+			case 0x88: d += Utf8Encode(d, SCC_BLUE);    break;
+			case 0x89: d += Utf8Encode(d, SCC_SILVER);  break;
+			case 0x8A: d += Utf8Encode(d, SCC_GOLD);    break;
+			case 0x8B: d += Utf8Encode(d, SCC_RED);     break;
+			case 0x8C: d += Utf8Encode(d, SCC_PURPLE);  break;
+			case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break;
+			case 0x8E: d += Utf8Encode(d, SCC_ORANGE);  break;
+			case 0x8F: d += Utf8Encode(d, SCC_GREEN);   break;
+			case 0x90: d += Utf8Encode(d, SCC_YELLOW);  break;
+			case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break;
+			case 0x92: d += Utf8Encode(d, SCC_CREAM);   break;
+			case 0x93: d += Utf8Encode(d, SCC_BROWN);   break;
+			case 0x94: d += Utf8Encode(d, SCC_WHITE);   break;
+			case 0x95: d += Utf8Encode(d, SCC_LTBLUE);  break;
+			case 0x96: d += Utf8Encode(d, SCC_GRAY);    break;
+			case 0x97: d += Utf8Encode(d, SCC_DKBLUE);  break;
+			case 0x98: d += Utf8Encode(d, SCC_BLACK);   break;
+			case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro
+			case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis
+			case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break;
+			case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break;
+			case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break;
+			case 0xAD: d += Utf8Encode(d, SCC_CROSS); break;
+			case 0xAF: d += Utf8Encode(d, SCC_RIGHTARROW); break;
+			case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break;
+			case 0xB5: d += Utf8Encode(d, SCC_LORRY); break;
+			case 0xB6: d += Utf8Encode(d, SCC_BUS); break;
+			case 0xB7: d += Utf8Encode(d, SCC_PLANE); break;
+			case 0xB8: d += Utf8Encode(d, SCC_SHIP); break;
+			default:
+				if (unicode) {
+					d += Utf8Encode(d, Utf8Consume(&tmp));
+					str = tmp;
+					break;
+				}
+
+				/* Validate any unhandled character */
+				if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
+				d += Utf8Encode(d, c);
+				break;
+		}
+	}
+
+	*d = '\0';
+	return realloc(tmp, strlen(tmp) + 1);
+}
+
+
+/**
+ * Add the new read string into our structure.
+ */
+StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, const char *text_to_add, StringID def_string)
+{
+	char *translatedtext;
+	GRFText *newtext;
+	uint id;
+
+	/* When working with the old language scheme (grf_version is less than 7) and
+	 * English or American is among the set bits, simply add it as English in
+	 * the new scheme, i.e. as langid = 1.
+	 * If English is set, it is pretty safe to assume the translations are not
+	 * actually translated.
+	 */
+	if (!new_scheme) {
+		if (HASBITS(langid_to_add, GRFLB_AMERICAN | GRFLB_ENGLISH)) {
+			langid_to_add = GRFLX_ENGLISH;
+		} else {
+			StringID ret = STR_EMPTY;
+			if (langid_to_add & GRFLB_GERMAN)  ret = AddGRFString(grfid, stringid, GRFLX_GERMAN,  true, text_to_add, def_string);
+			if (langid_to_add & GRFLB_FRENCH)  ret = AddGRFString(grfid, stringid, GRFLX_FRENCH,  true, text_to_add, def_string);
+			if (langid_to_add & GRFLB_SPANISH) ret = AddGRFString(grfid, stringid, GRFLX_SPANISH, true, text_to_add, def_string);
+			return ret;
+		}
+	}
+
+	for (id = 0; id < _num_grf_texts; id++) {
+		if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
+			break;
+		}
+	}
+
+	/* Too many strings allocated, return empty */
+	if (id == lengthof(_grf_text)) return STR_EMPTY;
+
+	translatedtext = TranslateTTDPatchCodes(text_to_add);
+
+	newtext = malloc(sizeof(*newtext) + strlen(translatedtext) + 1);
+	newtext->next   = NULL;
+	newtext->langid = langid_to_add;
+	strcpy(newtext->text, translatedtext);
+
+	free(translatedtext);
+
+	/* If we didn't find our stringid and grfid in the list, allocate a new id */
+	if (id == _num_grf_texts) _num_grf_texts++;
+
+	if (_grf_text[id].textholder == NULL) {
+		_grf_text[id].grfid      = grfid;
+		_grf_text[id].stringid   = stringid;
+		_grf_text[id].def_string = def_string;
+		_grf_text[id].textholder = newtext;
+	} else {
+		GRFText **ptext, *text;
+		bool replaced = false;
+
+		/* Loop through all languages and see if we can replace a string */
+		for (ptext = &_grf_text[id].textholder; (text = *ptext) != NULL; ptext = &text->next) {
+			if (text->langid != langid_to_add) continue;
+			newtext->next = text->next;
+			*ptext = newtext;
+			free(text);
+			replaced = true;
+			break;
+		}
+
+		/* If a string wasn't replaced, then we must append the new string */
+		if (!replaced) *ptext = newtext;
+	}
+
+	grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'", id, grfid, stringid, newtext->langid, newtext->text);
+
+	return (GRFTAB << TABSIZE) + id;
+}
+
+/* Used to remember the grfid that the last retrieved string came from */
+static uint32 _last_grfid = 0;
+
+/**
+ * Returns the index for this stringid associated with its grfID
+ */
+StringID GetGRFStringID(uint32 grfid, uint16 stringid)
+{
+	uint id;
+
+	/* grfid is zero when we're being called via an include */
+	if (grfid == 0) grfid = _last_grfid;
+
+	for (id = 0; id < _num_grf_texts; id++) {
+		if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
+			return (GRFTAB << TABSIZE) + id;
+		}
+	}
+
+	return STR_UNDEFINED;
+}
+
+
+char *GetGRFString(char *buff, uint16 stringid, const char* last)
+{
+	const GRFText *default_text = NULL;
+	const GRFText *search_text;
+
+	assert(_grf_text[stringid].grfid != 0);
+
+	/* Remember this grfid in case the string has included text */
+	_last_grfid = _grf_text[stringid].grfid;
+
+	/*Search the list of lang-strings of this stringid for current lang */
+	for (search_text = _grf_text[stringid].textholder; search_text != NULL; search_text = search_text->next) {
+		if (search_text->langid == _currentLangID) {
+			return strecpy(buff, search_text->text, last);
+		}
+
+		/* If the current string is English or American, set it as the
+		 * fallback language if the specific language isn't available. */
+		if (search_text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (search_text->langid == GRFLX_ENGLISH || search_text->langid == GRFLX_AMERICAN))) {
+			default_text = search_text;
+		}
+	}
+
+	/* If there is a fallback string, return that */
+	if (default_text != NULL) return strecpy(buff, default_text->text, last);
+
+	/* Use the default string ID if the fallback string isn't available */
+	return GetString(buff, _grf_text[stringid].def_string, last);
+}
+
+/**
+ * Equivalence Setter function between game and newgrf langID.
+ * This function will adjust _currentLangID as to what is the LangID
+ * of the current language set by the user.
+ * The array iso_codes will be used to find that match.
+ * If not found, it will have to be standard english
+ * This function is called after the user changed language,
+ * from strings.c:ReadLanguagePack
+ * @param iso code of current selection
+ */
+void SetCurrentGrfLangID(const char *iso_name)
+{
+	/* Use English by default, if we can't match up the iso_code. */
+	byte ret = GRFLX_ENGLISH;
+	byte i;
+
+	for (i=0; i < lengthof(iso_codes); i++) {
+		if (strncmp(iso_codes[i].code, iso_name, strlen(iso_codes[i].code)) == 0) {
+			/* We found a match, so let's use it. */
+			ret = i;
+			break;
+		}
+	}
+	_currentLangID = ret;
+}
+
+/**
+ * House cleaning.
+ * Remove all strings and reset the text counter.
+ */
+void CleanUpStrings(void)
+{
+	uint id;
+
+	for (id = 0; id < _num_grf_texts; id++) {
+		GRFText *grftext = _grf_text[id].textholder;
+		while (grftext != NULL) {
+			GRFText *grftext2 = grftext->next;
+			free(grftext);
+			grftext = grftext2;
+		}
+		_grf_text[id].grfid      = 0;
+		_grf_text[id].stringid   = 0;
+		_grf_text[id].textholder = NULL;
+	}
+
+	_num_grf_texts = 0;
+}
deleted file mode 100644
--- a/src/news_gui.c
+++ /dev/null
@@ -1,939 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "news.h"
-#include "vehicle.h"
-#include "sound.h"
-#include "variables.h"
-#include "date.h"
-#include "string.h"
-
-/* News system
- * News system is realized as a FIFO queue (in an array)
- * The positions in the queue can't be rearranged, we only access
- * the array elements through pointers to the elements. Once the
- * array is full, the oldest entry (_oldest_news) is being overwritten
- * by the newest (_latest news).
- *
- * oldest                   current   lastest
- *  |                          |         |
- * [O------------F-------------C---------L           ]
- *               |
- *            forced
- *
- * Of course by using an array we can have situations like
- *
- * [----L          O-----F---------C-----------------]
- * This is where we have wrapped around the array and have
- * (MAX_NEWS - O) + L news items
- */
-
-#define MAX_NEWS 30
-
-typedef byte NewsID;
-#define INVALID_NEWS 255
-
-static NewsItem _news_items[MAX_NEWS];
-static NewsID _current_news = INVALID_NEWS; // points to news item that should be shown next
-static NewsID _oldest_news = 0;    // points to first item in fifo queue
-static NewsID _latest_news = INVALID_NEWS;  // points to last item in fifo queue
-/* if the message being shown was forced by the user, its index is stored in
- * _forced_news. forced_news is INVALID_NEWS otherwise.
- * (Users can force messages through history or "last message") */
-static NewsID _forced_news = INVALID_NEWS;
-
-static byte _total_news = 0; // total news count
-
-void DrawNewsNewTrainAvail(Window *w);
-void DrawNewsNewRoadVehAvail(Window *w);
-void DrawNewsNewShipAvail(Window *w);
-void DrawNewsNewAircraftAvail(Window *w);
-void DrawNewsBankrupcy(Window *w);
-static void MoveToNextItem(void);
-
-StringID GetNewsStringNewTrainAvail(const NewsItem *ni);
-StringID GetNewsStringNewRoadVehAvail(const NewsItem *ni);
-StringID GetNewsStringNewShipAvail(const NewsItem *ni);
-StringID GetNewsStringNewAircraftAvail(const NewsItem *ni);
-StringID GetNewsStringBankrupcy(const NewsItem *ni);
-
-static DrawNewsCallbackProc * const _draw_news_callback[] = {
-	DrawNewsNewTrainAvail,    /* DNC_TRAINAVAIL */
-	DrawNewsNewRoadVehAvail,  /* DNC_ROADAVAIL */
-	DrawNewsNewShipAvail,     /* DNC_SHIPAVAIL */
-	DrawNewsNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
-	DrawNewsBankrupcy,        /* DNC_BANKRUPCY */
-};
-
-GetNewsStringCallbackProc * const _get_news_string_callback[] = {
-	GetNewsStringNewTrainAvail,    /* DNC_TRAINAVAIL */
-	GetNewsStringNewRoadVehAvail,  /* DNC_ROADAVAIL */
-	GetNewsStringNewShipAvail,     /* DNC_SHIPAVAIL */
-	GetNewsStringNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
-	GetNewsStringBankrupcy,        /* DNC_BANKRUPCY */
-};
-
-void InitNewsItemStructs(void)
-{
-	memset(_news_items, 0, sizeof(_news_items));
-	_current_news = INVALID_NEWS;
-	_oldest_news = 0;
-	_latest_news = INVALID_NEWS;
-	_forced_news = INVALID_NEWS;
-	_total_news = 0;
-}
-
-void DrawNewsBorder(const Window *w)
-{
-	int left = 0;
-	int right = w->width - 1;
-	int top = 0;
-	int bottom = w->height - 1;
-
-	GfxFillRect(left, top, right, bottom, 0xF);
-
-	GfxFillRect(left, top, left, bottom, 0xD7);
-	GfxFillRect(right, top, right, bottom, 0xD7);
-	GfxFillRect(left, top, right, top, 0xD7);
-	GfxFillRect(left, bottom, right, bottom, 0xD7);
-
-	DrawString(left + 2, top + 1, STR_00C6, 0);
-}
-
-static void NewsWindowProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: { /* If chatbar is open at creation time, we need to go above it */
-		const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0);
-		w->message.msg = (w1 != NULL) ? w1->height : 0;
-	} break;
-
-	case WE_PAINT: {
-		const NewsItem *ni = WP(w, news_d).ni;
-		ViewPort *vp;
-
-		switch (ni->display_mode) {
-			case NM_NORMAL:
-			case NM_THIN: {
-				DrawNewsBorder(w);
-
-				DrawString(2, 1, STR_00C6, 0);
-
-				SetDParam(0, ni->date);
-				DrawStringRightAligned(428, 1, STR_01FF, 0);
-
-				if (!(ni->flags & NF_VIEWPORT)) {
-					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-					DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
-						ni->string_id, 426);
-				} else {
-					byte bk = _display_opt;
-					_display_opt &= ~DO_TRANS_BUILDINGS;
-					DrawWindowViewport(w);
-					_display_opt = bk;
-
-					/* Shade the viewport into gray, or color*/
-					vp = w->viewport;
-					GfxFillRect(vp->left - w->left, vp->top - w->top,
-						vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
-						(ni->flags & NF_INCOLOR ? 0x322 : 0x323) | USE_COLORTABLE
-					);
-
-					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-					DrawStringMultiCenter(w->width / 2, 20, ni->string_id, 428);
-				}
-				break;
-			}
-
-			case NM_CALLBACK: {
-				_draw_news_callback[ni->callback](w);
-				break;
-			}
-
-			default: {
-				DrawWindowWidgets(w);
-				if (!(ni->flags & NF_VIEWPORT)) {
-					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-					DrawStringMultiCenter(140, 38, ni->string_id, 276);
-				} else {
-					DrawWindowViewport(w);
-					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-					DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, 276);
-				}
-				break;
-			}
-		}
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 1: {
-			NewsItem *ni = WP(w, news_d).ni;
-			DeleteWindow(w);
-			ni->duration = 0;
-			_forced_news = INVALID_NEWS;
-		} break;
-		case 0: {
-			NewsItem *ni = WP(w, news_d).ni;
-			if (ni->flags & NF_VEHICLE) {
-				Vehicle *v = GetVehicle(ni->data_a);
-				ScrollMainWindowTo(v->x_pos, v->y_pos);
-			} else if (ni->flags & NF_TILE) {
-				if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
-					ScrollMainWindowToTile(ni->data_b);
-			}
-		} break;
-		}
-	} break;
-
-	case WE_KEYPRESS:
-		if (e->we.keypress.keycode == WKC_SPACE) {
-			// Don't continue.
-			e->we.keypress.cont = false;
-			DeleteWindow(w);
-		}
-		break;
-
-	case WE_MESSAGE: /* The chatbar has notified us that is was either created or closed */
-		switch (e->we.message.msg) {
-			case WE_CREATE: w->message.msg = e->we.message.wparam; break;
-			case WE_DESTROY: w->message.msg = 0; break;
-		}
-		break;
-
-	case WE_TICK: { /* Scroll up newsmessages from the bottom in steps of 4 pixels */
-		int diff;
-		int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg);
-		if (y == w->top) return;
-
-		if (w->viewport != NULL)
-			w->viewport->top += y - w->top;
-
-		diff = abs(w->top - y);
-		w->top = y;
-
-		SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
-	} break;
-	}
-}
-
-/** Return the correct index in the pseudo-fifo
- * queue and deals with overflows when increasing the index */
-static inline NewsID increaseIndex(NewsID i)
-{
-	assert(i != INVALID_NEWS);
-	return (i + 1) % MAX_NEWS;
-}
-
-/** Return the correct index in the pseudo-fifo
- * queue and deals with overflows when decreasing the index */
-static inline NewsID decreaseIndex(NewsID i)
-{
-	assert(i != INVALID_NEWS);
-	return (i + MAX_NEWS - 1) % MAX_NEWS;
-}
-
-/** Add a new newsitem to be shown.
- * @param string String to display, can have special values based on parameter 'flags'
- * @param flags various control bits that will show various news-types. See macro NEWS_FLAGS()
- * @param data_a news-specific value based on news type
- * @param data_b news-specific value based on news type
- * @note flags exists of 4 byte-sized extra parameters.<br/>
- * 1.  0 -  7 display_mode, any of the NewsMode enums (NM_)<br/>
- * 2.  8 - 15 news flags, any of the NewsFlags enums (NF_) NF_INCOLOR are set automatically if needed<br/>
- * 3. 16 - 23 news category, any of the NewsType enums (NT_)<br/>
- * 4. 24 - 31 news callback function, any of the NewsCallback enums (DNC_)<br/>
- * If the display mode is NM_CALLBACK special news is shown and parameter
- * stringid has a special meaning.<br/>
- * DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL: StringID is
- * the index of the engine that is shown<br/>
- * DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble,
- * and 4-7 contains what kind of bankrupcy message is shown, NewsBankrupcy enum (NB_)<br/>
- * @see NewsMode
- * @see NewsFlags
- * @see NewsType
- * @see NewsCallback */
-void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b)
-{
-	NewsID l_news;
-
-	if (_game_mode == GM_MENU) return;
-
-	// check the rare case that the oldest (to be overwritten) news item is open
-	if (_total_news == MAX_NEWS && (_oldest_news == _current_news || _oldest_news == _forced_news))
-		MoveToNextItem();
-
-	_forced_news = INVALID_NEWS;
-	if (_total_news < MAX_NEWS) _total_news++;
-
-	/* Increase _latest_news. If we have no news yet, use _oldest news as an
-	 * index. We cannot use 0 as _oldest_news can jump around due to
-	 * DeleteVehicleNews */
-	l_news = _latest_news;
-	_latest_news = (_latest_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_latest_news);
-
-	/* If the fifo-buffer is full, overwrite the oldest entry */
-	if (l_news != INVALID_NEWS && _latest_news == _oldest_news) {
-		assert(_total_news == MAX_NEWS);
-		_oldest_news = increaseIndex(_oldest_news);
-	}
-
-	/*DEBUG(misc, 0) ("+cur %3d, old %2d, lat %3d, for %3d, tot %2d",
-	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
-
-	{ /* Add news to _latest_news */
-		Window *w;
-		NewsItem *ni = &_news_items[_latest_news];
-		memset(ni, 0, sizeof(*ni));
-
-		ni->string_id = string;
-		ni->display_mode = (byte)flags;
-		ni->flags = (byte)(flags >> 8);
-
-		// show this news message in color?
-		if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
-
-		ni->type = (byte)(flags >> 16);
-		ni->callback = (byte)(flags >> 24);
-		ni->data_a = data_a;
-		ni->data_b = data_b;
-		ni->date = _date;
-		COPY_OUT_DPARAM(ni->params, 0, lengthof(ni->params));
-
-		w = FindWindowById(WC_MESSAGE_HISTORY, 0);
-		if (w == NULL) return;
-		SetWindowDirty(w);
-		w->vscroll.count = _total_news;
-	}
-}
-
-
-/* Don't show item if it's older than x days, corresponds with NewsType in news.h */
-static const byte _news_items_age[] = {60, 60, 90, 60, 90, 30, 150, 30, 90, 180};
-
-static const Widget _news_type13_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   169, 0x0, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    15,     0,    10,     0,    11, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static WindowDesc _news_type13_desc = {
-	WDP_CENTER, 476, 430, 170,
-	WC_NEWS_WINDOW, 0,
-	WDF_DEF_WIDGET,
-	_news_type13_widgets,
-	NewsWindowProc
-};
-
-static const Widget _news_type2_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   129, 0x0, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    15,     0,    10,     0,    11, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static WindowDesc _news_type2_desc = {
-	WDP_CENTER, 476, 430, 130,
-	WC_NEWS_WINDOW, 0,
-	WDF_DEF_WIDGET,
-	_news_type2_widgets,
-	NewsWindowProc
-};
-
-static const Widget _news_type0_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,     5,     0,   279,    14,    86, 0x0,              STR_NULL},
-{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   279,     0,    13, STR_012C_MESSAGE, STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,     5,     2,   277,    16,    64, 0x0,              STR_NULL},
-{   WIDGETS_END},
-};
-
-static WindowDesc _news_type0_desc = {
-	WDP_CENTER, 476, 280, 87,
-	WC_NEWS_WINDOW, 0,
-	WDF_DEF_WIDGET,
-	_news_type0_widgets,
-	NewsWindowProc
-};
-
-static const SoundFx _news_sounds[] = {
-	SND_1D_APPLAUSE,
-	SND_1D_APPLAUSE,
-	0,
-	0,
-	0,
-	0,
-	SND_1E_OOOOH,
-	0,
-	0,
-	0
-};
-
-/** Get the value of an item of the news-display settings. This is
- * a little tricky since on/off/summary must use 2 bits to store the value
- * @param item the item whose value is requested
- * @return return the found value which is between 0-2
- */
-static inline byte GetNewsDisplayValue(byte item)
-{
-	assert(item < 10 && GB(_news_display_opt, item * 2, 2) <= 2);
-	return GB(_news_display_opt, item * 2, 2);
-}
-
-/** Set the value of an item in the news-display settings. This is
- * a little tricky since on/off/summary must use 2 bits to store the value
- * @param item the item whose value is being set
- * @param val new value
- */
-static inline void SetNewsDisplayValue(byte item, byte val)
-{
-	assert(item < 10 && val <= 2);
-	SB(_news_display_opt, item * 2, 2, val);
-}
-
-// open up an own newspaper window for the news item
-static void ShowNewspaper(NewsItem *ni)
-{
-	Window *w;
-	SoundFx sound;
-	int top;
-	ni->flags &= ~NF_FORCE_BIG;
-	ni->duration = 555;
-
-	sound = _news_sounds[ni->type];
-	if (sound != 0) SndPlayFx(sound);
-
-	top = _screen.height;
-	switch (ni->display_mode) {
-		case NM_NORMAL:
-		case NM_CALLBACK: {
-			_news_type13_desc.top = top;
-			w = AllocateWindowDesc(&_news_type13_desc);
-			if (ni->flags & NF_VIEWPORT)
-				AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
-			break;
-		}
-
-		case NM_THIN: {
-			_news_type2_desc.top = top;
-			w = AllocateWindowDesc(&_news_type2_desc);
-			if (ni->flags & NF_VIEWPORT)
-				AssignWindowViewport(w, 2, 58, 0x1AA, 0x46,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
-			break;
-		}
-
-		default: {
-			_news_type0_desc.top = top;
-			w = AllocateWindowDesc(&_news_type0_desc);
-			if (ni->flags & NF_VIEWPORT)
-				AssignWindowViewport(w, 3, 17, 0x112, 0x2F,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
-			break;
-		}
-	}
-
-	/*DEBUG(misc, 0) (" cur %3d, old %2d, lat %3d, for %3d, tot %2d",
-	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
-
-	WP(w, news_d).ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
-	w->flags4 |= WF_DISABLE_VP_SCROLL;
-}
-
-// show news item in the ticker
-static void ShowTicker(const NewsItem *ni)
-{
-	Window *w;
-
-	if (_news_ticker_sound) SndPlayFx(SND_16_MORSE);
-
-	_statusbar_news_item = *ni;
-	w = FindWindowById(WC_STATUS_BAR, 0);
-	if (w != NULL) WP(w, def_d).data_1 = 360;
-}
-
-
-// Are we ready to show another news item?
-// Only if nothing is in the newsticker and no newspaper is displayed
-static bool ReadyForNextItem(void)
-{
-	const Window *w;
-	NewsID item = (_forced_news == INVALID_NEWS) ? _current_news : _forced_news;
-	NewsItem *ni;
-
-	if (item >= MAX_NEWS) return true;
-	ni = &_news_items[item];
-
-	// Ticker message
-	// Check if the status bar message is still being displayed?
-	w = FindWindowById(WC_STATUS_BAR, 0);
-	if (w != NULL && WP(w, const def_d).data_1 > -1280) return false;
-
-	// Newspaper message, decrement duration counter
-	if (ni->duration != 0) ni->duration--;
-
-	// neither newsticker nor newspaper are running
-	return (ni->duration == 0 || FindWindowById(WC_NEWS_WINDOW, 0) == NULL);
-}
-
-static void MoveToNextItem(void)
-{
-	DeleteWindowById(WC_NEWS_WINDOW, 0);
-	_forced_news = INVALID_NEWS;
-
-	// if we're not at the last item, then move on
-	if (_current_news != _latest_news) {
-		NewsItem *ni;
-
-		_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_current_news);
-		ni = &_news_items[_current_news];
-
-		// check the date, don't show too old items
-		if (_date - _news_items_age[ni->type] > ni->date) return;
-
-		switch (GetNewsDisplayValue(ni->type)) {
-		case 0: { /* Off - show nothing only a small reminder in the status bar */
-			Window *w = FindWindowById(WC_STATUS_BAR, 0);
-
-			if (w != NULL) {
-				WP(w, def_d).data_2 = 91;
-				SetWindowDirty(w);
-			}
-			break;
-		}
-
-		case 1: /* Summary - show ticker, but if forced big, cascade to full */
-			if (!(ni->flags & NF_FORCE_BIG)) {
-				ShowTicker(ni);
-				break;
-			}
-			/* Fallthrough */
-
-		case 2: /* Full - show newspaper*/
-			ShowNewspaper(ni);
-			break;
-		}
-	}
-}
-
-void NewsLoop(void)
-{
-	// no news item yet
-	if (_total_news == 0) return;
-
-	if (ReadyForNextItem()) MoveToNextItem();
-}
-
-/* Do a forced show of a specific message */
-static void ShowNewsMessage(NewsID i)
-{
-	if (_total_news == 0) return;
-
-	// Delete the news window
-	DeleteWindowById(WC_NEWS_WINDOW, 0);
-
-	// setup forced news item
-	_forced_news = i;
-
-	if (_forced_news != INVALID_NEWS) {
-		NewsItem *ni = &_news_items[_forced_news];
-		ni->duration = 555;
-		ni->flags |= NF_FORCE_BIG;
-		DeleteWindowById(WC_NEWS_WINDOW, 0);
-		ShowNewspaper(ni);
-	}
-}
-
-void ShowLastNewsMessage(void)
-{
-	switch (_forced_news) {
-		case INVALID_NEWS: // Not forced any news yet, show the current one
-			ShowNewsMessage(_current_news);
-			break;
-		case 0: //
-			ShowNewsMessage(_total_news != MAX_NEWS ? _latest_news : MAX_NEWS - 1);
-			break;
-		default: // 'Scrolling' through news history show each one in turn
-			ShowNewsMessage(_forced_news - 1);
-			break;
-	}
-}
-
-
-/* return news by number, with 0 being the most
- * recent news. Returns INVALID_NEWS if end of queue reached. */
-static NewsID getNews(NewsID i)
-{
-	if (i >= _total_news) return INVALID_NEWS;
-
-	if (_latest_news < i) {
-		i = _latest_news + MAX_NEWS - i;
-	} else {
-		i = _latest_news - i;
-	}
-
-	i %= MAX_NEWS;
-	return i;
-}
-
-/** Draw an unformatted news message truncated to a maximum length. If
- * length exceeds maximum length it will be postfixed by '...'
- * @param x,y position of the string
- * @param color the color the string will be shown in
- * @param *ni NewsItem being printed
- * @param maxw maximum width of string in pixels
- */
-static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw)
-{
-	char buffer[512], buffer2[512];
-	const char *ptr;
-	char *dest;
-	StringID str;
-
-	if (ni->display_mode == 3) {
-		str = _get_news_string_callback[ni->callback](ni);
-	} else {
-		COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
-		str = ni->string_id;
-	}
-
-	GetString(buffer, str, lastof(buffer));
-	/* Copy the just gotten string to another buffer to remove any formatting
-	 * from it such as big fonts, etc. */
-	ptr  = buffer;
-	dest = buffer2;
-	for (;;) {
-		WChar c = Utf8Consume(&ptr);
-		if (c == 0) break;
-		if (c == '\r') {
-			dest[0] = dest[1] = dest[2] = dest[3] = ' ';
-			dest += 4;
-		} else if (IsPrintable(c)) {
-			dest += Utf8Encode(dest, c);
-		}
-	}
-
-	*dest = '\0';
-	/* Truncate and show string; postfixed by '...' if neccessary */
-	DoDrawStringTruncated(buffer2, x, y, color, maxw);
-}
-
-
-static void MessageHistoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int y = 19;
-		NewsID p, show;
-
-		SetVScrollCount(w, _total_news);
-		DrawWindowWidgets(w);
-
-		if (_total_news == 0) break;
-		show = min(_total_news, w->vscroll.cap);
-
-		for (p = w->vscroll.pos; p < w->vscroll.pos + show; p++) {
-			// get news in correct order
-			const NewsItem *ni = &_news_items[getNews(p)];
-
-			SetDParam(0, ni->date);
-			DrawString(4, y, STR_SHORT_DATE, 12);
-
-			DrawNewsString(82, y, 12, ni, w->width - 95);
-			y += 12;
-		}
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: {
-			int y = (e->we.click.pt.y - 19) / 12;
-			NewsID p = getNews(y + w->vscroll.pos);
-
-			if (p == INVALID_NEWS) break;
-
-			ShowNewsMessage(p);
-			break;
-		}
-		}
-		break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 12;
-		break;
-	}
-}
-
-static const Widget _message_history_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    13,    11,   387,     0,    13, STR_MESSAGE_HISTORY, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,     RESIZE_LR,    13,   388,   399,     0,    13, 0x0,                 STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_RB,    13,     0,   387,    14,   139, 0x0,                 STR_MESSAGE_HISTORY_TIP},
-{  WWT_SCROLLBAR,    RESIZE_LRB,    13,   388,   399,    14,   127, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    13,   388,   399,   128,   139, 0x0,                 STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _message_history_desc = {
-	240, 22, 400, 140,
-	WC_MESSAGE_HISTORY, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_message_history_widgets,
-	MessageHistoryWndProc
-};
-
-void ShowMessageHistory(void)
-{
-	Window *w;
-
-	DeleteWindowById(WC_MESSAGE_HISTORY, 0);
-	w = AllocateWindowDesc(&_message_history_desc);
-
-	if (w != NULL) {
-		w->vscroll.cap = 10;
-		w->vscroll.count = _total_news;
-		w->resize.step_height = 12;
-		w->resize.height = w->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
-		w->resize.step_width = 1;
-		w->resize.width = 200; // can't make window any smaller than 200 pixel
-		SetWindowDirty(w);
-	}
-}
-
-/** Setup the disabled/enabled buttons in the message window
- * If the value is 'off' disable the [<] widget, and enable the [>] one
- * Same-wise for all the others. Starting value of 3 is the first widget
- * group. These are grouped as [<][>] .. [<][>], etc.
- */
-static void SetMessageButtonStates(Window *w, byte value, int element)
-{
-	element *= 2;
-
-	SetWindowWidgetDisabledState(w, element + 3, value == 0);
-	SetWindowWidgetDisabledState(w, element + 3 + 1, value == 2);
-}
-
-static void MessageOptionsWndProc(Window *w, WindowEvent *e)
-{
-	static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
-
-	/* WP(w, def_d).data_1 are stores the clicked state of the fake widgets
-	 * WP(w, def_d).data_2 stores state of the ALL on/off/summary button */
-	switch (e->event) {
-	case WE_CREATE: {
-		uint32 val = _news_display_opt;
-		int i;
-		WP(w, def_d).data_1 = WP(w, def_d).data_2 = 0;
-
-		// Set up the initial disabled buttons in the case of 'off' or 'full'
-		for (i = 0; i != 10; i++, val >>= 2) SetMessageButtonStates(w, val & 0x3, i);
-	} break;
-
-	case WE_PAINT: {
-		uint32 val = _news_display_opt;
-		int click_state = WP(w, def_d).data_1;
-		int i, y;
-
-		if (_news_ticker_sound) LowerWindowWidget(w, 25);
-		DrawWindowWidgets(w);
-
-		/* XXX - Draw the fake widgets-buttons. Can't add these to the widget-desc since
-		 * openttd currently can only handle 32 widgets. So hack it *g* */
-		for (i = 0, y = 26; i != 10; i++, y += 12, click_state >>= 1, val >>= 2) {
-			bool clicked = !!(click_state & 1);
-
-			DrawFrameRect(13, y, 89, 11 + y, 3, (clicked) ? FR_LOWERED : 0);
-			DrawStringCentered(((13 + 89 + 1) >> 1) + clicked, ((y + 11 + y + 1) >> 1) - 5 + clicked, message_opt[val & 0x3], 0x10);
-			DrawString(103, y + 1, i + STR_0206_ARRIVAL_OF_FIRST_VEHICLE, 0);
-		}
-
-		DrawString(  8, y + 9, message_opt[WP(w, def_d).data_2], 0x10);
-		DrawString(103, y + 9, STR_MESSAGES_ALL, 0);
-		DrawString(103, y + 9 + 12, STR_MESSAGE_SOUND, 0);
-
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: /* Clicked on any of the fake widgets */
-			if (e->we.click.pt.x > 13 && e->we.click.pt.x < 89 && e->we.click.pt.y > 26 && e->we.click.pt.y < 146) {
-				int element = (e->we.click.pt.y - 26) / 12;
-				byte val = (GetNewsDisplayValue(element) + 1) % 3;
-
-				SetMessageButtonStates(w, val, element);
-				SetNewsDisplayValue(element, val);
-
-				WP(w, def_d).data_1 |= (1 << element);
-				w->flags4 |= 5 << WF_TIMEOUT_SHL; // XXX - setup unclick (fake widget)
-				SetWindowDirty(w);
-			}
-			break;
-		case 23: case 24: /* Dropdown menu for all settings */
-			ShowDropDownMenu(w, message_opt, WP(w, def_d).data_2, 24, 0, 0);
-			break;
-		case 25: /* Change ticker sound on/off */
-			_news_ticker_sound ^= 1;
-			ToggleWidgetLoweredState(w, e->we.click.widget);
-			InvalidateWidget(w, e->we.click.widget);
-			break;
-		default: { /* Clicked on the [<] .. [>] widgets */
-			int wid = e->we.click.widget;
-			if (wid > 2 && wid < 23) {
-				int element = (wid - 3) / 2;
-				byte val = (GetNewsDisplayValue(element) + ((wid & 1) ? -1 : 1)) % 3;
-
-				SetMessageButtonStates(w, val, element);
-				SetNewsDisplayValue(element, val);
-				SetWindowDirty(w);
-			}
-		} break;
-		} break;
-
-	case WE_DROPDOWN_SELECT: {/* Select all settings for newsmessages */
-		int i;
-
-		WP(w, def_d).data_2 = e->we.dropdown.index;
-
-		for (i = 0; i != 10; i++) {
-			SB(_news_display_opt, i*2, 2, e->we.dropdown.index);
-			SetMessageButtonStates(w, e->we.dropdown.index, i);
-		}
-		SetWindowDirty(w);
-		break;
-		}
-
-	case WE_TIMEOUT: /* XXX - Hack to animate 'fake' buttons */
-		WP(w, def_d).data_1 = 0;
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const Widget _message_options_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,   10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,  409,     0,    13, STR_0204_MESSAGE_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,  409,    14,   184, 0x0,                      STR_NULL},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    26,    37, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    26,    37, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    38,    49, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    38,    49, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    50,    61, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    50,    61, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    62,    73, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    62,    73, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    74,    85, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    74,    85, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    86,    97, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    86,    97, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    98,   109, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    98,   109, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   110,   121, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   110,   121, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   122,   133, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   122,   133, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   134,   145, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   134,   145, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
-
-{      WWT_PANEL,   RESIZE_NONE,     3,     4,   86,   154,   165, 0x0,                      STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,    87,   98,   154,   165, STR_0225,                 STR_NULL},
-{  WWT_TEXTBTN_2,   RESIZE_NONE,     3,     4,   98,   166,   177, STR_02DB_OFF,             STR_NULL},
-
-{      WWT_LABEL,   RESIZE_NONE,    13,     0,  409,    13,    26, STR_0205_MESSAGE_TYPES,   STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _message_options_desc = {
-	270, 22, 410, 185,
-	WC_GAME_OPTIONS, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_message_options_widgets,
-	MessageOptionsWndProc
-};
-
-void ShowMessageOptions(void)
-{
-	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	AllocateWindowDesc(&_message_options_desc);
-}
-
-
-void DeleteVehicleNews(VehicleID vid, StringID news)
-{
-	NewsID n;
-
-	for (n = _oldest_news; _latest_news != INVALID_NEWS; n = increaseIndex(n)) {
-		const NewsItem *ni = &_news_items[n];
-
-		if (ni->flags & NF_VEHICLE &&
-				ni->data_a == vid &&
-				(news == INVALID_STRING_ID || ni->string_id == news)) {
-			Window *w;
-
-			if (_forced_news == n || _current_news == n) MoveToNextItem();
-			_total_news--;
-
-			/* If this is the last news item, invalidate _latest_news */
-			if (_total_news == 0) {
-				assert(_latest_news == _oldest_news);
-				_latest_news = INVALID_NEWS;
-			}
-
-			/* Since we only imitate a FIFO removing an arbitrary element does need
-			 * some magic. Remove the item by shifting head towards the tail. eg
-			 *    oldest    remove  last
-			 *        |        |     |
-			 * [------O--------n-----L--]
-			 * will become (change dramatized to make clear)
-			 * [---------O-----------L--]
-			 * We also need an update of the current, forced and visible (open window)
-			 * news's as this shifting could change the items they were pointing to */
-			if (_total_news != 0) {
-				NewsID i, visible_news;
-				w = FindWindowById(WC_NEWS_WINDOW, 0);
-				visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS;
-
-				for (i = n;; i = decreaseIndex(i)) {
-					_news_items[i] = _news_items[decreaseIndex(i)];
-
-					if (i == _current_news) _current_news = increaseIndex(_current_news);
-					if (i == _forced_news) _forced_news = increaseIndex(_forced_news);
-					if (i == visible_news) WP(w, news_d).ni = &_news_items[increaseIndex(visible_news)];
-
-					if (i == _oldest_news) break;
-				}
-				_oldest_news = increaseIndex(_oldest_news);
-			}
-
-			/*DEBUG(misc, 0) ("-cur %3d, old %2d, lat %3d, for %3d, tot %2d",
-			  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
-
-			w = FindWindowById(WC_MESSAGE_HISTORY, 0);
-			if (w != NULL) {
-				SetWindowDirty(w);
-				w->vscroll.count = _total_news;
-			}
-		}
-
-		if (n == _latest_news) break;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/news_gui.cpp
@@ -0,0 +1,939 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "news.h"
+#include "vehicle.h"
+#include "sound.h"
+#include "variables.h"
+#include "date.h"
+#include "string.h"
+
+/* News system
+ * News system is realized as a FIFO queue (in an array)
+ * The positions in the queue can't be rearranged, we only access
+ * the array elements through pointers to the elements. Once the
+ * array is full, the oldest entry (_oldest_news) is being overwritten
+ * by the newest (_latest news).
+ *
+ * oldest                   current   lastest
+ *  |                          |         |
+ * [O------------F-------------C---------L           ]
+ *               |
+ *            forced
+ *
+ * Of course by using an array we can have situations like
+ *
+ * [----L          O-----F---------C-----------------]
+ * This is where we have wrapped around the array and have
+ * (MAX_NEWS - O) + L news items
+ */
+
+#define MAX_NEWS 30
+
+typedef byte NewsID;
+#define INVALID_NEWS 255
+
+static NewsItem _news_items[MAX_NEWS];
+static NewsID _current_news = INVALID_NEWS; // points to news item that should be shown next
+static NewsID _oldest_news = 0;    // points to first item in fifo queue
+static NewsID _latest_news = INVALID_NEWS;  // points to last item in fifo queue
+/* if the message being shown was forced by the user, its index is stored in
+ * _forced_news. forced_news is INVALID_NEWS otherwise.
+ * (Users can force messages through history or "last message") */
+static NewsID _forced_news = INVALID_NEWS;
+
+static byte _total_news = 0; // total news count
+
+void DrawNewsNewTrainAvail(Window *w);
+void DrawNewsNewRoadVehAvail(Window *w);
+void DrawNewsNewShipAvail(Window *w);
+void DrawNewsNewAircraftAvail(Window *w);
+void DrawNewsBankrupcy(Window *w);
+static void MoveToNextItem(void);
+
+StringID GetNewsStringNewTrainAvail(const NewsItem *ni);
+StringID GetNewsStringNewRoadVehAvail(const NewsItem *ni);
+StringID GetNewsStringNewShipAvail(const NewsItem *ni);
+StringID GetNewsStringNewAircraftAvail(const NewsItem *ni);
+StringID GetNewsStringBankrupcy(const NewsItem *ni);
+
+static DrawNewsCallbackProc * const _draw_news_callback[] = {
+	DrawNewsNewTrainAvail,    /* DNC_TRAINAVAIL */
+	DrawNewsNewRoadVehAvail,  /* DNC_ROADAVAIL */
+	DrawNewsNewShipAvail,     /* DNC_SHIPAVAIL */
+	DrawNewsNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
+	DrawNewsBankrupcy,        /* DNC_BANKRUPCY */
+};
+
+GetNewsStringCallbackProc * const _get_news_string_callback[] = {
+	GetNewsStringNewTrainAvail,    /* DNC_TRAINAVAIL */
+	GetNewsStringNewRoadVehAvail,  /* DNC_ROADAVAIL */
+	GetNewsStringNewShipAvail,     /* DNC_SHIPAVAIL */
+	GetNewsStringNewAircraftAvail, /* DNC_AIRCRAFTAVAIL */
+	GetNewsStringBankrupcy,        /* DNC_BANKRUPCY */
+};
+
+void InitNewsItemStructs(void)
+{
+	memset(_news_items, 0, sizeof(_news_items));
+	_current_news = INVALID_NEWS;
+	_oldest_news = 0;
+	_latest_news = INVALID_NEWS;
+	_forced_news = INVALID_NEWS;
+	_total_news = 0;
+}
+
+void DrawNewsBorder(const Window *w)
+{
+	int left = 0;
+	int right = w->width - 1;
+	int top = 0;
+	int bottom = w->height - 1;
+
+	GfxFillRect(left, top, right, bottom, 0xF);
+
+	GfxFillRect(left, top, left, bottom, 0xD7);
+	GfxFillRect(right, top, right, bottom, 0xD7);
+	GfxFillRect(left, top, right, top, 0xD7);
+	GfxFillRect(left, bottom, right, bottom, 0xD7);
+
+	DrawString(left + 2, top + 1, STR_00C6, 0);
+}
+
+static void NewsWindowProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: { /* If chatbar is open at creation time, we need to go above it */
+		const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0);
+		w->message.msg = (w1 != NULL) ? w1->height : 0;
+	} break;
+
+	case WE_PAINT: {
+		const NewsItem *ni = WP(w, news_d).ni;
+		ViewPort *vp;
+
+		switch (ni->display_mode) {
+			case NM_NORMAL:
+			case NM_THIN: {
+				DrawNewsBorder(w);
+
+				DrawString(2, 1, STR_00C6, 0);
+
+				SetDParam(0, ni->date);
+				DrawStringRightAligned(428, 1, STR_01FF, 0);
+
+				if (!(ni->flags & NF_VIEWPORT)) {
+					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+					DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
+						ni->string_id, 426);
+				} else {
+					byte bk = _display_opt;
+					_display_opt &= ~DO_TRANS_BUILDINGS;
+					DrawWindowViewport(w);
+					_display_opt = bk;
+
+					/* Shade the viewport into gray, or color*/
+					vp = w->viewport;
+					GfxFillRect(vp->left - w->left, vp->top - w->top,
+						vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
+						(ni->flags & NF_INCOLOR ? 0x322 : 0x323) | USE_COLORTABLE
+					);
+
+					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+					DrawStringMultiCenter(w->width / 2, 20, ni->string_id, 428);
+				}
+				break;
+			}
+
+			case NM_CALLBACK: {
+				_draw_news_callback[ni->callback](w);
+				break;
+			}
+
+			default: {
+				DrawWindowWidgets(w);
+				if (!(ni->flags & NF_VIEWPORT)) {
+					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+					DrawStringMultiCenter(140, 38, ni->string_id, 276);
+				} else {
+					DrawWindowViewport(w);
+					COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+					DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, 276);
+				}
+				break;
+			}
+		}
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 1: {
+			NewsItem *ni = WP(w, news_d).ni;
+			DeleteWindow(w);
+			ni->duration = 0;
+			_forced_news = INVALID_NEWS;
+		} break;
+		case 0: {
+			NewsItem *ni = WP(w, news_d).ni;
+			if (ni->flags & NF_VEHICLE) {
+				Vehicle *v = GetVehicle(ni->data_a);
+				ScrollMainWindowTo(v->x_pos, v->y_pos);
+			} else if (ni->flags & NF_TILE) {
+				if (!ScrollMainWindowToTile(ni->data_a) && ni->data_b != 0)
+					ScrollMainWindowToTile(ni->data_b);
+			}
+		} break;
+		}
+	} break;
+
+	case WE_KEYPRESS:
+		if (e->we.keypress.keycode == WKC_SPACE) {
+			// Don't continue.
+			e->we.keypress.cont = false;
+			DeleteWindow(w);
+		}
+		break;
+
+	case WE_MESSAGE: /* The chatbar has notified us that is was either created or closed */
+		switch (e->we.message.msg) {
+			case WE_CREATE: w->message.msg = e->we.message.wparam; break;
+			case WE_DESTROY: w->message.msg = 0; break;
+		}
+		break;
+
+	case WE_TICK: { /* Scroll up newsmessages from the bottom in steps of 4 pixels */
+		int diff;
+		int y = max(w->top - 4, _screen.height - w->height - 12 - w->message.msg);
+		if (y == w->top) return;
+
+		if (w->viewport != NULL)
+			w->viewport->top += y - w->top;
+
+		diff = abs(w->top - y);
+		w->top = y;
+
+		SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
+	} break;
+	}
+}
+
+/** Return the correct index in the pseudo-fifo
+ * queue and deals with overflows when increasing the index */
+static inline NewsID increaseIndex(NewsID i)
+{
+	assert(i != INVALID_NEWS);
+	return (i + 1) % MAX_NEWS;
+}
+
+/** Return the correct index in the pseudo-fifo
+ * queue and deals with overflows when decreasing the index */
+static inline NewsID decreaseIndex(NewsID i)
+{
+	assert(i != INVALID_NEWS);
+	return (i + MAX_NEWS - 1) % MAX_NEWS;
+}
+
+/** Add a new newsitem to be shown.
+ * @param string String to display, can have special values based on parameter 'flags'
+ * @param flags various control bits that will show various news-types. See macro NEWS_FLAGS()
+ * @param data_a news-specific value based on news type
+ * @param data_b news-specific value based on news type
+ * @note flags exists of 4 byte-sized extra parameters.<br/>
+ * 1.  0 -  7 display_mode, any of the NewsMode enums (NM_)<br/>
+ * 2.  8 - 15 news flags, any of the NewsFlags enums (NF_) NF_INCOLOR are set automatically if needed<br/>
+ * 3. 16 - 23 news category, any of the NewsType enums (NT_)<br/>
+ * 4. 24 - 31 news callback function, any of the NewsCallback enums (DNC_)<br/>
+ * If the display mode is NM_CALLBACK special news is shown and parameter
+ * stringid has a special meaning.<br/>
+ * DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL: StringID is
+ * the index of the engine that is shown<br/>
+ * DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble,
+ * and 4-7 contains what kind of bankrupcy message is shown, NewsBankrupcy enum (NB_)<br/>
+ * @see NewsMode
+ * @see NewsFlags
+ * @see NewsType
+ * @see NewsCallback */
+void AddNewsItem(StringID string, uint32 flags, uint data_a, uint data_b)
+{
+	NewsID l_news;
+
+	if (_game_mode == GM_MENU) return;
+
+	// check the rare case that the oldest (to be overwritten) news item is open
+	if (_total_news == MAX_NEWS && (_oldest_news == _current_news || _oldest_news == _forced_news))
+		MoveToNextItem();
+
+	_forced_news = INVALID_NEWS;
+	if (_total_news < MAX_NEWS) _total_news++;
+
+	/* Increase _latest_news. If we have no news yet, use _oldest news as an
+	 * index. We cannot use 0 as _oldest_news can jump around due to
+	 * DeleteVehicleNews */
+	l_news = _latest_news;
+	_latest_news = (_latest_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_latest_news);
+
+	/* If the fifo-buffer is full, overwrite the oldest entry */
+	if (l_news != INVALID_NEWS && _latest_news == _oldest_news) {
+		assert(_total_news == MAX_NEWS);
+		_oldest_news = increaseIndex(_oldest_news);
+	}
+
+	/*DEBUG(misc, 0) ("+cur %3d, old %2d, lat %3d, for %3d, tot %2d",
+	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
+
+	{ /* Add news to _latest_news */
+		Window *w;
+		NewsItem *ni = &_news_items[_latest_news];
+		memset(ni, 0, sizeof(*ni));
+
+		ni->string_id = string;
+		ni->display_mode = (byte)flags;
+		ni->flags = (byte)(flags >> 8);
+
+		// show this news message in color?
+		if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
+
+		ni->type = (byte)(flags >> 16);
+		ni->callback = (byte)(flags >> 24);
+		ni->data_a = data_a;
+		ni->data_b = data_b;
+		ni->date = _date;
+		COPY_OUT_DPARAM(ni->params, 0, lengthof(ni->params));
+
+		w = FindWindowById(WC_MESSAGE_HISTORY, 0);
+		if (w == NULL) return;
+		SetWindowDirty(w);
+		w->vscroll.count = _total_news;
+	}
+}
+
+
+/* Don't show item if it's older than x days, corresponds with NewsType in news.h */
+static const byte _news_items_age[] = {60, 60, 90, 60, 90, 30, 150, 30, 90, 180};
+
+static const Widget _news_type13_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   169, 0x0, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    15,     0,    10,     0,    11, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static WindowDesc _news_type13_desc = {
+	WDP_CENTER, 476, 430, 170,
+	WC_NEWS_WINDOW, 0,
+	WDF_DEF_WIDGET,
+	_news_type13_widgets,
+	NewsWindowProc
+};
+
+static const Widget _news_type2_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,    15,     0,   429,     0,   129, 0x0, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    15,     0,    10,     0,    11, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static WindowDesc _news_type2_desc = {
+	WDP_CENTER, 476, 430, 130,
+	WC_NEWS_WINDOW, 0,
+	WDF_DEF_WIDGET,
+	_news_type2_widgets,
+	NewsWindowProc
+};
+
+static const Widget _news_type0_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,     5,     0,   279,    14,    86, 0x0,              STR_NULL},
+{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   279,     0,    13, STR_012C_MESSAGE, STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,     5,     2,   277,    16,    64, 0x0,              STR_NULL},
+{   WIDGETS_END},
+};
+
+static WindowDesc _news_type0_desc = {
+	WDP_CENTER, 476, 280, 87,
+	WC_NEWS_WINDOW, 0,
+	WDF_DEF_WIDGET,
+	_news_type0_widgets,
+	NewsWindowProc
+};
+
+static const SoundFx _news_sounds[] = {
+	SND_1D_APPLAUSE,
+	SND_1D_APPLAUSE,
+	0,
+	0,
+	0,
+	0,
+	SND_1E_OOOOH,
+	0,
+	0,
+	0
+};
+
+/** Get the value of an item of the news-display settings. This is
+ * a little tricky since on/off/summary must use 2 bits to store the value
+ * @param item the item whose value is requested
+ * @return return the found value which is between 0-2
+ */
+static inline byte GetNewsDisplayValue(byte item)
+{
+	assert(item < 10 && GB(_news_display_opt, item * 2, 2) <= 2);
+	return GB(_news_display_opt, item * 2, 2);
+}
+
+/** Set the value of an item in the news-display settings. This is
+ * a little tricky since on/off/summary must use 2 bits to store the value
+ * @param item the item whose value is being set
+ * @param val new value
+ */
+static inline void SetNewsDisplayValue(byte item, byte val)
+{
+	assert(item < 10 && val <= 2);
+	SB(_news_display_opt, item * 2, 2, val);
+}
+
+// open up an own newspaper window for the news item
+static void ShowNewspaper(NewsItem *ni)
+{
+	Window *w;
+	SoundFx sound;
+	int top;
+	ni->flags &= ~NF_FORCE_BIG;
+	ni->duration = 555;
+
+	sound = _news_sounds[ni->type];
+	if (sound != 0) SndPlayFx(sound);
+
+	top = _screen.height;
+	switch (ni->display_mode) {
+		case NM_NORMAL:
+		case NM_CALLBACK: {
+			_news_type13_desc.top = top;
+			w = AllocateWindowDesc(&_news_type13_desc);
+			if (ni->flags & NF_VIEWPORT)
+				AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E,
+					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
+			break;
+		}
+
+		case NM_THIN: {
+			_news_type2_desc.top = top;
+			w = AllocateWindowDesc(&_news_type2_desc);
+			if (ni->flags & NF_VIEWPORT)
+				AssignWindowViewport(w, 2, 58, 0x1AA, 0x46,
+					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
+			break;
+		}
+
+		default: {
+			_news_type0_desc.top = top;
+			w = AllocateWindowDesc(&_news_type0_desc);
+			if (ni->flags & NF_VIEWPORT)
+				AssignWindowViewport(w, 3, 17, 0x112, 0x2F,
+					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), 0);
+			break;
+		}
+	}
+
+	/*DEBUG(misc, 0) (" cur %3d, old %2d, lat %3d, for %3d, tot %2d",
+	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
+
+	WP(w, news_d).ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
+	w->flags4 |= WF_DISABLE_VP_SCROLL;
+}
+
+// show news item in the ticker
+static void ShowTicker(const NewsItem *ni)
+{
+	Window *w;
+
+	if (_news_ticker_sound) SndPlayFx(SND_16_MORSE);
+
+	_statusbar_news_item = *ni;
+	w = FindWindowById(WC_STATUS_BAR, 0);
+	if (w != NULL) WP(w, def_d).data_1 = 360;
+}
+
+
+// Are we ready to show another news item?
+// Only if nothing is in the newsticker and no newspaper is displayed
+static bool ReadyForNextItem(void)
+{
+	const Window *w;
+	NewsID item = (_forced_news == INVALID_NEWS) ? _current_news : _forced_news;
+	NewsItem *ni;
+
+	if (item >= MAX_NEWS) return true;
+	ni = &_news_items[item];
+
+	// Ticker message
+	// Check if the status bar message is still being displayed?
+	w = FindWindowById(WC_STATUS_BAR, 0);
+	if (w != NULL && WP(w, const def_d).data_1 > -1280) return false;
+
+	// Newspaper message, decrement duration counter
+	if (ni->duration != 0) ni->duration--;
+
+	// neither newsticker nor newspaper are running
+	return (ni->duration == 0 || FindWindowById(WC_NEWS_WINDOW, 0) == NULL);
+}
+
+static void MoveToNextItem(void)
+{
+	DeleteWindowById(WC_NEWS_WINDOW, 0);
+	_forced_news = INVALID_NEWS;
+
+	// if we're not at the last item, then move on
+	if (_current_news != _latest_news) {
+		NewsItem *ni;
+
+		_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : increaseIndex(_current_news);
+		ni = &_news_items[_current_news];
+
+		// check the date, don't show too old items
+		if (_date - _news_items_age[ni->type] > ni->date) return;
+
+		switch (GetNewsDisplayValue(ni->type)) {
+		case 0: { /* Off - show nothing only a small reminder in the status bar */
+			Window *w = FindWindowById(WC_STATUS_BAR, 0);
+
+			if (w != NULL) {
+				WP(w, def_d).data_2 = 91;
+				SetWindowDirty(w);
+			}
+			break;
+		}
+
+		case 1: /* Summary - show ticker, but if forced big, cascade to full */
+			if (!(ni->flags & NF_FORCE_BIG)) {
+				ShowTicker(ni);
+				break;
+			}
+			/* Fallthrough */
+
+		case 2: /* Full - show newspaper*/
+			ShowNewspaper(ni);
+			break;
+		}
+	}
+}
+
+void NewsLoop(void)
+{
+	// no news item yet
+	if (_total_news == 0) return;
+
+	if (ReadyForNextItem()) MoveToNextItem();
+}
+
+/* Do a forced show of a specific message */
+static void ShowNewsMessage(NewsID i)
+{
+	if (_total_news == 0) return;
+
+	// Delete the news window
+	DeleteWindowById(WC_NEWS_WINDOW, 0);
+
+	// setup forced news item
+	_forced_news = i;
+
+	if (_forced_news != INVALID_NEWS) {
+		NewsItem *ni = &_news_items[_forced_news];
+		ni->duration = 555;
+		ni->flags |= NF_FORCE_BIG;
+		DeleteWindowById(WC_NEWS_WINDOW, 0);
+		ShowNewspaper(ni);
+	}
+}
+
+void ShowLastNewsMessage(void)
+{
+	switch (_forced_news) {
+		case INVALID_NEWS: // Not forced any news yet, show the current one
+			ShowNewsMessage(_current_news);
+			break;
+		case 0: //
+			ShowNewsMessage(_total_news != MAX_NEWS ? _latest_news : MAX_NEWS - 1);
+			break;
+		default: // 'Scrolling' through news history show each one in turn
+			ShowNewsMessage(_forced_news - 1);
+			break;
+	}
+}
+
+
+/* return news by number, with 0 being the most
+ * recent news. Returns INVALID_NEWS if end of queue reached. */
+static NewsID getNews(NewsID i)
+{
+	if (i >= _total_news) return INVALID_NEWS;
+
+	if (_latest_news < i) {
+		i = _latest_news + MAX_NEWS - i;
+	} else {
+		i = _latest_news - i;
+	}
+
+	i %= MAX_NEWS;
+	return i;
+}
+
+/** Draw an unformatted news message truncated to a maximum length. If
+ * length exceeds maximum length it will be postfixed by '...'
+ * @param x,y position of the string
+ * @param color the color the string will be shown in
+ * @param *ni NewsItem being printed
+ * @param maxw maximum width of string in pixels
+ */
+static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw)
+{
+	char buffer[512], buffer2[512];
+	const char *ptr;
+	char *dest;
+	StringID str;
+
+	if (ni->display_mode == 3) {
+		str = _get_news_string_callback[ni->callback](ni);
+	} else {
+		COPY_IN_DPARAM(0, ni->params, lengthof(ni->params));
+		str = ni->string_id;
+	}
+
+	GetString(buffer, str, lastof(buffer));
+	/* Copy the just gotten string to another buffer to remove any formatting
+	 * from it such as big fonts, etc. */
+	ptr  = buffer;
+	dest = buffer2;
+	for (;;) {
+		WChar c = Utf8Consume(&ptr);
+		if (c == 0) break;
+		if (c == '\r') {
+			dest[0] = dest[1] = dest[2] = dest[3] = ' ';
+			dest += 4;
+		} else if (IsPrintable(c)) {
+			dest += Utf8Encode(dest, c);
+		}
+	}
+
+	*dest = '\0';
+	/* Truncate and show string; postfixed by '...' if neccessary */
+	DoDrawStringTruncated(buffer2, x, y, color, maxw);
+}
+
+
+static void MessageHistoryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int y = 19;
+		NewsID p, show;
+
+		SetVScrollCount(w, _total_news);
+		DrawWindowWidgets(w);
+
+		if (_total_news == 0) break;
+		show = min(_total_news, w->vscroll.cap);
+
+		for (p = w->vscroll.pos; p < w->vscroll.pos + show; p++) {
+			// get news in correct order
+			const NewsItem *ni = &_news_items[getNews(p)];
+
+			SetDParam(0, ni->date);
+			DrawString(4, y, STR_SHORT_DATE, 12);
+
+			DrawNewsString(82, y, 12, ni, w->width - 95);
+			y += 12;
+		}
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: {
+			int y = (e->we.click.pt.y - 19) / 12;
+			NewsID p = getNews(y + w->vscroll.pos);
+
+			if (p == INVALID_NEWS) break;
+
+			ShowNewsMessage(p);
+			break;
+		}
+		}
+		break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 12;
+		break;
+	}
+}
+
+static const Widget _message_history_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    13,    11,   387,     0,    13, STR_MESSAGE_HISTORY, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,     RESIZE_LR,    13,   388,   399,     0,    13, 0x0,                 STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_RB,    13,     0,   387,    14,   139, 0x0,                 STR_MESSAGE_HISTORY_TIP},
+{  WWT_SCROLLBAR,    RESIZE_LRB,    13,   388,   399,    14,   127, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    13,   388,   399,   128,   139, 0x0,                 STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _message_history_desc = {
+	240, 22, 400, 140,
+	WC_MESSAGE_HISTORY, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_message_history_widgets,
+	MessageHistoryWndProc
+};
+
+void ShowMessageHistory(void)
+{
+	Window *w;
+
+	DeleteWindowById(WC_MESSAGE_HISTORY, 0);
+	w = AllocateWindowDesc(&_message_history_desc);
+
+	if (w != NULL) {
+		w->vscroll.cap = 10;
+		w->vscroll.count = _total_news;
+		w->resize.step_height = 12;
+		w->resize.height = w->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
+		w->resize.step_width = 1;
+		w->resize.width = 200; // can't make window any smaller than 200 pixel
+		SetWindowDirty(w);
+	}
+}
+
+/** Setup the disabled/enabled buttons in the message window
+ * If the value is 'off' disable the [<] widget, and enable the [>] one
+ * Same-wise for all the others. Starting value of 3 is the first widget
+ * group. These are grouped as [<][>] .. [<][>], etc.
+ */
+static void SetMessageButtonStates(Window *w, byte value, int element)
+{
+	element *= 2;
+
+	SetWindowWidgetDisabledState(w, element + 3, value == 0);
+	SetWindowWidgetDisabledState(w, element + 3 + 1, value == 2);
+}
+
+static void MessageOptionsWndProc(Window *w, WindowEvent *e)
+{
+	static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
+
+	/* WP(w, def_d).data_1 are stores the clicked state of the fake widgets
+	 * WP(w, def_d).data_2 stores state of the ALL on/off/summary button */
+	switch (e->event) {
+	case WE_CREATE: {
+		uint32 val = _news_display_opt;
+		int i;
+		WP(w, def_d).data_1 = WP(w, def_d).data_2 = 0;
+
+		// Set up the initial disabled buttons in the case of 'off' or 'full'
+		for (i = 0; i != 10; i++, val >>= 2) SetMessageButtonStates(w, val & 0x3, i);
+	} break;
+
+	case WE_PAINT: {
+		uint32 val = _news_display_opt;
+		int click_state = WP(w, def_d).data_1;
+		int i, y;
+
+		if (_news_ticker_sound) LowerWindowWidget(w, 25);
+		DrawWindowWidgets(w);
+
+		/* XXX - Draw the fake widgets-buttons. Can't add these to the widget-desc since
+		 * openttd currently can only handle 32 widgets. So hack it *g* */
+		for (i = 0, y = 26; i != 10; i++, y += 12, click_state >>= 1, val >>= 2) {
+			bool clicked = !!(click_state & 1);
+
+			DrawFrameRect(13, y, 89, 11 + y, 3, (clicked) ? FR_LOWERED : 0);
+			DrawStringCentered(((13 + 89 + 1) >> 1) + clicked, ((y + 11 + y + 1) >> 1) - 5 + clicked, message_opt[val & 0x3], 0x10);
+			DrawString(103, y + 1, i + STR_0206_ARRIVAL_OF_FIRST_VEHICLE, 0);
+		}
+
+		DrawString(  8, y + 9, message_opt[WP(w, def_d).data_2], 0x10);
+		DrawString(103, y + 9, STR_MESSAGES_ALL, 0);
+		DrawString(103, y + 9 + 12, STR_MESSAGE_SOUND, 0);
+
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: /* Clicked on any of the fake widgets */
+			if (e->we.click.pt.x > 13 && e->we.click.pt.x < 89 && e->we.click.pt.y > 26 && e->we.click.pt.y < 146) {
+				int element = (e->we.click.pt.y - 26) / 12;
+				byte val = (GetNewsDisplayValue(element) + 1) % 3;
+
+				SetMessageButtonStates(w, val, element);
+				SetNewsDisplayValue(element, val);
+
+				WP(w, def_d).data_1 |= (1 << element);
+				w->flags4 |= 5 << WF_TIMEOUT_SHL; // XXX - setup unclick (fake widget)
+				SetWindowDirty(w);
+			}
+			break;
+		case 23: case 24: /* Dropdown menu for all settings */
+			ShowDropDownMenu(w, message_opt, WP(w, def_d).data_2, 24, 0, 0);
+			break;
+		case 25: /* Change ticker sound on/off */
+			_news_ticker_sound ^= 1;
+			ToggleWidgetLoweredState(w, e->we.click.widget);
+			InvalidateWidget(w, e->we.click.widget);
+			break;
+		default: { /* Clicked on the [<] .. [>] widgets */
+			int wid = e->we.click.widget;
+			if (wid > 2 && wid < 23) {
+				int element = (wid - 3) / 2;
+				byte val = (GetNewsDisplayValue(element) + ((wid & 1) ? -1 : 1)) % 3;
+
+				SetMessageButtonStates(w, val, element);
+				SetNewsDisplayValue(element, val);
+				SetWindowDirty(w);
+			}
+		} break;
+		} break;
+
+	case WE_DROPDOWN_SELECT: {/* Select all settings for newsmessages */
+		int i;
+
+		WP(w, def_d).data_2 = e->we.dropdown.index;
+
+		for (i = 0; i != 10; i++) {
+			SB(_news_display_opt, i*2, 2, e->we.dropdown.index);
+			SetMessageButtonStates(w, e->we.dropdown.index, i);
+		}
+		SetWindowDirty(w);
+		break;
+		}
+
+	case WE_TIMEOUT: /* XXX - Hack to animate 'fake' buttons */
+		WP(w, def_d).data_1 = 0;
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const Widget _message_options_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,   10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,  409,     0,    13, STR_0204_MESSAGE_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,  409,    14,   184, 0x0,                      STR_NULL},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    26,    37, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    26,    37, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    38,    49, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    38,    49, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    50,    61, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    50,    61, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    62,    73, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    62,    73, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    74,    85, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    74,    85, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    86,    97, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    86,    97, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,    98,   109, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,    98,   109, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   110,   121, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   110,   121, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   122,   133, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   122,   133, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,     4,   12,   134,   145, SPR_ARROW_LEFT,           STR_HSCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,     3,    90,   98,   134,   145, SPR_ARROW_RIGHT,          STR_HSCROLL_BAR_SCROLLS_LIST},
+
+{      WWT_PANEL,   RESIZE_NONE,     3,     4,   86,   154,   165, 0x0,                      STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,    87,   98,   154,   165, STR_0225,                 STR_NULL},
+{  WWT_TEXTBTN_2,   RESIZE_NONE,     3,     4,   98,   166,   177, STR_02DB_OFF,             STR_NULL},
+
+{      WWT_LABEL,   RESIZE_NONE,    13,     0,  409,    13,    26, STR_0205_MESSAGE_TYPES,   STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _message_options_desc = {
+	270, 22, 410, 185,
+	WC_GAME_OPTIONS, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_message_options_widgets,
+	MessageOptionsWndProc
+};
+
+void ShowMessageOptions(void)
+{
+	DeleteWindowById(WC_GAME_OPTIONS, 0);
+	AllocateWindowDesc(&_message_options_desc);
+}
+
+
+void DeleteVehicleNews(VehicleID vid, StringID news)
+{
+	NewsID n;
+
+	for (n = _oldest_news; _latest_news != INVALID_NEWS; n = increaseIndex(n)) {
+		const NewsItem *ni = &_news_items[n];
+
+		if (ni->flags & NF_VEHICLE &&
+				ni->data_a == vid &&
+				(news == INVALID_STRING_ID || ni->string_id == news)) {
+			Window *w;
+
+			if (_forced_news == n || _current_news == n) MoveToNextItem();
+			_total_news--;
+
+			/* If this is the last news item, invalidate _latest_news */
+			if (_total_news == 0) {
+				assert(_latest_news == _oldest_news);
+				_latest_news = INVALID_NEWS;
+			}
+
+			/* Since we only imitate a FIFO removing an arbitrary element does need
+			 * some magic. Remove the item by shifting head towards the tail. eg
+			 *    oldest    remove  last
+			 *        |        |     |
+			 * [------O--------n-----L--]
+			 * will become (change dramatized to make clear)
+			 * [---------O-----------L--]
+			 * We also need an update of the current, forced and visible (open window)
+			 * news's as this shifting could change the items they were pointing to */
+			if (_total_news != 0) {
+				NewsID i, visible_news;
+				w = FindWindowById(WC_NEWS_WINDOW, 0);
+				visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS;
+
+				for (i = n;; i = decreaseIndex(i)) {
+					_news_items[i] = _news_items[decreaseIndex(i)];
+
+					if (i == _current_news) _current_news = increaseIndex(_current_news);
+					if (i == _forced_news) _forced_news = increaseIndex(_forced_news);
+					if (i == visible_news) WP(w, news_d).ni = &_news_items[increaseIndex(visible_news)];
+
+					if (i == _oldest_news) break;
+				}
+				_oldest_news = increaseIndex(_oldest_news);
+			}
+
+			/*DEBUG(misc, 0) ("-cur %3d, old %2d, lat %3d, for %3d, tot %2d",
+			  _current_news, _oldest_news, _latest_news, _forced_news, _total_news); */
+
+			w = FindWindowById(WC_MESSAGE_HISTORY, 0);
+			if (w != NULL) {
+				SetWindowDirty(w);
+				w->vscroll.count = _total_news;
+			}
+		}
+
+		if (n == _latest_news) break;
+	}
+}
deleted file mode 100644
--- a/src/npf.c
+++ /dev/null
@@ -1,894 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "debug.h"
-#include "functions.h"
-#include "npf.h"
-#include "aystar.h"
-#include "macros.h"
-#include "pathfind.h"
-#include "station.h"
-#include "station_map.h"
-#include "tile.h"
-#include "depot.h"
-#include "tunnel_map.h"
-#include "network/network.h"
-#include "water_map.h"
-
-static AyStar _npf_aystar;
-
-/* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH,
- * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071
- */
-#define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
-static const uint _trackdir_length[TRACKDIR_END] = {
-	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
-	0, 0,
-	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
-};
-
-/**
- * Calculates the minimum distance traveled to get from t0 to t1 when only
- * using tracks (ie, only making 45 degree turns). Returns the distance in the
- * NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to
- * prevent rounding.
- */
-static uint NPFDistanceTrack(TileIndex t0, TileIndex t1)
-{
-	const uint dx = abs(TileX(t0) - TileX(t1));
-	const uint dy = abs(TileY(t0) - TileY(t1));
-
-	const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
-	/* OPTIMISATION:
-	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
-	 * Proof:
-	 * (dx+dy) - straightTracks  == (min + max) - straightTracks = min + max - 2 * min = max - min */
-	const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
-
-	/* Don't factor out NPF_TILE_LENGTH below, this will round values and lose
-	 * precision */
-	return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH;
-}
-
-
-#if 0
-static uint NTPHash(uint key1, uint key2)
-{
-	/* This function uses the old hash, which is fixed on 10 bits (1024 buckets) */
-	return PATHFIND_HASH_TILE(key1);
-}
-#endif
-
-/**
- * Calculates a hash value for use in the NPF.
- * @param key1 The TileIndex of the tile to hash
- * @param key2 The Trackdir of the track on the tile.
- *
- * @todo Think of a better hash.
- */
-static uint NPFHash(uint key1, uint key2)
-{
-	/* TODO: think of a better hash? */
-	uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
-	uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
-
-	assert(IsValidTrackdir(key2));
-	assert(IsValidTile(key1));
-	return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE;
-}
-
-static int32 NPFCalcZero(AyStar* as, AyStarNode* current, OpenListNode* parent)
-{
-	return 0;
-}
-
-/* Calcs the tile of given station that is closest to a given tile
- * for this we assume the station is a rectangle,
- * as defined by its top tile (st->train_tile) and its width/height (st->trainst_w, st->trainst_h)
- */
-static TileIndex CalcClosestStationTile(StationID station, TileIndex tile)
-{
-	const Station* st = GetStation(station);
-
-	uint minx = TileX(st->train_tile);  // topmost corner of station
-	uint miny = TileY(st->train_tile);
-	uint maxx = minx + st->trainst_w - 1; // lowermost corner of station
-	uint maxy = miny + st->trainst_h - 1;
-	uint x;
-	uint y;
-
-	// we are going the aim for the x coordinate of the closest corner
-	// but if we are between those coordinates, we will aim for our own x coordinate
-	x = clamp(TileX(tile), minx, maxx);
-
-	// same for y coordinate, see above comment
-	y = clamp(TileY(tile), miny, maxy);
-
-	// return the tile of our target coordinates
-	return TileXY(x, y);
-}
-
-/* Calcs the heuristic to the target station or tile. For train stations, it
- * takes into account the direction of approach.
- */
-static int32 NPFCalcStationOrTileHeuristic(AyStar* as, AyStarNode* current, OpenListNode* parent)
-{
-	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
-	NPFFoundTargetData* ftd = (NPFFoundTargetData*)as->user_path;
-	TileIndex from = current->tile;
-	TileIndex to = fstd->dest_coords;
-	uint dist;
-
-	// for train-stations, we are going to aim for the closest station tile
-	if (as->user_data[NPF_TYPE] == TRANSPORT_RAIL && fstd->station_index != INVALID_STATION)
-		to = CalcClosestStationTile(fstd->station_index, from);
-
-	if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) {
-		/* Since roads only have diagonal pieces, we use manhattan distance here */
-		dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH;
-	} else {
-		/* Ships and trains can also go diagonal, so the minimum distance is shorter */
-		dist = NPFDistanceTrack(from, to);
-	}
-
-	DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist);
-
-	if (dist < ftd->best_bird_dist) {
-		ftd->best_bird_dist = dist;
-		ftd->best_trackdir = current->user_data[NPF_TRACKDIR_CHOICE];
-	}
-	return dist;
-}
-
-
-/* Fills AyStarNode.user_data[NPF_TRACKDIRCHOICE] with the chosen direction to
- * get here, either getting it from the current choice or from the parent's
- * choice */
-static void NPFFillTrackdirChoice(AyStarNode* current, OpenListNode* parent)
-{
-	if (parent->path.parent == NULL) {
-		Trackdir trackdir = (Trackdir)current->direction;
-		/* This is a first order decision, so we'd better save the
-		 * direction we chose */
-		current->user_data[NPF_TRACKDIR_CHOICE] = trackdir;
-		DEBUG(npf, 6, "Saving trackdir: 0x%X", trackdir);
-	} else {
-		/* We've already made the decision, so just save our parent's decision */
-		current->user_data[NPF_TRACKDIR_CHOICE] = parent->path.node.user_data[NPF_TRACKDIR_CHOICE];
-	}
-}
-
-/* Will return the cost of the tunnel. If it is an entry, it will return the
- * cost of that tile. If the tile is an exit, it will return the tunnel length
- * including the exit tile. Requires that this is a Tunnel tile */
-static uint NPFTunnelCost(AyStarNode* current)
-{
-	DiagDirection exitdir = TrackdirToExitdir((Trackdir)current->direction);
-	TileIndex tile = current->tile;
-	if (GetTunnelDirection(tile) == ReverseDiagDir(exitdir)) {
-		/* We just popped out if this tunnel, since were
-		 * facing the tunnel exit */
-		FindLengthOfTunnelResult flotr;
-		flotr = FindLengthOfTunnel(tile, ReverseDiagDir(exitdir));
-		return flotr.length * NPF_TILE_LENGTH;
-		//TODO: Penalty for tunnels?
-	} else {
-		/* We are entering the tunnel, the enter tile is just a
-		 * straight track */
-		return NPF_TILE_LENGTH;
-	}
-}
-
-static inline uint NPFBridgeCost(AyStarNode *current)
-{
-	return NPF_TILE_LENGTH * GetBridgeLength(current->tile, GetOtherBridgeEnd(current->tile));
-}
-
-static uint NPFSlopeCost(AyStarNode* current)
-{
-	TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction));
-	int x,y;
-	int8 z1,z2;
-
-	x = TileX(current->tile) * TILE_SIZE;
-	y = TileY(current->tile) * TILE_SIZE;
-	/* get the height of the center of the current tile */
-	z1 = GetSlopeZ(x + TILE_SIZE / 2, y + TILE_SIZE / 2);
-
-	x = TileX(next) * TILE_SIZE;
-	y = TileY(next) * TILE_SIZE;
-	/* get the height of the center of the next tile */
-	z2 = GetSlopeZ(x + TILE_SIZE / 2, y + TILE_SIZE / 2);
-
-	if (z2 - z1 > 1) {
-		/* Slope up */
-		return _patches.npf_rail_slope_penalty;
-	}
-	return 0;
-	/* Should we give a bonus for slope down? Probably not, we
-	 * could just substract that bonus from the penalty, because
-	 * there is only one level of steepness... */
-}
-
-/**
- * Mark tiles by mowing the grass when npf debug level >= 1.
- * Will not work for multiplayer games, since it can (will) cause desyncs.
- */
-static void NPFMarkTile(TileIndex tile)
-{
-#ifndef NO_DEBUG_MESSAGES
-	if (_debug_npf_level < 1 || _networking) return;
-	switch (GetTileType(tile)) {
-		case MP_RAILWAY:
-			/* DEBUG: mark visited tiles by mowing the grass under them ;-) */
-			if (!IsTileDepotType(tile, TRANSPORT_RAIL)) {
-				SetRailGroundType(tile, RAIL_GROUND_BARREN);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		case MP_STREET:
-			if (!IsTileDepotType(tile, TRANSPORT_ROAD)) {
-				SetRoadside(tile, ROADSIDE_BARREN);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		default:
-			break;
-	}
-#endif
-}
-
-static int32 NPFWaterPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
-{
-	//TileIndex tile = current->tile;
-	int32 cost = 0;
-	Trackdir trackdir = (Trackdir)current->direction;
-
-	cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
-
-	if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir))
-		cost += _patches.npf_buoy_penalty; /* A small penalty for going over buoys */
-
-	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
-		cost += _patches.npf_water_curve_penalty;
-
-	/* TODO More penalties? */
-
-	return cost;
-}
-
-/* Determine the cost of this node, for road tracks */
-static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
-{
-	TileIndex tile = current->tile;
-	int32 cost = 0;
-
-	/* Determine base length */
-	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-			cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
-			break;
-
-		case MP_STREET:
-			cost = NPF_TILE_LENGTH;
-			/* Increase the cost for level crossings */
-			if (IsLevelCrossing(tile)) cost += _patches.npf_crossing_penalty;
-			break;
-
-		default:
-			break;
-	}
-
-	/* Determine extra costs */
-
-	/* Check for slope */
-	cost += NPFSlopeCost(current);
-
-	/* Check for turns. Road vehicles only really drive diagonal, turns are
-	 * represented by non-diagonal tracks */
-	if (!IsDiagonalTrackdir(current->direction))
-		cost += _patches.npf_road_curve_penalty;
-
-	NPFMarkTile(tile);
-	DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
-	return cost;
-}
-
-
-/* Determine the cost of this node, for railway tracks */
-static int32 NPFRailPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
-{
-	TileIndex tile = current->tile;
-	Trackdir trackdir = (Trackdir)current->direction;
-	int32 cost = 0;
-	/* HACK: We create a OpenListNode manually, so we can call EndNodeCheck */
-	OpenListNode new_node;
-
-	/* Determine base length */
-	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-			cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
-			break;
-
-		case MP_RAILWAY:
-			cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
-			break;
-
-		case MP_STREET: /* Railway crossing */
-			cost = NPF_TILE_LENGTH;
-			break;
-
-		case MP_STATION:
-			/* We give a station tile a penalty. Logically we would only want to give
-			 * station tiles that are not our destination this penalty. This would
-			 * discourage trains to drive through busy stations. But, we can just
-			 * give any station tile a penalty, because every possible route will get
-			 * this penalty exactly once, on its end tile (if it's a station) and it
-			 * will therefore not make a difference. */
-			cost = NPF_TILE_LENGTH + _patches.npf_rail_station_penalty;
-			break;
-
-		default:
-			break;
-	}
-
-	/* Determine extra costs */
-
-	/* Check for signals */
-	if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir)) {
-		/* Ordinary track with signals */
-		if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) {
-			/* Signal facing us is red */
-			if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
-				/* Penalize the first signal we
-				 * encounter, if it is red */
-
-				/* Is this a presignal exit or combo? */
-				SignalType sigtype = GetSignalType(tile);
-				if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) {
-					/* Penalise exit and combo signals differently (heavier) */
-					cost += _patches.npf_rail_firstred_exit_penalty;
-				} else {
-					cost += _patches.npf_rail_firstred_penalty;
-				}
-			}
-			/* Record the state of this signal */
-			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
-		} else {
-			/* Record the state of this signal */
-			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
-		}
-		NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
-	}
-
-	/* Penalise the tile if it is a target tile and the last signal was
-	 * red */
-	/* HACK: We create a new_node here so we can call EndNodeCheck. Ugly as hell
-	 * of course... */
-	new_node.path.node = *current;
-	if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
-		cost += _patches.npf_rail_lastred_penalty;
-
-	/* Check for slope */
-	cost += NPFSlopeCost(current);
-
-	/* Check for turns */
-	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
-		cost += _patches.npf_rail_curve_penalty;
-	//TODO, with realistic acceleration, also the amount of straight track between
-	//      curves should be taken into account, as this affects the speed limit.
-
-	/* Check for reverse in depot */
-	if (IsTileDepotType(tile, TRANSPORT_RAIL) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
-		/* Penalise any depot tile that is not the last tile in the path. This
-		 * _should_ penalise every occurence of reversing in a depot (and only
-		 * that) */
-		cost += _patches.npf_rail_depot_reverse_penalty;
-	}
-
-	/* Check for occupied track */
-	//TODO
-
-	NPFMarkTile(tile);
-	DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
-	return cost;
-}
-
-/* Will find any depot */
-static int32 NPFFindDepot(AyStar* as, OpenListNode *current)
-{
-	/* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below,
-	 * since checking the cache not that much faster than the actual check */
-	return IsTileDepotType(current->path.node.tile, as->user_data[NPF_TYPE]) ?
-		AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
-}
-
-/* Will find a station identified using the NPFFindStationOrTileData */
-static int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current)
-{
-	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
-	AyStarNode *node = &current->path.node;
-	TileIndex tile = node->tile;
-
-	/* If GetNeighbours said we could get here, we assume the station type
-	 * is correct */
-	if (
-		(fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) || /* We've found the tile, or */
-		(IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) /* the station */
-	) {
-		return AYSTAR_FOUND_END_NODE;
-	} else {
-		return AYSTAR_DONE;
-	}
-}
-
-/* To be called when current contains the (shortest route to) the target node.
- * Will fill the contents of the NPFFoundTargetData using
- * AyStarNode[NPF_TRACKDIR_CHOICE].
- */
-static void NPFSaveTargetData(AyStar* as, OpenListNode* current)
-{
-	NPFFoundTargetData* ftd = (NPFFoundTargetData*)as->user_path;
-	ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE];
-	ftd->best_path_dist = current->g;
-	ftd->best_bird_dist = 0;
-	ftd->node = current->path.node;
-}
-
-/**
- * Finds out if a given player's vehicles are allowed to enter a given tile.
- * @param owner    The owner of the vehicle.
- * @param tile     The tile that is about to be entered.
- * @param enterdir The direction from which the vehicle wants to enter the tile.
- * @return         true if the vehicle can enter the tile.
- * @todo           This function should be used in other places than just NPF,
- *                 maybe moved to another file too.
- */
-static bool VehicleMayEnterTile(Owner owner, TileIndex tile, DiagDirection enterdir)
-{
-	if (IsTileType(tile, MP_RAILWAY) ||           /* Rail tile (also rail depot) */
-			IsRailwayStationTile(tile) ||               /* Rail station tile */
-			IsTileDepotType(tile, TRANSPORT_ROAD) ||  /* Road depot tile */
-			IsRoadStopTile(tile) ||                /* Road station tile */
-			IsTileDepotType(tile, TRANSPORT_WATER)) { /* Water depot tile */
-		return IsTileOwner(tile, owner); /* You need to own these tiles entirely to use them */
-	}
-
-	switch (GetTileType(tile)) {
-		case MP_STREET:
-			/* rail-road crossing : are we looking at the railway part? */
-			if (IsLevelCrossing(tile) &&
-					DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
-				return IsTileOwner(tile, owner); /* Railway needs owner check, while the street is public */
-			}
-			break;
-
-		case MP_TUNNELBRIDGE:
-			if ((IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) ||
-					(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL)) {
-				return IsTileOwner(tile, owner);
-			}
-			break;
-
-		default:
-			break;
-	}
-
-	return true; /* no need to check */
-}
-
-
-/**
- * Returns the direction the exit of the depot on the given tile is facing.
- */
-static DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
-{
-	assert(IsTileDepotType(tile, type));
-
-	switch (type) {
-		case TRANSPORT_RAIL:  return GetRailDepotDirection(tile);
-		case TRANSPORT_ROAD:  return GetRoadDepotDirection(tile);
-		case TRANSPORT_WATER: return GetShipDepotDirection(tile);
-		default: return INVALID_DIAGDIR; /* Not reached */
-	}
-}
-
-
-/* Will just follow the results of GetTileTrackStatus concerning where we can
- * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and
- * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the
- * entry and exit are neighbours. Will fill
- * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and
- * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */
-static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
-{
-	Trackdir src_trackdir = (Trackdir)current->path.node.direction;
-	TileIndex src_tile = current->path.node.tile;
-	DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir);
-	TileIndex dst_tile = INVALID_TILE;
-	int i;
-	TrackdirBits trackdirbits, ts;
-	TransportType type = aystar->user_data[NPF_TYPE];
-	bool override_dst_check = false;
-	/* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
-	aystar->num_neighbours = 0;
-	DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
-
-	/* Find dest tile */
-	if (IsTunnelTile(src_tile) && GetTunnelDirection(src_tile) == src_exitdir) {
-		/* This is a tunnel. We know this tunnel is our type,
-		 * otherwise we wouldn't have got here. It is also facing us,
-		 * so we should skip it's body */
-		dst_tile = GetOtherTunnelEnd(src_tile);
-		override_dst_check = true;
-	} else if (IsBridgeTile(src_tile) && GetBridgeRampDirection(src_tile) == src_exitdir) {
-		dst_tile = GetOtherBridgeEnd(src_tile);
-		override_dst_check = true;
-	} else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) {
-		/* This is a road station or a train or road depot. We can enter and exit
-		 * those from one side only. Trackdirs don't support that (yet), so we'll
-		 * do this here. */
-
-		DiagDirection exitdir;
-		/* Find out the exit direction first */
-		if (IsRoadStopTile(src_tile)) {
-			exitdir = GetRoadStopDir(src_tile);
-		} else { /* Train or road depot */
-			exitdir = GetDepotDirection(src_tile, type);
-		}
-
-		/* Let's see if were headed the right way into the depot */
-		if (src_trackdir == DiagdirToDiagTrackdir(ReverseDiagDir(exitdir))) {
-			/* We are headed inwards. We cannot go through the back of the depot.
-			 * For rail, we can now reverse. Reversing for road vehicles is never
-			 * useful, since you cannot take paths you couldn't take before
-			 * reversing (as with rail). */
-			if (type == TRANSPORT_RAIL) {
-				/* We can only reverse here, so we'll not consider this direction, but
-				 * jump ahead to the reverse direction.  It would be nicer to return
-				 * one neighbour here (the reverse trackdir of the one we are
-				 * considering now) and then considering that one to return the tracks
-				 * outside of the depot. But, because the code layout is cleaner this
-				 * way, we will just pretend we are reversed already */
-				src_trackdir = ReverseTrackdir(src_trackdir);
-				dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(exitdir));
-			} else {
-				dst_tile = INVALID_TILE; /* Road vehicle heading inwards: dead end */
-			}
-		} else {
-			dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(exitdir));
-		}
-	} else {
-		/* This a normal tile, a bridge, a tunnel exit, etc. */
-		dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(TrackdirToExitdir(src_trackdir)));
-	}
-	if (dst_tile == INVALID_TILE) {
-		/* We reached the border of the map */
-		/* TODO Nicer control flow for this */
-		return;
-	}
-
-	/* I can't enter a tunnel entry/exit tile from a tile above the tunnel. Note
-	 * that I can enter the tunnel from a tile below the tunnel entrance. This
-	 * solves the problem of vehicles wanting to drive off a tunnel entrance */
-	if (!override_dst_check) {
-		if (IsTileType(dst_tile, MP_TUNNELBRIDGE)) {
-			if (IsTunnel(dst_tile)) {
-				if (GetTunnelDirection(dst_tile) != src_exitdir) return;
-			} else {
-				if (GetBridgeRampDirection(dst_tile) != src_exitdir) return;
-			}
-		}
-	}
-
-	/* check correct rail type (mono, maglev, etc) */
-	if (type == TRANSPORT_RAIL) {
-		RailType dst_type = GetTileRailType(dst_tile, src_trackdir);
-		if (!HASBIT(aystar->user_data[NPF_RAILTYPES], dst_type))
-			return;
-	}
-
-	/* Check the owner of the tile */
-	if (!VehicleMayEnterTile(aystar->user_data[NPF_OWNER], dst_tile, TrackdirToExitdir(src_trackdir))) {
-		return;
-	}
-
-	/* Determine available tracks */
-	if (type != TRANSPORT_WATER && (IsRoadStopTile(dst_tile) || IsTileDepotType(dst_tile, type))){
-		/* Road stations and road and train depots return 0 on GTTS, so we have to do this by hand... */
-		DiagDirection exitdir;
-		if (IsRoadStopTile(dst_tile)) {
-			exitdir = GetRoadStopDir(dst_tile);
-		} else { /* Road or train depot */
-			exitdir = GetDepotDirection(dst_tile, type);
-		}
-		/* Find the trackdirs that are available for a depot or station with this
-		 * orientation. They are only "inwards", since we are reaching this tile
-		 * from some other tile. This prevents vehicles driving into depots from
-		 * the back */
-		ts = TrackdirToTrackdirBits(DiagdirToDiagTrackdir(ReverseDiagDir(exitdir)));
-	} else {
-		ts = GetTileTrackStatus(dst_tile, type);
-	}
-	trackdirbits = ts & TRACKDIR_BIT_MASK; /* Filter out signal status and the unused bits */
-
-	DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits);
-	/* Select only trackdirs we can reach from our current trackdir */
-	trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
-	if (_patches.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) /* Filter out trackdirs that would make 90 deg turns for trains */
-		trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
-
-	DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
-
-	i = 0;
-	/* Enumerate possible track */
-	while (trackdirbits != 0) {
-		Trackdir dst_trackdir;
-		dst_trackdir =  FindFirstBit2x64(trackdirbits);
-		trackdirbits = KillFirstBit2x64(trackdirbits);
-		DEBUG(npf, 5, "Expanded into trackdir: %d, remaining trackdirs: 0x%X", dst_trackdir, trackdirbits);
-
-		/* Check for oneway signal against us */
-		if (IsTileType(dst_tile, MP_RAILWAY) && GetRailTileType(dst_tile) == RAIL_TILE_SIGNALS) {
-			if (HasSignalOnTrackdir(dst_tile, ReverseTrackdir(dst_trackdir)) && !HasSignalOnTrackdir(dst_tile, dst_trackdir))
-				// if one way signal not pointing towards us, stop going in this direction.
-				break;
-		}
-		{
-			/* We've found ourselves a neighbour :-) */
-			AyStarNode* neighbour = &aystar->neighbours[i];
-			neighbour->tile = dst_tile;
-			neighbour->direction = dst_trackdir;
-			/* Save user data */
-			neighbour->user_data[NPF_NODE_FLAGS] = current->path.node.user_data[NPF_NODE_FLAGS];
-			NPFFillTrackdirChoice(neighbour, current);
-		}
-		i++;
-	}
-	aystar->num_neighbours = i;
-}
-
-/*
- * Plan a route to the specified target (which is checked by target_proc),
- * from start1 and if not NULL, from start2 as well. The type of transport we
- * are checking is in type. reverse_penalty is applied to all routes that
- * originate from the second start node.
- * When we are looking for one specific target (optionally multiple tiles), we
- * should use a good heuristic to perform aystar search. When we search for
- * multiple targets that are spread around, we should perform a breadth first
- * search by specifiying CalcZero as our heuristic.
- */
-static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start2, NPFFindStationOrTileData* target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, Owner owner, RailTypeMask railtypes, uint reverse_penalty)
-{
-	int r;
-	NPFFoundTargetData result;
-
-	/* Initialize procs */
-	_npf_aystar.CalculateH = heuristic_proc;
-	_npf_aystar.EndNodeCheck = target_proc;
-	_npf_aystar.FoundEndNode = NPFSaveTargetData;
-	_npf_aystar.GetNeighbours = NPFFollowTrack;
-	switch (type) {
-		default: NOT_REACHED();
-		case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
-		case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
-		case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
-	}
-
-	/* Initialize Start Node(s) */
-	start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-	start1->user_data[NPF_NODE_FLAGS] = 0;
-	_npf_aystar.addstart(&_npf_aystar, start1, 0);
-	if (start2) {
-		start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-		start2->user_data[NPF_NODE_FLAGS] = 0;
-		NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
-		_npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty);
-	}
-
-	/* Initialize result */
-	result.best_bird_dist = (uint)-1;
-	result.best_path_dist = (uint)-1;
-	result.best_trackdir = INVALID_TRACKDIR;
-	_npf_aystar.user_path = &result;
-
-	/* Initialize target */
-	_npf_aystar.user_target = target;
-
-	/* Initialize user_data */
-	_npf_aystar.user_data[NPF_TYPE] = type;
-	_npf_aystar.user_data[NPF_OWNER] = owner;
-	_npf_aystar.user_data[NPF_RAILTYPES] = railtypes;
-
-	/* GO! */
-	r = AyStarMain_Main(&_npf_aystar);
-	assert(r != AYSTAR_STILL_BUSY);
-
-	if (result.best_bird_dist != 0) {
-		if (target != NULL) {
-			DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile);
-		} else {
-			/* Assumption: target == NULL, so we are looking for a depot */
-			DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile);
-		}
-
-	}
-	return result;
-}
-
-NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-	AyStarNode start1;
-	AyStarNode start2;
-
-	start1.tile = tile1;
-	start2.tile = tile2;
-	/* We set this in case the target is also the start tile, we will just
-	 * return a not found then */
-	start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-	start1.direction = trackdir1;
-	start2.direction = trackdir2;
-	start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-
-	return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, railtypes, 0);
-}
-
-NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-	return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner, railtypes);
-}
-
-NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailTypeMask railtypes, uint reverse_penalty)
-{
-	AyStarNode start1;
-	AyStarNode start2;
-
-	start1.tile = tile1;
-	start2.tile = tile2;
-	/* We set this in case the target is also the start tile, we will just
-	 * return a not found then */
-	start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-	start1.direction = trackdir1;
-	start2.direction = trackdir2;
-	start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-
-	/* perform a breadth first search. Target is NULL,
-	 * since we are just looking for any depot...*/
-	return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, railtypes, reverse_penalty);
-}
-
-NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-	return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, railtypes, 0);
-}
-
-NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-	/* Okay, what we're gonna do. First, we look at all depots, calculate
-	 * the manhatten distance to get to each depot. We then sort them by
-	 * distance. We start by trying to plan a route to the closest, then
-	 * the next closest, etc. We stop when the best route we have found so
-	 * far, is shorter than the manhattan distance. This will obviously
-	 * always find the closest depot. It will probably be most efficient
-	 * for ships, since the heuristic will not be to far off then. I hope.
-	 */
-	Queue depots;
-	int r;
-	NPFFoundTargetData best_result = {(uint)-1, (uint)-1, INVALID_TRACKDIR, {INVALID_TILE, 0, {0, 0}}};
-	NPFFoundTargetData result;
-	NPFFindStationOrTileData target;
-	AyStarNode start;
-	Depot* current;
-	Depot *depot;
-
-	init_InsSort(&depots);
-	/* Okay, let's find all depots that we can use first */
-	FOR_ALL_DEPOTS(depot) {
-		/* Check if this is really a valid depot, it is of the needed type and
-		 * owner */
-		if (IsTileDepotType(depot->xy, type) && IsTileOwner(depot->xy, owner))
-			/* If so, let's add it to the queue, sorted by distance */
-			depots.push(&depots, depot, DistanceManhattan(tile, depot->xy));
-	}
-
-	/* Now, let's initialise the aystar */
-
-	/* Initialize procs */
-	_npf_aystar.CalculateH = NPFCalcStationOrTileHeuristic;
-	_npf_aystar.EndNodeCheck = NPFFindStationOrTile;
-	_npf_aystar.FoundEndNode = NPFSaveTargetData;
-	_npf_aystar.GetNeighbours = NPFFollowTrack;
-	switch (type) {
-		default: NOT_REACHED();
-		case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
-		case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
-		case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
-	}
-
-	/* Initialize target */
-	target.station_index = INVALID_STATION; /* We will initialize dest_coords inside the loop below */
-	_npf_aystar.user_target = &target;
-
-	/* Initialize user_data */
-	_npf_aystar.user_data[NPF_TYPE] = type;
-	_npf_aystar.user_data[NPF_OWNER] = owner;
-
-	/* Initialize Start Node */
-	start.tile = tile;
-	start.direction = trackdir; /* We will initialize user_data inside the loop below */
-
-	/* Initialize Result */
-	_npf_aystar.user_path = &result;
-	best_result.best_path_dist = (uint)-1;
-	best_result.best_bird_dist = (uint)-1;
-
-	/* Just iterate the depots in order of increasing distance */
-	while ((current = depots.pop(&depots))) {
-		/* Check to see if we already have a path shorter than this
-		 * depot's manhattan distance. HACK: We call DistanceManhattan
-		 * again, we should probably modify the queue to give us that
-		 * value... */
-		if ( DistanceManhattan(tile, current->xy * NPF_TILE_LENGTH) > best_result.best_path_dist)
-			break;
-
-		/* Initialize Start Node */
-		/* We set this in case the target is also the start tile, we will just
-		 * return a not found then */
-		start.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
-		start.user_data[NPF_NODE_FLAGS] = 0;
-		_npf_aystar.addstart(&_npf_aystar, &start, 0);
-
-		/* Initialize result */
-		result.best_bird_dist = (uint)-1;
-		result.best_path_dist = (uint)-1;
-		result.best_trackdir = INVALID_TRACKDIR;
-
-		/* Initialize target */
-		target.dest_coords = current->xy;
-
-		/* GO! */
-		r = AyStarMain_Main(&_npf_aystar);
-		assert(r != AYSTAR_STILL_BUSY);
-
-		/* This depot is closer */
-		if (result.best_path_dist < best_result.best_path_dist)
-			best_result = result;
-	}
-	if (result.best_bird_dist != 0) {
-		DEBUG(npf, 1, "Could not find route to any depot from tile 0x%X.", tile);
-	}
-	return best_result;
-}
-
-void InitializeNPF(void)
-{
-	init_AyStar(&_npf_aystar, NPFHash, NPF_HASH_SIZE);
-	_npf_aystar.loops_per_tick = 0;
-	_npf_aystar.max_path_cost = 0;
-	//_npf_aystar.max_search_nodes = 0;
-	/* We will limit the number of nodes for now, until we have a better
-	 * solution to really fix performance */
-	_npf_aystar.max_search_nodes = _patches.npf_max_search_nodes;
-}
-
-void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v)
-{
-	/* Ships don't really reach their stations, but the tile in front. So don't
-	 * save the station id for ships. For roadvehs we don't store it either,
-	 * because multistop depends on vehicles actually reaching the exact
-	 * dest_tile, not just any stop of that station.
-	 * So only for train orders to stations we fill fstd->station_index, for all
-	 * others only dest_coords */
-	if (v->current_order.type == OT_GOTO_STATION && v->type == VEH_Train) {
-		fstd->station_index = v->current_order.dest;
-		/* Let's take the closest tile of the station as our target for trains */
-		fstd->dest_coords = CalcClosestStationTile(v->current_order.dest, v->tile);
-	} else {
-		fstd->dest_coords = v->dest_tile;
-		fstd->station_index = INVALID_STATION;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/npf.cpp
@@ -0,0 +1,894 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "debug.h"
+#include "functions.h"
+#include "npf.h"
+#include "aystar.h"
+#include "macros.h"
+#include "pathfind.h"
+#include "station.h"
+#include "station_map.h"
+#include "tile.h"
+#include "depot.h"
+#include "tunnel_map.h"
+#include "network/network.h"
+#include "water_map.h"
+
+static AyStar _npf_aystar;
+
+/* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH,
+ * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071
+ */
+#define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
+static const uint _trackdir_length[TRACKDIR_END] = {
+	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
+	0, 0,
+	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
+};
+
+/**
+ * Calculates the minimum distance traveled to get from t0 to t1 when only
+ * using tracks (ie, only making 45 degree turns). Returns the distance in the
+ * NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to
+ * prevent rounding.
+ */
+static uint NPFDistanceTrack(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+
+	const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
+	/* OPTIMISATION:
+	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
+	 * Proof:
+	 * (dx+dy) - straightTracks  == (min + max) - straightTracks = min + max - 2 * min = max - min */
+	const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
+
+	/* Don't factor out NPF_TILE_LENGTH below, this will round values and lose
+	 * precision */
+	return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH;
+}
+
+
+#if 0
+static uint NTPHash(uint key1, uint key2)
+{
+	/* This function uses the old hash, which is fixed on 10 bits (1024 buckets) */
+	return PATHFIND_HASH_TILE(key1);
+}
+#endif
+
+/**
+ * Calculates a hash value for use in the NPF.
+ * @param key1 The TileIndex of the tile to hash
+ * @param key2 The Trackdir of the track on the tile.
+ *
+ * @todo Think of a better hash.
+ */
+static uint NPFHash(uint key1, uint key2)
+{
+	/* TODO: think of a better hash? */
+	uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
+	uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
+
+	assert(IsValidTrackdir(key2));
+	assert(IsValidTile(key1));
+	return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE;
+}
+
+static int32 NPFCalcZero(AyStar* as, AyStarNode* current, OpenListNode* parent)
+{
+	return 0;
+}
+
+/* Calcs the tile of given station that is closest to a given tile
+ * for this we assume the station is a rectangle,
+ * as defined by its top tile (st->train_tile) and its width/height (st->trainst_w, st->trainst_h)
+ */
+static TileIndex CalcClosestStationTile(StationID station, TileIndex tile)
+{
+	const Station* st = GetStation(station);
+
+	uint minx = TileX(st->train_tile);  // topmost corner of station
+	uint miny = TileY(st->train_tile);
+	uint maxx = minx + st->trainst_w - 1; // lowermost corner of station
+	uint maxy = miny + st->trainst_h - 1;
+	uint x;
+	uint y;
+
+	// we are going the aim for the x coordinate of the closest corner
+	// but if we are between those coordinates, we will aim for our own x coordinate
+	x = clamp(TileX(tile), minx, maxx);
+
+	// same for y coordinate, see above comment
+	y = clamp(TileY(tile), miny, maxy);
+
+	// return the tile of our target coordinates
+	return TileXY(x, y);
+}
+
+/* Calcs the heuristic to the target station or tile. For train stations, it
+ * takes into account the direction of approach.
+ */
+static int32 NPFCalcStationOrTileHeuristic(AyStar* as, AyStarNode* current, OpenListNode* parent)
+{
+	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
+	NPFFoundTargetData* ftd = (NPFFoundTargetData*)as->user_path;
+	TileIndex from = current->tile;
+	TileIndex to = fstd->dest_coords;
+	uint dist;
+
+	// for train-stations, we are going to aim for the closest station tile
+	if (as->user_data[NPF_TYPE] == TRANSPORT_RAIL && fstd->station_index != INVALID_STATION)
+		to = CalcClosestStationTile(fstd->station_index, from);
+
+	if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) {
+		/* Since roads only have diagonal pieces, we use manhattan distance here */
+		dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH;
+	} else {
+		/* Ships and trains can also go diagonal, so the minimum distance is shorter */
+		dist = NPFDistanceTrack(from, to);
+	}
+
+	DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist);
+
+	if (dist < ftd->best_bird_dist) {
+		ftd->best_bird_dist = dist;
+		ftd->best_trackdir = current->user_data[NPF_TRACKDIR_CHOICE];
+	}
+	return dist;
+}
+
+
+/* Fills AyStarNode.user_data[NPF_TRACKDIRCHOICE] with the chosen direction to
+ * get here, either getting it from the current choice or from the parent's
+ * choice */
+static void NPFFillTrackdirChoice(AyStarNode* current, OpenListNode* parent)
+{
+	if (parent->path.parent == NULL) {
+		Trackdir trackdir = (Trackdir)current->direction;
+		/* This is a first order decision, so we'd better save the
+		 * direction we chose */
+		current->user_data[NPF_TRACKDIR_CHOICE] = trackdir;
+		DEBUG(npf, 6, "Saving trackdir: 0x%X", trackdir);
+	} else {
+		/* We've already made the decision, so just save our parent's decision */
+		current->user_data[NPF_TRACKDIR_CHOICE] = parent->path.node.user_data[NPF_TRACKDIR_CHOICE];
+	}
+}
+
+/* Will return the cost of the tunnel. If it is an entry, it will return the
+ * cost of that tile. If the tile is an exit, it will return the tunnel length
+ * including the exit tile. Requires that this is a Tunnel tile */
+static uint NPFTunnelCost(AyStarNode* current)
+{
+	DiagDirection exitdir = TrackdirToExitdir((Trackdir)current->direction);
+	TileIndex tile = current->tile;
+	if (GetTunnelDirection(tile) == ReverseDiagDir(exitdir)) {
+		/* We just popped out if this tunnel, since were
+		 * facing the tunnel exit */
+		FindLengthOfTunnelResult flotr;
+		flotr = FindLengthOfTunnel(tile, ReverseDiagDir(exitdir));
+		return flotr.length * NPF_TILE_LENGTH;
+		//TODO: Penalty for tunnels?
+	} else {
+		/* We are entering the tunnel, the enter tile is just a
+		 * straight track */
+		return NPF_TILE_LENGTH;
+	}
+}
+
+static inline uint NPFBridgeCost(AyStarNode *current)
+{
+	return NPF_TILE_LENGTH * GetBridgeLength(current->tile, GetOtherBridgeEnd(current->tile));
+}
+
+static uint NPFSlopeCost(AyStarNode* current)
+{
+	TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction));
+	int x,y;
+	int8 z1,z2;
+
+	x = TileX(current->tile) * TILE_SIZE;
+	y = TileY(current->tile) * TILE_SIZE;
+	/* get the height of the center of the current tile */
+	z1 = GetSlopeZ(x + TILE_SIZE / 2, y + TILE_SIZE / 2);
+
+	x = TileX(next) * TILE_SIZE;
+	y = TileY(next) * TILE_SIZE;
+	/* get the height of the center of the next tile */
+	z2 = GetSlopeZ(x + TILE_SIZE / 2, y + TILE_SIZE / 2);
+
+	if (z2 - z1 > 1) {
+		/* Slope up */
+		return _patches.npf_rail_slope_penalty;
+	}
+	return 0;
+	/* Should we give a bonus for slope down? Probably not, we
+	 * could just substract that bonus from the penalty, because
+	 * there is only one level of steepness... */
+}
+
+/**
+ * Mark tiles by mowing the grass when npf debug level >= 1.
+ * Will not work for multiplayer games, since it can (will) cause desyncs.
+ */
+static void NPFMarkTile(TileIndex tile)
+{
+#ifndef NO_DEBUG_MESSAGES
+	if (_debug_npf_level < 1 || _networking) return;
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			/* DEBUG: mark visited tiles by mowing the grass under them ;-) */
+			if (!IsTileDepotType(tile, TRANSPORT_RAIL)) {
+				SetRailGroundType(tile, RAIL_GROUND_BARREN);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		case MP_STREET:
+			if (!IsTileDepotType(tile, TRANSPORT_ROAD)) {
+				SetRoadside(tile, ROADSIDE_BARREN);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		default:
+			break;
+	}
+#endif
+}
+
+static int32 NPFWaterPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
+{
+	//TileIndex tile = current->tile;
+	int32 cost = 0;
+	Trackdir trackdir = (Trackdir)current->direction;
+
+	cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
+
+	if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir))
+		cost += _patches.npf_buoy_penalty; /* A small penalty for going over buoys */
+
+	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
+		cost += _patches.npf_water_curve_penalty;
+
+	/* TODO More penalties? */
+
+	return cost;
+}
+
+/* Determine the cost of this node, for road tracks */
+static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
+{
+	TileIndex tile = current->tile;
+	int32 cost = 0;
+
+	/* Determine base length */
+	switch (GetTileType(tile)) {
+		case MP_TUNNELBRIDGE:
+			cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
+			break;
+
+		case MP_STREET:
+			cost = NPF_TILE_LENGTH;
+			/* Increase the cost for level crossings */
+			if (IsLevelCrossing(tile)) cost += _patches.npf_crossing_penalty;
+			break;
+
+		default:
+			break;
+	}
+
+	/* Determine extra costs */
+
+	/* Check for slope */
+	cost += NPFSlopeCost(current);
+
+	/* Check for turns. Road vehicles only really drive diagonal, turns are
+	 * represented by non-diagonal tracks */
+	if (!IsDiagonalTrackdir(current->direction))
+		cost += _patches.npf_road_curve_penalty;
+
+	NPFMarkTile(tile);
+	DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
+	return cost;
+}
+
+
+/* Determine the cost of this node, for railway tracks */
+static int32 NPFRailPathCost(AyStar* as, AyStarNode* current, OpenListNode* parent)
+{
+	TileIndex tile = current->tile;
+	Trackdir trackdir = (Trackdir)current->direction;
+	int32 cost = 0;
+	/* HACK: We create a OpenListNode manually, so we can call EndNodeCheck */
+	OpenListNode new_node;
+
+	/* Determine base length */
+	switch (GetTileType(tile)) {
+		case MP_TUNNELBRIDGE:
+			cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
+			break;
+
+		case MP_RAILWAY:
+			cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
+			break;
+
+		case MP_STREET: /* Railway crossing */
+			cost = NPF_TILE_LENGTH;
+			break;
+
+		case MP_STATION:
+			/* We give a station tile a penalty. Logically we would only want to give
+			 * station tiles that are not our destination this penalty. This would
+			 * discourage trains to drive through busy stations. But, we can just
+			 * give any station tile a penalty, because every possible route will get
+			 * this penalty exactly once, on its end tile (if it's a station) and it
+			 * will therefore not make a difference. */
+			cost = NPF_TILE_LENGTH + _patches.npf_rail_station_penalty;
+			break;
+
+		default:
+			break;
+	}
+
+	/* Determine extra costs */
+
+	/* Check for signals */
+	if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir)) {
+		/* Ordinary track with signals */
+		if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) {
+			/* Signal facing us is red */
+			if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
+				/* Penalize the first signal we
+				 * encounter, if it is red */
+
+				/* Is this a presignal exit or combo? */
+				SignalType sigtype = GetSignalType(tile);
+				if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) {
+					/* Penalise exit and combo signals differently (heavier) */
+					cost += _patches.npf_rail_firstred_exit_penalty;
+				} else {
+					cost += _patches.npf_rail_firstred_penalty;
+				}
+			}
+			/* Record the state of this signal */
+			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
+		} else {
+			/* Record the state of this signal */
+			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
+		}
+		NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
+	}
+
+	/* Penalise the tile if it is a target tile and the last signal was
+	 * red */
+	/* HACK: We create a new_node here so we can call EndNodeCheck. Ugly as hell
+	 * of course... */
+	new_node.path.node = *current;
+	if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
+		cost += _patches.npf_rail_lastred_penalty;
+
+	/* Check for slope */
+	cost += NPFSlopeCost(current);
+
+	/* Check for turns */
+	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
+		cost += _patches.npf_rail_curve_penalty;
+	//TODO, with realistic acceleration, also the amount of straight track between
+	//      curves should be taken into account, as this affects the speed limit.
+
+	/* Check for reverse in depot */
+	if (IsTileDepotType(tile, TRANSPORT_RAIL) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
+		/* Penalise any depot tile that is not the last tile in the path. This
+		 * _should_ penalise every occurence of reversing in a depot (and only
+		 * that) */
+		cost += _patches.npf_rail_depot_reverse_penalty;
+	}
+
+	/* Check for occupied track */
+	//TODO
+
+	NPFMarkTile(tile);
+	DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
+	return cost;
+}
+
+/* Will find any depot */
+static int32 NPFFindDepot(AyStar* as, OpenListNode *current)
+{
+	/* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below,
+	 * since checking the cache not that much faster than the actual check */
+	return IsTileDepotType(current->path.node.tile, as->user_data[NPF_TYPE]) ?
+		AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
+}
+
+/* Will find a station identified using the NPFFindStationOrTileData */
+static int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current)
+{
+	NPFFindStationOrTileData* fstd = (NPFFindStationOrTileData*)as->user_target;
+	AyStarNode *node = &current->path.node;
+	TileIndex tile = node->tile;
+
+	/* If GetNeighbours said we could get here, we assume the station type
+	 * is correct */
+	if (
+		(fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) || /* We've found the tile, or */
+		(IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) /* the station */
+	) {
+		return AYSTAR_FOUND_END_NODE;
+	} else {
+		return AYSTAR_DONE;
+	}
+}
+
+/* To be called when current contains the (shortest route to) the target node.
+ * Will fill the contents of the NPFFoundTargetData using
+ * AyStarNode[NPF_TRACKDIR_CHOICE].
+ */
+static void NPFSaveTargetData(AyStar* as, OpenListNode* current)
+{
+	NPFFoundTargetData* ftd = (NPFFoundTargetData*)as->user_path;
+	ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE];
+	ftd->best_path_dist = current->g;
+	ftd->best_bird_dist = 0;
+	ftd->node = current->path.node;
+}
+
+/**
+ * Finds out if a given player's vehicles are allowed to enter a given tile.
+ * @param owner    The owner of the vehicle.
+ * @param tile     The tile that is about to be entered.
+ * @param enterdir The direction from which the vehicle wants to enter the tile.
+ * @return         true if the vehicle can enter the tile.
+ * @todo           This function should be used in other places than just NPF,
+ *                 maybe moved to another file too.
+ */
+static bool VehicleMayEnterTile(Owner owner, TileIndex tile, DiagDirection enterdir)
+{
+	if (IsTileType(tile, MP_RAILWAY) ||           /* Rail tile (also rail depot) */
+			IsRailwayStationTile(tile) ||               /* Rail station tile */
+			IsTileDepotType(tile, TRANSPORT_ROAD) ||  /* Road depot tile */
+			IsRoadStopTile(tile) ||                /* Road station tile */
+			IsTileDepotType(tile, TRANSPORT_WATER)) { /* Water depot tile */
+		return IsTileOwner(tile, owner); /* You need to own these tiles entirely to use them */
+	}
+
+	switch (GetTileType(tile)) {
+		case MP_STREET:
+			/* rail-road crossing : are we looking at the railway part? */
+			if (IsLevelCrossing(tile) &&
+					DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
+				return IsTileOwner(tile, owner); /* Railway needs owner check, while the street is public */
+			}
+			break;
+
+		case MP_TUNNELBRIDGE:
+			if ((IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) ||
+					(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL)) {
+				return IsTileOwner(tile, owner);
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	return true; /* no need to check */
+}
+
+
+/**
+ * Returns the direction the exit of the depot on the given tile is facing.
+ */
+static DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
+{
+	assert(IsTileDepotType(tile, type));
+
+	switch (type) {
+		case TRANSPORT_RAIL:  return GetRailDepotDirection(tile);
+		case TRANSPORT_ROAD:  return GetRoadDepotDirection(tile);
+		case TRANSPORT_WATER: return GetShipDepotDirection(tile);
+		default: return INVALID_DIAGDIR; /* Not reached */
+	}
+}
+
+
+/* Will just follow the results of GetTileTrackStatus concerning where we can
+ * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and
+ * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the
+ * entry and exit are neighbours. Will fill
+ * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and
+ * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */
+static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
+{
+	Trackdir src_trackdir = (Trackdir)current->path.node.direction;
+	TileIndex src_tile = current->path.node.tile;
+	DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir);
+	TileIndex dst_tile = INVALID_TILE;
+	int i;
+	TrackdirBits trackdirbits, ts;
+	TransportType type = aystar->user_data[NPF_TYPE];
+	bool override_dst_check = false;
+	/* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
+	aystar->num_neighbours = 0;
+	DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
+
+	/* Find dest tile */
+	if (IsTunnelTile(src_tile) && GetTunnelDirection(src_tile) == src_exitdir) {
+		/* This is a tunnel. We know this tunnel is our type,
+		 * otherwise we wouldn't have got here. It is also facing us,
+		 * so we should skip it's body */
+		dst_tile = GetOtherTunnelEnd(src_tile);
+		override_dst_check = true;
+	} else if (IsBridgeTile(src_tile) && GetBridgeRampDirection(src_tile) == src_exitdir) {
+		dst_tile = GetOtherBridgeEnd(src_tile);
+		override_dst_check = true;
+	} else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) {
+		/* This is a road station or a train or road depot. We can enter and exit
+		 * those from one side only. Trackdirs don't support that (yet), so we'll
+		 * do this here. */
+
+		DiagDirection exitdir;
+		/* Find out the exit direction first */
+		if (IsRoadStopTile(src_tile)) {
+			exitdir = GetRoadStopDir(src_tile);
+		} else { /* Train or road depot */
+			exitdir = GetDepotDirection(src_tile, type);
+		}
+
+		/* Let's see if were headed the right way into the depot */
+		if (src_trackdir == DiagdirToDiagTrackdir(ReverseDiagDir(exitdir))) {
+			/* We are headed inwards. We cannot go through the back of the depot.
+			 * For rail, we can now reverse. Reversing for road vehicles is never
+			 * useful, since you cannot take paths you couldn't take before
+			 * reversing (as with rail). */
+			if (type == TRANSPORT_RAIL) {
+				/* We can only reverse here, so we'll not consider this direction, but
+				 * jump ahead to the reverse direction.  It would be nicer to return
+				 * one neighbour here (the reverse trackdir of the one we are
+				 * considering now) and then considering that one to return the tracks
+				 * outside of the depot. But, because the code layout is cleaner this
+				 * way, we will just pretend we are reversed already */
+				src_trackdir = ReverseTrackdir(src_trackdir);
+				dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(exitdir));
+			} else {
+				dst_tile = INVALID_TILE; /* Road vehicle heading inwards: dead end */
+			}
+		} else {
+			dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(exitdir));
+		}
+	} else {
+		/* This a normal tile, a bridge, a tunnel exit, etc. */
+		dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(TrackdirToExitdir(src_trackdir)));
+	}
+	if (dst_tile == INVALID_TILE) {
+		/* We reached the border of the map */
+		/* TODO Nicer control flow for this */
+		return;
+	}
+
+	/* I can't enter a tunnel entry/exit tile from a tile above the tunnel. Note
+	 * that I can enter the tunnel from a tile below the tunnel entrance. This
+	 * solves the problem of vehicles wanting to drive off a tunnel entrance */
+	if (!override_dst_check) {
+		if (IsTileType(dst_tile, MP_TUNNELBRIDGE)) {
+			if (IsTunnel(dst_tile)) {
+				if (GetTunnelDirection(dst_tile) != src_exitdir) return;
+			} else {
+				if (GetBridgeRampDirection(dst_tile) != src_exitdir) return;
+			}
+		}
+	}
+
+	/* check correct rail type (mono, maglev, etc) */
+	if (type == TRANSPORT_RAIL) {
+		RailType dst_type = GetTileRailType(dst_tile, src_trackdir);
+		if (!HASBIT(aystar->user_data[NPF_RAILTYPES], dst_type))
+			return;
+	}
+
+	/* Check the owner of the tile */
+	if (!VehicleMayEnterTile(aystar->user_data[NPF_OWNER], dst_tile, TrackdirToExitdir(src_trackdir))) {
+		return;
+	}
+
+	/* Determine available tracks */
+	if (type != TRANSPORT_WATER && (IsRoadStopTile(dst_tile) || IsTileDepotType(dst_tile, type))){
+		/* Road stations and road and train depots return 0 on GTTS, so we have to do this by hand... */
+		DiagDirection exitdir;
+		if (IsRoadStopTile(dst_tile)) {
+			exitdir = GetRoadStopDir(dst_tile);
+		} else { /* Road or train depot */
+			exitdir = GetDepotDirection(dst_tile, type);
+		}
+		/* Find the trackdirs that are available for a depot or station with this
+		 * orientation. They are only "inwards", since we are reaching this tile
+		 * from some other tile. This prevents vehicles driving into depots from
+		 * the back */
+		ts = TrackdirToTrackdirBits(DiagdirToDiagTrackdir(ReverseDiagDir(exitdir)));
+	} else {
+		ts = GetTileTrackStatus(dst_tile, type);
+	}
+	trackdirbits = ts & TRACKDIR_BIT_MASK; /* Filter out signal status and the unused bits */
+
+	DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits);
+	/* Select only trackdirs we can reach from our current trackdir */
+	trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
+	if (_patches.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) /* Filter out trackdirs that would make 90 deg turns for trains */
+		trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
+
+	DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
+
+	i = 0;
+	/* Enumerate possible track */
+	while (trackdirbits != 0) {
+		Trackdir dst_trackdir;
+		dst_trackdir =  FindFirstBit2x64(trackdirbits);
+		trackdirbits = KillFirstBit2x64(trackdirbits);
+		DEBUG(npf, 5, "Expanded into trackdir: %d, remaining trackdirs: 0x%X", dst_trackdir, trackdirbits);
+
+		/* Check for oneway signal against us */
+		if (IsTileType(dst_tile, MP_RAILWAY) && GetRailTileType(dst_tile) == RAIL_TILE_SIGNALS) {
+			if (HasSignalOnTrackdir(dst_tile, ReverseTrackdir(dst_trackdir)) && !HasSignalOnTrackdir(dst_tile, dst_trackdir))
+				// if one way signal not pointing towards us, stop going in this direction.
+				break;
+		}
+		{
+			/* We've found ourselves a neighbour :-) */
+			AyStarNode* neighbour = &aystar->neighbours[i];
+			neighbour->tile = dst_tile;
+			neighbour->direction = dst_trackdir;
+			/* Save user data */
+			neighbour->user_data[NPF_NODE_FLAGS] = current->path.node.user_data[NPF_NODE_FLAGS];
+			NPFFillTrackdirChoice(neighbour, current);
+		}
+		i++;
+	}
+	aystar->num_neighbours = i;
+}
+
+/*
+ * Plan a route to the specified target (which is checked by target_proc),
+ * from start1 and if not NULL, from start2 as well. The type of transport we
+ * are checking is in type. reverse_penalty is applied to all routes that
+ * originate from the second start node.
+ * When we are looking for one specific target (optionally multiple tiles), we
+ * should use a good heuristic to perform aystar search. When we search for
+ * multiple targets that are spread around, we should perform a breadth first
+ * search by specifiying CalcZero as our heuristic.
+ */
+static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start2, NPFFindStationOrTileData* target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, Owner owner, RailTypeMask railtypes, uint reverse_penalty)
+{
+	int r;
+	NPFFoundTargetData result;
+
+	/* Initialize procs */
+	_npf_aystar.CalculateH = heuristic_proc;
+	_npf_aystar.EndNodeCheck = target_proc;
+	_npf_aystar.FoundEndNode = NPFSaveTargetData;
+	_npf_aystar.GetNeighbours = NPFFollowTrack;
+	switch (type) {
+		default: NOT_REACHED();
+		case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
+		case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
+		case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
+	}
+
+	/* Initialize Start Node(s) */
+	start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+	start1->user_data[NPF_NODE_FLAGS] = 0;
+	_npf_aystar.addstart(&_npf_aystar, start1, 0);
+	if (start2) {
+		start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+		start2->user_data[NPF_NODE_FLAGS] = 0;
+		NPFSetFlag(start2, NPF_FLAG_REVERSE, true);
+		_npf_aystar.addstart(&_npf_aystar, start2, reverse_penalty);
+	}
+
+	/* Initialize result */
+	result.best_bird_dist = (uint)-1;
+	result.best_path_dist = (uint)-1;
+	result.best_trackdir = INVALID_TRACKDIR;
+	_npf_aystar.user_path = &result;
+
+	/* Initialize target */
+	_npf_aystar.user_target = target;
+
+	/* Initialize user_data */
+	_npf_aystar.user_data[NPF_TYPE] = type;
+	_npf_aystar.user_data[NPF_OWNER] = owner;
+	_npf_aystar.user_data[NPF_RAILTYPES] = railtypes;
+
+	/* GO! */
+	r = AyStarMain_Main(&_npf_aystar);
+	assert(r != AYSTAR_STILL_BUSY);
+
+	if (result.best_bird_dist != 0) {
+		if (target != NULL) {
+			DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile);
+		} else {
+			/* Assumption: target == NULL, so we are looking for a depot */
+			DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile);
+		}
+
+	}
+	return result;
+}
+
+NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+	AyStarNode start1;
+	AyStarNode start2;
+
+	start1.tile = tile1;
+	start2.tile = tile2;
+	/* We set this in case the target is also the start tile, we will just
+	 * return a not found then */
+	start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+	start1.direction = trackdir1;
+	start2.direction = trackdir2;
+	start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+
+	return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, railtypes, 0);
+}
+
+NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+	return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner, railtypes);
+}
+
+NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailTypeMask railtypes, uint reverse_penalty)
+{
+	AyStarNode start1;
+	AyStarNode start2;
+
+	start1.tile = tile1;
+	start2.tile = tile2;
+	/* We set this in case the target is also the start tile, we will just
+	 * return a not found then */
+	start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+	start1.direction = trackdir1;
+	start2.direction = trackdir2;
+	start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+
+	/* perform a breadth first search. Target is NULL,
+	 * since we are just looking for any depot...*/
+	return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, railtypes, reverse_penalty);
+}
+
+NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+	return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, railtypes, 0);
+}
+
+NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+	/* Okay, what we're gonna do. First, we look at all depots, calculate
+	 * the manhatten distance to get to each depot. We then sort them by
+	 * distance. We start by trying to plan a route to the closest, then
+	 * the next closest, etc. We stop when the best route we have found so
+	 * far, is shorter than the manhattan distance. This will obviously
+	 * always find the closest depot. It will probably be most efficient
+	 * for ships, since the heuristic will not be to far off then. I hope.
+	 */
+	Queue depots;
+	int r;
+	NPFFoundTargetData best_result = {(uint)-1, (uint)-1, INVALID_TRACKDIR, {INVALID_TILE, 0, {0, 0}}};
+	NPFFoundTargetData result;
+	NPFFindStationOrTileData target;
+	AyStarNode start;
+	Depot* current;
+	Depot *depot;
+
+	init_InsSort(&depots);
+	/* Okay, let's find all depots that we can use first */
+	FOR_ALL_DEPOTS(depot) {
+		/* Check if this is really a valid depot, it is of the needed type and
+		 * owner */
+		if (IsTileDepotType(depot->xy, type) && IsTileOwner(depot->xy, owner))
+			/* If so, let's add it to the queue, sorted by distance */
+			depots.push(&depots, depot, DistanceManhattan(tile, depot->xy));
+	}
+
+	/* Now, let's initialise the aystar */
+
+	/* Initialize procs */
+	_npf_aystar.CalculateH = NPFCalcStationOrTileHeuristic;
+	_npf_aystar.EndNodeCheck = NPFFindStationOrTile;
+	_npf_aystar.FoundEndNode = NPFSaveTargetData;
+	_npf_aystar.GetNeighbours = NPFFollowTrack;
+	switch (type) {
+		default: NOT_REACHED();
+		case TRANSPORT_RAIL:  _npf_aystar.CalculateG = NPFRailPathCost;  break;
+		case TRANSPORT_ROAD:  _npf_aystar.CalculateG = NPFRoadPathCost;  break;
+		case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break;
+	}
+
+	/* Initialize target */
+	target.station_index = INVALID_STATION; /* We will initialize dest_coords inside the loop below */
+	_npf_aystar.user_target = &target;
+
+	/* Initialize user_data */
+	_npf_aystar.user_data[NPF_TYPE] = type;
+	_npf_aystar.user_data[NPF_OWNER] = owner;
+
+	/* Initialize Start Node */
+	start.tile = tile;
+	start.direction = trackdir; /* We will initialize user_data inside the loop below */
+
+	/* Initialize Result */
+	_npf_aystar.user_path = &result;
+	best_result.best_path_dist = (uint)-1;
+	best_result.best_bird_dist = (uint)-1;
+
+	/* Just iterate the depots in order of increasing distance */
+	while ((current = depots.pop(&depots))) {
+		/* Check to see if we already have a path shorter than this
+		 * depot's manhattan distance. HACK: We call DistanceManhattan
+		 * again, we should probably modify the queue to give us that
+		 * value... */
+		if ( DistanceManhattan(tile, current->xy * NPF_TILE_LENGTH) > best_result.best_path_dist)
+			break;
+
+		/* Initialize Start Node */
+		/* We set this in case the target is also the start tile, we will just
+		 * return a not found then */
+		start.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
+		start.user_data[NPF_NODE_FLAGS] = 0;
+		_npf_aystar.addstart(&_npf_aystar, &start, 0);
+
+		/* Initialize result */
+		result.best_bird_dist = (uint)-1;
+		result.best_path_dist = (uint)-1;
+		result.best_trackdir = INVALID_TRACKDIR;
+
+		/* Initialize target */
+		target.dest_coords = current->xy;
+
+		/* GO! */
+		r = AyStarMain_Main(&_npf_aystar);
+		assert(r != AYSTAR_STILL_BUSY);
+
+		/* This depot is closer */
+		if (result.best_path_dist < best_result.best_path_dist)
+			best_result = result;
+	}
+	if (result.best_bird_dist != 0) {
+		DEBUG(npf, 1, "Could not find route to any depot from tile 0x%X.", tile);
+	}
+	return best_result;
+}
+
+void InitializeNPF(void)
+{
+	init_AyStar(&_npf_aystar, NPFHash, NPF_HASH_SIZE);
+	_npf_aystar.loops_per_tick = 0;
+	_npf_aystar.max_path_cost = 0;
+	//_npf_aystar.max_search_nodes = 0;
+	/* We will limit the number of nodes for now, until we have a better
+	 * solution to really fix performance */
+	_npf_aystar.max_search_nodes = _patches.npf_max_search_nodes;
+}
+
+void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v)
+{
+	/* Ships don't really reach their stations, but the tile in front. So don't
+	 * save the station id for ships. For roadvehs we don't store it either,
+	 * because multistop depends on vehicles actually reaching the exact
+	 * dest_tile, not just any stop of that station.
+	 * So only for train orders to stations we fill fstd->station_index, for all
+	 * others only dest_coords */
+	if (v->current_order.type == OT_GOTO_STATION && v->type == VEH_Train) {
+		fstd->station_index = v->current_order.dest;
+		/* Let's take the closest tile of the station as our target for trains */
+		fstd->dest_coords = CalcClosestStationTile(v->current_order.dest, v->tile);
+	} else {
+		fstd->dest_coords = v->dest_tile;
+		fstd->station_index = INVALID_STATION;
+	}
+}
deleted file mode 100644
--- a/src/oldloader.c
+++ /dev/null
@@ -1,1583 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "town.h"
-#include "industry.h"
-#include "station.h"
-#include "economy.h"
-#include "player.h"
-#include "engine.h"
-#include "vehicle.h"
-#include "signs.h"
-#include "debug.h"
-#include "depot.h"
-#include "network/network.h"
-#include "ai/ai.h"
-#include "date.h"
-
-enum {
-	HEADER_SIZE = 49,
-	BUFFER_SIZE = 4096,
-
-	OLD_MAP_SIZE = 256 * 256
-};
-
-typedef struct LoadgameState {
-	FILE *file;
-
-	uint chunk_size;
-
-	bool decoding;
-	byte decode_char;
-
-	uint buffer_count;
-	uint buffer_cur;
-	byte buffer[BUFFER_SIZE];
-
-	uint total_read;
-	bool failed;
-} LoadgameState;
-
-/* OldChunk-Type */
-typedef enum OldChunkTypes {
-	OC_SIMPLE    = 0,
-	OC_NULL      = 1,
-	OC_CHUNK     = 2,
-	OC_ASSERT    = 3,
-	/* 8 bytes allocated (256 max) */
-
-	OC_VAR_I8    = 1 << 8,
-	OC_VAR_U8    = 2 << 8,
-	OC_VAR_I16   = 3 << 8,
-	OC_VAR_U16   = 4 << 8,
-	OC_VAR_I32   = 5 << 8,
-	OC_VAR_U32   = 6 << 8,
-	OC_VAR_I64   = 7 << 8,
-	/* 8 bytes allocated (256 max) */
-
-	OC_FILE_I8   = 1 << 16,
-	OC_FILE_U8   = 2 << 16,
-	OC_FILE_I16  = 3 << 16,
-	OC_FILE_U16  = 4 << 16,
-	OC_FILE_I32  = 5 << 16,
-	OC_FILE_U32  = 6 << 16,
-	/* 8 bytes allocated (256 max) */
-
-	OC_INT8      = OC_VAR_I8   | OC_FILE_I8,
-	OC_UINT8     = OC_VAR_U8   | OC_FILE_U8,
-	OC_INT16     = OC_VAR_I16  | OC_FILE_I16,
-	OC_UINT16    = OC_VAR_U16  | OC_FILE_U16,
-	OC_INT32     = OC_VAR_I32  | OC_FILE_I32,
-	OC_UINT32    = OC_VAR_U32  | OC_FILE_U32,
-
-	OC_TILE      = OC_VAR_U32  | OC_FILE_U16,
-
-	OC_END       = 0 ///< End of the whole chunk, all 32bits set to zero
-} OldChunkType;
-
-typedef bool OldChunkProc(LoadgameState *ls, int num);
-
-typedef struct OldChunks {
-	OldChunkType type;   ///< Type of field
-	uint32 amount;       ///< Amount of fields
-
-	void *ptr;           ///< Pointer where to save the data (may only be set if offset is 0)
-	uint offset;         ///< Offset from basepointer (may only be set if ptr is NULL)
-	OldChunkProc *proc;  ///< Pointer to function that is called with OC_CHUNK
-} OldChunks;
-
-/* If it fails, check lines above.. */
-assert_compile(sizeof(TileIndex) == 4);
-
-static uint32 _bump_assert_value;
-static bool   _read_ttdpatch_flags;
-
-static OldChunkType GetOldChunkType(OldChunkType type)     {return GB(type, 0, 8);}
-static OldChunkType GetOldChunkVarType(OldChunkType type)  {return GB(type, 8, 8) << 8;}
-static OldChunkType GetOldChunkFileType(OldChunkType type) {return GB(type, 16, 8) << 16;}
-
-static inline byte CalcOldVarLen(OldChunkType type)
-{
-	static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
-	byte length = GB(type, 8, 8);
-	assert(length != 0 && length < lengthof(type_mem_size));
-	return type_mem_size[length];
-}
-
-/**
- *
- * Reads a byte from a file (do not call yourself, use ReadByte())
- *
- */
-static byte ReadByteFromFile(LoadgameState *ls)
-{
-	/* To avoid slow reads, we read BUFFER_SIZE of bytes per time
-	and just return a byte per time */
-	if (ls->buffer_cur >= ls->buffer_count) {
-		/* Read some new bytes from the file */
-		int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
-
-		/* We tried to read, but there is nothing in the file anymore.. */
-		if (count == 0) {
-			DEBUG(oldloader, 0, "Read past end of file, loading failed");
-			ls->failed = true;
-		}
-
-		ls->buffer_count = count;
-		ls->buffer_cur   = 0;
-	}
-
-	return ls->buffer[ls->buffer_cur++];
-}
-
-/**
- *
- * Reads a byte from the buffer and decompress if needed
- *
- */
-static byte ReadByte(LoadgameState *ls)
-{
-	/* Old savegames have a nice compression algorithm (RLE)
-	which means that we have a chunk, which starts with a length
-	byte. If that byte is negative, we have to repeat the next byte
-	that many times (+1). Else, we need to read that amount of bytes.
-	Works pretty good if you have many zero's behind eachother */
-
-	if (ls->chunk_size == 0) {
-		/* Read new chunk */
-		int8 new_byte = ReadByteFromFile(ls);
-
-		if (new_byte < 0) {
-			/* Repeat next char for new_byte times */
-			ls->decoding    = true;
-			ls->decode_char = ReadByteFromFile(ls);
-			ls->chunk_size  = -new_byte + 1;
-		} else {
-			ls->decoding    = false;
-			ls->chunk_size  = new_byte + 1;
-		}
-	}
-
-	ls->total_read++;
-	ls->chunk_size--;
-
-	return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
-}
-
-static inline uint16 ReadUint16(LoadgameState *ls)
-{
-	byte x = ReadByte(ls);
-	return x | ReadByte(ls) << 8;
-}
-
-static inline uint32 ReadUint32(LoadgameState *ls)
-{
-	uint16 x = ReadUint16(ls);
-	return x | ReadUint16(ls) << 16;
-}
-
-/**
- *
- * Loads a chunk from the old savegame
- *
- */
-static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
-{
-	const OldChunks *chunk = chunks;
-	byte *base_ptr = base;
-
-	while (chunk->type != OC_END) {
-		byte* ptr = chunk->ptr;
-		uint i;
-
-		for (i = 0; i < chunk->amount; i++) {
-			if (ls->failed) return false;
-
-			/* Handle simple types */
-			if (GetOldChunkType(chunk->type) != 0) {
-				switch (GetOldChunkType(chunk->type)) {
-					/* Just read the byte and forget about it */
-					case OC_NULL: ReadByte(ls); break;
-
-					case OC_CHUNK:
-						/* Call function, with 'i' as parameter to tell which item we
-						 * are going to read */
-						if (!chunk->proc(ls, i)) return false;
-						break;
-
-					case OC_ASSERT:
-						DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
-						if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
-					default: break;
-				}
-			} else {
-				uint32 res = 0;
-
-				/* Reading from the file: bits 16 to 23 have the FILE type */
-				switch (GetOldChunkFileType(chunk->type)) {
-					case OC_FILE_I8:  res = (int8)ReadByte(ls); break;
-					case OC_FILE_U8:  res = ReadByte(ls); break;
-					case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
-					case OC_FILE_U16: res = ReadUint16(ls); break;
-					case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
-					case OC_FILE_U32: res = ReadUint32(ls); break;
-					default: NOT_REACHED();
-				}
-
-				/* Sanity check */
-				assert(base_ptr != NULL || chunk->ptr != NULL);
-
-				/* Writing to the var: bits 8 to 15 have the VAR type */
-				if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset;
-
-				/* Write the data */
-				switch (GetOldChunkVarType(chunk->type)) {
-					case OC_VAR_I8: *(int8  *)ptr = GB(res, 0, 8); break;
-					case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
-					case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
-					case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
-					case OC_VAR_I32:*(int32 *)ptr = res; break;
-					case OC_VAR_U32:*(uint32*)ptr = res; break;
-					case OC_VAR_I64:*(int64 *)ptr = res; break;
-					default: NOT_REACHED();
-				}
-
-				/* Increase pointer base for arrays when looping */
-				if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type);
-			}
-		}
-
-		chunk++;
-	}
-
-	return true;
-}
-
-/**
- *
- * Initialize some data before reading
- *
- */
-static void InitLoading(LoadgameState *ls)
-{
-	ls->chunk_size   = 0;
-	ls->total_read   = 0;
-	ls->failed       = false;
-
-	ls->decoding     = false;
-	ls->decode_char  = 0;
-
-	ls->buffer_cur   = 0;
-	ls->buffer_count = 0;
-	memset(ls->buffer, 0, BUFFER_SIZE);
-
-	_bump_assert_value = 0;
-
-	_read_ttdpatch_flags = false;
-}
-
-
-/*
- * Begin -- Stuff to fix the savegames to be OpenTTD compatible
- */
-
-extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type);
-
-static void FixOldTowns(void)
-{
-	Town *town;
-
-	/* Convert town-names if needed */
-	FOR_ALL_TOWNS(town) {
-		if (IS_INT_INSIDE(town->townnametype, 0x20C1, 0x20C3)) {
-			town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _opt.town_name;
-			town->townnameparts = GetOldTownName(town->townnameparts, _opt.town_name);
-		}
-	}
-}
-
-static void FixOldStations(void)
-{
-	Station *st;
-
-	FOR_ALL_STATIONS(st) {
-		/* Check if we need to swap width and height for the station */
-		if (st->train_tile != 0 && GetRailStationAxis(st->train_tile) != AXIS_X) {
-			swap_byte(&st->trainst_w, &st->trainst_h);
-		}
-
-		/* Check if there is a bus or truck station, and convert to new format */
-		if (st->bus_tile_obsolete != 0) {
-			st->bus_stops = AllocateRoadStop();
-			st->bus_stops->xy = st->bus_tile_obsolete;
-			st->bus_stops->used = true;
-			st->bus_stops->status = 3;
-			st->bus_stops->station = st->index;
-			st->bus_stops->next = NULL;
-			st->bus_stops->prev = NULL;
-			st->bus_stops->num_vehicles = 0;
-		}
-
-		if (st->lorry_tile_obsolete != 0) {
-			st->truck_stops = AllocateRoadStop();
-			st->truck_stops->xy = st->lorry_tile_obsolete;
-			st->truck_stops->used = true;
-			st->truck_stops->status = 3;
-			st->truck_stops->station = st->index;
-			st->truck_stops->next = NULL;
-			st->truck_stops->prev = NULL;
-			st->truck_stops->num_vehicles = 0;
-		}
-	}
-}
-
-static void FixOldVehicles(void)
-{
-	/* Check for shared orders, and link them correctly */
-	Vehicle* v;
-
-	FOR_ALL_VEHICLES(v) {
-		Vehicle *u;
-
-		FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
-			/* If a vehicle has the same orders, add the link to eachother
-			 * in both vehicles */
-			if (v->orders == u->orders) {
-				v->next_shared = u;
-				u->prev_shared = v;
-				break;
-			}
-		}
-	}
-}
-
-/*
- * End -- Stuff to fix the savegames to be OpenTTD compatible
- */
-
-
-/* Help:
- *  - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
- *       be given via base in LoadChunk() as real pointer
- *  - OCL_VAR: load 'type' to a global var
- *  - OCL_END: every struct must end with this
- *  - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something
- *  - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times
- *  - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;)
- */
-#define OCL_SVAR(type, base, offset)         { type,          1, NULL,    (uint)offsetof(base, offset), NULL }
-#define OCL_VAR(type, amount, pointer)       { type,     amount, pointer, 0,                      NULL }
-#define OCL_END()                                   { OC_END,        0, NULL,    0,                      NULL }
-#define OCL_NULL(amount)                            { OC_NULL,  amount, NULL,    0,                      NULL }
-#define OCL_CHUNK(amount, proc)                     { OC_CHUNK, amount, NULL,    0,                      proc }
-#define OCL_ASSERT(size)                            { OC_ASSERT,     1, NULL, size,                      NULL }
-
-/* The savegames has some hard-coded pointers, because it always enters the same
-    piece of memory.. we don't.. so we need to remap ;)
-   Old Towns are 94 bytes big
-   Old Orders are 2 bytes big */
-#define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94
-#define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2
-
-extern TileIndex _animated_tile_list[256];
-extern char _name_array[512][32];
-
-static byte   _old_vehicle_multiplier;
-static uint8  _old_map3[OLD_MAP_SIZE * 2];
-static bool   _new_ttdpatch_format;
-static uint32 _old_town_index;
-static uint16 _old_string_id;
-static uint16 _old_string_id_2;
-
-static void ReadTTDPatchFlags(void)
-{
-	int i;
-
-	if (_read_ttdpatch_flags) return;
-
-	_read_ttdpatch_flags = true;
-
-	/* TTDPatch misuses _old_map3 for flags.. read them! */
-	_old_vehicle_multiplier = _old_map3[0];
-	/* Somehow.... there was an error in some savegames, so 0 becomes 1
-	and 1 becomes 2. The rest of the values are okay */
-	if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++;
-
-	/* TTDPatch incraeses the Vehicle-part in the middle of the game,
-	so if the multipler is anything else but 1, the assert fails..
-	bump the assert value so it doesn't!
-	(1 multipler == 850 vehicles
-	1 vehicle   == 128 bytes */
-	_bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128;
-
-	/* Check if we have a modern TTDPatch savegame (has extra data all around) */
-	_new_ttdpatch_format = (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0);
-
-	/* Clean the misused places */
-	for (i = 0;       i < 17;      i++) _old_map3[i] = 0;
-	for (i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0;
-
-	if (_new_ttdpatch_format) DEBUG(oldloader, 1, "Found TTDPatch game");
-
-	DEBUG(oldloader, 1, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850);
-}
-
-static const OldChunks town_chunk[] = {
-	OCL_SVAR(   OC_TILE, Town, xy ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, population ),
-	OCL_SVAR( OC_UINT16, Town, townnametype ),
-	OCL_SVAR( OC_UINT32, Town, townnameparts ),
-	OCL_SVAR(  OC_UINT8, Town, grow_counter ),
-	OCL_NULL( 1 ),         // sort_index,        no longer in use
-	OCL_NULL( 4 ),         // sign-coordinates,  no longer in use
-	OCL_NULL( 2 ),         // namewidth,         no longer in use
-	OCL_SVAR( OC_UINT16, Town, flags12 ),
-	OCL_NULL( 10 ),        // radius,            no longer in use
-
-	OCL_SVAR( OC_UINT16, Town, ratings[0] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[1] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[2] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[3] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[4] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[5] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[6] ),
-	OCL_SVAR( OC_UINT16, Town, ratings[7] ),
-
-	/* XXX - This is pretty odd.. we read 32bit, but only write 8bit.. sure there is
-	nothing changed?? */
-	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ),
-	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ),
-	OCL_SVAR( OC_UINT16, Town, num_houses ),
-	OCL_SVAR(  OC_UINT8, Town, time_until_rebuild ),
-	OCL_SVAR(  OC_UINT8, Town, growth_rate ),
-
-	OCL_SVAR( OC_UINT16, Town, new_max_pass ),
-	OCL_SVAR( OC_UINT16, Town, new_max_mail ),
-	OCL_SVAR( OC_UINT16, Town, new_act_pass ),
-	OCL_SVAR( OC_UINT16, Town, new_act_mail ),
-	OCL_SVAR( OC_UINT16, Town, max_pass ),
-	OCL_SVAR( OC_UINT16, Town, max_mail ),
-	OCL_SVAR( OC_UINT16, Town, act_pass ),
-	OCL_SVAR( OC_UINT16, Town, act_mail ),
-
-	OCL_SVAR(  OC_UINT8, Town, pct_pass_transported ),
-	OCL_SVAR(  OC_UINT8, Town, pct_mail_transported ),
-
-	OCL_SVAR( OC_UINT16, Town, new_act_food ),
-	OCL_SVAR( OC_UINT16, Town, new_act_water ),
-	OCL_SVAR( OC_UINT16, Town, act_food ),
-	OCL_SVAR( OC_UINT16, Town, act_water ),
-
-	OCL_SVAR(  OC_UINT8, Town, road_build_months ),
-	OCL_SVAR(  OC_UINT8, Town, fund_buildings_months ),
-
-	OCL_NULL( 8 ),         // some junk at the end of the record
-
-	OCL_END()
-};
-static bool LoadOldTown(LoadgameState *ls, int num)
-{
-	if (!AddBlockIfNeeded(&_Town_pool, num))
-		error("Towns: failed loading savegame: too many towns");
-
-	return LoadChunk(ls, GetTown(num), town_chunk);
-}
-
-static uint16 _old_order;
-static const OldChunks order_chunk[] = {
-	OCL_VAR ( OC_UINT16,   1, &_old_order ),
-	OCL_END()
-};
-
-static bool LoadOldOrder(LoadgameState *ls, int num)
-{
-	if (!AddBlockIfNeeded(&_Order_pool, num))
-		error("Orders: failed loading savegame: too many orders");
-
-	if (!LoadChunk(ls, NULL, order_chunk)) return false;
-
-	AssignOrder(GetOrder(num), UnpackOldOrder(_old_order));
-
-	/* Relink the orders to eachother (in TTD(Patch) the orders for one
-	vehicle are behind eachother, with OT_NOTHING as indication that
-	it is the last order */
-	if (num > 0 && GetOrder(num)->type != OT_NOTHING)
-		GetOrder(num - 1)->next = GetOrder(num);
-
-	return true;
-}
-
-static const OldChunks depot_chunk[] = {
-	OCL_SVAR(   OC_TILE, Depot, xy ),
-	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
-	OCL_END()
-};
-
-static bool LoadOldDepot(LoadgameState *ls, int num)
-{
-	if (!AddBlockIfNeeded(&_Depot_pool, num))
-		error("Depots: failed loading savegame: too many depots");
-
-	if (!LoadChunk(ls, GetDepot(num), depot_chunk)) return false;
-
-	if (IsValidDepot(GetDepot(num))) {
-		GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
-	}
-
-	return true;
-}
-
-static int32 _old_price;
-static uint16 _old_price_frac;
-static const OldChunks price_chunk[] = {
-	OCL_VAR (  OC_INT32,   1, &_old_price ),
-	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
-	OCL_END()
-};
-
-static bool LoadOldPrice(LoadgameState *ls, int num)
-{
-	if (!LoadChunk(ls, NULL, price_chunk)) return false;
-
-	/* We use a struct to store the prices, but they are ints in a row..
-	so just access the struct as an array of int32's */
-	((int32*)&_price)[num] = _old_price;
-	_price_frac[num] = _old_price_frac;
-
-	return true;
-}
-
-static const OldChunks cargo_payment_rate_chunk[] = {
-	OCL_VAR (  OC_INT32,   1, &_old_price ),
-	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
-
-	OCL_NULL( 2 ),         // Junk
-	OCL_END()
-};
-
-static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num)
-{
-	if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) return false;
-
-	_cargo_payment_rates[num] = -_old_price;
-	_cargo_payment_rates_frac[num] = _old_price_frac;
-
-	return true;
-}
-
-static uint8 _old_platforms;
-static uint _current_station_id;
-
-static const OldChunks goods_chunk[] = {
-	OCL_SVAR( OC_UINT16, GoodsEntry, waiting_acceptance ),
-	OCL_SVAR(  OC_UINT8, GoodsEntry, days_since_pickup ),
-	OCL_SVAR(  OC_UINT8, GoodsEntry, rating ),
-	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, GoodsEntry, enroute_from ),
-	OCL_SVAR(  OC_UINT8, GoodsEntry, enroute_time ),
-	OCL_SVAR(  OC_UINT8, GoodsEntry, last_speed ),
-	OCL_SVAR(  OC_UINT8, GoodsEntry, last_age ),
-
-	OCL_END()
-};
-
-static bool LoadOldGood(LoadgameState *ls, int num)
-{
-	Station *st = GetStation(_current_station_id);
-	return LoadChunk(ls, &st->goods[num], goods_chunk);
-}
-
-static const OldChunks station_chunk[] = {
-	OCL_SVAR(   OC_TILE, Station, xy ),
-	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
-
-	OCL_SVAR(   OC_TILE, Station, bus_tile_obsolete ),
-	OCL_SVAR(   OC_TILE, Station, lorry_tile_obsolete ),
-	OCL_SVAR(   OC_TILE, Station, train_tile ),
-	OCL_SVAR(   OC_TILE, Station, airport_tile ),
-	OCL_SVAR(   OC_TILE, Station, dock_tile ),
-
-	OCL_VAR (  OC_UINT8,   1, &_old_platforms ),
-
-	OCL_NULL( 1 ),         // sort-index, no longer in use
-	OCL_NULL( 2 ),         // sign-width, no longer in use
-
-	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
-
-	OCL_NULL( 4 ),         // sign left/top, no longer in use
-
-	OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ),
-
-	OCL_CHUNK( 12, LoadOldGood ),
-
-	OCL_SVAR(  OC_UINT8, Station, time_since_load ),
-	OCL_SVAR(  OC_UINT8, Station, time_since_unload ),
-	OCL_SVAR(  OC_UINT8, Station, delete_ctr ),
-	OCL_SVAR(  OC_UINT8, Station, owner ),
-	OCL_SVAR(  OC_UINT8, Station, facilities ),
-	OCL_SVAR(  OC_UINT8, Station, airport_type ),
-	OCL_NULL( 2 ),         // Bus/truck status, no longer in use
-	OCL_SVAR(  OC_UINT8, Station, blocked_months_obsolete ),
-	OCL_NULL( 1 ),         // Unknown
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ),
-	OCL_NULL( 2 ),         // last_vehicle. now last_vehicle_type
-
-	OCL_NULL( 4 ),         // Junk at end of chunk
-
-	OCL_END()
-};
-static bool LoadOldStation(LoadgameState *ls, int num)
-{
-	Station *st;
-
-	if (!AddBlockIfNeeded(&_Station_pool, num))
-		error("Stations: failed loading savegame: too many stations");
-
-	st = GetStation(num);
-	_current_station_id = num;
-
-	if (!LoadChunk(ls, st, station_chunk))
-		return false;
-
-	if (IsValidStation(st)) {
-		if (st->train_tile) {
-			/* Calculate the trainst_w and trainst_h */
-			uint w = GB(_old_platforms, 3, 3);
-			uint h = GB(_old_platforms, 0, 3);
-			st->trainst_w = w;
-			st->trainst_h = h;
-		}
-
-		st->town    = GetTown(REMAP_TOWN_IDX(_old_town_index));
-		st->string_id = RemapOldStringID(_old_string_id);
-	}
-
-	return true;
-}
-
-static const OldChunks industry_chunk[] = {
-	OCL_SVAR(   OC_TILE, Industry, xy ),
-	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
-	OCL_SVAR(  OC_UINT8, Industry, width ),
-	OCL_SVAR(  OC_UINT8, Industry, height ),
-	OCL_SVAR(  OC_UINT8, Industry, produced_cargo[0] ),
-	OCL_SVAR(  OC_UINT8, Industry, produced_cargo[1] ),
-
-	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[0] ),
-	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[1] ),
-
-	OCL_SVAR(  OC_UINT8, Industry, production_rate[0] ),
-	OCL_SVAR(  OC_UINT8, Industry, production_rate[1] ),
-
-	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[0] ),
-	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[1] ),
-	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[2] ),
-
-	OCL_SVAR(  OC_UINT8, Industry, prod_level ),
-
-	OCL_SVAR( OC_UINT16, Industry, last_mo_production[0] ),
-	OCL_SVAR( OC_UINT16, Industry, last_mo_production[1] ),
-	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[0] ),
-	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[1] ),
-
-	OCL_SVAR(  OC_UINT8, Industry, pct_transported[0] ),
-	OCL_SVAR(  OC_UINT8, Industry, pct_transported[1] ),
-
-	OCL_SVAR( OC_UINT16, Industry, total_production[0] ),
-	OCL_SVAR( OC_UINT16, Industry, total_production[1] ),
-	OCL_SVAR( OC_UINT16, Industry, total_transported[0] ),
-	OCL_SVAR( OC_UINT16, Industry, total_transported[1] ),
-
-	OCL_SVAR(  OC_UINT8, Industry, type ),
-	OCL_SVAR(  OC_UINT8, Industry, owner ),
-	OCL_SVAR(  OC_UINT8, Industry, random_color ),
-	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ),
-	OCL_SVAR( OC_UINT16, Industry, counter ),
-	OCL_SVAR(  OC_UINT8, Industry, was_cargo_delivered ),
-
-	OCL_NULL( 9 ), // Random junk at the end of this chunk
-
-	OCL_END()
-};
-
-static bool LoadOldIndustry(LoadgameState *ls, int num)
-{
-	Industry *i;
-
-	if (!AddBlockIfNeeded(&_Industry_pool, num))
-		error("Industries: failed loading savegame: too many industries");
-
-	i = GetIndustry(num);
-	if (!LoadChunk(ls, i, industry_chunk)) return false;
-
-	if (IsValidIndustry(i)) {
-		i->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
-	}
-
-	return true;
-}
-
-static PlayerID _current_player_id;
-static uint16 _old_inaugurated_year;
-static int32 _old_yearly;
-
-static const OldChunks player_yearly_chunk[] = {
-	OCL_VAR(  OC_INT32,   1, &_old_yearly ),
-	OCL_END()
-};
-
-static bool OldPlayerYearly(LoadgameState *ls, int num)
-{
-	int i;
-	Player *p = GetPlayer(_current_player_id);
-
-	for (i = 0; i < 13; i++) {
-		if (!LoadChunk(ls, NULL, player_yearly_chunk)) return false;
-
-		p->yearly_expenses[num][i] = _old_yearly;
-	}
-
-	return true;
-}
-
-static const OldChunks player_economy_chunk[] = {
-	OCL_SVAR( OC_INT32, PlayerEconomyEntry, income ),
-	OCL_SVAR( OC_INT32, PlayerEconomyEntry, expenses ),
-	OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ),
-	OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ),
-	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ),
-
-	OCL_END()
-};
-
-static bool OldPlayerEconomy(LoadgameState *ls, int num)
-{
-	int i;
-	Player *p = GetPlayer(_current_player_id);
-
-	if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk)) return false;
-
-	/* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */
-	p->cur_economy.income   = -p->cur_economy.income;
-	p->cur_economy.expenses = -p->cur_economy.expenses;
-
-	for (i = 0; i < 24; i++) {
-		if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk)) return false;
-
-		p->old_economy[i].income   = -p->old_economy[i].income;
-		p->old_economy[i].expenses = -p->old_economy[i].expenses;
-	}
-
-	return true;
-}
-
-static const OldChunks player_ai_build_rec_chunk[] = {
-	OCL_SVAR(   OC_TILE, AiBuildRec, spec_tile ),
-	OCL_SVAR(   OC_TILE, AiBuildRec, use_tile ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, rand_rng ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, cur_building_rule ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, unk6 ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, unk7 ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_a ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_b ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, direction ),
-	OCL_SVAR(  OC_UINT8, AiBuildRec, cargo ),
-
-	OCL_NULL( 8 ),  // Junk...
-
-	OCL_END()
-};
-
-static bool OldLoadAIBuildRec(LoadgameState *ls, int num)
-{
-	Player *p = GetPlayer(_current_player_id);
-
-	switch (num) {
-		case 0: return LoadChunk(ls, &p->ai.src, player_ai_build_rec_chunk);
-		case 1: return LoadChunk(ls, &p->ai.dst, player_ai_build_rec_chunk);
-		case 2: return LoadChunk(ls, &p->ai.mid1, player_ai_build_rec_chunk);
-		case 3: return LoadChunk(ls, &p->ai.mid2, player_ai_build_rec_chunk);
-	}
-
-	return false;
-}
-static const OldChunks player_ai_chunk[] = {
-	OCL_SVAR(  OC_UINT8, PlayerAI, state ),
-	OCL_NULL( 1 ),         // Junk
-	OCL_SVAR(  OC_UINT8, PlayerAI, state_mode ),
-	OCL_SVAR( OC_UINT16, PlayerAI, state_counter ),
-	OCL_SVAR( OC_UINT16, PlayerAI, timeout_counter ),
-
-	OCL_CHUNK( 4, OldLoadAIBuildRec ),
-
-	OCL_NULL( 20 ),        // More junk
-
-	OCL_SVAR(  OC_UINT8, PlayerAI, cargo_type ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, num_wagons ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, build_kind ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, num_build_rec ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, num_loco_to_build ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, num_want_fullload ),
-
-	OCL_NULL( 14 ),        // Oh no more junk :|
-
-	OCL_NULL( 2 ),         // Loco-id, not used
-
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[0] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[1] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[2] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[3] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[4] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[5] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[6] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[7] ),
-	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[8] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[0] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[1] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[2] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[3] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[4] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[5] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[6] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[7] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[8] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[9] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[10] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[11] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[12] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[13] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[14] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[15] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[16] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[17] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[18] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[19] ),
-
-	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_a ),
-	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_b ),
-	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_a ),
-	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_b ),
-
-	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_a ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_b ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_a ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_b ),
-
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_tile_count ),
-
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[0] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[0] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[1] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[1] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[2] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[2] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[3] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[3] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[4] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[4] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[5] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[5] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[6] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[6] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[7] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[7] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[8] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[8] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[9] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[9] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[10] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[10] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[11] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[11] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[12] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[12] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[13] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[13] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[14] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[14] ),
-	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[15] ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[15] ),
-
-	OCL_SVAR(  OC_UINT8, PlayerAI, railtype_to_use ),
-	OCL_SVAR(  OC_UINT8, PlayerAI, route_type_mask ),
-
-	OCL_END()
-};
-
-static bool OldPlayerAI(LoadgameState *ls, int num)
-{
-	Player *p = GetPlayer(_current_player_id);
-
-	return LoadChunk(ls, &p->ai, player_ai_chunk);
-}
-
-static const OldChunks player_chunk[] = {
-	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
-	OCL_SVAR( OC_UINT32, Player, name_2 ),
-	OCL_SVAR( OC_UINT32, Player, face ),
-	OCL_VAR ( OC_UINT16,   1, &_old_string_id_2 ),
-	OCL_SVAR( OC_UINT32, Player, president_name_2 ),
-
-	OCL_SVAR(  OC_INT32, Player, player_money ),
-	OCL_SVAR(  OC_INT32, Player, current_loan ),
-
-	OCL_SVAR(  OC_UINT8, Player, player_color ),
-	OCL_SVAR(  OC_UINT8, Player, player_money_fraction ),
-	OCL_SVAR(  OC_UINT8, Player, quarters_of_bankrupcy ),
-	OCL_SVAR(  OC_UINT8, Player, bankrupt_asked ),
-	OCL_SVAR( OC_UINT32, Player, bankrupt_value ),
-	OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ),
-
-	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ),
-
-	OCL_CHUNK( 3, OldPlayerYearly ),
-	OCL_CHUNK( 1, OldPlayerEconomy ),
-
-	OCL_VAR ( OC_UINT16,   1,    &_old_inaugurated_year ),
-	OCL_SVAR(   OC_TILE, Player, last_build_coordinate ),
-	OCL_SVAR(  OC_UINT8, Player, num_valid_stat_ent ),
-
-	OCL_CHUNK( 1, OldPlayerAI ),
-
-	OCL_SVAR(  OC_UINT8, Player, block_preview ),
-	OCL_SVAR(  OC_UINT8, Player, ai.tick ),
-	OCL_SVAR(  OC_UINT8, Player, avail_railtypes ),
-	OCL_SVAR(   OC_TILE, Player, location_of_house ),
-	OCL_SVAR(  OC_UINT8, Player, share_owners[0] ),
-	OCL_SVAR(  OC_UINT8, Player, share_owners[1] ),
-	OCL_SVAR(  OC_UINT8, Player, share_owners[2] ),
-	OCL_SVAR(  OC_UINT8, Player, share_owners[3] ),
-
-	OCL_NULL( 8 ), // junk at end of chunk
-
-	OCL_END()
-};
-
-static bool LoadOldPlayer(LoadgameState *ls, int num)
-{
-	Player *p = GetPlayer(num);
-
-	_current_player_id = num;
-
-	if (!LoadChunk(ls, p, player_chunk)) return false;
-
-	p->name_1 = RemapOldStringID(_old_string_id);
-	p->president_name_1 = RemapOldStringID(_old_string_id_2);
-	p->money64 = p->player_money;
-
-	if (num == 0) {
-		/* If the first player has no name, make sure we call it UNNAMED */
-		if (p->name_1 == 0)
-			p->name_1 = STR_SV_UNNAMED;
-	} else {
-		/* Beside some multiplayer maps (1 on 1), which we don't official support,
-		all other players are an AI.. mark them as such */
-		p->is_ai = true;
-	}
-
-	/* Sometimes it is better to not ask.. in old scenarios, the money
-	was always 893288 pounds. In the newer versions this is correct,
-	but correct for those oldies
-	Ps: this also means that if you had exact 893288 pounds, you will go back
-	to 10000.. this is a very VERY small chance ;) */
-	if (p->player_money == 893288)
-		p->money64 = p->player_money = p->current_loan = 100000;
-
-	_player_colors[num] = p->player_color;
-	p->inaugurated_year = _old_inaugurated_year;
-	if (p->location_of_house == 0xFFFF)
-		p->location_of_house = 0;
-
-	/* State 20 for AI players is sell vehicle. Since the AI struct is not
-	 * really figured out as of now, p->ai.cur_veh; needed for 'sell vehicle'
-	 * is NULL and the function will crash. To fix this, just change the state
-	 * to some harmless state, like 'loop vehicle'; 1 */
-	if (!IsHumanPlayer(num) && p->ai.state == 20) p->ai.state = 1;
-
-	if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
-		AI_StartNewAI(p->index);
-
-	return true;
-}
-
-static uint32 _old_order_ptr;
-static uint16 _old_next_ptr;
-static uint32 _current_vehicle_id;
-
-static const OldChunks vehicle_train_chunk[] = {
-	OCL_SVAR(  OC_UINT8, VehicleRail, track ),
-	OCL_SVAR(  OC_UINT8, VehicleRail, force_proceed ),
-	OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ),
-	OCL_SVAR(  OC_UINT8, VehicleRail, railtype ),
-
-	OCL_NULL( 5 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_road_chunk[] = {
-	OCL_SVAR(  OC_UINT8, VehicleRoad, state ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, frame ),
-	OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking_ctr ),
-	OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, reverse_ctr ),
-
-	OCL_NULL( 1 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_ship_chunk[] = {
-	OCL_SVAR(  OC_UINT8, VehicleShip, state ),
-
-	OCL_NULL( 9 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_air_chunk[] = {
-	OCL_SVAR(  OC_UINT8, VehicleAir, pos ),
-	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ),
-	OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ),
-	OCL_SVAR(  OC_UINT8, VehicleAir, state ),
-
-	OCL_NULL( 5 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_special_chunk[] = {
-	OCL_SVAR( OC_UINT16, VehicleSpecial, unk0 ),
-	OCL_SVAR(  OC_UINT8, VehicleSpecial, unk2 ),
-
-	OCL_NULL( 7 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_disaster_chunk[] = {
-	OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ),
-	OCL_SVAR( OC_UINT16, VehicleDisaster, unk2 ),
-
-	OCL_NULL( 6 ), // Junk
-
-	OCL_END()
-};
-
-static const OldChunks vehicle_empty_chunk[] = {
-	OCL_NULL( 10 ), // Junk
-
-	OCL_END()
-};
-
-static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
-{
-	Vehicle *v = GetVehicle(_current_vehicle_id);
-	uint temp = ls->total_read;
-	bool res;
-
-	switch (v->type) {
-		case VEH_Train:    res = LoadChunk(ls, &v->u.rail,     vehicle_train_chunk);    break;
-		case VEH_Road:     res = LoadChunk(ls, &v->u.road,     vehicle_road_chunk);     break;
-		case VEH_Ship:     res = LoadChunk(ls, &v->u.ship,     vehicle_ship_chunk);     break;
-		case VEH_Aircraft: res = LoadChunk(ls, &v->u.air,      vehicle_air_chunk);      break;
-		case VEH_Special:  res = LoadChunk(ls, &v->u.special,  vehicle_special_chunk);  break;
-		case VEH_Disaster: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
-		default:           res = LoadChunk(ls, NULL,           vehicle_empty_chunk);    break;
-	}
-
-	/* This chunk size should always be 10 bytes */
-	if (ls->total_read - temp != 10) {
-		DEBUG(oldloader, 4, "Assert failed in Vehicle");
-		return false;
-	}
-
-	return res;
-}
-
-static const OldChunks vehicle_chunk[] = {
-	OCL_SVAR(  OC_UINT8, Vehicle, type ),
-	OCL_SVAR(  OC_UINT8, Vehicle, subtype ),
-
-	OCL_NULL( 2 ),         // Hash, calculated automatically
-	OCL_NULL( 2 ),         // Index, calculated automatically
-
-	OCL_VAR ( OC_UINT32,   1, &_old_order_ptr ),
-	OCL_VAR ( OC_UINT16,   1, &_old_order ),
-
-	OCL_SVAR(  OC_UINT8, Vehicle, num_orders ),
-	OCL_SVAR(  OC_UINT8, Vehicle, cur_order_index ),
-	OCL_SVAR(   OC_TILE, Vehicle, dest_tile ),
-	OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ),
-	OCL_SVAR( OC_UINT16, Vehicle, service_interval ),
-	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ),
-	OCL_SVAR(  OC_UINT8, Vehicle, tick_counter ),
-	OCL_SVAR( OC_UINT16, Vehicle, max_speed ),
-
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ),
-	OCL_SVAR(  OC_UINT8, Vehicle, z_pos ),
-	OCL_SVAR(  OC_UINT8, Vehicle, direction ),
-	OCL_SVAR(   OC_INT8, Vehicle, x_offs ),
-	OCL_SVAR(   OC_INT8, Vehicle, y_offs ),
-	OCL_SVAR(  OC_UINT8, Vehicle, sprite_width ),
-	OCL_SVAR(  OC_UINT8, Vehicle, sprite_height ),
-	OCL_SVAR(  OC_UINT8, Vehicle, z_height ),
-
-	OCL_SVAR(  OC_UINT8, Vehicle, owner ),
-	OCL_SVAR(   OC_TILE, Vehicle, tile ),
-	OCL_SVAR( OC_UINT16, Vehicle, cur_image ),
-
-	OCL_NULL( 8 ),        // Vehicle sprite box, calculated automatically
-
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ),
-	OCL_SVAR( OC_UINT16, Vehicle, cur_speed ),
-	OCL_SVAR(  OC_UINT8, Vehicle, subspeed ),
-	OCL_SVAR(  OC_UINT8, Vehicle, acceleration ),
-	OCL_SVAR(  OC_UINT8, Vehicle, progress ),
-
-	OCL_SVAR(  OC_UINT8, Vehicle, cargo_type ),
-	OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ),
-	OCL_SVAR( OC_UINT16, Vehicle, cargo_count ),
-	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_source ),
-	OCL_SVAR(  OC_UINT8, Vehicle, cargo_days ),
-
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ),
-	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ),
-	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ),
-
-	OCL_SVAR( OC_UINT16, Vehicle, engine_type ),
-
-	OCL_SVAR(  OC_UINT8, Vehicle, spritenum ),
-	OCL_SVAR(  OC_UINT8, Vehicle, day_counter ),
-
-	OCL_SVAR(  OC_UINT8, Vehicle, breakdowns_since_last_service ),
-	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_ctr ),
-	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_delay ),
-	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_chance ),
-
-	OCL_SVAR( OC_UINT16, Vehicle, reliability ),
-	OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ),
-
-	OCL_SVAR(  OC_INT32, Vehicle, profit_this_year ),
-	OCL_SVAR(  OC_INT32, Vehicle, profit_last_year ),
-
-	OCL_VAR ( OC_UINT16,   1, &_old_next_ptr ),
-
-	OCL_SVAR( OC_UINT32, Vehicle, value ),
-
-	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
-
-	OCL_CHUNK( 1, LoadOldVehicleUnion ),
-
-	OCL_NULL( 20 ), // Junk at end of struct (TTDPatch has some data in it)
-
-	OCL_END()
-};
-
-static bool LoadOldVehicle(LoadgameState *ls, int num)
-{
-	uint i;
-
-	/* Read the TTDPatch flags, because we need some info from it */
-	ReadTTDPatchFlags();
-
-	for (i = 0; i < _old_vehicle_multiplier; i++) {
-		Vehicle *v;
-
-		_current_vehicle_id = num * _old_vehicle_multiplier + i;
-
-		if (!AddBlockIfNeeded(&_Vehicle_pool, _current_vehicle_id))
-			error("Vehicles: failed loading savegame: too many vehicles");
-
-		v = GetVehicle(_current_vehicle_id);
-		if (!LoadChunk(ls, v, vehicle_chunk)) return false;
-
-		/* This should be consistent, else we have a big problem... */
-		if (v->index != _current_vehicle_id) {
-			DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid");
-			return false;
-		}
-
-		if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
-			v->orders = GetOrder(REMAP_ORDER_IDX(_old_order_ptr));
-		}
-		AssignOrder(&v->current_order, UnpackOldOrder(_old_order));
-
-		/* For some reason we need to correct for this */
-		switch (v->spritenum) {
-			case 0xfd: break;
-			case 0xff: v->spritenum = 0xfe; break;
-			default:   v->spritenum >>= 1; break;
-		}
-
-		if (_old_next_ptr != 0xFFFF)
-			v->next = GetVehicle(_old_next_ptr);
-
-		v->string_id = RemapOldStringID(_old_string_id);
-
-		/* Vehicle-subtype is different in TTD(Patch) */
-		if (v->type == VEH_Special) v->subtype = v->subtype >> 1;
-	}
-
-	return true;
-}
-
-static const OldChunks sign_chunk[] = {
-	OCL_SVAR( OC_UINT16, Sign, str ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,Sign, x ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,Sign, y ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ),
-
-	OCL_NULL( 6 ),         // Width of sign, no longer in use
-
-	OCL_END()
-};
-
-static bool LoadOldSign(LoadgameState *ls, int num)
-{
-	if (!AddBlockIfNeeded(&_Sign_pool, num))
-		error("Signs: failed loading savegame: too many signs");
-
-	return LoadChunk(ls, GetSign(num), sign_chunk);
-}
-
-static const OldChunks engine_chunk[] = {
-	OCL_SVAR( OC_UINT16, Engine, player_avail ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ),
-	OCL_SVAR( OC_UINT16, Engine, reliability ),
-	OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ),
-	OCL_SVAR( OC_UINT16, Engine, reliability_start ),
-	OCL_SVAR( OC_UINT16, Engine, reliability_max ),
-	OCL_SVAR( OC_UINT16, Engine, reliability_final ),
-	OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ),
-	OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ),
-	OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ),
-
-	OCL_SVAR(  OC_UINT8, Engine, lifelength ),
-	OCL_SVAR(  OC_UINT8, Engine, flags ),
-	OCL_SVAR(  OC_UINT8, Engine, preview_player ),
-	OCL_SVAR(  OC_UINT8, Engine, preview_wait ),
-	OCL_SVAR(  OC_UINT8, Engine, railtype ),
-
-	OCL_NULL( 1 ),         // Junk
-
-	OCL_END()
-};
-
-static bool LoadOldEngine(LoadgameState *ls, int num)
-{
-	if (!LoadChunk(ls, GetEngine(num), engine_chunk)) return false;
-
-	/* Make sure wagons are marked as do-not-age */
-	if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116))
-		GetEngine(num)->age = 0xFFFF;
-
-	return true;
-}
-
-static const OldChunks subsidy_chunk[] = {
-	OCL_SVAR(  OC_UINT8, Subsidy, cargo_type ),
-	OCL_SVAR(  OC_UINT8, Subsidy, age ),
-	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, from ),
-	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, to ),
-
-	OCL_END()
-};
-
-static inline bool LoadOldSubsidy(LoadgameState *ls, int num)
-{
-	return LoadChunk(ls, &_subsidies[num], subsidy_chunk);
-}
-
-static const OldChunks game_difficulty_chunk[] = {
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_no_competitors ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_start_time ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_towns ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_industries ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_loan ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, initial_interest ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_costs ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_speed ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_intelligence ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_breakdowns ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, subsidy_multiplier ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, construction_cost ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, terrain_type ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, quantity_sea_lakes ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, economy ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, line_reverse_mode ),
-	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, disasters ),
-	OCL_END()
-};
-
-static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num)
-{
-	return LoadChunk(ls, &_opt.diff, game_difficulty_chunk);
-}
-
-
-static bool LoadOldMapPart1(LoadgameState *ls, int num)
-{
-	uint i;
-
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_m[i].m1 = ReadByte(ls);
-	}
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_m[i].m2 = ReadByte(ls);
-	}
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_old_map3[i * 2] = ReadByte(ls);
-		_old_map3[i * 2 + 1] = ReadByte(ls);
-	}
-	for (i = 0; i < OLD_MAP_SIZE / 4; i++) {
-		byte b = ReadByte(ls);
-		_m[i * 4 + 0].extra = GB(b, 0, 2);
-		_m[i * 4 + 1].extra = GB(b, 2, 2);
-		_m[i * 4 + 2].extra = GB(b, 4, 2);
-		_m[i * 4 + 3].extra = GB(b, 6, 2);
-	}
-
-	return !ls->failed;
-}
-
-static bool LoadOldMapPart2(LoadgameState *ls, int num)
-{
-	uint i;
-
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_m[i].type_height = ReadByte(ls);
-	}
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_m[i].m5 = ReadByte(ls);
-	}
-
-	return !ls->failed;
-}
-
-static uint32 _old_cur_town_ctr;
-static const OldChunks main_chunk[] = {
-	OCL_ASSERT( 0 ),
-	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
-	OCL_VAR ( OC_UINT16,   1, &_date_fract ),
-	OCL_NULL( 600 ),            // TextEffects
-	OCL_VAR ( OC_UINT32,   2, &_random_seeds[0] ),
-
-	OCL_ASSERT( 0x264 ),
-	OCL_CHUNK(  70, LoadOldTown ),
-	OCL_ASSERT( 0x1C18 ),
-	OCL_CHUNK(5000, LoadOldOrder ),
-	OCL_ASSERT( 0x4328 ),
-
-	OCL_VAR (   OC_TILE, 256, &_animated_tile_list[0] ),
-	OCL_NULL( 4 ),              // old end-of-order-list-pointer, no longer in use
-
-	OCL_CHUNK( 255, LoadOldDepot ),
-	OCL_ASSERT( 0x4B26 ),
-
-	OCL_VAR ( OC_UINT32,   1, &_old_cur_town_ctr ),
-	OCL_NULL( 2 ),              // timer_counter, no longer in use
-	OCL_NULL( 2 ),              // land_code,     no longer in use
-
-	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ),
-	OCL_VAR ( OC_UINT16,   1, &_tick_counter ),
-	OCL_VAR (   OC_TILE,   1, &_cur_tileloop_tile ),
-
-	OCL_CHUNK( 49, LoadOldPrice ),
-	OCL_CHUNK( 12, LoadOldCargoPaymentRate ),
-
-	OCL_ASSERT( 0x4CBA ),
-
-	OCL_CHUNK( 1, LoadOldMapPart1 ),
-
-	OCL_ASSERT( 0x48CBA ),
-
-	OCL_CHUNK(250, LoadOldStation ),
-	OCL_CHUNK( 90, LoadOldIndustry ),
-	OCL_CHUNK(  8, LoadOldPlayer ),
-
-	OCL_ASSERT( 0x547F2 ),
-
-	OCL_CHUNK( 850, LoadOldVehicle ),
-
-	OCL_ASSERT( 0x6F0F2 ),
-
-	OCL_VAR (  OC_UINT8, 32 * 500, &_name_array[0] ),
-
-	OCL_NULL( 0x2000 ),            // Old hash-table, no longer in use
-
-	OCL_CHUNK( 40, LoadOldSign ),
-	OCL_CHUNK(256, LoadOldEngine ),
-
-	OCL_VAR ( OC_UINT16,    1, &_vehicle_id_ctr_day ),
-
-	OCL_CHUNK(  8, LoadOldSubsidy ),
-
-	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,   1, &_next_competitor_start ),
-	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_x ),
-	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_y ),
-	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8,    1, &_saved_scrollpos_zoom ),
-
-	OCL_VAR ( OC_UINT32,    1, &_economy.max_loan ),
-	OCL_VAR ( OC_UINT32,    1, &_economy.max_loan_unround ),
-	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,    1, &_economy.fluct ),
-
-	OCL_VAR ( OC_UINT16,    1, &_disaster_delay ),
-
-	OCL_NULL( 144 ),             // cargo-stuff, calculated in InitializeLandscapeVariables
-
-	OCL_VAR ( OC_UINT16,  256, &_engine_name_strings[0] ),
-
-	OCL_NULL( 144 ),             // AI cargo-stuff, calculated in InitializeLandscapeVariables
-	OCL_NULL( 2 ),               // Company indexes of players, no longer in use
-
-	OCL_VAR ( OC_FILE_U8 | OC_VAR_U16,    1, &_station_tick_ctr ),
-
-	OCL_VAR (  OC_UINT8,    1, &_opt.currency ),
-	OCL_VAR (  OC_UINT8,    1, &_opt.units ),
-	OCL_VAR ( OC_FILE_U8 | OC_VAR_U32,    1, &_cur_player_tick_index ),
-
-	OCL_NULL( 2 ),               // Date stuff, calculated automatically
-	OCL_NULL( 8 ),               // Player colors, calculated automatically
-
-	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount ),
-	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount_pr ),
-	OCL_VAR (  OC_UINT8,    1, &_economy.interest_rate ),
-	OCL_VAR (  OC_UINT8,    1, &_avail_aircraft ),
-	OCL_VAR (  OC_UINT8,    1, &_opt.road_side ),
-	OCL_VAR (  OC_UINT8,    1, &_opt.town_name ),
-
-	OCL_CHUNK( 1, LoadOldGameDifficulty ),
-
-	OCL_ASSERT( 0x77130 ),
-
-	OCL_VAR (  OC_UINT8,    1, &_opt.diff_level ),
-	OCL_VAR (  OC_UINT8,    1, &_opt.landscape ),
-	OCL_VAR (  OC_UINT8,    1, &_trees_tick_ctr ),
-
-	OCL_NULL( 1 ),               // Custom vehicle types yes/no, no longer used
-	OCL_VAR (  OC_UINT8,    1, &_opt.snow_line ),
-
-	OCL_NULL( 32 ),              // new_industry_randtable, no longer used (because of new design)
-	OCL_NULL( 36 ),              // cargo-stuff, calculated in InitializeLandscapeVariables
-
-	OCL_ASSERT( 0x77179 ),
-
-	OCL_CHUNK( 1, LoadOldMapPart2 ),
-
-	OCL_ASSERT( 0x97179 ),
-
-	/* Below any (if available) extra chunks from TTDPatch can follow */
-
-	OCL_END()
-};
-
-static bool LoadOldMain(LoadgameState *ls)
-{
-	int i;
-
-	/* The first 49 is the name of the game + checksum, skip it */
-	fseek(ls->file, HEADER_SIZE, SEEK_SET);
-
-	DEBUG(oldloader, 4, "Reading main chunk...");
-	/* Load the biggest chunk */
-	if (!LoadChunk(ls, NULL, main_chunk)) {
-		DEBUG(oldloader, 0, "Loading failed");
-		return false;
-	}
-	DEBUG(oldloader, 4, "Done, converting game data...");
-
-	/* Fix some general stuff */
-	_opt.landscape = _opt.landscape & 0xF;
-
-	/* Remap some pointers */
-	_cur_town_ctr      = REMAP_TOWN_IDX(_old_cur_town_ctr);
-
-	/* _old_map3 is changed in _map3_lo and _map3_hi */
-	for (i = 0; i < OLD_MAP_SIZE; i++) {
-		_m[i].m3 = _old_map3[i * 2];
-		_m[i].m4 = _old_map3[i * 2 + 1];
-	}
-
-	for (i = 0; i < OLD_MAP_SIZE; i ++) {
-		if (IsTileType(i, MP_RAILWAY)) {
-			/* We save presignals different from TTDPatch, convert them */
-			if (GetRailTileType(i) == RAIL_TILE_SIGNALS) {
-				/* This byte is always zero in TTD for this type of tile */
-				if (_m[i].m4) /* Convert the presignals to our own format */
-					_m[i].m4 = (_m[i].m4 >> 1) & 7;
-			}
-			/* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just
-			 * clear it for ourselves and let OTTD's rebuild PBS itself */
-			_m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */
-		}
-	}
-
-	/* Fix the game to be compatible with OpenTTD */
-	FixOldTowns();
-	FixOldStations();
-	FixOldVehicles();
-
-	AddTypeToEngines();
-
-	/* We have a new difficulty setting */
-	_opt.diff.town_council_tolerance = clamp(_opt.diff_level, 0, 2);
-
-	DEBUG(oldloader, 4, "Finished converting game data");
-	DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted");
-
-	return true;
-}
-
-bool LoadOldSaveGame(const char *file)
-{
-	LoadgameState ls;
-
-	DEBUG(oldloader, 4, "Trying to load a TTD(Patch) savegame");
-
-	InitLoading(&ls);
-
-	/* Open file */
-	ls.file = fopen(file, "rb");
-
-	if (ls.file == NULL) {
-		DEBUG(oldloader, 0, "Cannot open file '%s'", file);
-		return false;
-	}
-
-	/* Load the main chunk */
-	if (!LoadOldMain(&ls)) return false;
-
-	fclose(ls.file);
-
-	_pause = 2;
-
-	return true;
-}
-
-void GetOldSaveGameName(char *title, const char *path, const char *file)
-{
-	char filename[MAX_PATH];
-	FILE *f;
-
-	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
-	f = fopen(filename, "rb");
-	title[0] = '\0';
-	title[48] = '\0';
-
-	if (f == NULL) return;
-
-	if (fread(title, 1, 48, f) != 48) snprintf(title, 48, "Corrupt file");
-
-	fclose(f);
-}
new file mode 100644
--- /dev/null
+++ b/src/oldloader.cpp
@@ -0,0 +1,1583 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "town.h"
+#include "industry.h"
+#include "station.h"
+#include "economy.h"
+#include "player.h"
+#include "engine.h"
+#include "vehicle.h"
+#include "signs.h"
+#include "debug.h"
+#include "depot.h"
+#include "network/network.h"
+#include "ai/ai.h"
+#include "date.h"
+
+enum {
+	HEADER_SIZE = 49,
+	BUFFER_SIZE = 4096,
+
+	OLD_MAP_SIZE = 256 * 256
+};
+
+typedef struct LoadgameState {
+	FILE *file;
+
+	uint chunk_size;
+
+	bool decoding;
+	byte decode_char;
+
+	uint buffer_count;
+	uint buffer_cur;
+	byte buffer[BUFFER_SIZE];
+
+	uint total_read;
+	bool failed;
+} LoadgameState;
+
+/* OldChunk-Type */
+typedef enum OldChunkTypes {
+	OC_SIMPLE    = 0,
+	OC_NULL      = 1,
+	OC_CHUNK     = 2,
+	OC_ASSERT    = 3,
+	/* 8 bytes allocated (256 max) */
+
+	OC_VAR_I8    = 1 << 8,
+	OC_VAR_U8    = 2 << 8,
+	OC_VAR_I16   = 3 << 8,
+	OC_VAR_U16   = 4 << 8,
+	OC_VAR_I32   = 5 << 8,
+	OC_VAR_U32   = 6 << 8,
+	OC_VAR_I64   = 7 << 8,
+	/* 8 bytes allocated (256 max) */
+
+	OC_FILE_I8   = 1 << 16,
+	OC_FILE_U8   = 2 << 16,
+	OC_FILE_I16  = 3 << 16,
+	OC_FILE_U16  = 4 << 16,
+	OC_FILE_I32  = 5 << 16,
+	OC_FILE_U32  = 6 << 16,
+	/* 8 bytes allocated (256 max) */
+
+	OC_INT8      = OC_VAR_I8   | OC_FILE_I8,
+	OC_UINT8     = OC_VAR_U8   | OC_FILE_U8,
+	OC_INT16     = OC_VAR_I16  | OC_FILE_I16,
+	OC_UINT16    = OC_VAR_U16  | OC_FILE_U16,
+	OC_INT32     = OC_VAR_I32  | OC_FILE_I32,
+	OC_UINT32    = OC_VAR_U32  | OC_FILE_U32,
+
+	OC_TILE      = OC_VAR_U32  | OC_FILE_U16,
+
+	OC_END       = 0 ///< End of the whole chunk, all 32bits set to zero
+} OldChunkType;
+
+typedef bool OldChunkProc(LoadgameState *ls, int num);
+
+typedef struct OldChunks {
+	OldChunkType type;   ///< Type of field
+	uint32 amount;       ///< Amount of fields
+
+	void *ptr;           ///< Pointer where to save the data (may only be set if offset is 0)
+	uint offset;         ///< Offset from basepointer (may only be set if ptr is NULL)
+	OldChunkProc *proc;  ///< Pointer to function that is called with OC_CHUNK
+} OldChunks;
+
+/* If it fails, check lines above.. */
+assert_compile(sizeof(TileIndex) == 4);
+
+static uint32 _bump_assert_value;
+static bool   _read_ttdpatch_flags;
+
+static OldChunkType GetOldChunkType(OldChunkType type)     {return GB(type, 0, 8);}
+static OldChunkType GetOldChunkVarType(OldChunkType type)  {return GB(type, 8, 8) << 8;}
+static OldChunkType GetOldChunkFileType(OldChunkType type) {return GB(type, 16, 8) << 16;}
+
+static inline byte CalcOldVarLen(OldChunkType type)
+{
+	static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
+	byte length = GB(type, 8, 8);
+	assert(length != 0 && length < lengthof(type_mem_size));
+	return type_mem_size[length];
+}
+
+/**
+ *
+ * Reads a byte from a file (do not call yourself, use ReadByte())
+ *
+ */
+static byte ReadByteFromFile(LoadgameState *ls)
+{
+	/* To avoid slow reads, we read BUFFER_SIZE of bytes per time
+	and just return a byte per time */
+	if (ls->buffer_cur >= ls->buffer_count) {
+		/* Read some new bytes from the file */
+		int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
+
+		/* We tried to read, but there is nothing in the file anymore.. */
+		if (count == 0) {
+			DEBUG(oldloader, 0, "Read past end of file, loading failed");
+			ls->failed = true;
+		}
+
+		ls->buffer_count = count;
+		ls->buffer_cur   = 0;
+	}
+
+	return ls->buffer[ls->buffer_cur++];
+}
+
+/**
+ *
+ * Reads a byte from the buffer and decompress if needed
+ *
+ */
+static byte ReadByte(LoadgameState *ls)
+{
+	/* Old savegames have a nice compression algorithm (RLE)
+	which means that we have a chunk, which starts with a length
+	byte. If that byte is negative, we have to repeat the next byte
+	that many times (+1). Else, we need to read that amount of bytes.
+	Works pretty good if you have many zero's behind eachother */
+
+	if (ls->chunk_size == 0) {
+		/* Read new chunk */
+		int8 new_byte = ReadByteFromFile(ls);
+
+		if (new_byte < 0) {
+			/* Repeat next char for new_byte times */
+			ls->decoding    = true;
+			ls->decode_char = ReadByteFromFile(ls);
+			ls->chunk_size  = -new_byte + 1;
+		} else {
+			ls->decoding    = false;
+			ls->chunk_size  = new_byte + 1;
+		}
+	}
+
+	ls->total_read++;
+	ls->chunk_size--;
+
+	return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
+}
+
+static inline uint16 ReadUint16(LoadgameState *ls)
+{
+	byte x = ReadByte(ls);
+	return x | ReadByte(ls) << 8;
+}
+
+static inline uint32 ReadUint32(LoadgameState *ls)
+{
+	uint16 x = ReadUint16(ls);
+	return x | ReadUint16(ls) << 16;
+}
+
+/**
+ *
+ * Loads a chunk from the old savegame
+ *
+ */
+static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
+{
+	const OldChunks *chunk = chunks;
+	byte *base_ptr = base;
+
+	while (chunk->type != OC_END) {
+		byte* ptr = chunk->ptr;
+		uint i;
+
+		for (i = 0; i < chunk->amount; i++) {
+			if (ls->failed) return false;
+
+			/* Handle simple types */
+			if (GetOldChunkType(chunk->type) != 0) {
+				switch (GetOldChunkType(chunk->type)) {
+					/* Just read the byte and forget about it */
+					case OC_NULL: ReadByte(ls); break;
+
+					case OC_CHUNK:
+						/* Call function, with 'i' as parameter to tell which item we
+						 * are going to read */
+						if (!chunk->proc(ls, i)) return false;
+						break;
+
+					case OC_ASSERT:
+						DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
+						if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
+					default: break;
+				}
+			} else {
+				uint32 res = 0;
+
+				/* Reading from the file: bits 16 to 23 have the FILE type */
+				switch (GetOldChunkFileType(chunk->type)) {
+					case OC_FILE_I8:  res = (int8)ReadByte(ls); break;
+					case OC_FILE_U8:  res = ReadByte(ls); break;
+					case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
+					case OC_FILE_U16: res = ReadUint16(ls); break;
+					case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
+					case OC_FILE_U32: res = ReadUint32(ls); break;
+					default: NOT_REACHED();
+				}
+
+				/* Sanity check */
+				assert(base_ptr != NULL || chunk->ptr != NULL);
+
+				/* Writing to the var: bits 8 to 15 have the VAR type */
+				if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset;
+
+				/* Write the data */
+				switch (GetOldChunkVarType(chunk->type)) {
+					case OC_VAR_I8: *(int8  *)ptr = GB(res, 0, 8); break;
+					case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
+					case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
+					case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
+					case OC_VAR_I32:*(int32 *)ptr = res; break;
+					case OC_VAR_U32:*(uint32*)ptr = res; break;
+					case OC_VAR_I64:*(int64 *)ptr = res; break;
+					default: NOT_REACHED();
+				}
+
+				/* Increase pointer base for arrays when looping */
+				if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type);
+			}
+		}
+
+		chunk++;
+	}
+
+	return true;
+}
+
+/**
+ *
+ * Initialize some data before reading
+ *
+ */
+static void InitLoading(LoadgameState *ls)
+{
+	ls->chunk_size   = 0;
+	ls->total_read   = 0;
+	ls->failed       = false;
+
+	ls->decoding     = false;
+	ls->decode_char  = 0;
+
+	ls->buffer_cur   = 0;
+	ls->buffer_count = 0;
+	memset(ls->buffer, 0, BUFFER_SIZE);
+
+	_bump_assert_value = 0;
+
+	_read_ttdpatch_flags = false;
+}
+
+
+/*
+ * Begin -- Stuff to fix the savegames to be OpenTTD compatible
+ */
+
+extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type);
+
+static void FixOldTowns(void)
+{
+	Town *town;
+
+	/* Convert town-names if needed */
+	FOR_ALL_TOWNS(town) {
+		if (IS_INT_INSIDE(town->townnametype, 0x20C1, 0x20C3)) {
+			town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _opt.town_name;
+			town->townnameparts = GetOldTownName(town->townnameparts, _opt.town_name);
+		}
+	}
+}
+
+static void FixOldStations(void)
+{
+	Station *st;
+
+	FOR_ALL_STATIONS(st) {
+		/* Check if we need to swap width and height for the station */
+		if (st->train_tile != 0 && GetRailStationAxis(st->train_tile) != AXIS_X) {
+			swap_byte(&st->trainst_w, &st->trainst_h);
+		}
+
+		/* Check if there is a bus or truck station, and convert to new format */
+		if (st->bus_tile_obsolete != 0) {
+			st->bus_stops = AllocateRoadStop();
+			st->bus_stops->xy = st->bus_tile_obsolete;
+			st->bus_stops->used = true;
+			st->bus_stops->status = 3;
+			st->bus_stops->station = st->index;
+			st->bus_stops->next = NULL;
+			st->bus_stops->prev = NULL;
+			st->bus_stops->num_vehicles = 0;
+		}
+
+		if (st->lorry_tile_obsolete != 0) {
+			st->truck_stops = AllocateRoadStop();
+			st->truck_stops->xy = st->lorry_tile_obsolete;
+			st->truck_stops->used = true;
+			st->truck_stops->status = 3;
+			st->truck_stops->station = st->index;
+			st->truck_stops->next = NULL;
+			st->truck_stops->prev = NULL;
+			st->truck_stops->num_vehicles = 0;
+		}
+	}
+}
+
+static void FixOldVehicles(void)
+{
+	/* Check for shared orders, and link them correctly */
+	Vehicle* v;
+
+	FOR_ALL_VEHICLES(v) {
+		Vehicle *u;
+
+		FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
+			/* If a vehicle has the same orders, add the link to eachother
+			 * in both vehicles */
+			if (v->orders == u->orders) {
+				v->next_shared = u;
+				u->prev_shared = v;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * End -- Stuff to fix the savegames to be OpenTTD compatible
+ */
+
+
+/* Help:
+ *  - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
+ *       be given via base in LoadChunk() as real pointer
+ *  - OCL_VAR: load 'type' to a global var
+ *  - OCL_END: every struct must end with this
+ *  - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something
+ *  - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times
+ *  - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;)
+ */
+#define OCL_SVAR(type, base, offset)         { type,          1, NULL,    (uint)offsetof(base, offset), NULL }
+#define OCL_VAR(type, amount, pointer)       { type,     amount, pointer, 0,                      NULL }
+#define OCL_END()                                   { OC_END,        0, NULL,    0,                      NULL }
+#define OCL_NULL(amount)                            { OC_NULL,  amount, NULL,    0,                      NULL }
+#define OCL_CHUNK(amount, proc)                     { OC_CHUNK, amount, NULL,    0,                      proc }
+#define OCL_ASSERT(size)                            { OC_ASSERT,     1, NULL, size,                      NULL }
+
+/* The savegames has some hard-coded pointers, because it always enters the same
+    piece of memory.. we don't.. so we need to remap ;)
+   Old Towns are 94 bytes big
+   Old Orders are 2 bytes big */
+#define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94
+#define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2
+
+extern TileIndex _animated_tile_list[256];
+extern char _name_array[512][32];
+
+static byte   _old_vehicle_multiplier;
+static uint8  _old_map3[OLD_MAP_SIZE * 2];
+static bool   _new_ttdpatch_format;
+static uint32 _old_town_index;
+static uint16 _old_string_id;
+static uint16 _old_string_id_2;
+
+static void ReadTTDPatchFlags(void)
+{
+	int i;
+
+	if (_read_ttdpatch_flags) return;
+
+	_read_ttdpatch_flags = true;
+
+	/* TTDPatch misuses _old_map3 for flags.. read them! */
+	_old_vehicle_multiplier = _old_map3[0];
+	/* Somehow.... there was an error in some savegames, so 0 becomes 1
+	and 1 becomes 2. The rest of the values are okay */
+	if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++;
+
+	/* TTDPatch incraeses the Vehicle-part in the middle of the game,
+	so if the multipler is anything else but 1, the assert fails..
+	bump the assert value so it doesn't!
+	(1 multipler == 850 vehicles
+	1 vehicle   == 128 bytes */
+	_bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128;
+
+	/* Check if we have a modern TTDPatch savegame (has extra data all around) */
+	_new_ttdpatch_format = (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0);
+
+	/* Clean the misused places */
+	for (i = 0;       i < 17;      i++) _old_map3[i] = 0;
+	for (i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0;
+
+	if (_new_ttdpatch_format) DEBUG(oldloader, 1, "Found TTDPatch game");
+
+	DEBUG(oldloader, 1, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850);
+}
+
+static const OldChunks town_chunk[] = {
+	OCL_SVAR(   OC_TILE, Town, xy ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, population ),
+	OCL_SVAR( OC_UINT16, Town, townnametype ),
+	OCL_SVAR( OC_UINT32, Town, townnameparts ),
+	OCL_SVAR(  OC_UINT8, Town, grow_counter ),
+	OCL_NULL( 1 ),         // sort_index,        no longer in use
+	OCL_NULL( 4 ),         // sign-coordinates,  no longer in use
+	OCL_NULL( 2 ),         // namewidth,         no longer in use
+	OCL_SVAR( OC_UINT16, Town, flags12 ),
+	OCL_NULL( 10 ),        // radius,            no longer in use
+
+	OCL_SVAR( OC_UINT16, Town, ratings[0] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[1] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[2] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[3] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[4] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[5] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[6] ),
+	OCL_SVAR( OC_UINT16, Town, ratings[7] ),
+
+	/* XXX - This is pretty odd.. we read 32bit, but only write 8bit.. sure there is
+	nothing changed?? */
+	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ),
+	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ),
+	OCL_SVAR( OC_UINT16, Town, num_houses ),
+	OCL_SVAR(  OC_UINT8, Town, time_until_rebuild ),
+	OCL_SVAR(  OC_UINT8, Town, growth_rate ),
+
+	OCL_SVAR( OC_UINT16, Town, new_max_pass ),
+	OCL_SVAR( OC_UINT16, Town, new_max_mail ),
+	OCL_SVAR( OC_UINT16, Town, new_act_pass ),
+	OCL_SVAR( OC_UINT16, Town, new_act_mail ),
+	OCL_SVAR( OC_UINT16, Town, max_pass ),
+	OCL_SVAR( OC_UINT16, Town, max_mail ),
+	OCL_SVAR( OC_UINT16, Town, act_pass ),
+	OCL_SVAR( OC_UINT16, Town, act_mail ),
+
+	OCL_SVAR(  OC_UINT8, Town, pct_pass_transported ),
+	OCL_SVAR(  OC_UINT8, Town, pct_mail_transported ),
+
+	OCL_SVAR( OC_UINT16, Town, new_act_food ),
+	OCL_SVAR( OC_UINT16, Town, new_act_water ),
+	OCL_SVAR( OC_UINT16, Town, act_food ),
+	OCL_SVAR( OC_UINT16, Town, act_water ),
+
+	OCL_SVAR(  OC_UINT8, Town, road_build_months ),
+	OCL_SVAR(  OC_UINT8, Town, fund_buildings_months ),
+
+	OCL_NULL( 8 ),         // some junk at the end of the record
+
+	OCL_END()
+};
+static bool LoadOldTown(LoadgameState *ls, int num)
+{
+	if (!AddBlockIfNeeded(&_Town_pool, num))
+		error("Towns: failed loading savegame: too many towns");
+
+	return LoadChunk(ls, GetTown(num), town_chunk);
+}
+
+static uint16 _old_order;
+static const OldChunks order_chunk[] = {
+	OCL_VAR ( OC_UINT16,   1, &_old_order ),
+	OCL_END()
+};
+
+static bool LoadOldOrder(LoadgameState *ls, int num)
+{
+	if (!AddBlockIfNeeded(&_Order_pool, num))
+		error("Orders: failed loading savegame: too many orders");
+
+	if (!LoadChunk(ls, NULL, order_chunk)) return false;
+
+	AssignOrder(GetOrder(num), UnpackOldOrder(_old_order));
+
+	/* Relink the orders to eachother (in TTD(Patch) the orders for one
+	vehicle are behind eachother, with OT_NOTHING as indication that
+	it is the last order */
+	if (num > 0 && GetOrder(num)->type != OT_NOTHING)
+		GetOrder(num - 1)->next = GetOrder(num);
+
+	return true;
+}
+
+static const OldChunks depot_chunk[] = {
+	OCL_SVAR(   OC_TILE, Depot, xy ),
+	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
+	OCL_END()
+};
+
+static bool LoadOldDepot(LoadgameState *ls, int num)
+{
+	if (!AddBlockIfNeeded(&_Depot_pool, num))
+		error("Depots: failed loading savegame: too many depots");
+
+	if (!LoadChunk(ls, GetDepot(num), depot_chunk)) return false;
+
+	if (IsValidDepot(GetDepot(num))) {
+		GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
+	}
+
+	return true;
+}
+
+static int32 _old_price;
+static uint16 _old_price_frac;
+static const OldChunks price_chunk[] = {
+	OCL_VAR (  OC_INT32,   1, &_old_price ),
+	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
+	OCL_END()
+};
+
+static bool LoadOldPrice(LoadgameState *ls, int num)
+{
+	if (!LoadChunk(ls, NULL, price_chunk)) return false;
+
+	/* We use a struct to store the prices, but they are ints in a row..
+	so just access the struct as an array of int32's */
+	((int32*)&_price)[num] = _old_price;
+	_price_frac[num] = _old_price_frac;
+
+	return true;
+}
+
+static const OldChunks cargo_payment_rate_chunk[] = {
+	OCL_VAR (  OC_INT32,   1, &_old_price ),
+	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
+
+	OCL_NULL( 2 ),         // Junk
+	OCL_END()
+};
+
+static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num)
+{
+	if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) return false;
+
+	_cargo_payment_rates[num] = -_old_price;
+	_cargo_payment_rates_frac[num] = _old_price_frac;
+
+	return true;
+}
+
+static uint8 _old_platforms;
+static uint _current_station_id;
+
+static const OldChunks goods_chunk[] = {
+	OCL_SVAR( OC_UINT16, GoodsEntry, waiting_acceptance ),
+	OCL_SVAR(  OC_UINT8, GoodsEntry, days_since_pickup ),
+	OCL_SVAR(  OC_UINT8, GoodsEntry, rating ),
+	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, GoodsEntry, enroute_from ),
+	OCL_SVAR(  OC_UINT8, GoodsEntry, enroute_time ),
+	OCL_SVAR(  OC_UINT8, GoodsEntry, last_speed ),
+	OCL_SVAR(  OC_UINT8, GoodsEntry, last_age ),
+
+	OCL_END()
+};
+
+static bool LoadOldGood(LoadgameState *ls, int num)
+{
+	Station *st = GetStation(_current_station_id);
+	return LoadChunk(ls, &st->goods[num], goods_chunk);
+}
+
+static const OldChunks station_chunk[] = {
+	OCL_SVAR(   OC_TILE, Station, xy ),
+	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
+
+	OCL_SVAR(   OC_TILE, Station, bus_tile_obsolete ),
+	OCL_SVAR(   OC_TILE, Station, lorry_tile_obsolete ),
+	OCL_SVAR(   OC_TILE, Station, train_tile ),
+	OCL_SVAR(   OC_TILE, Station, airport_tile ),
+	OCL_SVAR(   OC_TILE, Station, dock_tile ),
+
+	OCL_VAR (  OC_UINT8,   1, &_old_platforms ),
+
+	OCL_NULL( 1 ),         // sort-index, no longer in use
+	OCL_NULL( 2 ),         // sign-width, no longer in use
+
+	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
+
+	OCL_NULL( 4 ),         // sign left/top, no longer in use
+
+	OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ),
+
+	OCL_CHUNK( 12, LoadOldGood ),
+
+	OCL_SVAR(  OC_UINT8, Station, time_since_load ),
+	OCL_SVAR(  OC_UINT8, Station, time_since_unload ),
+	OCL_SVAR(  OC_UINT8, Station, delete_ctr ),
+	OCL_SVAR(  OC_UINT8, Station, owner ),
+	OCL_SVAR(  OC_UINT8, Station, facilities ),
+	OCL_SVAR(  OC_UINT8, Station, airport_type ),
+	OCL_NULL( 2 ),         // Bus/truck status, no longer in use
+	OCL_SVAR(  OC_UINT8, Station, blocked_months_obsolete ),
+	OCL_NULL( 1 ),         // Unknown
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ),
+	OCL_NULL( 2 ),         // last_vehicle. now last_vehicle_type
+
+	OCL_NULL( 4 ),         // Junk at end of chunk
+
+	OCL_END()
+};
+static bool LoadOldStation(LoadgameState *ls, int num)
+{
+	Station *st;
+
+	if (!AddBlockIfNeeded(&_Station_pool, num))
+		error("Stations: failed loading savegame: too many stations");
+
+	st = GetStation(num);
+	_current_station_id = num;
+
+	if (!LoadChunk(ls, st, station_chunk))
+		return false;
+
+	if (IsValidStation(st)) {
+		if (st->train_tile) {
+			/* Calculate the trainst_w and trainst_h */
+			uint w = GB(_old_platforms, 3, 3);
+			uint h = GB(_old_platforms, 0, 3);
+			st->trainst_w = w;
+			st->trainst_h = h;
+		}
+
+		st->town    = GetTown(REMAP_TOWN_IDX(_old_town_index));
+		st->string_id = RemapOldStringID(_old_string_id);
+	}
+
+	return true;
+}
+
+static const OldChunks industry_chunk[] = {
+	OCL_SVAR(   OC_TILE, Industry, xy ),
+	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
+	OCL_SVAR(  OC_UINT8, Industry, width ),
+	OCL_SVAR(  OC_UINT8, Industry, height ),
+	OCL_SVAR(  OC_UINT8, Industry, produced_cargo[0] ),
+	OCL_SVAR(  OC_UINT8, Industry, produced_cargo[1] ),
+
+	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[0] ),
+	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[1] ),
+
+	OCL_SVAR(  OC_UINT8, Industry, production_rate[0] ),
+	OCL_SVAR(  OC_UINT8, Industry, production_rate[1] ),
+
+	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[0] ),
+	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[1] ),
+	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[2] ),
+
+	OCL_SVAR(  OC_UINT8, Industry, prod_level ),
+
+	OCL_SVAR( OC_UINT16, Industry, last_mo_production[0] ),
+	OCL_SVAR( OC_UINT16, Industry, last_mo_production[1] ),
+	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[0] ),
+	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[1] ),
+
+	OCL_SVAR(  OC_UINT8, Industry, pct_transported[0] ),
+	OCL_SVAR(  OC_UINT8, Industry, pct_transported[1] ),
+
+	OCL_SVAR( OC_UINT16, Industry, total_production[0] ),
+	OCL_SVAR( OC_UINT16, Industry, total_production[1] ),
+	OCL_SVAR( OC_UINT16, Industry, total_transported[0] ),
+	OCL_SVAR( OC_UINT16, Industry, total_transported[1] ),
+
+	OCL_SVAR(  OC_UINT8, Industry, type ),
+	OCL_SVAR(  OC_UINT8, Industry, owner ),
+	OCL_SVAR(  OC_UINT8, Industry, random_color ),
+	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ),
+	OCL_SVAR( OC_UINT16, Industry, counter ),
+	OCL_SVAR(  OC_UINT8, Industry, was_cargo_delivered ),
+
+	OCL_NULL( 9 ), // Random junk at the end of this chunk
+
+	OCL_END()
+};
+
+static bool LoadOldIndustry(LoadgameState *ls, int num)
+{
+	Industry *i;
+
+	if (!AddBlockIfNeeded(&_Industry_pool, num))
+		error("Industries: failed loading savegame: too many industries");
+
+	i = GetIndustry(num);
+	if (!LoadChunk(ls, i, industry_chunk)) return false;
+
+	if (IsValidIndustry(i)) {
+		i->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
+	}
+
+	return true;
+}
+
+static PlayerID _current_player_id;
+static uint16 _old_inaugurated_year;
+static int32 _old_yearly;
+
+static const OldChunks player_yearly_chunk[] = {
+	OCL_VAR(  OC_INT32,   1, &_old_yearly ),
+	OCL_END()
+};
+
+static bool OldPlayerYearly(LoadgameState *ls, int num)
+{
+	int i;
+	Player *p = GetPlayer(_current_player_id);
+
+	for (i = 0; i < 13; i++) {
+		if (!LoadChunk(ls, NULL, player_yearly_chunk)) return false;
+
+		p->yearly_expenses[num][i] = _old_yearly;
+	}
+
+	return true;
+}
+
+static const OldChunks player_economy_chunk[] = {
+	OCL_SVAR( OC_INT32, PlayerEconomyEntry, income ),
+	OCL_SVAR( OC_INT32, PlayerEconomyEntry, expenses ),
+	OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ),
+	OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ),
+	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ),
+
+	OCL_END()
+};
+
+static bool OldPlayerEconomy(LoadgameState *ls, int num)
+{
+	int i;
+	Player *p = GetPlayer(_current_player_id);
+
+	if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk)) return false;
+
+	/* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */
+	p->cur_economy.income   = -p->cur_economy.income;
+	p->cur_economy.expenses = -p->cur_economy.expenses;
+
+	for (i = 0; i < 24; i++) {
+		if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk)) return false;
+
+		p->old_economy[i].income   = -p->old_economy[i].income;
+		p->old_economy[i].expenses = -p->old_economy[i].expenses;
+	}
+
+	return true;
+}
+
+static const OldChunks player_ai_build_rec_chunk[] = {
+	OCL_SVAR(   OC_TILE, AiBuildRec, spec_tile ),
+	OCL_SVAR(   OC_TILE, AiBuildRec, use_tile ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, rand_rng ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, cur_building_rule ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, unk6 ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, unk7 ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_a ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_b ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, direction ),
+	OCL_SVAR(  OC_UINT8, AiBuildRec, cargo ),
+
+	OCL_NULL( 8 ),  // Junk...
+
+	OCL_END()
+};
+
+static bool OldLoadAIBuildRec(LoadgameState *ls, int num)
+{
+	Player *p = GetPlayer(_current_player_id);
+
+	switch (num) {
+		case 0: return LoadChunk(ls, &p->ai.src, player_ai_build_rec_chunk);
+		case 1: return LoadChunk(ls, &p->ai.dst, player_ai_build_rec_chunk);
+		case 2: return LoadChunk(ls, &p->ai.mid1, player_ai_build_rec_chunk);
+		case 3: return LoadChunk(ls, &p->ai.mid2, player_ai_build_rec_chunk);
+	}
+
+	return false;
+}
+static const OldChunks player_ai_chunk[] = {
+	OCL_SVAR(  OC_UINT8, PlayerAI, state ),
+	OCL_NULL( 1 ),         // Junk
+	OCL_SVAR(  OC_UINT8, PlayerAI, state_mode ),
+	OCL_SVAR( OC_UINT16, PlayerAI, state_counter ),
+	OCL_SVAR( OC_UINT16, PlayerAI, timeout_counter ),
+
+	OCL_CHUNK( 4, OldLoadAIBuildRec ),
+
+	OCL_NULL( 20 ),        // More junk
+
+	OCL_SVAR(  OC_UINT8, PlayerAI, cargo_type ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, num_wagons ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, build_kind ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, num_build_rec ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, num_loco_to_build ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, num_want_fullload ),
+
+	OCL_NULL( 14 ),        // Oh no more junk :|
+
+	OCL_NULL( 2 ),         // Loco-id, not used
+
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[0] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[1] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[2] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[3] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[4] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[5] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[6] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[7] ),
+	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[8] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[0] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[1] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[2] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[3] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[4] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[5] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[6] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[7] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[8] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[9] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[10] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[11] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[12] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[13] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[14] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[15] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[16] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[17] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[18] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[19] ),
+
+	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_a ),
+	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_b ),
+	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_a ),
+	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_b ),
+
+	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_a ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_b ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_a ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_b ),
+
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_tile_count ),
+
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[0] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[0] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[1] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[1] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[2] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[2] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[3] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[3] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[4] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[4] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[5] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[5] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[6] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[6] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[7] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[7] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[8] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[8] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[9] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[9] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[10] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[10] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[11] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[11] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[12] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[12] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[13] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[13] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[14] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[14] ),
+	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[15] ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[15] ),
+
+	OCL_SVAR(  OC_UINT8, PlayerAI, railtype_to_use ),
+	OCL_SVAR(  OC_UINT8, PlayerAI, route_type_mask ),
+
+	OCL_END()
+};
+
+static bool OldPlayerAI(LoadgameState *ls, int num)
+{
+	Player *p = GetPlayer(_current_player_id);
+
+	return LoadChunk(ls, &p->ai, player_ai_chunk);
+}
+
+static const OldChunks player_chunk[] = {
+	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
+	OCL_SVAR( OC_UINT32, Player, name_2 ),
+	OCL_SVAR( OC_UINT32, Player, face ),
+	OCL_VAR ( OC_UINT16,   1, &_old_string_id_2 ),
+	OCL_SVAR( OC_UINT32, Player, president_name_2 ),
+
+	OCL_SVAR(  OC_INT32, Player, player_money ),
+	OCL_SVAR(  OC_INT32, Player, current_loan ),
+
+	OCL_SVAR(  OC_UINT8, Player, player_color ),
+	OCL_SVAR(  OC_UINT8, Player, player_money_fraction ),
+	OCL_SVAR(  OC_UINT8, Player, quarters_of_bankrupcy ),
+	OCL_SVAR(  OC_UINT8, Player, bankrupt_asked ),
+	OCL_SVAR( OC_UINT32, Player, bankrupt_value ),
+	OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ),
+
+	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ),
+
+	OCL_CHUNK( 3, OldPlayerYearly ),
+	OCL_CHUNK( 1, OldPlayerEconomy ),
+
+	OCL_VAR ( OC_UINT16,   1,    &_old_inaugurated_year ),
+	OCL_SVAR(   OC_TILE, Player, last_build_coordinate ),
+	OCL_SVAR(  OC_UINT8, Player, num_valid_stat_ent ),
+
+	OCL_CHUNK( 1, OldPlayerAI ),
+
+	OCL_SVAR(  OC_UINT8, Player, block_preview ),
+	OCL_SVAR(  OC_UINT8, Player, ai.tick ),
+	OCL_SVAR(  OC_UINT8, Player, avail_railtypes ),
+	OCL_SVAR(   OC_TILE, Player, location_of_house ),
+	OCL_SVAR(  OC_UINT8, Player, share_owners[0] ),
+	OCL_SVAR(  OC_UINT8, Player, share_owners[1] ),
+	OCL_SVAR(  OC_UINT8, Player, share_owners[2] ),
+	OCL_SVAR(  OC_UINT8, Player, share_owners[3] ),
+
+	OCL_NULL( 8 ), // junk at end of chunk
+
+	OCL_END()
+};
+
+static bool LoadOldPlayer(LoadgameState *ls, int num)
+{
+	Player *p = GetPlayer(num);
+
+	_current_player_id = num;
+
+	if (!LoadChunk(ls, p, player_chunk)) return false;
+
+	p->name_1 = RemapOldStringID(_old_string_id);
+	p->president_name_1 = RemapOldStringID(_old_string_id_2);
+	p->money64 = p->player_money;
+
+	if (num == 0) {
+		/* If the first player has no name, make sure we call it UNNAMED */
+		if (p->name_1 == 0)
+			p->name_1 = STR_SV_UNNAMED;
+	} else {
+		/* Beside some multiplayer maps (1 on 1), which we don't official support,
+		all other players are an AI.. mark them as such */
+		p->is_ai = true;
+	}
+
+	/* Sometimes it is better to not ask.. in old scenarios, the money
+	was always 893288 pounds. In the newer versions this is correct,
+	but correct for those oldies
+	Ps: this also means that if you had exact 893288 pounds, you will go back
+	to 10000.. this is a very VERY small chance ;) */
+	if (p->player_money == 893288)
+		p->money64 = p->player_money = p->current_loan = 100000;
+
+	_player_colors[num] = p->player_color;
+	p->inaugurated_year = _old_inaugurated_year;
+	if (p->location_of_house == 0xFFFF)
+		p->location_of_house = 0;
+
+	/* State 20 for AI players is sell vehicle. Since the AI struct is not
+	 * really figured out as of now, p->ai.cur_veh; needed for 'sell vehicle'
+	 * is NULL and the function will crash. To fix this, just change the state
+	 * to some harmless state, like 'loop vehicle'; 1 */
+	if (!IsHumanPlayer(num) && p->ai.state == 20) p->ai.state = 1;
+
+	if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
+		AI_StartNewAI(p->index);
+
+	return true;
+}
+
+static uint32 _old_order_ptr;
+static uint16 _old_next_ptr;
+static uint32 _current_vehicle_id;
+
+static const OldChunks vehicle_train_chunk[] = {
+	OCL_SVAR(  OC_UINT8, VehicleRail, track ),
+	OCL_SVAR(  OC_UINT8, VehicleRail, force_proceed ),
+	OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ),
+	OCL_SVAR(  OC_UINT8, VehicleRail, railtype ),
+
+	OCL_NULL( 5 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_road_chunk[] = {
+	OCL_SVAR(  OC_UINT8, VehicleRoad, state ),
+	OCL_SVAR(  OC_UINT8, VehicleRoad, frame ),
+	OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ),
+	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking ),
+	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking_ctr ),
+	OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ),
+	OCL_SVAR(  OC_UINT8, VehicleRoad, reverse_ctr ),
+
+	OCL_NULL( 1 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_ship_chunk[] = {
+	OCL_SVAR(  OC_UINT8, VehicleShip, state ),
+
+	OCL_NULL( 9 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_air_chunk[] = {
+	OCL_SVAR(  OC_UINT8, VehicleAir, pos ),
+	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ),
+	OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ),
+	OCL_SVAR(  OC_UINT8, VehicleAir, state ),
+
+	OCL_NULL( 5 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_special_chunk[] = {
+	OCL_SVAR( OC_UINT16, VehicleSpecial, unk0 ),
+	OCL_SVAR(  OC_UINT8, VehicleSpecial, unk2 ),
+
+	OCL_NULL( 7 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_disaster_chunk[] = {
+	OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ),
+	OCL_SVAR( OC_UINT16, VehicleDisaster, unk2 ),
+
+	OCL_NULL( 6 ), // Junk
+
+	OCL_END()
+};
+
+static const OldChunks vehicle_empty_chunk[] = {
+	OCL_NULL( 10 ), // Junk
+
+	OCL_END()
+};
+
+static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
+{
+	Vehicle *v = GetVehicle(_current_vehicle_id);
+	uint temp = ls->total_read;
+	bool res;
+
+	switch (v->type) {
+		case VEH_Train:    res = LoadChunk(ls, &v->u.rail,     vehicle_train_chunk);    break;
+		case VEH_Road:     res = LoadChunk(ls, &v->u.road,     vehicle_road_chunk);     break;
+		case VEH_Ship:     res = LoadChunk(ls, &v->u.ship,     vehicle_ship_chunk);     break;
+		case VEH_Aircraft: res = LoadChunk(ls, &v->u.air,      vehicle_air_chunk);      break;
+		case VEH_Special:  res = LoadChunk(ls, &v->u.special,  vehicle_special_chunk);  break;
+		case VEH_Disaster: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
+		default:           res = LoadChunk(ls, NULL,           vehicle_empty_chunk);    break;
+	}
+
+	/* This chunk size should always be 10 bytes */
+	if (ls->total_read - temp != 10) {
+		DEBUG(oldloader, 4, "Assert failed in Vehicle");
+		return false;
+	}
+
+	return res;
+}
+
+static const OldChunks vehicle_chunk[] = {
+	OCL_SVAR(  OC_UINT8, Vehicle, type ),
+	OCL_SVAR(  OC_UINT8, Vehicle, subtype ),
+
+	OCL_NULL( 2 ),         // Hash, calculated automatically
+	OCL_NULL( 2 ),         // Index, calculated automatically
+
+	OCL_VAR ( OC_UINT32,   1, &_old_order_ptr ),
+	OCL_VAR ( OC_UINT16,   1, &_old_order ),
+
+	OCL_SVAR(  OC_UINT8, Vehicle, num_orders ),
+	OCL_SVAR(  OC_UINT8, Vehicle, cur_order_index ),
+	OCL_SVAR(   OC_TILE, Vehicle, dest_tile ),
+	OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ),
+	OCL_SVAR( OC_UINT16, Vehicle, service_interval ),
+	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ),
+	OCL_SVAR(  OC_UINT8, Vehicle, tick_counter ),
+	OCL_SVAR( OC_UINT16, Vehicle, max_speed ),
+
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ),
+	OCL_SVAR(  OC_UINT8, Vehicle, z_pos ),
+	OCL_SVAR(  OC_UINT8, Vehicle, direction ),
+	OCL_SVAR(   OC_INT8, Vehicle, x_offs ),
+	OCL_SVAR(   OC_INT8, Vehicle, y_offs ),
+	OCL_SVAR(  OC_UINT8, Vehicle, sprite_width ),
+	OCL_SVAR(  OC_UINT8, Vehicle, sprite_height ),
+	OCL_SVAR(  OC_UINT8, Vehicle, z_height ),
+
+	OCL_SVAR(  OC_UINT8, Vehicle, owner ),
+	OCL_SVAR(   OC_TILE, Vehicle, tile ),
+	OCL_SVAR( OC_UINT16, Vehicle, cur_image ),
+
+	OCL_NULL( 8 ),        // Vehicle sprite box, calculated automatically
+
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ),
+	OCL_SVAR( OC_UINT16, Vehicle, cur_speed ),
+	OCL_SVAR(  OC_UINT8, Vehicle, subspeed ),
+	OCL_SVAR(  OC_UINT8, Vehicle, acceleration ),
+	OCL_SVAR(  OC_UINT8, Vehicle, progress ),
+
+	OCL_SVAR(  OC_UINT8, Vehicle, cargo_type ),
+	OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ),
+	OCL_SVAR( OC_UINT16, Vehicle, cargo_count ),
+	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_source ),
+	OCL_SVAR(  OC_UINT8, Vehicle, cargo_days ),
+
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ),
+	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ),
+	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ),
+
+	OCL_SVAR( OC_UINT16, Vehicle, engine_type ),
+
+	OCL_SVAR(  OC_UINT8, Vehicle, spritenum ),
+	OCL_SVAR(  OC_UINT8, Vehicle, day_counter ),
+
+	OCL_SVAR(  OC_UINT8, Vehicle, breakdowns_since_last_service ),
+	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_ctr ),
+	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_delay ),
+	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_chance ),
+
+	OCL_SVAR( OC_UINT16, Vehicle, reliability ),
+	OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ),
+
+	OCL_SVAR(  OC_INT32, Vehicle, profit_this_year ),
+	OCL_SVAR(  OC_INT32, Vehicle, profit_last_year ),
+
+	OCL_VAR ( OC_UINT16,   1, &_old_next_ptr ),
+
+	OCL_SVAR( OC_UINT32, Vehicle, value ),
+
+	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
+
+	OCL_CHUNK( 1, LoadOldVehicleUnion ),
+
+	OCL_NULL( 20 ), // Junk at end of struct (TTDPatch has some data in it)
+
+	OCL_END()
+};
+
+static bool LoadOldVehicle(LoadgameState *ls, int num)
+{
+	uint i;
+
+	/* Read the TTDPatch flags, because we need some info from it */
+	ReadTTDPatchFlags();
+
+	for (i = 0; i < _old_vehicle_multiplier; i++) {
+		Vehicle *v;
+
+		_current_vehicle_id = num * _old_vehicle_multiplier + i;
+
+		if (!AddBlockIfNeeded(&_Vehicle_pool, _current_vehicle_id))
+			error("Vehicles: failed loading savegame: too many vehicles");
+
+		v = GetVehicle(_current_vehicle_id);
+		if (!LoadChunk(ls, v, vehicle_chunk)) return false;
+
+		/* This should be consistent, else we have a big problem... */
+		if (v->index != _current_vehicle_id) {
+			DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid");
+			return false;
+		}
+
+		if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
+			v->orders = GetOrder(REMAP_ORDER_IDX(_old_order_ptr));
+		}
+		AssignOrder(&v->current_order, UnpackOldOrder(_old_order));
+
+		/* For some reason we need to correct for this */
+		switch (v->spritenum) {
+			case 0xfd: break;
+			case 0xff: v->spritenum = 0xfe; break;
+			default:   v->spritenum >>= 1; break;
+		}
+
+		if (_old_next_ptr != 0xFFFF)
+			v->next = GetVehicle(_old_next_ptr);
+
+		v->string_id = RemapOldStringID(_old_string_id);
+
+		/* Vehicle-subtype is different in TTD(Patch) */
+		if (v->type == VEH_Special) v->subtype = v->subtype >> 1;
+	}
+
+	return true;
+}
+
+static const OldChunks sign_chunk[] = {
+	OCL_SVAR( OC_UINT16, Sign, str ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,Sign, x ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,Sign, y ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ),
+
+	OCL_NULL( 6 ),         // Width of sign, no longer in use
+
+	OCL_END()
+};
+
+static bool LoadOldSign(LoadgameState *ls, int num)
+{
+	if (!AddBlockIfNeeded(&_Sign_pool, num))
+		error("Signs: failed loading savegame: too many signs");
+
+	return LoadChunk(ls, GetSign(num), sign_chunk);
+}
+
+static const OldChunks engine_chunk[] = {
+	OCL_SVAR( OC_UINT16, Engine, player_avail ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ),
+	OCL_SVAR( OC_UINT16, Engine, reliability ),
+	OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ),
+	OCL_SVAR( OC_UINT16, Engine, reliability_start ),
+	OCL_SVAR( OC_UINT16, Engine, reliability_max ),
+	OCL_SVAR( OC_UINT16, Engine, reliability_final ),
+	OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ),
+	OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ),
+	OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ),
+
+	OCL_SVAR(  OC_UINT8, Engine, lifelength ),
+	OCL_SVAR(  OC_UINT8, Engine, flags ),
+	OCL_SVAR(  OC_UINT8, Engine, preview_player ),
+	OCL_SVAR(  OC_UINT8, Engine, preview_wait ),
+	OCL_SVAR(  OC_UINT8, Engine, railtype ),
+
+	OCL_NULL( 1 ),         // Junk
+
+	OCL_END()
+};
+
+static bool LoadOldEngine(LoadgameState *ls, int num)
+{
+	if (!LoadChunk(ls, GetEngine(num), engine_chunk)) return false;
+
+	/* Make sure wagons are marked as do-not-age */
+	if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116))
+		GetEngine(num)->age = 0xFFFF;
+
+	return true;
+}
+
+static const OldChunks subsidy_chunk[] = {
+	OCL_SVAR(  OC_UINT8, Subsidy, cargo_type ),
+	OCL_SVAR(  OC_UINT8, Subsidy, age ),
+	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, from ),
+	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, to ),
+
+	OCL_END()
+};
+
+static inline bool LoadOldSubsidy(LoadgameState *ls, int num)
+{
+	return LoadChunk(ls, &_subsidies[num], subsidy_chunk);
+}
+
+static const OldChunks game_difficulty_chunk[] = {
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_no_competitors ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_start_time ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_towns ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_industries ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_loan ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, initial_interest ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_costs ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_speed ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_intelligence ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_breakdowns ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, subsidy_multiplier ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, construction_cost ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, terrain_type ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, quantity_sea_lakes ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, economy ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, line_reverse_mode ),
+	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, disasters ),
+	OCL_END()
+};
+
+static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num)
+{
+	return LoadChunk(ls, &_opt.diff, game_difficulty_chunk);
+}
+
+
+static bool LoadOldMapPart1(LoadgameState *ls, int num)
+{
+	uint i;
+
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_m[i].m1 = ReadByte(ls);
+	}
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_m[i].m2 = ReadByte(ls);
+	}
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_old_map3[i * 2] = ReadByte(ls);
+		_old_map3[i * 2 + 1] = ReadByte(ls);
+	}
+	for (i = 0; i < OLD_MAP_SIZE / 4; i++) {
+		byte b = ReadByte(ls);
+		_m[i * 4 + 0].extra = GB(b, 0, 2);
+		_m[i * 4 + 1].extra = GB(b, 2, 2);
+		_m[i * 4 + 2].extra = GB(b, 4, 2);
+		_m[i * 4 + 3].extra = GB(b, 6, 2);
+	}
+
+	return !ls->failed;
+}
+
+static bool LoadOldMapPart2(LoadgameState *ls, int num)
+{
+	uint i;
+
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_m[i].type_height = ReadByte(ls);
+	}
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_m[i].m5 = ReadByte(ls);
+	}
+
+	return !ls->failed;
+}
+
+static uint32 _old_cur_town_ctr;
+static const OldChunks main_chunk[] = {
+	OCL_ASSERT( 0 ),
+	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
+	OCL_VAR ( OC_UINT16,   1, &_date_fract ),
+	OCL_NULL( 600 ),            // TextEffects
+	OCL_VAR ( OC_UINT32,   2, &_random_seeds[0] ),
+
+	OCL_ASSERT( 0x264 ),
+	OCL_CHUNK(  70, LoadOldTown ),
+	OCL_ASSERT( 0x1C18 ),
+	OCL_CHUNK(5000, LoadOldOrder ),
+	OCL_ASSERT( 0x4328 ),
+
+	OCL_VAR (   OC_TILE, 256, &_animated_tile_list[0] ),
+	OCL_NULL( 4 ),              // old end-of-order-list-pointer, no longer in use
+
+	OCL_CHUNK( 255, LoadOldDepot ),
+	OCL_ASSERT( 0x4B26 ),
+
+	OCL_VAR ( OC_UINT32,   1, &_old_cur_town_ctr ),
+	OCL_NULL( 2 ),              // timer_counter, no longer in use
+	OCL_NULL( 2 ),              // land_code,     no longer in use
+
+	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ),
+	OCL_VAR ( OC_UINT16,   1, &_tick_counter ),
+	OCL_VAR (   OC_TILE,   1, &_cur_tileloop_tile ),
+
+	OCL_CHUNK( 49, LoadOldPrice ),
+	OCL_CHUNK( 12, LoadOldCargoPaymentRate ),
+
+	OCL_ASSERT( 0x4CBA ),
+
+	OCL_CHUNK( 1, LoadOldMapPart1 ),
+
+	OCL_ASSERT( 0x48CBA ),
+
+	OCL_CHUNK(250, LoadOldStation ),
+	OCL_CHUNK( 90, LoadOldIndustry ),
+	OCL_CHUNK(  8, LoadOldPlayer ),
+
+	OCL_ASSERT( 0x547F2 ),
+
+	OCL_CHUNK( 850, LoadOldVehicle ),
+
+	OCL_ASSERT( 0x6F0F2 ),
+
+	OCL_VAR (  OC_UINT8, 32 * 500, &_name_array[0] ),
+
+	OCL_NULL( 0x2000 ),            // Old hash-table, no longer in use
+
+	OCL_CHUNK( 40, LoadOldSign ),
+	OCL_CHUNK(256, LoadOldEngine ),
+
+	OCL_VAR ( OC_UINT16,    1, &_vehicle_id_ctr_day ),
+
+	OCL_CHUNK(  8, LoadOldSubsidy ),
+
+	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,   1, &_next_competitor_start ),
+	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_x ),
+	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_y ),
+	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8,    1, &_saved_scrollpos_zoom ),
+
+	OCL_VAR ( OC_UINT32,    1, &_economy.max_loan ),
+	OCL_VAR ( OC_UINT32,    1, &_economy.max_loan_unround ),
+	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,    1, &_economy.fluct ),
+
+	OCL_VAR ( OC_UINT16,    1, &_disaster_delay ),
+
+	OCL_NULL( 144 ),             // cargo-stuff, calculated in InitializeLandscapeVariables
+
+	OCL_VAR ( OC_UINT16,  256, &_engine_name_strings[0] ),
+
+	OCL_NULL( 144 ),             // AI cargo-stuff, calculated in InitializeLandscapeVariables
+	OCL_NULL( 2 ),               // Company indexes of players, no longer in use
+
+	OCL_VAR ( OC_FILE_U8 | OC_VAR_U16,    1, &_station_tick_ctr ),
+
+	OCL_VAR (  OC_UINT8,    1, &_opt.currency ),
+	OCL_VAR (  OC_UINT8,    1, &_opt.units ),
+	OCL_VAR ( OC_FILE_U8 | OC_VAR_U32,    1, &_cur_player_tick_index ),
+
+	OCL_NULL( 2 ),               // Date stuff, calculated automatically
+	OCL_NULL( 8 ),               // Player colors, calculated automatically
+
+	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount ),
+	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount_pr ),
+	OCL_VAR (  OC_UINT8,    1, &_economy.interest_rate ),
+	OCL_VAR (  OC_UINT8,    1, &_avail_aircraft ),
+	OCL_VAR (  OC_UINT8,    1, &_opt.road_side ),
+	OCL_VAR (  OC_UINT8,    1, &_opt.town_name ),
+
+	OCL_CHUNK( 1, LoadOldGameDifficulty ),
+
+	OCL_ASSERT( 0x77130 ),
+
+	OCL_VAR (  OC_UINT8,    1, &_opt.diff_level ),
+	OCL_VAR (  OC_UINT8,    1, &_opt.landscape ),
+	OCL_VAR (  OC_UINT8,    1, &_trees_tick_ctr ),
+
+	OCL_NULL( 1 ),               // Custom vehicle types yes/no, no longer used
+	OCL_VAR (  OC_UINT8,    1, &_opt.snow_line ),
+
+	OCL_NULL( 32 ),              // new_industry_randtable, no longer used (because of new design)
+	OCL_NULL( 36 ),              // cargo-stuff, calculated in InitializeLandscapeVariables
+
+	OCL_ASSERT( 0x77179 ),
+
+	OCL_CHUNK( 1, LoadOldMapPart2 ),
+
+	OCL_ASSERT( 0x97179 ),
+
+	/* Below any (if available) extra chunks from TTDPatch can follow */
+
+	OCL_END()
+};
+
+static bool LoadOldMain(LoadgameState *ls)
+{
+	int i;
+
+	/* The first 49 is the name of the game + checksum, skip it */
+	fseek(ls->file, HEADER_SIZE, SEEK_SET);
+
+	DEBUG(oldloader, 4, "Reading main chunk...");
+	/* Load the biggest chunk */
+	if (!LoadChunk(ls, NULL, main_chunk)) {
+		DEBUG(oldloader, 0, "Loading failed");
+		return false;
+	}
+	DEBUG(oldloader, 4, "Done, converting game data...");
+
+	/* Fix some general stuff */
+	_opt.landscape = _opt.landscape & 0xF;
+
+	/* Remap some pointers */
+	_cur_town_ctr      = REMAP_TOWN_IDX(_old_cur_town_ctr);
+
+	/* _old_map3 is changed in _map3_lo and _map3_hi */
+	for (i = 0; i < OLD_MAP_SIZE; i++) {
+		_m[i].m3 = _old_map3[i * 2];
+		_m[i].m4 = _old_map3[i * 2 + 1];
+	}
+
+	for (i = 0; i < OLD_MAP_SIZE; i ++) {
+		if (IsTileType(i, MP_RAILWAY)) {
+			/* We save presignals different from TTDPatch, convert them */
+			if (GetRailTileType(i) == RAIL_TILE_SIGNALS) {
+				/* This byte is always zero in TTD for this type of tile */
+				if (_m[i].m4) /* Convert the presignals to our own format */
+					_m[i].m4 = (_m[i].m4 >> 1) & 7;
+			}
+			/* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just
+			 * clear it for ourselves and let OTTD's rebuild PBS itself */
+			_m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */
+		}
+	}
+
+	/* Fix the game to be compatible with OpenTTD */
+	FixOldTowns();
+	FixOldStations();
+	FixOldVehicles();
+
+	AddTypeToEngines();
+
+	/* We have a new difficulty setting */
+	_opt.diff.town_council_tolerance = clamp(_opt.diff_level, 0, 2);
+
+	DEBUG(oldloader, 4, "Finished converting game data");
+	DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted");
+
+	return true;
+}
+
+bool LoadOldSaveGame(const char *file)
+{
+	LoadgameState ls;
+
+	DEBUG(oldloader, 4, "Trying to load a TTD(Patch) savegame");
+
+	InitLoading(&ls);
+
+	/* Open file */
+	ls.file = fopen(file, "rb");
+
+	if (ls.file == NULL) {
+		DEBUG(oldloader, 0, "Cannot open file '%s'", file);
+		return false;
+	}
+
+	/* Load the main chunk */
+	if (!LoadOldMain(&ls)) return false;
+
+	fclose(ls.file);
+
+	_pause = 2;
+
+	return true;
+}
+
+void GetOldSaveGameName(char *title, const char *path, const char *file)
+{
+	char filename[MAX_PATH];
+	FILE *f;
+
+	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
+	f = fopen(filename, "rb");
+	title[0] = '\0';
+	title[48] = '\0';
+
+	if (f == NULL) return;
+
+	if (fread(title, 1, 48, f) != 48) snprintf(title, 48, "Corrupt file");
+
+	fclose(f);
+}
deleted file mode 100644
--- a/src/oldpool.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "oldpool.h"
-
-/**
- * Clean a pool in a safe way (does free all blocks)
- */
-void CleanPool(OldMemoryPool *pool)
-{
-	uint i;
-
-	DEBUG(misc, 4, "[Pool] (%s) cleaning pool..", pool->name);
-
-	/* Free all blocks */
-	for (i = 0; i < pool->current_blocks; i++) {
-		if (pool->clean_block_proc != NULL) {
-			pool->clean_block_proc(i * (1 << pool->block_size_bits), (i + 1) * (1 << pool->block_size_bits) - 1);
-		}
-		free(pool->blocks[i]);
-	}
-
-	/* Free the block itself */
-	free(pool->blocks);
-
-	/* Clear up some critical data */
-	pool->total_items = 0;
-	pool->current_blocks = 0;
-	pool->blocks = NULL;
-}
-
-/**
- * This function tries to increase the size of array by adding
- *  1 block too it
- *
- * @return Returns false if the pool could not be increased
- */
-bool AddBlockToPool(OldMemoryPool *pool)
-{
-	/* Is the pool at his max? */
-	if (pool->max_blocks == pool->current_blocks)
-		return false;
-
-	pool->total_items = (pool->current_blocks + 1) * (1 << pool->block_size_bits);
-
-	DEBUG(misc, 4, "[Pool] (%s) increasing size of pool to %d items (%d bytes)", pool->name, pool->total_items, pool->total_items * pool->item_size);
-
-	/* Increase the poolsize */
-	pool->blocks = realloc(pool->blocks, sizeof(pool->blocks[0]) * (pool->current_blocks + 1));
-	if (pool->blocks == NULL) error("Pool: (%s) could not allocate memory for blocks", pool->name);
-
-	/* Allocate memory to the new block item */
-	pool->blocks[pool->current_blocks] = malloc(pool->item_size * (1 << pool->block_size_bits));
-	if (pool->blocks[pool->current_blocks] == NULL)
-		error("Pool: (%s) could not allocate memory for blocks", pool->name);
-
-	/* Clean the content of the new block */
-	memset(pool->blocks[pool->current_blocks], 0, pool->item_size * (1 << pool->block_size_bits));
-
-	/* Call a custom function if defined (e.g. to fill indexes) */
-	if (pool->new_block_proc != NULL)
-		pool->new_block_proc(pool->current_blocks * (1 << pool->block_size_bits));
-
-	/* We have a new block */
-	pool->current_blocks++;
-
-	return true;
-}
-
-/**
- * Adds blocks to the pool if needed (and possible) till index fits inside the pool
- *
- * @return Returns false if adding failed
- */
-bool AddBlockIfNeeded(OldMemoryPool *pool, uint index)
-{
-	while (index >= pool->total_items) {
-		if (!AddBlockToPool(pool))
-			return false;
-	}
-
-	return true;
-}
new file mode 100644
--- /dev/null
+++ b/src/oldpool.cpp
@@ -0,0 +1,86 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "oldpool.h"
+
+/**
+ * Clean a pool in a safe way (does free all blocks)
+ */
+void CleanPool(OldMemoryPool *pool)
+{
+	uint i;
+
+	DEBUG(misc, 4, "[Pool] (%s) cleaning pool..", pool->name);
+
+	/* Free all blocks */
+	for (i = 0; i < pool->current_blocks; i++) {
+		if (pool->clean_block_proc != NULL) {
+			pool->clean_block_proc(i * (1 << pool->block_size_bits), (i + 1) * (1 << pool->block_size_bits) - 1);
+		}
+		free(pool->blocks[i]);
+	}
+
+	/* Free the block itself */
+	free(pool->blocks);
+
+	/* Clear up some critical data */
+	pool->total_items = 0;
+	pool->current_blocks = 0;
+	pool->blocks = NULL;
+}
+
+/**
+ * This function tries to increase the size of array by adding
+ *  1 block too it
+ *
+ * @return Returns false if the pool could not be increased
+ */
+bool AddBlockToPool(OldMemoryPool *pool)
+{
+	/* Is the pool at his max? */
+	if (pool->max_blocks == pool->current_blocks)
+		return false;
+
+	pool->total_items = (pool->current_blocks + 1) * (1 << pool->block_size_bits);
+
+	DEBUG(misc, 4, "[Pool] (%s) increasing size of pool to %d items (%d bytes)", pool->name, pool->total_items, pool->total_items * pool->item_size);
+
+	/* Increase the poolsize */
+	pool->blocks = realloc(pool->blocks, sizeof(pool->blocks[0]) * (pool->current_blocks + 1));
+	if (pool->blocks == NULL) error("Pool: (%s) could not allocate memory for blocks", pool->name);
+
+	/* Allocate memory to the new block item */
+	pool->blocks[pool->current_blocks] = malloc(pool->item_size * (1 << pool->block_size_bits));
+	if (pool->blocks[pool->current_blocks] == NULL)
+		error("Pool: (%s) could not allocate memory for blocks", pool->name);
+
+	/* Clean the content of the new block */
+	memset(pool->blocks[pool->current_blocks], 0, pool->item_size * (1 << pool->block_size_bits));
+
+	/* Call a custom function if defined (e.g. to fill indexes) */
+	if (pool->new_block_proc != NULL)
+		pool->new_block_proc(pool->current_blocks * (1 << pool->block_size_bits));
+
+	/* We have a new block */
+	pool->current_blocks++;
+
+	return true;
+}
+
+/**
+ * Adds blocks to the pool if needed (and possible) till index fits inside the pool
+ *
+ * @return Returns false if adding failed
+ */
+bool AddBlockIfNeeded(OldMemoryPool *pool, uint index)
+{
+	while (index >= pool->total_items) {
+		if (!AddBlockToPool(pool))
+			return false;
+	}
+
+	return true;
+}
deleted file mode 100644
--- a/src/openttd.c
+++ /dev/null
@@ -1,1704 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "string.h"
-#include "table/strings.h"
-#include "debug.h"
-#include "driver.h"
-#include "saveload.h"
-#include "strings.h"
-#include "map.h"
-#include "tile.h"
-#include "void_map.h"
-
-#define VARDEF
-#include "openttd.h"
-#include "bridge_map.h"
-#include "functions.h"
-#include "mixer.h"
-#include "spritecache.h"
-#include "strings.h"
-#include "gfx.h"
-#include "gfxinit.h"
-#include "gui.h"
-#include "station.h"
-#include "station_map.h"
-#include "town_map.h"
-#include "tunnel_map.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "window.h"
-#include "player.h"
-#include "command.h"
-#include "town.h"
-#include "industry.h"
-#include "news.h"
-#include "engine.h"
-#include "sound.h"
-#include "economy.h"
-#include "fileio.h"
-#include "hal.h"
-#include "airport.h"
-#include "console.h"
-#include "screenshot.h"
-#include "network/network.h"
-#include "signs.h"
-#include "depot.h"
-#include "waypoint.h"
-#include "ai/ai.h"
-#include "train.h"
-#include "yapf/yapf.h"
-#include "settings.h"
-#include "genworld.h"
-#include "date.h"
-#include "clear_map.h"
-#include "fontcache.h"
-#include "newgrf_config.h"
-
-#include "bridge_map.h"
-#include "clear_map.h"
-#include "rail_map.h"
-#include "road_map.h"
-#include "water_map.h"
-#include "industry_map.h"
-
-#include <stdarg.h>
-
-void CallLandscapeTick(void);
-void IncreaseDate(void);
-void DoPaletteAnimations(void);
-void MusicLoop(void);
-void ResetMusic(void);
-void InitializeStations(void);
-void DeleteAllPlayerStations(void);
-
-extern void SetDifficultyLevel(int mode, GameOptions *gm_opt);
-extern void DoStartupNewPlayer(bool is_ai);
-extern void ShowOSErrorBox(const char *buf);
-
-/* TODO: usrerror() for errors which are not of an internal nature but
- * caused by the user, i.e. missing files or fatal configuration errors.
- * Post-0.4.0 since Celestar doesn't want this in SVN before. --pasky */
-
-void CDECL error(const char *s, ...)
-{
-	va_list va;
-	char buf[512];
-
-	va_start(va, s);
-	vsnprintf(buf, lengthof(buf), s, va);
-	va_end(va);
-
-	ShowOSErrorBox(buf);
-	if (_video_driver != NULL) _video_driver->stop();
-
-	assert(0);
-	exit(1);
-}
-
-void CDECL ShowInfoF(const char *str, ...)
-{
-	va_list va;
-	char buf[1024];
-	va_start(va, str);
-	vsnprintf(buf, lengthof(buf), str, va);
-	va_end(va);
-	ShowInfo(buf);
-}
-
-
-void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
-{
-	FILE *in;
-	byte *mem;
-	size_t len;
-
-	in = fopen(filename, "rb");
-	if (in == NULL) return NULL;
-
-	fseek(in, 0, SEEK_END);
-	len = ftell(in);
-	fseek(in, 0, SEEK_SET);
-	if (len > maxsize || (mem = malloc(len + 1)) == NULL) {
-		fclose(in);
-		return NULL;
-	}
-	mem[len] = 0;
-	if (fread(mem, len, 1, in) != 1) {
-		fclose(in);
-		free(mem);
-		return NULL;
-	}
-	fclose(in);
-
-	*lenp = len;
-	return mem;
-}
-
-static void showhelp(void)
-{
-	extern const char _openttd_revision[];
-	char buf[4096], *p;
-
-	p = buf;
-
-	p += snprintf(p, lengthof(buf), "OpenTTD %s\n", _openttd_revision);
-	p = strecpy(p,
-		"\n"
-		"\n"
-		"Command line options:\n"
-		"  -v drv              = Set video driver (see below)\n"
-		"  -s drv              = Set sound driver (see below)\n"
-		"  -m drv              = Set music driver (see below)\n"
-		"  -r res              = Set resolution (for instance 800x600)\n"
-		"  -h                  = Display this help text\n"
-		"  -t year             = Set starting year\n"
-		"  -d [[fac=]lvl[,...]]= Debug mode\n"
-		"  -e                  = Start Editor\n"
-		"  -g [savegame]       = Start new/save game immediately\n"
-		"  -G seed             = Set random seed\n"
-		"  -n [ip:port#player] = Start networkgame\n"
-		"  -D [ip][:port]      = Start dedicated server\n"
-#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
-		"  -f                  = Fork into the background (dedicated only)\n"
-#endif
-		"  -i                  = Force to use the DOS palette\n"
-		"                          (use this if you see a lot of pink)\n"
-		"  -c config_file      = Use 'config_file' instead of 'openttd.cfg'\n"
-		"  -x                  = Do not automatically save to config file on exit\n",
-		lastof(buf)
-	);
-
-	p = GetDriverList(p, lastof(buf));
-
-	ShowInfo(buf);
-}
-
-
-typedef struct {
-	char *opt;
-	int numleft;
-	char **argv;
-	const char *options;
-	char *cont;
-} MyGetOptData;
-
-static void MyGetOptInit(MyGetOptData *md, int argc, char **argv, const char *options)
-{
-	md->cont = NULL;
-	md->numleft = argc;
-	md->argv = argv;
-	md->options = options;
-}
-
-static int MyGetOpt(MyGetOptData *md)
-{
-	char *s,*r,*t;
-
-	s = md->cont;
-	if (s != NULL)
-		goto md_continue_here;
-
-	for (;;) {
-		if (--md->numleft < 0) return -1;
-
-		s = *md->argv++;
-		if (*s == '-') {
-md_continue_here:;
-			s++;
-			if (*s != 0) {
-				// Found argument, try to locate it in options.
-				if (*s == ':' || (r = strchr(md->options, *s)) == NULL) {
-					// ERROR!
-					return -2;
-				}
-				if (r[1] == ':') {
-					// Item wants an argument. Check if the argument follows, or if it comes as a separate arg.
-					if (!*(t = s + 1)) {
-						// It comes as a separate arg. Check if out of args?
-						if (--md->numleft < 0 || *(t = *md->argv) == '-') {
-							// Check if item is optional?
-							if (r[2] != ':')
-								return -2;
-							md->numleft++;
-							t = NULL;
-						} else {
-							md->argv++;
-						}
-					}
-					md->opt = t;
-					md->cont = NULL;
-					return *s;
-				}
-				md->opt = NULL;
-				md->cont = s;
-				return *s;
-			}
-		} else {
-			// This is currently not supported.
-			return -2;
-		}
-	}
-}
-
-
-static void ParseResolution(int res[2], const char *s)
-{
-	char *t = strchr(s, 'x');
-	if (t == NULL) {
-		ShowInfoF("Invalid resolution '%s'", s);
-		return;
-	}
-
-	res[0] = clamp(strtoul(s, NULL, 0), 64, MAX_SCREEN_WIDTH);
-	res[1] = clamp(strtoul(t + 1, NULL, 0), 64, MAX_SCREEN_HEIGHT);
-}
-
-static void InitializeDynamicVariables(void)
-{
-	/* Dynamic stuff needs to be initialized somewhere... */
-	_town_sort     = NULL;
-	_industry_sort = NULL;
-}
-
-static void UnInitializeDynamicVariables(void)
-{
-	/* Dynamic stuff needs to be free'd somewhere... */
-	CleanPool(&_Town_pool);
-	CleanPool(&_Industry_pool);
-	CleanPool(&_Station_pool);
-	CleanPool(&_Vehicle_pool);
-	CleanPool(&_Sign_pool);
-	CleanPool(&_Order_pool);
-
-	free((void*)_town_sort);
-	free((void*)_industry_sort);
-}
-
-static void UnInitializeGame(void)
-{
-	UnInitWindowSystem();
-
-	free(_config_file);
-}
-
-static void LoadIntroGame(void)
-{
-	char filename[256];
-
-	_game_mode = GM_MENU;
-	CLRBITS(_display_opt, DO_TRANS_BUILDINGS); // don't make buildings transparent in intro
-	_opt_ptr = &_opt_newgame;
-	ResetGRFConfig(false);
-
-	// Setup main window
-	ResetWindowSystem();
-	SetupColorsAndInitialWindow();
-
-	// Generate a world.
-	snprintf(filename, lengthof(filename), "%sopntitle.dat",  _paths.data_dir);
-#if defined SECOND_DATA_DIR
-	if (SaveOrLoad(filename, SL_LOAD) != SL_OK) {
-		snprintf(filename, lengthof(filename), "%sopntitle.dat",  _paths.second_data_dir);
-	}
-#endif
-	if (SaveOrLoad(filename, SL_LOAD) != SL_OK) {
-		GenerateWorld(GW_EMPTY, 64, 64); // if failed loading, make empty world.
-		WaitTillGeneratedWorld();
-	}
-
-	_pause = 0;
-	SetLocalPlayer(0);
-	/* Make sure you can't scroll in the menu */
-	_scrolling_viewport = 0;
-	_cursor.fix_at = false;
-	MarkWholeScreenDirty();
-
-	// Play main theme
-	if (_music_driver->is_song_playing()) ResetMusic();
-}
-
-#if defined(UNIX) && !defined(__MORPHOS__)
-extern void DedicatedFork(void);
-#endif
-
-int ttd_main(int argc, char *argv[])
-{
-	MyGetOptData mgo;
-	int i;
-	const char *optformat;
-	char musicdriver[16], sounddriver[16], videodriver[16];
-	int resolution[2] = {0,0};
-	Year startyear = INVALID_YEAR;
-	uint generation_seed = GENERATE_NEW_SEED;
-	bool dedicated = false;
-	bool network   = false;
-	bool save_config = true;
-	char *network_conn = NULL;
-	char *dedicated_host = NULL;
-	uint16 dedicated_port = 0;
-
-	musicdriver[0] = sounddriver[0] = videodriver[0] = 0;
-
-	_game_mode = GM_MENU;
-	_switch_mode = SM_MENU;
-	_switch_mode_errorstr = INVALID_STRING_ID;
-	_dedicated_forks = false;
-	_config_file = NULL;
-
-	// The last param of the following function means this:
-	//   a letter means: it accepts that param (e.g.: -h)
-	//   a ':' behind it means: it need a param (e.g.: -m<driver>)
-	//   a '::' behind it means: it can optional have a param (e.g.: -d<debug>)
-	optformat = "m:s:v:hD::n::eit:d::r:g::G:c:x"
-#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
-		"f"
-#endif
-	;
-
-	MyGetOptInit(&mgo, argc-1, argv+1, optformat);
-	while ((i = MyGetOpt(&mgo)) != -1) {
-		switch (i) {
-		case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break;
-		case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break;
-		case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break;
-		case 'D':
-			strcpy(musicdriver, "null");
-			strcpy(sounddriver, "null");
-			strcpy(videodriver, "dedicated");
-			dedicated = true;
-			if (mgo.opt != NULL)
-			{
-				/* Use the existing method for parsing (openttd -n).
-				 * However, we do ignore the #player part. */
-				const char *temp = NULL;
-				const char *port = NULL;
-				ParseConnectionString(&temp, &port, mgo.opt);
-				if (*mgo.opt != '\0') dedicated_host = mgo.opt;
-				if (port != NULL) dedicated_port = atoi(port);
-			}
-			break;
-		case 'f': _dedicated_forks = true; break;
-		case 'n':
-			network = true;
-			network_conn = mgo.opt; // optional IP parameter, NULL if unset
-			break;
-		case 'r': ParseResolution(resolution, mgo.opt); break;
-		case 't': startyear = atoi(mgo.opt); break;
-		case 'd': {
-#if defined(WIN32)
-				CreateConsole();
-#endif
-				if (mgo.opt != NULL) SetDebugString(mgo.opt);
-			} break;
-		case 'e': _switch_mode = SM_EDITOR; break;
-		case 'i': _use_dos_palette = true; break;
-		case 'g':
-			if (mgo.opt != NULL) {
-				strcpy(_file_to_saveload.name, mgo.opt);
-				_switch_mode = SM_LOAD;
-			} else {
-				_switch_mode = SM_NEWGAME;
-			}
-			break;
-		case 'G': generation_seed = atoi(mgo.opt); break;
-		case 'c': _config_file = strdup(mgo.opt); break;
-		case 'x': save_config = false; break;
-		case -2:
-		case 'h':
-			showhelp();
-			return 0;
-		}
-	}
-
-	DeterminePaths();
-	CheckExternalFiles();
-
-#if defined(UNIX) && !defined(__MORPHOS__)
-	// We must fork here, or we'll end up without some resources we need (like sockets)
-	if (_dedicated_forks)
-		DedicatedFork();
-#endif
-
-	LoadFromConfig();
-	CheckConfig();
-	LoadFromHighScore();
-
-	// override config?
-	if (musicdriver[0]) ttd_strlcpy(_ini_musicdriver, musicdriver, sizeof(_ini_musicdriver));
-	if (sounddriver[0]) ttd_strlcpy(_ini_sounddriver, sounddriver, sizeof(_ini_sounddriver));
-	if (videodriver[0]) ttd_strlcpy(_ini_videodriver, videodriver, sizeof(_ini_videodriver));
-	if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; }
-	if (startyear != INVALID_YEAR) _patches_newgame.starting_year = startyear;
-	if (generation_seed != GENERATE_NEW_SEED) _patches_newgame.generation_seed = generation_seed;
-
-	if (dedicated_host) snprintf(_network_server_bind_ip_host, NETWORK_HOSTNAME_LENGTH, "%s", dedicated_host);
-	if (dedicated_port) _network_server_port = dedicated_port;
-	if (_dedicated_forks && !dedicated) _dedicated_forks = false;
-
-	// enumerate language files
-	InitializeLanguagePacks();
-
-	// initialize screenshot formats
-	InitializeScreenshotFormats();
-
-	// initialize airport state machines
-	InitializeAirports();
-
-	/* initialize all variables that are allocated dynamically */
-	InitializeDynamicVariables();
-
-	/* start the AI */
-	AI_Initialize();
-
-	// Sample catalogue
-	DEBUG(misc, 1, "Loading sound effects...");
-	MxInitialize(11025);
-	SoundInitialize("sample.cat");
-
-	/* Initialize FreeType */
-	InitFreeType();
-
-	// This must be done early, since functions use the InvalidateWindow* calls
-	InitWindowSystem();
-
-	/* Initialize game palette */
-	GfxInitPalettes();
-
-	DEBUG(driver, 1, "Loading drivers...");
-	LoadDriver(SOUND_DRIVER, _ini_sounddriver);
-	LoadDriver(MUSIC_DRIVER, _ini_musicdriver);
-	LoadDriver(VIDEO_DRIVER, _ini_videodriver); // load video last, to prevent an empty window while sound and music loads
-	_savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
-
-	// restore saved music volume
-	_music_driver->set_volume(msf.music_vol);
-
-	NetworkStartUp(); // initialize network-core
-
-	ScanNewGRFFiles();
-
-	_opt_ptr = &_opt_newgame;
-	ResetGRFConfig(false);
-
-	/* XXX - ugly hack, if diff_level is 9, it means we got no setting from the config file */
-	if (_opt_newgame.diff_level == 9) SetDifficultyLevel(0, &_opt_newgame);
-
-	/* Make sure _patches is filled with _patches_newgame if we switch to a game directly */
-	if (_switch_mode != SM_NONE) {
-		_opt = _opt_newgame;
-		UpdatePatches();
-	}
-
-	// initialize the ingame console
-	IConsoleInit();
-	_cursor.in_window = true;
-	InitializeGUI();
-	IConsoleCmdExec("exec scripts/autoexec.scr 0");
-
-	GenerateWorld(GW_EMPTY, 64, 64); // Make the viewport initialization happy
-	WaitTillGeneratedWorld();
-
-#ifdef ENABLE_NETWORK
-	if (network && _network_available) {
-		if (network_conn != NULL) {
-			const char *port = NULL;
-			const char *player = NULL;
-			uint16 rport;
-
-			rport = NETWORK_DEFAULT_PORT;
-			_network_playas = PLAYER_NEW_COMPANY;
-
-			ParseConnectionString(&player, &port, network_conn);
-
-			if (player != NULL) {
-				_network_playas = atoi(player);
-
-				if (_network_playas != PLAYER_SPECTATOR) {
-					_network_playas--;
-					if (!IsValidPlayer(_network_playas)) return false;
-				}
-			}
-			if (port != NULL) rport = atoi(port);
-
-			LoadIntroGame();
-			_switch_mode = SM_NONE;
-			NetworkClientConnectGame(network_conn, rport);
-		}
-	}
-#endif /* ENABLE_NETWORK */
-
-	_video_driver->main_loop();
-
-	WaitTillSaved();
-	IConsoleFree();
-
-	if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections
-
-	_video_driver->stop();
-	_music_driver->stop();
-	_sound_driver->stop();
-
-	/* only save config if we have to */
-	if (save_config) {
-		SaveToConfig();
-		SaveToHighScore();
-	}
-
-	// uninitialize airport state machines
-	UnInitializeAirports();
-
-	/* uninitialize variables that are allocated dynamic */
-	UnInitializeDynamicVariables();
-
-	/* stop the AI */
-	AI_Uninitialize();
-
-	/* Close all and any open filehandles */
-	FioCloseAll();
-	UnInitializeGame();
-
-	return 0;
-}
-
-void HandleExitGameRequest(void)
-{
-	if (_game_mode == GM_MENU) { // do not ask to quit on the main screen
-		_exit_game = true;
-	} else if (_patches.autosave_on_exit) {
-		DoExitSave();
-		_exit_game = true;
-	} else {
-		AskExitGame();
-	}
-}
-
-
-/** Mutex so that only one thread can communicate with the main program
- * at any given time */
-static ThreadMsg _message = MSG_OTTD_NO_MESSAGE;
-
-static inline void OTTD_ReleaseMutex(void) {_message = MSG_OTTD_NO_MESSAGE;}
-static inline ThreadMsg OTTD_PollThreadEvent(void) {return _message;}
-
-/** Called by running thread to execute some action in the main game.
- * It will stall as long as the mutex is not freed (handled) by the game */
-void OTTD_SendThreadMessage(ThreadMsg msg)
-{
-	if (_exit_game) return;
-	while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10);
-
-	_message = msg;
-}
-
-
-/** Handle the user-messages sent to us
- * @param message message sent
- */
-static void ProcessSentMessage(ThreadMsg message)
-{
-	switch (message) {
-		case MSG_OTTD_SAVETHREAD_DONE:  SaveFileDone(); break;
-		case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break;
-		default: NOT_REACHED();
-	}
-
-	OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled
-}
-
-static void ShowScreenshotResult(bool b)
-{
-	if (b) {
-		SetDParamStr(0, _screenshot_name);
-		ShowErrorMessage(INVALID_STRING_ID, STR_031B_SCREENSHOT_SUCCESSFULLY, 0, 0);
-	} else {
-		ShowErrorMessage(INVALID_STRING_ID, STR_031C_SCREENSHOT_FAILED, 0, 0);
-	}
-
-}
-
-static void MakeNewGameDone(void)
-{
-	/* In a dedicated server, the server does not play */
-	if (_network_dedicated) {
-		SetLocalPlayer(PLAYER_SPECTATOR);
-		return;
-	}
-
-	/* Create a single player */
-	DoStartupNewPlayer(false);
-
-	SetLocalPlayer(0);
-	_current_player = _local_player;
-	DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
-
-	SettingsDisableElrail(_patches.disable_elrails);
-
-	MarkWholeScreenDirty();
-}
-
-static void MakeNewGame(bool from_heightmap)
-{
-	_game_mode = GM_NORMAL;
-
-	ResetGRFConfig(true);
-
-	GenerateWorldSetCallback(&MakeNewGameDone);
-	GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _patches.map_x, 1 << _patches.map_y);
-}
-
-static void MakeNewEditorWorldDone(void)
-{
-	SetLocalPlayer(OWNER_NONE);
-
-	MarkWholeScreenDirty();
-}
-
-static void MakeNewEditorWorld(void)
-{
-	_game_mode = GM_EDITOR;
-
-	ResetGRFConfig(true);
-
-	GenerateWorldSetCallback(&MakeNewEditorWorldDone);
-	GenerateWorld(GW_EMPTY, 1 << _patches.map_x, 1 << _patches.map_y);
-}
-
-void StartupPlayers(void);
-void StartupDisasters(void);
-extern void StartupEconomy(void);
-
-/**
- * Start Scenario starts a new game based on a scenario.
- * Eg 'New Game' --> select a preset scenario
- * This starts a scenario based on your current difficulty settings
- */
-static void StartScenario(void)
-{
-	_game_mode = GM_NORMAL;
-
-	// invalid type
-	if (_file_to_saveload.mode == SL_INVALID) {
-		DEBUG(sl, 0, "Savegame is obsolete or invalid format: '%s'", _file_to_saveload.name);
-		ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
-		_game_mode = GM_MENU;
-		return;
-	}
-
-	// Reinitialize windows
-	ResetWindowSystem();
-
-	SetupColorsAndInitialWindow();
-
-	ResetGRFConfig(true);
-
-	// Load game
-	if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode) != SL_OK) {
-		LoadIntroGame();
-		ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
-	}
-
-	_opt_ptr = &_opt;
-	_opt_ptr->diff = _opt_newgame.diff;
-	_opt.diff_level = _opt_newgame.diff_level;
-
-	// Inititalize data
-	StartupEconomy();
-	StartupPlayers();
-	StartupEngines();
-	StartupDisasters();
-
-	SetLocalPlayer(0);
-	_current_player = _local_player;
-	DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
-
-	MarkWholeScreenDirty();
-}
-
-bool SafeSaveOrLoad(const char *filename, int mode, int newgm)
-{
-	byte ogm = _game_mode;
-
-	_game_mode = newgm;
-	switch (SaveOrLoad(filename, mode)) {
-		case SL_OK: return true;
-
-		case SL_REINIT:
-			switch (ogm) {
-				case GM_MENU:   LoadIntroGame();      break;
-				case GM_EDITOR: MakeNewEditorWorld(); break;
-				default:        MakeNewGame(false);   break;
-			}
-			return false;
-
-		default:
-			_game_mode = ogm;
-			return false;
-	}
-}
-
-void SwitchMode(int new_mode)
-{
-#ifdef ENABLE_NETWORK
-	// If we are saving something, the network stays in his current state
-	if (new_mode != SM_SAVE) {
-		// If the network is active, make it not-active
-		if (_networking) {
-			if (_network_server && (new_mode == SM_LOAD || new_mode == SM_NEWGAME)) {
-				NetworkReboot();
-				NetworkUDPStop();
-			} else {
-				NetworkDisconnect();
-				NetworkUDPStop();
-			}
-		}
-
-		// If we are a server, we restart the server
-		if (_is_network_server) {
-			// But not if we are going to the menu
-			if (new_mode != SM_MENU) {
-				NetworkServerStart();
-			} else {
-				// This client no longer wants to be a network-server
-				_is_network_server = false;
-			}
-		}
-	}
-#endif /* ENABLE_NETWORK */
-
-	switch (new_mode) {
-	case SM_EDITOR: /* Switch to scenario editor */
-		MakeNewEditorWorld();
-		break;
-
-	case SM_NEWGAME: /* New Game --> 'Random game' */
-#ifdef ENABLE_NETWORK
-		if (_network_server) {
-			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map");
-		}
-#endif /* ENABLE_NETWORK */
-		MakeNewGame(false);
-		break;
-
-	case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */
-#ifdef ENABLE_NETWORK
-		if (_network_server) {
-			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title);
-		}
-#endif /* ENABLE_NETWORK */
-		StartScenario();
-		break;
-
-	case SM_LOAD: { /* Load game, Play Scenario */
-		_opt_ptr = &_opt;
-		ResetGRFConfig(true);
-
-		if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
-			LoadIntroGame();
-			ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
-		} else {
-			/* Update the local player for a loaded game. It is either always
-			 * player #1 (eg 0) or in the case of a dedicated server a spectator */
-			SetLocalPlayer(_network_dedicated ? PLAYER_SPECTATOR : 0);
-			DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // decrease pause counter (was increased from opening load dialog)
-#ifdef ENABLE_NETWORK
-			if (_network_server) {
-				snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title);
-			}
-#endif /* ENABLE_NETWORK */
-		}
-		break;
-	}
-
-	case SM_START_HEIGHTMAP: /* Load a heightmap and start a new game from it */
-#ifdef ENABLE_NETWORK
-		if (_network_server) {
-			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title);
-		}
-#endif /* ENABLE_NETWORK */
-		MakeNewGame(true);
-		break;
-
-	case SM_LOAD_HEIGHTMAP: /* Load heightmap from scenario editor */
-		SetLocalPlayer(OWNER_NONE);
-
-		GenerateWorld(GW_HEIGHTMAP, 1 << _patches.map_x, 1 << _patches.map_y);
-		MarkWholeScreenDirty();
-		break;
-
-	case SM_LOAD_SCENARIO: { /* Load scenario from scenario editor */
-		if (SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR)) {
-			Player *p;
-
-			_opt_ptr = &_opt;
-
-			SetLocalPlayer(OWNER_NONE);
-			_generating_world = true;
-			/* Delete all players */
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
-					p->is_active = false;
-				}
-			}
-			_generating_world = false;
-			_patches_newgame.starting_year = _cur_year;
-			// delete all stations owned by a player
-			DeleteAllPlayerStations();
-		} else {
-			ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
-		}
-		break;
-	}
-
-	case SM_MENU: /* Switch to game intro menu */
-		LoadIntroGame();
-		break;
-
-	case SM_SAVE: /* Save game */
-		if (SaveOrLoad(_file_to_saveload.name, SL_SAVE) != SL_OK) {
-			ShowErrorMessage(INVALID_STRING_ID, STR_4007_GAME_SAVE_FAILED, 0, 0);
-		} else {
-			DeleteWindowById(WC_SAVELOAD, 0);
-		}
-		break;
-
-	case SM_GENRANDLAND: /* Generate random land within scenario editor */
-		SetLocalPlayer(OWNER_NONE);
-		GenerateWorld(GW_RANDOM, 1 << _patches.map_x, 1 << _patches.map_y);
-		// XXX: set date
-		MarkWholeScreenDirty();
-		break;
-	}
-
-	if (_switch_mode_errorstr != INVALID_STRING_ID) {
-		ShowErrorMessage(INVALID_STRING_ID, _switch_mode_errorstr, 0, 0);
-	}
-}
-
-
-// State controlling game loop.
-// The state must not be changed from anywhere
-// but here.
-// That check is enforced in DoCommand.
-void StateGameLoop(void)
-{
-	// dont execute the state loop during pause
-	if (_pause) return;
-	if (IsGeneratingWorld()) return;
-
-	if (_game_mode == GM_EDITOR) {
-		RunTileLoop();
-		CallVehicleTicks();
-		CallLandscapeTick();
-		CallWindowTickEvent();
-		NewsLoop();
-	} else {
-		// All these actions has to be done from OWNER_NONE
-		//  for multiplayer compatibility
-		PlayerID p = _current_player;
-		_current_player = OWNER_NONE;
-
-		AnimateAnimatedTiles();
-		IncreaseDate();
-		RunTileLoop();
-		CallVehicleTicks();
-		CallLandscapeTick();
-
-		AI_RunGameLoop();
-
-		CallWindowTickEvent();
-		NewsLoop();
-		_current_player = p;
-	}
-}
-
-static void DoAutosave(void)
-{
-	char buf[200];
-
-	if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) {
-		const Player *p = GetPlayer(_local_player);
-		char* s = buf;
-
-		s += snprintf(buf, lengthof(buf), "%s%s", _paths.autosave_dir, PATHSEP);
-
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		SetDParam(2, _date);
-		s = GetString(s, STR_4004, lastof(buf));
-		strecpy(s, ".sav", lastof(buf));
-	} else { /* generate a savegame name and number according to _patches.max_num_autosaves */
-		snprintf(buf, lengthof(buf), "%s%sautosave%d.sav", _paths.autosave_dir, PATHSEP, _autosave_ctr);
-
-		_autosave_ctr++;
-		if (_autosave_ctr >= _patches.max_num_autosaves) {
-			// we reached the limit for numbers of autosaves. We will start over
-			_autosave_ctr = 0;
-		}
-	}
-
-	DEBUG(sl, 2, "Autosaving to '%s'", buf);
-	if (SaveOrLoad(buf, SL_SAVE) != SL_OK)
-		ShowErrorMessage(INVALID_STRING_ID, STR_AUTOSAVE_FAILED, 0, 0);
-}
-
-static void ScrollMainViewport(int x, int y)
-{
-	if (_game_mode != GM_MENU) {
-		Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
-		assert(w);
-
-		WP(w,vp_d).scrollpos_x += x << w->viewport->zoom;
-		WP(w,vp_d).scrollpos_y += y << w->viewport->zoom;
-	}
-}
-
-static const int8 scrollamt[16][2] = {
-	{ 0,  0},
-	{-2,  0}, //  1 : left
-	{ 0, -2}, //  2 : up
-	{-2, -1}, //  3 : left + up
-	{ 2,  0}, //  4 : right
-	{ 0,  0}, //  5 : left + right
-	{ 2, -1}, //  6 : right + up
-	{ 0, -2}, //  7 : left + right + up = up
-	{ 0  ,2}, //  8 : down
-	{-2  ,1}, //  9 : down+left
-	{ 0,  0}, // 10 : impossible
-	{-2,  0}, // 11 : left + up + down = left
-	{ 2,  1}, // 12 : down+right
-	{ 0,  2}, // 13 : left + right + down = down
-	{ 0, -2}, // 14 : left + right + up = up
-	{ 0,  0}, // 15 : impossible
-};
-
-static void HandleKeyScrolling(void)
-{
-	if (_dirkeys && !_no_scroll) {
-		int factor = _shift_pressed ? 50 : 10;
-		ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
-	}
-}
-
-void GameLoop(void)
-{
-	ThreadMsg message;
-
-	if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
-
-	// autosave game?
-	if (_do_autosave) {
-		_do_autosave = false;
-		DoAutosave();
-		RedrawAutosave();
-	}
-
-	// handle scrolling of the main window
-	HandleKeyScrolling();
-
-	// make a screenshot?
-	if (IsScreenshotRequested()) ShowScreenshotResult(MakeScreenshot());
-
-	// switch game mode?
-	if (_switch_mode != SM_NONE) {
-		SwitchMode(_switch_mode);
-		_switch_mode = SM_NONE;
-	}
-
-	IncreaseSpriteLRU();
-	InteractiveRandom();
-
-	if (_scroller_click_timeout > 3) {
-		_scroller_click_timeout -= 3;
-	} else {
-		_scroller_click_timeout = 0;
-	}
-
-	_caret_timer += 3;
-	_timer_counter += 8;
-	CursorTick();
-
-#ifdef ENABLE_NETWORK
-	// Check for UDP stuff
-	if (_network_available) NetworkUDPGameLoop();
-
-	if (_networking && !IsGeneratingWorld()) {
-		// Multiplayer
-		NetworkGameLoop();
-	} else {
-		if (_network_reconnect > 0 && --_network_reconnect == 0) {
-			// This means that we want to reconnect to the last host
-			// We do this here, because it means that the network is really closed
-			NetworkClientConnectGame(_network_last_host, _network_last_port);
-		}
-		// Singleplayer
-		StateGameLoop();
-	}
-#else
-	StateGameLoop();
-#endif /* ENABLE_NETWORK */
-
-	if (!_pause && _display_opt & DO_FULL_ANIMATION) DoPaletteAnimations();
-
-	if (!_pause || _cheats.build_in_pause.value) MoveAllTextEffects();
-
-	InputLoop();
-
-	MusicLoop();
-}
-
-void BeforeSaveGame(void)
-{
-	const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
-
-	if (w != NULL) {
-		_saved_scrollpos_x = WP(w, const vp_d).scrollpos_x;
-		_saved_scrollpos_y = WP(w, const vp_d).scrollpos_y;
-		_saved_scrollpos_zoom = w->viewport->zoom;
-	}
-}
-
-static void ConvertTownOwner(void)
-{
-	TileIndex tile;
-
-	for (tile = 0; tile != MapSize(); tile++) {
-		switch (GetTileType(tile)) {
-			case MP_STREET:
-				if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) & 0x80) {
-					SetCrossingRoadOwner(tile, OWNER_TOWN);
-				}
-				/* FALLTHROUGH */
-
-			case MP_TUNNELBRIDGE:
-				if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
-				break;
-
-			default: break;
-		}
-	}
-}
-
-// before savegame version 4, the name of the company determined if it existed
-static void CheckIsPlayerActive(void)
-{
-	Player *p;
-
-	FOR_ALL_PLAYERS(p) {
-		if (p->name_1 != 0) p->is_active = true;
-	}
-}
-
-// since savegame version 4.1, exclusive transport rights are stored at towns
-static void UpdateExclusiveRights(void)
-{
-	Town *t;
-
-	FOR_ALL_TOWNS(t) {
-		t->exclusivity = (byte)-1;
-	}
-
-	/* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete)
-	 *   could be implemented this way:
-	 * 1.) Go through all stations
-	 *     Build an array town_blocked[ town_id ][ player_id ]
-	 *     that stores if at least one station in that town is blocked for a player
-	 * 2.) Go through that array, if you find a town that is not blocked for
-	 *     one player, but for all others, then give him exclusivity.
-	 */
-}
-
-static const byte convert_currency[] = {
-	 0,  1, 12,  8,  3,
-	10, 14, 19,  4,  5,
-	 9, 11, 13,  6, 17,
-	16, 22, 21,  7, 15,
-	18,  2, 20, };
-
-// since savegame version 4.2 the currencies are arranged differently
-static void UpdateCurrencies(void)
-{
-	_opt.currency = convert_currency[_opt.currency];
-}
-
-/* Up to revision 1413 the invisible tiles at the southern border have not been
- * MP_VOID, even though they should have. This is fixed by this function
- */
-static void UpdateVoidTiles(void)
-{
-	uint i;
-
-	for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX());
-	for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i);
-}
-
-// since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255)
-static void UpdateSignOwner(void)
-{
-	Sign *si;
-
-	FOR_ALL_SIGNS(si) si->owner = OWNER_NONE;
-}
-
-extern void UpdateOldAircraft( void );
-extern void UpdateOilRig( void );
-
-
-static inline RailType UpdateRailType(RailType rt, RailType min)
-{
-	return rt >= min ? (RailType)(rt + 1): rt;
-}
-
-bool AfterLoadGame(void)
-{
-	Window *w;
-	ViewPort *vp;
-	Player *p;
-
-	// in version 2.1 of the savegame, town owner was unified.
-	if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner();
-
-	// from version 4.1 of the savegame, exclusive rights are stored at towns
-	if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights();
-
-	// from version 4.2 of the savegame, currencies are in a different order
-	if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies();
-
-	// from version 6.1 of the savegame, signs have an "owner"
-	if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner();
-
-	/* In old version there seems to be a problem that water is owned by
-	    OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current
-	    (4.3) version, so I just check when versions are older, and then
-	    walk through the whole map.. */
-	if (CheckSavegameVersionOldStyle(4, 3)) {
-		TileIndex tile = TileXY(0, 0);
-		uint w = MapSizeX();
-		uint h = MapSizeY();
-
-		BEGIN_TILE_LOOP(tile_cur, w, h, tile)
-			if (IsTileType(tile_cur, MP_WATER) && GetTileOwner(tile_cur) >= MAX_PLAYERS)
-				SetTileOwner(tile_cur, OWNER_WATER);
-		END_TILE_LOOP(tile_cur, w, h, tile)
-	}
-
-	// convert road side to my format.
-	if (_opt.road_side) _opt.road_side = 1;
-
-	/* Check all NewGRFs are present */
-	if (!IsGoodGRFConfigList()) return false;
-
-	/* Update current year
-	 * must be done before loading sprites as some newgrfs check it */
-	SetDate(_date);
-
-	// Load the sprites
-	GfxLoadSprites();
-	LoadStringWidthTable();
-
-	/* Connect front and rear engines of multiheaded trains and converts
-	 * subtype to the new format */
-	if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew();
-
-	/* Connect front and rear engines of multiheaded trains */
-	ConnectMultiheadedTrains();
-
-	// reinit the landscape variables (landscape might have changed)
-	InitializeLandscapeVariables(true);
-
-	// Update all vehicles
-	AfterLoadVehicles();
-
-	// Update all waypoints
-	if (CheckSavegameVersion(12)) FixOldWaypoints();
-
-	UpdateAllWaypointSigns();
-
-	// in version 2.2 of the savegame, we have new airports
-	if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft();
-
-	UpdateAllStationVirtCoord();
-
-	// Setup town coords
-	AfterLoadTown();
-	UpdateAllSignVirtCoords();
-
-	// make sure there is a town in the game
-	if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, (uint)-1)) {
-		_error_message = STR_NO_TOWN_IN_SCENARIO;
-		return false;
-	}
-
-	// Initialize windows
-	ResetWindowSystem();
-	SetupColorsAndInitialWindow();
-
-	w = FindWindowById(WC_MAIN_WINDOW, 0);
-
-	WP(w,vp_d).scrollpos_x = _saved_scrollpos_x;
-	WP(w,vp_d).scrollpos_y = _saved_scrollpos_y;
-
-	vp = w->viewport;
-	vp->zoom = _saved_scrollpos_zoom;
-	vp->virtual_width = vp->width << vp->zoom;
-	vp->virtual_height = vp->height << vp->zoom;
-
-	// in version 4.1 of the savegame, is_active was introduced to determine
-	// if a player does exist, rather then checking name_1
-	if (CheckSavegameVersionOldStyle(4, 1)) CheckIsPlayerActive();
-
-	// the void tiles on the southern border used to belong to a wrong class (pre 4.3).
-	if (CheckSavegameVersionOldStyle(4, 3)) UpdateVoidTiles();
-
-	// If Load Scenario / New (Scenario) Game is used,
-	//  a player does not exist yet. So create one here.
-	// 1 exeption: network-games. Those can have 0 players
-	//   But this exeption is not true for network_servers!
-	if (!_players[0].is_active && (!_networking || (_networking && _network_server)))
-		DoStartupNewPlayer(false);
-
-	DoZoomInOutWindow(ZOOM_NONE, w); // update button status
-	MarkWholeScreenDirty();
-
-	// In 5.1, Oilrigs have been moved (again)
-	if (CheckSavegameVersionOldStyle(5, 1)) UpdateOilRig();
-
-	/* In version 6.1 we put the town index in the map-array. To do this, we need
-	 *  to use m2 (16bit big), so we need to clean m2, and that is where this is
-	 *  all about ;) */
-	if (CheckSavegameVersionOldStyle(6, 1)) {
-		BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) {
-			switch (GetTileType(tile)) {
-				case MP_HOUSE:
-					_m[tile].m4 = _m[tile].m2;
-					SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index);
-					break;
-
-				case MP_STREET:
-					_m[tile].m4 |= (_m[tile].m2 << 4);
-					if (IsTileOwner(tile, OWNER_TOWN)) {
-						SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index);
-					} else {
-						SetTownIndex(tile, 0);
-					}
-					break;
-
-				default: break;
-			}
-		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
-	}
-
-	/* From version 9.0, we update the max passengers of a town (was sometimes negative
-	 *  before that. */
-	if (CheckSavegameVersion(9)) {
-		Town *t;
-		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
-	}
-
-	/* From version 16.0, we included autorenew on engines, which are now saved, but
-	 *  of course, we do need to initialize them for older savegames. */
-	if (CheckSavegameVersion(16)) {
-		FOR_ALL_PLAYERS(p) {
-			p->engine_renew_list   = NULL;
-			p->engine_renew        = false;
-			p->engine_renew_months = -6;
-			p->engine_renew_money  = 100000;
-		}
-
-		/* When loading a game, _local_player is not yet set to the correct value.
-		 * However, in a dedicated server we are a spectator, so nothing needs to
-		 * happen. In case we are not a dedicated server, the local player always
-		 * becomes player 0, unless we are in the scenario editor where all the
-		 * players are 'invalid'.
-		 */
-		if (!_network_dedicated && IsValidPlayer(0)) {
-			p = GetPlayer(0);
-			p->engine_renew        = _patches.autorenew;
-			p->engine_renew_months = _patches.autorenew_months;
-			p->engine_renew_money  = _patches.autorenew_money;
-		}
-	}
-
-	if (CheckSavegameVersion(42)) {
-		TileIndex map_end = MapSize();
-		TileIndex tile;
-		Vehicle* v;
-
-		for (tile = 0; tile != map_end; tile++) {
-			if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile);
-			if (IsBridgeTile(tile)) {
-				if (HASBIT(_m[tile].m5, 6)) { // middle part
-					Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
-
-					if (HASBIT(_m[tile].m5, 5)) { // transport route under bridge?
-						if (GB(_m[tile].m5, 3, 2) == TRANSPORT_RAIL) {
-							MakeRailNormal(
-								tile,
-								GetTileOwner(tile),
-								axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
-								GetRailType(tile)
-							);
-						} else {
-							TownID town = IsTileOwner(tile, OWNER_TOWN) ? ClosestTownFromTile(tile, (uint)-1)->index : 0;
-
-							MakeRoadNormal(
-								tile,
-								GetTileOwner(tile),
-								axis == AXIS_X ? ROAD_Y : ROAD_X,
-								town
-							);
-						}
-					} else {
-						if (GB(_m[tile].m5, 3, 2) == 0) {
-							MakeClear(tile, CLEAR_GRASS, 3);
-						} else {
-							MakeCanal(tile, GetTileOwner(tile));
-						}
-					}
-					SetBridgeMiddle(tile, axis);
-				} else { // ramp
-					Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
-					uint north_south = GB(_m[tile].m5, 5, 1);
-					DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south));
-					TransportType type = (TransportType)GB(_m[tile].m5, 1, 2);
-
-					_m[tile].m5 = 1 << 7 | type << 2 | dir;
-				}
-			}
-		}
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_Train && v->type != VEH_Road) continue;
-			if (IsBridgeTile(v->tile)) {
-				DiagDirection dir = GetBridgeRampDirection(v->tile);
-
-				if (dir != DirToDiagDir(v->direction)) continue;
-				switch (dir) {
-					default: NOT_REACHED();
-					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0)            continue; break;
-					case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
-					case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
-					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0)            continue; break;
-				}
-			} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
-				v->tile = GetNorthernBridgeEnd(v->tile);
-			} else {
-				continue;
-			}
-			if (v->type == VEH_Train) {
-				v->u.rail.track = 0x40;
-			} else {
-				v->u.road.state = 0xFF;
-			}
-		}
-	}
-
-	/* Elrails got added in rev 24 */
-	if (CheckSavegameVersion(24)) {
-		Vehicle *v;
-		uint i;
-		TileIndex t;
-		RailType min_rail = RAILTYPE_ELECTRIC;
-
-		for (i = 0; i < lengthof(_engines); i++) {
-			Engine *e = GetEngine(i);
-			if (e->type == VEH_Train &&
-					(e->railtype != RAILTYPE_RAIL || RailVehInfo(i)->engclass == 2)) {
-				e->railtype++;
-			}
-		}
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_Train) {
-				RailType rt = GetEngine(v->engine_type)->railtype;
-
-				v->u.rail.railtype = rt;
-				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
-			}
-		}
-
-		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
-		for (t = 0; t < MapSize(); t++) {
-			switch (GetTileType(t)) {
-				case MP_RAILWAY:
-					SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
-					break;
-
-				case MP_STREET:
-					if (IsLevelCrossing(t)) {
-						SetRailTypeCrossing(t, UpdateRailType(GetRailTypeCrossing(t), min_rail));
-					}
-					break;
-
-				case MP_STATION:
-					if (IsRailwayStation(t)) {
-						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
-					}
-					break;
-
-				case MP_TUNNELBRIDGE:
-					if (IsTunnel(t)) {
-						if (GetTunnelTransportType(t) == TRANSPORT_RAIL) {
-							SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
-						}
-					} else {
-						if (GetBridgeTransportType(t) == TRANSPORT_RAIL) {
-							SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
-						}
-					}
-					break;
-
-				default:
-					break;
-			}
-		}
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v);
-		}
-
-	}
-
-	/* In version 16.1 of the savegame a player can decide if trains, which get
-	 * replaced, shall keep their old length. In all prior versions, just default
-	 * to false */
-	if (CheckSavegameVersionOldStyle(16, 1)) {
-		FOR_ALL_PLAYERS(p) p->renew_keep_length = false;
-	}
-
-	/* In version 17, ground type is moved from m2 to m4 for depots and
-	 * waypoints to make way for storing the index in m2. The custom graphics
-	 * id which was stored in m4 is now saved as a grf/id reference in the
-	 * waypoint struct. */
-	if (CheckSavegameVersion(17)) {
-		Waypoint *wp;
-
-		FOR_ALL_WAYPOINTS(wp) {
-			if (wp->deleted == 0) {
-				const StationSpec *statspec = NULL;
-
-				if (HASBIT(_m[wp->xy].m3, 4))
-					statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1);
-
-				if (statspec != NULL) {
-					wp->stat_id = _m[wp->xy].m4 + 1;
-					wp->grfid = statspec->grfid;
-					wp->localidx = statspec->localidx;
-				} else {
-					// No custom graphics set, so set to default.
-					wp->stat_id = 0;
-					wp->grfid = 0;
-					wp->localidx = 0;
-				}
-
-				// Move ground type bits from m2 to m4.
-				_m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4);
-				// Store waypoint index in the tile.
-				_m[wp->xy].m2 = wp->index;
-			}
-		}
-	} else {
-		/* As of version 17, we recalculate the custom graphic ID of waypoints
-		 * from the GRF ID / station index. */
-		AfterLoadWaypoints();
-	}
-
-	/* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making
-	 *  room for PBS. Now in version 21 move it back :P. */
-	if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) {
-		BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) {
-			if (IsTileType(tile, MP_RAILWAY)) {
-				if (HasSignals(tile)) {
-					// convert PBS signals to combo-signals
-					if (HASBIT(_m[tile].m4, 2)) SetSignalType(tile, SIGTYPE_COMBO);
-
-					// move the signal variant back
-					SetSignalVariant(tile, HASBIT(_m[tile].m4, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC);
-					CLRBIT(_m[tile].m4, 3);
-				}
-
-				// Clear PBS reservation on track
-				if (!IsTileDepotType(tile, TRANSPORT_RAIL)) {
-					SB(_m[tile].m4, 4, 4, 0);
-				} else {
-					CLRBIT(_m[tile].m3, 6);
-				}
-			}
-
-			// Clear PBS reservation on crossing
-			if (IsTileType(tile, MP_STREET) && IsLevelCrossing(tile))
-				CLRBIT(_m[tile].m5, 0);
-
-			// Clear PBS reservation on station
-			if (IsTileType(tile, MP_STATION))
-				CLRBIT(_m[tile].m3, 6);
-		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
-	}
-
-	if (CheckSavegameVersion(22))  UpdatePatches();
-
-	if (CheckSavegameVersion(25)) {
-		Vehicle *v;
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_Road) {
-				v->vehstatus &= ~0x40;
-				v->u.road.slot = NULL;
-				v->u.road.slot_age = 0;
-			}
-		}
-	}
-
-	if (CheckSavegameVersion(26)) {
-		Station *st;
-		FOR_ALL_STATIONS(st) {
-			st->last_vehicle_type = VEH_Invalid;
-		}
-	}
-
-	YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
-
-	if (CheckSavegameVersion(34)) FOR_ALL_PLAYERS(p) ResetPlayerLivery(p);
-
-	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
-
-	if (!CheckSavegameVersion(27)) AfterLoadStations();
-
-	{
-		/* Set up the engine count for all players */
-		Player *players[MAX_PLAYERS];
-		int i;
-		const Vehicle *v;
-
-		for (i = 0; i < MAX_PLAYERS; i++) players[i] = GetPlayer(i);
-
-		FOR_ALL_VEHICLES(v) {
-			if (!IsEngineCountable(v)) continue;
-			players[v->owner]->num_engines[v->engine_type]++;
-		}
-	}
-
-	/* Time starts at 0 instead of 1920.
-	 * Account for this in older games by adding an offset */
-	if (CheckSavegameVersion(31)) {
-		Station *st;
-		Waypoint *wp;
-		Engine *e;
-		Player *player;
-		Industry *i;
-		Vehicle *v;
-
-		_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
-		_cur_year += ORIGINAL_BASE_YEAR;
-
-		FOR_ALL_STATIONS(st)    st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
-		FOR_ALL_WAYPOINTS(wp)   wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
-		FOR_ALL_ENGINES(e)      e->intro_date  += DAYS_TILL_ORIGINAL_BASE_YEAR;
-		FOR_ALL_PLAYERS(player) player->inaugurated_year += ORIGINAL_BASE_YEAR;
-		FOR_ALL_INDUSTRIES(i)   i->last_prod_year        += ORIGINAL_BASE_YEAR;
-
-		FOR_ALL_VEHICLES(v) {
-			v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR;
-			v->build_year += ORIGINAL_BASE_YEAR;
-		}
-	}
-
-	/* From 32 on we save the industry who made the farmland.
-	 *  To give this prettyness to old savegames, we remove all farmfields and
-	 *  plant new ones. */
-	if (CheckSavegameVersion(32)) {
-		Industry *i;
-
-		BEGIN_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) {
-			if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS)) {
-				MakeClear(tile_cur, CLEAR_GRASS, 3);
-			}
-		} END_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0)
-
-		FOR_ALL_INDUSTRIES(i) {
-			uint j;
-
-			if (i->type == IT_FARM || i->type == IT_FARM_2) {
-				for (j = 0; j != 50; j++) PlantRandomFarmField(i);
-			}
-		}
-	}
-
-	/* Setting no refit flags to all orders in savegames from before refit in orders were added */
-	if (CheckSavegameVersion(36)) {
-		Order *order;
-		Vehicle *v;
-
-		FOR_ALL_ORDERS(order) {
-			order->refit_cargo   = CT_NO_REFIT;
-			order->refit_subtype = CT_NO_REFIT;
-		}
-
-		FOR_ALL_VEHICLES(v) {
-			v->current_order.refit_cargo   = CT_NO_REFIT;
-			v->current_order.refit_subtype = CT_NO_REFIT;
-		}
-	}
-
-	if (CheckSavegameVersion(37)) {
-		ConvertNameArray();
-	}
-
-	/* from version 38 we have optional elrails, since we cannot know the
-	 * preference of a user, let elrails enabled; it can be disabled manually */
-	if (CheckSavegameVersion(38)) {
-		_patches.disable_elrails = false; // enable elrails
-		/* do the same as when elrails were enabled/disabled manually just now */
-		SettingsDisableElrail(_patches.disable_elrails);
-	}
-
-	if (CheckSavegameVersion(43)) {
-		BEGIN_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) {
-			if (IsTileType(tile_cur, MP_INDUSTRY)) {
-				switch (GetIndustryGfx(tile_cur)) {
-					case GFX_POWERPLANT_SPARKS:
-						SetIndustryAnimationState(tile_cur, GB(_m[tile_cur].m1, 2, 5));
-						break;
-
-					case GFX_OILWELL_ANIMATED_1:
-					case GFX_OILWELL_ANIMATED_2:
-					case GFX_OILWELL_ANIMATED_3:
-						SetIndustryAnimationState(tile_cur, GB(_m[tile_cur].m1, 0, 2));
-						break;
-
-					case GFX_COAL_MINE_TOWER_ANIMATED:
-					case GFX_COPPER_MINE_TOWER_ANIMATED:
-					case GFX_GOLD_MINE_TOWER_ANIMATED:
-						 SetIndustryAnimationState(tile_cur, _m[tile_cur].m1);
-						 break;
-
-					default: /* No animation states to change */
-						break;
-				}
-			}
-		} END_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0)
-	}
-
-	return true;
-}
-
-/** Reload all NewGRF files during a running game. This is a cut-down
- * version of AfterLoadGame().
- * XXX - We need to reset the vehicle position hash because with a non-empty
- * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
- * to recalculate vehicle data as some NewGRF vehicle sets could have been
- * removed or added and changed statistics */
-void ReloadNewGRFData(void)
-{
-	/* reload grf data */
-	GfxLoadSprites();
-	LoadStringWidthTable();
-	/* reload vehicles */
-	ResetVehiclePosHash();
-	AfterLoadVehicles();
-	/* update station and waypoint graphics */
-	AfterLoadWaypoints();
-	AfterLoadStations();
-	/* redraw the whole screen */
-	MarkWholeScreenDirty();
-}
new file mode 100644
--- /dev/null
+++ b/src/openttd.cpp
@@ -0,0 +1,1704 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "string.h"
+#include "table/strings.h"
+#include "debug.h"
+#include "driver.h"
+#include "saveload.h"
+#include "strings.h"
+#include "map.h"
+#include "tile.h"
+#include "void_map.h"
+
+#define VARDEF
+#include "openttd.h"
+#include "bridge_map.h"
+#include "functions.h"
+#include "mixer.h"
+#include "spritecache.h"
+#include "strings.h"
+#include "gfx.h"
+#include "gfxinit.h"
+#include "gui.h"
+#include "station.h"
+#include "station_map.h"
+#include "town_map.h"
+#include "tunnel_map.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "window.h"
+#include "player.h"
+#include "command.h"
+#include "town.h"
+#include "industry.h"
+#include "news.h"
+#include "engine.h"
+#include "sound.h"
+#include "economy.h"
+#include "fileio.h"
+#include "hal.h"
+#include "airport.h"
+#include "console.h"
+#include "screenshot.h"
+#include "network/network.h"
+#include "signs.h"
+#include "depot.h"
+#include "waypoint.h"
+#include "ai/ai.h"
+#include "train.h"
+#include "yapf/yapf.h"
+#include "settings.h"
+#include "genworld.h"
+#include "date.h"
+#include "clear_map.h"
+#include "fontcache.h"
+#include "newgrf_config.h"
+
+#include "bridge_map.h"
+#include "clear_map.h"
+#include "rail_map.h"
+#include "road_map.h"
+#include "water_map.h"
+#include "industry_map.h"
+
+#include <stdarg.h>
+
+void CallLandscapeTick(void);
+void IncreaseDate(void);
+void DoPaletteAnimations(void);
+void MusicLoop(void);
+void ResetMusic(void);
+void InitializeStations(void);
+void DeleteAllPlayerStations(void);
+
+extern void SetDifficultyLevel(int mode, GameOptions *gm_opt);
+extern void DoStartupNewPlayer(bool is_ai);
+extern void ShowOSErrorBox(const char *buf);
+
+/* TODO: usrerror() for errors which are not of an internal nature but
+ * caused by the user, i.e. missing files or fatal configuration errors.
+ * Post-0.4.0 since Celestar doesn't want this in SVN before. --pasky */
+
+void CDECL error(const char *s, ...)
+{
+	va_list va;
+	char buf[512];
+
+	va_start(va, s);
+	vsnprintf(buf, lengthof(buf), s, va);
+	va_end(va);
+
+	ShowOSErrorBox(buf);
+	if (_video_driver != NULL) _video_driver->stop();
+
+	assert(0);
+	exit(1);
+}
+
+void CDECL ShowInfoF(const char *str, ...)
+{
+	va_list va;
+	char buf[1024];
+	va_start(va, str);
+	vsnprintf(buf, lengthof(buf), str, va);
+	va_end(va);
+	ShowInfo(buf);
+}
+
+
+void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
+{
+	FILE *in;
+	byte *mem;
+	size_t len;
+
+	in = fopen(filename, "rb");
+	if (in == NULL) return NULL;
+
+	fseek(in, 0, SEEK_END);
+	len = ftell(in);
+	fseek(in, 0, SEEK_SET);
+	if (len > maxsize || (mem = malloc(len + 1)) == NULL) {
+		fclose(in);
+		return NULL;
+	}
+	mem[len] = 0;
+	if (fread(mem, len, 1, in) != 1) {
+		fclose(in);
+		free(mem);
+		return NULL;
+	}
+	fclose(in);
+
+	*lenp = len;
+	return mem;
+}
+
+static void showhelp(void)
+{
+	extern const char _openttd_revision[];
+	char buf[4096], *p;
+
+	p = buf;
+
+	p += snprintf(p, lengthof(buf), "OpenTTD %s\n", _openttd_revision);
+	p = strecpy(p,
+		"\n"
+		"\n"
+		"Command line options:\n"
+		"  -v drv              = Set video driver (see below)\n"
+		"  -s drv              = Set sound driver (see below)\n"
+		"  -m drv              = Set music driver (see below)\n"
+		"  -r res              = Set resolution (for instance 800x600)\n"
+		"  -h                  = Display this help text\n"
+		"  -t year             = Set starting year\n"
+		"  -d [[fac=]lvl[,...]]= Debug mode\n"
+		"  -e                  = Start Editor\n"
+		"  -g [savegame]       = Start new/save game immediately\n"
+		"  -G seed             = Set random seed\n"
+		"  -n [ip:port#player] = Start networkgame\n"
+		"  -D [ip][:port]      = Start dedicated server\n"
+#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
+		"  -f                  = Fork into the background (dedicated only)\n"
+#endif
+		"  -i                  = Force to use the DOS palette\n"
+		"                          (use this if you see a lot of pink)\n"
+		"  -c config_file      = Use 'config_file' instead of 'openttd.cfg'\n"
+		"  -x                  = Do not automatically save to config file on exit\n",
+		lastof(buf)
+	);
+
+	p = GetDriverList(p, lastof(buf));
+
+	ShowInfo(buf);
+}
+
+
+typedef struct {
+	char *opt;
+	int numleft;
+	char **argv;
+	const char *options;
+	char *cont;
+} MyGetOptData;
+
+static void MyGetOptInit(MyGetOptData *md, int argc, char **argv, const char *options)
+{
+	md->cont = NULL;
+	md->numleft = argc;
+	md->argv = argv;
+	md->options = options;
+}
+
+static int MyGetOpt(MyGetOptData *md)
+{
+	char *s,*r,*t;
+
+	s = md->cont;
+	if (s != NULL)
+		goto md_continue_here;
+
+	for (;;) {
+		if (--md->numleft < 0) return -1;
+
+		s = *md->argv++;
+		if (*s == '-') {
+md_continue_here:;
+			s++;
+			if (*s != 0) {
+				// Found argument, try to locate it in options.
+				if (*s == ':' || (r = strchr(md->options, *s)) == NULL) {
+					// ERROR!
+					return -2;
+				}
+				if (r[1] == ':') {
+					// Item wants an argument. Check if the argument follows, or if it comes as a separate arg.
+					if (!*(t = s + 1)) {
+						// It comes as a separate arg. Check if out of args?
+						if (--md->numleft < 0 || *(t = *md->argv) == '-') {
+							// Check if item is optional?
+							if (r[2] != ':')
+								return -2;
+							md->numleft++;
+							t = NULL;
+						} else {
+							md->argv++;
+						}
+					}
+					md->opt = t;
+					md->cont = NULL;
+					return *s;
+				}
+				md->opt = NULL;
+				md->cont = s;
+				return *s;
+			}
+		} else {
+			// This is currently not supported.
+			return -2;
+		}
+	}
+}
+
+
+static void ParseResolution(int res[2], const char *s)
+{
+	char *t = strchr(s, 'x');
+	if (t == NULL) {
+		ShowInfoF("Invalid resolution '%s'", s);
+		return;
+	}
+
+	res[0] = clamp(strtoul(s, NULL, 0), 64, MAX_SCREEN_WIDTH);
+	res[1] = clamp(strtoul(t + 1, NULL, 0), 64, MAX_SCREEN_HEIGHT);
+}
+
+static void InitializeDynamicVariables(void)
+{
+	/* Dynamic stuff needs to be initialized somewhere... */
+	_town_sort     = NULL;
+	_industry_sort = NULL;
+}
+
+static void UnInitializeDynamicVariables(void)
+{
+	/* Dynamic stuff needs to be free'd somewhere... */
+	CleanPool(&_Town_pool);
+	CleanPool(&_Industry_pool);
+	CleanPool(&_Station_pool);
+	CleanPool(&_Vehicle_pool);
+	CleanPool(&_Sign_pool);
+	CleanPool(&_Order_pool);
+
+	free((void*)_town_sort);
+	free((void*)_industry_sort);
+}
+
+static void UnInitializeGame(void)
+{
+	UnInitWindowSystem();
+
+	free(_config_file);
+}
+
+static void LoadIntroGame(void)
+{
+	char filename[256];
+
+	_game_mode = GM_MENU;
+	CLRBITS(_display_opt, DO_TRANS_BUILDINGS); // don't make buildings transparent in intro
+	_opt_ptr = &_opt_newgame;
+	ResetGRFConfig(false);
+
+	// Setup main window
+	ResetWindowSystem();
+	SetupColorsAndInitialWindow();
+
+	// Generate a world.
+	snprintf(filename, lengthof(filename), "%sopntitle.dat",  _paths.data_dir);
+#if defined SECOND_DATA_DIR
+	if (SaveOrLoad(filename, SL_LOAD) != SL_OK) {
+		snprintf(filename, lengthof(filename), "%sopntitle.dat",  _paths.second_data_dir);
+	}
+#endif
+	if (SaveOrLoad(filename, SL_LOAD) != SL_OK) {
+		GenerateWorld(GW_EMPTY, 64, 64); // if failed loading, make empty world.
+		WaitTillGeneratedWorld();
+	}
+
+	_pause = 0;
+	SetLocalPlayer(0);
+	/* Make sure you can't scroll in the menu */
+	_scrolling_viewport = 0;
+	_cursor.fix_at = false;
+	MarkWholeScreenDirty();
+
+	// Play main theme
+	if (_music_driver->is_song_playing()) ResetMusic();
+}
+
+#if defined(UNIX) && !defined(__MORPHOS__)
+extern void DedicatedFork(void);
+#endif
+
+int ttd_main(int argc, char *argv[])
+{
+	MyGetOptData mgo;
+	int i;
+	const char *optformat;
+	char musicdriver[16], sounddriver[16], videodriver[16];
+	int resolution[2] = {0,0};
+	Year startyear = INVALID_YEAR;
+	uint generation_seed = GENERATE_NEW_SEED;
+	bool dedicated = false;
+	bool network   = false;
+	bool save_config = true;
+	char *network_conn = NULL;
+	char *dedicated_host = NULL;
+	uint16 dedicated_port = 0;
+
+	musicdriver[0] = sounddriver[0] = videodriver[0] = 0;
+
+	_game_mode = GM_MENU;
+	_switch_mode = SM_MENU;
+	_switch_mode_errorstr = INVALID_STRING_ID;
+	_dedicated_forks = false;
+	_config_file = NULL;
+
+	// The last param of the following function means this:
+	//   a letter means: it accepts that param (e.g.: -h)
+	//   a ':' behind it means: it need a param (e.g.: -m<driver>)
+	//   a '::' behind it means: it can optional have a param (e.g.: -d<debug>)
+	optformat = "m:s:v:hD::n::eit:d::r:g::G:c:x"
+#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
+		"f"
+#endif
+	;
+
+	MyGetOptInit(&mgo, argc-1, argv+1, optformat);
+	while ((i = MyGetOpt(&mgo)) != -1) {
+		switch (i) {
+		case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break;
+		case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break;
+		case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break;
+		case 'D':
+			strcpy(musicdriver, "null");
+			strcpy(sounddriver, "null");
+			strcpy(videodriver, "dedicated");
+			dedicated = true;
+			if (mgo.opt != NULL)
+			{
+				/* Use the existing method for parsing (openttd -n).
+				 * However, we do ignore the #player part. */
+				const char *temp = NULL;
+				const char *port = NULL;
+				ParseConnectionString(&temp, &port, mgo.opt);
+				if (*mgo.opt != '\0') dedicated_host = mgo.opt;
+				if (port != NULL) dedicated_port = atoi(port);
+			}
+			break;
+		case 'f': _dedicated_forks = true; break;
+		case 'n':
+			network = true;
+			network_conn = mgo.opt; // optional IP parameter, NULL if unset
+			break;
+		case 'r': ParseResolution(resolution, mgo.opt); break;
+		case 't': startyear = atoi(mgo.opt); break;
+		case 'd': {
+#if defined(WIN32)
+				CreateConsole();
+#endif
+				if (mgo.opt != NULL) SetDebugString(mgo.opt);
+			} break;
+		case 'e': _switch_mode = SM_EDITOR; break;
+		case 'i': _use_dos_palette = true; break;
+		case 'g':
+			if (mgo.opt != NULL) {
+				strcpy(_file_to_saveload.name, mgo.opt);
+				_switch_mode = SM_LOAD;
+			} else {
+				_switch_mode = SM_NEWGAME;
+			}
+			break;
+		case 'G': generation_seed = atoi(mgo.opt); break;
+		case 'c': _config_file = strdup(mgo.opt); break;
+		case 'x': save_config = false; break;
+		case -2:
+		case 'h':
+			showhelp();
+			return 0;
+		}
+	}
+
+	DeterminePaths();
+	CheckExternalFiles();
+
+#if defined(UNIX) && !defined(__MORPHOS__)
+	// We must fork here, or we'll end up without some resources we need (like sockets)
+	if (_dedicated_forks)
+		DedicatedFork();
+#endif
+
+	LoadFromConfig();
+	CheckConfig();
+	LoadFromHighScore();
+
+	// override config?
+	if (musicdriver[0]) ttd_strlcpy(_ini_musicdriver, musicdriver, sizeof(_ini_musicdriver));
+	if (sounddriver[0]) ttd_strlcpy(_ini_sounddriver, sounddriver, sizeof(_ini_sounddriver));
+	if (videodriver[0]) ttd_strlcpy(_ini_videodriver, videodriver, sizeof(_ini_videodriver));
+	if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; }
+	if (startyear != INVALID_YEAR) _patches_newgame.starting_year = startyear;
+	if (generation_seed != GENERATE_NEW_SEED) _patches_newgame.generation_seed = generation_seed;
+
+	if (dedicated_host) snprintf(_network_server_bind_ip_host, NETWORK_HOSTNAME_LENGTH, "%s", dedicated_host);
+	if (dedicated_port) _network_server_port = dedicated_port;
+	if (_dedicated_forks && !dedicated) _dedicated_forks = false;
+
+	// enumerate language files
+	InitializeLanguagePacks();
+
+	// initialize screenshot formats
+	InitializeScreenshotFormats();
+
+	// initialize airport state machines
+	InitializeAirports();
+
+	/* initialize all variables that are allocated dynamically */
+	InitializeDynamicVariables();
+
+	/* start the AI */
+	AI_Initialize();
+
+	// Sample catalogue
+	DEBUG(misc, 1, "Loading sound effects...");
+	MxInitialize(11025);
+	SoundInitialize("sample.cat");
+
+	/* Initialize FreeType */
+	InitFreeType();
+
+	// This must be done early, since functions use the InvalidateWindow* calls
+	InitWindowSystem();
+
+	/* Initialize game palette */
+	GfxInitPalettes();
+
+	DEBUG(driver, 1, "Loading drivers...");
+	LoadDriver(SOUND_DRIVER, _ini_sounddriver);
+	LoadDriver(MUSIC_DRIVER, _ini_musicdriver);
+	LoadDriver(VIDEO_DRIVER, _ini_videodriver); // load video last, to prevent an empty window while sound and music loads
+	_savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
+
+	// restore saved music volume
+	_music_driver->set_volume(msf.music_vol);
+
+	NetworkStartUp(); // initialize network-core
+
+	ScanNewGRFFiles();
+
+	_opt_ptr = &_opt_newgame;
+	ResetGRFConfig(false);
+
+	/* XXX - ugly hack, if diff_level is 9, it means we got no setting from the config file */
+	if (_opt_newgame.diff_level == 9) SetDifficultyLevel(0, &_opt_newgame);
+
+	/* Make sure _patches is filled with _patches_newgame if we switch to a game directly */
+	if (_switch_mode != SM_NONE) {
+		_opt = _opt_newgame;
+		UpdatePatches();
+	}
+
+	// initialize the ingame console
+	IConsoleInit();
+	_cursor.in_window = true;
+	InitializeGUI();
+	IConsoleCmdExec("exec scripts/autoexec.scr 0");
+
+	GenerateWorld(GW_EMPTY, 64, 64); // Make the viewport initialization happy
+	WaitTillGeneratedWorld();
+
+#ifdef ENABLE_NETWORK
+	if (network && _network_available) {
+		if (network_conn != NULL) {
+			const char *port = NULL;
+			const char *player = NULL;
+			uint16 rport;
+
+			rport = NETWORK_DEFAULT_PORT;
+			_network_playas = PLAYER_NEW_COMPANY;
+
+			ParseConnectionString(&player, &port, network_conn);
+
+			if (player != NULL) {
+				_network_playas = atoi(player);
+
+				if (_network_playas != PLAYER_SPECTATOR) {
+					_network_playas--;
+					if (!IsValidPlayer(_network_playas)) return false;
+				}
+			}
+			if (port != NULL) rport = atoi(port);
+
+			LoadIntroGame();
+			_switch_mode = SM_NONE;
+			NetworkClientConnectGame(network_conn, rport);
+		}
+	}
+#endif /* ENABLE_NETWORK */
+
+	_video_driver->main_loop();
+
+	WaitTillSaved();
+	IConsoleFree();
+
+	if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections
+
+	_video_driver->stop();
+	_music_driver->stop();
+	_sound_driver->stop();
+
+	/* only save config if we have to */
+	if (save_config) {
+		SaveToConfig();
+		SaveToHighScore();
+	}
+
+	// uninitialize airport state machines
+	UnInitializeAirports();
+
+	/* uninitialize variables that are allocated dynamic */
+	UnInitializeDynamicVariables();
+
+	/* stop the AI */
+	AI_Uninitialize();
+
+	/* Close all and any open filehandles */
+	FioCloseAll();
+	UnInitializeGame();
+
+	return 0;
+}
+
+void HandleExitGameRequest(void)
+{
+	if (_game_mode == GM_MENU) { // do not ask to quit on the main screen
+		_exit_game = true;
+	} else if (_patches.autosave_on_exit) {
+		DoExitSave();
+		_exit_game = true;
+	} else {
+		AskExitGame();
+	}
+}
+
+
+/** Mutex so that only one thread can communicate with the main program
+ * at any given time */
+static ThreadMsg _message = MSG_OTTD_NO_MESSAGE;
+
+static inline void OTTD_ReleaseMutex(void) {_message = MSG_OTTD_NO_MESSAGE;}
+static inline ThreadMsg OTTD_PollThreadEvent(void) {return _message;}
+
+/** Called by running thread to execute some action in the main game.
+ * It will stall as long as the mutex is not freed (handled) by the game */
+void OTTD_SendThreadMessage(ThreadMsg msg)
+{
+	if (_exit_game) return;
+	while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10);
+
+	_message = msg;
+}
+
+
+/** Handle the user-messages sent to us
+ * @param message message sent
+ */
+static void ProcessSentMessage(ThreadMsg message)
+{
+	switch (message) {
+		case MSG_OTTD_SAVETHREAD_DONE:  SaveFileDone(); break;
+		case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break;
+		default: NOT_REACHED();
+	}
+
+	OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled
+}
+
+static void ShowScreenshotResult(bool b)
+{
+	if (b) {
+		SetDParamStr(0, _screenshot_name);
+		ShowErrorMessage(INVALID_STRING_ID, STR_031B_SCREENSHOT_SUCCESSFULLY, 0, 0);
+	} else {
+		ShowErrorMessage(INVALID_STRING_ID, STR_031C_SCREENSHOT_FAILED, 0, 0);
+	}
+
+}
+
+static void MakeNewGameDone(void)
+{
+	/* In a dedicated server, the server does not play */
+	if (_network_dedicated) {
+		SetLocalPlayer(PLAYER_SPECTATOR);
+		return;
+	}
+
+	/* Create a single player */
+	DoStartupNewPlayer(false);
+
+	SetLocalPlayer(0);
+	_current_player = _local_player;
+	DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
+
+	SettingsDisableElrail(_patches.disable_elrails);
+
+	MarkWholeScreenDirty();
+}
+
+static void MakeNewGame(bool from_heightmap)
+{
+	_game_mode = GM_NORMAL;
+
+	ResetGRFConfig(true);
+
+	GenerateWorldSetCallback(&MakeNewGameDone);
+	GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _patches.map_x, 1 << _patches.map_y);
+}
+
+static void MakeNewEditorWorldDone(void)
+{
+	SetLocalPlayer(OWNER_NONE);
+
+	MarkWholeScreenDirty();
+}
+
+static void MakeNewEditorWorld(void)
+{
+	_game_mode = GM_EDITOR;
+
+	ResetGRFConfig(true);
+
+	GenerateWorldSetCallback(&MakeNewEditorWorldDone);
+	GenerateWorld(GW_EMPTY, 1 << _patches.map_x, 1 << _patches.map_y);
+}
+
+void StartupPlayers(void);
+void StartupDisasters(void);
+extern void StartupEconomy(void);
+
+/**
+ * Start Scenario starts a new game based on a scenario.
+ * Eg 'New Game' --> select a preset scenario
+ * This starts a scenario based on your current difficulty settings
+ */
+static void StartScenario(void)
+{
+	_game_mode = GM_NORMAL;
+
+	// invalid type
+	if (_file_to_saveload.mode == SL_INVALID) {
+		DEBUG(sl, 0, "Savegame is obsolete or invalid format: '%s'", _file_to_saveload.name);
+		ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
+		_game_mode = GM_MENU;
+		return;
+	}
+
+	// Reinitialize windows
+	ResetWindowSystem();
+
+	SetupColorsAndInitialWindow();
+
+	ResetGRFConfig(true);
+
+	// Load game
+	if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode) != SL_OK) {
+		LoadIntroGame();
+		ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
+	}
+
+	_opt_ptr = &_opt;
+	_opt_ptr->diff = _opt_newgame.diff;
+	_opt.diff_level = _opt_newgame.diff_level;
+
+	// Inititalize data
+	StartupEconomy();
+	StartupPlayers();
+	StartupEngines();
+	StartupDisasters();
+
+	SetLocalPlayer(0);
+	_current_player = _local_player;
+	DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
+
+	MarkWholeScreenDirty();
+}
+
+bool SafeSaveOrLoad(const char *filename, int mode, int newgm)
+{
+	byte ogm = _game_mode;
+
+	_game_mode = newgm;
+	switch (SaveOrLoad(filename, mode)) {
+		case SL_OK: return true;
+
+		case SL_REINIT:
+			switch (ogm) {
+				case GM_MENU:   LoadIntroGame();      break;
+				case GM_EDITOR: MakeNewEditorWorld(); break;
+				default:        MakeNewGame(false);   break;
+			}
+			return false;
+
+		default:
+			_game_mode = ogm;
+			return false;
+	}
+}
+
+void SwitchMode(int new_mode)
+{
+#ifdef ENABLE_NETWORK
+	// If we are saving something, the network stays in his current state
+	if (new_mode != SM_SAVE) {
+		// If the network is active, make it not-active
+		if (_networking) {
+			if (_network_server && (new_mode == SM_LOAD || new_mode == SM_NEWGAME)) {
+				NetworkReboot();
+				NetworkUDPStop();
+			} else {
+				NetworkDisconnect();
+				NetworkUDPStop();
+			}
+		}
+
+		// If we are a server, we restart the server
+		if (_is_network_server) {
+			// But not if we are going to the menu
+			if (new_mode != SM_MENU) {
+				NetworkServerStart();
+			} else {
+				// This client no longer wants to be a network-server
+				_is_network_server = false;
+			}
+		}
+	}
+#endif /* ENABLE_NETWORK */
+
+	switch (new_mode) {
+	case SM_EDITOR: /* Switch to scenario editor */
+		MakeNewEditorWorld();
+		break;
+
+	case SM_NEWGAME: /* New Game --> 'Random game' */
+#ifdef ENABLE_NETWORK
+		if (_network_server) {
+			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map");
+		}
+#endif /* ENABLE_NETWORK */
+		MakeNewGame(false);
+		break;
+
+	case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */
+#ifdef ENABLE_NETWORK
+		if (_network_server) {
+			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title);
+		}
+#endif /* ENABLE_NETWORK */
+		StartScenario();
+		break;
+
+	case SM_LOAD: { /* Load game, Play Scenario */
+		_opt_ptr = &_opt;
+		ResetGRFConfig(true);
+
+		if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
+			LoadIntroGame();
+			ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
+		} else {
+			/* Update the local player for a loaded game. It is either always
+			 * player #1 (eg 0) or in the case of a dedicated server a spectator */
+			SetLocalPlayer(_network_dedicated ? PLAYER_SPECTATOR : 0);
+			DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // decrease pause counter (was increased from opening load dialog)
+#ifdef ENABLE_NETWORK
+			if (_network_server) {
+				snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title);
+			}
+#endif /* ENABLE_NETWORK */
+		}
+		break;
+	}
+
+	case SM_START_HEIGHTMAP: /* Load a heightmap and start a new game from it */
+#ifdef ENABLE_NETWORK
+		if (_network_server) {
+			snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title);
+		}
+#endif /* ENABLE_NETWORK */
+		MakeNewGame(true);
+		break;
+
+	case SM_LOAD_HEIGHTMAP: /* Load heightmap from scenario editor */
+		SetLocalPlayer(OWNER_NONE);
+
+		GenerateWorld(GW_HEIGHTMAP, 1 << _patches.map_x, 1 << _patches.map_y);
+		MarkWholeScreenDirty();
+		break;
+
+	case SM_LOAD_SCENARIO: { /* Load scenario from scenario editor */
+		if (SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR)) {
+			Player *p;
+
+			_opt_ptr = &_opt;
+
+			SetLocalPlayer(OWNER_NONE);
+			_generating_world = true;
+			/* Delete all players */
+			FOR_ALL_PLAYERS(p) {
+				if (p->is_active) {
+					ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
+					p->is_active = false;
+				}
+			}
+			_generating_world = false;
+			_patches_newgame.starting_year = _cur_year;
+			// delete all stations owned by a player
+			DeleteAllPlayerStations();
+		} else {
+			ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
+		}
+		break;
+	}
+
+	case SM_MENU: /* Switch to game intro menu */
+		LoadIntroGame();
+		break;
+
+	case SM_SAVE: /* Save game */
+		if (SaveOrLoad(_file_to_saveload.name, SL_SAVE) != SL_OK) {
+			ShowErrorMessage(INVALID_STRING_ID, STR_4007_GAME_SAVE_FAILED, 0, 0);
+		} else {
+			DeleteWindowById(WC_SAVELOAD, 0);
+		}
+		break;
+
+	case SM_GENRANDLAND: /* Generate random land within scenario editor */
+		SetLocalPlayer(OWNER_NONE);
+		GenerateWorld(GW_RANDOM, 1 << _patches.map_x, 1 << _patches.map_y);
+		// XXX: set date
+		MarkWholeScreenDirty();
+		break;
+	}
+
+	if (_switch_mode_errorstr != INVALID_STRING_ID) {
+		ShowErrorMessage(INVALID_STRING_ID, _switch_mode_errorstr, 0, 0);
+	}
+}
+
+
+// State controlling game loop.
+// The state must not be changed from anywhere
+// but here.
+// That check is enforced in DoCommand.
+void StateGameLoop(void)
+{
+	// dont execute the state loop during pause
+	if (_pause) return;
+	if (IsGeneratingWorld()) return;
+
+	if (_game_mode == GM_EDITOR) {
+		RunTileLoop();
+		CallVehicleTicks();
+		CallLandscapeTick();
+		CallWindowTickEvent();
+		NewsLoop();
+	} else {
+		// All these actions has to be done from OWNER_NONE
+		//  for multiplayer compatibility
+		PlayerID p = _current_player;
+		_current_player = OWNER_NONE;
+
+		AnimateAnimatedTiles();
+		IncreaseDate();
+		RunTileLoop();
+		CallVehicleTicks();
+		CallLandscapeTick();
+
+		AI_RunGameLoop();
+
+		CallWindowTickEvent();
+		NewsLoop();
+		_current_player = p;
+	}
+}
+
+static void DoAutosave(void)
+{
+	char buf[200];
+
+	if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) {
+		const Player *p = GetPlayer(_local_player);
+		char* s = buf;
+
+		s += snprintf(buf, lengthof(buf), "%s%s", _paths.autosave_dir, PATHSEP);
+
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		SetDParam(2, _date);
+		s = GetString(s, STR_4004, lastof(buf));
+		strecpy(s, ".sav", lastof(buf));
+	} else { /* generate a savegame name and number according to _patches.max_num_autosaves */
+		snprintf(buf, lengthof(buf), "%s%sautosave%d.sav", _paths.autosave_dir, PATHSEP, _autosave_ctr);
+
+		_autosave_ctr++;
+		if (_autosave_ctr >= _patches.max_num_autosaves) {
+			// we reached the limit for numbers of autosaves. We will start over
+			_autosave_ctr = 0;
+		}
+	}
+
+	DEBUG(sl, 2, "Autosaving to '%s'", buf);
+	if (SaveOrLoad(buf, SL_SAVE) != SL_OK)
+		ShowErrorMessage(INVALID_STRING_ID, STR_AUTOSAVE_FAILED, 0, 0);
+}
+
+static void ScrollMainViewport(int x, int y)
+{
+	if (_game_mode != GM_MENU) {
+		Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+		assert(w);
+
+		WP(w,vp_d).scrollpos_x += x << w->viewport->zoom;
+		WP(w,vp_d).scrollpos_y += y << w->viewport->zoom;
+	}
+}
+
+static const int8 scrollamt[16][2] = {
+	{ 0,  0},
+	{-2,  0}, //  1 : left
+	{ 0, -2}, //  2 : up
+	{-2, -1}, //  3 : left + up
+	{ 2,  0}, //  4 : right
+	{ 0,  0}, //  5 : left + right
+	{ 2, -1}, //  6 : right + up
+	{ 0, -2}, //  7 : left + right + up = up
+	{ 0  ,2}, //  8 : down
+	{-2  ,1}, //  9 : down+left
+	{ 0,  0}, // 10 : impossible
+	{-2,  0}, // 11 : left + up + down = left
+	{ 2,  1}, // 12 : down+right
+	{ 0,  2}, // 13 : left + right + down = down
+	{ 0, -2}, // 14 : left + right + up = up
+	{ 0,  0}, // 15 : impossible
+};
+
+static void HandleKeyScrolling(void)
+{
+	if (_dirkeys && !_no_scroll) {
+		int factor = _shift_pressed ? 50 : 10;
+		ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
+	}
+}
+
+void GameLoop(void)
+{
+	ThreadMsg message;
+
+	if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
+
+	// autosave game?
+	if (_do_autosave) {
+		_do_autosave = false;
+		DoAutosave();
+		RedrawAutosave();
+	}
+
+	// handle scrolling of the main window
+	HandleKeyScrolling();
+
+	// make a screenshot?
+	if (IsScreenshotRequested()) ShowScreenshotResult(MakeScreenshot());
+
+	// switch game mode?
+	if (_switch_mode != SM_NONE) {
+		SwitchMode(_switch_mode);
+		_switch_mode = SM_NONE;
+	}
+
+	IncreaseSpriteLRU();
+	InteractiveRandom();
+
+	if (_scroller_click_timeout > 3) {
+		_scroller_click_timeout -= 3;
+	} else {
+		_scroller_click_timeout = 0;
+	}
+
+	_caret_timer += 3;
+	_timer_counter += 8;
+	CursorTick();
+
+#ifdef ENABLE_NETWORK
+	// Check for UDP stuff
+	if (_network_available) NetworkUDPGameLoop();
+
+	if (_networking && !IsGeneratingWorld()) {
+		// Multiplayer
+		NetworkGameLoop();
+	} else {
+		if (_network_reconnect > 0 && --_network_reconnect == 0) {
+			// This means that we want to reconnect to the last host
+			// We do this here, because it means that the network is really closed
+			NetworkClientConnectGame(_network_last_host, _network_last_port);
+		}
+		// Singleplayer
+		StateGameLoop();
+	}
+#else
+	StateGameLoop();
+#endif /* ENABLE_NETWORK */
+
+	if (!_pause && _display_opt & DO_FULL_ANIMATION) DoPaletteAnimations();
+
+	if (!_pause || _cheats.build_in_pause.value) MoveAllTextEffects();
+
+	InputLoop();
+
+	MusicLoop();
+}
+
+void BeforeSaveGame(void)
+{
+	const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+
+	if (w != NULL) {
+		_saved_scrollpos_x = WP(w, const vp_d).scrollpos_x;
+		_saved_scrollpos_y = WP(w, const vp_d).scrollpos_y;
+		_saved_scrollpos_zoom = w->viewport->zoom;
+	}
+}
+
+static void ConvertTownOwner(void)
+{
+	TileIndex tile;
+
+	for (tile = 0; tile != MapSize(); tile++) {
+		switch (GetTileType(tile)) {
+			case MP_STREET:
+				if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) & 0x80) {
+					SetCrossingRoadOwner(tile, OWNER_TOWN);
+				}
+				/* FALLTHROUGH */
+
+			case MP_TUNNELBRIDGE:
+				if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
+				break;
+
+			default: break;
+		}
+	}
+}
+
+// before savegame version 4, the name of the company determined if it existed
+static void CheckIsPlayerActive(void)
+{
+	Player *p;
+
+	FOR_ALL_PLAYERS(p) {
+		if (p->name_1 != 0) p->is_active = true;
+	}
+}
+
+// since savegame version 4.1, exclusive transport rights are stored at towns
+static void UpdateExclusiveRights(void)
+{
+	Town *t;
+
+	FOR_ALL_TOWNS(t) {
+		t->exclusivity = (byte)-1;
+	}
+
+	/* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete)
+	 *   could be implemented this way:
+	 * 1.) Go through all stations
+	 *     Build an array town_blocked[ town_id ][ player_id ]
+	 *     that stores if at least one station in that town is blocked for a player
+	 * 2.) Go through that array, if you find a town that is not blocked for
+	 *     one player, but for all others, then give him exclusivity.
+	 */
+}
+
+static const byte convert_currency[] = {
+	 0,  1, 12,  8,  3,
+	10, 14, 19,  4,  5,
+	 9, 11, 13,  6, 17,
+	16, 22, 21,  7, 15,
+	18,  2, 20, };
+
+// since savegame version 4.2 the currencies are arranged differently
+static void UpdateCurrencies(void)
+{
+	_opt.currency = convert_currency[_opt.currency];
+}
+
+/* Up to revision 1413 the invisible tiles at the southern border have not been
+ * MP_VOID, even though they should have. This is fixed by this function
+ */
+static void UpdateVoidTiles(void)
+{
+	uint i;
+
+	for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX());
+	for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i);
+}
+
+// since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255)
+static void UpdateSignOwner(void)
+{
+	Sign *si;
+
+	FOR_ALL_SIGNS(si) si->owner = OWNER_NONE;
+}
+
+extern void UpdateOldAircraft( void );
+extern void UpdateOilRig( void );
+
+
+static inline RailType UpdateRailType(RailType rt, RailType min)
+{
+	return rt >= min ? (RailType)(rt + 1): rt;
+}
+
+bool AfterLoadGame(void)
+{
+	Window *w;
+	ViewPort *vp;
+	Player *p;
+
+	// in version 2.1 of the savegame, town owner was unified.
+	if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner();
+
+	// from version 4.1 of the savegame, exclusive rights are stored at towns
+	if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights();
+
+	// from version 4.2 of the savegame, currencies are in a different order
+	if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies();
+
+	// from version 6.1 of the savegame, signs have an "owner"
+	if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner();
+
+	/* In old version there seems to be a problem that water is owned by
+	    OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current
+	    (4.3) version, so I just check when versions are older, and then
+	    walk through the whole map.. */
+	if (CheckSavegameVersionOldStyle(4, 3)) {
+		TileIndex tile = TileXY(0, 0);
+		uint w = MapSizeX();
+		uint h = MapSizeY();
+
+		BEGIN_TILE_LOOP(tile_cur, w, h, tile)
+			if (IsTileType(tile_cur, MP_WATER) && GetTileOwner(tile_cur) >= MAX_PLAYERS)
+				SetTileOwner(tile_cur, OWNER_WATER);
+		END_TILE_LOOP(tile_cur, w, h, tile)
+	}
+
+	// convert road side to my format.
+	if (_opt.road_side) _opt.road_side = 1;
+
+	/* Check all NewGRFs are present */
+	if (!IsGoodGRFConfigList()) return false;
+
+	/* Update current year
+	 * must be done before loading sprites as some newgrfs check it */
+	SetDate(_date);
+
+	// Load the sprites
+	GfxLoadSprites();
+	LoadStringWidthTable();
+
+	/* Connect front and rear engines of multiheaded trains and converts
+	 * subtype to the new format */
+	if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew();
+
+	/* Connect front and rear engines of multiheaded trains */
+	ConnectMultiheadedTrains();
+
+	// reinit the landscape variables (landscape might have changed)
+	InitializeLandscapeVariables(true);
+
+	// Update all vehicles
+	AfterLoadVehicles();
+
+	// Update all waypoints
+	if (CheckSavegameVersion(12)) FixOldWaypoints();
+
+	UpdateAllWaypointSigns();
+
+	// in version 2.2 of the savegame, we have new airports
+	if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft();
+
+	UpdateAllStationVirtCoord();
+
+	// Setup town coords
+	AfterLoadTown();
+	UpdateAllSignVirtCoords();
+
+	// make sure there is a town in the game
+	if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, (uint)-1)) {
+		_error_message = STR_NO_TOWN_IN_SCENARIO;
+		return false;
+	}
+
+	// Initialize windows
+	ResetWindowSystem();
+	SetupColorsAndInitialWindow();
+
+	w = FindWindowById(WC_MAIN_WINDOW, 0);
+
+	WP(w,vp_d).scrollpos_x = _saved_scrollpos_x;
+	WP(w,vp_d).scrollpos_y = _saved_scrollpos_y;
+
+	vp = w->viewport;
+	vp->zoom = _saved_scrollpos_zoom;
+	vp->virtual_width = vp->width << vp->zoom;
+	vp->virtual_height = vp->height << vp->zoom;
+
+	// in version 4.1 of the savegame, is_active was introduced to determine
+	// if a player does exist, rather then checking name_1
+	if (CheckSavegameVersionOldStyle(4, 1)) CheckIsPlayerActive();
+
+	// the void tiles on the southern border used to belong to a wrong class (pre 4.3).
+	if (CheckSavegameVersionOldStyle(4, 3)) UpdateVoidTiles();
+
+	// If Load Scenario / New (Scenario) Game is used,
+	//  a player does not exist yet. So create one here.
+	// 1 exeption: network-games. Those can have 0 players
+	//   But this exeption is not true for network_servers!
+	if (!_players[0].is_active && (!_networking || (_networking && _network_server)))
+		DoStartupNewPlayer(false);
+
+	DoZoomInOutWindow(ZOOM_NONE, w); // update button status
+	MarkWholeScreenDirty();
+
+	// In 5.1, Oilrigs have been moved (again)
+	if (CheckSavegameVersionOldStyle(5, 1)) UpdateOilRig();
+
+	/* In version 6.1 we put the town index in the map-array. To do this, we need
+	 *  to use m2 (16bit big), so we need to clean m2, and that is where this is
+	 *  all about ;) */
+	if (CheckSavegameVersionOldStyle(6, 1)) {
+		BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) {
+			switch (GetTileType(tile)) {
+				case MP_HOUSE:
+					_m[tile].m4 = _m[tile].m2;
+					SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index);
+					break;
+
+				case MP_STREET:
+					_m[tile].m4 |= (_m[tile].m2 << 4);
+					if (IsTileOwner(tile, OWNER_TOWN)) {
+						SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index);
+					} else {
+						SetTownIndex(tile, 0);
+					}
+					break;
+
+				default: break;
+			}
+		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
+	}
+
+	/* From version 9.0, we update the max passengers of a town (was sometimes negative
+	 *  before that. */
+	if (CheckSavegameVersion(9)) {
+		Town *t;
+		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
+	}
+
+	/* From version 16.0, we included autorenew on engines, which are now saved, but
+	 *  of course, we do need to initialize them for older savegames. */
+	if (CheckSavegameVersion(16)) {
+		FOR_ALL_PLAYERS(p) {
+			p->engine_renew_list   = NULL;
+			p->engine_renew        = false;
+			p->engine_renew_months = -6;
+			p->engine_renew_money  = 100000;
+		}
+
+		/* When loading a game, _local_player is not yet set to the correct value.
+		 * However, in a dedicated server we are a spectator, so nothing needs to
+		 * happen. In case we are not a dedicated server, the local player always
+		 * becomes player 0, unless we are in the scenario editor where all the
+		 * players are 'invalid'.
+		 */
+		if (!_network_dedicated && IsValidPlayer(0)) {
+			p = GetPlayer(0);
+			p->engine_renew        = _patches.autorenew;
+			p->engine_renew_months = _patches.autorenew_months;
+			p->engine_renew_money  = _patches.autorenew_money;
+		}
+	}
+
+	if (CheckSavegameVersion(42)) {
+		TileIndex map_end = MapSize();
+		TileIndex tile;
+		Vehicle* v;
+
+		for (tile = 0; tile != map_end; tile++) {
+			if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile);
+			if (IsBridgeTile(tile)) {
+				if (HASBIT(_m[tile].m5, 6)) { // middle part
+					Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
+
+					if (HASBIT(_m[tile].m5, 5)) { // transport route under bridge?
+						if (GB(_m[tile].m5, 3, 2) == TRANSPORT_RAIL) {
+							MakeRailNormal(
+								tile,
+								GetTileOwner(tile),
+								axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
+								GetRailType(tile)
+							);
+						} else {
+							TownID town = IsTileOwner(tile, OWNER_TOWN) ? ClosestTownFromTile(tile, (uint)-1)->index : 0;
+
+							MakeRoadNormal(
+								tile,
+								GetTileOwner(tile),
+								axis == AXIS_X ? ROAD_Y : ROAD_X,
+								town
+							);
+						}
+					} else {
+						if (GB(_m[tile].m5, 3, 2) == 0) {
+							MakeClear(tile, CLEAR_GRASS, 3);
+						} else {
+							MakeCanal(tile, GetTileOwner(tile));
+						}
+					}
+					SetBridgeMiddle(tile, axis);
+				} else { // ramp
+					Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
+					uint north_south = GB(_m[tile].m5, 5, 1);
+					DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south));
+					TransportType type = (TransportType)GB(_m[tile].m5, 1, 2);
+
+					_m[tile].m5 = 1 << 7 | type << 2 | dir;
+				}
+			}
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->type != VEH_Train && v->type != VEH_Road) continue;
+			if (IsBridgeTile(v->tile)) {
+				DiagDirection dir = GetBridgeRampDirection(v->tile);
+
+				if (dir != DirToDiagDir(v->direction)) continue;
+				switch (dir) {
+					default: NOT_REACHED();
+					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0)            continue; break;
+					case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
+					case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
+					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0)            continue; break;
+				}
+			} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
+				v->tile = GetNorthernBridgeEnd(v->tile);
+			} else {
+				continue;
+			}
+			if (v->type == VEH_Train) {
+				v->u.rail.track = 0x40;
+			} else {
+				v->u.road.state = 0xFF;
+			}
+		}
+	}
+
+	/* Elrails got added in rev 24 */
+	if (CheckSavegameVersion(24)) {
+		Vehicle *v;
+		uint i;
+		TileIndex t;
+		RailType min_rail = RAILTYPE_ELECTRIC;
+
+		for (i = 0; i < lengthof(_engines); i++) {
+			Engine *e = GetEngine(i);
+			if (e->type == VEH_Train &&
+					(e->railtype != RAILTYPE_RAIL || RailVehInfo(i)->engclass == 2)) {
+				e->railtype++;
+			}
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Train) {
+				RailType rt = GetEngine(v->engine_type)->railtype;
+
+				v->u.rail.railtype = rt;
+				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
+			}
+		}
+
+		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
+		for (t = 0; t < MapSize(); t++) {
+			switch (GetTileType(t)) {
+				case MP_RAILWAY:
+					SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
+					break;
+
+				case MP_STREET:
+					if (IsLevelCrossing(t)) {
+						SetRailTypeCrossing(t, UpdateRailType(GetRailTypeCrossing(t), min_rail));
+					}
+					break;
+
+				case MP_STATION:
+					if (IsRailwayStation(t)) {
+						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
+					}
+					break;
+
+				case MP_TUNNELBRIDGE:
+					if (IsTunnel(t)) {
+						if (GetTunnelTransportType(t) == TRANSPORT_RAIL) {
+							SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
+						}
+					} else {
+						if (GetBridgeTransportType(t) == TRANSPORT_RAIL) {
+							SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
+						}
+					}
+					break;
+
+				default:
+					break;
+			}
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v);
+		}
+
+	}
+
+	/* In version 16.1 of the savegame a player can decide if trains, which get
+	 * replaced, shall keep their old length. In all prior versions, just default
+	 * to false */
+	if (CheckSavegameVersionOldStyle(16, 1)) {
+		FOR_ALL_PLAYERS(p) p->renew_keep_length = false;
+	}
+
+	/* In version 17, ground type is moved from m2 to m4 for depots and
+	 * waypoints to make way for storing the index in m2. The custom graphics
+	 * id which was stored in m4 is now saved as a grf/id reference in the
+	 * waypoint struct. */
+	if (CheckSavegameVersion(17)) {
+		Waypoint *wp;
+
+		FOR_ALL_WAYPOINTS(wp) {
+			if (wp->deleted == 0) {
+				const StationSpec *statspec = NULL;
+
+				if (HASBIT(_m[wp->xy].m3, 4))
+					statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1);
+
+				if (statspec != NULL) {
+					wp->stat_id = _m[wp->xy].m4 + 1;
+					wp->grfid = statspec->grfid;
+					wp->localidx = statspec->localidx;
+				} else {
+					// No custom graphics set, so set to default.
+					wp->stat_id = 0;
+					wp->grfid = 0;
+					wp->localidx = 0;
+				}
+
+				// Move ground type bits from m2 to m4.
+				_m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4);
+				// Store waypoint index in the tile.
+				_m[wp->xy].m2 = wp->index;
+			}
+		}
+	} else {
+		/* As of version 17, we recalculate the custom graphic ID of waypoints
+		 * from the GRF ID / station index. */
+		AfterLoadWaypoints();
+	}
+
+	/* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making
+	 *  room for PBS. Now in version 21 move it back :P. */
+	if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) {
+		BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) {
+			if (IsTileType(tile, MP_RAILWAY)) {
+				if (HasSignals(tile)) {
+					// convert PBS signals to combo-signals
+					if (HASBIT(_m[tile].m4, 2)) SetSignalType(tile, SIGTYPE_COMBO);
+
+					// move the signal variant back
+					SetSignalVariant(tile, HASBIT(_m[tile].m4, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC);
+					CLRBIT(_m[tile].m4, 3);
+				}
+
+				// Clear PBS reservation on track
+				if (!IsTileDepotType(tile, TRANSPORT_RAIL)) {
+					SB(_m[tile].m4, 4, 4, 0);
+				} else {
+					CLRBIT(_m[tile].m3, 6);
+				}
+			}
+
+			// Clear PBS reservation on crossing
+			if (IsTileType(tile, MP_STREET) && IsLevelCrossing(tile))
+				CLRBIT(_m[tile].m5, 0);
+
+			// Clear PBS reservation on station
+			if (IsTileType(tile, MP_STATION))
+				CLRBIT(_m[tile].m3, 6);
+		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
+	}
+
+	if (CheckSavegameVersion(22))  UpdatePatches();
+
+	if (CheckSavegameVersion(25)) {
+		Vehicle *v;
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Road) {
+				v->vehstatus &= ~0x40;
+				v->u.road.slot = NULL;
+				v->u.road.slot_age = 0;
+			}
+		}
+	}
+
+	if (CheckSavegameVersion(26)) {
+		Station *st;
+		FOR_ALL_STATIONS(st) {
+			st->last_vehicle_type = VEH_Invalid;
+		}
+	}
+
+	YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
+
+	if (CheckSavegameVersion(34)) FOR_ALL_PLAYERS(p) ResetPlayerLivery(p);
+
+	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
+
+	if (!CheckSavegameVersion(27)) AfterLoadStations();
+
+	{
+		/* Set up the engine count for all players */
+		Player *players[MAX_PLAYERS];
+		int i;
+		const Vehicle *v;
+
+		for (i = 0; i < MAX_PLAYERS; i++) players[i] = GetPlayer(i);
+
+		FOR_ALL_VEHICLES(v) {
+			if (!IsEngineCountable(v)) continue;
+			players[v->owner]->num_engines[v->engine_type]++;
+		}
+	}
+
+	/* Time starts at 0 instead of 1920.
+	 * Account for this in older games by adding an offset */
+	if (CheckSavegameVersion(31)) {
+		Station *st;
+		Waypoint *wp;
+		Engine *e;
+		Player *player;
+		Industry *i;
+		Vehicle *v;
+
+		_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
+		_cur_year += ORIGINAL_BASE_YEAR;
+
+		FOR_ALL_STATIONS(st)    st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
+		FOR_ALL_WAYPOINTS(wp)   wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
+		FOR_ALL_ENGINES(e)      e->intro_date  += DAYS_TILL_ORIGINAL_BASE_YEAR;
+		FOR_ALL_PLAYERS(player) player->inaugurated_year += ORIGINAL_BASE_YEAR;
+		FOR_ALL_INDUSTRIES(i)   i->last_prod_year        += ORIGINAL_BASE_YEAR;
+
+		FOR_ALL_VEHICLES(v) {
+			v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR;
+			v->build_year += ORIGINAL_BASE_YEAR;
+		}
+	}
+
+	/* From 32 on we save the industry who made the farmland.
+	 *  To give this prettyness to old savegames, we remove all farmfields and
+	 *  plant new ones. */
+	if (CheckSavegameVersion(32)) {
+		Industry *i;
+
+		BEGIN_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) {
+			if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS)) {
+				MakeClear(tile_cur, CLEAR_GRASS, 3);
+			}
+		} END_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0)
+
+		FOR_ALL_INDUSTRIES(i) {
+			uint j;
+
+			if (i->type == IT_FARM || i->type == IT_FARM_2) {
+				for (j = 0; j != 50; j++) PlantRandomFarmField(i);
+			}
+		}
+	}
+
+	/* Setting no refit flags to all orders in savegames from before refit in orders were added */
+	if (CheckSavegameVersion(36)) {
+		Order *order;
+		Vehicle *v;
+
+		FOR_ALL_ORDERS(order) {
+			order->refit_cargo   = CT_NO_REFIT;
+			order->refit_subtype = CT_NO_REFIT;
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			v->current_order.refit_cargo   = CT_NO_REFIT;
+			v->current_order.refit_subtype = CT_NO_REFIT;
+		}
+	}
+
+	if (CheckSavegameVersion(37)) {
+		ConvertNameArray();
+	}
+
+	/* from version 38 we have optional elrails, since we cannot know the
+	 * preference of a user, let elrails enabled; it can be disabled manually */
+	if (CheckSavegameVersion(38)) {
+		_patches.disable_elrails = false; // enable elrails
+		/* do the same as when elrails were enabled/disabled manually just now */
+		SettingsDisableElrail(_patches.disable_elrails);
+	}
+
+	if (CheckSavegameVersion(43)) {
+		BEGIN_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) {
+			if (IsTileType(tile_cur, MP_INDUSTRY)) {
+				switch (GetIndustryGfx(tile_cur)) {
+					case GFX_POWERPLANT_SPARKS:
+						SetIndustryAnimationState(tile_cur, GB(_m[tile_cur].m1, 2, 5));
+						break;
+
+					case GFX_OILWELL_ANIMATED_1:
+					case GFX_OILWELL_ANIMATED_2:
+					case GFX_OILWELL_ANIMATED_3:
+						SetIndustryAnimationState(tile_cur, GB(_m[tile_cur].m1, 0, 2));
+						break;
+
+					case GFX_COAL_MINE_TOWER_ANIMATED:
+					case GFX_COPPER_MINE_TOWER_ANIMATED:
+					case GFX_GOLD_MINE_TOWER_ANIMATED:
+						 SetIndustryAnimationState(tile_cur, _m[tile_cur].m1);
+						 break;
+
+					default: /* No animation states to change */
+						break;
+				}
+			}
+		} END_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0)
+	}
+
+	return true;
+}
+
+/** Reload all NewGRF files during a running game. This is a cut-down
+ * version of AfterLoadGame().
+ * XXX - We need to reset the vehicle position hash because with a non-empty
+ * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
+ * to recalculate vehicle data as some NewGRF vehicle sets could have been
+ * removed or added and changed statistics */
+void ReloadNewGRFData(void)
+{
+	/* reload grf data */
+	GfxLoadSprites();
+	LoadStringWidthTable();
+	/* reload vehicles */
+	ResetVehiclePosHash();
+	AfterLoadVehicles();
+	/* update station and waypoint graphics */
+	AfterLoadWaypoints();
+	AfterLoadStations();
+	/* redraw the whole screen */
+	MarkWholeScreenDirty();
+}
deleted file mode 100644
--- a/src/order_cmd.c
+++ /dev/null
@@ -1,1278 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "order.h"
-#include "airport.h"
-#include "depot.h"
-#include "functions.h"
-#include "table/strings.h"
-#include "vehicle.h"
-#include "waypoint.h"
-#include "command.h"
-#include "station.h"
-#include "player.h"
-#include "news.h"
-#include "saveload.h"
-#include "vehicle_gui.h"
-
-/**
- * Called if a new block is added to the order-pool
- */
-static void OrderPoolNewBlock(uint start_item)
-{
-	Order *order;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (order = GetOrder(start_item); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) order->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Order, Order, OrderPoolNewBlock, NULL)
-
-/**
- *
- * Unpacks a order from savegames made with TTD(Patch)
- *
- */
-Order UnpackOldOrder(uint16 packed)
-{
-	Order order;
-	order.type    = GB(packed, 0, 4);
-	order.flags   = GB(packed, 4, 4);
-	order.dest    = GB(packed, 8, 8);
-	order.next    = NULL;
-
-	order.refit_cargo   = CT_NO_REFIT;
-	order.refit_subtype = 0;
-	order.index = 0; // avoid compiler warning
-
-	// Sanity check
-	// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
-	if (order.type == OT_NOTHING && (order.flags != 0 || order.dest != 0)) {
-		order.type = OT_DUMMY;
-		order.flags = 0;
-	}
-
-	return order;
-}
-
-/**
- *
- * Unpacks a order from savegames with version 4 and lower
- *
- */
-static Order UnpackVersion4Order(uint16 packed)
-{
-	Order order;
-	order.type  = GB(packed, 0, 4);
-	order.flags = GB(packed, 4, 4);
-	order.dest  = GB(packed, 8, 8);
-	order.next  = NULL;
-	order.index = 0; // avoid compiler warning
-	order.refit_cargo   = CT_NO_REFIT;
-	order.refit_subtype = 0;
-	return order;
-}
-
-/**
- *
- * Updates the widgets of a vehicle which contains the order-data
- *
- */
-void InvalidateVehicleOrder(const Vehicle *v)
-{
-	InvalidateWindow(WC_VEHICLE_VIEW,   v->index);
-	InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
-}
-
-/**
- *
- * Swap two orders
- *
- */
-static void SwapOrders(Order *order1, Order *order2)
-{
-	Order temp_order;
-
-	temp_order = *order1;
-	AssignOrder(order1, *order2);
-	order1->next = order2->next;
-	AssignOrder(order2, temp_order);
-	order2->next = temp_order.next;
-}
-
-/**
- *
- * Allocate a new order
- *
- * @return Order* if a free space is found, else NULL.
- *
- */
-static Order *AllocateOrder(void)
-{
-	Order *order;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (order = GetOrder(0); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) {
-		if (!IsValidOrder(order)) {
-			OrderID index = order->index;
-
-			memset(order, 0, sizeof(*order));
-			order->index = index;
-			order->next = NULL;
-			order->refit_cargo   = CT_NO_REFIT;
-			order->refit_subtype = 0;
-
-			return order;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Order_pool)) return AllocateOrder();
-
-	return NULL;
-}
-
-/**
- *
- * Assign data to an order (from an other order)
- *   This function makes sure that the index is maintained correctly
- *
- */
-void AssignOrder(Order *order, Order data)
-{
-	order->type  = data.type;
-	order->flags = data.flags;
-	order->dest  = data.dest;
-
-	order->refit_cargo   = data.refit_cargo;
-	order->refit_subtype = data.refit_subtype;
-}
-
-
-/**
- * Delete all news items regarding defective orders about a vehicle
- * This could kill still valid warnings (for example about void order when just
- * another order gets added), but assume the player will notice the problems,
- * when (s)he's changing the orders.
- */
-static void DeleteOrderWarnings(const Vehicle* v)
-{
-	DeleteVehicleNews(v->index, STR_TRAIN_HAS_TOO_FEW_ORDERS  + (v->type - VEH_Train) * 4);
-	DeleteVehicleNews(v->index, STR_TRAIN_HAS_VOID_ORDER      + (v->type - VEH_Train) * 4);
-	DeleteVehicleNews(v->index, STR_TRAIN_HAS_DUPLICATE_ENTRY + (v->type - VEH_Train) * 4);
-	DeleteVehicleNews(v->index, STR_TRAIN_HAS_INVALID_ENTRY   + (v->type - VEH_Train) * 4);
-}
-
-
-/** Add an order to the orderlist of a vehicle.
- * @param tile unused
- * @param p1 various bitstuffed elements
- * - p1 = (bit  0 - 15) - ID of the vehicle
- * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
- *                        the order will be inserted before that one
- *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 packed order to insert
- */
-int32 CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	VehicleID veh   = GB(p1,  0, 16);
-	VehicleOrderID sel_ord = GB(p1, 16, 16);
-	Order new_order = UnpackOrder(p2);
-
-	if (!IsValidVehicleID(veh)) return CMD_ERROR;
-
-	v = GetVehicle(veh);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* Check if the inserted order is to the correct destination (owner, type),
-	 * and has the correct flags if any */
-	switch (new_order.type) {
-		case OT_GOTO_STATION: {
-			const Station *st;
-
-			if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
-			st = GetStation(new_order.dest);
-
-			if (st->airport_type != AT_OILRIG && !IsBuoy(st) && !CheckOwnership(st->owner)) {
-				return CMD_ERROR;
-			}
-
-			switch (v->type) {
-				case VEH_Train:
-					if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
-					break;
-
-				case VEH_Road:
-					if (v->cargo_type == CT_PASSENGERS) {
-						if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
-					} else {
-						if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
-					}
-					break;
-
-				case VEH_Ship:
-					if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
-					break;
-
-				case VEH_Aircraft:
-					if (!(st->facilities & FACIL_AIRPORT)) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
-
-			/* Order flags can be any of the following for stations:
-			 * [full-load | unload] [+ transfer] [+ non-stop]
-			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case 0:
-				case OF_FULL_LOAD:
-				case OF_FULL_LOAD | OF_TRANSFER:
-				case OF_UNLOAD:
-				case OF_UNLOAD | OF_TRANSFER:
-				case OF_TRANSFER:
-					break;
-
-				case OF_NON_STOP:
-				case OF_NON_STOP | OF_FULL_LOAD:
-				case OF_NON_STOP | OF_FULL_LOAD | OF_TRANSFER:
-				case OF_NON_STOP | OF_UNLOAD:
-				case OF_NON_STOP | OF_UNLOAD | OF_TRANSFER:
-				case OF_NON_STOP | OF_TRANSFER:
-					if (v->type != VEH_Train) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
-			break;
-		}
-
-		case OT_GOTO_DEPOT: {
-			if (v->type == VEH_Aircraft) {
-				const Station* st;
-
-				if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
-				st = GetStation(new_order.dest);
-
-				if ((st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
-						!(st->facilities & FACIL_AIRPORT) ||
-						GetAirport(st->airport_type)->nof_depots == 0) {
-					return CMD_ERROR;
-				}
-			} else {
-				const Depot* dp;
-
-				if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
-				dp = GetDepot(new_order.dest);
-
-				if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
-
-				switch (v->type) {
-					case VEH_Train:
-						if (!IsTileDepotType(dp->xy, TRANSPORT_RAIL)) return CMD_ERROR;
-						break;
-
-					case VEH_Road:
-						if (!IsTileDepotType(dp->xy, TRANSPORT_ROAD)) return CMD_ERROR;
-						break;
-
-					case VEH_Ship:
-						if (!IsTileDepotType(dp->xy, TRANSPORT_WATER)) return CMD_ERROR;
-						break;
-
-					default: return CMD_ERROR;
-				}
-			}
-
-			/* Order flags can be any of the following for depots:
-			 * order [+ halt] [+ non-stop]
-			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case OF_PART_OF_ORDERS:
-				case OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
-					break;
-
-				case OF_NON_STOP | OF_PART_OF_ORDERS:
-				case OF_NON_STOP | OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
-					if (v->type != VEH_Train) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
-			break;
-		}
-
-		case OT_GOTO_WAYPOINT: {
-			const Waypoint* wp;
-
-			if (v->type != VEH_Train) return CMD_ERROR;
-
-			if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
-			wp = GetWaypoint(new_order.dest);
-
-			if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
-
-			/* Order flags can be any of the following for waypoints:
-			 * [non-stop]
-			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case 0: break;
-
-				case OF_NON_STOP:
-					if (v->type != VEH_Train) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
-			break;
-		}
-
-		default: return CMD_ERROR;
-	}
-
-	if (sel_ord > v->num_orders) return CMD_ERROR;
-
-	if (IsOrderPoolFull()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
-
-	/* XXX - This limit is only here because the backuppedorders can't
-	 * handle any more then this.. */
-	if (v->num_orders >= MAX_BACKUP_ORDER_COUNT) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
-
-	/* For ships, make sure that the station is not too far away from the
-	 * previous destination, for human players with new pathfinding disabled */
-	if (v->type == VEH_Ship && IsHumanPlayer(v->owner) &&
-		sel_ord != 0 && GetVehicleOrder(v, sel_ord - 1)->type == OT_GOTO_STATION
-		&& !_patches.new_pathfinding_all) {
-
-		int dist = DistanceManhattan(
-			GetStation(GetVehicleOrder(v, sel_ord - 1)->dest)->xy,
-			GetStation(new_order.dest)->xy // XXX type != OT_GOTO_STATION?
-		);
-		if (dist >= 130)
-			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
-	}
-
-	if (flags & DC_EXEC) {
-		Vehicle *u;
-		Order *new = AllocateOrder();
-		AssignOrder(new, new_order);
-
-		/* Create new order and link in list */
-		if (v->orders == NULL) {
-			v->orders = new;
-		} else {
-			/* Try to get the previous item (we are inserting above the
-			    selected) */
-			Order *order = GetVehicleOrder(v, sel_ord - 1);
-
-			if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) {
-				/* There is no previous item, so we are altering v->orders itself
-				    But because the orders can be shared, we copy the info over
-				    the v->orders, so we don't have to change the pointers of
-				    all vehicles */
-				SwapOrders(v->orders, new);
-				/* Now update the next pointers */
-				v->orders->next = new;
-			} else if (order == NULL) {
-				/* 'sel' is a non-existing order, add him to the end */
-				order = GetLastVehicleOrder(v);
-				order->next = new;
-			} else {
-				/* Put the new order in between */
-				new->next = order->next;
-				order->next = new;
-			}
-		}
-
-		u = GetFirstVehicleFromSharedList(v);
-		DeleteOrderWarnings(u);
-		for (; u != NULL; u = u->next_shared) {
-			/* Increase amount of orders */
-			u->num_orders++;
-
-			/* If the orderlist was empty, assign it */
-			if (u->orders == NULL) u->orders = v->orders;
-
-			assert(v->orders == u->orders);
-
-			/* If there is added an order before the current one, we need
-			to update the selected order */
-			if (sel_ord <= u->cur_order_index) {
-				uint cur = u->cur_order_index + 1;
-				/* Check if we don't go out of bound */
-				if (cur < u->num_orders)
-					u->cur_order_index = cur;
-			}
-			/* Update any possible open window of the vehicle */
-			InvalidateVehicleOrder(u);
-		}
-
-		/* Make sure to rebuild the whole list */
-		RebuildVehicleLists();
-	}
-
-	return 0;
-}
-
-/** Declone an order-list
- * @param *dst delete the orders of this vehicle
- * @param flags execution flags
- */
-static int32 DecloneOrder(Vehicle *dst, uint32 flags)
-{
-	if (flags & DC_EXEC) {
-		DeleteVehicleOrders(dst);
-		InvalidateVehicleOrder(dst);
-		RebuildVehicleLists();
-	}
-	return 0;
-}
-
-/** Delete an order from the orderlist of a vehicle.
- * @param tile unused
- * @param p1 the ID of the vehicle
- * @param p2 the order to delete (max 255)
- */
-int32 CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v, *u;
-	VehicleID veh_id = p1;
-	VehicleOrderID sel_ord = p2;
-	Order *order;
-
-	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
-
-	v = GetVehicle(veh_id);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* If we did not select an order, we maybe want to de-clone the orders */
-	if (sel_ord >= v->num_orders)
-		return DecloneOrder(v, flags);
-
-	order = GetVehicleOrder(v, sel_ord);
-	if (order == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
-			if (GetVehicleOrder(v, sel_ord + 1) != NULL) {
-				/* First item, but not the last, so we need to alter v->orders
-				    Because we can have shared order, we copy the data
-				    from the next item over the deleted */
-				order = GetVehicleOrder(v, sel_ord + 1);
-				SwapOrders(v->orders, order);
-			} else {
-				/* Last item, so clean the list */
-				v->orders = NULL;
-			}
-		} else {
-			GetVehicleOrder(v, sel_ord - 1)->next = order->next;
-		}
-
-		/* Give the item free */
-		order->type = OT_NOTHING;
-		order->next = NULL;
-
-		u = GetFirstVehicleFromSharedList(v);
-		DeleteOrderWarnings(u);
-		for (; u != NULL; u = u->next_shared) {
-			u->num_orders--;
-
-			if (sel_ord < u->cur_order_index)
-				u->cur_order_index--;
-
-			/* If we removed the last order, make sure the shared vehicles
-			 * also set their orders to NULL */
-			if (v->orders == NULL) u->orders = NULL;
-
-			assert(v->orders == u->orders);
-
-			/* NON-stop flag is misused to see if a train is in a station that is
-			 * on his order list or not */
-			if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
-					HASBIT(u->current_order.flags, OFB_NON_STOP)) {
-				u->current_order.flags = 0;
-			}
-
-			/* Update any possible open window of the vehicle */
-			InvalidateVehicleOrder(u);
-		}
-
-		RebuildVehicleLists();
-	}
-
-	return 0;
-}
-
-/** Goto next order of order-list.
- * @param tile unused
- * @param p1 The ID of the vehicle which order is skipped
- * @param p2 unused
- */
-int32 CmdSkipOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	VehicleID veh_id = p1;
-
-	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
-
-	v = GetVehicle(veh_id);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		/* Goto next order */
-		VehicleOrderID b = v->cur_order_index + 1;
-		if (b >= v->num_orders) b = 0;
-
-		v->cur_order_index = b;
-
-		if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
-
-		if (v->type == VEH_Road) ClearSlot(v);
-
-		/* NON-stop flag is misused to see if a train is in a station that is
-		 * on his order list or not */
-		if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
-			v->current_order.flags = 0;
-
-		InvalidateVehicleOrder(v);
-	}
-
-	/* We have an aircraft/ship, they have a mini-schedule, so update them all */
-	if (v->type == VEH_Aircraft) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
-	if (v->type == VEH_Ship) InvalidateWindowClasses(WC_SHIPS_LIST);
-
-	return 0;
-}
-
-
-/** Modify an order in the orderlist of a vehicle.
- * @param tile unused
- * @param p1 various bitstuffed elements
- * - p1 = (bit  0 - 15) - ID of the vehicle
- * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
- *                        the order will be inserted before that one
- *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 mode to change the order to (always set)
- */
-int32 CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	Order *order;
-	VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
-	VehicleID veh   = GB(p1,  0, 16);
-
-	if (!IsValidVehicleID(veh)) return CMD_ERROR;
-	if (p2 != OFB_FULL_LOAD && p2 != OFB_UNLOAD && p2 != OFB_NON_STOP && p2 != OFB_TRANSFER) return CMD_ERROR;
-
-	v = GetVehicle(veh);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* Is it a valid order? */
-	if (sel_ord >= v->num_orders) return CMD_ERROR;
-
-	order = GetVehicleOrder(v, sel_ord);
-	if (order->type != OT_GOTO_STATION &&
-			(order->type != OT_GOTO_DEPOT    || p2 == OFB_UNLOAD) &&
-			(order->type != OT_GOTO_WAYPOINT || p2 != OFB_NON_STOP)) {
-		return CMD_ERROR;
-	}
-
-	if (flags & DC_EXEC) {
-		switch (p2) {
-		case OFB_FULL_LOAD:
-			TOGGLEBIT(order->flags, OFB_FULL_LOAD);
-			if (order->type != OT_GOTO_DEPOT) CLRBIT(order->flags, OFB_UNLOAD);
-			break;
-		case OFB_UNLOAD:
-			TOGGLEBIT(order->flags, OFB_UNLOAD);
-			CLRBIT(order->flags, OFB_FULL_LOAD);
-			break;
-		case OFB_NON_STOP:
-			TOGGLEBIT(order->flags, OFB_NON_STOP);
-			break;
-		case OFB_TRANSFER:
-			TOGGLEBIT(order->flags, OFB_TRANSFER);
-			break;
-		default: NOT_REACHED();
-		}
-
-		/* Update the windows and full load flags, also for vehicles that share the same order list */
-		{
-			Vehicle* u;
-
-			u = GetFirstVehicleFromSharedList(v);
-			DeleteOrderWarnings(u);
-			for (; u != NULL; u = u->next_shared) {
-				/* Toggle u->current_order "Full load" flag if it changed.
-				 * However, as the same flag is used for depot orders, check
-				 * whether we are not going to a depot as there are three
-				 * cases where the full load flag can be active and only
-				 * one case where the flag is used for depot orders. In the
-				 * other cases for the OrderType the flags are not used,
-				 * so do not care and those orders should not be active
-				 * when this function is called.
-				 */
-				if (sel_ord == u->cur_order_index &&
-						u->current_order.type != OT_GOTO_DEPOT &&
-						HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) {
-					TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD);
-				}
-				InvalidateVehicleOrder(u);
-			}
-		}
-	}
-
-	return 0;
-}
-
-/** Clone/share/copy an order-list of an other vehicle.
- * @param p1 various bitstuffed elements
- * - p1 = (bit  0-15) - destination vehicle to clone orders to (p1 & 0xFFFF)
- * - p1 = (bit 16-31) - source vehicle to clone orders from, if any (none for CO_UNSHARE)
- * @param p2 mode of cloning: CO_SHARE, CO_COPY, or CO_UNSHARE
- */
-int32 CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *dst;
-	VehicleID veh_src = GB(p1, 16, 16);
-	VehicleID veh_dst = GB(p1,  0, 16);
-
-	if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
-
-	dst = GetVehicle(veh_dst);
-
-	if (!CheckOwnership(dst->owner)) return CMD_ERROR;
-
-	switch (p2) {
-		case CO_SHARE: {
-			Vehicle *src;
-
-			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
-
-			src = GetVehicle(veh_src);
-
-			/* Sanity checks */
-			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
-				return CMD_ERROR;
-
-			/* Trucks can't share orders with busses (and visa versa) */
-			if (src->type == VEH_Road) {
-				if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
-					return CMD_ERROR;
-			}
-
-			/* Is the vehicle already in the shared list? */
-			{
-				const Vehicle* u;
-
-				for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
-					if (u == dst) return CMD_ERROR;
-				}
-			}
-
-			if (flags & DC_EXEC) {
-				/* If the destination vehicle had a OrderList, destroy it */
-				DeleteVehicleOrders(dst);
-
-				dst->orders = src->orders;
-				dst->num_orders = src->num_orders;
-
-				/* Link this vehicle in the shared-list */
-				dst->next_shared = src->next_shared;
-				dst->prev_shared = src;
-				if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
-				src->next_shared = dst;
-
-				InvalidateVehicleOrder(dst);
-				InvalidateVehicleOrder(src);
-
-				RebuildVehicleLists();
-			}
-		} break;
-
-		case CO_COPY: {
-			Vehicle *src;
-			int delta;
-
-			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
-
-			src = GetVehicle(veh_src);
-
-			/* Sanity checks */
-			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
-				return CMD_ERROR;
-
-			/* Trucks can't copy all the orders from busses (and visa versa) */
-			if (src->type == VEH_Road) {
-				const Order *order;
-				TileIndex required_dst = INVALID_TILE;
-
-				FOR_VEHICLE_ORDERS(src, order) {
-					if (order->type == OT_GOTO_STATION) {
-						const Station *st = GetStation(order->dest);
-						if (dst->cargo_type == CT_PASSENGERS) {
-							if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
-						} else {
-							if (st->truck_stops != NULL) required_dst = st->truck_stops->xy;
-						}
-						/* This station has not the correct road-bay, so we can't copy! */
-						if (required_dst == INVALID_TILE)
-							return CMD_ERROR;
-					}
-				}
-			}
-
-			/* make sure there are orders available */
-			delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
-			if (!HasOrderPoolFree(delta))
-				return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
-
-			if (flags & DC_EXEC) {
-				const Order *order;
-				Order **order_dst;
-
-				/* If the destination vehicle had a OrderList, destroy it */
-				DeleteVehicleOrders(dst);
-
-				order_dst = &dst->orders;
-				FOR_VEHICLE_ORDERS(src, order) {
-					*order_dst = AllocateOrder();
-					AssignOrder(*order_dst, *order);
-					order_dst = &(*order_dst)->next;
-				}
-
-				dst->num_orders = src->num_orders;
-
-				InvalidateVehicleOrder(dst);
-
-				RebuildVehicleLists();
-			}
-		} break;
-
-		case CO_UNSHARE: return DecloneOrder(dst, flags);
-		default: return CMD_ERROR;
-	}
-
-	return 0;
-}
-
-/** Add/remove refit orders from an order
- * @param tile Not used
- * @param p1 VehicleIndex of the vehicle having the order
- * @param p2 bitmask
- *   - bit 0-7 CargoID
- *   - bit 8-15 Cargo subtype
- *   - bit 16-23 number of order to modify
- */
-int32 CmdOrderRefit(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	const Vehicle *v;
-	Order *order;
-	VehicleID veh = GB(p1, 0, 16);
-	VehicleOrderID order_number  = GB(p2, 16, 8);
-	CargoID cargo = GB(p2, 0, 8);
-	byte subtype  = GB(p2, 8, 8);
-
-	if (!IsValidVehicleID(veh)) return CMD_ERROR;
-
-	v = GetVehicle(veh);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	order = GetVehicleOrder(v, order_number);
-	if (order == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		Vehicle *u;
-
-		order->refit_cargo = cargo;
-		order->refit_subtype = subtype;
-
-		u = GetFirstVehicleFromSharedList(v);
-		for (; u != NULL; u = u->next_shared) {
-			/* Update any possible open window of the vehicle */
-			InvalidateVehicleOrder(u);
-
-			/* If the vehicle already got the current depot set as current order, then update current order as well */
-			if (u->cur_order_index == order_number && HASBIT(u->current_order.flags, OFB_PART_OF_ORDERS)) {
-				u->current_order.refit_cargo = cargo;
-				u->current_order.refit_subtype = subtype;
-			}
-		}
-	}
-
-	return 0;
-}
-
-/**
- *
- * Backup a vehicle order-list, so you can replace a vehicle
- *  without loosing the order-list
- *
- */
-void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
-{
-	/* Save general info */
-	bak->orderindex       = v->cur_order_index;
-	bak->service_interval = v->service_interval;
-
-	/* Safe custom string, if any */
-	if (!IsCustomName(v->string_id)) {
-		bak->name[0] = '\0';
-	} else {
-		GetName(bak->name, v->string_id & 0x7FF, lastof(bak->name));
-	}
-
-	/* If we have shared orders, store it on a special way */
-	if (IsOrderListShared(v)) {
-		const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
-
-		bak->clone = u->index;
-	} else {
-		/* Else copy the orders */
-		Order *order, *dest;
-
-		dest = bak->order;
-
-		/* We do not have shared orders */
-		bak->clone = INVALID_VEHICLE;
-
-		/* Copy the orders */
-		FOR_VEHICLE_ORDERS(v, order) {
-			*dest = *order;
-			dest++;
-		}
-		/* End the list with an OT_NOTHING */
-		dest->type = OT_NOTHING;
-		dest->next = NULL;
-	}
-}
-
-/**
- *
- * Restore vehicle orders that are backupped via BackupVehicleOrders
- *
- */
-void RestoreVehicleOrders(const Vehicle* v, const BackuppedOrders* bak)
-{
-	uint i;
-
-	/* If we have a custom name, process that */
-	if (bak->name[0] != 0) {
-		_cmd_text = bak->name;
-		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
-	}
-
-	/* If we had shared orders, recover that */
-	if (bak->clone != INVALID_VEHICLE) {
-		DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
-		return;
-	}
-
-	/* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
-	 *  order number is one more than the current amount of orders, and because
-	 *  in network the commands are queued before send, the second insert always
-	 *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
-	for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
-		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
-			break;
-	}
-
-	/* Restore vehicle order-index and service interval */
-	DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
-}
-
-/** Restore the current order-index of a vehicle and sets service-interval.
- * @param tile unused
- * @param p1 the ID of the vehicle
- * @param p2 various bistuffed elements
- * - p2 = (bit  0-15) - current order-index (p2 & 0xFFFF)
- * - p2 = (bit 16-31) - service interval (p2 >> 16)
- * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle
- * as far as I can see. We can store it in BackuppedOrders, and restore it, but
- * but we have no way of seeing it has been tampered with or not, as we have no
- * legit way of knowing what that ID was.@n
- * If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and
- * restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;"
- */
-int32 CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	VehicleOrderID cur_ord = GB(p2,  0, 16);
-	uint16 serv_int = GB(p2, 16, 16);
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	/* Check the vehicle type and ownership, and if the service interval and order are in range */
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-	if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		v->cur_order_index = cur_ord;
-		v->service_interval = serv_int;
-	}
-
-	return 0;
-}
-
-
-static TileIndex GetStationTileForVehicle(const Vehicle* v, const Station* st)
-{
-	switch (v->type) {
-		default: NOT_REACHED();
-		case VEH_Train:     return st->train_tile;
-		case VEH_Aircraft:  return st->airport_tile;
-		case VEH_Ship:      return st->dock_tile;
-		case VEH_Road:
-			if (v->cargo_type == CT_PASSENGERS) {
-				return (st->bus_stops != NULL) ? st->bus_stops->xy : 0;
-			} else {
-				return (st->truck_stops != NULL) ? st->truck_stops->xy : 0;
-			}
-	}
-}
-
-
-/**
- *
- * Check the orders of a vehicle, to see if there are invalid orders and stuff
- *
- */
-void CheckOrders(const Vehicle* v)
-{
-	/* Does the user wants us to check things? */
-	if (_patches.order_review_system == 0) return;
-
-	/* Do nothing for crashed vehicles */
-	if (v->vehstatus & VS_CRASHED) return;
-
-	/* Do nothing for stopped vehicles if setting is '1' */
-	if (_patches.order_review_system == 1 && v->vehstatus & VS_STOPPED)
-		return;
-
-	/* do nothing we we're not the first vehicle in a share-chain */
-	if (v->next_shared != NULL) return;
-
-	/* Only check every 20 days, so that we don't flood the message log */
-	if (v->owner == _local_player && v->day_counter % 20 == 0) {
-		int n_st, problem_type = -1;
-		const Order *order;
-		int message = 0;
-
-		/* Check the order list */
-		n_st = 0;
-
-		FOR_VEHICLE_ORDERS(v, order) {
-			/* Dummy order? */
-			if (order->type == OT_DUMMY) {
-				problem_type = 1;
-				break;
-			}
-			/* Does station have a load-bay for this vehicle? */
-			if (order->type == OT_GOTO_STATION) {
-				const Station* st = GetStation(order->dest);
-				TileIndex required_tile = GetStationTileForVehicle(v, st);
-
-				n_st++;
-				if (required_tile == 0) problem_type = 3;
-			}
-		}
-
-		/* Check if the last and the first order are the same */
-		if (v->num_orders > 1) {
-			const Order* last = GetLastVehicleOrder(v);
-
-			if (v->orders->type  == last->type &&
-					v->orders->flags == last->flags &&
-					v->orders->dest  == last->dest) {
-				problem_type = 2;
-			}
-		}
-
-		/* Do we only have 1 station in our order list? */
-		if (n_st < 2 && problem_type == -1) problem_type = 0;
-
-		/* We don't have a problem */
-		if (problem_type < 0) return;
-
-		message = STR_TRAIN_HAS_TOO_FEW_ORDERS + ((v->type - VEH_Train) << 2) + problem_type;
-		//DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
-
-		SetDParam(0, v->unitnumber);
-		AddNewsItem(
-			message,
-			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
-			v->index,
-			0
-		);
-	}
-}
-
-/**
- * Removes an order from all vehicles. Triggers when, say, a station is removed.
- * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
- * @param destination The destination. Can be a StationID, DepotID or WaypointID.
- */
-void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
-{
-	Vehicle *v;
-
-	/* Aircraft have StationIDs for depot orders and never use DepotIDs
-	 * This fact is handled specially below
-	 */
-
-	/* Go through all vehicles */
-	FOR_ALL_VEHICLES(v) {
-		Order *order;
-		bool invalidate;
-
-		/* Forget about this station if this station is removed */
-		if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
-			v->last_station_visited = INVALID_STATION;
-		}
-
-		order = &v->current_order;
-		if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
-				v->current_order.dest == destination) {
-			order->type = OT_DUMMY;
-			order->flags = 0;
-			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		}
-
-		/* Clear the order from the order-list */
-		invalidate = false;
-		FOR_VEHICLE_ORDERS(v, order) {
-			if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
-					order->dest == destination) {
-				order->type = OT_DUMMY;
-				order->flags = 0;
-				invalidate = true;
-			}
-		}
-
-		/* Only invalidate once, and if needed */
-		if (invalidate) InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
-	}
-}
-
-/**
- *
- * Checks if a vehicle has a GOTO_DEPOT in his order list
- *
- * @return True if this is true (lol ;))
- *
- */
-bool VehicleHasDepotOrders(const Vehicle *v)
-{
-	const Order *order;
-
-	FOR_VEHICLE_ORDERS(v, order) {
-		if (order->type == OT_GOTO_DEPOT)
-			return true;
-	}
-
-	return false;
-}
-
-/**
- *
- * Delete all orders from a vehicle
- *
- */
-void DeleteVehicleOrders(Vehicle *v)
-{
-	Order *cur, *next;
-
-	DeleteOrderWarnings(v);
-
-	/* If we have a shared order-list, don't delete the list, but just
-	    remove our pointer */
-	if (IsOrderListShared(v)) {
-		const Vehicle *u = v;
-
-		v->orders = NULL;
-		v->num_orders = 0;
-
-		/* Unlink ourself */
-		if (v->prev_shared != NULL) {
-			v->prev_shared->next_shared = v->next_shared;
-			u = v->prev_shared;
-		}
-		if (v->next_shared != NULL) {
-			v->next_shared->prev_shared = v->prev_shared;
-			u = v->next_shared;
-		}
-		v->prev_shared = NULL;
-		v->next_shared = NULL;
-
-		/* We only need to update this-one, because if there is a third
-		 *  vehicle which shares the same order-list, nothing will change. If
-		 *  this is the last vehicle, the last line of the order-window
-		 *  will change from Shared order list, to Order list, so it needs
-		 *  an update */
-		InvalidateVehicleOrder(u);
-		return;
-	}
-
-	/* Remove the orders */
-	cur = v->orders;
-	v->orders = NULL;
-	v->num_orders = 0;
-
-	if (cur != NULL) {
-		/* Delete the vehicle list of shared orders, if any */
-		int window_type = 0;
-
-		switch (v->type) {
-			case VEH_Train:    window_type = WC_TRAINS_LIST;   break;
-			case VEH_Road:     window_type = WC_ROADVEH_LIST;  break;
-			case VEH_Ship:     window_type = WC_SHIPS_LIST;    break;
-			case VEH_Aircraft: window_type = WC_AIRCRAFT_LIST; break;
-			default: NOT_REACHED();
-		}
-		DeleteWindowById(window_type, (cur->index << 16) | (v->type << 11) | VLW_SHARED_ORDERS | v->owner);
-	}
-
-	while (cur != NULL) {
-		next = cur->next;
-		DeleteOrder(cur);
-		cur = next;
-	}
-}
-
-/**
- *
- * Check if we share our orders with an other vehicle
- *
- * @return Returns the vehicle who has the same order
- *
- */
-bool IsOrderListShared(const Vehicle *v)
-{
-	return v->next_shared != NULL || v->prev_shared != NULL;
-}
-
-/**
- *
- * Check if a vehicle has any valid orders
- *
- * @return false if there are no valid orders
- *
- */
-bool CheckForValidOrders(const Vehicle* v)
-{
-	const Order *order;
-
-	FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
-
-	return false;
-}
-
-void InitializeOrders(void)
-{
-	CleanPool(&_Order_pool);
-	AddBlockToPool(&_Order_pool);
-
-	_backup_orders_tile = 0;
-}
-
-static const SaveLoad _order_desc[] = {
-	SLE_VAR(Order, type,  SLE_UINT8),
-	SLE_VAR(Order, flags, SLE_UINT8),
-	SLE_VAR(Order, dest,  SLE_UINT16),
-	SLE_REF(Order, next,  REF_ORDER),
-	SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8, 36, SL_MAX_VERSION),
-	SLE_CONDVAR(Order, refit_subtype,  SLE_UINT8, 36, SL_MAX_VERSION),
-
-	/* Leftover from the minor savegame version stuff
-	 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
-	SLE_CONDNULL(10, 5, 35),
-	SLE_END()
-};
-
-static void Save_ORDR(void)
-{
-	Order *order;
-
-	FOR_ALL_ORDERS(order) {
-		SlSetArrayIndex(order->index);
-		SlObject(order, _order_desc);
-	}
-}
-
-static void Load_ORDR(void)
-{
-	if (CheckSavegameVersionOldStyle(5, 2)) {
-		/* Version older than 5.2 did not have a ->next pointer. Convert them
-		    (in the old days, the orderlist was 5000 items big) */
-		uint len = SlGetFieldLength();
-		uint i;
-
-		if (CheckSavegameVersion(5)) {
-			/* Pre-version 5 had an other layout for orders
-			    (uint16 instead of uint32) */
-			uint16 orders[5000];
-
-			len /= sizeof(uint16);
-			assert (len <= lengthof(orders));
-
-			SlArray(orders, len, SLE_UINT16);
-
-			for (i = 0; i < len; ++i) {
-				if (!AddBlockIfNeeded(&_Order_pool, i))
-					error("Orders: failed loading savegame: too many orders");
-
-				AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
-			}
-		} else if (CheckSavegameVersionOldStyle(5, 2)) {
-			uint32 orders[5000];
-
-			len /= sizeof(uint32);
-			assert (len <= lengthof(orders));
-
-			SlArray(orders, len, SLE_UINT32);
-
-			for (i = 0; i < len; ++i) {
-				if (!AddBlockIfNeeded(&_Order_pool, i))
-					error("Orders: failed loading savegame: too many orders");
-
-				AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
-			}
-		}
-
-		/* Update all the next pointer */
-		for (i = 1; i < len; ++i) {
-			/* The orders were built like this:
-			 *   Vehicle one had order[0], and as long as order++.type was not
-			 *   OT_NOTHING, it was part of the order-list of that vehicle */
-			if (GetOrder(i)->type != OT_NOTHING)
-				GetOrder(i - 1)->next = GetOrder(i);
-		}
-	} else {
-		int index;
-
-		while ((index = SlIterateArray()) != -1) {
-			Order *order;
-
-			if (!AddBlockIfNeeded(&_Order_pool, index))
-				error("Orders: failed loading savegame: too many orders");
-
-			order = GetOrder(index);
-			SlObject(order, _order_desc);
-		}
-	}
-}
-
-const ChunkHandler _order_chunk_handlers[] = {
-	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/order_cmd.cpp
@@ -0,0 +1,1278 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "order.h"
+#include "airport.h"
+#include "depot.h"
+#include "functions.h"
+#include "table/strings.h"
+#include "vehicle.h"
+#include "waypoint.h"
+#include "command.h"
+#include "station.h"
+#include "player.h"
+#include "news.h"
+#include "saveload.h"
+#include "vehicle_gui.h"
+
+/**
+ * Called if a new block is added to the order-pool
+ */
+static void OrderPoolNewBlock(uint start_item)
+{
+	Order *order;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (order = GetOrder(start_item); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) order->index = start_item++;
+}
+
+DEFINE_OLD_POOL(Order, Order, OrderPoolNewBlock, NULL)
+
+/**
+ *
+ * Unpacks a order from savegames made with TTD(Patch)
+ *
+ */
+Order UnpackOldOrder(uint16 packed)
+{
+	Order order;
+	order.type    = GB(packed, 0, 4);
+	order.flags   = GB(packed, 4, 4);
+	order.dest    = GB(packed, 8, 8);
+	order.next    = NULL;
+
+	order.refit_cargo   = CT_NO_REFIT;
+	order.refit_subtype = 0;
+	order.index = 0; // avoid compiler warning
+
+	// Sanity check
+	// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
+	if (order.type == OT_NOTHING && (order.flags != 0 || order.dest != 0)) {
+		order.type = OT_DUMMY;
+		order.flags = 0;
+	}
+
+	return order;
+}
+
+/**
+ *
+ * Unpacks a order from savegames with version 4 and lower
+ *
+ */
+static Order UnpackVersion4Order(uint16 packed)
+{
+	Order order;
+	order.type  = GB(packed, 0, 4);
+	order.flags = GB(packed, 4, 4);
+	order.dest  = GB(packed, 8, 8);
+	order.next  = NULL;
+	order.index = 0; // avoid compiler warning
+	order.refit_cargo   = CT_NO_REFIT;
+	order.refit_subtype = 0;
+	return order;
+}
+
+/**
+ *
+ * Updates the widgets of a vehicle which contains the order-data
+ *
+ */
+void InvalidateVehicleOrder(const Vehicle *v)
+{
+	InvalidateWindow(WC_VEHICLE_VIEW,   v->index);
+	InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+}
+
+/**
+ *
+ * Swap two orders
+ *
+ */
+static void SwapOrders(Order *order1, Order *order2)
+{
+	Order temp_order;
+
+	temp_order = *order1;
+	AssignOrder(order1, *order2);
+	order1->next = order2->next;
+	AssignOrder(order2, temp_order);
+	order2->next = temp_order.next;
+}
+
+/**
+ *
+ * Allocate a new order
+ *
+ * @return Order* if a free space is found, else NULL.
+ *
+ */
+static Order *AllocateOrder(void)
+{
+	Order *order;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (order = GetOrder(0); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) {
+		if (!IsValidOrder(order)) {
+			OrderID index = order->index;
+
+			memset(order, 0, sizeof(*order));
+			order->index = index;
+			order->next = NULL;
+			order->refit_cargo   = CT_NO_REFIT;
+			order->refit_subtype = 0;
+
+			return order;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Order_pool)) return AllocateOrder();
+
+	return NULL;
+}
+
+/**
+ *
+ * Assign data to an order (from an other order)
+ *   This function makes sure that the index is maintained correctly
+ *
+ */
+void AssignOrder(Order *order, Order data)
+{
+	order->type  = data.type;
+	order->flags = data.flags;
+	order->dest  = data.dest;
+
+	order->refit_cargo   = data.refit_cargo;
+	order->refit_subtype = data.refit_subtype;
+}
+
+
+/**
+ * Delete all news items regarding defective orders about a vehicle
+ * This could kill still valid warnings (for example about void order when just
+ * another order gets added), but assume the player will notice the problems,
+ * when (s)he's changing the orders.
+ */
+static void DeleteOrderWarnings(const Vehicle* v)
+{
+	DeleteVehicleNews(v->index, STR_TRAIN_HAS_TOO_FEW_ORDERS  + (v->type - VEH_Train) * 4);
+	DeleteVehicleNews(v->index, STR_TRAIN_HAS_VOID_ORDER      + (v->type - VEH_Train) * 4);
+	DeleteVehicleNews(v->index, STR_TRAIN_HAS_DUPLICATE_ENTRY + (v->type - VEH_Train) * 4);
+	DeleteVehicleNews(v->index, STR_TRAIN_HAS_INVALID_ENTRY   + (v->type - VEH_Train) * 4);
+}
+
+
+/** Add an order to the orderlist of a vehicle.
+ * @param tile unused
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit  0 - 15) - ID of the vehicle
+ * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
+ *                        the order will be inserted before that one
+ *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
+ * @param p2 packed order to insert
+ */
+int32 CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	VehicleID veh   = GB(p1,  0, 16);
+	VehicleOrderID sel_ord = GB(p1, 16, 16);
+	Order new_order = UnpackOrder(p2);
+
+	if (!IsValidVehicleID(veh)) return CMD_ERROR;
+
+	v = GetVehicle(veh);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* Check if the inserted order is to the correct destination (owner, type),
+	 * and has the correct flags if any */
+	switch (new_order.type) {
+		case OT_GOTO_STATION: {
+			const Station *st;
+
+			if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
+			st = GetStation(new_order.dest);
+
+			if (st->airport_type != AT_OILRIG && !IsBuoy(st) && !CheckOwnership(st->owner)) {
+				return CMD_ERROR;
+			}
+
+			switch (v->type) {
+				case VEH_Train:
+					if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
+					break;
+
+				case VEH_Road:
+					if (v->cargo_type == CT_PASSENGERS) {
+						if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
+					} else {
+						if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
+					}
+					break;
+
+				case VEH_Ship:
+					if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
+					break;
+
+				case VEH_Aircraft:
+					if (!(st->facilities & FACIL_AIRPORT)) return CMD_ERROR;
+					break;
+
+				default: return CMD_ERROR;
+			}
+
+			/* Order flags can be any of the following for stations:
+			 * [full-load | unload] [+ transfer] [+ non-stop]
+			 * non-stop orders (if any) are only valid for trains */
+			switch (new_order.flags) {
+				case 0:
+				case OF_FULL_LOAD:
+				case OF_FULL_LOAD | OF_TRANSFER:
+				case OF_UNLOAD:
+				case OF_UNLOAD | OF_TRANSFER:
+				case OF_TRANSFER:
+					break;
+
+				case OF_NON_STOP:
+				case OF_NON_STOP | OF_FULL_LOAD:
+				case OF_NON_STOP | OF_FULL_LOAD | OF_TRANSFER:
+				case OF_NON_STOP | OF_UNLOAD:
+				case OF_NON_STOP | OF_UNLOAD | OF_TRANSFER:
+				case OF_NON_STOP | OF_TRANSFER:
+					if (v->type != VEH_Train) return CMD_ERROR;
+					break;
+
+				default: return CMD_ERROR;
+			}
+			break;
+		}
+
+		case OT_GOTO_DEPOT: {
+			if (v->type == VEH_Aircraft) {
+				const Station* st;
+
+				if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
+				st = GetStation(new_order.dest);
+
+				if ((st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
+						!(st->facilities & FACIL_AIRPORT) ||
+						GetAirport(st->airport_type)->nof_depots == 0) {
+					return CMD_ERROR;
+				}
+			} else {
+				const Depot* dp;
+
+				if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
+				dp = GetDepot(new_order.dest);
+
+				if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
+
+				switch (v->type) {
+					case VEH_Train:
+						if (!IsTileDepotType(dp->xy, TRANSPORT_RAIL)) return CMD_ERROR;
+						break;
+
+					case VEH_Road:
+						if (!IsTileDepotType(dp->xy, TRANSPORT_ROAD)) return CMD_ERROR;
+						break;
+
+					case VEH_Ship:
+						if (!IsTileDepotType(dp->xy, TRANSPORT_WATER)) return CMD_ERROR;
+						break;
+
+					default: return CMD_ERROR;
+				}
+			}
+
+			/* Order flags can be any of the following for depots:
+			 * order [+ halt] [+ non-stop]
+			 * non-stop orders (if any) are only valid for trains */
+			switch (new_order.flags) {
+				case OF_PART_OF_ORDERS:
+				case OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
+					break;
+
+				case OF_NON_STOP | OF_PART_OF_ORDERS:
+				case OF_NON_STOP | OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
+					if (v->type != VEH_Train) return CMD_ERROR;
+					break;
+
+				default: return CMD_ERROR;
+			}
+			break;
+		}
+
+		case OT_GOTO_WAYPOINT: {
+			const Waypoint* wp;
+
+			if (v->type != VEH_Train) return CMD_ERROR;
+
+			if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
+			wp = GetWaypoint(new_order.dest);
+
+			if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
+
+			/* Order flags can be any of the following for waypoints:
+			 * [non-stop]
+			 * non-stop orders (if any) are only valid for trains */
+			switch (new_order.flags) {
+				case 0: break;
+
+				case OF_NON_STOP:
+					if (v->type != VEH_Train) return CMD_ERROR;
+					break;
+
+				default: return CMD_ERROR;
+			}
+			break;
+		}
+
+		default: return CMD_ERROR;
+	}
+
+	if (sel_ord > v->num_orders) return CMD_ERROR;
+
+	if (IsOrderPoolFull()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
+
+	/* XXX - This limit is only here because the backuppedorders can't
+	 * handle any more then this.. */
+	if (v->num_orders >= MAX_BACKUP_ORDER_COUNT) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
+
+	/* For ships, make sure that the station is not too far away from the
+	 * previous destination, for human players with new pathfinding disabled */
+	if (v->type == VEH_Ship && IsHumanPlayer(v->owner) &&
+		sel_ord != 0 && GetVehicleOrder(v, sel_ord - 1)->type == OT_GOTO_STATION
+		&& !_patches.new_pathfinding_all) {
+
+		int dist = DistanceManhattan(
+			GetStation(GetVehicleOrder(v, sel_ord - 1)->dest)->xy,
+			GetStation(new_order.dest)->xy // XXX type != OT_GOTO_STATION?
+		);
+		if (dist >= 130)
+			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
+	}
+
+	if (flags & DC_EXEC) {
+		Vehicle *u;
+		Order *new = AllocateOrder();
+		AssignOrder(new, new_order);
+
+		/* Create new order and link in list */
+		if (v->orders == NULL) {
+			v->orders = new;
+		} else {
+			/* Try to get the previous item (we are inserting above the
+			    selected) */
+			Order *order = GetVehicleOrder(v, sel_ord - 1);
+
+			if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) {
+				/* There is no previous item, so we are altering v->orders itself
+				    But because the orders can be shared, we copy the info over
+				    the v->orders, so we don't have to change the pointers of
+				    all vehicles */
+				SwapOrders(v->orders, new);
+				/* Now update the next pointers */
+				v->orders->next = new;
+			} else if (order == NULL) {
+				/* 'sel' is a non-existing order, add him to the end */
+				order = GetLastVehicleOrder(v);
+				order->next = new;
+			} else {
+				/* Put the new order in between */
+				new->next = order->next;
+				order->next = new;
+			}
+		}
+
+		u = GetFirstVehicleFromSharedList(v);
+		DeleteOrderWarnings(u);
+		for (; u != NULL; u = u->next_shared) {
+			/* Increase amount of orders */
+			u->num_orders++;
+
+			/* If the orderlist was empty, assign it */
+			if (u->orders == NULL) u->orders = v->orders;
+
+			assert(v->orders == u->orders);
+
+			/* If there is added an order before the current one, we need
+			to update the selected order */
+			if (sel_ord <= u->cur_order_index) {
+				uint cur = u->cur_order_index + 1;
+				/* Check if we don't go out of bound */
+				if (cur < u->num_orders)
+					u->cur_order_index = cur;
+			}
+			/* Update any possible open window of the vehicle */
+			InvalidateVehicleOrder(u);
+		}
+
+		/* Make sure to rebuild the whole list */
+		RebuildVehicleLists();
+	}
+
+	return 0;
+}
+
+/** Declone an order-list
+ * @param *dst delete the orders of this vehicle
+ * @param flags execution flags
+ */
+static int32 DecloneOrder(Vehicle *dst, uint32 flags)
+{
+	if (flags & DC_EXEC) {
+		DeleteVehicleOrders(dst);
+		InvalidateVehicleOrder(dst);
+		RebuildVehicleLists();
+	}
+	return 0;
+}
+
+/** Delete an order from the orderlist of a vehicle.
+ * @param tile unused
+ * @param p1 the ID of the vehicle
+ * @param p2 the order to delete (max 255)
+ */
+int32 CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v, *u;
+	VehicleID veh_id = p1;
+	VehicleOrderID sel_ord = p2;
+	Order *order;
+
+	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
+
+	v = GetVehicle(veh_id);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* If we did not select an order, we maybe want to de-clone the orders */
+	if (sel_ord >= v->num_orders)
+		return DecloneOrder(v, flags);
+
+	order = GetVehicleOrder(v, sel_ord);
+	if (order == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
+			if (GetVehicleOrder(v, sel_ord + 1) != NULL) {
+				/* First item, but not the last, so we need to alter v->orders
+				    Because we can have shared order, we copy the data
+				    from the next item over the deleted */
+				order = GetVehicleOrder(v, sel_ord + 1);
+				SwapOrders(v->orders, order);
+			} else {
+				/* Last item, so clean the list */
+				v->orders = NULL;
+			}
+		} else {
+			GetVehicleOrder(v, sel_ord - 1)->next = order->next;
+		}
+
+		/* Give the item free */
+		order->type = OT_NOTHING;
+		order->next = NULL;
+
+		u = GetFirstVehicleFromSharedList(v);
+		DeleteOrderWarnings(u);
+		for (; u != NULL; u = u->next_shared) {
+			u->num_orders--;
+
+			if (sel_ord < u->cur_order_index)
+				u->cur_order_index--;
+
+			/* If we removed the last order, make sure the shared vehicles
+			 * also set their orders to NULL */
+			if (v->orders == NULL) u->orders = NULL;
+
+			assert(v->orders == u->orders);
+
+			/* NON-stop flag is misused to see if a train is in a station that is
+			 * on his order list or not */
+			if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
+					HASBIT(u->current_order.flags, OFB_NON_STOP)) {
+				u->current_order.flags = 0;
+			}
+
+			/* Update any possible open window of the vehicle */
+			InvalidateVehicleOrder(u);
+		}
+
+		RebuildVehicleLists();
+	}
+
+	return 0;
+}
+
+/** Goto next order of order-list.
+ * @param tile unused
+ * @param p1 The ID of the vehicle which order is skipped
+ * @param p2 unused
+ */
+int32 CmdSkipOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	VehicleID veh_id = p1;
+
+	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
+
+	v = GetVehicle(veh_id);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		/* Goto next order */
+		VehicleOrderID b = v->cur_order_index + 1;
+		if (b >= v->num_orders) b = 0;
+
+		v->cur_order_index = b;
+
+		if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
+
+		if (v->type == VEH_Road) ClearSlot(v);
+
+		/* NON-stop flag is misused to see if a train is in a station that is
+		 * on his order list or not */
+		if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
+			v->current_order.flags = 0;
+
+		InvalidateVehicleOrder(v);
+	}
+
+	/* We have an aircraft/ship, they have a mini-schedule, so update them all */
+	if (v->type == VEH_Aircraft) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
+	if (v->type == VEH_Ship) InvalidateWindowClasses(WC_SHIPS_LIST);
+
+	return 0;
+}
+
+
+/** Modify an order in the orderlist of a vehicle.
+ * @param tile unused
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit  0 - 15) - ID of the vehicle
+ * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
+ *                        the order will be inserted before that one
+ *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
+ * @param p2 mode to change the order to (always set)
+ */
+int32 CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	Order *order;
+	VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
+	VehicleID veh   = GB(p1,  0, 16);
+
+	if (!IsValidVehicleID(veh)) return CMD_ERROR;
+	if (p2 != OFB_FULL_LOAD && p2 != OFB_UNLOAD && p2 != OFB_NON_STOP && p2 != OFB_TRANSFER) return CMD_ERROR;
+
+	v = GetVehicle(veh);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* Is it a valid order? */
+	if (sel_ord >= v->num_orders) return CMD_ERROR;
+
+	order = GetVehicleOrder(v, sel_ord);
+	if (order->type != OT_GOTO_STATION &&
+			(order->type != OT_GOTO_DEPOT    || p2 == OFB_UNLOAD) &&
+			(order->type != OT_GOTO_WAYPOINT || p2 != OFB_NON_STOP)) {
+		return CMD_ERROR;
+	}
+
+	if (flags & DC_EXEC) {
+		switch (p2) {
+		case OFB_FULL_LOAD:
+			TOGGLEBIT(order->flags, OFB_FULL_LOAD);
+			if (order->type != OT_GOTO_DEPOT) CLRBIT(order->flags, OFB_UNLOAD);
+			break;
+		case OFB_UNLOAD:
+			TOGGLEBIT(order->flags, OFB_UNLOAD);
+			CLRBIT(order->flags, OFB_FULL_LOAD);
+			break;
+		case OFB_NON_STOP:
+			TOGGLEBIT(order->flags, OFB_NON_STOP);
+			break;
+		case OFB_TRANSFER:
+			TOGGLEBIT(order->flags, OFB_TRANSFER);
+			break;
+		default: NOT_REACHED();
+		}
+
+		/* Update the windows and full load flags, also for vehicles that share the same order list */
+		{
+			Vehicle* u;
+
+			u = GetFirstVehicleFromSharedList(v);
+			DeleteOrderWarnings(u);
+			for (; u != NULL; u = u->next_shared) {
+				/* Toggle u->current_order "Full load" flag if it changed.
+				 * However, as the same flag is used for depot orders, check
+				 * whether we are not going to a depot as there are three
+				 * cases where the full load flag can be active and only
+				 * one case where the flag is used for depot orders. In the
+				 * other cases for the OrderType the flags are not used,
+				 * so do not care and those orders should not be active
+				 * when this function is called.
+				 */
+				if (sel_ord == u->cur_order_index &&
+						u->current_order.type != OT_GOTO_DEPOT &&
+						HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) {
+					TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD);
+				}
+				InvalidateVehicleOrder(u);
+			}
+		}
+	}
+
+	return 0;
+}
+
+/** Clone/share/copy an order-list of an other vehicle.
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit  0-15) - destination vehicle to clone orders to (p1 & 0xFFFF)
+ * - p1 = (bit 16-31) - source vehicle to clone orders from, if any (none for CO_UNSHARE)
+ * @param p2 mode of cloning: CO_SHARE, CO_COPY, or CO_UNSHARE
+ */
+int32 CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *dst;
+	VehicleID veh_src = GB(p1, 16, 16);
+	VehicleID veh_dst = GB(p1,  0, 16);
+
+	if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
+
+	dst = GetVehicle(veh_dst);
+
+	if (!CheckOwnership(dst->owner)) return CMD_ERROR;
+
+	switch (p2) {
+		case CO_SHARE: {
+			Vehicle *src;
+
+			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
+
+			src = GetVehicle(veh_src);
+
+			/* Sanity checks */
+			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
+				return CMD_ERROR;
+
+			/* Trucks can't share orders with busses (and visa versa) */
+			if (src->type == VEH_Road) {
+				if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
+					return CMD_ERROR;
+			}
+
+			/* Is the vehicle already in the shared list? */
+			{
+				const Vehicle* u;
+
+				for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
+					if (u == dst) return CMD_ERROR;
+				}
+			}
+
+			if (flags & DC_EXEC) {
+				/* If the destination vehicle had a OrderList, destroy it */
+				DeleteVehicleOrders(dst);
+
+				dst->orders = src->orders;
+				dst->num_orders = src->num_orders;
+
+				/* Link this vehicle in the shared-list */
+				dst->next_shared = src->next_shared;
+				dst->prev_shared = src;
+				if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
+				src->next_shared = dst;
+
+				InvalidateVehicleOrder(dst);
+				InvalidateVehicleOrder(src);
+
+				RebuildVehicleLists();
+			}
+		} break;
+
+		case CO_COPY: {
+			Vehicle *src;
+			int delta;
+
+			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
+
+			src = GetVehicle(veh_src);
+
+			/* Sanity checks */
+			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
+				return CMD_ERROR;
+
+			/* Trucks can't copy all the orders from busses (and visa versa) */
+			if (src->type == VEH_Road) {
+				const Order *order;
+				TileIndex required_dst = INVALID_TILE;
+
+				FOR_VEHICLE_ORDERS(src, order) {
+					if (order->type == OT_GOTO_STATION) {
+						const Station *st = GetStation(order->dest);
+						if (dst->cargo_type == CT_PASSENGERS) {
+							if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
+						} else {
+							if (st->truck_stops != NULL) required_dst = st->truck_stops->xy;
+						}
+						/* This station has not the correct road-bay, so we can't copy! */
+						if (required_dst == INVALID_TILE)
+							return CMD_ERROR;
+					}
+				}
+			}
+
+			/* make sure there are orders available */
+			delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
+			if (!HasOrderPoolFree(delta))
+				return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
+
+			if (flags & DC_EXEC) {
+				const Order *order;
+				Order **order_dst;
+
+				/* If the destination vehicle had a OrderList, destroy it */
+				DeleteVehicleOrders(dst);
+
+				order_dst = &dst->orders;
+				FOR_VEHICLE_ORDERS(src, order) {
+					*order_dst = AllocateOrder();
+					AssignOrder(*order_dst, *order);
+					order_dst = &(*order_dst)->next;
+				}
+
+				dst->num_orders = src->num_orders;
+
+				InvalidateVehicleOrder(dst);
+
+				RebuildVehicleLists();
+			}
+		} break;
+
+		case CO_UNSHARE: return DecloneOrder(dst, flags);
+		default: return CMD_ERROR;
+	}
+
+	return 0;
+}
+
+/** Add/remove refit orders from an order
+ * @param tile Not used
+ * @param p1 VehicleIndex of the vehicle having the order
+ * @param p2 bitmask
+ *   - bit 0-7 CargoID
+ *   - bit 8-15 Cargo subtype
+ *   - bit 16-23 number of order to modify
+ */
+int32 CmdOrderRefit(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	const Vehicle *v;
+	Order *order;
+	VehicleID veh = GB(p1, 0, 16);
+	VehicleOrderID order_number  = GB(p2, 16, 8);
+	CargoID cargo = GB(p2, 0, 8);
+	byte subtype  = GB(p2, 8, 8);
+
+	if (!IsValidVehicleID(veh)) return CMD_ERROR;
+
+	v = GetVehicle(veh);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	order = GetVehicleOrder(v, order_number);
+	if (order == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		Vehicle *u;
+
+		order->refit_cargo = cargo;
+		order->refit_subtype = subtype;
+
+		u = GetFirstVehicleFromSharedList(v);
+		for (; u != NULL; u = u->next_shared) {
+			/* Update any possible open window of the vehicle */
+			InvalidateVehicleOrder(u);
+
+			/* If the vehicle already got the current depot set as current order, then update current order as well */
+			if (u->cur_order_index == order_number && HASBIT(u->current_order.flags, OFB_PART_OF_ORDERS)) {
+				u->current_order.refit_cargo = cargo;
+				u->current_order.refit_subtype = subtype;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *
+ * Backup a vehicle order-list, so you can replace a vehicle
+ *  without loosing the order-list
+ *
+ */
+void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
+{
+	/* Save general info */
+	bak->orderindex       = v->cur_order_index;
+	bak->service_interval = v->service_interval;
+
+	/* Safe custom string, if any */
+	if (!IsCustomName(v->string_id)) {
+		bak->name[0] = '\0';
+	} else {
+		GetName(bak->name, v->string_id & 0x7FF, lastof(bak->name));
+	}
+
+	/* If we have shared orders, store it on a special way */
+	if (IsOrderListShared(v)) {
+		const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
+
+		bak->clone = u->index;
+	} else {
+		/* Else copy the orders */
+		Order *order, *dest;
+
+		dest = bak->order;
+
+		/* We do not have shared orders */
+		bak->clone = INVALID_VEHICLE;
+
+		/* Copy the orders */
+		FOR_VEHICLE_ORDERS(v, order) {
+			*dest = *order;
+			dest++;
+		}
+		/* End the list with an OT_NOTHING */
+		dest->type = OT_NOTHING;
+		dest->next = NULL;
+	}
+}
+
+/**
+ *
+ * Restore vehicle orders that are backupped via BackupVehicleOrders
+ *
+ */
+void RestoreVehicleOrders(const Vehicle* v, const BackuppedOrders* bak)
+{
+	uint i;
+
+	/* If we have a custom name, process that */
+	if (bak->name[0] != 0) {
+		_cmd_text = bak->name;
+		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
+	}
+
+	/* If we had shared orders, recover that */
+	if (bak->clone != INVALID_VEHICLE) {
+		DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
+		return;
+	}
+
+	/* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
+	 *  order number is one more than the current amount of orders, and because
+	 *  in network the commands are queued before send, the second insert always
+	 *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
+	for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
+		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
+			break;
+	}
+
+	/* Restore vehicle order-index and service interval */
+	DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
+}
+
+/** Restore the current order-index of a vehicle and sets service-interval.
+ * @param tile unused
+ * @param p1 the ID of the vehicle
+ * @param p2 various bistuffed elements
+ * - p2 = (bit  0-15) - current order-index (p2 & 0xFFFF)
+ * - p2 = (bit 16-31) - service interval (p2 >> 16)
+ * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle
+ * as far as I can see. We can store it in BackuppedOrders, and restore it, but
+ * but we have no way of seeing it has been tampered with or not, as we have no
+ * legit way of knowing what that ID was.@n
+ * If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and
+ * restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;"
+ */
+int32 CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	VehicleOrderID cur_ord = GB(p2,  0, 16);
+	uint16 serv_int = GB(p2, 16, 16);
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	/* Check the vehicle type and ownership, and if the service interval and order are in range */
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+	if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		v->cur_order_index = cur_ord;
+		v->service_interval = serv_int;
+	}
+
+	return 0;
+}
+
+
+static TileIndex GetStationTileForVehicle(const Vehicle* v, const Station* st)
+{
+	switch (v->type) {
+		default: NOT_REACHED();
+		case VEH_Train:     return st->train_tile;
+		case VEH_Aircraft:  return st->airport_tile;
+		case VEH_Ship:      return st->dock_tile;
+		case VEH_Road:
+			if (v->cargo_type == CT_PASSENGERS) {
+				return (st->bus_stops != NULL) ? st->bus_stops->xy : 0;
+			} else {
+				return (st->truck_stops != NULL) ? st->truck_stops->xy : 0;
+			}
+	}
+}
+
+
+/**
+ *
+ * Check the orders of a vehicle, to see if there are invalid orders and stuff
+ *
+ */
+void CheckOrders(const Vehicle* v)
+{
+	/* Does the user wants us to check things? */
+	if (_patches.order_review_system == 0) return;
+
+	/* Do nothing for crashed vehicles */
+	if (v->vehstatus & VS_CRASHED) return;
+
+	/* Do nothing for stopped vehicles if setting is '1' */
+	if (_patches.order_review_system == 1 && v->vehstatus & VS_STOPPED)
+		return;
+
+	/* do nothing we we're not the first vehicle in a share-chain */
+	if (v->next_shared != NULL) return;
+
+	/* Only check every 20 days, so that we don't flood the message log */
+	if (v->owner == _local_player && v->day_counter % 20 == 0) {
+		int n_st, problem_type = -1;
+		const Order *order;
+		int message = 0;
+
+		/* Check the order list */
+		n_st = 0;
+
+		FOR_VEHICLE_ORDERS(v, order) {
+			/* Dummy order? */
+			if (order->type == OT_DUMMY) {
+				problem_type = 1;
+				break;
+			}
+			/* Does station have a load-bay for this vehicle? */
+			if (order->type == OT_GOTO_STATION) {
+				const Station* st = GetStation(order->dest);
+				TileIndex required_tile = GetStationTileForVehicle(v, st);
+
+				n_st++;
+				if (required_tile == 0) problem_type = 3;
+			}
+		}
+
+		/* Check if the last and the first order are the same */
+		if (v->num_orders > 1) {
+			const Order* last = GetLastVehicleOrder(v);
+
+			if (v->orders->type  == last->type &&
+					v->orders->flags == last->flags &&
+					v->orders->dest  == last->dest) {
+				problem_type = 2;
+			}
+		}
+
+		/* Do we only have 1 station in our order list? */
+		if (n_st < 2 && problem_type == -1) problem_type = 0;
+
+		/* We don't have a problem */
+		if (problem_type < 0) return;
+
+		message = STR_TRAIN_HAS_TOO_FEW_ORDERS + ((v->type - VEH_Train) << 2) + problem_type;
+		//DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
+
+		SetDParam(0, v->unitnumber);
+		AddNewsItem(
+			message,
+			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
+			v->index,
+			0
+		);
+	}
+}
+
+/**
+ * Removes an order from all vehicles. Triggers when, say, a station is removed.
+ * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
+ * @param destination The destination. Can be a StationID, DepotID or WaypointID.
+ */
+void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
+{
+	Vehicle *v;
+
+	/* Aircraft have StationIDs for depot orders and never use DepotIDs
+	 * This fact is handled specially below
+	 */
+
+	/* Go through all vehicles */
+	FOR_ALL_VEHICLES(v) {
+		Order *order;
+		bool invalidate;
+
+		/* Forget about this station if this station is removed */
+		if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
+			v->last_station_visited = INVALID_STATION;
+		}
+
+		order = &v->current_order;
+		if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
+				v->current_order.dest == destination) {
+			order->type = OT_DUMMY;
+			order->flags = 0;
+			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		}
+
+		/* Clear the order from the order-list */
+		invalidate = false;
+		FOR_VEHICLE_ORDERS(v, order) {
+			if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
+					order->dest == destination) {
+				order->type = OT_DUMMY;
+				order->flags = 0;
+				invalidate = true;
+			}
+		}
+
+		/* Only invalidate once, and if needed */
+		if (invalidate) InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+	}
+}
+
+/**
+ *
+ * Checks if a vehicle has a GOTO_DEPOT in his order list
+ *
+ * @return True if this is true (lol ;))
+ *
+ */
+bool VehicleHasDepotOrders(const Vehicle *v)
+{
+	const Order *order;
+
+	FOR_VEHICLE_ORDERS(v, order) {
+		if (order->type == OT_GOTO_DEPOT)
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ *
+ * Delete all orders from a vehicle
+ *
+ */
+void DeleteVehicleOrders(Vehicle *v)
+{
+	Order *cur, *next;
+
+	DeleteOrderWarnings(v);
+
+	/* If we have a shared order-list, don't delete the list, but just
+	    remove our pointer */
+	if (IsOrderListShared(v)) {
+		const Vehicle *u = v;
+
+		v->orders = NULL;
+		v->num_orders = 0;
+
+		/* Unlink ourself */
+		if (v->prev_shared != NULL) {
+			v->prev_shared->next_shared = v->next_shared;
+			u = v->prev_shared;
+		}
+		if (v->next_shared != NULL) {
+			v->next_shared->prev_shared = v->prev_shared;
+			u = v->next_shared;
+		}
+		v->prev_shared = NULL;
+		v->next_shared = NULL;
+
+		/* We only need to update this-one, because if there is a third
+		 *  vehicle which shares the same order-list, nothing will change. If
+		 *  this is the last vehicle, the last line of the order-window
+		 *  will change from Shared order list, to Order list, so it needs
+		 *  an update */
+		InvalidateVehicleOrder(u);
+		return;
+	}
+
+	/* Remove the orders */
+	cur = v->orders;
+	v->orders = NULL;
+	v->num_orders = 0;
+
+	if (cur != NULL) {
+		/* Delete the vehicle list of shared orders, if any */
+		int window_type = 0;
+
+		switch (v->type) {
+			case VEH_Train:    window_type = WC_TRAINS_LIST;   break;
+			case VEH_Road:     window_type = WC_ROADVEH_LIST;  break;
+			case VEH_Ship:     window_type = WC_SHIPS_LIST;    break;
+			case VEH_Aircraft: window_type = WC_AIRCRAFT_LIST; break;
+			default: NOT_REACHED();
+		}
+		DeleteWindowById(window_type, (cur->index << 16) | (v->type << 11) | VLW_SHARED_ORDERS | v->owner);
+	}
+
+	while (cur != NULL) {
+		next = cur->next;
+		DeleteOrder(cur);
+		cur = next;
+	}
+}
+
+/**
+ *
+ * Check if we share our orders with an other vehicle
+ *
+ * @return Returns the vehicle who has the same order
+ *
+ */
+bool IsOrderListShared(const Vehicle *v)
+{
+	return v->next_shared != NULL || v->prev_shared != NULL;
+}
+
+/**
+ *
+ * Check if a vehicle has any valid orders
+ *
+ * @return false if there are no valid orders
+ *
+ */
+bool CheckForValidOrders(const Vehicle* v)
+{
+	const Order *order;
+
+	FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
+
+	return false;
+}
+
+void InitializeOrders(void)
+{
+	CleanPool(&_Order_pool);
+	AddBlockToPool(&_Order_pool);
+
+	_backup_orders_tile = 0;
+}
+
+static const SaveLoad _order_desc[] = {
+	SLE_VAR(Order, type,  SLE_UINT8),
+	SLE_VAR(Order, flags, SLE_UINT8),
+	SLE_VAR(Order, dest,  SLE_UINT16),
+	SLE_REF(Order, next,  REF_ORDER),
+	SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8, 36, SL_MAX_VERSION),
+	SLE_CONDVAR(Order, refit_subtype,  SLE_UINT8, 36, SL_MAX_VERSION),
+
+	/* Leftover from the minor savegame version stuff
+	 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
+	SLE_CONDNULL(10, 5, 35),
+	SLE_END()
+};
+
+static void Save_ORDR(void)
+{
+	Order *order;
+
+	FOR_ALL_ORDERS(order) {
+		SlSetArrayIndex(order->index);
+		SlObject(order, _order_desc);
+	}
+}
+
+static void Load_ORDR(void)
+{
+	if (CheckSavegameVersionOldStyle(5, 2)) {
+		/* Version older than 5.2 did not have a ->next pointer. Convert them
+		    (in the old days, the orderlist was 5000 items big) */
+		uint len = SlGetFieldLength();
+		uint i;
+
+		if (CheckSavegameVersion(5)) {
+			/* Pre-version 5 had an other layout for orders
+			    (uint16 instead of uint32) */
+			uint16 orders[5000];
+
+			len /= sizeof(uint16);
+			assert (len <= lengthof(orders));
+
+			SlArray(orders, len, SLE_UINT16);
+
+			for (i = 0; i < len; ++i) {
+				if (!AddBlockIfNeeded(&_Order_pool, i))
+					error("Orders: failed loading savegame: too many orders");
+
+				AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
+			}
+		} else if (CheckSavegameVersionOldStyle(5, 2)) {
+			uint32 orders[5000];
+
+			len /= sizeof(uint32);
+			assert (len <= lengthof(orders));
+
+			SlArray(orders, len, SLE_UINT32);
+
+			for (i = 0; i < len; ++i) {
+				if (!AddBlockIfNeeded(&_Order_pool, i))
+					error("Orders: failed loading savegame: too many orders");
+
+				AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
+			}
+		}
+
+		/* Update all the next pointer */
+		for (i = 1; i < len; ++i) {
+			/* The orders were built like this:
+			 *   Vehicle one had order[0], and as long as order++.type was not
+			 *   OT_NOTHING, it was part of the order-list of that vehicle */
+			if (GetOrder(i)->type != OT_NOTHING)
+				GetOrder(i - 1)->next = GetOrder(i);
+		}
+	} else {
+		int index;
+
+		while ((index = SlIterateArray()) != -1) {
+			Order *order;
+
+			if (!AddBlockIfNeeded(&_Order_pool, index))
+				error("Orders: failed loading savegame: too many orders");
+
+			order = GetOrder(index);
+			SlObject(order, _order_desc);
+		}
+	}
+}
+
+const ChunkHandler _order_chunk_handlers[] = {
+	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/order_gui.c
+++ /dev/null
@@ -1,664 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "road_map.h"
-#include "station_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "vehicle.h"
-#include "station.h"
-#include "town.h"
-#include "command.h"
-#include "viewport.h"
-#include "depot.h"
-#include "waypoint.h"
-#include "train.h"
-#include "water_map.h"
-#include "vehicle_gui.h"
-
-static int OrderGetSel(const Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	int num = WP(w,order_d).sel;
-
-	return (num >= 0 && num < v->num_orders) ? num : v->num_orders;
-}
-
-static StringID StationOrderStrings[] = {
-	STR_8806_GO_TO,
-	STR_8807_GO_TO_TRANSFER,
-	STR_8808_GO_TO_UNLOAD,
-	STR_8809_GO_TO_TRANSFER_UNLOAD,
-	STR_880A_GO_TO_LOAD,
-	STR_880B_GO_TO_TRANSFER_LOAD,
-	STR_NULL,
-	STR_NULL,
-	STR_880C_GO_NON_STOP_TO,
-	STR_880D_GO_TO_NON_STOP_TRANSFER,
-	STR_880E_GO_NON_STOP_TO_UNLOAD,
-	STR_880F_GO_TO_NON_STOP_TRANSFER_UNLOAD,
-	STR_8810_GO_NON_STOP_TO_LOAD,
-	STR_8811_GO_TO_NON_STOP_TRANSFER_LOAD,
-	STR_NULL
-};
-
-static void DrawOrdersWindow(Window *w)
-{
-	const Vehicle *v;
-	const Order *order;
-	StringID str;
-	int sel;
-	int y, i;
-	bool shared_orders;
-	byte color;
-
-	v = GetVehicle(w->window_number);
-
-	shared_orders = IsOrderListShared(v);
-
-	SetVScrollCount(w, v->num_orders + 1);
-
-	sel = OrderGetSel(w);
-	SetDParam(2, STR_8827_FULL_LOAD);
-
-	order = GetVehicleOrder(v, sel);
-
-	if (v->owner == _local_player) {
-		/* skip */
-		SetWindowWidgetDisabledState(w,  4, v->num_orders == 0);
-
-		/* delete */
-		SetWindowWidgetDisabledState(w,  5,
-				(uint)v->num_orders + (shared_orders ? 1 : 0) <= (uint)WP(w, order_d).sel);
-
-		/* non-stop only for trains */
-		SetWindowWidgetDisabledState(w,  6, v->type != VEH_Train || order == NULL);
-		SetWindowWidgetDisabledState(w,  8, order == NULL); // full load
-		SetWindowWidgetDisabledState(w,  9, order == NULL); // unload
-		SetWindowWidgetDisabledState(w, 10, order == NULL); // transfer
-		/* Disable list of vehicles with the same shared orders if there is no list */
-		SetWindowWidgetDisabledState(w, 11, !shared_orders || v->orders == NULL);
-		SetWindowWidgetDisabledState(w, 12, order == NULL); // Refit
-		HideWindowWidget(w, 12); // Refit
-	} else {
-		DisableWindowWidget(w, 10);
-	}
-
-	ShowWindowWidget(w, 9); // Unload
-
-	if (order != NULL) {
-		switch (order->type) {
-			case OT_GOTO_STATION: break;
-
-			case OT_GOTO_DEPOT:
-				DisableWindowWidget(w, 10);
-
-				/* Remove unload and replace it with refit */
-				HideWindowWidget(w,  9);
-				ShowWindowWidget(w, 12);
-				SetDParam(2,STR_SERVICE);
-				break;
-
-			case OT_GOTO_WAYPOINT:
-				DisableWindowWidget(w,  8);
-				DisableWindowWidget(w,  9);
-				DisableWindowWidget(w, 10);
-				break;
-
-			default: // every other orders
-				DisableWindowWidget(w, 6);
-				DisableWindowWidget(w, 8);
-				DisableWindowWidget(w, 9);
-		}
-	}
-
-	SetDParam(0, v->string_id);
-	SetDParam(1, v->unitnumber);
-	DrawWindowWidgets(w);
-
-	y = 15;
-
-	i = w->vscroll.pos;
-	order = GetVehicleOrder(v, i);
-	while (order != NULL) {
-		str = (v->cur_order_index == i) ? STR_8805 : STR_8804;
-		SetDParam(3, STR_EMPTY);
-
-		if (i - w->vscroll.pos < w->vscroll.cap) {
-			SetDParam(1, 6);
-
-			switch (order->type) {
-				case OT_GOTO_STATION:
-					SetDParam(1, StationOrderStrings[order->flags]);
-					SetDParam(2, order->dest);
-					break;
-
-				case OT_GOTO_DEPOT: {
-					StringID s = STR_NULL;
-
-					if (v->type == VEH_Aircraft) {
-						s = STR_GO_TO_AIRPORT_HANGAR;
-						SetDParam(2, order->dest);
-					} else {
-						SetDParam(2, GetDepot(order->dest)->town_index);
-
-						switch (v->type) {
-							case VEH_Train: s = (order->flags & OF_NON_STOP) ? STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT : STR_GO_TO_TRAIN_DEPOT; break;
-							case VEH_Road:  s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
-							case VEH_Ship:  s = STR_GO_TO_SHIP_DEPOT; break;
-							default: break;
-						}
-					}
-
-					if (order->flags & OF_FULL_LOAD) s++; /* service at */
-
-					SetDParam(1, s);
-					if (order->refit_cargo < NUM_CARGO) {
-						SetDParam(3, STR_REFIT_ORDER);
-						SetDParam(4, _cargoc.names_s[order->refit_cargo]);
-					} else {
-						SetDParam(3, STR_EMPTY);
-					}
-					break;
-				}
-
-				case OT_GOTO_WAYPOINT:
-					SetDParam(1, (order->flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
-					SetDParam(2, order->dest);
-					break;
-
-				default: break;
-			}
-
-			color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
-			SetDParam(0, i + 1);
-			if (order->type != OT_DUMMY) {
-				DrawString(2, y, str, color);
-			} else {
-				SetDParam(1, STR_INVALID_ORDER);
-				SetDParam(2, order->dest);
-				DrawString(2, y, str, color);
-			}
-			y += 10;
-		}
-
-		i++;
-		order = order->next;
-	}
-
-	if (i - w->vscroll.pos < w->vscroll.cap) {
-		str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
-		color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
-		DrawString(2, y, str, color);
-	}
-}
-
-static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
-{
-	Order order;
-	order.next  = NULL;
-	order.index = 0;
-	order.refit_cargo   = CT_INVALID;
-	order.refit_subtype = 0;
-
-	// check depot first
-	if (_patches.gotodepot) {
-		switch (GetTileType(tile)) {
-		case MP_RAILWAY:
-			if (v->type == VEH_Train && IsTileOwner(tile, _local_player)) {
-				if (IsRailDepot(tile)) {
-					order.type = OT_GOTO_DEPOT;
-					order.flags = OF_PART_OF_ORDERS;
-					order.dest = GetDepotByTile(tile)->index;
-					return order;
-				}
-			}
-			break;
-
-		case MP_STREET:
-			if (GetRoadTileType(tile) == ROAD_TILE_DEPOT && v->type == VEH_Road && IsTileOwner(tile, _local_player)) {
-				order.type = OT_GOTO_DEPOT;
-				order.flags = OF_PART_OF_ORDERS;
-				order.dest = GetDepotByTile(tile)->index;
-				return order;
-			}
-			break;
-
-		case MP_STATION:
-			if (v->type != VEH_Aircraft) break;
-			if (IsHangar(tile) && IsTileOwner(tile, _local_player)) {
-				order.type = OT_GOTO_DEPOT;
-				order.flags = OF_PART_OF_ORDERS;
-				order.dest = GetStationIndex(tile);
-				return order;
-			}
-			break;
-
-		case MP_WATER:
-			if (v->type != VEH_Ship) break;
-			if (IsTileDepotType(tile, TRANSPORT_WATER) &&
-					IsTileOwner(tile, _local_player)) {
-				TileIndex tile2 = GetOtherShipDepotTile(tile);
-
-				order.type = OT_GOTO_DEPOT;
-				order.flags = OF_PART_OF_ORDERS;
-				order.dest = GetDepotByTile(tile < tile2 ? tile : tile2)->index;
-				return order;
-			}
-
-			default:
-				break;
-		}
-	}
-
-	// check waypoint
-	if (IsTileType(tile, MP_RAILWAY) &&
-			v->type == VEH_Train &&
-			IsTileOwner(tile, _local_player) &&
-			IsRailWaypoint(tile)) {
-		order.type = OT_GOTO_WAYPOINT;
-		order.flags = 0;
-		order.dest = GetWaypointByTile(tile)->index;
-		return order;
-	}
-
-	if (IsTileType(tile, MP_STATION)) {
-		StationID st_index = GetStationIndex(tile);
-		const Station *st = GetStation(st_index);
-
-		if (st->owner == _current_player || st->owner == OWNER_NONE) {
-			byte facil;
-			(facil=FACIL_DOCK, v->type == VEH_Ship) ||
-			(facil=FACIL_TRAIN, v->type == VEH_Train) ||
-			(facil=FACIL_AIRPORT, v->type == VEH_Aircraft) ||
-			(facil=FACIL_BUS_STOP, v->type == VEH_Road && v->cargo_type == CT_PASSENGERS) ||
-			(facil=FACIL_TRUCK_STOP, 1);
-			if (st->facilities & facil) {
-				order.type = OT_GOTO_STATION;
-				order.flags = 0;
-				order.dest = st_index;
-				return order;
-			}
-		}
-	}
-
-	// not found
-	order.type = OT_NOTHING;
-	order.flags = 0;
-	order.dest = INVALID_STATION;
-	return order;
-}
-
-static bool HandleOrderVehClick(const Vehicle *v, const Vehicle *u, Window *w)
-{
-	if (u->type != v->type) return false;
-
-	if (u->type == VEH_Train && !IsFrontEngine(u)) {
-		u = GetFirstVehicleInChain(u);
-		if (!IsFrontEngine(u)) return false;
-	}
-
-	// v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
-	// obviously if you press CTRL on a non-empty orders vehicle you know what you are doing
-	if (v->num_orders != 0 && _ctrl_pressed == 0) return false;
-
-	if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? 0 : 1, NULL,
-		_ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
-		WP(w,order_d).sel = -1;
-		ResetObjectToPlace();
-	}
-
-	return true;
-}
-
-static void OrdersPlaceObj(const Vehicle *v, TileIndex tile, Window *w)
-{
-	Order cmd;
-	const Vehicle *u;
-
-	// check if we're clicking on a vehicle first.. clone orders in that case.
-	u = CheckMouseOverVehicle();
-	if (u != NULL && HandleOrderVehClick(v, u, w)) return;
-
-	cmd = GetOrderCmdFromTile(v, tile);
-	if (cmd.type == OT_NOTHING) return;
-
-	if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), PackOrder(&cmd), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
-		if (WP(w,order_d).sel != -1) WP(w,order_d).sel++;
-		ResetObjectToPlace();
-	}
-}
-
-static void OrderClick_Goto(Window *w, const Vehicle *v)
-{
-	InvalidateWidget(w, 7);
-	ToggleWidgetLoweredState(w, 7);
-	if (IsWindowWidgetLowered(w, 7)) {
-		_place_clicked_vehicle = NULL;
-		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, 1, w);
-	} else {
-		ResetObjectToPlace();
-	}
-}
-
-static void OrderClick_FullLoad(Window *w, const Vehicle *v)
-{
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_FULL_LOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-static void OrderClick_Unload(Window *w, const Vehicle *v)
-{
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_UNLOAD,    NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-static void OrderClick_Nonstop(Window *w, const Vehicle *v)
-{
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_NON_STOP,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-static void OrderClick_Transfer(Window* w, const Vehicle* v)
-{
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) <<  16), OFB_TRANSFER, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-static void OrderClick_Skip(Window *w, const Vehicle *v)
-{
-	DoCommandP(v->tile, v->index, 0, NULL, CMD_SKIP_ORDER);
-}
-
-static void OrderClick_Delete(Window *w, const Vehicle *v)
-{
-	DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
-}
-
-static void OrderClick_Refit(Window *w, const Vehicle *v)
-{
-	if (_ctrl_pressed) {
-		/* Cancel refitting */
-		DoCommandP(v->tile, v->index, (WP(w,order_d).sel << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
-	} else {
-		ShowVehicleRefitWindow(v, WP(w,order_d).sel);
-	}
-}
-
-typedef void OnButtonVehClick(Window *w, const Vehicle *v);
-
-static OnButtonVehClick* const _order_button_proc[] = {
-	OrderClick_Skip,
-	OrderClick_Delete,
-	OrderClick_Nonstop,
-	OrderClick_Goto,
-	OrderClick_FullLoad,
-	OrderClick_Unload,
-	OrderClick_Transfer
-};
-
-static const uint16 _order_keycodes[] = {
-	'D', //skip order
-	'F', //delete order
-	'G', //non-stop
-	'H', //goto order
-	'J', //full load
-	'K'  //unload
-};
-
-static void OrdersWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			/* Move Refit to the same location as Unload
-			 * This will ensure that they always stay at the same location even if Unload is moved in a later commit */
-			w->widget[12].left   = w->widget[9].left;
-			w->widget[12].right  = w->widget[9].right;
-			w->widget[12].top    = w->widget[9].top;
-			w->widget[12].bottom = w->widget[9].bottom;
-			break;
-
-	case WE_PAINT:
-		DrawOrdersWindow(w);
-		break;
-
-	case WE_CLICK: {
-		Vehicle *v = GetVehicle(w->window_number);
-		switch (e->we.click.widget) {
-		case 2: { /* orders list */
-			int sel = (e->we.click.pt.y - 15) / 10;
-
-			if ((uint)sel >= w->vscroll.cap) return;
-
-			sel += w->vscroll.pos;
-
-			if (_ctrl_pressed && sel < v->num_orders) {
-				const Order *ord = GetVehicleOrder(v, sel);
-				TileIndex xy;
-
-				switch (ord->type) {
-					case OT_GOTO_STATION:  xy = GetStation(ord->dest)->xy ; break;
-					case OT_GOTO_DEPOT:    xy = GetDepot(ord->dest)->xy;    break;
-					case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->dest)->xy; break;
-					default:               xy = 0; break;
-				}
-
-				if (xy != 0) ScrollMainWindowToTile(xy);
-				return;
-			}
-
-			if (sel == WP(w,order_d).sel) sel = -1;
-			WP(w,order_d).sel = sel;
-			SetWindowDirty(w);
-		}	break;
-
-		case 4: /* skip button */
-			OrderClick_Skip(w, v);
-			break;
-
-		case 5: /* delete button */
-			OrderClick_Delete(w, v);
-			break;
-
-		case 6: /* non stop button */
-			OrderClick_Nonstop(w, v);
-			break;
-
-		case 7: /* goto button */
-			OrderClick_Goto(w, v);
-			break;
-
-		case 8: /* full load button */
-			OrderClick_FullLoad(w, v);
-			break;
-
-		case 9: /* unload button */
-			OrderClick_Unload(w, v);
-			break;
-		case 10: /* transfer button */
-			OrderClick_Transfer(w, v);
-			break;
-		case 11: /* Vehicle with same shared Orders button */
-			ShowVehWithSharedOrders(v, v->type);
-			break;
-		case 12:
-			OrderClick_Refit(w, v);
-			break;
-		}
-	} break;
-
-	case WE_KEYPRESS: {
-		Vehicle *v = GetVehicle(w->window_number);
-		uint i;
-
-		if (v->owner != _local_player) break;
-
-		for (i = 0; i < lengthof(_order_keycodes); i++) {
-			if (e->we.keypress.keycode == _order_keycodes[i]) {
-				e->we.keypress.cont = false;
-				//see if the button is disabled
-				if (!IsWindowWidgetDisabled(w, i + 4)) _order_button_proc[i](w, v);
-				break;
-			}
-		}
-		break;
-	}
-
-	case WE_RCLICK: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		int s = OrderGetSel(w);
-
-		if (e->we.click.widget != 8) break;
-		if (s == v->num_orders || GetVehicleOrder(v, s)->type != OT_GOTO_DEPOT) {
-			GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);
-		} else {
-			GuiShowTooltips(STR_SERVICE_HINT);
-		}
-	} break;
-
-	case WE_PLACE_OBJ: {
-		OrdersPlaceObj(GetVehicle(w->window_number), e->we.place.tile, w);
-	} break;
-
-	case WE_ABORT_PLACE_OBJ: {
-		RaiseWindowWidget(w, 7);
-		InvalidateWidget(w, 7);
-	} break;
-
-	// check if a vehicle in a depot was clicked..
-	case WE_MOUSELOOP: {
-		const Vehicle *v = _place_clicked_vehicle;
-		/*
-		 * Check if we clicked on a vehicle
-		 * and if the GOTO button of this window is pressed
-		 * This is because of all open order windows WE_MOUSELOOP is called
-		 * and if you have 3 windows open, and this check is not done
-		 * the order is copied to the last open window instead of the
-		 * one where GOTO is enabled
-		 */
-		if (v != NULL && IsWindowWidgetLowered(w, 7)) {
-			_place_clicked_vehicle = NULL;
-			HandleOrderVehClick(GetVehicle(w->window_number), v, w);
-		}
-	} break;
-
-	case WE_RESIZE:
-		/* Update the scroll + matrix */
-		w->vscroll.cap = (w->widget[2].bottom - w->widget[2].top) / 10;
-		break;
-
-	case WE_TIMEOUT: { // handle button unclick ourselves...
-		// unclick all buttons except for the 'goto' button (7), which is 'persistent'
-		uint i;
-		for (i = 0; i < w->widget_count; i++) {
-			if (IsWindowWidgetLowered(w, i) && i != 7) {
-				RaiseWindowWidget(w, i);
-				InvalidateWidget(w, i);
-			}
-		}
-	} break;
-	}
-}
-
-static const Widget _orders_train_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   398,     0,    13, STR_8829_ORDERS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_RB,      14,     0,   386,    14,    75, 0x0,                     STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
-{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   387,   398,    14,    75, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,     0,    52,    76,    87, STR_8823_SKIP,           STR_8853_SKIP_THE_CURRENT_ORDER},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,    53,   105,    76,    87, STR_8824_DELETE,         STR_8854_DELETE_THE_HIGHLIGHTED},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   106,   158,    76,    87, STR_8825_NON_STOP,       STR_8855_MAKE_THE_HIGHLIGHTED_ORDER},
-{    WWT_TEXTBTN,   RESIZE_TB,      14,   159,   211,    76,    87, STR_8826_GO_TO,          STR_8856_INSERT_A_NEW_ORDER_BEFORE},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   212,   264,    76,    87, STR_FULLLOAD_OR_SERVICE, STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   265,   319,    76,    87, STR_8828_UNLOAD,         STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   372,    76,    87, STR_886F_TRANSFER,       STR_886D_MAKE_THE_HIGHLIGHTED_ORDER},
-{ WWT_PUSHIMGBTN,   RESIZE_TB,      14,   373,   386,    76,    87, SPR_SHARED_ORDERS_ICON,  STR_VEH_WITH_SHARED_ORDERS_LIST_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   372,    76,    87, STR_REFIT,               STR_REFIT_TIP},
-{      WWT_PANEL,   RESIZE_RTB,     14,   387,   386,    76,    87, 0x0,                     STR_NULL},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   387,   398,    76,    87, 0x0,                     STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _orders_train_desc = {
-	WDP_AUTO, WDP_AUTO, 399, 88,
-	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
-	_orders_train_widgets,
-	OrdersWndProc
-};
-
-static const Widget _orders_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   409,     0,    13, STR_8829_ORDERS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_RB,      14,     0,   397,    14,    75, 0x0,                     STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
-{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   398,   409,    14,    75, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,     0,    63,    76,    87, STR_8823_SKIP,           STR_8853_SKIP_THE_CURRENT_ORDER},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,    64,   128,    76,    87, STR_8824_DELETE,         STR_8854_DELETE_THE_HIGHLIGHTED},
-{      WWT_EMPTY,   RESIZE_TB,      14,     0,     0,    76,    87, 0x0,                     0x0},
-{    WWT_TEXTBTN,   RESIZE_TB,      14,   129,   192,    76,    87, STR_8826_GO_TO,          STR_8856_INSERT_A_NEW_ORDER_BEFORE},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   193,   256,    76,    87, STR_FULLLOAD_OR_SERVICE, STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   257,   319,    76,    87, STR_8828_UNLOAD,         STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   383,    76,    87, STR_886F_TRANSFER,       STR_886D_MAKE_THE_HIGHLIGHTED_ORDER},
-{ WWT_PUSHIMGBTN,   RESIZE_TB,      14,   384,   397,    76,    87, SPR_SHARED_ORDERS_ICON,  STR_VEH_WITH_SHARED_ORDERS_LIST_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   383,    76,    87, STR_REFIT,               STR_REFIT_TIP},
-{      WWT_PANEL,   RESIZE_RTB,     14,   397,   396,    76,    87, 0x0,                     STR_NULL},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   398,   409,    76,    87, 0x0,                     STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _orders_desc = {
-	WDP_AUTO, WDP_AUTO, 410, 88,
-	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
-	_orders_widgets,
-	OrdersWndProc
-};
-
-static const Widget _other_orders_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   331,     0,    13, STR_A00B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_RB,      14,     0,   319,    14,    75, 0x0,             STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
-{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   320,   331,    14,    75, 0x0,             STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{      WWT_PANEL,   RESIZE_RTB,     14,     0,   319,    76,    87, 0x0,             STR_NULL},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   320,   331,    76,    87, 0x0,             STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _other_orders_desc = {
-	WDP_AUTO, WDP_AUTO, 332, 88,
-	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_other_orders_widgets,
-	OrdersWndProc
-};
-
-void ShowOrdersWindow(const Vehicle *v)
-{
-	Window *w;
-	VehicleID veh = v->index;
-
-	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
-	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
-
-	if (v->owner != _local_player) {
-		w = AllocateWindowDescFront(&_other_orders_desc, veh);
-	} else {
-		w = AllocateWindowDescFront((v->type == VEH_Train) ? &_orders_train_desc : &_orders_desc, veh);
-	}
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		w->vscroll.cap = 6;
-		w->resize.step_height = 10;
-		WP(w,order_d).sel = -1;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/order_gui.cpp
@@ -0,0 +1,664 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "road_map.h"
+#include "station_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "vehicle.h"
+#include "station.h"
+#include "town.h"
+#include "command.h"
+#include "viewport.h"
+#include "depot.h"
+#include "waypoint.h"
+#include "train.h"
+#include "water_map.h"
+#include "vehicle_gui.h"
+
+static int OrderGetSel(const Window *w)
+{
+	const Vehicle *v = GetVehicle(w->window_number);
+	int num = WP(w,order_d).sel;
+
+	return (num >= 0 && num < v->num_orders) ? num : v->num_orders;
+}
+
+static StringID StationOrderStrings[] = {
+	STR_8806_GO_TO,
+	STR_8807_GO_TO_TRANSFER,
+	STR_8808_GO_TO_UNLOAD,
+	STR_8809_GO_TO_TRANSFER_UNLOAD,
+	STR_880A_GO_TO_LOAD,
+	STR_880B_GO_TO_TRANSFER_LOAD,
+	STR_NULL,
+	STR_NULL,
+	STR_880C_GO_NON_STOP_TO,
+	STR_880D_GO_TO_NON_STOP_TRANSFER,
+	STR_880E_GO_NON_STOP_TO_UNLOAD,
+	STR_880F_GO_TO_NON_STOP_TRANSFER_UNLOAD,
+	STR_8810_GO_NON_STOP_TO_LOAD,
+	STR_8811_GO_TO_NON_STOP_TRANSFER_LOAD,
+	STR_NULL
+};
+
+static void DrawOrdersWindow(Window *w)
+{
+	const Vehicle *v;
+	const Order *order;
+	StringID str;
+	int sel;
+	int y, i;
+	bool shared_orders;
+	byte color;
+
+	v = GetVehicle(w->window_number);
+
+	shared_orders = IsOrderListShared(v);
+
+	SetVScrollCount(w, v->num_orders + 1);
+
+	sel = OrderGetSel(w);
+	SetDParam(2, STR_8827_FULL_LOAD);
+
+	order = GetVehicleOrder(v, sel);
+
+	if (v->owner == _local_player) {
+		/* skip */
+		SetWindowWidgetDisabledState(w,  4, v->num_orders == 0);
+
+		/* delete */
+		SetWindowWidgetDisabledState(w,  5,
+				(uint)v->num_orders + (shared_orders ? 1 : 0) <= (uint)WP(w, order_d).sel);
+
+		/* non-stop only for trains */
+		SetWindowWidgetDisabledState(w,  6, v->type != VEH_Train || order == NULL);
+		SetWindowWidgetDisabledState(w,  8, order == NULL); // full load
+		SetWindowWidgetDisabledState(w,  9, order == NULL); // unload
+		SetWindowWidgetDisabledState(w, 10, order == NULL); // transfer
+		/* Disable list of vehicles with the same shared orders if there is no list */
+		SetWindowWidgetDisabledState(w, 11, !shared_orders || v->orders == NULL);
+		SetWindowWidgetDisabledState(w, 12, order == NULL); // Refit
+		HideWindowWidget(w, 12); // Refit
+	} else {
+		DisableWindowWidget(w, 10);
+	}
+
+	ShowWindowWidget(w, 9); // Unload
+
+	if (order != NULL) {
+		switch (order->type) {
+			case OT_GOTO_STATION: break;
+
+			case OT_GOTO_DEPOT:
+				DisableWindowWidget(w, 10);
+
+				/* Remove unload and replace it with refit */
+				HideWindowWidget(w,  9);
+				ShowWindowWidget(w, 12);
+				SetDParam(2,STR_SERVICE);
+				break;
+
+			case OT_GOTO_WAYPOINT:
+				DisableWindowWidget(w,  8);
+				DisableWindowWidget(w,  9);
+				DisableWindowWidget(w, 10);
+				break;
+
+			default: // every other orders
+				DisableWindowWidget(w, 6);
+				DisableWindowWidget(w, 8);
+				DisableWindowWidget(w, 9);
+		}
+	}
+
+	SetDParam(0, v->string_id);
+	SetDParam(1, v->unitnumber);
+	DrawWindowWidgets(w);
+
+	y = 15;
+
+	i = w->vscroll.pos;
+	order = GetVehicleOrder(v, i);
+	while (order != NULL) {
+		str = (v->cur_order_index == i) ? STR_8805 : STR_8804;
+		SetDParam(3, STR_EMPTY);
+
+		if (i - w->vscroll.pos < w->vscroll.cap) {
+			SetDParam(1, 6);
+
+			switch (order->type) {
+				case OT_GOTO_STATION:
+					SetDParam(1, StationOrderStrings[order->flags]);
+					SetDParam(2, order->dest);
+					break;
+
+				case OT_GOTO_DEPOT: {
+					StringID s = STR_NULL;
+
+					if (v->type == VEH_Aircraft) {
+						s = STR_GO_TO_AIRPORT_HANGAR;
+						SetDParam(2, order->dest);
+					} else {
+						SetDParam(2, GetDepot(order->dest)->town_index);
+
+						switch (v->type) {
+							case VEH_Train: s = (order->flags & OF_NON_STOP) ? STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT : STR_GO_TO_TRAIN_DEPOT; break;
+							case VEH_Road:  s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
+							case VEH_Ship:  s = STR_GO_TO_SHIP_DEPOT; break;
+							default: break;
+						}
+					}
+
+					if (order->flags & OF_FULL_LOAD) s++; /* service at */
+
+					SetDParam(1, s);
+					if (order->refit_cargo < NUM_CARGO) {
+						SetDParam(3, STR_REFIT_ORDER);
+						SetDParam(4, _cargoc.names_s[order->refit_cargo]);
+					} else {
+						SetDParam(3, STR_EMPTY);
+					}
+					break;
+				}
+
+				case OT_GOTO_WAYPOINT:
+					SetDParam(1, (order->flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
+					SetDParam(2, order->dest);
+					break;
+
+				default: break;
+			}
+
+			color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
+			SetDParam(0, i + 1);
+			if (order->type != OT_DUMMY) {
+				DrawString(2, y, str, color);
+			} else {
+				SetDParam(1, STR_INVALID_ORDER);
+				SetDParam(2, order->dest);
+				DrawString(2, y, str, color);
+			}
+			y += 10;
+		}
+
+		i++;
+		order = order->next;
+	}
+
+	if (i - w->vscroll.pos < w->vscroll.cap) {
+		str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
+		color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
+		DrawString(2, y, str, color);
+	}
+}
+
+static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
+{
+	Order order;
+	order.next  = NULL;
+	order.index = 0;
+	order.refit_cargo   = CT_INVALID;
+	order.refit_subtype = 0;
+
+	// check depot first
+	if (_patches.gotodepot) {
+		switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			if (v->type == VEH_Train && IsTileOwner(tile, _local_player)) {
+				if (IsRailDepot(tile)) {
+					order.type = OT_GOTO_DEPOT;
+					order.flags = OF_PART_OF_ORDERS;
+					order.dest = GetDepotByTile(tile)->index;
+					return order;
+				}
+			}
+			break;
+
+		case MP_STREET:
+			if (GetRoadTileType(tile) == ROAD_TILE_DEPOT && v->type == VEH_Road && IsTileOwner(tile, _local_player)) {
+				order.type = OT_GOTO_DEPOT;
+				order.flags = OF_PART_OF_ORDERS;
+				order.dest = GetDepotByTile(tile)->index;
+				return order;
+			}
+			break;
+
+		case MP_STATION:
+			if (v->type != VEH_Aircraft) break;
+			if (IsHangar(tile) && IsTileOwner(tile, _local_player)) {
+				order.type = OT_GOTO_DEPOT;
+				order.flags = OF_PART_OF_ORDERS;
+				order.dest = GetStationIndex(tile);
+				return order;
+			}
+			break;
+
+		case MP_WATER:
+			if (v->type != VEH_Ship) break;
+			if (IsTileDepotType(tile, TRANSPORT_WATER) &&
+					IsTileOwner(tile, _local_player)) {
+				TileIndex tile2 = GetOtherShipDepotTile(tile);
+
+				order.type = OT_GOTO_DEPOT;
+				order.flags = OF_PART_OF_ORDERS;
+				order.dest = GetDepotByTile(tile < tile2 ? tile : tile2)->index;
+				return order;
+			}
+
+			default:
+				break;
+		}
+	}
+
+	// check waypoint
+	if (IsTileType(tile, MP_RAILWAY) &&
+			v->type == VEH_Train &&
+			IsTileOwner(tile, _local_player) &&
+			IsRailWaypoint(tile)) {
+		order.type = OT_GOTO_WAYPOINT;
+		order.flags = 0;
+		order.dest = GetWaypointByTile(tile)->index;
+		return order;
+	}
+
+	if (IsTileType(tile, MP_STATION)) {
+		StationID st_index = GetStationIndex(tile);
+		const Station *st = GetStation(st_index);
+
+		if (st->owner == _current_player || st->owner == OWNER_NONE) {
+			byte facil;
+			(facil=FACIL_DOCK, v->type == VEH_Ship) ||
+			(facil=FACIL_TRAIN, v->type == VEH_Train) ||
+			(facil=FACIL_AIRPORT, v->type == VEH_Aircraft) ||
+			(facil=FACIL_BUS_STOP, v->type == VEH_Road && v->cargo_type == CT_PASSENGERS) ||
+			(facil=FACIL_TRUCK_STOP, 1);
+			if (st->facilities & facil) {
+				order.type = OT_GOTO_STATION;
+				order.flags = 0;
+				order.dest = st_index;
+				return order;
+			}
+		}
+	}
+
+	// not found
+	order.type = OT_NOTHING;
+	order.flags = 0;
+	order.dest = INVALID_STATION;
+	return order;
+}
+
+static bool HandleOrderVehClick(const Vehicle *v, const Vehicle *u, Window *w)
+{
+	if (u->type != v->type) return false;
+
+	if (u->type == VEH_Train && !IsFrontEngine(u)) {
+		u = GetFirstVehicleInChain(u);
+		if (!IsFrontEngine(u)) return false;
+	}
+
+	// v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
+	// obviously if you press CTRL on a non-empty orders vehicle you know what you are doing
+	if (v->num_orders != 0 && _ctrl_pressed == 0) return false;
+
+	if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? 0 : 1, NULL,
+		_ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
+		WP(w,order_d).sel = -1;
+		ResetObjectToPlace();
+	}
+
+	return true;
+}
+
+static void OrdersPlaceObj(const Vehicle *v, TileIndex tile, Window *w)
+{
+	Order cmd;
+	const Vehicle *u;
+
+	// check if we're clicking on a vehicle first.. clone orders in that case.
+	u = CheckMouseOverVehicle();
+	if (u != NULL && HandleOrderVehClick(v, u, w)) return;
+
+	cmd = GetOrderCmdFromTile(v, tile);
+	if (cmd.type == OT_NOTHING) return;
+
+	if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), PackOrder(&cmd), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
+		if (WP(w,order_d).sel != -1) WP(w,order_d).sel++;
+		ResetObjectToPlace();
+	}
+}
+
+static void OrderClick_Goto(Window *w, const Vehicle *v)
+{
+	InvalidateWidget(w, 7);
+	ToggleWidgetLoweredState(w, 7);
+	if (IsWindowWidgetLowered(w, 7)) {
+		_place_clicked_vehicle = NULL;
+		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, 1, w);
+	} else {
+		ResetObjectToPlace();
+	}
+}
+
+static void OrderClick_FullLoad(Window *w, const Vehicle *v)
+{
+	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_FULL_LOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+}
+
+static void OrderClick_Unload(Window *w, const Vehicle *v)
+{
+	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_UNLOAD,    NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+}
+
+static void OrderClick_Nonstop(Window *w, const Vehicle *v)
+{
+	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_NON_STOP,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+}
+
+static void OrderClick_Transfer(Window* w, const Vehicle* v)
+{
+	DoCommandP(v->tile, v->index + (OrderGetSel(w) <<  16), OFB_TRANSFER, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+}
+
+static void OrderClick_Skip(Window *w, const Vehicle *v)
+{
+	DoCommandP(v->tile, v->index, 0, NULL, CMD_SKIP_ORDER);
+}
+
+static void OrderClick_Delete(Window *w, const Vehicle *v)
+{
+	DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
+}
+
+static void OrderClick_Refit(Window *w, const Vehicle *v)
+{
+	if (_ctrl_pressed) {
+		/* Cancel refitting */
+		DoCommandP(v->tile, v->index, (WP(w,order_d).sel << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
+	} else {
+		ShowVehicleRefitWindow(v, WP(w,order_d).sel);
+	}
+}
+
+typedef void OnButtonVehClick(Window *w, const Vehicle *v);
+
+static OnButtonVehClick* const _order_button_proc[] = {
+	OrderClick_Skip,
+	OrderClick_Delete,
+	OrderClick_Nonstop,
+	OrderClick_Goto,
+	OrderClick_FullLoad,
+	OrderClick_Unload,
+	OrderClick_Transfer
+};
+
+static const uint16 _order_keycodes[] = {
+	'D', //skip order
+	'F', //delete order
+	'G', //non-stop
+	'H', //goto order
+	'J', //full load
+	'K'  //unload
+};
+
+static void OrdersWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_CREATE:
+			/* Move Refit to the same location as Unload
+			 * This will ensure that they always stay at the same location even if Unload is moved in a later commit */
+			w->widget[12].left   = w->widget[9].left;
+			w->widget[12].right  = w->widget[9].right;
+			w->widget[12].top    = w->widget[9].top;
+			w->widget[12].bottom = w->widget[9].bottom;
+			break;
+
+	case WE_PAINT:
+		DrawOrdersWindow(w);
+		break;
+
+	case WE_CLICK: {
+		Vehicle *v = GetVehicle(w->window_number);
+		switch (e->we.click.widget) {
+		case 2: { /* orders list */
+			int sel = (e->we.click.pt.y - 15) / 10;
+
+			if ((uint)sel >= w->vscroll.cap) return;
+
+			sel += w->vscroll.pos;
+
+			if (_ctrl_pressed && sel < v->num_orders) {
+				const Order *ord = GetVehicleOrder(v, sel);
+				TileIndex xy;
+
+				switch (ord->type) {
+					case OT_GOTO_STATION:  xy = GetStation(ord->dest)->xy ; break;
+					case OT_GOTO_DEPOT:    xy = GetDepot(ord->dest)->xy;    break;
+					case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->dest)->xy; break;
+					default:               xy = 0; break;
+				}
+
+				if (xy != 0) ScrollMainWindowToTile(xy);
+				return;
+			}
+
+			if (sel == WP(w,order_d).sel) sel = -1;
+			WP(w,order_d).sel = sel;
+			SetWindowDirty(w);
+		}	break;
+
+		case 4: /* skip button */
+			OrderClick_Skip(w, v);
+			break;
+
+		case 5: /* delete button */
+			OrderClick_Delete(w, v);
+			break;
+
+		case 6: /* non stop button */
+			OrderClick_Nonstop(w, v);
+			break;
+
+		case 7: /* goto button */
+			OrderClick_Goto(w, v);
+			break;
+
+		case 8: /* full load button */
+			OrderClick_FullLoad(w, v);
+			break;
+
+		case 9: /* unload button */
+			OrderClick_Unload(w, v);
+			break;
+		case 10: /* transfer button */
+			OrderClick_Transfer(w, v);
+			break;
+		case 11: /* Vehicle with same shared Orders button */
+			ShowVehWithSharedOrders(v, v->type);
+			break;
+		case 12:
+			OrderClick_Refit(w, v);
+			break;
+		}
+	} break;
+
+	case WE_KEYPRESS: {
+		Vehicle *v = GetVehicle(w->window_number);
+		uint i;
+
+		if (v->owner != _local_player) break;
+
+		for (i = 0; i < lengthof(_order_keycodes); i++) {
+			if (e->we.keypress.keycode == _order_keycodes[i]) {
+				e->we.keypress.cont = false;
+				//see if the button is disabled
+				if (!IsWindowWidgetDisabled(w, i + 4)) _order_button_proc[i](w, v);
+				break;
+			}
+		}
+		break;
+	}
+
+	case WE_RCLICK: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		int s = OrderGetSel(w);
+
+		if (e->we.click.widget != 8) break;
+		if (s == v->num_orders || GetVehicleOrder(v, s)->type != OT_GOTO_DEPOT) {
+			GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);
+		} else {
+			GuiShowTooltips(STR_SERVICE_HINT);
+		}
+	} break;
+
+	case WE_PLACE_OBJ: {
+		OrdersPlaceObj(GetVehicle(w->window_number), e->we.place.tile, w);
+	} break;
+
+	case WE_ABORT_PLACE_OBJ: {
+		RaiseWindowWidget(w, 7);
+		InvalidateWidget(w, 7);
+	} break;
+
+	// check if a vehicle in a depot was clicked..
+	case WE_MOUSELOOP: {
+		const Vehicle *v = _place_clicked_vehicle;
+		/*
+		 * Check if we clicked on a vehicle
+		 * and if the GOTO button of this window is pressed
+		 * This is because of all open order windows WE_MOUSELOOP is called
+		 * and if you have 3 windows open, and this check is not done
+		 * the order is copied to the last open window instead of the
+		 * one where GOTO is enabled
+		 */
+		if (v != NULL && IsWindowWidgetLowered(w, 7)) {
+			_place_clicked_vehicle = NULL;
+			HandleOrderVehClick(GetVehicle(w->window_number), v, w);
+		}
+	} break;
+
+	case WE_RESIZE:
+		/* Update the scroll + matrix */
+		w->vscroll.cap = (w->widget[2].bottom - w->widget[2].top) / 10;
+		break;
+
+	case WE_TIMEOUT: { // handle button unclick ourselves...
+		// unclick all buttons except for the 'goto' button (7), which is 'persistent'
+		uint i;
+		for (i = 0; i < w->widget_count; i++) {
+			if (IsWindowWidgetLowered(w, i) && i != 7) {
+				RaiseWindowWidget(w, i);
+				InvalidateWidget(w, i);
+			}
+		}
+	} break;
+	}
+}
+
+static const Widget _orders_train_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   398,     0,    13, STR_8829_ORDERS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_RB,      14,     0,   386,    14,    75, 0x0,                     STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
+{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   387,   398,    14,    75, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,     0,    52,    76,    87, STR_8823_SKIP,           STR_8853_SKIP_THE_CURRENT_ORDER},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,    53,   105,    76,    87, STR_8824_DELETE,         STR_8854_DELETE_THE_HIGHLIGHTED},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   106,   158,    76,    87, STR_8825_NON_STOP,       STR_8855_MAKE_THE_HIGHLIGHTED_ORDER},
+{    WWT_TEXTBTN,   RESIZE_TB,      14,   159,   211,    76,    87, STR_8826_GO_TO,          STR_8856_INSERT_A_NEW_ORDER_BEFORE},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   212,   264,    76,    87, STR_FULLLOAD_OR_SERVICE, STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   265,   319,    76,    87, STR_8828_UNLOAD,         STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   372,    76,    87, STR_886F_TRANSFER,       STR_886D_MAKE_THE_HIGHLIGHTED_ORDER},
+{ WWT_PUSHIMGBTN,   RESIZE_TB,      14,   373,   386,    76,    87, SPR_SHARED_ORDERS_ICON,  STR_VEH_WITH_SHARED_ORDERS_LIST_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   372,    76,    87, STR_REFIT,               STR_REFIT_TIP},
+{      WWT_PANEL,   RESIZE_RTB,     14,   387,   386,    76,    87, 0x0,                     STR_NULL},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   387,   398,    76,    87, 0x0,                     STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _orders_train_desc = {
+	WDP_AUTO, WDP_AUTO, 399, 88,
+	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
+	_orders_train_widgets,
+	OrdersWndProc
+};
+
+static const Widget _orders_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   409,     0,    13, STR_8829_ORDERS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_RB,      14,     0,   397,    14,    75, 0x0,                     STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
+{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   398,   409,    14,    75, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,     0,    63,    76,    87, STR_8823_SKIP,           STR_8853_SKIP_THE_CURRENT_ORDER},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,    64,   128,    76,    87, STR_8824_DELETE,         STR_8854_DELETE_THE_HIGHLIGHTED},
+{      WWT_EMPTY,   RESIZE_TB,      14,     0,     0,    76,    87, 0x0,                     0x0},
+{    WWT_TEXTBTN,   RESIZE_TB,      14,   129,   192,    76,    87, STR_8826_GO_TO,          STR_8856_INSERT_A_NEW_ORDER_BEFORE},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   193,   256,    76,    87, STR_FULLLOAD_OR_SERVICE, STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   257,   319,    76,    87, STR_8828_UNLOAD,         STR_8858_MAKE_THE_HIGHLIGHTED_ORDER},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   383,    76,    87, STR_886F_TRANSFER,       STR_886D_MAKE_THE_HIGHLIGHTED_ORDER},
+{ WWT_PUSHIMGBTN,   RESIZE_TB,      14,   384,   397,    76,    87, SPR_SHARED_ORDERS_ICON,  STR_VEH_WITH_SHARED_ORDERS_LIST_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   320,   383,    76,    87, STR_REFIT,               STR_REFIT_TIP},
+{      WWT_PANEL,   RESIZE_RTB,     14,   397,   396,    76,    87, 0x0,                     STR_NULL},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   398,   409,    76,    87, 0x0,                     STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _orders_desc = {
+	WDP_AUTO, WDP_AUTO, 410, 88,
+	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
+	_orders_widgets,
+	OrdersWndProc
+};
+
+static const Widget _other_orders_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   331,     0,    13, STR_A00B_ORDERS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_RB,      14,     0,   319,    14,    75, 0x0,             STR_8852_ORDERS_LIST_CLICK_ON_ORDER},
+{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   320,   331,    14,    75, 0x0,             STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,    14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{      WWT_PANEL,   RESIZE_RTB,     14,     0,   319,    76,    87, 0x0,             STR_NULL},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   320,   331,    76,    87, 0x0,             STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _other_orders_desc = {
+	WDP_AUTO, WDP_AUTO, 332, 88,
+	WC_VEHICLE_ORDERS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_other_orders_widgets,
+	OrdersWndProc
+};
+
+void ShowOrdersWindow(const Vehicle *v)
+{
+	Window *w;
+	VehicleID veh = v->index;
+
+	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
+	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
+
+	if (v->owner != _local_player) {
+		w = AllocateWindowDescFront(&_other_orders_desc, veh);
+	} else {
+		w = AllocateWindowDescFront((v->type == VEH_Train) ? &_orders_train_desc : &_orders_desc, veh);
+	}
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		w->vscroll.cap = 6;
+		w->resize.step_height = 10;
+		WP(w,order_d).sel = -1;
+	}
+}
deleted file mode 100644
--- a/src/os/macosx/G5_detector.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $Id$ */
-
-#include <mach/mach.h>
-#include <mach/mach_host.h>
-#include <mach/host_info.h>
-#include <mach/machine.h>
-#include <stdio.h>
-
-
-#ifndef CPU_SUBTYPE_POWERPC_970
-#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
-#endif
-
-// this function is a lightly modified version of some code from Apple's developer homepage to detect G5 CPUs at runtime
-main()
-{
-	host_basic_info_data_t hostInfo;
-	mach_msg_type_number_t infoCount;
-	boolean_t is_G5;
-
-	infoCount = HOST_BASIC_INFO_COUNT;
-	host_info(mach_host_self(), HOST_BASIC_INFO,
-			  (host_info_t)&hostInfo, &infoCount);
-
-	 is_G5 = ((hostInfo.cpu_type == CPU_TYPE_POWERPC) &&
-			(hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970));
-	 if (is_G5)
-		 printf("1");
-}
new file mode 100644
--- /dev/null
+++ b/src/os/macosx/G5_detector.cpp
@@ -0,0 +1,29 @@
+/* $Id$ */
+
+#include <mach/mach.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <mach/machine.h>
+#include <stdio.h>
+
+
+#ifndef CPU_SUBTYPE_POWERPC_970
+#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
+#endif
+
+// this function is a lightly modified version of some code from Apple's developer homepage to detect G5 CPUs at runtime
+main()
+{
+	host_basic_info_data_t hostInfo;
+	mach_msg_type_number_t infoCount;
+	boolean_t is_G5;
+
+	infoCount = HOST_BASIC_INFO_COUNT;
+	host_info(mach_host_self(), HOST_BASIC_INFO,
+			  (host_info_t)&hostInfo, &infoCount);
+
+	 is_G5 = ((hostInfo.cpu_type == CPU_TYPE_POWERPC) &&
+			(hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970));
+	 if (is_G5)
+		 printf("1");
+}
deleted file mode 100644
--- a/src/os/macosx/splash.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* $Id$ */
-
-#include "../../stdafx.h"
-#include "../../openttd.h"
-#include "../../variables.h"
-#include "../../macros.h"
-#include "../../debug.h"
-#include "../../functions.h"
-#include "../../gfx.h"
-#include "../../fileio.h"
-
-#include "splash.h"
-
-#ifdef WITH_PNG
-
-#include <png.h>
-
-static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
-{
-	DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
-	longjmp(png_ptr->jmpbuf, 1);
-}
-
-static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
-{
-	DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
-}
-
-void DisplaySplashImage(void)
-{
-	png_byte header[8];
-	FILE *f;
-	png_structp png_ptr;
-	png_infop info_ptr, end_info;
-	uint width, height, bit_depth, color_type;
-	png_colorp palette;
-	int num_palette;
-	png_bytep *row_pointers;
-	uint8 *src, *dst;
-	uint y;
-	uint xoff, yoff;
-	int i;
-
-	f = FioFOpenFile(SPLASH_IMAGE_FILE);
-	if (f == NULL) return;
-
-	fread(header, 1, 8, f);
-	if (png_sig_cmp(header, 0, 8) != 0) {
-		fclose(f);
-		return;
-	}
-
-	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning);
-
-	if (png_ptr == NULL) {
-		fclose(f);
-		return;
-	}
-
-	info_ptr = png_create_info_struct(png_ptr);
-	if (info_ptr == NULL) {
-		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
-		fclose(f);
-		return;
-	}
-
-	end_info = png_create_info_struct(png_ptr);
-	if (end_info == NULL) {
-		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
-		fclose(f);
-		return;
-	}
-
-	if (setjmp(png_jmpbuf(png_ptr))) {
-		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-		fclose(f);
-		return;
-	}
-
-	png_init_io(png_ptr, f);
-	png_set_sig_bytes(png_ptr, 8);
-
-	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
-
-	width            = png_get_image_width(png_ptr, info_ptr);
-	height           = png_get_image_height(png_ptr, info_ptr);
-	bit_depth        = png_get_bit_depth(png_ptr, info_ptr);
-	color_type       = png_get_color_type(png_ptr, info_ptr);
-
-	if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) {
-		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-		fclose(f);
-		return;
-	}
-
-	if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
-		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-		fclose(f);
-		return;
-	}
-
-	png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
-
-	row_pointers = png_get_rows(png_ptr, info_ptr);
-
-	memset(_screen.dst_ptr, 0xff, _screen.pitch * _screen.height);
-
-	if (width > (uint) _screen.width) width = _screen.width;
-	if (height > (uint) _screen.height) height = _screen.height;
-
-	xoff = (_screen.width - width) / 2;
-	yoff = (_screen.height - height) / 2;
-	for (y = 0; y < height; y++) {
-		src = row_pointers[y];
-		dst = ((uint8 *) _screen.dst_ptr) + (yoff + y) * _screen.pitch + xoff;
-
-		memcpy(dst, src, width);
-	}
-
-	for (i = 0; i < num_palette; i++) {
-		_cur_palette[i].r = palette[i].red;
-		_cur_palette[i].g = palette[i].green;
-		_cur_palette[i].b = palette[i].blue;
-	}
-
-	_cur_palette[0xff].r = 0;
-	_cur_palette[0xff].g = 0;
-	_cur_palette[0xff].b = 0;
-
-	_pal_first_dirty = 0;
-	_pal_last_dirty = 0xff;
-
-	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-	fclose(f);
-	return;
-}
-
-
-
-#else /* WITH_PNG */
-
-void DisplaySplashImage(void) {}
-
-#endif /* WITH_PNG */
new file mode 100644
--- /dev/null
+++ b/src/os/macosx/splash.cpp
@@ -0,0 +1,144 @@
+/* $Id$ */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../variables.h"
+#include "../../macros.h"
+#include "../../debug.h"
+#include "../../functions.h"
+#include "../../gfx.h"
+#include "../../fileio.h"
+
+#include "splash.h"
+
+#ifdef WITH_PNG
+
+#include <png.h>
+
+static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
+{
+	DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
+	longjmp(png_ptr->jmpbuf, 1);
+}
+
+static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
+{
+	DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
+}
+
+void DisplaySplashImage(void)
+{
+	png_byte header[8];
+	FILE *f;
+	png_structp png_ptr;
+	png_infop info_ptr, end_info;
+	uint width, height, bit_depth, color_type;
+	png_colorp palette;
+	int num_palette;
+	png_bytep *row_pointers;
+	uint8 *src, *dst;
+	uint y;
+	uint xoff, yoff;
+	int i;
+
+	f = FioFOpenFile(SPLASH_IMAGE_FILE);
+	if (f == NULL) return;
+
+	fread(header, 1, 8, f);
+	if (png_sig_cmp(header, 0, 8) != 0) {
+		fclose(f);
+		return;
+	}
+
+	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning);
+
+	if (png_ptr == NULL) {
+		fclose(f);
+		return;
+	}
+
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+		fclose(f);
+		return;
+	}
+
+	end_info = png_create_info_struct(png_ptr);
+	if (end_info == NULL) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+		fclose(f);
+		return;
+	}
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		fclose(f);
+		return;
+	}
+
+	png_init_io(png_ptr, f);
+	png_set_sig_bytes(png_ptr, 8);
+
+	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+	width            = png_get_image_width(png_ptr, info_ptr);
+	height           = png_get_image_height(png_ptr, info_ptr);
+	bit_depth        = png_get_bit_depth(png_ptr, info_ptr);
+	color_type       = png_get_color_type(png_ptr, info_ptr);
+
+	if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		fclose(f);
+		return;
+	}
+
+	if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		fclose(f);
+		return;
+	}
+
+	png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+
+	row_pointers = png_get_rows(png_ptr, info_ptr);
+
+	memset(_screen.dst_ptr, 0xff, _screen.pitch * _screen.height);
+
+	if (width > (uint) _screen.width) width = _screen.width;
+	if (height > (uint) _screen.height) height = _screen.height;
+
+	xoff = (_screen.width - width) / 2;
+	yoff = (_screen.height - height) / 2;
+	for (y = 0; y < height; y++) {
+		src = row_pointers[y];
+		dst = ((uint8 *) _screen.dst_ptr) + (yoff + y) * _screen.pitch + xoff;
+
+		memcpy(dst, src, width);
+	}
+
+	for (i = 0; i < num_palette; i++) {
+		_cur_palette[i].r = palette[i].red;
+		_cur_palette[i].g = palette[i].green;
+		_cur_palette[i].b = palette[i].blue;
+	}
+
+	_cur_palette[0xff].r = 0;
+	_cur_palette[0xff].g = 0;
+	_cur_palette[0xff].b = 0;
+
+	_pal_first_dirty = 0;
+	_pal_last_dirty = 0xff;
+
+	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+	fclose(f);
+	return;
+}
+
+
+
+#else /* WITH_PNG */
+
+void DisplaySplashImage(void) {}
+
+#endif /* WITH_PNG */
deleted file mode 100644
--- a/src/os2.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "variables.h"
-#include "string.h"
-#include "table/strings.h"
-#include "gfx.h"
-#include "gui.h"
-#include "functions.h"
-#include "macros.h"
-
-#include <direct.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <time.h>
-#include <dos.h>
-
-#define INCL_WIN
-#define INCL_WINCLIPBOARD
-
-#include <os2.h>
-#include <i86.h>
-
-bool FiosIsRoot(const char *file)
-{
-	return path[3] == '\0';
-}
-
-void FiosGetDrives(void)
-{
-	FiosItem *fios;
-	unsigned disk, disk2, save, total;
-
-	_dos_getdrive(&save); // save original drive
-
-	/* get an available drive letter */
-	for (disk = 1;; disk++) {
-		_dos_setdrive(disk, &total);
-		if (disk >= total) return;
-		_dos_getdrive(&disk2);
-
-		if (disk == disk2) {
-			FiosItem *fios = FiosAlloc();
-			fios->type = FIOS_TYPE_DRIVE;
-			fios->mtime = 0;
-			snprintf(fios->name, lengthof(fios->name),  "%c:", 'A' + disk - 1);
-			ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
-		}
-	}
-
-	_dos_setdrive(save, &total); // restore the original drive
-}
-
-bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
-{
-	struct diskfree_t free;
-	char drive = path[0] - 'A' + 1;
-
-	if (tot != NULL && _getdiskfree(drive, &free) == 0) {
-		*tot = free.avail_clusters * free.sectors_per_cluster * free.bytes_per_sector;
-		return true;
-	}
-
-	return false;
-}
-
-bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
-{
-	char filename[MAX_PATH];
-
-	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, ent->d_name);
-	if (stat(filename, sb) != 0) return false;
-
-	return (ent->d_name[0] != '.'); // hidden file
-}
-
-static void ChangeWorkingDirectory(char *exe)
-{
-	char *s = strrchr(exe, '\\');
-	if (s != NULL) {
-		*s = '\0';
-		chdir(exe);
-		*s = '\\';
-	}
-}
-
-void ShowInfo(const char *str)
-{
-	HAB hab;
-	HMQ hmq;
-	ULONG rc;
-
-	// init PM env.
-	hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
-
-	// display the box
-	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_INFORMATION);
-
-	// terminate PM env.
-	WinDestroyMsgQueue(hmq);
-	WinTerminate(hab);
-}
-
-void ShowOSErrorBox(const char *buf)
-{
-	HAB hab;
-	HMQ hmq;
-	ULONG rc;
-
-	// init PM env.
-	hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
-
-	// display the box
-	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, buf, "OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_ERROR);
-
-	// terminate PM env.
-	WinDestroyMsgQueue(hmq);
-	WinTerminate(hab);
-}
-
-int CDECL main(int argc, char* argv[])
-{
-	// change the working directory to enable doubleclicking in UIs
-	ChangeWorkingDirectory(argv[0]);
-
-	_random_seeds[1][1] = _random_seeds[1][0] = _random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
-
-	return ttd_main(argc, argv);
-}
-
-void DeterminePaths(void)
-{
-	char *s;
-
-	_paths.game_data_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.game_data_dir, GAME_DATA_DIR, MAX_PATH);
-	#if defined SECOND_DATA_DIR
-	_paths.second_data_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.second_data_dir, SECOND_DATA_DIR, MAX_PATH);
-	#endif
-
-#if defined(USE_HOMEDIR)
-	{
-		const char *homedir = getenv("HOME");
-
-		if (homedir == NULL) {
-			const struct passwd *pw = getpwuid(getuid());
-			if (pw != NULL) homedir = pw->pw_dir;
-		}
-
-		_paths.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR);
-	}
-
-#else /* not defined(USE_HOMEDIR) */
-
-	_paths.personal_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.personal_dir, PERSONAL_DIR, MAX_PATH);
-
-	// check if absolute or relative path
-	s = strchr(_paths.personal_dir, '\\');
-
-	// add absolute path
-	if (s == NULL || _paths.personal_dir != s) {
-		getcwd(_paths.personal_dir, MAX_PATH);
-		s = strchr(_paths.personal_dir, 0);
-		*s++ = '\\';
-		ttd_strlcpy(s, PERSONAL_DIR, MAX_PATH);
-	}
-
-#endif /* defined(USE_HOMEDIR) */
-
-	s = strchr(_paths.personal_dir, 0);
-
-	// append a / ?
-	if (s[-1] != '\\') strcpy(s, "\\");
-
-	_paths.save_dir = str_fmt("%ssave", _paths.personal_dir);
-	_paths.autosave_dir = str_fmt("%s\\autosave", _paths.save_dir);
-	_paths.scenario_dir = str_fmt("%sscenario", _paths.personal_dir);
-	_paths.heightmap_dir = str_fmt("%sscenario\\heightmap", _paths.personal_dir);
-	_paths.gm_dir = str_fmt("%sgm\\", _paths.game_data_dir);
-	_paths.data_dir = str_fmt("%sdata\\", _paths.game_data_dir);
-
-	if (_config_file == NULL)
-		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
-
-	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
-	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
-
-#if defined CUSTOM_LANG_DIR
-	// sets the search path for lng files to the custom one
-	_paths.lang_dir = malloc( MAX_PATH );
-	ttd_strlcpy( _paths.lang_dir, CUSTOM_LANG_DIR, MAX_PATH);
-#else
-	_paths.lang_dir = str_fmt("%slang\\", _paths.game_data_dir);
-#endif
-
-	// create necessary folders
-	mkdir(_paths.personal_dir);
-	mkdir(_paths.save_dir);
-	mkdir(_paths.autosave_dir);
-	mkdir(_paths.scenario_dir);
-	mkdir(_paths.heightmap_dir);
-}
-
-/**
- * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard
- * and append this up to the maximum length (either absolute or screenlength). If maxlength
- * is zero, we don't care about the screenlength but only about the physical length of the string
- * @param tb @Textbuf type to be changed
- * @return Return true on successfull change of Textbuf, or false otherwise
- */
-bool InsertTextBufferClipboard(Textbuf *tb)
-{
-	HAB hab = 0;
-
-	if (WinOpenClipbrd(hab))
-	{
-		const char* text = (const char*)WinQueryClipbrdData(hab, CF_TEXT);
-
-		if (text != NULL)
-		{
-			uint length = 0;
-			uint width = 0;
-			const char* i;
-
-			for (i = text; IsValidAsciiChar(*i); i++)
-			{
-				uint w;
-
-				if (tb->length + length >= tb->maxlength - 1) break;
-
-				w = GetCharacterWidth(FS_NORMAL, (byte)*i);
-				if (tb->maxwidth != 0 && width + tb->width + w > tb->maxwidth) break;
-
-				width += w;
-				length++;
-			}
-
-			memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
-			memcpy(tb->buf + tb->caretpos, text, length);
-			tb->width += width;
-			tb->caretxoffs += width;
-			tb->length += length;
-			tb->caretpos += length;
-
-			WinCloseClipbrd(hab);
-			return true;
-		}
-
-		WinCloseClipbrd(hab);
-	}
-
-	return false;
-}
-
-
-void CSleep(int milliseconds)
-{
-	delay(milliseconds);
-}
-
-const char *FS2OTTD(const char *name) {return name;}
-const char *OTTD2FS(const char *name) {return name;}
new file mode 100644
--- /dev/null
+++ b/src/os2.cpp
@@ -0,0 +1,266 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "variables.h"
+#include "string.h"
+#include "table/strings.h"
+#include "gfx.h"
+#include "gui.h"
+#include "functions.h"
+#include "macros.h"
+
+#include <direct.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <time.h>
+#include <dos.h>
+
+#define INCL_WIN
+#define INCL_WINCLIPBOARD
+
+#include <os2.h>
+#include <i86.h>
+
+bool FiosIsRoot(const char *file)
+{
+	return path[3] == '\0';
+}
+
+void FiosGetDrives(void)
+{
+	FiosItem *fios;
+	unsigned disk, disk2, save, total;
+
+	_dos_getdrive(&save); // save original drive
+
+	/* get an available drive letter */
+	for (disk = 1;; disk++) {
+		_dos_setdrive(disk, &total);
+		if (disk >= total) return;
+		_dos_getdrive(&disk2);
+
+		if (disk == disk2) {
+			FiosItem *fios = FiosAlloc();
+			fios->type = FIOS_TYPE_DRIVE;
+			fios->mtime = 0;
+			snprintf(fios->name, lengthof(fios->name),  "%c:", 'A' + disk - 1);
+			ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
+		}
+	}
+
+	_dos_setdrive(save, &total); // restore the original drive
+}
+
+bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
+{
+	struct diskfree_t free;
+	char drive = path[0] - 'A' + 1;
+
+	if (tot != NULL && _getdiskfree(drive, &free) == 0) {
+		*tot = free.avail_clusters * free.sectors_per_cluster * free.bytes_per_sector;
+		return true;
+	}
+
+	return false;
+}
+
+bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
+{
+	char filename[MAX_PATH];
+
+	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, ent->d_name);
+	if (stat(filename, sb) != 0) return false;
+
+	return (ent->d_name[0] != '.'); // hidden file
+}
+
+static void ChangeWorkingDirectory(char *exe)
+{
+	char *s = strrchr(exe, '\\');
+	if (s != NULL) {
+		*s = '\0';
+		chdir(exe);
+		*s = '\\';
+	}
+}
+
+void ShowInfo(const char *str)
+{
+	HAB hab;
+	HMQ hmq;
+	ULONG rc;
+
+	// init PM env.
+	hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
+
+	// display the box
+	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_INFORMATION);
+
+	// terminate PM env.
+	WinDestroyMsgQueue(hmq);
+	WinTerminate(hab);
+}
+
+void ShowOSErrorBox(const char *buf)
+{
+	HAB hab;
+	HMQ hmq;
+	ULONG rc;
+
+	// init PM env.
+	hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
+
+	// display the box
+	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, buf, "OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_ERROR);
+
+	// terminate PM env.
+	WinDestroyMsgQueue(hmq);
+	WinTerminate(hab);
+}
+
+int CDECL main(int argc, char* argv[])
+{
+	// change the working directory to enable doubleclicking in UIs
+	ChangeWorkingDirectory(argv[0]);
+
+	_random_seeds[1][1] = _random_seeds[1][0] = _random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
+
+	return ttd_main(argc, argv);
+}
+
+void DeterminePaths(void)
+{
+	char *s;
+
+	_paths.game_data_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.game_data_dir, GAME_DATA_DIR, MAX_PATH);
+	#if defined SECOND_DATA_DIR
+	_paths.second_data_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.second_data_dir, SECOND_DATA_DIR, MAX_PATH);
+	#endif
+
+#if defined(USE_HOMEDIR)
+	{
+		const char *homedir = getenv("HOME");
+
+		if (homedir == NULL) {
+			const struct passwd *pw = getpwuid(getuid());
+			if (pw != NULL) homedir = pw->pw_dir;
+		}
+
+		_paths.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR);
+	}
+
+#else /* not defined(USE_HOMEDIR) */
+
+	_paths.personal_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.personal_dir, PERSONAL_DIR, MAX_PATH);
+
+	// check if absolute or relative path
+	s = strchr(_paths.personal_dir, '\\');
+
+	// add absolute path
+	if (s == NULL || _paths.personal_dir != s) {
+		getcwd(_paths.personal_dir, MAX_PATH);
+		s = strchr(_paths.personal_dir, 0);
+		*s++ = '\\';
+		ttd_strlcpy(s, PERSONAL_DIR, MAX_PATH);
+	}
+
+#endif /* defined(USE_HOMEDIR) */
+
+	s = strchr(_paths.personal_dir, 0);
+
+	// append a / ?
+	if (s[-1] != '\\') strcpy(s, "\\");
+
+	_paths.save_dir = str_fmt("%ssave", _paths.personal_dir);
+	_paths.autosave_dir = str_fmt("%s\\autosave", _paths.save_dir);
+	_paths.scenario_dir = str_fmt("%sscenario", _paths.personal_dir);
+	_paths.heightmap_dir = str_fmt("%sscenario\\heightmap", _paths.personal_dir);
+	_paths.gm_dir = str_fmt("%sgm\\", _paths.game_data_dir);
+	_paths.data_dir = str_fmt("%sdata\\", _paths.game_data_dir);
+
+	if (_config_file == NULL)
+		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
+
+	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
+	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
+
+#if defined CUSTOM_LANG_DIR
+	// sets the search path for lng files to the custom one
+	_paths.lang_dir = malloc( MAX_PATH );
+	ttd_strlcpy( _paths.lang_dir, CUSTOM_LANG_DIR, MAX_PATH);
+#else
+	_paths.lang_dir = str_fmt("%slang\\", _paths.game_data_dir);
+#endif
+
+	// create necessary folders
+	mkdir(_paths.personal_dir);
+	mkdir(_paths.save_dir);
+	mkdir(_paths.autosave_dir);
+	mkdir(_paths.scenario_dir);
+	mkdir(_paths.heightmap_dir);
+}
+
+/**
+ * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard
+ * and append this up to the maximum length (either absolute or screenlength). If maxlength
+ * is zero, we don't care about the screenlength but only about the physical length of the string
+ * @param tb @Textbuf type to be changed
+ * @return Return true on successfull change of Textbuf, or false otherwise
+ */
+bool InsertTextBufferClipboard(Textbuf *tb)
+{
+	HAB hab = 0;
+
+	if (WinOpenClipbrd(hab))
+	{
+		const char* text = (const char*)WinQueryClipbrdData(hab, CF_TEXT);
+
+		if (text != NULL)
+		{
+			uint length = 0;
+			uint width = 0;
+			const char* i;
+
+			for (i = text; IsValidAsciiChar(*i); i++)
+			{
+				uint w;
+
+				if (tb->length + length >= tb->maxlength - 1) break;
+
+				w = GetCharacterWidth(FS_NORMAL, (byte)*i);
+				if (tb->maxwidth != 0 && width + tb->width + w > tb->maxwidth) break;
+
+				width += w;
+				length++;
+			}
+
+			memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
+			memcpy(tb->buf + tb->caretpos, text, length);
+			tb->width += width;
+			tb->caretxoffs += width;
+			tb->length += length;
+			tb->caretpos += length;
+
+			WinCloseClipbrd(hab);
+			return true;
+		}
+
+		WinCloseClipbrd(hab);
+	}
+
+	return false;
+}
+
+
+void CSleep(int milliseconds)
+{
+	delay(milliseconds);
+}
+
+const char *FS2OTTD(const char *name) {return name;}
+const char *OTTD2FS(const char *name) {return name;}
deleted file mode 100644
--- a/src/os_timer.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-
-#undef RDTSC_AVAILABLE
-
-/* rdtsc for MSC_VER, uses simple inline assembly, or _rdtsc
- * from external win64.asm because VS2005 does not support inline assembly */
-#if defined(_MSC_VER) && !defined(RDTSC_AVAILABLE)
-# if defined (_M_AMD64)
-extern uint64 _rdtsc(void);
-#	else
-uint64 _declspec(naked) _rdtsc(void)
-{
-	_asm {
-		rdtsc
-		ret
-	}
-}
-# endif
-# define RDTSC_AVAILABLE
-#endif
-
-/* rdtsc for OS/2. Hopefully this works, who knows */
-#if defined (__WATCOMC__) && !defined(RDTSC_AVAILABLE)
-unsigned __int64 _rdtsc( void);
-# pragma aux _rdtsc = 0x0F 0x31 value [edx eax] parm nomemory modify exact [edx eax] nomemory;
-# define RDTSC_AVAILABLE
-#endif
-
-/* rdtsc for all other *nix-en (hopefully). Use GCC syntax */
-#if defined(__i386__) || defined(__x86_64__) && !defined(RDTSC_AVAILABLE)
-uint64 _rdtsc(void)
-{
-	uint32 high, low;
-	__asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high));
-	return ((uint64)high << 32) | low;
-}
-# define RDTSC_AVAILABLE
-#endif
-
-/* rdtsc for PPC which has this not */
-#if (defined(__POWERPC__) || defined(__powerpc__)) && !defined(RDTSC_AVAILABLE)
-uint64 _rdtsc(void)
-{
-	uint32 high = 0, high2 = 0, low;
-	/* PPC does not have rdtsc, so we cheat by reading the two 32-bit time-counters
-	 * it has, 'Move From Time Base (Upper)'. Since these are two reads, in the
-	 * very unlikely event that the lower part overflows to the upper part while we
-	 * read it; we double-check and reread the registers */
-	asm volatile (
-				  "mftbu %0\n"
-				  "mftb %1\n"
-				  "mftbu %2\n"
-				  "cmpw %3,%4\n"
-				  "bne- $-16\n"
-				  : "=r" (high), "=r" (low), "=r" (high2)
-				  : "0" (high), "2" (high2)
-				  );
-	return ((uint64)high << 32) | low;
-}
-# define RDTSC_AVAILABLE
-#endif
-
-/* In all other cases we have no support for rdtsc. No major issue,
- * you just won't be able to profile your code with TIC()/TOC() */
-#if !defined(RDTSC_AVAILABLE)
-#warning "(non-fatal) No support for rdtsc(), you won't be able to profile with TIC/TOC"
-uint64 _rdtsc(void) {return 0;}
-#endif
new file mode 100644
--- /dev/null
+++ b/src/os_timer.cpp
@@ -0,0 +1,70 @@
+/* $Id$ */
+
+#include "stdafx.h"
+
+#undef RDTSC_AVAILABLE
+
+/* rdtsc for MSC_VER, uses simple inline assembly, or _rdtsc
+ * from external win64.asm because VS2005 does not support inline assembly */
+#if defined(_MSC_VER) && !defined(RDTSC_AVAILABLE)
+# if defined (_M_AMD64)
+extern uint64 _rdtsc(void);
+#	else
+uint64 _declspec(naked) _rdtsc(void)
+{
+	_asm {
+		rdtsc
+		ret
+	}
+}
+# endif
+# define RDTSC_AVAILABLE
+#endif
+
+/* rdtsc for OS/2. Hopefully this works, who knows */
+#if defined (__WATCOMC__) && !defined(RDTSC_AVAILABLE)
+unsigned __int64 _rdtsc( void);
+# pragma aux _rdtsc = 0x0F 0x31 value [edx eax] parm nomemory modify exact [edx eax] nomemory;
+# define RDTSC_AVAILABLE
+#endif
+
+/* rdtsc for all other *nix-en (hopefully). Use GCC syntax */
+#if defined(__i386__) || defined(__x86_64__) && !defined(RDTSC_AVAILABLE)
+uint64 _rdtsc(void)
+{
+	uint32 high, low;
+	__asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high));
+	return ((uint64)high << 32) | low;
+}
+# define RDTSC_AVAILABLE
+#endif
+
+/* rdtsc for PPC which has this not */
+#if (defined(__POWERPC__) || defined(__powerpc__)) && !defined(RDTSC_AVAILABLE)
+uint64 _rdtsc(void)
+{
+	uint32 high = 0, high2 = 0, low;
+	/* PPC does not have rdtsc, so we cheat by reading the two 32-bit time-counters
+	 * it has, 'Move From Time Base (Upper)'. Since these are two reads, in the
+	 * very unlikely event that the lower part overflows to the upper part while we
+	 * read it; we double-check and reread the registers */
+	asm volatile (
+				  "mftbu %0\n"
+				  "mftb %1\n"
+				  "mftbu %2\n"
+				  "cmpw %3,%4\n"
+				  "bne- $-16\n"
+				  : "=r" (high), "=r" (low), "=r" (high2)
+				  : "0" (high), "2" (high2)
+				  );
+	return ((uint64)high << 32) | low;
+}
+# define RDTSC_AVAILABLE
+#endif
+
+/* In all other cases we have no support for rdtsc. No major issue,
+ * you just won't be able to profile your code with TIC()/TOC() */
+#if !defined(RDTSC_AVAILABLE)
+#warning "(non-fatal) No support for rdtsc(), you won't be able to profile with TIC/TOC"
+uint64 _rdtsc(void) {return 0;}
+#endif
deleted file mode 100644
--- a/src/pathfind.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "station_map.h"
-#include "depot.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "pathfind.h"
-#include "rail.h"
-#include "debug.h"
-#include "tunnel_map.h"
-#include "variables.h"
-#include "depot.h"
-
-// remember which tiles we have already visited so we don't visit them again.
-static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
-{
-	uint hash, val, offs;
-	TrackPathFinderLink *link, *new_link;
-	uint bits = 1 << dir;
-
-	if (tpf->disable_tile_hash)
-		return true;
-
-	hash = PATHFIND_HASH_TILE(tile);
-
-	val = tpf->hash_head[hash];
-
-	if (val == 0) {
-		/* unused hash entry, set the appropriate bit in it and return true
-		 * to indicate that a bit was set. */
-		tpf->hash_head[hash] = bits;
-		tpf->hash_tile[hash] = tile;
-		return true;
-	} else if (!(val & 0x8000)) {
-		/* single tile */
-
-		if (tile == tpf->hash_tile[hash]) {
-			/* found another bit for the same tile,
-			 * check if this bit is already set, if so, return false */
-			if (val & bits)
-				return false;
-
-			/* otherwise set the bit and return true to indicate that the bit
-			 * was set */
-			tpf->hash_head[hash] = val | bits;
-			return true;
-		} else {
-			/* two tiles with the same hash, need to make a link */
-
-			/* allocate a link. if out of links, handle this by returning
-			 * that a tile was already visisted. */
-			if (tpf->num_links_left == 0) {
-				return false;
-			}
-			tpf->num_links_left--;
-			link = tpf->new_link++;
-
-			/* move the data that was previously in the hash_??? variables
-			 * to the link struct, and let the hash variables point to the link */
-			link->tile = tpf->hash_tile[hash];
-			tpf->hash_tile[hash] = PATHFIND_GET_LINK_OFFS(tpf, link);
-
-			link->flags = tpf->hash_head[hash];
-			tpf->hash_head[hash] = 0xFFFF; /* multi link */
-
-			link->next = 0xFFFF;
-		}
-	} else {
-		/* a linked list of many tiles,
-		 * find the one corresponding to the tile, if it exists.
-		 * otherwise make a new link */
-
-		offs = tpf->hash_tile[hash];
-		do {
-			link = PATHFIND_GET_LINK_PTR(tpf, offs);
-			if (tile == link->tile) {
-				/* found the tile in the link list,
-				 * check if the bit was alrady set, if so return false to indicate that the
-				 * bit was already set */
-				if (link->flags & bits)
-					return false;
-				link->flags |= bits;
-				return true;
-			}
-		} while ((offs=link->next) != 0xFFFF);
-	}
-
-	/* get here if we need to add a new link to link,
-	 * first, allocate a new link, in the same way as before */
-	if (tpf->num_links_left == 0) {
-			return false;
-	}
-	tpf->num_links_left--;
-	new_link = tpf->new_link++;
-
-	/* then fill the link with the new info, and establish a ptr from the old
-	 * link to the new one */
-	new_link->tile = tile;
-	new_link->flags = bits;
-	new_link->next = 0xFFFF;
-
-	link->next = PATHFIND_GET_LINK_OFFS(tpf, new_link);
-	return true;
-}
-
-static const byte _bits_mask[4] = {
-	0x19,
-	0x16,
-	0x25,
-	0x2A,
-};
-
-static const byte _tpf_new_direction[14] = {
-	0, 1, 0, 1, 2, 1,
-	0, 0,
-	2, 3, 3, 2, 3, 0,
-};
-
-static const byte _tpf_prev_direction[14] = {
-	0, 1, 1, 0, 1, 2,
-	0, 0,
-	2, 3, 2, 3, 0, 3,
-};
-
-
-static const byte _otherdir_mask[4] = {
-	0x10,
-	0,
-	0x5,
-	0x2A,
-};
-
-static void TPFMode2(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
-{
-	uint bits;
-	int i;
-	RememberData rd;
-
-	assert(tpf->tracktype == TRANSPORT_WATER);
-
-	// This addition will sometimes overflow by a single tile.
-	// The use of TILE_MASK here makes sure that we still point at a valid
-	// tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail.
-	tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
-
-	if (++tpf->rd.cur_length > 50)
-		return;
-
-	bits = GetTileTrackStatus(tile, tpf->tracktype);
-	bits = (byte)((bits | (bits >> 8)) & _bits_mask[direction]);
-	if (bits == 0)
-		return;
-
-	assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
-
-	if ( (bits & (bits - 1)) == 0 ) {
-		/* only one direction */
-		i = 0;
-		while (!(bits&1))
-			i++, bits>>=1;
-
-		rd = tpf->rd;
-		goto continue_here;
-	}
-	/* several directions */
-	i=0;
-	do {
-		if (!(bits & 1)) continue;
-		rd = tpf->rd;
-
-		// Change direction 4 times only
-		if ((byte)i != tpf->rd.pft_var6) {
-			if (++tpf->rd.depth > 4) {
-				tpf->rd = rd;
-				return;
-			}
-			tpf->rd.pft_var6 = (byte)i;
-		}
-
-continue_here:;
-		tpf->the_dir = i + (HASBIT(_otherdir_mask[direction], i) ? 8 : 0);
-
-		if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
-			TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
-		}
-
-		tpf->rd = rd;
-	} while (++i, bits>>=1);
-
-}
-
-
-/* Returns the end tile and the length of a tunnel. The length does not
- * include the starting tile (entry), it does include the end tile (exit).
- */
-FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, DiagDirection dir)
-{
-	TileIndexDiff delta = TileOffsByDiagDir(dir);
-	uint z = GetTileZ(tile);
-	FindLengthOfTunnelResult flotr;
-
-	flotr.length = 0;
-
-	dir = ReverseDiagDir(dir);
-	do {
-		flotr.length++;
-		tile += delta;
-	} while(
-		!IsTunnelTile(tile) ||
-		GetTunnelDirection(tile) != dir ||
-		GetTileZ(tile) != z
-	);
-
-	flotr.tile = tile;
-	return flotr;
-}
-
-static const uint16 _tpfmode1_and[4] = { 0x1009, 0x16, 0x520, 0x2A00 };
-
-static uint SkipToEndOfTunnel(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
-{
-	FindLengthOfTunnelResult flotr;
-	TPFSetTileBit(tpf, tile, 14);
-	flotr = FindLengthOfTunnel(tile, direction);
-	tpf->rd.cur_length += flotr.length;
-	TPFSetTileBit(tpf, flotr.tile, 14);
-	return flotr.tile;
-}
-
-const byte _ffb_64[128] = {
- 0,  0,  1,  0,  2,  0,  1,  0,
- 3,  0,  1,  0,  2,  0,  1,  0,
- 4,  0,  1,  0,  2,  0,  1,  0,
- 3,  0,  1,  0,  2,  0,  1,  0,
- 5,  0,  1,  0,  2,  0,  1,  0,
- 3,  0,  1,  0,  2,  0,  1,  0,
- 4,  0,  1,  0,  2,  0,  1,  0,
- 3,  0,  1,  0,  2,  0,  1,  0,
-
- 0,  0,  0,  2,  0,  4,  4,  6,
- 0,  8,  8, 10,  8, 12, 12, 14,
- 0, 16, 16, 18, 16, 20, 20, 22,
-16, 24, 24, 26, 24, 28, 28, 30,
- 0, 32, 32, 34, 32, 36, 36, 38,
-32, 40, 40, 42, 40, 44, 44, 46,
-32, 48, 48, 50, 48, 52, 52, 54,
-48, 56, 56, 58, 56, 60, 60, 62,
-};
-
-static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
-{
-	uint bits;
-	int i;
-	RememberData rd;
-	TileIndex tile_org = tile;
-
-	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		if (IsTunnel(tile)) {
-			if (GetTunnelDirection(tile) != direction ||
-					GetTunnelTransportType(tile) != tpf->tracktype) {
-				return;
-			}
-			tile = SkipToEndOfTunnel(tpf, tile, direction);
-		} else {
-			TileIndex tile_end;
-			if (GetBridgeRampDirection(tile) != direction ||
-					GetBridgeTransportType(tile) != tpf->tracktype) {
-				return;
-			}
-			//fprintf(stderr, "%s: Planning over bridge\n", __func__);
-			// TODO doesn't work - WHAT doesn't work?
-			TPFSetTileBit(tpf, tile, 14);
-			tile_end = GetOtherBridgeEnd(tile);
-			tpf->rd.cur_length += DistanceManhattan(tile, tile_end);
-			tile = tile_end;
-			TPFSetTileBit(tpf, tile, 14);
-		}
-	}
-	tile += TileOffsByDiagDir(direction);
-
-	/* Check in case of rail if the owner is the same */
-	if (tpf->tracktype == TRANSPORT_RAIL) {
-		// don't enter train depot from the back
-		if (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) == direction) return;
-
-		if (IsTileType(tile_org, MP_RAILWAY) || IsTileType(tile_org, MP_STATION) || IsTileType(tile_org, MP_TUNNELBRIDGE))
-			if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE))
-				if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
-	}
-
-	// check if the new tile can be entered from that direction
-	if (tpf->tracktype == TRANSPORT_ROAD) {
-		// road stops and depots now have a track (r4419)
-		// don't enter road stop from the back
-		if (IsRoadStopTile(tile) && ReverseDiagDir(GetRoadStopDir(tile)) != direction) return;
-		// don't enter road depot from the back
-		if (IsTileDepotType(tile, TRANSPORT_ROAD) && ReverseDiagDir(GetRoadDepotDirection(tile)) != direction) return;
-	}
-
-	/* Check if the new tile is a tunnel or bridge head and that the direction
-	 * and transport type match */
-	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		if (IsTunnel(tile)) {
-			if (GetTunnelDirection(tile) != direction ||
-					GetTunnelTransportType(tile) != tpf->tracktype) {
-				return;
-			}
-		} else if (IsBridge(tile)) {
-			if (GetBridgeRampDirection(tile) != direction ||
-					GetBridgeTransportType(tile) != tpf->tracktype) {
-				return;
-			}
-		}
-	}
-
-	tpf->rd.cur_length++;
-
-	bits = GetTileTrackStatus(tile, tpf->tracktype);
-
-	if ((byte)bits != tpf->var2) {
-		bits &= _tpfmode1_and[direction];
-		bits = bits | (bits>>8);
-	}
-	bits &= 0xBF;
-
-	if (bits != 0) {
-		if (!tpf->disable_tile_hash || (tpf->rd.cur_length <= 64 && (KILL_FIRST_BIT(bits) == 0 || ++tpf->rd.depth <= 7))) {
-			do {
-				i = FIND_FIRST_BIT(bits);
-				bits = KILL_FIRST_BIT(bits);
-
-				tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
-				rd = tpf->rd;
-
-				if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
-						!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
-					TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
-				}
-				tpf->rd = rd;
-			} while (bits != 0);
-		}
-	}
-
-	/* the next is only used when signals are checked.
-	 * seems to go in 2 directions simultaneously */
-
-	/* if i can get rid of this, tail end recursion can be used to minimize
-	 * stack space dramatically. */
-
-	/* If we are doing signal setting, we must reverse at evere tile, so we
-	 * iterate all the tracks in a signal block, even when a normal train would
-	 * not reach it (for example, when two lines merge */
-	if (tpf->hasbit_13)
-		return;
-
-	direction = ReverseDiagDir(direction);
-	tile += TileOffsByDiagDir(direction);
-
-	bits = GetTileTrackStatus(tile, tpf->tracktype);
-	bits |= (bits >> 8);
-
-	if ( (byte)bits != tpf->var2) {
-		bits &= _bits_mask[direction];
-	}
-
-	bits &= 0xBF;
-	if (bits == 0)
-		return;
-
-	do {
-		i = FIND_FIRST_BIT(bits);
-		bits = KILL_FIRST_BIT(bits);
-
-		tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
-		rd = tpf->rd;
-		if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
-				!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
-			TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
-		}
-		tpf->rd = rd;
-	} while (bits != 0);
-}
-
-void FollowTrack(TileIndex tile, uint16 flags, DiagDirection direction, TPFEnumProc *enum_proc, TPFAfterProc *after_proc, void *data)
-{
-	TrackPathFinder tpf;
-
-	assert(direction < 4);
-
-	/* initialize path finder variables */
-	tpf.userdata = data;
-	tpf.enum_proc = enum_proc;
-	tpf.new_link = tpf.links;
-	tpf.num_links_left = lengthof(tpf.links);
-
-	tpf.rd.cur_length = 0;
-	tpf.rd.depth = 0;
-	tpf.rd.pft_var6 = 0;
-
-	tpf.var2 = HASBIT(flags, 15) ? 0x43 : 0xFF; /* 0x8000 */
-
-	tpf.disable_tile_hash = HASBIT(flags, 12);  /* 0x1000 */
-	tpf.hasbit_13         = HASBIT(flags, 13);  /* 0x2000 */
-
-
-	tpf.tracktype = (byte)flags;
-
-	if (HASBIT(flags, 11)) {
-		tpf.rd.pft_var6 = 0xFF;
-		tpf.enum_proc(tile, data, 0, 0, 0);
-		TPFMode2(&tpf, tile, direction);
-	} else {
-		/* clear the hash_heads */
-		memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
-		TPFMode1(&tpf, tile, direction);
-	}
-
-	if (after_proc != NULL)
-		after_proc(&tpf);
-}
-
-typedef struct {
-	TileIndex tile;
-	uint16 cur_length; // This is the current length to this tile.
-	uint16 priority; // This is the current length + estimated length to the goal.
-	byte track;
-	byte depth;
-	byte state;
-	byte first_track;
-} StackedItem;
-
-static const byte _new_track[6][4] = {
-{0,    0xff, 8,    0xff,},
-{0xff, 1,    0xff, 9,},
-{0xff, 2,    10,   0xff,},
-{3,    0xff, 0xff, 11,},
-{12,   4,    0xff, 0xff,},
-{0xff, 0xff, 5,    13,},
-};
-
-typedef struct HashLink {
-	TileIndex tile;
-	uint16 typelength;
-	uint16 next;
-} HashLink;
-
-typedef struct {
-	NTPEnumProc *enum_proc;
-	void *userdata;
-	TileIndex dest;
-
-	TransportType tracktype;
-	RailTypeMask railtypes;
-	uint maxlength;
-
-	HashLink *new_link;
-	uint num_links_left;
-
-	uint nstack;
-	StackedItem stack[256]; // priority queue of stacked items
-
-	uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFFC = length, 0x3 = dir
-	TileIndex hash_tile[0x400]; // tiles. or links.
-
-	HashLink links[0x400]; // hash links
-
-} NewTrackPathFinder;
-#define NTP_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
-#define NTP_GET_LINK_PTR(tpf, link_offs) (HashLink*)((byte*)tpf->links + (link_offs))
-
-#define ARR(i) tpf->stack[(i)-1]
-
-// called after a new element was added in the queue at the last index.
-// move it down to the proper position
-static inline void HeapifyUp(NewTrackPathFinder *tpf)
-{
-	StackedItem si;
-	int i = ++tpf->nstack;
-
-	while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
-		// the child element is larger than the parent item.
-		// swap the child item and the parent item.
-		si = ARR(i); ARR(i) = ARR(i>>1); ARR(i>>1) = si;
-		i>>=1;
-	}
-}
-
-// called after the element 0 was eaten. fill it with a new element
-static inline void HeapifyDown(NewTrackPathFinder *tpf)
-{
-	StackedItem si;
-	int i = 1, j;
-	int n;
-
-	assert(tpf->nstack > 0);
-	n = --tpf->nstack;
-
-	if (n == 0) return; // heap is empty so nothing to do?
-
-	// copy the last item to index 0. we use it as base for heapify.
-	ARR(1) = ARR(n+1);
-
-	while ((j=i*2) <= n) {
-		// figure out which is smaller of the children.
-		if (j != n && ARR(j).priority > ARR(j+1).priority)
-			j++; // right item is smaller
-
-		assert(i <= n && j <= n);
-		if (ARR(i).priority <= ARR(j).priority)
-			break; // base elem smaller than smallest, done!
-
-		// swap parent with the child
-		si = ARR(i); ARR(i) = ARR(j); ARR(j) = si;
-		i = j;
-	}
-}
-
-// mark a tile as visited and store the length of the path.
-// if we already had a better path to this tile, return false.
-// otherwise return true.
-static bool NtpVisit(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection dir, uint length)
-{
-	uint hash,head;
-	HashLink *link, *new_link;
-
-	assert(length < 16384-1);
-
-	hash = PATHFIND_HASH_TILE(tile);
-
-	// never visited before?
-	if ((head=tpf->hash_head[hash]) == 0) {
-		tpf->hash_tile[hash] = tile;
-		tpf->hash_head[hash] = dir | (length << 2);
-		return true;
-	}
-
-	if (head != 0xffff) {
-		if (tile == tpf->hash_tile[hash] && (head & 0x3) == dir) {
-
-			// longer length
-			if (length >= (head >> 2)) return false;
-
-			tpf->hash_head[hash] = dir | (length << 2);
-			return true;
-		}
-		// two tiles with the same hash, need to make a link
-		// allocate a link. if out of links, handle this by returning
-		// that a tile was already visisted.
-		if (tpf->num_links_left == 0) {
-			DEBUG(ntp, 1, "No links left");
-			return false;
-		}
-
-		tpf->num_links_left--;
-		link = tpf->new_link++;
-
-		/* move the data that was previously in the hash_??? variables
-		 * to the link struct, and let the hash variables point to the link */
-		link->tile = tpf->hash_tile[hash];
-		tpf->hash_tile[hash] = NTP_GET_LINK_OFFS(tpf, link);
-
-		link->typelength = tpf->hash_head[hash];
-		tpf->hash_head[hash] = 0xFFFF; /* multi link */
-		link->next = 0xFFFF;
-	} else {
-		// a linked list of many tiles,
-		// find the one corresponding to the tile, if it exists.
-		// otherwise make a new link
-
-		uint offs = tpf->hash_tile[hash];
-		do {
-			link = NTP_GET_LINK_PTR(tpf, offs);
-			if (tile == link->tile && (link->typelength & 0x3U) == dir) {
-				if (length >= (uint)(link->typelength >> 2)) return false;
-				link->typelength = dir | (length << 2);
-				return true;
-			}
-		} while ((offs = link->next) != 0xFFFF);
-	}
-
-	/* get here if we need to add a new link to link,
-	 * first, allocate a new link, in the same way as before */
-	if (tpf->num_links_left == 0) {
-		DEBUG(ntp, 1, "No links left");
-		return false;
-	}
-	tpf->num_links_left--;
-	new_link = tpf->new_link++;
-
-	/* then fill the link with the new info, and establish a ptr from the old
-	 * link to the new one */
-	new_link->tile = tile;
-	new_link->typelength = dir | (length << 2);
-	new_link->next = 0xFFFF;
-
-	link->next = NTP_GET_LINK_OFFS(tpf, new_link);
-	return true;
-}
-
-/**
- * Checks if the shortest path to the given tile/dir so far is still the given
- * length.
- * @return true if the length is still the same
- * @pre    The given tile/dir combination should be present in the hash, by a
- *         previous call to NtpVisit().
- */
-static bool NtpCheck(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint length)
-{
-	uint hash,head,offs;
-	HashLink *link;
-
-	hash = PATHFIND_HASH_TILE(tile);
-	head=tpf->hash_head[hash];
-	assert(head);
-
-	if (head != 0xffff) {
-		assert( tpf->hash_tile[hash] == tile && (head & 3) == dir);
-		assert( (head >> 2) <= length);
-		return length == (head >> 2);
-	}
-
-	// else it's a linked list of many tiles
-	offs = tpf->hash_tile[hash];
-	for (;;) {
-		link = NTP_GET_LINK_PTR(tpf, offs);
-		if (tile == link->tile && (link->typelength & 0x3U) == dir) {
-			assert((uint)(link->typelength >> 2) <= length);
-			return length == (uint)(link->typelength >> 2);
-		}
-		offs = link->next;
-		assert(offs != 0xffff);
-	}
-}
-
-
-static const uint16 _is_upwards_slope[15] = {
-	0, // no tileh
-	(1 << TRACKDIR_X_SW) | (1 << TRACKDIR_Y_NW), // 1
-	(1 << TRACKDIR_X_SW) | (1 << TRACKDIR_Y_SE), // 2
-	(1 << TRACKDIR_X_SW), // 3
-	(1 << TRACKDIR_X_NE) | (1 << TRACKDIR_Y_SE), // 4
-	0, // 5
-	(1 << TRACKDIR_Y_SE), // 6
-	0, // 7
-	(1 << TRACKDIR_X_NE) | (1 << TRACKDIR_Y_NW), // 8,
-	(1 << TRACKDIR_Y_NW), // 9
-	0, //10
-	0, //11,
-	(1 << TRACKDIR_X_NE), //12
-	0, //13
-	0, //14
-};
-
-static uint DistanceMoo(TileIndex t0, TileIndex t1)
-{
-	const uint dx = abs(TileX(t0) - TileX(t1));
-	const uint dy = abs(TileY(t0) - TileY(t1));
-
-	const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
-	/* OPTIMISATION:
-	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
-	 * Proof:
-	 * (dx-dy) - straightTracks  == (min + max) - straightTracks = min + // max - 2 * min = max - min */
-	const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
-
-	return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
-}
-
-// These has to be small cause the max length of a track
-// is currently limited to 16384
-
-static const byte _length_of_track[16] = {
-	DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0,
-	DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0
-};
-
-// new more optimized pathfinder for trains...
-// Tile is the tile the train is at.
-// direction is the tile the train is moving towards.
-
-static void NTPEnum(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
-{
-	TrackBits bits, allbits;
-	uint track;
-	TileIndex tile_org;
-	StackedItem si;
-	int estimation;
-
-
-
-	// Need to have a special case for the start.
-	// We shouldn't call the callback for the current tile.
-	si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
-	si.depth = 0;
-	si.state = 0;
-	si.first_track = 0xFF;
-	goto start_at;
-
-	for (;;) {
-		// Get the next item to search from from the priority queue
-		do {
-			if (tpf->nstack == 0)
-				return; // nothing left? then we're done!
-			si = tpf->stack[0];
-			tile = si.tile;
-
-			HeapifyDown(tpf);
-			// Make sure we havn't already visited this tile.
-		} while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
-
-		// Add the length of this track.
-		si.cur_length += _length_of_track[si.track];
-
-callback_and_continue:
-		if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
-			return;
-
-		assert(si.track <= 13);
-		direction = _tpf_new_direction[si.track];
-
-start_at:
-		// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
-		//   need to find the exit of the tunnel.
-		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-			if (IsTunnel(tile)) {
-				if (GetTunnelDirection(tile) != ReverseDiagDir(direction)) {
-					FindLengthOfTunnelResult flotr;
-
-					/* We are not just driving out of the tunnel */
-					if (GetTunnelDirection(tile) != direction ||
-							GetTunnelTransportType(tile) != tpf->tracktype) {
-						// We are not driving into the tunnel, or it is an invalid tunnel
-						continue;
-					}
-					if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
-						bits = 0;
-						break;
-					}
-					flotr = FindLengthOfTunnel(tile, direction);
-					si.cur_length += flotr.length * DIAG_FACTOR;
-					tile = flotr.tile;
-					// tile now points to the exit tile of the tunnel
-				}
-			} else {
-				TileIndex tile_end;
-				if (GetBridgeRampDirection(tile) != ReverseDiagDir(direction)) {
-					// We are not just leaving the bridge
-					if (GetBridgeRampDirection(tile) != direction ||
-							GetBridgeTransportType(tile) != tpf->tracktype) {
-						// Not entering the bridge or not compatible
-						continue;
-					}
-				}
-				tile_end = GetOtherBridgeEnd(tile);
-				si.cur_length += DistanceManhattan(tile, tile_end) * DIAG_FACTOR;
-				tile = tile_end;
-			}
-		}
-
-		// This is a special loop used to go through
-		// a rail net and find the first intersection
-		tile_org = tile;
-		for (;;) {
-			assert(direction <= 3);
-			tile += TileOffsByDiagDir(direction);
-
-			// too long search length? bail out.
-			if (si.cur_length >= tpf->maxlength) {
-				DEBUG(ntp, 1, "Cur_length too big");
-				bits = 0;
-				break;
-			}
-
-			// Not a regular rail tile?
-			// Then we can't use the code below, but revert to more general code.
-			if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
-				// We found a tile which is not a normal railway tile.
-				// Determine which tracks that exist on this tile.
-				bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
-				bits = (bits | (bits >> 8)) & 0x3F;
-
-				// Check that the tile contains exactly one track
-				if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break;
-
-				if (!HASBIT(tpf->railtypes, IsTileType(tile, MP_STREET) ? GetRailTypeCrossing(tile) : GetRailType(tile))) {
-					bits = 0;
-					break;
-				}
-
-				///////////////////
-				// If we reach here, the tile has exactly one track.
-				//   tile - index to a tile that is not rail tile, but still straight (with optional signals)
-				//   bits - bitmask of which track that exist on the tile (exactly one bit is set)
-				//   direction - which direction are we moving in?
-				///////////////////
-				si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
-				si.cur_length += _length_of_track[si.track];
-				goto callback_and_continue;
-			}
-
-			/* Regular rail tile, determine which tracks exist. */
-			allbits = GetTrackBits(tile);
-			/* Which tracks are reachable? */
-			bits = allbits & DiagdirReachesTracks(direction);
-
-			/* The tile has no reachable tracks => End of rail segment
-			 * or Intersection => End of rail segment. We check this agains all the
-			 * bits, not just reachable ones, to prevent infinite loops. */
-			if (bits == 0 || TracksOverlap(allbits)) break;
-
-			if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
-				bits = 0;
-				break;
-			}
-
-			/* If we reach here, the tile has exactly one track, and this
-			 track is reachable => Rail segment continues */
-
-			track = _new_track[FIND_FIRST_BIT(bits)][direction];
-			assert(track != 0xff);
-
-			si.cur_length += _length_of_track[track];
-
-			// Check if this rail is an upwards slope. If it is, then add a penalty.
-			// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
-			if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
-				// upwards slope. add some penalty.
-				si.cur_length += 4*DIAG_FACTOR;
-			}
-
-			// railway tile with signals..?
-			if (HasSignals(tile)) {
-				if (!HasSignalOnTrackdir(tile, track)) {
-					// if one way signal not pointing towards us, stop going in this direction => End of rail segment.
-					if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
-						bits = 0;
-						break;
-					}
-				} else if (GetSignalStateByTrackdir(tile, track) == SIGNAL_STATE_GREEN) {
-					// green signal in our direction. either one way or two way.
-					si.state |= 3;
-				} else {
-					// reached a red signal.
-					if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
-						// two way red signal. unless we passed another green signal on the way,
-						// stop going in this direction => End of rail segment.
-						// this is to prevent us from going into a full platform.
-						if (!(si.state&1)) {
-							bits = 0;
-							break;
-						}
-					}
-					if (!(si.state & 2)) {
-						// Is this the first signal we see? And it's red... add penalty
-						si.cur_length += 10*DIAG_FACTOR;
-						si.state += 2; // remember that we added penalty.
-						// Because we added a penalty, we can't just continue as usual.
-						// Need to get out and let A* do it's job with
-						// possibly finding an even shorter path.
-						break;
-					}
-				}
-
-				if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
-					return; /* Don't process this tile any further */
-			}
-
-			// continue with the next track
-			direction = _tpf_new_direction[track];
-
-			// safety check if we're running around chasing our tail... (infinite loop)
-			if (tile == tile_org) {
-				bits = 0;
-				break;
-			}
-		}
-
-		// There are no tracks to choose between.
-		// Stop searching in this direction
-		if (bits == 0)
-			continue;
-
-		////////////////
-		// We got multiple tracks to choose between (intersection).
-		// Branch the search space into several branches.
-		////////////////
-
-		// Check if we've already visited this intersection.
-		// If we've already visited it with a better length, then
-		// there's no point in visiting it again.
-		if (!NtpVisit(tpf, tile, direction, si.cur_length))
-			continue;
-
-		// Push all possible alternatives that we can reach from here
-		// onto the priority heap.
-		// 'bits' contains the tracks that we can choose between.
-
-		// First compute the estimated distance to the target.
-		// This is used to implement A*
-		estimation = 0;
-		if (tpf->dest != 0)
-			estimation = DistanceMoo(tile, tpf->dest);
-
-		si.depth++;
-		if (si.depth == 0)
-			continue; /* We overflowed our depth. No more searching in this direction. */
-		si.tile = tile;
-		do {
-			si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
-			assert(si.track != 0xFF);
-			si.priority = si.cur_length + estimation;
-
-			// out of stack items, bail out?
-			if (tpf->nstack >= lengthof(tpf->stack)) {
-				DEBUG(ntp, 1, "Out of stack");
-				break;
-			}
-
-			tpf->stack[tpf->nstack] = si;
-			HeapifyUp(tpf);
-		} while ((bits = KILL_FIRST_BIT(bits)) != 0);
-
-		// If this is the first intersection, we need to fill the first_track member.
-		// so the code outside knows which path is better.
-		// also randomize the order in which we search through them.
-		if (si.depth == 1) {
-			assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
-			if (tpf->nstack != 1) {
-				uint32 r = Random();
-				if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
-				if (tpf->nstack != 2) {
-					byte t = tpf->stack[2].track;
-					if (r&2) swap_byte(&tpf->stack[0].track, &t);
-					if (r&4) swap_byte(&tpf->stack[1].track, &t);
-					tpf->stack[2].first_track = tpf->stack[2].track = t;
-				}
-				tpf->stack[0].first_track = tpf->stack[0].track;
-				tpf->stack[1].first_track = tpf->stack[1].track;
-			}
-		}
-
-		// Continue with the next from the queue...
-	}
-}
-
-
-// new pathfinder for trains. better and faster.
-void NewTrainPathfind(TileIndex tile, TileIndex dest, RailTypeMask railtypes, DiagDirection direction, NTPEnumProc* enum_proc, void* data)
-{
-	NewTrackPathFinder tpf;
-
-	tpf.dest = dest;
-	tpf.userdata = data;
-	tpf.enum_proc = enum_proc;
-	tpf.tracktype = TRANSPORT_RAIL;
-	tpf.railtypes = railtypes;
-	tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
-	tpf.nstack = 0;
-	tpf.new_link = tpf.links;
-	tpf.num_links_left = lengthof(tpf.links);
-	memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
-
-	NTPEnum(&tpf, tile, direction);
-}
new file mode 100644
--- /dev/null
+++ b/src/pathfind.cpp
@@ -0,0 +1,968 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "station_map.h"
+#include "depot.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "pathfind.h"
+#include "rail.h"
+#include "debug.h"
+#include "tunnel_map.h"
+#include "variables.h"
+#include "depot.h"
+
+// remember which tiles we have already visited so we don't visit them again.
+static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
+{
+	uint hash, val, offs;
+	TrackPathFinderLink *link, *new_link;
+	uint bits = 1 << dir;
+
+	if (tpf->disable_tile_hash)
+		return true;
+
+	hash = PATHFIND_HASH_TILE(tile);
+
+	val = tpf->hash_head[hash];
+
+	if (val == 0) {
+		/* unused hash entry, set the appropriate bit in it and return true
+		 * to indicate that a bit was set. */
+		tpf->hash_head[hash] = bits;
+		tpf->hash_tile[hash] = tile;
+		return true;
+	} else if (!(val & 0x8000)) {
+		/* single tile */
+
+		if (tile == tpf->hash_tile[hash]) {
+			/* found another bit for the same tile,
+			 * check if this bit is already set, if so, return false */
+			if (val & bits)
+				return false;
+
+			/* otherwise set the bit and return true to indicate that the bit
+			 * was set */
+			tpf->hash_head[hash] = val | bits;
+			return true;
+		} else {
+			/* two tiles with the same hash, need to make a link */
+
+			/* allocate a link. if out of links, handle this by returning
+			 * that a tile was already visisted. */
+			if (tpf->num_links_left == 0) {
+				return false;
+			}
+			tpf->num_links_left--;
+			link = tpf->new_link++;
+
+			/* move the data that was previously in the hash_??? variables
+			 * to the link struct, and let the hash variables point to the link */
+			link->tile = tpf->hash_tile[hash];
+			tpf->hash_tile[hash] = PATHFIND_GET_LINK_OFFS(tpf, link);
+
+			link->flags = tpf->hash_head[hash];
+			tpf->hash_head[hash] = 0xFFFF; /* multi link */
+
+			link->next = 0xFFFF;
+		}
+	} else {
+		/* a linked list of many tiles,
+		 * find the one corresponding to the tile, if it exists.
+		 * otherwise make a new link */
+
+		offs = tpf->hash_tile[hash];
+		do {
+			link = PATHFIND_GET_LINK_PTR(tpf, offs);
+			if (tile == link->tile) {
+				/* found the tile in the link list,
+				 * check if the bit was alrady set, if so return false to indicate that the
+				 * bit was already set */
+				if (link->flags & bits)
+					return false;
+				link->flags |= bits;
+				return true;
+			}
+		} while ((offs=link->next) != 0xFFFF);
+	}
+
+	/* get here if we need to add a new link to link,
+	 * first, allocate a new link, in the same way as before */
+	if (tpf->num_links_left == 0) {
+			return false;
+	}
+	tpf->num_links_left--;
+	new_link = tpf->new_link++;
+
+	/* then fill the link with the new info, and establish a ptr from the old
+	 * link to the new one */
+	new_link->tile = tile;
+	new_link->flags = bits;
+	new_link->next = 0xFFFF;
+
+	link->next = PATHFIND_GET_LINK_OFFS(tpf, new_link);
+	return true;
+}
+
+static const byte _bits_mask[4] = {
+	0x19,
+	0x16,
+	0x25,
+	0x2A,
+};
+
+static const byte _tpf_new_direction[14] = {
+	0, 1, 0, 1, 2, 1,
+	0, 0,
+	2, 3, 3, 2, 3, 0,
+};
+
+static const byte _tpf_prev_direction[14] = {
+	0, 1, 1, 0, 1, 2,
+	0, 0,
+	2, 3, 2, 3, 0, 3,
+};
+
+
+static const byte _otherdir_mask[4] = {
+	0x10,
+	0,
+	0x5,
+	0x2A,
+};
+
+static void TPFMode2(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
+{
+	uint bits;
+	int i;
+	RememberData rd;
+
+	assert(tpf->tracktype == TRANSPORT_WATER);
+
+	// This addition will sometimes overflow by a single tile.
+	// The use of TILE_MASK here makes sure that we still point at a valid
+	// tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail.
+	tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
+
+	if (++tpf->rd.cur_length > 50)
+		return;
+
+	bits = GetTileTrackStatus(tile, tpf->tracktype);
+	bits = (byte)((bits | (bits >> 8)) & _bits_mask[direction]);
+	if (bits == 0)
+		return;
+
+	assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
+
+	if ( (bits & (bits - 1)) == 0 ) {
+		/* only one direction */
+		i = 0;
+		while (!(bits&1))
+			i++, bits>>=1;
+
+		rd = tpf->rd;
+		goto continue_here;
+	}
+	/* several directions */
+	i=0;
+	do {
+		if (!(bits & 1)) continue;
+		rd = tpf->rd;
+
+		// Change direction 4 times only
+		if ((byte)i != tpf->rd.pft_var6) {
+			if (++tpf->rd.depth > 4) {
+				tpf->rd = rd;
+				return;
+			}
+			tpf->rd.pft_var6 = (byte)i;
+		}
+
+continue_here:;
+		tpf->the_dir = i + (HASBIT(_otherdir_mask[direction], i) ? 8 : 0);
+
+		if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
+			TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
+		}
+
+		tpf->rd = rd;
+	} while (++i, bits>>=1);
+
+}
+
+
+/* Returns the end tile and the length of a tunnel. The length does not
+ * include the starting tile (entry), it does include the end tile (exit).
+ */
+FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, DiagDirection dir)
+{
+	TileIndexDiff delta = TileOffsByDiagDir(dir);
+	uint z = GetTileZ(tile);
+	FindLengthOfTunnelResult flotr;
+
+	flotr.length = 0;
+
+	dir = ReverseDiagDir(dir);
+	do {
+		flotr.length++;
+		tile += delta;
+	} while(
+		!IsTunnelTile(tile) ||
+		GetTunnelDirection(tile) != dir ||
+		GetTileZ(tile) != z
+	);
+
+	flotr.tile = tile;
+	return flotr;
+}
+
+static const uint16 _tpfmode1_and[4] = { 0x1009, 0x16, 0x520, 0x2A00 };
+
+static uint SkipToEndOfTunnel(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
+{
+	FindLengthOfTunnelResult flotr;
+	TPFSetTileBit(tpf, tile, 14);
+	flotr = FindLengthOfTunnel(tile, direction);
+	tpf->rd.cur_length += flotr.length;
+	TPFSetTileBit(tpf, flotr.tile, 14);
+	return flotr.tile;
+}
+
+const byte _ffb_64[128] = {
+ 0,  0,  1,  0,  2,  0,  1,  0,
+ 3,  0,  1,  0,  2,  0,  1,  0,
+ 4,  0,  1,  0,  2,  0,  1,  0,
+ 3,  0,  1,  0,  2,  0,  1,  0,
+ 5,  0,  1,  0,  2,  0,  1,  0,
+ 3,  0,  1,  0,  2,  0,  1,  0,
+ 4,  0,  1,  0,  2,  0,  1,  0,
+ 3,  0,  1,  0,  2,  0,  1,  0,
+
+ 0,  0,  0,  2,  0,  4,  4,  6,
+ 0,  8,  8, 10,  8, 12, 12, 14,
+ 0, 16, 16, 18, 16, 20, 20, 22,
+16, 24, 24, 26, 24, 28, 28, 30,
+ 0, 32, 32, 34, 32, 36, 36, 38,
+32, 40, 40, 42, 40, 44, 44, 46,
+32, 48, 48, 50, 48, 52, 52, 54,
+48, 56, 56, 58, 56, 60, 60, 62,
+};
+
+static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
+{
+	uint bits;
+	int i;
+	RememberData rd;
+	TileIndex tile_org = tile;
+
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (IsTunnel(tile)) {
+			if (GetTunnelDirection(tile) != direction ||
+					GetTunnelTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+			tile = SkipToEndOfTunnel(tpf, tile, direction);
+		} else {
+			TileIndex tile_end;
+			if (GetBridgeRampDirection(tile) != direction ||
+					GetBridgeTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+			//fprintf(stderr, "%s: Planning over bridge\n", __func__);
+			// TODO doesn't work - WHAT doesn't work?
+			TPFSetTileBit(tpf, tile, 14);
+			tile_end = GetOtherBridgeEnd(tile);
+			tpf->rd.cur_length += DistanceManhattan(tile, tile_end);
+			tile = tile_end;
+			TPFSetTileBit(tpf, tile, 14);
+		}
+	}
+	tile += TileOffsByDiagDir(direction);
+
+	/* Check in case of rail if the owner is the same */
+	if (tpf->tracktype == TRANSPORT_RAIL) {
+		// don't enter train depot from the back
+		if (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) == direction) return;
+
+		if (IsTileType(tile_org, MP_RAILWAY) || IsTileType(tile_org, MP_STATION) || IsTileType(tile_org, MP_TUNNELBRIDGE))
+			if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE))
+				if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
+	}
+
+	// check if the new tile can be entered from that direction
+	if (tpf->tracktype == TRANSPORT_ROAD) {
+		// road stops and depots now have a track (r4419)
+		// don't enter road stop from the back
+		if (IsRoadStopTile(tile) && ReverseDiagDir(GetRoadStopDir(tile)) != direction) return;
+		// don't enter road depot from the back
+		if (IsTileDepotType(tile, TRANSPORT_ROAD) && ReverseDiagDir(GetRoadDepotDirection(tile)) != direction) return;
+	}
+
+	/* Check if the new tile is a tunnel or bridge head and that the direction
+	 * and transport type match */
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (IsTunnel(tile)) {
+			if (GetTunnelDirection(tile) != direction ||
+					GetTunnelTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+		} else if (IsBridge(tile)) {
+			if (GetBridgeRampDirection(tile) != direction ||
+					GetBridgeTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+		}
+	}
+
+	tpf->rd.cur_length++;
+
+	bits = GetTileTrackStatus(tile, tpf->tracktype);
+
+	if ((byte)bits != tpf->var2) {
+		bits &= _tpfmode1_and[direction];
+		bits = bits | (bits>>8);
+	}
+	bits &= 0xBF;
+
+	if (bits != 0) {
+		if (!tpf->disable_tile_hash || (tpf->rd.cur_length <= 64 && (KILL_FIRST_BIT(bits) == 0 || ++tpf->rd.depth <= 7))) {
+			do {
+				i = FIND_FIRST_BIT(bits);
+				bits = KILL_FIRST_BIT(bits);
+
+				tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
+				rd = tpf->rd;
+
+				if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
+						!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
+					TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
+				}
+				tpf->rd = rd;
+			} while (bits != 0);
+		}
+	}
+
+	/* the next is only used when signals are checked.
+	 * seems to go in 2 directions simultaneously */
+
+	/* if i can get rid of this, tail end recursion can be used to minimize
+	 * stack space dramatically. */
+
+	/* If we are doing signal setting, we must reverse at evere tile, so we
+	 * iterate all the tracks in a signal block, even when a normal train would
+	 * not reach it (for example, when two lines merge */
+	if (tpf->hasbit_13)
+		return;
+
+	direction = ReverseDiagDir(direction);
+	tile += TileOffsByDiagDir(direction);
+
+	bits = GetTileTrackStatus(tile, tpf->tracktype);
+	bits |= (bits >> 8);
+
+	if ( (byte)bits != tpf->var2) {
+		bits &= _bits_mask[direction];
+	}
+
+	bits &= 0xBF;
+	if (bits == 0)
+		return;
+
+	do {
+		i = FIND_FIRST_BIT(bits);
+		bits = KILL_FIRST_BIT(bits);
+
+		tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
+		rd = tpf->rd;
+		if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
+				!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
+			TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
+		}
+		tpf->rd = rd;
+	} while (bits != 0);
+}
+
+void FollowTrack(TileIndex tile, uint16 flags, DiagDirection direction, TPFEnumProc *enum_proc, TPFAfterProc *after_proc, void *data)
+{
+	TrackPathFinder tpf;
+
+	assert(direction < 4);
+
+	/* initialize path finder variables */
+	tpf.userdata = data;
+	tpf.enum_proc = enum_proc;
+	tpf.new_link = tpf.links;
+	tpf.num_links_left = lengthof(tpf.links);
+
+	tpf.rd.cur_length = 0;
+	tpf.rd.depth = 0;
+	tpf.rd.pft_var6 = 0;
+
+	tpf.var2 = HASBIT(flags, 15) ? 0x43 : 0xFF; /* 0x8000 */
+
+	tpf.disable_tile_hash = HASBIT(flags, 12);  /* 0x1000 */
+	tpf.hasbit_13         = HASBIT(flags, 13);  /* 0x2000 */
+
+
+	tpf.tracktype = (byte)flags;
+
+	if (HASBIT(flags, 11)) {
+		tpf.rd.pft_var6 = 0xFF;
+		tpf.enum_proc(tile, data, 0, 0, 0);
+		TPFMode2(&tpf, tile, direction);
+	} else {
+		/* clear the hash_heads */
+		memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
+		TPFMode1(&tpf, tile, direction);
+	}
+
+	if (after_proc != NULL)
+		after_proc(&tpf);
+}
+
+typedef struct {
+	TileIndex tile;
+	uint16 cur_length; // This is the current length to this tile.
+	uint16 priority; // This is the current length + estimated length to the goal.
+	byte track;
+	byte depth;
+	byte state;
+	byte first_track;
+} StackedItem;
+
+static const byte _new_track[6][4] = {
+{0,    0xff, 8,    0xff,},
+{0xff, 1,    0xff, 9,},
+{0xff, 2,    10,   0xff,},
+{3,    0xff, 0xff, 11,},
+{12,   4,    0xff, 0xff,},
+{0xff, 0xff, 5,    13,},
+};
+
+typedef struct HashLink {
+	TileIndex tile;
+	uint16 typelength;
+	uint16 next;
+} HashLink;
+
+typedef struct {
+	NTPEnumProc *enum_proc;
+	void *userdata;
+	TileIndex dest;
+
+	TransportType tracktype;
+	RailTypeMask railtypes;
+	uint maxlength;
+
+	HashLink *new_link;
+	uint num_links_left;
+
+	uint nstack;
+	StackedItem stack[256]; // priority queue of stacked items
+
+	uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFFC = length, 0x3 = dir
+	TileIndex hash_tile[0x400]; // tiles. or links.
+
+	HashLink links[0x400]; // hash links
+
+} NewTrackPathFinder;
+#define NTP_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
+#define NTP_GET_LINK_PTR(tpf, link_offs) (HashLink*)((byte*)tpf->links + (link_offs))
+
+#define ARR(i) tpf->stack[(i)-1]
+
+// called after a new element was added in the queue at the last index.
+// move it down to the proper position
+static inline void HeapifyUp(NewTrackPathFinder *tpf)
+{
+	StackedItem si;
+	int i = ++tpf->nstack;
+
+	while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
+		// the child element is larger than the parent item.
+		// swap the child item and the parent item.
+		si = ARR(i); ARR(i) = ARR(i>>1); ARR(i>>1) = si;
+		i>>=1;
+	}
+}
+
+// called after the element 0 was eaten. fill it with a new element
+static inline void HeapifyDown(NewTrackPathFinder *tpf)
+{
+	StackedItem si;
+	int i = 1, j;
+	int n;
+
+	assert(tpf->nstack > 0);
+	n = --tpf->nstack;
+
+	if (n == 0) return; // heap is empty so nothing to do?
+
+	// copy the last item to index 0. we use it as base for heapify.
+	ARR(1) = ARR(n+1);
+
+	while ((j=i*2) <= n) {
+		// figure out which is smaller of the children.
+		if (j != n && ARR(j).priority > ARR(j+1).priority)
+			j++; // right item is smaller
+
+		assert(i <= n && j <= n);
+		if (ARR(i).priority <= ARR(j).priority)
+			break; // base elem smaller than smallest, done!
+
+		// swap parent with the child
+		si = ARR(i); ARR(i) = ARR(j); ARR(j) = si;
+		i = j;
+	}
+}
+
+// mark a tile as visited and store the length of the path.
+// if we already had a better path to this tile, return false.
+// otherwise return true.
+static bool NtpVisit(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection dir, uint length)
+{
+	uint hash,head;
+	HashLink *link, *new_link;
+
+	assert(length < 16384-1);
+
+	hash = PATHFIND_HASH_TILE(tile);
+
+	// never visited before?
+	if ((head=tpf->hash_head[hash]) == 0) {
+		tpf->hash_tile[hash] = tile;
+		tpf->hash_head[hash] = dir | (length << 2);
+		return true;
+	}
+
+	if (head != 0xffff) {
+		if (tile == tpf->hash_tile[hash] && (head & 0x3) == dir) {
+
+			// longer length
+			if (length >= (head >> 2)) return false;
+
+			tpf->hash_head[hash] = dir | (length << 2);
+			return true;
+		}
+		// two tiles with the same hash, need to make a link
+		// allocate a link. if out of links, handle this by returning
+		// that a tile was already visisted.
+		if (tpf->num_links_left == 0) {
+			DEBUG(ntp, 1, "No links left");
+			return false;
+		}
+
+		tpf->num_links_left--;
+		link = tpf->new_link++;
+
+		/* move the data that was previously in the hash_??? variables
+		 * to the link struct, and let the hash variables point to the link */
+		link->tile = tpf->hash_tile[hash];
+		tpf->hash_tile[hash] = NTP_GET_LINK_OFFS(tpf, link);
+
+		link->typelength = tpf->hash_head[hash];
+		tpf->hash_head[hash] = 0xFFFF; /* multi link */
+		link->next = 0xFFFF;
+	} else {
+		// a linked list of many tiles,
+		// find the one corresponding to the tile, if it exists.
+		// otherwise make a new link
+
+		uint offs = tpf->hash_tile[hash];
+		do {
+			link = NTP_GET_LINK_PTR(tpf, offs);
+			if (tile == link->tile && (link->typelength & 0x3U) == dir) {
+				if (length >= (uint)(link->typelength >> 2)) return false;
+				link->typelength = dir | (length << 2);
+				return true;
+			}
+		} while ((offs = link->next) != 0xFFFF);
+	}
+
+	/* get here if we need to add a new link to link,
+	 * first, allocate a new link, in the same way as before */
+	if (tpf->num_links_left == 0) {
+		DEBUG(ntp, 1, "No links left");
+		return false;
+	}
+	tpf->num_links_left--;
+	new_link = tpf->new_link++;
+
+	/* then fill the link with the new info, and establish a ptr from the old
+	 * link to the new one */
+	new_link->tile = tile;
+	new_link->typelength = dir | (length << 2);
+	new_link->next = 0xFFFF;
+
+	link->next = NTP_GET_LINK_OFFS(tpf, new_link);
+	return true;
+}
+
+/**
+ * Checks if the shortest path to the given tile/dir so far is still the given
+ * length.
+ * @return true if the length is still the same
+ * @pre    The given tile/dir combination should be present in the hash, by a
+ *         previous call to NtpVisit().
+ */
+static bool NtpCheck(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint length)
+{
+	uint hash,head,offs;
+	HashLink *link;
+
+	hash = PATHFIND_HASH_TILE(tile);
+	head=tpf->hash_head[hash];
+	assert(head);
+
+	if (head != 0xffff) {
+		assert( tpf->hash_tile[hash] == tile && (head & 3) == dir);
+		assert( (head >> 2) <= length);
+		return length == (head >> 2);
+	}
+
+	// else it's a linked list of many tiles
+	offs = tpf->hash_tile[hash];
+	for (;;) {
+		link = NTP_GET_LINK_PTR(tpf, offs);
+		if (tile == link->tile && (link->typelength & 0x3U) == dir) {
+			assert((uint)(link->typelength >> 2) <= length);
+			return length == (uint)(link->typelength >> 2);
+		}
+		offs = link->next;
+		assert(offs != 0xffff);
+	}
+}
+
+
+static const uint16 _is_upwards_slope[15] = {
+	0, // no tileh
+	(1 << TRACKDIR_X_SW) | (1 << TRACKDIR_Y_NW), // 1
+	(1 << TRACKDIR_X_SW) | (1 << TRACKDIR_Y_SE), // 2
+	(1 << TRACKDIR_X_SW), // 3
+	(1 << TRACKDIR_X_NE) | (1 << TRACKDIR_Y_SE), // 4
+	0, // 5
+	(1 << TRACKDIR_Y_SE), // 6
+	0, // 7
+	(1 << TRACKDIR_X_NE) | (1 << TRACKDIR_Y_NW), // 8,
+	(1 << TRACKDIR_Y_NW), // 9
+	0, //10
+	0, //11,
+	(1 << TRACKDIR_X_NE), //12
+	0, //13
+	0, //14
+};
+
+static uint DistanceMoo(TileIndex t0, TileIndex t1)
+{
+	const uint dx = abs(TileX(t0) - TileX(t1));
+	const uint dy = abs(TileY(t0) - TileY(t1));
+
+	const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
+	/* OPTIMISATION:
+	 * Original: diagTracks = max(dx, dy) - min(dx,dy);
+	 * Proof:
+	 * (dx-dy) - straightTracks  == (min + max) - straightTracks = min + // max - 2 * min = max - min */
+	const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
+
+	return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
+}
+
+// These has to be small cause the max length of a track
+// is currently limited to 16384
+
+static const byte _length_of_track[16] = {
+	DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0,
+	DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0
+};
+
+// new more optimized pathfinder for trains...
+// Tile is the tile the train is at.
+// direction is the tile the train is moving towards.
+
+static void NTPEnum(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
+{
+	TrackBits bits, allbits;
+	uint track;
+	TileIndex tile_org;
+	StackedItem si;
+	int estimation;
+
+
+
+	// Need to have a special case for the start.
+	// We shouldn't call the callback for the current tile.
+	si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
+	si.depth = 0;
+	si.state = 0;
+	si.first_track = 0xFF;
+	goto start_at;
+
+	for (;;) {
+		// Get the next item to search from from the priority queue
+		do {
+			if (tpf->nstack == 0)
+				return; // nothing left? then we're done!
+			si = tpf->stack[0];
+			tile = si.tile;
+
+			HeapifyDown(tpf);
+			// Make sure we havn't already visited this tile.
+		} while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
+
+		// Add the length of this track.
+		si.cur_length += _length_of_track[si.track];
+
+callback_and_continue:
+		if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
+			return;
+
+		assert(si.track <= 13);
+		direction = _tpf_new_direction[si.track];
+
+start_at:
+		// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
+		//   need to find the exit of the tunnel.
+		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+			if (IsTunnel(tile)) {
+				if (GetTunnelDirection(tile) != ReverseDiagDir(direction)) {
+					FindLengthOfTunnelResult flotr;
+
+					/* We are not just driving out of the tunnel */
+					if (GetTunnelDirection(tile) != direction ||
+							GetTunnelTransportType(tile) != tpf->tracktype) {
+						// We are not driving into the tunnel, or it is an invalid tunnel
+						continue;
+					}
+					if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
+						bits = 0;
+						break;
+					}
+					flotr = FindLengthOfTunnel(tile, direction);
+					si.cur_length += flotr.length * DIAG_FACTOR;
+					tile = flotr.tile;
+					// tile now points to the exit tile of the tunnel
+				}
+			} else {
+				TileIndex tile_end;
+				if (GetBridgeRampDirection(tile) != ReverseDiagDir(direction)) {
+					// We are not just leaving the bridge
+					if (GetBridgeRampDirection(tile) != direction ||
+							GetBridgeTransportType(tile) != tpf->tracktype) {
+						// Not entering the bridge or not compatible
+						continue;
+					}
+				}
+				tile_end = GetOtherBridgeEnd(tile);
+				si.cur_length += DistanceManhattan(tile, tile_end) * DIAG_FACTOR;
+				tile = tile_end;
+			}
+		}
+
+		// This is a special loop used to go through
+		// a rail net and find the first intersection
+		tile_org = tile;
+		for (;;) {
+			assert(direction <= 3);
+			tile += TileOffsByDiagDir(direction);
+
+			// too long search length? bail out.
+			if (si.cur_length >= tpf->maxlength) {
+				DEBUG(ntp, 1, "Cur_length too big");
+				bits = 0;
+				break;
+			}
+
+			// Not a regular rail tile?
+			// Then we can't use the code below, but revert to more general code.
+			if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
+				// We found a tile which is not a normal railway tile.
+				// Determine which tracks that exist on this tile.
+				bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
+				bits = (bits | (bits >> 8)) & 0x3F;
+
+				// Check that the tile contains exactly one track
+				if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break;
+
+				if (!HASBIT(tpf->railtypes, IsTileType(tile, MP_STREET) ? GetRailTypeCrossing(tile) : GetRailType(tile))) {
+					bits = 0;
+					break;
+				}
+
+				///////////////////
+				// If we reach here, the tile has exactly one track.
+				//   tile - index to a tile that is not rail tile, but still straight (with optional signals)
+				//   bits - bitmask of which track that exist on the tile (exactly one bit is set)
+				//   direction - which direction are we moving in?
+				///////////////////
+				si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
+				si.cur_length += _length_of_track[si.track];
+				goto callback_and_continue;
+			}
+
+			/* Regular rail tile, determine which tracks exist. */
+			allbits = GetTrackBits(tile);
+			/* Which tracks are reachable? */
+			bits = allbits & DiagdirReachesTracks(direction);
+
+			/* The tile has no reachable tracks => End of rail segment
+			 * or Intersection => End of rail segment. We check this agains all the
+			 * bits, not just reachable ones, to prevent infinite loops. */
+			if (bits == 0 || TracksOverlap(allbits)) break;
+
+			if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
+				bits = 0;
+				break;
+			}
+
+			/* If we reach here, the tile has exactly one track, and this
+			 track is reachable => Rail segment continues */
+
+			track = _new_track[FIND_FIRST_BIT(bits)][direction];
+			assert(track != 0xff);
+
+			si.cur_length += _length_of_track[track];
+
+			// Check if this rail is an upwards slope. If it is, then add a penalty.
+			// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
+			if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
+				// upwards slope. add some penalty.
+				si.cur_length += 4*DIAG_FACTOR;
+			}
+
+			// railway tile with signals..?
+			if (HasSignals(tile)) {
+				if (!HasSignalOnTrackdir(tile, track)) {
+					// if one way signal not pointing towards us, stop going in this direction => End of rail segment.
+					if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
+						bits = 0;
+						break;
+					}
+				} else if (GetSignalStateByTrackdir(tile, track) == SIGNAL_STATE_GREEN) {
+					// green signal in our direction. either one way or two way.
+					si.state |= 3;
+				} else {
+					// reached a red signal.
+					if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
+						// two way red signal. unless we passed another green signal on the way,
+						// stop going in this direction => End of rail segment.
+						// this is to prevent us from going into a full platform.
+						if (!(si.state&1)) {
+							bits = 0;
+							break;
+						}
+					}
+					if (!(si.state & 2)) {
+						// Is this the first signal we see? And it's red... add penalty
+						si.cur_length += 10*DIAG_FACTOR;
+						si.state += 2; // remember that we added penalty.
+						// Because we added a penalty, we can't just continue as usual.
+						// Need to get out and let A* do it's job with
+						// possibly finding an even shorter path.
+						break;
+					}
+				}
+
+				if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
+					return; /* Don't process this tile any further */
+			}
+
+			// continue with the next track
+			direction = _tpf_new_direction[track];
+
+			// safety check if we're running around chasing our tail... (infinite loop)
+			if (tile == tile_org) {
+				bits = 0;
+				break;
+			}
+		}
+
+		// There are no tracks to choose between.
+		// Stop searching in this direction
+		if (bits == 0)
+			continue;
+
+		////////////////
+		// We got multiple tracks to choose between (intersection).
+		// Branch the search space into several branches.
+		////////////////
+
+		// Check if we've already visited this intersection.
+		// If we've already visited it with a better length, then
+		// there's no point in visiting it again.
+		if (!NtpVisit(tpf, tile, direction, si.cur_length))
+			continue;
+
+		// Push all possible alternatives that we can reach from here
+		// onto the priority heap.
+		// 'bits' contains the tracks that we can choose between.
+
+		// First compute the estimated distance to the target.
+		// This is used to implement A*
+		estimation = 0;
+		if (tpf->dest != 0)
+			estimation = DistanceMoo(tile, tpf->dest);
+
+		si.depth++;
+		if (si.depth == 0)
+			continue; /* We overflowed our depth. No more searching in this direction. */
+		si.tile = tile;
+		do {
+			si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
+			assert(si.track != 0xFF);
+			si.priority = si.cur_length + estimation;
+
+			// out of stack items, bail out?
+			if (tpf->nstack >= lengthof(tpf->stack)) {
+				DEBUG(ntp, 1, "Out of stack");
+				break;
+			}
+
+			tpf->stack[tpf->nstack] = si;
+			HeapifyUp(tpf);
+		} while ((bits = KILL_FIRST_BIT(bits)) != 0);
+
+		// If this is the first intersection, we need to fill the first_track member.
+		// so the code outside knows which path is better.
+		// also randomize the order in which we search through them.
+		if (si.depth == 1) {
+			assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
+			if (tpf->nstack != 1) {
+				uint32 r = Random();
+				if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
+				if (tpf->nstack != 2) {
+					byte t = tpf->stack[2].track;
+					if (r&2) swap_byte(&tpf->stack[0].track, &t);
+					if (r&4) swap_byte(&tpf->stack[1].track, &t);
+					tpf->stack[2].first_track = tpf->stack[2].track = t;
+				}
+				tpf->stack[0].first_track = tpf->stack[0].track;
+				tpf->stack[1].first_track = tpf->stack[1].track;
+			}
+		}
+
+		// Continue with the next from the queue...
+	}
+}
+
+
+// new pathfinder for trains. better and faster.
+void NewTrainPathfind(TileIndex tile, TileIndex dest, RailTypeMask railtypes, DiagDirection direction, NTPEnumProc* enum_proc, void* data)
+{
+	NewTrackPathFinder tpf;
+
+	tpf.dest = dest;
+	tpf.userdata = data;
+	tpf.enum_proc = enum_proc;
+	tpf.tracktype = TRANSPORT_RAIL;
+	tpf.railtypes = railtypes;
+	tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
+	tpf.nstack = 0;
+	tpf.new_link = tpf.links;
+	tpf.num_links_left = lengthof(tpf.links);
+	memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
+
+	NTPEnum(&tpf, tile, direction);
+}
deleted file mode 100644
--- a/src/player_gui.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "player.h"
-#include "command.h"
-#include "vehicle.h"
-#include "economy.h"
-#include "network/network.h"
-#include "variables.h"
-#include "train.h"
-#include "date.h"
-#include "newgrf.h"
-#include "network/network_data.h"
-#include "network/network_client.h"
-
-static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied);
-
-static void DrawPlayerEconomyStats(const Player *p, byte mode)
-{
-	int x,y,i,j,year;
-	const int64 (*tbl)[13];
-	int64 sum, cost;
-	StringID str;
-
-	if (!(mode & 1)) { // normal sized economics window (mode&1) is minimized status
-		/* draw categories */
-		DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, 0);
-		for (i = 0; i != 13; i++)
-			DrawString(2, 27 + i*10, STR_7011_CONSTRUCTION + i, 0);
-		DrawStringRightAligned(111, 27 + 10*13 + 2, STR_7020_TOTAL, 0);
-
-		/* draw the price columns */
-		year = _cur_year - 2;
-		j = 3;
-		x = 215;
-		tbl = p->yearly_expenses + 2;
-		do {
-			if (year >= p->inaugurated_year) {
-				SetDParam(0, year);
-				DrawStringRightAlignedUnderline(x, 15, STR_7010, 0);
-				sum = 0;
-				for (i = 0; i != 13; i++) {
-					/* draw one row in the price column */
-					cost = (*tbl)[i];
-					if (cost != 0) {
-						sum += cost;
-
-						str = STR_701E;
-						if (cost < 0) { cost = -cost; str++; }
-						SetDParam64(0, cost);
-						DrawStringRightAligned(x, 27+i*10, str, 0);
-					}
-				}
-
-				str = STR_701E;
-				if (sum < 0) { sum = -sum; str++; }
-				SetDParam64(0, sum);
-				DrawStringRightAligned(x, 27 + 13*10 + 2, str, 0);
-
-				GfxFillRect(x - 75, 27 + 10*13, x, 27 + 10*13, 215);
-				x += 95;
-			}
-			year++;
-			tbl--;
-		} while (--j != 0);
-
-		y = 171;
-
-		// draw max loan aligned to loan below (y += 10)
-		SetDParam64(0, (uint64)_economy.max_loan);
-		DrawString(202, y+10, STR_MAX_LOAN, 0);
-	} else {
-		y = 15;
-	}
-
-	DrawString(2, y, STR_7026_BANK_BALANCE, 0);
-	SetDParam64(0, p->money64);
-	DrawStringRightAligned(182, y, STR_7028, 0);
-
-	y += 10;
-
-	DrawString(2, y, STR_7027_LOAN, 0);
-	SetDParam64(0, p->current_loan);
-	DrawStringRightAligned(182, y, STR_7028, 0);
-
-	y += 12;
-
-	GfxFillRect(182 - 75, y-2, 182, y-2, 215);
-
-	SetDParam64(0, p->money64 - p->current_loan);
-	DrawStringRightAligned(182, y, STR_7028, 0);
-}
-
-static const Widget _player_finances_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,    14,   169, 0x0,                    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,   170,   203, 0x0,                    STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   202,   204,   215, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   203,   406,   204,   215, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
-{   WIDGETS_END},
-};
-
-static const Widget _other_player_finances_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,    14,   169, 0x0,                    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,   170,   203, 0x0,                    STR_NULL},
-{   WIDGETS_END},
-};
-
-static const Widget _other_player_finances_small_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    47, 0x0,                    STR_NULL},
-{   WIDGETS_END},
-};
-
-static const Widget _player_finances_small_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_IMGBTN,   RESIZE_NONE,    14,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                    STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    47, STR_NULL,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   139,    48,    59, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   140,   279,    48,    59, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
-{   WIDGETS_END},
-};
-
-
-static void PlayerFinancesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		PlayerID player = w->window_number;
-		const Player *p = GetPlayer(player);
-
-		if (player == _local_player) {
-			/* borrow/repay buttons only exist for local player */
-			SetWindowWidgetDisabledState(w, 7, p->current_loan == 0);
-		}
-
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		SetDParam(2, GetPlayerNameString(player, 3));
-		SetDParam(4, 10000);
-		DrawWindowWidgets(w);
-
-		DrawPlayerEconomyStats(p, (byte)WP(w,def_d).data_1);
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: {/* toggle size */
-			byte mode = (byte)WP(w,def_d).data_1;
-			bool stickied = !!(w->flags4 & WF_STICKY);
-			PlayerID player = w->window_number;
-			DeleteWindow(w);
-			DoShowPlayerFinances(player, !HASBIT(mode, 0), stickied);
-		} break;
-
-		case 6: /* increase loan */
-			DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
-			break;
-
-		case 7: /* repay loan */
-			DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
-			break;
-		}
-		break;
-	}
-}
-
-static const WindowDesc _player_finances_desc = {
-	WDP_AUTO, WDP_AUTO, 407, 216,
-	WC_FINANCES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_player_finances_widgets,
-	PlayerFinancesWndProc
-};
-
-static const WindowDesc _player_finances_small_desc = {
-	WDP_AUTO, WDP_AUTO, 280, 60,
-	WC_FINANCES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_player_finances_small_widgets,
-	PlayerFinancesWndProc
-};
-
-static const WindowDesc _other_player_finances_desc = {
-	WDP_AUTO, WDP_AUTO, 407, 204,
-	WC_FINANCES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_other_player_finances_widgets,
-	PlayerFinancesWndProc
-};
-
-static const WindowDesc _other_player_finances_small_desc = {
-	WDP_AUTO, WDP_AUTO, 280, 48,
-	WC_FINANCES,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_other_player_finances_small_widgets,
-	PlayerFinancesWndProc
-};
-
-static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied)
-{
-	Window *w;
-	int mode;
-
-	static const WindowDesc * const desc_table[2 * 2] = {
-		&_player_finances_desc, &_player_finances_small_desc,
-		&_other_player_finances_desc, &_other_player_finances_small_desc,
-	};
-
-	if (!IsValidPlayer(player)) return;
-
-	mode = (player != _local_player) * 2 + show_small;
-	w = AllocateWindowDescFront(desc_table[mode], player);
-	if (w != NULL) {
-		w->caption_color = w->window_number;
-		WP(w,def_d).data_1 = mode;
-		if (show_stickied) w->flags4 |= WF_STICKY;
-	}
-}
-
-void ShowPlayerFinances(PlayerID player)
-{
-	DoShowPlayerFinances(player, false, false);
-}
-
-/* List of colours for the livery window */
-static const StringID _colour_dropdown[] = {
-	STR_00D1_DARK_BLUE,
-	STR_00D2_PALE_GREEN,
-	STR_00D3_PINK,
-	STR_00D4_YELLOW,
-	STR_00D5_RED,
-	STR_00D6_LIGHT_BLUE,
-	STR_00D7_GREEN,
-	STR_00D8_DARK_GREEN,
-	STR_00D9_BLUE,
-	STR_00DA_CREAM,
-	STR_00DB_MAUVE,
-	STR_00DC_PURPLE,
-	STR_00DD_ORANGE,
-	STR_00DE_BROWN,
-	STR_00DF_GREY,
-	STR_00E0_WHITE,
-	INVALID_STRING_ID
-};
-
-/* Association of liveries to livery classes */
-static const LiveryClass livery_class[LS_END] = {
-	LC_OTHER,
-	LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
-	LC_ROAD, LC_ROAD,
-	LC_SHIP, LC_SHIP,
-	LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
-};
-
-/* Number of liveries in each class, used to determine the height of the livery window */
-static const byte livery_height[] = {
-	1,
-	11,
-	2,
-	2,
-	3,
-};
-
-typedef struct livery_d {
-	uint32 sel;
-	LiveryClass livery_class;
-} livery_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d));
-
-static void ShowColourDropDownMenu(Window *w, uint32 widget)
-{
-	uint32 used_colours = 0;
-	const Livery *livery;
-	LiveryScheme scheme;
-
-	/* Disallow other player colours for the primary colour */
-	if (HASBIT(WP(w, livery_d).sel, LS_DEFAULT) && widget == 10) {
-		const Player *p;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && p->index != _local_player) SETBIT(used_colours, p->player_color);
-		}
-	}
-
-	/* Get the first selected livery to use as the default dropdown item */
-	for (scheme = 0; scheme < LS_END; scheme++) {
-		if (HASBIT(WP(w, livery_d).sel, scheme)) break;
-	}
-	if (scheme == LS_END) scheme = LS_DEFAULT;
-	livery = &GetPlayer(w->window_number)->livery[scheme];
-
-	ShowDropDownMenu(w, _colour_dropdown, widget == 10 ? livery->colour1 : livery->colour2, widget, used_colours, 0);
-}
-
-static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			LowerWindowWidget(w, WP(w, livery_d).livery_class + 2);
-			if (!_have_2cc) {
-				HideWindowWidget(w, 11);
-				HideWindowWidget(w, 12);
-			}
-			break;
-
-		case WE_PAINT: {
-			const Player *p = GetPlayer(w->window_number);
-			LiveryScheme scheme = LS_DEFAULT;
-			int y = 51;
-
-			/* Disable dropdown controls if no scheme is selected */
-			SetWindowWidgetDisabledState(w,  9, (WP(w, livery_d).sel == 0));
-			SetWindowWidgetDisabledState(w, 10, (WP(w, livery_d).sel == 0));
-			SetWindowWidgetDisabledState(w, 11, (WP(w, livery_d).sel == 0));
-			SetWindowWidgetDisabledState(w, 12, (WP(w, livery_d).sel == 0));
-
-			if (!(WP(w, livery_d).sel == 0)) {
-				for (scheme = 0; scheme < LS_END; scheme++) {
-					if (HASBIT(WP(w, livery_d).sel, scheme)) break;
-				}
-				if (scheme == LS_END) scheme = LS_DEFAULT;
-			}
-
-			SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
-			SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
-
-			DrawWindowWidgets(w);
-
-			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-				if (livery_class[scheme] == WP(w, livery_d).livery_class) {
-					bool sel = HASBIT(WP(w, livery_d).sel, scheme) != 0;
-
-					if (scheme != LS_DEFAULT) {
-						DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, 2, y);
-					}
-
-					DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? 0xC : 0x10);
-
-					DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour1) | PALETTE_MODIFIER_COLOR, 152, y);
-					DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? 0xC : 2);
-
-					if (_have_2cc) {
-						DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour2) | PALETTE_MODIFIER_COLOR, 277, y);
-						DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? 0xC : 2);
-					}
-
-					y += 14;
-				}
-			}
-			break;
-		}
-
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				/* Livery Class buttons */
-				case 2:
-				case 3:
-				case 4:
-				case 5:
-				case 6: {
-					LiveryScheme scheme;
-
-					RaiseWindowWidget(w, WP(w, livery_d).livery_class + 2);
-					WP(w, livery_d).livery_class = e->we.click.widget - 2;
-					WP(w, livery_d).sel = 0;
-					LowerWindowWidget(w, WP(w, livery_d).livery_class + 2);
-
-					/* Select the first item in the list */
-					for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-						if (livery_class[scheme] == WP(w, livery_d).livery_class) {
-							WP(w, livery_d).sel = 1 << scheme;
-							break;
-						}
-					}
-					w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14;
-					w->widget[13].bottom = w->height - 1;
-					w->widget[13].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1;
-					MarkWholeScreenDirty();
-					break;
-				}
-
-				case 9:
-				case 10: // First colour dropdown
-					ShowColourDropDownMenu(w, 10);
-					break;
-
-				case 11:
-				case 12: // Second colour dropdown
-					ShowColourDropDownMenu(w, 12);
-					break;
-
-				case 13: {
-					LiveryScheme scheme;
-					LiveryScheme j = (e->we.click.pt.y - 48) / 14;
-
-					for (scheme = 0; scheme <= j; scheme++) {
-						if (livery_class[scheme] != WP(w, livery_d).livery_class) j++;
-						if (scheme >= LS_END) return;
-					}
-					if (j >= LS_END) return;
-
-					/* If clicking on the left edge, toggle using the livery */
-					if (e->we.click.pt.x < 10) {
-						DoCommandP(0, j | (2 << 8), !GetPlayer(w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
-					}
-
-					if (_ctrl_pressed) {
-						TOGGLEBIT(WP(w, livery_d).sel, j);
-					} else {
-						WP(w, livery_d).sel = 1 << j;
-					}
-					SetWindowDirty(w);
-					break;
-				}
-			}
-			break;
-		}
-
-		case WE_DROPDOWN_SELECT: {
-			LiveryScheme scheme;
-
-			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-				if (HASBIT(WP(w, livery_d).sel, scheme)) {
-					DoCommandP(0, scheme | (e->we.dropdown.button == 10 ? 0 : 256), e->we.dropdown.index, NULL, CMD_SET_PLAYER_COLOR);
-				}
-			}
-			break;
-		}
-	}
-}
-
-static const Widget _select_player_livery_2cc_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
-{  WWT_CAPTION, RESIZE_NONE, 14,  11, 399,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
-{   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
-{    WWT_PANEL, RESIZE_NONE, 14, 110, 399,  14,  35, 0x0,                       STR_NULL },
-{    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 150, 262,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 263, 274,  36,  47, STR_0225,                  STR_LIVERY_PRIMARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 387,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 388, 399,  36,  47, STR_0225,                  STR_LIVERY_SECONDARY_TIP },
-{   WWT_MATRIX, RESIZE_NONE, 14,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
-{ WIDGETS_END },
-};
-
-static const WindowDesc _select_player_livery_2cc_desc = {
-	WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14,
-	WC_PLAYER_COLOR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_select_player_livery_2cc_widgets,
-	SelectPlayerLiveryWndProc
-};
-
-
-static const Widget _select_player_livery_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
-{  WWT_CAPTION, RESIZE_NONE, 14,  11, 274,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
-{   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
-{    WWT_PANEL, RESIZE_NONE, 14, 110, 274,  14,  35, 0x0,                       STR_NULL },
-{    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 150, 262,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 263, 274,  36,  47, STR_0225,                  STR_LIVERY_PRIMARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
-{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_0225,                  STR_LIVERY_SECONDARY_TIP },
-{   WWT_MATRIX, RESIZE_NONE, 14,   0, 274,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
-{ WIDGETS_END },
-};
-
-static const WindowDesc _select_player_livery_desc = {
-	WDP_AUTO, WDP_AUTO, 275, 49 + 1 * 14,
-	WC_PLAYER_COLOR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_select_player_livery_widgets,
-	SelectPlayerLiveryWndProc
-};
-
-static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		Player *p;
-		LowerWindowWidget(w, WP(w, facesel_d).gender + 5);
-		DrawWindowWidgets(w);
-		p = GetPlayer(w->window_number);
-		DrawPlayerFace(WP(w,facesel_d).face, p->player_color, 2, 16);
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: DeleteWindow(w); break;
-		case 4: /* ok click */
-			DoCommandP(0, 0, WP(w,facesel_d).face, NULL, CMD_SET_PLAYER_FACE);
-			DeleteWindow(w);
-			break;
-		case 5: /* male click */
-		case 6: /* female click */
-			RaiseWindowWidget(w, WP(w, facesel_d).gender + 5);
-			WP(w, facesel_d).gender = e->we.click.widget - 5;
-			LowerWindowWidget(w, WP(w, facesel_d).gender + 5);
-			SetWindowDirty(w);
-			break;
-		case 7:
-			WP(w,facesel_d).face = (WP(w,facesel_d).gender << 31) + GB(InteractiveRandom(), 0, 31);
-			SetWindowDirty(w);
-			break;
-		}
-		break;
-	}
-}
-
-static const Widget _select_player_face_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   189,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   189,    14,   136, 0x0,                     STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    94,   137,   148, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   189,   137,   148, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    25,    36, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    37,    48, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   187,    79,    90, STR_7046_NEW_FACE,       STR_704B_GENERATE_RANDOM_NEW_FACE},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _select_player_face_desc = {
-	WDP_AUTO, WDP_AUTO, 190, 149,
-	WC_PLAYER_FACE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_select_player_face_widgets,
-	SelectPlayerFaceWndProc
-};
-
-/* Names of the widgets. Keep them in the same order as in the widget array */
-enum PlayerCompanyWindowWidgets {
-	PCW_WIDGET_CLOSEBOX = 0,
-	PCW_WIDGET_CAPTION,
-	PCW_WIDGET_FACE,
-	PCW_WIDGET_NEW_FACE,
-	PCW_WIDGET_COLOR_SCHEME,
-	PCW_WIDGET_PRESIDENT_NAME,
-	PCW_WIDGET_COMPANY_NAME,
-	PCW_WIDGET_BUILD_VIEW_HQ,
-	PCW_WIDGET_RELOCATE_HQ,
-	PCW_WIDGET_BUY_SHARE,
-	PCW_WIDGET_SELL_SHARE,
-	PCW_WIDGET_COMPANY_PASSWORD,
-};
-
-static const Widget _player_company_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   359,    14,   157, 0x0,                               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    90,   179,   158,   169, STR_7005_COLOR_SCHEME,             STR_7031_CHANGE_THE_COMPANY_VEHICLE},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   179,   158,   169, STR_7077_BUY_25_SHARE_IN_COMPANY,  STR_7079_BUY_25_SHARE_IN_THIS_COMPANY},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   359,   158,   169, STR_7078_SELL_25_SHARE_IN_COMPANY, STR_707A_SELL_25_SHARE_IN_THIS_COMPANY},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
-{   WIDGETS_END},
-};
-
-static void DrawPlayerVehiclesAmount(PlayerID player)
-{
-	const int x = 110;
-	int y = 72;
-	const Vehicle *v;
-	uint train = 0;
-	uint road  = 0;
-	uint air   = 0;
-	uint ship  = 0;
-
-	DrawString(x, y, STR_7039_VEHICLES, 0);
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->owner == player) {
-			switch (v->type) {
-				case VEH_Train:    if (IsFrontEngine(v)) train++; break;
-				case VEH_Road:     road++; break;
-				case VEH_Aircraft: if (v->subtype <= 2) air++; break;
-				case VEH_Ship:     ship++; break;
-				default: break;
-			}
-		}
-	}
-
-	if (train+road+air+ship == 0) {
-		DrawString(x+70, y, STR_7042_NONE, 0);
-	} else {
-		if (train != 0) {
-			SetDParam(0, train);
-			DrawString(x + 70, y, STR_TRAINS, 0);
-			y += 10;
-		}
-
-		if (road != 0) {
-			SetDParam(0, road);
-			DrawString(x + 70, y, STR_ROAD_VEHICLES, 0);
-			y += 10;
-		}
-
-		if (air != 0) {
-			SetDParam(0, air);
-			DrawString(x + 70, y, STR_AIRCRAFT, 0);
-			y += 10;
-		}
-
-		if (ship != 0) {
-			SetDParam(0, ship);
-			DrawString(x + 70, y, STR_SHIPS, 0);
-		}
-	}
-}
-
-int GetAmountOwnedBy(const Player *p, PlayerID owner)
-{
-	return (p->share_owners[0] == owner) +
-				 (p->share_owners[1] == owner) +
-				 (p->share_owners[2] == owner) +
-				 (p->share_owners[3] == owner);
-}
-
-static void DrawCompanyOwnerText(const Player *p)
-{
-	const Player *p2;
-	int num = -1;
-
-	FOR_ALL_PLAYERS(p2) {
-		uint amt = GetAmountOwnedBy(p, p2->index);
-		if (amt != 0) {
-			num++;
-
-			SetDParam(num * 3 + 0, amt * 25);
-			SetDParam(num * 3 + 1, p2->name_1);
-			SetDParam(num * 3 + 2, p2->name_2);
-
-			if (num != 0) break;
-		}
-	}
-
-	if (num >= 0) DrawString(120, 124, STR_707D_OWNED_BY + num, 0);
-}
-
-static void PlayerCompanyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player *p = GetPlayer(w->window_number);
-			bool local = w->window_number == _local_player;
-
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_NEW_FACE,       !local);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_COLOR_SCHEME,   !local);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_PRESIDENT_NAME, !local);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_COMPANY_NAME,   !local);
-			w->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
-			if (local && p->location_of_house != 0) w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
-			SetWindowWidgetDisabledState(w, PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_RELOCATE_HQ,      !local || p->location_of_house == 0);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_BUY_SHARE,        local);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_SELL_SHARE,       local);
-			SetWindowWidgetHiddenState(w, PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
-
-			if (!local) {
-				if (_patches.allow_shares) { // Shares are allowed
-					/* If all shares are owned by someone (none by nobody), disable buy button */
-					SetWindowWidgetDisabledState(w, PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
-							/* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
-							(GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
-							/* Spectators cannot do anything of course */
-							_local_player == PLAYER_SPECTATOR);
-
-					/* If the player doesn't own any shares, disable sell button */
-					SetWindowWidgetDisabledState(w, PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
-							/* Spectators cannot do anything of course */
-							_local_player == PLAYER_SPECTATOR);
-				} else { // Shares are not allowed, disable buy/sell buttons
-					DisableWindowWidget(w, PCW_WIDGET_BUY_SHARE);
-					DisableWindowWidget(w, PCW_WIDGET_SELL_SHARE);
-				}
-			}
-
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, GetPlayerNameString((byte)w->window_number, 3));
-
-			DrawWindowWidgets(w);
-
-			SetDParam(0, p->inaugurated_year);
-			DrawString(110, 25, STR_7038_INAUGURATED, 0);
-
-			DrawPlayerVehiclesAmount(w->window_number);
-
-			DrawString(110,48, STR_7006_COLOR_SCHEME, 0);
-			// Draw company-colour bus
-			DrawSprite(PLAYER_SPRITE_COLOR(p->index) + SPRITE_PALETTE(SPR_VEH_BUS_SW_VIEW), 215, 49);
-
-			DrawPlayerFace(p->face, p->player_color, 2, 16);
-
-			SetDParam(0, p->president_name_1);
-			SetDParam(1, p->president_name_2);
-			DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
-
-			SetDParam64(0, CalculateCompanyValue(p));
-			DrawString(110, 114, STR_7076_COMPANY_VALUE, 0);
-
-			DrawCompanyOwnerText(p);
-
-			break;
-		}
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case PCW_WIDGET_NEW_FACE: {
-					Window *wf = AllocateWindowDescFront(&_select_player_face_desc, w->window_number);
-					if (wf != NULL) {
-						wf->caption_color = w->window_number;
-						WP(wf,facesel_d).face = GetPlayer(wf->window_number)->face;
-						WP(wf,facesel_d).gender = 0;
-					}
-					break;
-				}
-
-				case PCW_WIDGET_COLOR_SCHEME: {
-					Window *wf = AllocateWindowDescFront(_have_2cc ? &_select_player_livery_2cc_desc : &_select_player_livery_desc, w->window_number);
-					if (wf != NULL) {
-						wf->caption_color = wf->window_number;
-						WP(wf,livery_d).livery_class = LC_OTHER;
-						WP(wf,livery_d).sel = 1;
-						LowerWindowWidget(wf, 2);
-					}
-					break;
-				}
-
-				case PCW_WIDGET_PRESIDENT_NAME: {
-					const Player *p = GetPlayer(w->window_number);
-					WP(w, def_d).byte_1 = 0;
-					SetDParam(0, p->president_name_2);
-					ShowQueryString(p->president_name_1, STR_700B_PRESIDENT_S_NAME, 31, 94, w, CS_ALPHANUMERAL);
-					break;
-				}
-
-				case PCW_WIDGET_COMPANY_NAME: {
-					Player *p = GetPlayer(w->window_number);
-					WP(w,def_d).byte_1 = 1;
-					SetDParam(0, p->name_2);
-					ShowQueryString(p->name_1, STR_700A_COMPANY_NAME, 31, 150, w, CS_ALPHANUMERAL);
-					break;
-				}
-
-				case PCW_WIDGET_BUILD_VIEW_HQ: {
-					TileIndex tile = GetPlayer(w->window_number)->location_of_house;
-					if (tile == 0) {
-						if ((byte)w->window_number != _local_player)
-							return;
-						SetObjectToPlaceWnd(SPR_CURSOR_HQ, 1, w);
-						SetTileSelectSize(2, 2);
-						LowerWindowWidget(w, PCW_WIDGET_BUILD_VIEW_HQ);
-						InvalidateWidget(w, PCW_WIDGET_BUILD_VIEW_HQ);
-					} else {
-						ScrollMainWindowToTile(tile);
-					}
-					break;
-				}
-
-				case PCW_WIDGET_RELOCATE_HQ:
-					SetObjectToPlaceWnd(SPR_CURSOR_HQ, 1, w);
-					SetTileSelectSize(2, 2);
-					LowerWindowWidget(w, PCW_WIDGET_RELOCATE_HQ);
-					InvalidateWidget(w, PCW_WIDGET_RELOCATE_HQ);
-					break;
-
-				case PCW_WIDGET_BUY_SHARE:
-					DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
-					break;
-
-				case PCW_WIDGET_SELL_SHARE:
-					DoCommandP(0, w->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
-					break;
-
-				#ifdef ENABLE_NETWORK
-				case PCW_WIDGET_COMPANY_PASSWORD:
-					if (w->window_number == _local_player) {
-						WP(w,def_d).byte_1 = 2;
-						ShowQueryString(BindCString(_network_player_info[_local_player].password),
-							STR_SET_COMPANY_PASSWORD, sizeof(_network_player_info[_local_player].password), 250, w, CS_ALPHANUMERAL);
-					}
-					break;
-				#endif /* ENABLE_NETWORK */
-			}
-			break;
-
-		case WE_MOUSELOOP:
-			/* redraw the window every now and then */
-			if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w);
-			break;
-
-		case WE_PLACE_OBJ:
-			if (DoCommandP(e->we.place.tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
-				ResetObjectToPlace();
-				w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
-				RaiseWindowButtons(w);
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			RaiseWindowButtons(w);
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_PLAYER_FACE, w->window_number);
-			break;
-
-		case WE_ON_EDIT_TEXT: {
-			char *b = e->we.edittext.str;
-
-			// empty string is allowed for password
-			if (*b == '\0' && WP(w,def_d).byte_1 != 2) return;
-
-			_cmd_text = b;
-			switch (WP(w,def_d).byte_1) {
-				case 0: /* Change president name */
-					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
-					break;
-				case 1: /* Change company name */
-					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
-					break;
-				#ifdef ENABLE_NETWORK
-				case 2: /* Change company password */
-					if (*b == '\0') *b = '*'; // empty password is a '*' because of console argument
-					NetworkChangeCompanyPassword(1, &b);
-					break;
-				#endif /* ENABLE_NETWORK */
-			}
-			break;
-		}
-	}
-}
-
-
-static const WindowDesc _player_company_desc = {
-	WDP_AUTO, WDP_AUTO, 360, 170,
-	WC_COMPANY, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_player_company_widgets,
-	PlayerCompanyWndProc
-};
-
-void ShowPlayerCompany(PlayerID player)
-{
-	Window *w;
-
-	if (!IsValidPlayer(player)) return;
-
-	w = AllocateWindowDescFront(&_player_company_desc, player);
-	if (w != NULL) w->caption_color = w->window_number;
-}
-
-
-
-static void BuyCompanyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		Player *p = GetPlayer(w->window_number);
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		DrawWindowWidgets(w);
-
-		DrawPlayerFace(p->face, p->player_color, 2, 16);
-
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		SetDParam(2, p->bankrupt_value);
-		DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3:
-			DeleteWindow(w);
-			break;
-		case 4: {
-			DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
-			break;
-		}
-		}
-		break;
-	}
-}
-
-static const Widget _buy_company_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     5,     0,   333,    14,   136, 0x0,                   STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     5,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     5,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _buy_company_desc = {
-	153, 171, 334, 137,
-	WC_BUY_COMPANY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_buy_company_widgets,
-	BuyCompanyWndProc
-};
-
-
-void ShowBuyCompanyDialog(uint player)
-{
-	AllocateWindowDescFront(&_buy_company_desc, player);
-}
-
-/********** HIGHSCORE and ENDGAME windows */
-
-/* Always draw a maximized window and within there the centered background */
-static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
-{
-	uint i;
-	// resize window to "full-screen"
-	w->width = _screen.width;
-	w->height = _screen.height;
-	w->widget[0].right = w->width - 1;
-	w->widget[0].bottom = w->height - 1;
-
-	DrawWindowWidgets(w);
-
-	/* Center Highscore/Endscreen background */
-	*x = max(0, (_screen.width  / 2) - (640 / 2));
-	*y = max(0, (_screen.height / 2) - (480 / 2));
-	for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
-		DrawSprite(WP(w, highscore_d).background_img + i, *x, *y + (i * 50));
-}
-
-extern StringID EndGameGetPerformanceTitleFromValue(uint value);
-
-/* End game window shown at the end of the game */
-static void EndGameWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Player *p;
-		uint x, y;
-
-		SetupHighScoreEndWindow(w, &x, &y);
-
-		if (!IsValidPlayer(_local_player)) break;
-
-		p = GetPlayer(_local_player);
-		/* We need to get performance from last year because the image is shown
-		 * at the start of the new year when these things have already been copied */
-		if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
-			SetDParam(0, p->president_name_1);
-			SetDParam(1, p->president_name_2);
-			SetDParam(2, p->name_1);
-			SetDParam(3, p->name_2);
-			SetDParam(4, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
-			DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
-		} else {
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
-			DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
-		}
-	} break;
-	case WE_CLICK: /* Close the window (and show the highscore window) */
-		DeleteWindow(w);
-		break;
-	case WE_DESTROY: /* Show the highscore window when this one is closed */
-		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
-		ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
-		break;
-	}
-}
-
-static void HighScoreWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const HighScore *hs = _highscore_table[w->window_number];
-		uint x, y;
-		uint8 i;
-
-		SetupHighScoreEndWindow(w, &x, &y);
-
-		SetDParam(0, _patches.ending_year);
-		SetDParam(1, w->window_number + STR_6801_EASY);
-		DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
-
-		/* Draw Highscore peepz */
-		for (i = 0; i < lengthof(_highscore_table[0]); i++) {
-			SetDParam(0, i + 1);
-			DrawString(x + 40, y + 140 + (i * 55), STR_0212, 0x10);
-
-			if (hs[i].company[0] != '\0') {
-				uint16 colour = (WP(w, highscore_d).rank == (int8)i) ? 0x3 : 0x10; // draw new highscore in red
-
-				DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
-				SetDParam(0, hs[i].title);
-				SetDParam(1, hs[i].score);
-				DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
-			}
-		}
-	} break;
-
-	case WE_CLICK: /* Onclick to close window, and in destroy event handle the rest */
-		DeleteWindow(w);
-		break;
-
-	case WE_DESTROY: /* Get back all the hidden windows */
-		if (_game_mode != GM_MENU) ShowVitalWindows();
-
-		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
-		break;
-	}
-	}
-
-static const Widget _highscore_widgets[] = {
-{      WWT_PANEL, RESIZE_NONE, 16, 0, 640, 0, 480, 0x0, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _highscore_desc = {
-	0, 0, 641, 481,
-	WC_HIGHSCORE,0,
-	0,
-	_highscore_widgets,
-	HighScoreWndProc
-};
-
-static const WindowDesc _endgame_desc = {
-	0, 0, 641, 481,
-	WC_ENDSCREEN,0,
-	0,
-	_highscore_widgets,
-	EndGameWndProc
-};
-
-/* Show the highscore table for a given difficulty. When called from
- * endgame ranking is set to the top5 element that was newly added
- * and is thus highlighted */
-void ShowHighscoreTable(int difficulty, int8 ranking)
-{
-	Window *w;
-
-	// pause game to show the chart
-	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-
-	/* Close all always on-top windows to get a clean screen */
-	if (_game_mode != GM_MENU) HideVitalWindows();
-
-	DeleteWindowByClass(WC_HIGHSCORE);
-	w = AllocateWindowDesc(&_highscore_desc);
-
-	if (w != NULL) {
-		MarkWholeScreenDirty();
-		w->window_number = difficulty; // show highscore chart for difficulty...
-		WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
-		WP(w, highscore_d).rank = ranking;
-	}
-}
-
-/* Show the endgame victory screen in 2050. Update the new highscore
- * if it was high enough */
-void ShowEndGameChart(void)
-{
-	Window *w;
-
-	/* Dedicated server doesn't need the highscore window */
-	if (_network_dedicated) return;
-	/* Pause in single-player to have a look at the highscore at your own leisure */
-	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-
-	HideVitalWindows();
-	DeleteWindowByClass(WC_ENDSCREEN);
-	w = AllocateWindowDesc(&_endgame_desc);
-
-	if (w != NULL) {
-		MarkWholeScreenDirty();
-
-		WP(w, highscore_d).background_img = SPR_TYCOON_IMG1_BEGIN;
-
-		if (_local_player != PLAYER_SPECTATOR) {
-			const Player *p = GetPlayer(_local_player);
-			if (p->old_economy[0].performance_history == SCORE_MAX)
-				WP(w, highscore_d).background_img = SPR_TYCOON_IMG2_BEGIN;
-		}
-
-		/* In a network game show the endscores of the custom difficulty 'network' which is the last one
-		 * as well as generate a TOP5 of that game, and not an all-time top5. */
-		if (_networking) {
-			w->window_number = lengthof(_highscore_table) - 1;
-			WP(w, highscore_d).rank = SaveHighScoreValueNetwork();
-		} else {
-			// in single player _local player is always valid
-			const Player *p = GetPlayer(_local_player);
-			w->window_number = _opt.diff_level;
-			WP(w, highscore_d).rank = SaveHighScoreValue(p);
-		}
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/player_gui.cpp
@@ -0,0 +1,1131 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "player.h"
+#include "command.h"
+#include "vehicle.h"
+#include "economy.h"
+#include "network/network.h"
+#include "variables.h"
+#include "train.h"
+#include "date.h"
+#include "newgrf.h"
+#include "network/network_data.h"
+#include "network/network_client.h"
+
+static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied);
+
+static void DrawPlayerEconomyStats(const Player *p, byte mode)
+{
+	int x,y,i,j,year;
+	const int64 (*tbl)[13];
+	int64 sum, cost;
+	StringID str;
+
+	if (!(mode & 1)) { // normal sized economics window (mode&1) is minimized status
+		/* draw categories */
+		DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, 0);
+		for (i = 0; i != 13; i++)
+			DrawString(2, 27 + i*10, STR_7011_CONSTRUCTION + i, 0);
+		DrawStringRightAligned(111, 27 + 10*13 + 2, STR_7020_TOTAL, 0);
+
+		/* draw the price columns */
+		year = _cur_year - 2;
+		j = 3;
+		x = 215;
+		tbl = p->yearly_expenses + 2;
+		do {
+			if (year >= p->inaugurated_year) {
+				SetDParam(0, year);
+				DrawStringRightAlignedUnderline(x, 15, STR_7010, 0);
+				sum = 0;
+				for (i = 0; i != 13; i++) {
+					/* draw one row in the price column */
+					cost = (*tbl)[i];
+					if (cost != 0) {
+						sum += cost;
+
+						str = STR_701E;
+						if (cost < 0) { cost = -cost; str++; }
+						SetDParam64(0, cost);
+						DrawStringRightAligned(x, 27+i*10, str, 0);
+					}
+				}
+
+				str = STR_701E;
+				if (sum < 0) { sum = -sum; str++; }
+				SetDParam64(0, sum);
+				DrawStringRightAligned(x, 27 + 13*10 + 2, str, 0);
+
+				GfxFillRect(x - 75, 27 + 10*13, x, 27 + 10*13, 215);
+				x += 95;
+			}
+			year++;
+			tbl--;
+		} while (--j != 0);
+
+		y = 171;
+
+		// draw max loan aligned to loan below (y += 10)
+		SetDParam64(0, (uint64)_economy.max_loan);
+		DrawString(202, y+10, STR_MAX_LOAN, 0);
+	} else {
+		y = 15;
+	}
+
+	DrawString(2, y, STR_7026_BANK_BALANCE, 0);
+	SetDParam64(0, p->money64);
+	DrawStringRightAligned(182, y, STR_7028, 0);
+
+	y += 10;
+
+	DrawString(2, y, STR_7027_LOAN, 0);
+	SetDParam64(0, p->current_loan);
+	DrawStringRightAligned(182, y, STR_7028, 0);
+
+	y += 12;
+
+	GfxFillRect(182 - 75, y-2, 182, y-2, 215);
+
+	SetDParam64(0, p->money64 - p->current_loan);
+	DrawStringRightAligned(182, y, STR_7028, 0);
+}
+
+static const Widget _player_finances_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,    14,   169, 0x0,                    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,   170,   203, 0x0,                    STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   202,   204,   215, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   203,   406,   204,   215, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
+{   WIDGETS_END},
+};
+
+static const Widget _other_player_finances_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,    14,   169, 0x0,                    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   406,   170,   203, 0x0,                    STR_NULL},
+{   WIDGETS_END},
+};
+
+static const Widget _other_player_finances_small_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    47, 0x0,                    STR_NULL},
+{   WIDGETS_END},
+};
+
+static const Widget _player_finances_small_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                    STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   279,    14,    47, STR_NULL,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   139,    48,    59, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   140,   279,    48,    59, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
+{   WIDGETS_END},
+};
+
+
+static void PlayerFinancesWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		PlayerID player = w->window_number;
+		const Player *p = GetPlayer(player);
+
+		if (player == _local_player) {
+			/* borrow/repay buttons only exist for local player */
+			SetWindowWidgetDisabledState(w, 7, p->current_loan == 0);
+		}
+
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		SetDParam(2, GetPlayerNameString(player, 3));
+		SetDParam(4, 10000);
+		DrawWindowWidgets(w);
+
+		DrawPlayerEconomyStats(p, (byte)WP(w,def_d).data_1);
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: {/* toggle size */
+			byte mode = (byte)WP(w,def_d).data_1;
+			bool stickied = !!(w->flags4 & WF_STICKY);
+			PlayerID player = w->window_number;
+			DeleteWindow(w);
+			DoShowPlayerFinances(player, !HASBIT(mode, 0), stickied);
+		} break;
+
+		case 6: /* increase loan */
+			DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
+			break;
+
+		case 7: /* repay loan */
+			DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
+			break;
+		}
+		break;
+	}
+}
+
+static const WindowDesc _player_finances_desc = {
+	WDP_AUTO, WDP_AUTO, 407, 216,
+	WC_FINANCES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_player_finances_widgets,
+	PlayerFinancesWndProc
+};
+
+static const WindowDesc _player_finances_small_desc = {
+	WDP_AUTO, WDP_AUTO, 280, 60,
+	WC_FINANCES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_player_finances_small_widgets,
+	PlayerFinancesWndProc
+};
+
+static const WindowDesc _other_player_finances_desc = {
+	WDP_AUTO, WDP_AUTO, 407, 204,
+	WC_FINANCES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_other_player_finances_widgets,
+	PlayerFinancesWndProc
+};
+
+static const WindowDesc _other_player_finances_small_desc = {
+	WDP_AUTO, WDP_AUTO, 280, 48,
+	WC_FINANCES,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_other_player_finances_small_widgets,
+	PlayerFinancesWndProc
+};
+
+static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied)
+{
+	Window *w;
+	int mode;
+
+	static const WindowDesc * const desc_table[2 * 2] = {
+		&_player_finances_desc, &_player_finances_small_desc,
+		&_other_player_finances_desc, &_other_player_finances_small_desc,
+	};
+
+	if (!IsValidPlayer(player)) return;
+
+	mode = (player != _local_player) * 2 + show_small;
+	w = AllocateWindowDescFront(desc_table[mode], player);
+	if (w != NULL) {
+		w->caption_color = w->window_number;
+		WP(w,def_d).data_1 = mode;
+		if (show_stickied) w->flags4 |= WF_STICKY;
+	}
+}
+
+void ShowPlayerFinances(PlayerID player)
+{
+	DoShowPlayerFinances(player, false, false);
+}
+
+/* List of colours for the livery window */
+static const StringID _colour_dropdown[] = {
+	STR_00D1_DARK_BLUE,
+	STR_00D2_PALE_GREEN,
+	STR_00D3_PINK,
+	STR_00D4_YELLOW,
+	STR_00D5_RED,
+	STR_00D6_LIGHT_BLUE,
+	STR_00D7_GREEN,
+	STR_00D8_DARK_GREEN,
+	STR_00D9_BLUE,
+	STR_00DA_CREAM,
+	STR_00DB_MAUVE,
+	STR_00DC_PURPLE,
+	STR_00DD_ORANGE,
+	STR_00DE_BROWN,
+	STR_00DF_GREY,
+	STR_00E0_WHITE,
+	INVALID_STRING_ID
+};
+
+/* Association of liveries to livery classes */
+static const LiveryClass livery_class[LS_END] = {
+	LC_OTHER,
+	LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
+	LC_ROAD, LC_ROAD,
+	LC_SHIP, LC_SHIP,
+	LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
+};
+
+/* Number of liveries in each class, used to determine the height of the livery window */
+static const byte livery_height[] = {
+	1,
+	11,
+	2,
+	2,
+	3,
+};
+
+typedef struct livery_d {
+	uint32 sel;
+	LiveryClass livery_class;
+} livery_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d));
+
+static void ShowColourDropDownMenu(Window *w, uint32 widget)
+{
+	uint32 used_colours = 0;
+	const Livery *livery;
+	LiveryScheme scheme;
+
+	/* Disallow other player colours for the primary colour */
+	if (HASBIT(WP(w, livery_d).sel, LS_DEFAULT) && widget == 10) {
+		const Player *p;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && p->index != _local_player) SETBIT(used_colours, p->player_color);
+		}
+	}
+
+	/* Get the first selected livery to use as the default dropdown item */
+	for (scheme = 0; scheme < LS_END; scheme++) {
+		if (HASBIT(WP(w, livery_d).sel, scheme)) break;
+	}
+	if (scheme == LS_END) scheme = LS_DEFAULT;
+	livery = &GetPlayer(w->window_number)->livery[scheme];
+
+	ShowDropDownMenu(w, _colour_dropdown, widget == 10 ? livery->colour1 : livery->colour2, widget, used_colours, 0);
+}
+
+static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_CREATE:
+			LowerWindowWidget(w, WP(w, livery_d).livery_class + 2);
+			if (!_have_2cc) {
+				HideWindowWidget(w, 11);
+				HideWindowWidget(w, 12);
+			}
+			break;
+
+		case WE_PAINT: {
+			const Player *p = GetPlayer(w->window_number);
+			LiveryScheme scheme = LS_DEFAULT;
+			int y = 51;
+
+			/* Disable dropdown controls if no scheme is selected */
+			SetWindowWidgetDisabledState(w,  9, (WP(w, livery_d).sel == 0));
+			SetWindowWidgetDisabledState(w, 10, (WP(w, livery_d).sel == 0));
+			SetWindowWidgetDisabledState(w, 11, (WP(w, livery_d).sel == 0));
+			SetWindowWidgetDisabledState(w, 12, (WP(w, livery_d).sel == 0));
+
+			if (!(WP(w, livery_d).sel == 0)) {
+				for (scheme = 0; scheme < LS_END; scheme++) {
+					if (HASBIT(WP(w, livery_d).sel, scheme)) break;
+				}
+				if (scheme == LS_END) scheme = LS_DEFAULT;
+			}
+
+			SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
+			SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
+
+			DrawWindowWidgets(w);
+
+			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+				if (livery_class[scheme] == WP(w, livery_d).livery_class) {
+					bool sel = HASBIT(WP(w, livery_d).sel, scheme) != 0;
+
+					if (scheme != LS_DEFAULT) {
+						DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, 2, y);
+					}
+
+					DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? 0xC : 0x10);
+
+					DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour1) | PALETTE_MODIFIER_COLOR, 152, y);
+					DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? 0xC : 2);
+
+					if (_have_2cc) {
+						DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour2) | PALETTE_MODIFIER_COLOR, 277, y);
+						DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? 0xC : 2);
+					}
+
+					y += 14;
+				}
+			}
+			break;
+		}
+
+		case WE_CLICK: {
+			switch (e->we.click.widget) {
+				/* Livery Class buttons */
+				case 2:
+				case 3:
+				case 4:
+				case 5:
+				case 6: {
+					LiveryScheme scheme;
+
+					RaiseWindowWidget(w, WP(w, livery_d).livery_class + 2);
+					WP(w, livery_d).livery_class = e->we.click.widget - 2;
+					WP(w, livery_d).sel = 0;
+					LowerWindowWidget(w, WP(w, livery_d).livery_class + 2);
+
+					/* Select the first item in the list */
+					for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+						if (livery_class[scheme] == WP(w, livery_d).livery_class) {
+							WP(w, livery_d).sel = 1 << scheme;
+							break;
+						}
+					}
+					w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14;
+					w->widget[13].bottom = w->height - 1;
+					w->widget[13].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1;
+					MarkWholeScreenDirty();
+					break;
+				}
+
+				case 9:
+				case 10: // First colour dropdown
+					ShowColourDropDownMenu(w, 10);
+					break;
+
+				case 11:
+				case 12: // Second colour dropdown
+					ShowColourDropDownMenu(w, 12);
+					break;
+
+				case 13: {
+					LiveryScheme scheme;
+					LiveryScheme j = (e->we.click.pt.y - 48) / 14;
+
+					for (scheme = 0; scheme <= j; scheme++) {
+						if (livery_class[scheme] != WP(w, livery_d).livery_class) j++;
+						if (scheme >= LS_END) return;
+					}
+					if (j >= LS_END) return;
+
+					/* If clicking on the left edge, toggle using the livery */
+					if (e->we.click.pt.x < 10) {
+						DoCommandP(0, j | (2 << 8), !GetPlayer(w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
+					}
+
+					if (_ctrl_pressed) {
+						TOGGLEBIT(WP(w, livery_d).sel, j);
+					} else {
+						WP(w, livery_d).sel = 1 << j;
+					}
+					SetWindowDirty(w);
+					break;
+				}
+			}
+			break;
+		}
+
+		case WE_DROPDOWN_SELECT: {
+			LiveryScheme scheme;
+
+			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+				if (HASBIT(WP(w, livery_d).sel, scheme)) {
+					DoCommandP(0, scheme | (e->we.dropdown.button == 10 ? 0 : 256), e->we.dropdown.index, NULL, CMD_SET_PLAYER_COLOR);
+				}
+			}
+			break;
+		}
+	}
+}
+
+static const Widget _select_player_livery_2cc_widgets[] = {
+{ WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
+{  WWT_CAPTION, RESIZE_NONE, 14,  11, 399,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
+{   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
+{    WWT_PANEL, RESIZE_NONE, 14, 110, 399,  14,  35, 0x0,                       STR_NULL },
+{    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 150, 262,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 263, 274,  36,  47, STR_0225,                  STR_LIVERY_PRIMARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 387,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 388, 399,  36,  47, STR_0225,                  STR_LIVERY_SECONDARY_TIP },
+{   WWT_MATRIX, RESIZE_NONE, 14,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
+{ WIDGETS_END },
+};
+
+static const WindowDesc _select_player_livery_2cc_desc = {
+	WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14,
+	WC_PLAYER_COLOR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_select_player_livery_2cc_widgets,
+	SelectPlayerLiveryWndProc
+};
+
+
+static const Widget _select_player_livery_widgets[] = {
+{ WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
+{  WWT_CAPTION, RESIZE_NONE, 14,  11, 274,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
+{   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
+{   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
+{    WWT_PANEL, RESIZE_NONE, 14, 110, 274,  14,  35, 0x0,                       STR_NULL },
+{    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 150, 262,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 263, 274,  36,  47, STR_0225,                  STR_LIVERY_PRIMARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
+{  WWT_TEXTBTN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_0225,                  STR_LIVERY_SECONDARY_TIP },
+{   WWT_MATRIX, RESIZE_NONE, 14,   0, 274,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
+{ WIDGETS_END },
+};
+
+static const WindowDesc _select_player_livery_desc = {
+	WDP_AUTO, WDP_AUTO, 275, 49 + 1 * 14,
+	WC_PLAYER_COLOR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_select_player_livery_widgets,
+	SelectPlayerLiveryWndProc
+};
+
+static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		Player *p;
+		LowerWindowWidget(w, WP(w, facesel_d).gender + 5);
+		DrawWindowWidgets(w);
+		p = GetPlayer(w->window_number);
+		DrawPlayerFace(WP(w,facesel_d).face, p->player_color, 2, 16);
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: DeleteWindow(w); break;
+		case 4: /* ok click */
+			DoCommandP(0, 0, WP(w,facesel_d).face, NULL, CMD_SET_PLAYER_FACE);
+			DeleteWindow(w);
+			break;
+		case 5: /* male click */
+		case 6: /* female click */
+			RaiseWindowWidget(w, WP(w, facesel_d).gender + 5);
+			WP(w, facesel_d).gender = e->we.click.widget - 5;
+			LowerWindowWidget(w, WP(w, facesel_d).gender + 5);
+			SetWindowDirty(w);
+			break;
+		case 7:
+			WP(w,facesel_d).face = (WP(w,facesel_d).gender << 31) + GB(InteractiveRandom(), 0, 31);
+			SetWindowDirty(w);
+			break;
+		}
+		break;
+	}
+}
+
+static const Widget _select_player_face_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   189,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   189,    14,   136, 0x0,                     STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    94,   137,   148, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   189,   137,   148, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    25,    36, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    95,   187,    37,    48, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    95,   187,    79,    90, STR_7046_NEW_FACE,       STR_704B_GENERATE_RANDOM_NEW_FACE},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _select_player_face_desc = {
+	WDP_AUTO, WDP_AUTO, 190, 149,
+	WC_PLAYER_FACE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_select_player_face_widgets,
+	SelectPlayerFaceWndProc
+};
+
+/* Names of the widgets. Keep them in the same order as in the widget array */
+enum PlayerCompanyWindowWidgets {
+	PCW_WIDGET_CLOSEBOX = 0,
+	PCW_WIDGET_CAPTION,
+	PCW_WIDGET_FACE,
+	PCW_WIDGET_NEW_FACE,
+	PCW_WIDGET_COLOR_SCHEME,
+	PCW_WIDGET_PRESIDENT_NAME,
+	PCW_WIDGET_COMPANY_NAME,
+	PCW_WIDGET_BUILD_VIEW_HQ,
+	PCW_WIDGET_RELOCATE_HQ,
+	PCW_WIDGET_BUY_SHARE,
+	PCW_WIDGET_SELL_SHARE,
+	PCW_WIDGET_COMPANY_PASSWORD,
+};
+
+static const Widget _player_company_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   359,    14,   157, 0x0,                               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    90,   179,   158,   169, STR_7005_COLOR_SCHEME,             STR_7031_CHANGE_THE_COMPANY_VEHICLE},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,   179,   158,   169, STR_7077_BUY_25_SHARE_IN_COMPANY,  STR_7079_BUY_25_SHARE_IN_THIS_COMPANY},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   180,   359,   158,   169, STR_7078_SELL_25_SHARE_IN_COMPANY, STR_707A_SELL_25_SHARE_IN_THIS_COMPANY},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
+{   WIDGETS_END},
+};
+
+static void DrawPlayerVehiclesAmount(PlayerID player)
+{
+	const int x = 110;
+	int y = 72;
+	const Vehicle *v;
+	uint train = 0;
+	uint road  = 0;
+	uint air   = 0;
+	uint ship  = 0;
+
+	DrawString(x, y, STR_7039_VEHICLES, 0);
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->owner == player) {
+			switch (v->type) {
+				case VEH_Train:    if (IsFrontEngine(v)) train++; break;
+				case VEH_Road:     road++; break;
+				case VEH_Aircraft: if (v->subtype <= 2) air++; break;
+				case VEH_Ship:     ship++; break;
+				default: break;
+			}
+		}
+	}
+
+	if (train+road+air+ship == 0) {
+		DrawString(x+70, y, STR_7042_NONE, 0);
+	} else {
+		if (train != 0) {
+			SetDParam(0, train);
+			DrawString(x + 70, y, STR_TRAINS, 0);
+			y += 10;
+		}
+
+		if (road != 0) {
+			SetDParam(0, road);
+			DrawString(x + 70, y, STR_ROAD_VEHICLES, 0);
+			y += 10;
+		}
+
+		if (air != 0) {
+			SetDParam(0, air);
+			DrawString(x + 70, y, STR_AIRCRAFT, 0);
+			y += 10;
+		}
+
+		if (ship != 0) {
+			SetDParam(0, ship);
+			DrawString(x + 70, y, STR_SHIPS, 0);
+		}
+	}
+}
+
+int GetAmountOwnedBy(const Player *p, PlayerID owner)
+{
+	return (p->share_owners[0] == owner) +
+				 (p->share_owners[1] == owner) +
+				 (p->share_owners[2] == owner) +
+				 (p->share_owners[3] == owner);
+}
+
+static void DrawCompanyOwnerText(const Player *p)
+{
+	const Player *p2;
+	int num = -1;
+
+	FOR_ALL_PLAYERS(p2) {
+		uint amt = GetAmountOwnedBy(p, p2->index);
+		if (amt != 0) {
+			num++;
+
+			SetDParam(num * 3 + 0, amt * 25);
+			SetDParam(num * 3 + 1, p2->name_1);
+			SetDParam(num * 3 + 2, p2->name_2);
+
+			if (num != 0) break;
+		}
+	}
+
+	if (num >= 0) DrawString(120, 124, STR_707D_OWNED_BY + num, 0);
+}
+
+static void PlayerCompanyWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			const Player *p = GetPlayer(w->window_number);
+			bool local = w->window_number == _local_player;
+
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_NEW_FACE,       !local);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_COLOR_SCHEME,   !local);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_PRESIDENT_NAME, !local);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_COMPANY_NAME,   !local);
+			w->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
+			if (local && p->location_of_house != 0) w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
+			SetWindowWidgetDisabledState(w, PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_RELOCATE_HQ,      !local || p->location_of_house == 0);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_BUY_SHARE,        local);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_SELL_SHARE,       local);
+			SetWindowWidgetHiddenState(w, PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
+
+			if (!local) {
+				if (_patches.allow_shares) { // Shares are allowed
+					/* If all shares are owned by someone (none by nobody), disable buy button */
+					SetWindowWidgetDisabledState(w, PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
+							/* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
+							(GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
+							/* Spectators cannot do anything of course */
+							_local_player == PLAYER_SPECTATOR);
+
+					/* If the player doesn't own any shares, disable sell button */
+					SetWindowWidgetDisabledState(w, PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
+							/* Spectators cannot do anything of course */
+							_local_player == PLAYER_SPECTATOR);
+				} else { // Shares are not allowed, disable buy/sell buttons
+					DisableWindowWidget(w, PCW_WIDGET_BUY_SHARE);
+					DisableWindowWidget(w, PCW_WIDGET_SELL_SHARE);
+				}
+			}
+
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			SetDParam(2, GetPlayerNameString((byte)w->window_number, 3));
+
+			DrawWindowWidgets(w);
+
+			SetDParam(0, p->inaugurated_year);
+			DrawString(110, 25, STR_7038_INAUGURATED, 0);
+
+			DrawPlayerVehiclesAmount(w->window_number);
+
+			DrawString(110,48, STR_7006_COLOR_SCHEME, 0);
+			// Draw company-colour bus
+			DrawSprite(PLAYER_SPRITE_COLOR(p->index) + SPRITE_PALETTE(SPR_VEH_BUS_SW_VIEW), 215, 49);
+
+			DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+			SetDParam(0, p->president_name_1);
+			SetDParam(1, p->president_name_2);
+			DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
+
+			SetDParam64(0, CalculateCompanyValue(p));
+			DrawString(110, 114, STR_7076_COMPANY_VALUE, 0);
+
+			DrawCompanyOwnerText(p);
+
+			break;
+		}
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case PCW_WIDGET_NEW_FACE: {
+					Window *wf = AllocateWindowDescFront(&_select_player_face_desc, w->window_number);
+					if (wf != NULL) {
+						wf->caption_color = w->window_number;
+						WP(wf,facesel_d).face = GetPlayer(wf->window_number)->face;
+						WP(wf,facesel_d).gender = 0;
+					}
+					break;
+				}
+
+				case PCW_WIDGET_COLOR_SCHEME: {
+					Window *wf = AllocateWindowDescFront(_have_2cc ? &_select_player_livery_2cc_desc : &_select_player_livery_desc, w->window_number);
+					if (wf != NULL) {
+						wf->caption_color = wf->window_number;
+						WP(wf,livery_d).livery_class = LC_OTHER;
+						WP(wf,livery_d).sel = 1;
+						LowerWindowWidget(wf, 2);
+					}
+					break;
+				}
+
+				case PCW_WIDGET_PRESIDENT_NAME: {
+					const Player *p = GetPlayer(w->window_number);
+					WP(w, def_d).byte_1 = 0;
+					SetDParam(0, p->president_name_2);
+					ShowQueryString(p->president_name_1, STR_700B_PRESIDENT_S_NAME, 31, 94, w, CS_ALPHANUMERAL);
+					break;
+				}
+
+				case PCW_WIDGET_COMPANY_NAME: {
+					Player *p = GetPlayer(w->window_number);
+					WP(w,def_d).byte_1 = 1;
+					SetDParam(0, p->name_2);
+					ShowQueryString(p->name_1, STR_700A_COMPANY_NAME, 31, 150, w, CS_ALPHANUMERAL);
+					break;
+				}
+
+				case PCW_WIDGET_BUILD_VIEW_HQ: {
+					TileIndex tile = GetPlayer(w->window_number)->location_of_house;
+					if (tile == 0) {
+						if ((byte)w->window_number != _local_player)
+							return;
+						SetObjectToPlaceWnd(SPR_CURSOR_HQ, 1, w);
+						SetTileSelectSize(2, 2);
+						LowerWindowWidget(w, PCW_WIDGET_BUILD_VIEW_HQ);
+						InvalidateWidget(w, PCW_WIDGET_BUILD_VIEW_HQ);
+					} else {
+						ScrollMainWindowToTile(tile);
+					}
+					break;
+				}
+
+				case PCW_WIDGET_RELOCATE_HQ:
+					SetObjectToPlaceWnd(SPR_CURSOR_HQ, 1, w);
+					SetTileSelectSize(2, 2);
+					LowerWindowWidget(w, PCW_WIDGET_RELOCATE_HQ);
+					InvalidateWidget(w, PCW_WIDGET_RELOCATE_HQ);
+					break;
+
+				case PCW_WIDGET_BUY_SHARE:
+					DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
+					break;
+
+				case PCW_WIDGET_SELL_SHARE:
+					DoCommandP(0, w->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
+					break;
+
+				#ifdef ENABLE_NETWORK
+				case PCW_WIDGET_COMPANY_PASSWORD:
+					if (w->window_number == _local_player) {
+						WP(w,def_d).byte_1 = 2;
+						ShowQueryString(BindCString(_network_player_info[_local_player].password),
+							STR_SET_COMPANY_PASSWORD, sizeof(_network_player_info[_local_player].password), 250, w, CS_ALPHANUMERAL);
+					}
+					break;
+				#endif /* ENABLE_NETWORK */
+			}
+			break;
+
+		case WE_MOUSELOOP:
+			/* redraw the window every now and then */
+			if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w);
+			break;
+
+		case WE_PLACE_OBJ:
+			if (DoCommandP(e->we.place.tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
+				ResetObjectToPlace();
+				w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
+				RaiseWindowButtons(w);
+			break;
+
+		case WE_ABORT_PLACE_OBJ:
+			RaiseWindowButtons(w);
+			break;
+
+		case WE_DESTROY:
+			DeleteWindowById(WC_PLAYER_FACE, w->window_number);
+			break;
+
+		case WE_ON_EDIT_TEXT: {
+			char *b = e->we.edittext.str;
+
+			// empty string is allowed for password
+			if (*b == '\0' && WP(w,def_d).byte_1 != 2) return;
+
+			_cmd_text = b;
+			switch (WP(w,def_d).byte_1) {
+				case 0: /* Change president name */
+					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
+					break;
+				case 1: /* Change company name */
+					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
+					break;
+				#ifdef ENABLE_NETWORK
+				case 2: /* Change company password */
+					if (*b == '\0') *b = '*'; // empty password is a '*' because of console argument
+					NetworkChangeCompanyPassword(1, &b);
+					break;
+				#endif /* ENABLE_NETWORK */
+			}
+			break;
+		}
+	}
+}
+
+
+static const WindowDesc _player_company_desc = {
+	WDP_AUTO, WDP_AUTO, 360, 170,
+	WC_COMPANY, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_player_company_widgets,
+	PlayerCompanyWndProc
+};
+
+void ShowPlayerCompany(PlayerID player)
+{
+	Window *w;
+
+	if (!IsValidPlayer(player)) return;
+
+	w = AllocateWindowDescFront(&_player_company_desc, player);
+	if (w != NULL) w->caption_color = w->window_number;
+}
+
+
+
+static void BuyCompanyWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		Player *p = GetPlayer(w->window_number);
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		DrawWindowWidgets(w);
+
+		DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		SetDParam(2, p->bankrupt_value);
+		DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3:
+			DeleteWindow(w);
+			break;
+		case 4: {
+			DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
+			break;
+		}
+		}
+		break;
+	}
+}
+
+static const Widget _buy_company_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     5,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     5,     0,   333,    14,   136, 0x0,                   STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     5,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     5,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _buy_company_desc = {
+	153, 171, 334, 137,
+	WC_BUY_COMPANY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_buy_company_widgets,
+	BuyCompanyWndProc
+};
+
+
+void ShowBuyCompanyDialog(uint player)
+{
+	AllocateWindowDescFront(&_buy_company_desc, player);
+}
+
+/********** HIGHSCORE and ENDGAME windows */
+
+/* Always draw a maximized window and within there the centered background */
+static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
+{
+	uint i;
+	// resize window to "full-screen"
+	w->width = _screen.width;
+	w->height = _screen.height;
+	w->widget[0].right = w->width - 1;
+	w->widget[0].bottom = w->height - 1;
+
+	DrawWindowWidgets(w);
+
+	/* Center Highscore/Endscreen background */
+	*x = max(0, (_screen.width  / 2) - (640 / 2));
+	*y = max(0, (_screen.height / 2) - (480 / 2));
+	for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
+		DrawSprite(WP(w, highscore_d).background_img + i, *x, *y + (i * 50));
+}
+
+extern StringID EndGameGetPerformanceTitleFromValue(uint value);
+
+/* End game window shown at the end of the game */
+static void EndGameWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Player *p;
+		uint x, y;
+
+		SetupHighScoreEndWindow(w, &x, &y);
+
+		if (!IsValidPlayer(_local_player)) break;
+
+		p = GetPlayer(_local_player);
+		/* We need to get performance from last year because the image is shown
+		 * at the start of the new year when these things have already been copied */
+		if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
+			SetDParam(0, p->president_name_1);
+			SetDParam(1, p->president_name_2);
+			SetDParam(2, p->name_1);
+			SetDParam(3, p->name_2);
+			SetDParam(4, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+			DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
+		} else {
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+			DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+		}
+	} break;
+	case WE_CLICK: /* Close the window (and show the highscore window) */
+		DeleteWindow(w);
+		break;
+	case WE_DESTROY: /* Show the highscore window when this one is closed */
+		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+		ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
+		break;
+	}
+}
+
+static void HighScoreWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const HighScore *hs = _highscore_table[w->window_number];
+		uint x, y;
+		uint8 i;
+
+		SetupHighScoreEndWindow(w, &x, &y);
+
+		SetDParam(0, _patches.ending_year);
+		SetDParam(1, w->window_number + STR_6801_EASY);
+		DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
+
+		/* Draw Highscore peepz */
+		for (i = 0; i < lengthof(_highscore_table[0]); i++) {
+			SetDParam(0, i + 1);
+			DrawString(x + 40, y + 140 + (i * 55), STR_0212, 0x10);
+
+			if (hs[i].company[0] != '\0') {
+				uint16 colour = (WP(w, highscore_d).rank == (int8)i) ? 0x3 : 0x10; // draw new highscore in red
+
+				DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
+				SetDParam(0, hs[i].title);
+				SetDParam(1, hs[i].score);
+				DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
+			}
+		}
+	} break;
+
+	case WE_CLICK: /* Onclick to close window, and in destroy event handle the rest */
+		DeleteWindow(w);
+		break;
+
+	case WE_DESTROY: /* Get back all the hidden windows */
+		if (_game_mode != GM_MENU) ShowVitalWindows();
+
+		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+		break;
+	}
+	}
+
+static const Widget _highscore_widgets[] = {
+{      WWT_PANEL, RESIZE_NONE, 16, 0, 640, 0, 480, 0x0, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _highscore_desc = {
+	0, 0, 641, 481,
+	WC_HIGHSCORE,0,
+	0,
+	_highscore_widgets,
+	HighScoreWndProc
+};
+
+static const WindowDesc _endgame_desc = {
+	0, 0, 641, 481,
+	WC_ENDSCREEN,0,
+	0,
+	_highscore_widgets,
+	EndGameWndProc
+};
+
+/* Show the highscore table for a given difficulty. When called from
+ * endgame ranking is set to the top5 element that was newly added
+ * and is thus highlighted */
+void ShowHighscoreTable(int difficulty, int8 ranking)
+{
+	Window *w;
+
+	// pause game to show the chart
+	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+
+	/* Close all always on-top windows to get a clean screen */
+	if (_game_mode != GM_MENU) HideVitalWindows();
+
+	DeleteWindowByClass(WC_HIGHSCORE);
+	w = AllocateWindowDesc(&_highscore_desc);
+
+	if (w != NULL) {
+		MarkWholeScreenDirty();
+		w->window_number = difficulty; // show highscore chart for difficulty...
+		WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
+		WP(w, highscore_d).rank = ranking;
+	}
+}
+
+/* Show the endgame victory screen in 2050. Update the new highscore
+ * if it was high enough */
+void ShowEndGameChart(void)
+{
+	Window *w;
+
+	/* Dedicated server doesn't need the highscore window */
+	if (_network_dedicated) return;
+	/* Pause in single-player to have a look at the highscore at your own leisure */
+	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
+
+	HideVitalWindows();
+	DeleteWindowByClass(WC_ENDSCREEN);
+	w = AllocateWindowDesc(&_endgame_desc);
+
+	if (w != NULL) {
+		MarkWholeScreenDirty();
+
+		WP(w, highscore_d).background_img = SPR_TYCOON_IMG1_BEGIN;
+
+		if (_local_player != PLAYER_SPECTATOR) {
+			const Player *p = GetPlayer(_local_player);
+			if (p->old_economy[0].performance_history == SCORE_MAX)
+				WP(w, highscore_d).background_img = SPR_TYCOON_IMG2_BEGIN;
+		}
+
+		/* In a network game show the endscores of the custom difficulty 'network' which is the last one
+		 * as well as generate a TOP5 of that game, and not an all-time top5. */
+		if (_networking) {
+			w->window_number = lengthof(_highscore_table) - 1;
+			WP(w, highscore_d).rank = SaveHighScoreValueNetwork();
+		} else {
+			// in single player _local player is always valid
+			const Player *p = GetPlayer(_local_player);
+			w->window_number = _opt.diff_level;
+			WP(w, highscore_d).rank = SaveHighScoreValue(p);
+		}
+	}
+}
deleted file mode 100644
--- a/src/players.c
+++ /dev/null
@@ -1,1339 +0,0 @@
-/* $Id$ */
-
-/** @file players.c
- * @todo Cleanup the messy DrawPlayerFace function asap
- */
-#include "stdafx.h"
-#include "openttd.h"
-#include "engine.h"
-#include "functions.h"
-#include "string.h"
-#include "strings.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "player.h"
-#include "town.h"
-#include "vehicle.h"
-#include "station.h"
-#include "gfx.h"
-#include "news.h"
-#include "saveload.h"
-#include "command.h"
-#include "sound.h"
-#include "network/network.h"
-#include "variables.h"
-#include "engine.h"
-#include "ai/ai.h"
-#include "date.h"
-#include "window.h"
-
-/**
- * Sets the local player and updates the patch settings that are set on a
- * per-company (player) basis to reflect the core's state in the GUI.
- * @param new_player the new player
- * @pre IsValidPlayer(new_player) || new_player == PLAYER_SPECTATOR || new_player == OWNER_NONE
- */
-void SetLocalPlayer(PlayerID new_player)
-{
-	/* Player could also be PLAYER_SPECTATOR or OWNER_NONE */
-	assert(IsValidPlayer(new_player) || new_player == PLAYER_SPECTATOR || new_player == OWNER_NONE);
-
-	_local_player = new_player;
-
-	/* Do not update the patches if we are in the intro GUI */
-	if (IsValidPlayer(new_player) && _game_mode != GM_MENU) {
-		const Player *p = GetPlayer(new_player);
-		_patches.autorenew        = p->engine_renew;
-		_patches.autorenew_months = p->engine_renew_months;
-		_patches.autorenew_money  = p->engine_renew_money;
-		InvalidateWindow(WC_GAME_OPTIONS, 0);
-	}
-}
-
-
-uint16 GetDrawStringPlayerColor(PlayerID player)
-{
-	/* Get the color for DrawString-subroutines which matches the color
-	 * of the player */
-	if (!IsValidPlayer(player)) return _colour_gradient[COLOUR_WHITE][4] | IS_PALETTE_COLOR;
-	return (_colour_gradient[_player_colors[player]][4]) | IS_PALETTE_COLOR;
-}
-
-
-static const SpriteID cheeks_table[4] = {
-	0x325, 0x326,
-	0x390, 0x3B0,
-};
-
-static const SpriteID mouth_table[3] = {
-	0x34C, 0x34D, 0x34F
-};
-
-void DrawPlayerFace(uint32 face, int color, int x, int y)
-{
-	byte flag = 0;
-
-	if ( (int32)face < 0)
-		flag |= 1;
-	if ((((((face >> 7) ^ face) >> 7) ^ face) & 0x8080000) == 0x8000000)
-		flag |= 2;
-
-	/* draw the gradient */
-	DrawSprite(GENERAL_SPRITE_COLOR(color) + SPRITE_PALETTE(SPR_GRADIENT), x, y);
-
-	/* draw the cheeks */
-	DrawSprite(cheeks_table[flag&3], x, y);
-
-	/* draw the chin */
-	/* FIXME: real code uses -2 in zoomlevel 1 */
-	{
-		uint val = GB(face, 4, 2);
-		if (!(flag & 2)) {
-			DrawSprite(0x327 + (flag&1?0:val), x, y);
-		} else {
-			DrawSprite((flag&1?0x3B1:0x391) + (val>>1), x, y);
-		}
-	}
-	/* draw the eyes */
-	{
-		uint val1 = GB(face,  6, 4);
-		uint val2 = GB(face, 20, 3);
-		uint32 high = 0x314 << PALETTE_SPRITE_START;
-
-		if (val2 >= 6) {
-			high = 0x30F << PALETTE_SPRITE_START;
-			if (val2 != 6)
-				high = 0x30D << PALETTE_SPRITE_START;
-		}
-
-		if (!(flag & 2)) {
-			if (!(flag & 1)) {
-				DrawSprite(high+((val1 * 12 >> 4) + SPRITE_PALETTE(0x32B)), x, y);
-			} else {
-				DrawSprite(high+(val1 + SPRITE_PALETTE(0x337)), x, y);
-			}
-		} else {
-			if (!(flag & 1)) {
-				DrawSprite(high+((val1 * 11 >> 4) + SPRITE_PALETTE(0x39A)), x, y);
-			} else {
-				DrawSprite(high+(val1 + SPRITE_PALETTE(0x3B8)), x, y);
-			}
-		}
-	}
-
-	/* draw the mouth */
-	{
-		uint val = GB(face, 10, 6);
-		uint val2;
-
-		if (!(flag&1)) {
-			val2 = ((val&0xF) * 15 >> 4);
-
-			if (val2 < 3) {
-				DrawSprite((flag&2 ? 0x397 : 0x367) + val2, x, y);
-				/* skip the rest */
-				goto skip_mouth;
-			}
-
-			val2 -= 3;
-			if (flag & 2) {
-				if (val2 > 8) val2 = 0;
-				val2 += 0x3A5 - 0x35B;
-			}
-			DrawSprite(val2 + 0x35B, x, y);
-		} else if (!(flag&2)) {
-			DrawSprite(((val&0xF) * 10 >> 4) + 0x351, x, y);
-		} else {
-			DrawSprite(((val&0xF) * 9 >> 4) + 0x3C8, x, y);
-		}
-
-		val >>= 3;
-
-		if (!(flag&2)) {
-			if (!(flag&1)) {
-				DrawSprite(0x349 + val, x, y);
-			} else {
-				DrawSprite( mouth_table[(val*3>>3)], x, y);
-			}
-		} else {
-			if (!(flag&1)) {
-				DrawSprite(0x393 + (val&3), x, y);
-			} else {
-				DrawSprite(0x3B3 + (val*5>>3), x, y);
-			}
-		}
-
-		skip_mouth:;
-	}
-
-
-	/* draw the hair */
-	{
-		uint val = GB(face, 16, 4);
-		if (flag & 2) {
-			if (flag & 1) {
-				DrawSprite(0x3D9 + (val * 5 >> 4), x, y);
-			} else {
-				DrawSprite(0x3D4 + (val * 5 >> 4), x, y);
-			}
-		} else {
-			if (flag & 1) {
-				DrawSprite(0x38B + (val * 5 >> 4), x, y);
-			} else {
-				DrawSprite(0x382 + (val * 9 >> 4), x, y);
-			}
-		}
-	}
-
-	/* draw the tie */
-	{
-		uint val = GB(face, 20, 8);
-
-		if (!(flag&1)) {
-			DrawSprite(0x36B + (GB(val, 0, 2) * 3 >> 2), x, y);
-			DrawSprite(0x36E + (GB(val, 2, 2) * 4 >> 2), x, y);
-			DrawSprite(0x372 + (GB(val, 4, 4) * 6 >> 4), x, y);
-		} else {
-			DrawSprite(0x378 + (GB(val, 0, 2) * 3 >> 2), x, y);
-			DrawSprite(0x37B + (GB(val, 2, 2) * 4 >> 2), x, y);
-
-			val >>= 4;
-			if (val < 3) DrawSprite((flag & 2 ? 0x3D1 : 0x37F) + val, x, y);
-		}
-	}
-
-	/* draw the glasses */
-	{
-		uint val = GB(face, 28, 3);
-
-		if (flag & 2) {
-			if (val <= 1) DrawSprite(0x3AE + val, x, y);
-		} else {
-			if (val <= 1) DrawSprite(0x347 + val, x, y);
-		}
-	}
-}
-
-void InvalidatePlayerWindows(const Player *p)
-{
-	PlayerID pid = p->index;
-
-	if (pid == _local_player) InvalidateWindow(WC_STATUS_BAR, 0);
-	InvalidateWindow(WC_FINANCES, pid);
-}
-
-bool CheckPlayerHasMoney(int32 cost)
-{
-	if (cost > 0) {
-		PlayerID pid = _current_player;
-		if (IsValidPlayer(pid) && cost > GetPlayer(pid)->player_money) {
-			SetDParam(0, cost);
-			_error_message = STR_0003_NOT_ENOUGH_CASH_REQUIRES;
-			return false;
-		}
-	}
-	return true;
-}
-
-static void SubtractMoneyFromAnyPlayer(Player *p, int32 cost)
-{
-	p->money64 -= cost;
-	UpdatePlayerMoney32(p);
-
-	p->yearly_expenses[0][_yearly_expenses_type] += cost;
-
-	if (HASBIT(1<<7|1<<8|1<<9|1<<10, _yearly_expenses_type)) {
-		p->cur_economy.income -= cost;
-	} else if (HASBIT(1<<2|1<<3|1<<4|1<<5|1<<6|1<<11, _yearly_expenses_type)) {
-		p->cur_economy.expenses -= cost;
-	}
-
-	InvalidatePlayerWindows(p);
-}
-
-void SubtractMoneyFromPlayer(int32 cost)
-{
-	PlayerID pid = _current_player;
-
-	if (IsValidPlayer(pid)) SubtractMoneyFromAnyPlayer(GetPlayer(pid), cost);
-}
-
-void SubtractMoneyFromPlayerFract(PlayerID player, int32 cost)
-{
-	Player *p = GetPlayer(player);
-	byte m = p->player_money_fraction;
-
-	p->player_money_fraction = m - (byte)cost;
-	cost >>= 8;
-	if (p->player_money_fraction > m) cost++;
-	if (cost != 0) SubtractMoneyFromAnyPlayer(p, cost);
-}
-
-// the player_money field is kept as it is, but money64 contains the actual amount of money.
-void UpdatePlayerMoney32(Player *p)
-{
-	if (p->money64 < -2000000000) {
-		p->player_money = -2000000000;
-	} else if (p->money64 > 2000000000) {
-		p->player_money = 2000000000;
-	} else {
-		p->player_money = (int32)p->money64;
-	}
-}
-
-void GetNameOfOwner(Owner owner, TileIndex tile)
-{
-	SetDParam(2, owner);
-
-	if (owner != OWNER_TOWN) {
-		if (!IsValidPlayer(owner)) {
-			SetDParam(0, STR_0150_SOMEONE);
-		} else {
-			const Player* p = GetPlayer(owner);
-
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-		}
-	} else {
-		const Town* t = ClosestTownFromTile(tile, (uint)-1);
-
-		SetDParam(0, STR_TOWN);
-		SetDParam(1, t->index);
-	}
-}
-
-
-bool CheckOwnership(PlayerID owner)
-{
-	assert(owner < OWNER_END);
-
-	if (owner == _current_player) return true;
-	_error_message = STR_013B_OWNED_BY;
-	GetNameOfOwner(owner, 0);
-	return false;
-}
-
-bool CheckTileOwnership(TileIndex tile)
-{
-	Owner owner = GetTileOwner(tile);
-
-	assert(owner < OWNER_END);
-
-	if (owner == _current_player) return true;
-	_error_message = STR_013B_OWNED_BY;
-
-	// no need to get the name of the owner unless we're the local player (saves some time)
-	if (IsLocalPlayer()) GetNameOfOwner(owner, tile);
-	return false;
-}
-
-static void GenerateCompanyName(Player *p)
-{
-	TileIndex tile;
-	Town *t;
-	StringID str;
-	Player *pp;
-	uint32 strp;
-	char buffer[100];
-
-	if (p->name_1 != STR_SV_UNNAMED) return;
-
-	tile = p->last_build_coordinate;
-	if (tile == 0) return;
-
-	t = ClosestTownFromTile(tile, (uint)-1);
-
-	if (IS_INT_INSIDE(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST+1)) {
-		str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_PLAYERNAME_START;
-		strp = t->townnameparts;
-
-verify_name:;
-		// No player must have this name already
-		FOR_ALL_PLAYERS(pp) {
-			if (pp->name_1 == str && pp->name_2 == strp) goto bad_town_name;
-		}
-
-		GetString(buffer, str, lastof(buffer));
-		if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 150)
-			goto bad_town_name;
-
-set_name:;
-		p->name_1 = str;
-		p->name_2 = strp;
-
-		MarkWholeScreenDirty();
-
-		if (!IsHumanPlayer(p->index)) {
-			SetDParam(0, t->index);
-			AddNewsItem((StringID)(p->index | NB_BNEWCOMPANY), NEWS_FLAGS(NM_CALLBACK, NF_TILE, NT_COMPANY_INFO, DNC_BANKRUPCY), p->last_build_coordinate, 0);
-		}
-		return;
-	}
-bad_town_name:;
-
-	if (p->president_name_1 == SPECSTR_PRESIDENT_NAME) {
-		str = SPECSTR_ANDCO_NAME;
-		strp = p->president_name_2;
-		goto set_name;
-	} else {
-		str = SPECSTR_ANDCO_NAME;
-		strp = Random();
-		goto verify_name;
-	}
-}
-
-#define COLOR_SWAP(i,j) do { byte t=colors[i];colors[i]=colors[j];colors[j]=t; } while(0)
-
-static const byte _color_sort[16] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
-static const byte _color_similar_1[16] = {8, 6, 255, 12,  255, 0, 1, 1, 0, 13,  11,  10, 3,   9,  15, 14};
-static const byte _color_similar_2[16] = {5, 7, 255, 255, 255, 8, 7, 6, 5, 12, 255, 255, 9, 255, 255, 255};
-
-static byte GeneratePlayerColor(void)
-{
-	byte colors[16], pcolor, t2;
-	int i,j,n;
-	uint32 r;
-	Player *p;
-
-	// Initialize array
-	for (i = 0; i != 16; i++) colors[i] = i;
-
-	// And randomize it
-	n = 100;
-	do {
-		r = Random();
-		COLOR_SWAP(GB(r, 0, 4), GB(r, 4, 4));
-	} while (--n);
-
-	// Bubble sort it according to the values in table 1
-	i = 16;
-	do {
-		for (j = 0; j != 15; j++) {
-			if (_color_sort[colors[j]] < _color_sort[colors[j + 1]]) {
-				COLOR_SWAP(j, j + 1);
-			}
-		}
-	} while (--i);
-
-	// Move the colors that look similar to each player's color to the side
-	FOR_ALL_PLAYERS(p) if (p->is_active) {
-		pcolor = p->player_color;
-		for (i=0; i!=16; i++) if (colors[i] == pcolor) {
-			colors[i] = 0xFF;
-
-			t2 = _color_similar_1[pcolor];
-			if (t2 == 0xFF) break;
-			for (i=0; i!=15; i++) {
-				if (colors[i] == t2) {
-					do COLOR_SWAP(i,i+1); while (++i != 15);
-					break;
-				}
-			}
-
-			t2 = _color_similar_2[pcolor];
-			if (t2 == 0xFF) break;
-			for (i = 0; i != 15; i++) {
-				if (colors[i] == t2) {
-					do COLOR_SWAP(i, i + 1); while (++i != 15);
-					break;
-				}
-			}
-			break;
-		}
-	}
-
-	// Return the first available color
-	for (i = 0;; i++) {
-		if (colors[i] != 0xFF) return colors[i];
-	}
-}
-
-static void GeneratePresidentName(Player *p)
-{
-	Player *pp;
-	char buffer[100], buffer2[40];
-
-	for (;;) {
-restart:;
-
-		p->president_name_2 = Random();
-		p->president_name_1 = SPECSTR_PRESIDENT_NAME;
-
-		SetDParam(0, p->president_name_2);
-		GetString(buffer, p->president_name_1, lastof(buffer));
-		if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 94)
-			continue;
-
-		FOR_ALL_PLAYERS(pp) {
-			if (pp->is_active && p != pp) {
-				SetDParam(0, pp->president_name_2);
-				GetString(buffer2, pp->president_name_1, lastof(buffer2));
-				if (strcmp(buffer2, buffer) == 0)
-					goto restart;
-			}
-		}
-		return;
-	}
-}
-
-static Player *AllocatePlayer(void)
-{
-	Player *p;
-	// Find a free slot
-	FOR_ALL_PLAYERS(p) {
-		if (!p->is_active) {
-			int i = p->index;
-			memset(p, 0, sizeof(Player));
-			p->index = i;
-			return p;
-		}
-	}
-	return NULL;
-}
-
-void ResetPlayerLivery(Player *p)
-{
-	LiveryScheme scheme;
-
-	for (scheme = 0; scheme < LS_END; scheme++) {
-		p->livery[scheme].in_use  = false;
-		p->livery[scheme].colour1 = p->player_color;
-		p->livery[scheme].colour2 = p->player_color;
-	}
-}
-
-Player *DoStartupNewPlayer(bool is_ai)
-{
-	Player *p;
-
-	p = AllocatePlayer();
-	if (p == NULL) return NULL;
-
-	// Make a color
-	p->player_color = GeneratePlayerColor();
-	ResetPlayerLivery(p);
-	_player_colors[p->index] = p->player_color;
-	p->name_1 = STR_SV_UNNAMED;
-	p->is_active = true;
-
-	p->money64 = p->player_money = p->current_loan = 100000;
-
-	p->is_ai = is_ai;
-	p->ai.state = 5; /* AIS_WANT_NEW_ROUTE */
-	p->share_owners[0] = p->share_owners[1] = p->share_owners[2] = p->share_owners[3] = PLAYER_SPECTATOR;
-
-	p->avail_railtypes = GetPlayerRailtypes(p->index);
-	p->inaugurated_year = _cur_year;
-	p->face = Random();
-
-	/* Engine renewal settings */
-	p->engine_renew_list = NULL;
-	p->renew_keep_length = false;
-	p->engine_renew = false;
-	p->engine_renew_months = -6;
-	p->engine_renew_money = 100000;
-
-	GeneratePresidentName(p);
-
-	InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	InvalidateWindow(WC_TOOLBAR_MENU, 0);
-	InvalidateWindow(WC_CLIENT_LIST, 0);
-
-	if (is_ai && (!_networking || _network_server) && _ai.enabled)
-		AI_StartNewAI(p->index);
-
-	memset(p->num_engines, 0, sizeof(p->num_engines));
-
-	return p;
-}
-
-void StartupPlayers(void)
-{
-	// The AI starts like in the setting with +2 month max
-	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + RandomRange(60 * DAY_TICKS) + 1;
-}
-
-static void MaybeStartNewPlayer(void)
-{
-	uint n;
-	Player *p;
-
-	// count number of competitors
-	n = 0;
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active && p->is_ai) n++;
-	}
-
-	// when there's a lot of computers in game, the probability that a new one starts is lower
-	if (n < (uint)_opt.diff.max_no_competitors &&
-			n < (_network_server ?
-				InteractiveRandomRange(_opt.diff.max_no_competitors + 2) :
-				RandomRange(_opt.diff.max_no_competitors + 2)
-			)) {
-		/* Send a command to all clients to start up a new AI.
-		 * Works fine for Multiplayer and Singleplayer */
-		DoCommandP(0, 1, 0, NULL, CMD_PLAYER_CTRL);
-	}
-
-	// The next AI starts like the difficulty setting said, with +2 month max
-	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + 1;
-	_next_competitor_start += _network_server ? InteractiveRandomRange(60 * DAY_TICKS) : RandomRange(60 * DAY_TICKS);
-}
-
-void InitializePlayers(void)
-{
-	uint i;
-
-	memset(_players, 0, sizeof(_players));
-	for (i = 0; i != MAX_PLAYERS; i++) _players[i].index = i;
-	_cur_player_tick_index = 0;
-}
-
-void OnTick_Players(void)
-{
-	Player *p;
-
-	if (_game_mode == GM_EDITOR) return;
-
-	p = GetPlayer(_cur_player_tick_index);
-	_cur_player_tick_index = (_cur_player_tick_index + 1) % MAX_PLAYERS;
-	if (p->name_1 != 0) GenerateCompanyName(p);
-
-	if (AI_AllowNewAI() && _game_mode != GM_MENU && !--_next_competitor_start)
-		MaybeStartNewPlayer();
-}
-
-// index is the next parameter in _decode_parameters to set up
-StringID GetPlayerNameString(PlayerID player, uint index)
-{
-	if (IsHumanPlayer(player) && IsValidPlayer(player)) {
-		SetDParam(index, player+1);
-		return STR_7002_PLAYER;
-	}
-	return STR_EMPTY;
-}
-
-extern void ShowPlayerFinances(int player);
-
-void PlayersYearlyLoop(void)
-{
-	Player *p;
-
-	// Copy statistics
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) {
-			memmove(&p->yearly_expenses[1], &p->yearly_expenses[0], sizeof(p->yearly_expenses) - sizeof(p->yearly_expenses[0]));
-			memset(&p->yearly_expenses[0], 0, sizeof(p->yearly_expenses[0]));
-			InvalidateWindow(WC_FINANCES, p->index);
-		}
-	}
-
-	if (_patches.show_finances && _local_player != PLAYER_SPECTATOR) {
-		ShowPlayerFinances(_local_player);
-		p = GetPlayer(_local_player);
-		if (p->num_valid_stat_ent > 5 && p->old_economy[0].performance_history < p->old_economy[4].performance_history) {
-			SndPlayFx(SND_01_BAD_YEAR);
-		} else {
-			SndPlayFx(SND_00_GOOD_YEAR);
-		}
-	}
-}
-
-byte GetPlayerRailtypes(PlayerID p)
-{
-	byte rt = 0;
-	EngineID i;
-
-	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
-		const Engine* e = GetEngine(i);
-		const EngineInfo *ei = EngInfo(i);
-
-		if (e->type == VEH_Train && HASBIT(ei->climates, _opt.landscape) &&
-				(HASBIT(e->player_avail, p) || _date >= (e->intro_date + 365)) &&
-				!(RailVehInfo(i)->flags & RVI_WAGON)) {
-			assert(e->railtype < RAILTYPE_END);
-			SETBIT(rt, e->railtype);
-		}
-	}
-
-	return rt;
-}
-
-static void DeletePlayerStuff(PlayerID pi)
-{
-	Player *p;
-
-	DeletePlayerWindows(pi);
-	p = GetPlayer(pi);
-	DeleteName(p->name_1);
-	DeleteName(p->president_name_1);
-	p->name_1 = 0;
-	p->president_name_1 = 0;
-}
-
-/** Change engine renewal parameters
- * @param tile unused
- * @param p1 bits 0-3 command
- * - p1 = 0 - change auto renew bool
- * - p1 = 1 - change auto renew months
- * - p1 = 2 - change auto renew money
- * - p1 = 3 - change auto renew array
- * - p1 = 4 - change bool, months & money all together
- * - p1 = 5 - change renew_keep_length
- * @param p2 value to set
- * if p1 = 0, then:
- * - p2 = enable engine renewal
- * if p1 = 1, then:
- * - p2 = months left before engine expires to replace it
- * if p1 = 2, then
- * - p2 = minimum amount of money available
- * if p1 = 3, then:
- * - p2 bits  0-15 = old engine type
- * - p2 bits 16-31 = new engine type
- * if p1 = 4, then:
- * - p1 bit     15 = enable engine renewal
- * - p1 bits 16-31 = months left before engine expires to replace it
- * - p2 bits  0-31 = minimum amount of money available
- * if p1 = 5, then
- * - p2 = enable renew_keep_length
- */
-int32 CmdSetAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p;
-	if (!IsValidPlayer(_current_player)) return CMD_ERROR;
-
-	p = GetPlayer(_current_player);
-	switch (GB(p1, 0, 3)) {
-		case 0:
-			if (p->engine_renew == (bool)GB(p2, 0, 1))
-				return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				p->engine_renew = (bool)GB(p2, 0, 1);
-				if (IsLocalPlayer()) {
-					_patches.autorenew = p->engine_renew;
-					InvalidateWindow(WC_GAME_OPTIONS, 0);
-				}
-			}
-			break;
-		case 1:
-			if (p->engine_renew_months == (int16)p2)
-				return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				p->engine_renew_months = (int16)p2;
-				if (IsLocalPlayer()) {
-					_patches.autorenew_months = p->engine_renew_months;
-					InvalidateWindow(WC_GAME_OPTIONS, 0);
-				}
-			}
-			break;
-		case 2:
-			if (p->engine_renew_money == (uint32)p2)
-				return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				p->engine_renew_money = (uint32)p2;
-				if (IsLocalPlayer()) {
-					_patches.autorenew_money = p->engine_renew_money;
-					InvalidateWindow(WC_GAME_OPTIONS, 0);
-				}
-			}
-			break;
-		case 3: {
-			EngineID old_engine_type = GB(p2, 0, 16);
-			EngineID new_engine_type = GB(p2, 16, 16);
-			int32 cost;
-
-			if (new_engine_type != INVALID_ENGINE) {
-				/* First we make sure that it's a valid type the user requested
-				 * check that it's an engine that is in the engine array */
-				if (!IsEngineIndex(new_engine_type))
-					return CMD_ERROR;
-
-				// check that the new vehicle type is the same as the original one
-				if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type)
-					return CMD_ERROR;
-
-				// make sure that we do not replace a plane with a helicopter or vise versa
-				if (GetEngine(new_engine_type)->type == VEH_Aircraft &&
-						(AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL))
-					return CMD_ERROR;
-
-				// make sure that the player can actually buy the new engine
-				if (!HASBIT(GetEngine(new_engine_type)->player_avail, _current_player))
-					return CMD_ERROR;
-
-				cost = AddEngineReplacementForPlayer(p, old_engine_type, new_engine_type, flags);
-			} else {
-				cost = RemoveEngineReplacementForPlayer(p, old_engine_type, flags);
-			}
-
-			if (IsLocalPlayer()) InvalidateWindow(WC_REPLACE_VEHICLE, GetEngine(old_engine_type)->type);
-
-			return cost;
-		}
-
-		case 4:
-			if (flags & DC_EXEC) {
-				p->engine_renew = (bool)GB(p1, 15, 1);
-				p->engine_renew_months = (int16)GB(p1, 16, 16);
-				p->engine_renew_money = (uint32)p2;
-
-				if (IsLocalPlayer()) {
-					_patches.autorenew = p->engine_renew;
-					_patches.autorenew_months = p->engine_renew_months;
-					_patches.autorenew_money = p->engine_renew_money;
-					InvalidateWindow(WC_GAME_OPTIONS, 0);
-				}
-			}
-			break;
-		case 5:
-			if (p->renew_keep_length == (bool)GB(p2, 0, 1))
-				return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				p->renew_keep_length = (bool)GB(p2, 0, 1);
-				if (IsLocalPlayer()) {
-					InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
-				}
-			}
-		break;
-
-	}
-	return 0;
-}
-
-/** Control the players: add, delete, etc.
- * @param tile unused
- * @param p1 various functionality
- * - p1 = 0 - create a new player, Which player (network) it will be is in p2
- * - p1 = 1 - create a new AI player
- * - p1 = 2 - delete a player. Player is identified by p2
- * - p1 = 3 - merge two companies together. Player to merge #1 with player #2. Identified by p2
- * @param p2 various functionality, dictated by p1
- * - p1 = 0 - ClientID of the newly created player
- * - p1 = 2 - PlayerID of the that is getting deleted
- * - p1 = 3 - #1 p2 = (bit  0-15) - player to merge (p2 & 0xFFFF)
- *          - #2 p2 = (bit 16-31) - player to be merged into ((p2>>16)&0xFFFF)
- * @todo In the case of p1=0, create new player, the clientID of the new player is in parameter
- * p2. This parameter is passed in at function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
- * on the server itself. First of all this is unbelievably ugly; second of all, well,
- * it IS ugly! <b>Someone fix this up :)</b> So where to fix?@n
- * @arg - network_server.c:838 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)@n
- * @arg - network_client.c:536 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) from where the map has been received
- */
-int32 CmdPlayerCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	if (flags & DC_EXEC) _current_player = OWNER_NONE;
-
-	switch (p1) {
-	case 0: { /* Create a new player */
-		/* Joining Client:
-		 * _local_player: PLAYER_SPECTATOR
-		 * _network_playas/cid = requested company/player
-		 *
-		 * Other client(s)/server:
-		 * _local_player/_network_playas: what they play as
-		 * cid = requested company/player of joining client */
-		Player *p;
-		uint16 cid = p2; // ClientID
-
-		/* This command is only executed in a multiplayer game */
-		if (!_networking) return CMD_ERROR;
-
-		/* Has the network client a correct ClientID? */
-		if (!(flags & DC_EXEC)) return 0;
-#ifdef ENABLE_NETWORK
-		if (cid >= MAX_CLIENT_INFO) return 0;
-#endif /* ENABLE_NETWORK */
-
-		/* Delete multiplayer progress bar */
-		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-
-		p = DoStartupNewPlayer(false);
-
-		/* A new player could not be created, revert to being a spectator */
-		if (p == NULL) {
-#ifdef ENABLE_NETWORK
-			if (_network_server) {
-				NetworkClientInfo *ci = &_network_client_info[cid];
-				ci->client_playas = PLAYER_SPECTATOR;
-				NetworkUpdateClientInfo(ci->client_index);
-			} else
-#endif /* ENABLE_NETWORK */
-			{
-				_network_playas = PLAYER_SPECTATOR;
-				SetLocalPlayer(PLAYER_SPECTATOR);
-			}
-			break;
-		}
-
-		/* This is the joining client who wants a new company */
-		if (_local_player != _network_playas) {
-			assert(_local_player == PLAYER_SPECTATOR && _network_playas == p->index);
-			SetLocalPlayer(p->index);
-			MarkWholeScreenDirty();
-		}
-
-		/* Now that we have a new player, broadcast its autorenew settings to
-		 * all clients so everything is in sync */
-		DoCommand(0,
-			(_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4,
-			_patches.autorenew_money,
-			DC_EXEC,
-			CMD_SET_AUTOREPLACE
-		);
-
-#ifdef ENABLE_NETWORK
-		if (_network_server) {
-			/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
-			 * server-side in network_server.c:838, function
-			 * DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
-			NetworkClientInfo *ci = &_network_client_info[cid];
-			ci->client_playas = p->index;
-			NetworkUpdateClientInfo(ci->client_index);
-
-			if (IsValidPlayer(ci->client_playas)) {
-				PlayerID player_backup = _local_player;
-				_network_player_info[p->index].months_empty = 0;
-
-				/* XXX - When a client joins, we automatically set its name to the
-				 * player's name (for some reason). As it stands now only the server
-				 * knows the client's name, so it needs to send out a "broadcast" to
-				 * do this. To achieve this we send a network command. However, it
-				 * uses _local_player to execute the command as.  To prevent abuse
-				 * (eg. only yourself can change your name/company), we 'cheat' by
-				 * impersonation _local_player as the server. Not the best solution;
-				 * but it works.
-				 * TODO: Perhaps this could be improved by when the client is ready
-				 * with joining to let it send itself the command, and not the server?
-				 * For example in network_client.c:534? */
-				_cmd_text = ci->client_name;
-				_local_player = ci->client_playas;
-				NetworkSend_Command(0, 0, 0, CMD_CHANGE_PRESIDENT_NAME, NULL);
-				_local_player = player_backup;
-			}
-		}
-#endif /* ENABLE_NETWORK */
-	} break;
-
-	case 1: /* Make a new AI player */
-		if (!(flags & DC_EXEC)) return 0;
-
-		DoStartupNewPlayer(true);
-		break;
-
-	case 2: { /* Delete a player */
-		Player *p;
-
-		if (!IsValidPlayer(p2)) return CMD_ERROR;
-
-		if (!(flags & DC_EXEC)) return 0;
-
-		p = GetPlayer(p2);
-
-		/* Only allow removal of HUMAN companies */
-		if (IsHumanPlayer(p->index)) {
-			/* Delete any open window of the company */
-			DeletePlayerWindows(p->index);
-
-			/* Show the bankrupt news */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			AddNewsItem( (StringID)(p->index | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
-
-			/* Remove the company */
-			ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
-			p->is_active = false;
-		}
-		RemoveAllEngineReplacementForPlayer(p);
-
-	} break;
-
-	case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
-		PlayerID pid_old = GB(p2,  0, 16);
-		PlayerID pid_new = GB(p2, 16, 16);
-
-		if (!IsValidPlayer(pid_old) || !IsValidPlayer(pid_new)) return CMD_ERROR;
-
-		if (!(flags & DC_EXEC)) return CMD_ERROR;
-
-		ChangeOwnershipOfPlayerItems(pid_old, pid_new);
-		DeletePlayerStuff(pid_old);
-	} break;
-
-	default: return CMD_ERROR;
-	}
-
-	return 0;
-}
-
-static const StringID _endgame_perf_titles[] = {
-	STR_0213_BUSINESSMAN,
-	STR_0213_BUSINESSMAN,
-	STR_0213_BUSINESSMAN,
-	STR_0213_BUSINESSMAN,
-	STR_0213_BUSINESSMAN,
-	STR_0214_ENTREPRENEUR,
-	STR_0214_ENTREPRENEUR,
-	STR_0215_INDUSTRIALIST,
-	STR_0215_INDUSTRIALIST,
-	STR_0216_CAPITALIST,
-	STR_0216_CAPITALIST,
-	STR_0217_MAGNATE,
-	STR_0217_MAGNATE,
-	STR_0218_MOGUL,
-	STR_0218_MOGUL,
-	STR_0219_TYCOON_OF_THE_CENTURY
-};
-
-StringID EndGameGetPerformanceTitleFromValue(uint value)
-{
-	value = minu(value / 64, lengthof(_endgame_perf_titles) - 1);
-
-	return _endgame_perf_titles[value];
-}
-
-/* Return true if any cheat has been used, false otherwise */
-static bool CheatHasBeenUsed(void)
-{
-	const Cheat* cht = (Cheat*)&_cheats;
-	const Cheat* cht_last = &cht[sizeof(_cheats) / sizeof(Cheat)];
-
-	for (; cht != cht_last; cht++) {
-		if (cht->been_used) return true;
-	}
-
-	return false;
-}
-
-/* Save the highscore for the player */
-int8 SaveHighScoreValue(const Player *p)
-{
-	HighScore *hs = _highscore_table[_opt.diff_level];
-	uint i;
-	uint16 score = p->old_economy[0].performance_history;
-
-	/* Exclude cheaters from the honour of being in the highscore table */
-	if (CheatHasBeenUsed()) return -1;
-
-	for (i = 0; i < lengthof(_highscore_table[0]); i++) {
-		/* You are in the TOP5. Move all values one down and save us there */
-		if (hs[i].score <= score) {
-			// move all elements one down starting from the replaced one
-			memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1));
-			SetDParam(0, p->president_name_1);
-			SetDParam(1, p->president_name_2);
-			SetDParam(2, p->name_1);
-			SetDParam(3, p->name_2);
-			GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string
-			hs[i].score = score;
-			hs[i].title = EndGameGetPerformanceTitleFromValue(score);
-			return i;
-		}
-	}
-
-	return -1; // too bad; we did not make it into the top5
-}
-
-/* Sort all players given their performance */
-static int CDECL HighScoreSorter(const void *a, const void *b)
-{
-	const Player *pa = *(const Player* const*)a;
-	const Player *pb = *(const Player* const*)b;
-
-	return pb->old_economy[0].performance_history - pa->old_economy[0].performance_history;
-}
-
-/* Save the highscores in a network game when it has ended */
-#define LAST_HS_ITEM lengthof(_highscore_table) - 1
-int8 SaveHighScoreValueNetwork(void)
-{
-	const Player* p;
-	const Player* pl[MAX_PLAYERS];
-	size_t count = 0;
-	int8 player = -1;
-
-	/* Sort all active players with the highest score first */
-	FOR_ALL_PLAYERS(p) if (p->is_active) pl[count++] = p;
-	qsort((Player*)pl, count, sizeof(pl[0]), HighScoreSorter);
-
-	{
-		uint i;
-
-		memset(_highscore_table[LAST_HS_ITEM], 0, sizeof(_highscore_table[0]));
-
-		/* Copy over Top5 companies */
-		for (i = 0; i < lengthof(_highscore_table[LAST_HS_ITEM]) && i < count; i++) {
-			HighScore* hs = &_highscore_table[LAST_HS_ITEM][i];
-
-			SetDParam(0, pl[i]->president_name_1);
-			SetDParam(1, pl[i]->president_name_2);
-			SetDParam(2, pl[i]->name_1);
-			SetDParam(3, pl[i]->name_2);
-			GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string
-			hs->score = pl[i]->old_economy[0].performance_history;
-			hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
-
-			// get the ranking of the local player
-			if (pl[i]->index == _local_player) player = i;
-		}
-	}
-
-	/* Add top5 players to highscore table */
-	return player;
-}
-
-/* Save HighScore table to file */
-void SaveToHighScore(void)
-{
-	FILE *fp = fopen(_highscore_file, "wb");
-
-	if (fp != NULL) {
-		uint i;
-		HighScore *hs;
-
-		for (i = 0; i < LAST_HS_ITEM; i++) { // don't save network highscores
-			for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
-				/* First character is a command character, so strlen will fail on that */
-				byte length = min(sizeof(hs->company), (hs->company[0] == '\0') ? 0 : (int)strlen(&hs->company[1]) + 1);
-
-				fwrite(&length, sizeof(length), 1, fp); // write away string length
-				fwrite(hs->company, length, 1, fp);
-				fwrite(&hs->score, sizeof(hs->score), 1, fp);
-				fwrite("", 2, 1, fp); /* XXX - placeholder for hs->title, not saved anymore; compatibility */
-			}
-		}
-		fclose(fp);
-	}
-}
-
-/* Initialize the highscore table to 0 and if any file exists, load in values */
-void LoadFromHighScore(void)
-{
-	FILE *fp = fopen(_highscore_file, "rb");
-
-	memset(_highscore_table, 0, sizeof(_highscore_table));
-
-	if (fp != NULL) {
-		uint i;
-		HighScore *hs;
-
-		for (i = 0; i < LAST_HS_ITEM; i++) { // don't load network highscores
-			for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
-				byte length;
-				fread(&length, sizeof(length), 1, fp);
-
-				fread(hs->company, 1, length, fp);
-				fread(&hs->score, sizeof(hs->score), 1, fp);
-				fseek(fp, 2, SEEK_CUR); /* XXX - placeholder for hs->title, not saved anymore; compatibility */
-				hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
-			}
-		}
-		fclose(fp);
-	}
-
-	/* Initialize end of game variable (when to show highscore chart) */
-	_patches.ending_year = 2051;
-}
-
-// Save/load of players
-static const SaveLoad _player_desc[] = {
-	    SLE_VAR(Player, name_2,          SLE_UINT32),
-	    SLE_VAR(Player, name_1,          SLE_STRINGID),
-
-	    SLE_VAR(Player, president_name_1,SLE_UINT16),
-	    SLE_VAR(Player, president_name_2,SLE_UINT32),
-
-	    SLE_VAR(Player, face,            SLE_UINT32),
-
-	// money was changed to a 64 bit field in savegame version 1.
-	SLE_CONDVAR(Player, money64,               SLE_VAR_I64 | SLE_FILE_I32, 0, 0),
-	SLE_CONDVAR(Player, money64,               SLE_INT64, 1, SL_MAX_VERSION),
-
-	    SLE_VAR(Player, current_loan,          SLE_INT32),
-
-	    SLE_VAR(Player, player_color,          SLE_UINT8),
-	    SLE_VAR(Player, player_money_fraction, SLE_UINT8),
-	    SLE_VAR(Player, avail_railtypes,       SLE_UINT8),
-	    SLE_VAR(Player, block_preview,         SLE_UINT8),
-
-	    SLE_VAR(Player, cargo_types,           SLE_UINT16),
-	SLE_CONDVAR(Player, location_of_house,     SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(Player, location_of_house,     SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(Player, last_build_coordinate, SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, inaugurated_year,      SLE_FILE_U8  | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Player, inaugurated_year,      SLE_INT32,                  31, SL_MAX_VERSION),
-
-	    SLE_ARR(Player, share_owners,          SLE_UINT8, 4),
-
-	    SLE_VAR(Player, num_valid_stat_ent,    SLE_UINT8),
-
-	    SLE_VAR(Player, quarters_of_bankrupcy, SLE_UINT8),
-	    SLE_VAR(Player, bankrupt_asked,        SLE_UINT8),
-	    SLE_VAR(Player, bankrupt_timeout,      SLE_INT16),
-	    SLE_VAR(Player, bankrupt_value,        SLE_INT32),
-
-	// yearly expenses was changed to 64-bit in savegame version 2.
-	SLE_CONDARR(Player, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1),
-	SLE_CONDARR(Player, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_MAX_VERSION),
-
-	SLE_CONDVAR(Player, is_ai,                 SLE_BOOL, 2, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, is_active,             SLE_BOOL, 4, SL_MAX_VERSION),
-
-	// Engine renewal settings
-	SLE_CONDNULL(512, 16, 18),
-	SLE_CONDREF(Player, engine_renew_list,     REF_ENGINE_RENEWS,          19, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, engine_renew,          SLE_BOOL,                   16, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, engine_renew_months,   SLE_INT16,                  16, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, engine_renew_money,    SLE_UINT32,                 16, SL_MAX_VERSION),
-	SLE_CONDVAR(Player, renew_keep_length,     SLE_BOOL,                    2, SL_MAX_VERSION), // added with 16.1, but was blank since 2
-
-	// reserve extra space in savegame here. (currently 63 bytes)
-	SLE_CONDNULL(63, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _player_economy_desc[] = {
-	// these were changed to 64-bit in savegame format 2
-	SLE_CONDVAR(PlayerEconomyEntry, income,              SLE_INT32,                  0, 1),
-	SLE_CONDVAR(PlayerEconomyEntry, expenses,            SLE_INT32,                  0, 1),
-	SLE_CONDVAR(PlayerEconomyEntry, company_value,       SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
-	SLE_CONDVAR(PlayerEconomyEntry, income,              SLE_FILE_I64 | SLE_VAR_I32, 2, SL_MAX_VERSION),
-	SLE_CONDVAR(PlayerEconomyEntry, expenses,            SLE_FILE_I64 | SLE_VAR_I32, 2, SL_MAX_VERSION),
-	SLE_CONDVAR(PlayerEconomyEntry, company_value,       SLE_INT64,                  2, SL_MAX_VERSION),
-
-	    SLE_VAR(PlayerEconomyEntry, delivered_cargo,     SLE_INT32),
-	    SLE_VAR(PlayerEconomyEntry, performance_history, SLE_INT32),
-
-	SLE_END()
-};
-
-static const SaveLoad _player_ai_desc[] = {
-	    SLE_VAR(PlayerAI, state,             SLE_UINT8),
-	    SLE_VAR(PlayerAI, tick,              SLE_UINT8),
-	SLE_CONDVAR(PlayerAI, state_counter,     SLE_FILE_U16 | SLE_VAR_U32,  0, 12),
-	SLE_CONDVAR(PlayerAI, state_counter,     SLE_UINT32,                 13, SL_MAX_VERSION),
-	    SLE_VAR(PlayerAI, timeout_counter,   SLE_UINT16),
-
-	    SLE_VAR(PlayerAI, state_mode,        SLE_UINT8),
-	    SLE_VAR(PlayerAI, banned_tile_count, SLE_UINT8),
-	    SLE_VAR(PlayerAI, railtype_to_use,   SLE_UINT8),
-
-	    SLE_VAR(PlayerAI, cargo_type,        SLE_UINT8),
-	    SLE_VAR(PlayerAI, num_wagons,        SLE_UINT8),
-	    SLE_VAR(PlayerAI, build_kind,        SLE_UINT8),
-	    SLE_VAR(PlayerAI, num_build_rec,     SLE_UINT8),
-	    SLE_VAR(PlayerAI, num_loco_to_build, SLE_UINT8),
-	    SLE_VAR(PlayerAI, num_want_fullload, SLE_UINT8),
-
-	    SLE_VAR(PlayerAI, route_type_mask,   SLE_UINT8),
-
-	SLE_CONDVAR(PlayerAI, start_tile_a,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(PlayerAI, start_tile_a,      SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(PlayerAI, cur_tile_a,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(PlayerAI, cur_tile_a,        SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLE_VAR(PlayerAI, start_dir_a,       SLE_UINT8),
-	    SLE_VAR(PlayerAI, cur_dir_a,         SLE_UINT8),
-
-	SLE_CONDVAR(PlayerAI, start_tile_b,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(PlayerAI, start_tile_b,      SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(PlayerAI, cur_tile_b,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
-	SLE_CONDVAR(PlayerAI, cur_tile_b,        SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLE_VAR(PlayerAI, start_dir_b,       SLE_UINT8),
-	    SLE_VAR(PlayerAI, cur_dir_b,         SLE_UINT8),
-
-	    SLE_REF(PlayerAI, cur_veh,           REF_VEHICLE),
-
-	    SLE_ARR(PlayerAI, wagon_list,        SLE_UINT16, 9),
-	    SLE_ARR(PlayerAI, order_list_blocks, SLE_UINT8, 20),
-	    SLE_ARR(PlayerAI, banned_tiles,      SLE_UINT16, 16),
-
-	SLE_CONDNULL(64, 2, SL_MAX_VERSION),
-	SLE_END()
-};
-
-static const SaveLoad _player_ai_build_rec_desc[] = {
-	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
-	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_UINT32,                 6, SL_MAX_VERSION),
-	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
-	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
-	    SLE_VAR(AiBuildRec, rand_rng,          SLE_UINT8),
-	    SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8),
-	    SLE_VAR(AiBuildRec, unk6,              SLE_UINT8),
-	    SLE_VAR(AiBuildRec, unk7,              SLE_UINT8),
-	    SLE_VAR(AiBuildRec, buildcmd_a,        SLE_UINT8),
-	    SLE_VAR(AiBuildRec, buildcmd_b,        SLE_UINT8),
-	    SLE_VAR(AiBuildRec, direction,         SLE_UINT8),
-	    SLE_VAR(AiBuildRec, cargo,             SLE_UINT8),
-	SLE_END()
-};
-
-static const SaveLoad _player_livery_desc[] = {
-	SLE_CONDVAR(Livery, in_use,  SLE_BOOL,  34, SL_MAX_VERSION),
-	SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION),
-	SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION),
-	SLE_END()
-};
-
-static void SaveLoad_PLYR(Player* p)
-{
-	int i;
-
-	SlObject(p, _player_desc);
-
-	// Write AI?
-	if (!IsHumanPlayer(p->index)) {
-		SlObject(&p->ai, _player_ai_desc);
-		for (i = 0; i != p->ai.num_build_rec; i++) {
-			SlObject(&p->ai.src + i, _player_ai_build_rec_desc);
-		}
-	}
-
-	// Write economy
-	SlObject(&p->cur_economy, _player_economy_desc);
-
-	// Write old economy entries.
-	for (i = 0; i < p->num_valid_stat_ent; i++) {
-		SlObject(&p->old_economy[i], _player_economy_desc);
-	}
-
-	// Write each livery entry.
-	for (i = 0; i < LS_END; i++) {
-		SlObject(&p->livery[i], _player_livery_desc);
-	}
-}
-
-static void Save_PLYR(void)
-{
-	Player *p;
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) {
-			SlSetArrayIndex(p->index);
-			SlAutolength((AutolengthProc*)SaveLoad_PLYR, p);
-		}
-	}
-}
-
-static void Load_PLYR(void)
-{
-	int index;
-	while ((index = SlIterateArray()) != -1) {
-		Player *p = GetPlayer(index);
-		SaveLoad_PLYR(p);
-		_player_colors[index] = p->player_color;
-		UpdatePlayerMoney32(p);
-
-		/* This is needed so an AI is attached to a loaded AI */
-		if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
-			AI_StartNewAI(p->index);
-	}
-}
-
-const ChunkHandler _player_chunk_handlers[] = {
-	{ 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/players.cpp
@@ -0,0 +1,1339 @@
+/* $Id$ */
+
+/** @file players.c
+ * @todo Cleanup the messy DrawPlayerFace function asap
+ */
+#include "stdafx.h"
+#include "openttd.h"
+#include "engine.h"
+#include "functions.h"
+#include "string.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "player.h"
+#include "town.h"
+#include "vehicle.h"
+#include "station.h"
+#include "gfx.h"
+#include "news.h"
+#include "saveload.h"
+#include "command.h"
+#include "sound.h"
+#include "network/network.h"
+#include "variables.h"
+#include "engine.h"
+#include "ai/ai.h"
+#include "date.h"
+#include "window.h"
+
+/**
+ * Sets the local player and updates the patch settings that are set on a
+ * per-company (player) basis to reflect the core's state in the GUI.
+ * @param new_player the new player
+ * @pre IsValidPlayer(new_player) || new_player == PLAYER_SPECTATOR || new_player == OWNER_NONE
+ */
+void SetLocalPlayer(PlayerID new_player)
+{
+	/* Player could also be PLAYER_SPECTATOR or OWNER_NONE */
+	assert(IsValidPlayer(new_player) || new_player == PLAYER_SPECTATOR || new_player == OWNER_NONE);
+
+	_local_player = new_player;
+
+	/* Do not update the patches if we are in the intro GUI */
+	if (IsValidPlayer(new_player) && _game_mode != GM_MENU) {
+		const Player *p = GetPlayer(new_player);
+		_patches.autorenew        = p->engine_renew;
+		_patches.autorenew_months = p->engine_renew_months;
+		_patches.autorenew_money  = p->engine_renew_money;
+		InvalidateWindow(WC_GAME_OPTIONS, 0);
+	}
+}
+
+
+uint16 GetDrawStringPlayerColor(PlayerID player)
+{
+	/* Get the color for DrawString-subroutines which matches the color
+	 * of the player */
+	if (!IsValidPlayer(player)) return _colour_gradient[COLOUR_WHITE][4] | IS_PALETTE_COLOR;
+	return (_colour_gradient[_player_colors[player]][4]) | IS_PALETTE_COLOR;
+}
+
+
+static const SpriteID cheeks_table[4] = {
+	0x325, 0x326,
+	0x390, 0x3B0,
+};
+
+static const SpriteID mouth_table[3] = {
+	0x34C, 0x34D, 0x34F
+};
+
+void DrawPlayerFace(uint32 face, int color, int x, int y)
+{
+	byte flag = 0;
+
+	if ( (int32)face < 0)
+		flag |= 1;
+	if ((((((face >> 7) ^ face) >> 7) ^ face) & 0x8080000) == 0x8000000)
+		flag |= 2;
+
+	/* draw the gradient */
+	DrawSprite(GENERAL_SPRITE_COLOR(color) + SPRITE_PALETTE(SPR_GRADIENT), x, y);
+
+	/* draw the cheeks */
+	DrawSprite(cheeks_table[flag&3], x, y);
+
+	/* draw the chin */
+	/* FIXME: real code uses -2 in zoomlevel 1 */
+	{
+		uint val = GB(face, 4, 2);
+		if (!(flag & 2)) {
+			DrawSprite(0x327 + (flag&1?0:val), x, y);
+		} else {
+			DrawSprite((flag&1?0x3B1:0x391) + (val>>1), x, y);
+		}
+	}
+	/* draw the eyes */
+	{
+		uint val1 = GB(face,  6, 4);
+		uint val2 = GB(face, 20, 3);
+		uint32 high = 0x314 << PALETTE_SPRITE_START;
+
+		if (val2 >= 6) {
+			high = 0x30F << PALETTE_SPRITE_START;
+			if (val2 != 6)
+				high = 0x30D << PALETTE_SPRITE_START;
+		}
+
+		if (!(flag & 2)) {
+			if (!(flag & 1)) {
+				DrawSprite(high+((val1 * 12 >> 4) + SPRITE_PALETTE(0x32B)), x, y);
+			} else {
+				DrawSprite(high+(val1 + SPRITE_PALETTE(0x337)), x, y);
+			}
+		} else {
+			if (!(flag & 1)) {
+				DrawSprite(high+((val1 * 11 >> 4) + SPRITE_PALETTE(0x39A)), x, y);
+			} else {
+				DrawSprite(high+(val1 + SPRITE_PALETTE(0x3B8)), x, y);
+			}
+		}
+	}
+
+	/* draw the mouth */
+	{
+		uint val = GB(face, 10, 6);
+		uint val2;
+
+		if (!(flag&1)) {
+			val2 = ((val&0xF) * 15 >> 4);
+
+			if (val2 < 3) {
+				DrawSprite((flag&2 ? 0x397 : 0x367) + val2, x, y);
+				/* skip the rest */
+				goto skip_mouth;
+			}
+
+			val2 -= 3;
+			if (flag & 2) {
+				if (val2 > 8) val2 = 0;
+				val2 += 0x3A5 - 0x35B;
+			}
+			DrawSprite(val2 + 0x35B, x, y);
+		} else if (!(flag&2)) {
+			DrawSprite(((val&0xF) * 10 >> 4) + 0x351, x, y);
+		} else {
+			DrawSprite(((val&0xF) * 9 >> 4) + 0x3C8, x, y);
+		}
+
+		val >>= 3;
+
+		if (!(flag&2)) {
+			if (!(flag&1)) {
+				DrawSprite(0x349 + val, x, y);
+			} else {
+				DrawSprite( mouth_table[(val*3>>3)], x, y);
+			}
+		} else {
+			if (!(flag&1)) {
+				DrawSprite(0x393 + (val&3), x, y);
+			} else {
+				DrawSprite(0x3B3 + (val*5>>3), x, y);
+			}
+		}
+
+		skip_mouth:;
+	}
+
+
+	/* draw the hair */
+	{
+		uint val = GB(face, 16, 4);
+		if (flag & 2) {
+			if (flag & 1) {
+				DrawSprite(0x3D9 + (val * 5 >> 4), x, y);
+			} else {
+				DrawSprite(0x3D4 + (val * 5 >> 4), x, y);
+			}
+		} else {
+			if (flag & 1) {
+				DrawSprite(0x38B + (val * 5 >> 4), x, y);
+			} else {
+				DrawSprite(0x382 + (val * 9 >> 4), x, y);
+			}
+		}
+	}
+
+	/* draw the tie */
+	{
+		uint val = GB(face, 20, 8);
+
+		if (!(flag&1)) {
+			DrawSprite(0x36B + (GB(val, 0, 2) * 3 >> 2), x, y);
+			DrawSprite(0x36E + (GB(val, 2, 2) * 4 >> 2), x, y);
+			DrawSprite(0x372 + (GB(val, 4, 4) * 6 >> 4), x, y);
+		} else {
+			DrawSprite(0x378 + (GB(val, 0, 2) * 3 >> 2), x, y);
+			DrawSprite(0x37B + (GB(val, 2, 2) * 4 >> 2), x, y);
+
+			val >>= 4;
+			if (val < 3) DrawSprite((flag & 2 ? 0x3D1 : 0x37F) + val, x, y);
+		}
+	}
+
+	/* draw the glasses */
+	{
+		uint val = GB(face, 28, 3);
+
+		if (flag & 2) {
+			if (val <= 1) DrawSprite(0x3AE + val, x, y);
+		} else {
+			if (val <= 1) DrawSprite(0x347 + val, x, y);
+		}
+	}
+}
+
+void InvalidatePlayerWindows(const Player *p)
+{
+	PlayerID pid = p->index;
+
+	if (pid == _local_player) InvalidateWindow(WC_STATUS_BAR, 0);
+	InvalidateWindow(WC_FINANCES, pid);
+}
+
+bool CheckPlayerHasMoney(int32 cost)
+{
+	if (cost > 0) {
+		PlayerID pid = _current_player;
+		if (IsValidPlayer(pid) && cost > GetPlayer(pid)->player_money) {
+			SetDParam(0, cost);
+			_error_message = STR_0003_NOT_ENOUGH_CASH_REQUIRES;
+			return false;
+		}
+	}
+	return true;
+}
+
+static void SubtractMoneyFromAnyPlayer(Player *p, int32 cost)
+{
+	p->money64 -= cost;
+	UpdatePlayerMoney32(p);
+
+	p->yearly_expenses[0][_yearly_expenses_type] += cost;
+
+	if (HASBIT(1<<7|1<<8|1<<9|1<<10, _yearly_expenses_type)) {
+		p->cur_economy.income -= cost;
+	} else if (HASBIT(1<<2|1<<3|1<<4|1<<5|1<<6|1<<11, _yearly_expenses_type)) {
+		p->cur_economy.expenses -= cost;
+	}
+
+	InvalidatePlayerWindows(p);
+}
+
+void SubtractMoneyFromPlayer(int32 cost)
+{
+	PlayerID pid = _current_player;
+
+	if (IsValidPlayer(pid)) SubtractMoneyFromAnyPlayer(GetPlayer(pid), cost);
+}
+
+void SubtractMoneyFromPlayerFract(PlayerID player, int32 cost)
+{
+	Player *p = GetPlayer(player);
+	byte m = p->player_money_fraction;
+
+	p->player_money_fraction = m - (byte)cost;
+	cost >>= 8;
+	if (p->player_money_fraction > m) cost++;
+	if (cost != 0) SubtractMoneyFromAnyPlayer(p, cost);
+}
+
+// the player_money field is kept as it is, but money64 contains the actual amount of money.
+void UpdatePlayerMoney32(Player *p)
+{
+	if (p->money64 < -2000000000) {
+		p->player_money = -2000000000;
+	} else if (p->money64 > 2000000000) {
+		p->player_money = 2000000000;
+	} else {
+		p->player_money = (int32)p->money64;
+	}
+}
+
+void GetNameOfOwner(Owner owner, TileIndex tile)
+{
+	SetDParam(2, owner);
+
+	if (owner != OWNER_TOWN) {
+		if (!IsValidPlayer(owner)) {
+			SetDParam(0, STR_0150_SOMEONE);
+		} else {
+			const Player* p = GetPlayer(owner);
+
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+		}
+	} else {
+		const Town* t = ClosestTownFromTile(tile, (uint)-1);
+
+		SetDParam(0, STR_TOWN);
+		SetDParam(1, t->index);
+	}
+}
+
+
+bool CheckOwnership(PlayerID owner)
+{
+	assert(owner < OWNER_END);
+
+	if (owner == _current_player) return true;
+	_error_message = STR_013B_OWNED_BY;
+	GetNameOfOwner(owner, 0);
+	return false;
+}
+
+bool CheckTileOwnership(TileIndex tile)
+{
+	Owner owner = GetTileOwner(tile);
+
+	assert(owner < OWNER_END);
+
+	if (owner == _current_player) return true;
+	_error_message = STR_013B_OWNED_BY;
+
+	// no need to get the name of the owner unless we're the local player (saves some time)
+	if (IsLocalPlayer()) GetNameOfOwner(owner, tile);
+	return false;
+}
+
+static void GenerateCompanyName(Player *p)
+{
+	TileIndex tile;
+	Town *t;
+	StringID str;
+	Player *pp;
+	uint32 strp;
+	char buffer[100];
+
+	if (p->name_1 != STR_SV_UNNAMED) return;
+
+	tile = p->last_build_coordinate;
+	if (tile == 0) return;
+
+	t = ClosestTownFromTile(tile, (uint)-1);
+
+	if (IS_INT_INSIDE(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST+1)) {
+		str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_PLAYERNAME_START;
+		strp = t->townnameparts;
+
+verify_name:;
+		// No player must have this name already
+		FOR_ALL_PLAYERS(pp) {
+			if (pp->name_1 == str && pp->name_2 == strp) goto bad_town_name;
+		}
+
+		GetString(buffer, str, lastof(buffer));
+		if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 150)
+			goto bad_town_name;
+
+set_name:;
+		p->name_1 = str;
+		p->name_2 = strp;
+
+		MarkWholeScreenDirty();
+
+		if (!IsHumanPlayer(p->index)) {
+			SetDParam(0, t->index);
+			AddNewsItem((StringID)(p->index | NB_BNEWCOMPANY), NEWS_FLAGS(NM_CALLBACK, NF_TILE, NT_COMPANY_INFO, DNC_BANKRUPCY), p->last_build_coordinate, 0);
+		}
+		return;
+	}
+bad_town_name:;
+
+	if (p->president_name_1 == SPECSTR_PRESIDENT_NAME) {
+		str = SPECSTR_ANDCO_NAME;
+		strp = p->president_name_2;
+		goto set_name;
+	} else {
+		str = SPECSTR_ANDCO_NAME;
+		strp = Random();
+		goto verify_name;
+	}
+}
+
+#define COLOR_SWAP(i,j) do { byte t=colors[i];colors[i]=colors[j];colors[j]=t; } while(0)
+
+static const byte _color_sort[16] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
+static const byte _color_similar_1[16] = {8, 6, 255, 12,  255, 0, 1, 1, 0, 13,  11,  10, 3,   9,  15, 14};
+static const byte _color_similar_2[16] = {5, 7, 255, 255, 255, 8, 7, 6, 5, 12, 255, 255, 9, 255, 255, 255};
+
+static byte GeneratePlayerColor(void)
+{
+	byte colors[16], pcolor, t2;
+	int i,j,n;
+	uint32 r;
+	Player *p;
+
+	// Initialize array
+	for (i = 0; i != 16; i++) colors[i] = i;
+
+	// And randomize it
+	n = 100;
+	do {
+		r = Random();
+		COLOR_SWAP(GB(r, 0, 4), GB(r, 4, 4));
+	} while (--n);
+
+	// Bubble sort it according to the values in table 1
+	i = 16;
+	do {
+		for (j = 0; j != 15; j++) {
+			if (_color_sort[colors[j]] < _color_sort[colors[j + 1]]) {
+				COLOR_SWAP(j, j + 1);
+			}
+		}
+	} while (--i);
+
+	// Move the colors that look similar to each player's color to the side
+	FOR_ALL_PLAYERS(p) if (p->is_active) {
+		pcolor = p->player_color;
+		for (i=0; i!=16; i++) if (colors[i] == pcolor) {
+			colors[i] = 0xFF;
+
+			t2 = _color_similar_1[pcolor];
+			if (t2 == 0xFF) break;
+			for (i=0; i!=15; i++) {
+				if (colors[i] == t2) {
+					do COLOR_SWAP(i,i+1); while (++i != 15);
+					break;
+				}
+			}
+
+			t2 = _color_similar_2[pcolor];
+			if (t2 == 0xFF) break;
+			for (i = 0; i != 15; i++) {
+				if (colors[i] == t2) {
+					do COLOR_SWAP(i, i + 1); while (++i != 15);
+					break;
+				}
+			}
+			break;
+		}
+	}
+
+	// Return the first available color
+	for (i = 0;; i++) {
+		if (colors[i] != 0xFF) return colors[i];
+	}
+}
+
+static void GeneratePresidentName(Player *p)
+{
+	Player *pp;
+	char buffer[100], buffer2[40];
+
+	for (;;) {
+restart:;
+
+		p->president_name_2 = Random();
+		p->president_name_1 = SPECSTR_PRESIDENT_NAME;
+
+		SetDParam(0, p->president_name_2);
+		GetString(buffer, p->president_name_1, lastof(buffer));
+		if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 94)
+			continue;
+
+		FOR_ALL_PLAYERS(pp) {
+			if (pp->is_active && p != pp) {
+				SetDParam(0, pp->president_name_2);
+				GetString(buffer2, pp->president_name_1, lastof(buffer2));
+				if (strcmp(buffer2, buffer) == 0)
+					goto restart;
+			}
+		}
+		return;
+	}
+}
+
+static Player *AllocatePlayer(void)
+{
+	Player *p;
+	// Find a free slot
+	FOR_ALL_PLAYERS(p) {
+		if (!p->is_active) {
+			int i = p->index;
+			memset(p, 0, sizeof(Player));
+			p->index = i;
+			return p;
+		}
+	}
+	return NULL;
+}
+
+void ResetPlayerLivery(Player *p)
+{
+	LiveryScheme scheme;
+
+	for (scheme = 0; scheme < LS_END; scheme++) {
+		p->livery[scheme].in_use  = false;
+		p->livery[scheme].colour1 = p->player_color;
+		p->livery[scheme].colour2 = p->player_color;
+	}
+}
+
+Player *DoStartupNewPlayer(bool is_ai)
+{
+	Player *p;
+
+	p = AllocatePlayer();
+	if (p == NULL) return NULL;
+
+	// Make a color
+	p->player_color = GeneratePlayerColor();
+	ResetPlayerLivery(p);
+	_player_colors[p->index] = p->player_color;
+	p->name_1 = STR_SV_UNNAMED;
+	p->is_active = true;
+
+	p->money64 = p->player_money = p->current_loan = 100000;
+
+	p->is_ai = is_ai;
+	p->ai.state = 5; /* AIS_WANT_NEW_ROUTE */
+	p->share_owners[0] = p->share_owners[1] = p->share_owners[2] = p->share_owners[3] = PLAYER_SPECTATOR;
+
+	p->avail_railtypes = GetPlayerRailtypes(p->index);
+	p->inaugurated_year = _cur_year;
+	p->face = Random();
+
+	/* Engine renewal settings */
+	p->engine_renew_list = NULL;
+	p->renew_keep_length = false;
+	p->engine_renew = false;
+	p->engine_renew_months = -6;
+	p->engine_renew_money = 100000;
+
+	GeneratePresidentName(p);
+
+	InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	InvalidateWindow(WC_TOOLBAR_MENU, 0);
+	InvalidateWindow(WC_CLIENT_LIST, 0);
+
+	if (is_ai && (!_networking || _network_server) && _ai.enabled)
+		AI_StartNewAI(p->index);
+
+	memset(p->num_engines, 0, sizeof(p->num_engines));
+
+	return p;
+}
+
+void StartupPlayers(void)
+{
+	// The AI starts like in the setting with +2 month max
+	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + RandomRange(60 * DAY_TICKS) + 1;
+}
+
+static void MaybeStartNewPlayer(void)
+{
+	uint n;
+	Player *p;
+
+	// count number of competitors
+	n = 0;
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active && p->is_ai) n++;
+	}
+
+	// when there's a lot of computers in game, the probability that a new one starts is lower
+	if (n < (uint)_opt.diff.max_no_competitors &&
+			n < (_network_server ?
+				InteractiveRandomRange(_opt.diff.max_no_competitors + 2) :
+				RandomRange(_opt.diff.max_no_competitors + 2)
+			)) {
+		/* Send a command to all clients to start up a new AI.
+		 * Works fine for Multiplayer and Singleplayer */
+		DoCommandP(0, 1, 0, NULL, CMD_PLAYER_CTRL);
+	}
+
+	// The next AI starts like the difficulty setting said, with +2 month max
+	_next_competitor_start = _opt.diff.competitor_start_time * 90 * DAY_TICKS + 1;
+	_next_competitor_start += _network_server ? InteractiveRandomRange(60 * DAY_TICKS) : RandomRange(60 * DAY_TICKS);
+}
+
+void InitializePlayers(void)
+{
+	uint i;
+
+	memset(_players, 0, sizeof(_players));
+	for (i = 0; i != MAX_PLAYERS; i++) _players[i].index = i;
+	_cur_player_tick_index = 0;
+}
+
+void OnTick_Players(void)
+{
+	Player *p;
+
+	if (_game_mode == GM_EDITOR) return;
+
+	p = GetPlayer(_cur_player_tick_index);
+	_cur_player_tick_index = (_cur_player_tick_index + 1) % MAX_PLAYERS;
+	if (p->name_1 != 0) GenerateCompanyName(p);
+
+	if (AI_AllowNewAI() && _game_mode != GM_MENU && !--_next_competitor_start)
+		MaybeStartNewPlayer();
+}
+
+// index is the next parameter in _decode_parameters to set up
+StringID GetPlayerNameString(PlayerID player, uint index)
+{
+	if (IsHumanPlayer(player) && IsValidPlayer(player)) {
+		SetDParam(index, player+1);
+		return STR_7002_PLAYER;
+	}
+	return STR_EMPTY;
+}
+
+extern void ShowPlayerFinances(int player);
+
+void PlayersYearlyLoop(void)
+{
+	Player *p;
+
+	// Copy statistics
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active) {
+			memmove(&p->yearly_expenses[1], &p->yearly_expenses[0], sizeof(p->yearly_expenses) - sizeof(p->yearly_expenses[0]));
+			memset(&p->yearly_expenses[0], 0, sizeof(p->yearly_expenses[0]));
+			InvalidateWindow(WC_FINANCES, p->index);
+		}
+	}
+
+	if (_patches.show_finances && _local_player != PLAYER_SPECTATOR) {
+		ShowPlayerFinances(_local_player);
+		p = GetPlayer(_local_player);
+		if (p->num_valid_stat_ent > 5 && p->old_economy[0].performance_history < p->old_economy[4].performance_history) {
+			SndPlayFx(SND_01_BAD_YEAR);
+		} else {
+			SndPlayFx(SND_00_GOOD_YEAR);
+		}
+	}
+}
+
+byte GetPlayerRailtypes(PlayerID p)
+{
+	byte rt = 0;
+	EngineID i;
+
+	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
+		const Engine* e = GetEngine(i);
+		const EngineInfo *ei = EngInfo(i);
+
+		if (e->type == VEH_Train && HASBIT(ei->climates, _opt.landscape) &&
+				(HASBIT(e->player_avail, p) || _date >= (e->intro_date + 365)) &&
+				!(RailVehInfo(i)->flags & RVI_WAGON)) {
+			assert(e->railtype < RAILTYPE_END);
+			SETBIT(rt, e->railtype);
+		}
+	}
+
+	return rt;
+}
+
+static void DeletePlayerStuff(PlayerID pi)
+{
+	Player *p;
+
+	DeletePlayerWindows(pi);
+	p = GetPlayer(pi);
+	DeleteName(p->name_1);
+	DeleteName(p->president_name_1);
+	p->name_1 = 0;
+	p->president_name_1 = 0;
+}
+
+/** Change engine renewal parameters
+ * @param tile unused
+ * @param p1 bits 0-3 command
+ * - p1 = 0 - change auto renew bool
+ * - p1 = 1 - change auto renew months
+ * - p1 = 2 - change auto renew money
+ * - p1 = 3 - change auto renew array
+ * - p1 = 4 - change bool, months & money all together
+ * - p1 = 5 - change renew_keep_length
+ * @param p2 value to set
+ * if p1 = 0, then:
+ * - p2 = enable engine renewal
+ * if p1 = 1, then:
+ * - p2 = months left before engine expires to replace it
+ * if p1 = 2, then
+ * - p2 = minimum amount of money available
+ * if p1 = 3, then:
+ * - p2 bits  0-15 = old engine type
+ * - p2 bits 16-31 = new engine type
+ * if p1 = 4, then:
+ * - p1 bit     15 = enable engine renewal
+ * - p1 bits 16-31 = months left before engine expires to replace it
+ * - p2 bits  0-31 = minimum amount of money available
+ * if p1 = 5, then
+ * - p2 = enable renew_keep_length
+ */
+int32 CmdSetAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p;
+	if (!IsValidPlayer(_current_player)) return CMD_ERROR;
+
+	p = GetPlayer(_current_player);
+	switch (GB(p1, 0, 3)) {
+		case 0:
+			if (p->engine_renew == (bool)GB(p2, 0, 1))
+				return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				p->engine_renew = (bool)GB(p2, 0, 1);
+				if (IsLocalPlayer()) {
+					_patches.autorenew = p->engine_renew;
+					InvalidateWindow(WC_GAME_OPTIONS, 0);
+				}
+			}
+			break;
+		case 1:
+			if (p->engine_renew_months == (int16)p2)
+				return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				p->engine_renew_months = (int16)p2;
+				if (IsLocalPlayer()) {
+					_patches.autorenew_months = p->engine_renew_months;
+					InvalidateWindow(WC_GAME_OPTIONS, 0);
+				}
+			}
+			break;
+		case 2:
+			if (p->engine_renew_money == (uint32)p2)
+				return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				p->engine_renew_money = (uint32)p2;
+				if (IsLocalPlayer()) {
+					_patches.autorenew_money = p->engine_renew_money;
+					InvalidateWindow(WC_GAME_OPTIONS, 0);
+				}
+			}
+			break;
+		case 3: {
+			EngineID old_engine_type = GB(p2, 0, 16);
+			EngineID new_engine_type = GB(p2, 16, 16);
+			int32 cost;
+
+			if (new_engine_type != INVALID_ENGINE) {
+				/* First we make sure that it's a valid type the user requested
+				 * check that it's an engine that is in the engine array */
+				if (!IsEngineIndex(new_engine_type))
+					return CMD_ERROR;
+
+				// check that the new vehicle type is the same as the original one
+				if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type)
+					return CMD_ERROR;
+
+				// make sure that we do not replace a plane with a helicopter or vise versa
+				if (GetEngine(new_engine_type)->type == VEH_Aircraft &&
+						(AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL))
+					return CMD_ERROR;
+
+				// make sure that the player can actually buy the new engine
+				if (!HASBIT(GetEngine(new_engine_type)->player_avail, _current_player))
+					return CMD_ERROR;
+
+				cost = AddEngineReplacementForPlayer(p, old_engine_type, new_engine_type, flags);
+			} else {
+				cost = RemoveEngineReplacementForPlayer(p, old_engine_type, flags);
+			}
+
+			if (IsLocalPlayer()) InvalidateWindow(WC_REPLACE_VEHICLE, GetEngine(old_engine_type)->type);
+
+			return cost;
+		}
+
+		case 4:
+			if (flags & DC_EXEC) {
+				p->engine_renew = (bool)GB(p1, 15, 1);
+				p->engine_renew_months = (int16)GB(p1, 16, 16);
+				p->engine_renew_money = (uint32)p2;
+
+				if (IsLocalPlayer()) {
+					_patches.autorenew = p->engine_renew;
+					_patches.autorenew_months = p->engine_renew_months;
+					_patches.autorenew_money = p->engine_renew_money;
+					InvalidateWindow(WC_GAME_OPTIONS, 0);
+				}
+			}
+			break;
+		case 5:
+			if (p->renew_keep_length == (bool)GB(p2, 0, 1))
+				return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				p->renew_keep_length = (bool)GB(p2, 0, 1);
+				if (IsLocalPlayer()) {
+					InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
+				}
+			}
+		break;
+
+	}
+	return 0;
+}
+
+/** Control the players: add, delete, etc.
+ * @param tile unused
+ * @param p1 various functionality
+ * - p1 = 0 - create a new player, Which player (network) it will be is in p2
+ * - p1 = 1 - create a new AI player
+ * - p1 = 2 - delete a player. Player is identified by p2
+ * - p1 = 3 - merge two companies together. Player to merge #1 with player #2. Identified by p2
+ * @param p2 various functionality, dictated by p1
+ * - p1 = 0 - ClientID of the newly created player
+ * - p1 = 2 - PlayerID of the that is getting deleted
+ * - p1 = 3 - #1 p2 = (bit  0-15) - player to merge (p2 & 0xFFFF)
+ *          - #2 p2 = (bit 16-31) - player to be merged into ((p2>>16)&0xFFFF)
+ * @todo In the case of p1=0, create new player, the clientID of the new player is in parameter
+ * p2. This parameter is passed in at function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
+ * on the server itself. First of all this is unbelievably ugly; second of all, well,
+ * it IS ugly! <b>Someone fix this up :)</b> So where to fix?@n
+ * @arg - network_server.c:838 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)@n
+ * @arg - network_client.c:536 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) from where the map has been received
+ */
+int32 CmdPlayerCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	if (flags & DC_EXEC) _current_player = OWNER_NONE;
+
+	switch (p1) {
+	case 0: { /* Create a new player */
+		/* Joining Client:
+		 * _local_player: PLAYER_SPECTATOR
+		 * _network_playas/cid = requested company/player
+		 *
+		 * Other client(s)/server:
+		 * _local_player/_network_playas: what they play as
+		 * cid = requested company/player of joining client */
+		Player *p;
+		uint16 cid = p2; // ClientID
+
+		/* This command is only executed in a multiplayer game */
+		if (!_networking) return CMD_ERROR;
+
+		/* Has the network client a correct ClientID? */
+		if (!(flags & DC_EXEC)) return 0;
+#ifdef ENABLE_NETWORK
+		if (cid >= MAX_CLIENT_INFO) return 0;
+#endif /* ENABLE_NETWORK */
+
+		/* Delete multiplayer progress bar */
+		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
+
+		p = DoStartupNewPlayer(false);
+
+		/* A new player could not be created, revert to being a spectator */
+		if (p == NULL) {
+#ifdef ENABLE_NETWORK
+			if (_network_server) {
+				NetworkClientInfo *ci = &_network_client_info[cid];
+				ci->client_playas = PLAYER_SPECTATOR;
+				NetworkUpdateClientInfo(ci->client_index);
+			} else
+#endif /* ENABLE_NETWORK */
+			{
+				_network_playas = PLAYER_SPECTATOR;
+				SetLocalPlayer(PLAYER_SPECTATOR);
+			}
+			break;
+		}
+
+		/* This is the joining client who wants a new company */
+		if (_local_player != _network_playas) {
+			assert(_local_player == PLAYER_SPECTATOR && _network_playas == p->index);
+			SetLocalPlayer(p->index);
+			MarkWholeScreenDirty();
+		}
+
+		/* Now that we have a new player, broadcast its autorenew settings to
+		 * all clients so everything is in sync */
+		DoCommand(0,
+			(_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4,
+			_patches.autorenew_money,
+			DC_EXEC,
+			CMD_SET_AUTOREPLACE
+		);
+
+#ifdef ENABLE_NETWORK
+		if (_network_server) {
+			/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
+			 * server-side in network_server.c:838, function
+			 * DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
+			NetworkClientInfo *ci = &_network_client_info[cid];
+			ci->client_playas = p->index;
+			NetworkUpdateClientInfo(ci->client_index);
+
+			if (IsValidPlayer(ci->client_playas)) {
+				PlayerID player_backup = _local_player;
+				_network_player_info[p->index].months_empty = 0;
+
+				/* XXX - When a client joins, we automatically set its name to the
+				 * player's name (for some reason). As it stands now only the server
+				 * knows the client's name, so it needs to send out a "broadcast" to
+				 * do this. To achieve this we send a network command. However, it
+				 * uses _local_player to execute the command as.  To prevent abuse
+				 * (eg. only yourself can change your name/company), we 'cheat' by
+				 * impersonation _local_player as the server. Not the best solution;
+				 * but it works.
+				 * TODO: Perhaps this could be improved by when the client is ready
+				 * with joining to let it send itself the command, and not the server?
+				 * For example in network_client.c:534? */
+				_cmd_text = ci->client_name;
+				_local_player = ci->client_playas;
+				NetworkSend_Command(0, 0, 0, CMD_CHANGE_PRESIDENT_NAME, NULL);
+				_local_player = player_backup;
+			}
+		}
+#endif /* ENABLE_NETWORK */
+	} break;
+
+	case 1: /* Make a new AI player */
+		if (!(flags & DC_EXEC)) return 0;
+
+		DoStartupNewPlayer(true);
+		break;
+
+	case 2: { /* Delete a player */
+		Player *p;
+
+		if (!IsValidPlayer(p2)) return CMD_ERROR;
+
+		if (!(flags & DC_EXEC)) return 0;
+
+		p = GetPlayer(p2);
+
+		/* Only allow removal of HUMAN companies */
+		if (IsHumanPlayer(p->index)) {
+			/* Delete any open window of the company */
+			DeletePlayerWindows(p->index);
+
+			/* Show the bankrupt news */
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			AddNewsItem( (StringID)(p->index | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
+
+			/* Remove the company */
+			ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
+			p->is_active = false;
+		}
+		RemoveAllEngineReplacementForPlayer(p);
+
+	} break;
+
+	case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
+		PlayerID pid_old = GB(p2,  0, 16);
+		PlayerID pid_new = GB(p2, 16, 16);
+
+		if (!IsValidPlayer(pid_old) || !IsValidPlayer(pid_new)) return CMD_ERROR;
+
+		if (!(flags & DC_EXEC)) return CMD_ERROR;
+
+		ChangeOwnershipOfPlayerItems(pid_old, pid_new);
+		DeletePlayerStuff(pid_old);
+	} break;
+
+	default: return CMD_ERROR;
+	}
+
+	return 0;
+}
+
+static const StringID _endgame_perf_titles[] = {
+	STR_0213_BUSINESSMAN,
+	STR_0213_BUSINESSMAN,
+	STR_0213_BUSINESSMAN,
+	STR_0213_BUSINESSMAN,
+	STR_0213_BUSINESSMAN,
+	STR_0214_ENTREPRENEUR,
+	STR_0214_ENTREPRENEUR,
+	STR_0215_INDUSTRIALIST,
+	STR_0215_INDUSTRIALIST,
+	STR_0216_CAPITALIST,
+	STR_0216_CAPITALIST,
+	STR_0217_MAGNATE,
+	STR_0217_MAGNATE,
+	STR_0218_MOGUL,
+	STR_0218_MOGUL,
+	STR_0219_TYCOON_OF_THE_CENTURY
+};
+
+StringID EndGameGetPerformanceTitleFromValue(uint value)
+{
+	value = minu(value / 64, lengthof(_endgame_perf_titles) - 1);
+
+	return _endgame_perf_titles[value];
+}
+
+/* Return true if any cheat has been used, false otherwise */
+static bool CheatHasBeenUsed(void)
+{
+	const Cheat* cht = (Cheat*)&_cheats;
+	const Cheat* cht_last = &cht[sizeof(_cheats) / sizeof(Cheat)];
+
+	for (; cht != cht_last; cht++) {
+		if (cht->been_used) return true;
+	}
+
+	return false;
+}
+
+/* Save the highscore for the player */
+int8 SaveHighScoreValue(const Player *p)
+{
+	HighScore *hs = _highscore_table[_opt.diff_level];
+	uint i;
+	uint16 score = p->old_economy[0].performance_history;
+
+	/* Exclude cheaters from the honour of being in the highscore table */
+	if (CheatHasBeenUsed()) return -1;
+
+	for (i = 0; i < lengthof(_highscore_table[0]); i++) {
+		/* You are in the TOP5. Move all values one down and save us there */
+		if (hs[i].score <= score) {
+			// move all elements one down starting from the replaced one
+			memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1));
+			SetDParam(0, p->president_name_1);
+			SetDParam(1, p->president_name_2);
+			SetDParam(2, p->name_1);
+			SetDParam(3, p->name_2);
+			GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string
+			hs[i].score = score;
+			hs[i].title = EndGameGetPerformanceTitleFromValue(score);
+			return i;
+		}
+	}
+
+	return -1; // too bad; we did not make it into the top5
+}
+
+/* Sort all players given their performance */
+static int CDECL HighScoreSorter(const void *a, const void *b)
+{
+	const Player *pa = *(const Player* const*)a;
+	const Player *pb = *(const Player* const*)b;
+
+	return pb->old_economy[0].performance_history - pa->old_economy[0].performance_history;
+}
+
+/* Save the highscores in a network game when it has ended */
+#define LAST_HS_ITEM lengthof(_highscore_table) - 1
+int8 SaveHighScoreValueNetwork(void)
+{
+	const Player* p;
+	const Player* pl[MAX_PLAYERS];
+	size_t count = 0;
+	int8 player = -1;
+
+	/* Sort all active players with the highest score first */
+	FOR_ALL_PLAYERS(p) if (p->is_active) pl[count++] = p;
+	qsort((Player*)pl, count, sizeof(pl[0]), HighScoreSorter);
+
+	{
+		uint i;
+
+		memset(_highscore_table[LAST_HS_ITEM], 0, sizeof(_highscore_table[0]));
+
+		/* Copy over Top5 companies */
+		for (i = 0; i < lengthof(_highscore_table[LAST_HS_ITEM]) && i < count; i++) {
+			HighScore* hs = &_highscore_table[LAST_HS_ITEM][i];
+
+			SetDParam(0, pl[i]->president_name_1);
+			SetDParam(1, pl[i]->president_name_2);
+			SetDParam(2, pl[i]->name_1);
+			SetDParam(3, pl[i]->name_2);
+			GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string
+			hs->score = pl[i]->old_economy[0].performance_history;
+			hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
+
+			// get the ranking of the local player
+			if (pl[i]->index == _local_player) player = i;
+		}
+	}
+
+	/* Add top5 players to highscore table */
+	return player;
+}
+
+/* Save HighScore table to file */
+void SaveToHighScore(void)
+{
+	FILE *fp = fopen(_highscore_file, "wb");
+
+	if (fp != NULL) {
+		uint i;
+		HighScore *hs;
+
+		for (i = 0; i < LAST_HS_ITEM; i++) { // don't save network highscores
+			for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
+				/* First character is a command character, so strlen will fail on that */
+				byte length = min(sizeof(hs->company), (hs->company[0] == '\0') ? 0 : (int)strlen(&hs->company[1]) + 1);
+
+				fwrite(&length, sizeof(length), 1, fp); // write away string length
+				fwrite(hs->company, length, 1, fp);
+				fwrite(&hs->score, sizeof(hs->score), 1, fp);
+				fwrite("", 2, 1, fp); /* XXX - placeholder for hs->title, not saved anymore; compatibility */
+			}
+		}
+		fclose(fp);
+	}
+}
+
+/* Initialize the highscore table to 0 and if any file exists, load in values */
+void LoadFromHighScore(void)
+{
+	FILE *fp = fopen(_highscore_file, "rb");
+
+	memset(_highscore_table, 0, sizeof(_highscore_table));
+
+	if (fp != NULL) {
+		uint i;
+		HighScore *hs;
+
+		for (i = 0; i < LAST_HS_ITEM; i++) { // don't load network highscores
+			for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
+				byte length;
+				fread(&length, sizeof(length), 1, fp);
+
+				fread(hs->company, 1, length, fp);
+				fread(&hs->score, sizeof(hs->score), 1, fp);
+				fseek(fp, 2, SEEK_CUR); /* XXX - placeholder for hs->title, not saved anymore; compatibility */
+				hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
+			}
+		}
+		fclose(fp);
+	}
+
+	/* Initialize end of game variable (when to show highscore chart) */
+	_patches.ending_year = 2051;
+}
+
+// Save/load of players
+static const SaveLoad _player_desc[] = {
+	    SLE_VAR(Player, name_2,          SLE_UINT32),
+	    SLE_VAR(Player, name_1,          SLE_STRINGID),
+
+	    SLE_VAR(Player, president_name_1,SLE_UINT16),
+	    SLE_VAR(Player, president_name_2,SLE_UINT32),
+
+	    SLE_VAR(Player, face,            SLE_UINT32),
+
+	// money was changed to a 64 bit field in savegame version 1.
+	SLE_CONDVAR(Player, money64,               SLE_VAR_I64 | SLE_FILE_I32, 0, 0),
+	SLE_CONDVAR(Player, money64,               SLE_INT64, 1, SL_MAX_VERSION),
+
+	    SLE_VAR(Player, current_loan,          SLE_INT32),
+
+	    SLE_VAR(Player, player_color,          SLE_UINT8),
+	    SLE_VAR(Player, player_money_fraction, SLE_UINT8),
+	    SLE_VAR(Player, avail_railtypes,       SLE_UINT8),
+	    SLE_VAR(Player, block_preview,         SLE_UINT8),
+
+	    SLE_VAR(Player, cargo_types,           SLE_UINT16),
+	SLE_CONDVAR(Player, location_of_house,     SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(Player, location_of_house,     SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(Player, last_build_coordinate, SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, inaugurated_year,      SLE_FILE_U8  | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Player, inaugurated_year,      SLE_INT32,                  31, SL_MAX_VERSION),
+
+	    SLE_ARR(Player, share_owners,          SLE_UINT8, 4),
+
+	    SLE_VAR(Player, num_valid_stat_ent,    SLE_UINT8),
+
+	    SLE_VAR(Player, quarters_of_bankrupcy, SLE_UINT8),
+	    SLE_VAR(Player, bankrupt_asked,        SLE_UINT8),
+	    SLE_VAR(Player, bankrupt_timeout,      SLE_INT16),
+	    SLE_VAR(Player, bankrupt_value,        SLE_INT32),
+
+	// yearly expenses was changed to 64-bit in savegame version 2.
+	SLE_CONDARR(Player, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1),
+	SLE_CONDARR(Player, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_MAX_VERSION),
+
+	SLE_CONDVAR(Player, is_ai,                 SLE_BOOL, 2, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, is_active,             SLE_BOOL, 4, SL_MAX_VERSION),
+
+	// Engine renewal settings
+	SLE_CONDNULL(512, 16, 18),
+	SLE_CONDREF(Player, engine_renew_list,     REF_ENGINE_RENEWS,          19, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, engine_renew,          SLE_BOOL,                   16, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, engine_renew_months,   SLE_INT16,                  16, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, engine_renew_money,    SLE_UINT32,                 16, SL_MAX_VERSION),
+	SLE_CONDVAR(Player, renew_keep_length,     SLE_BOOL,                    2, SL_MAX_VERSION), // added with 16.1, but was blank since 2
+
+	// reserve extra space in savegame here. (currently 63 bytes)
+	SLE_CONDNULL(63, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _player_economy_desc[] = {
+	// these were changed to 64-bit in savegame format 2
+	SLE_CONDVAR(PlayerEconomyEntry, income,              SLE_INT32,                  0, 1),
+	SLE_CONDVAR(PlayerEconomyEntry, expenses,            SLE_INT32,                  0, 1),
+	SLE_CONDVAR(PlayerEconomyEntry, company_value,       SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
+	SLE_CONDVAR(PlayerEconomyEntry, income,              SLE_FILE_I64 | SLE_VAR_I32, 2, SL_MAX_VERSION),
+	SLE_CONDVAR(PlayerEconomyEntry, expenses,            SLE_FILE_I64 | SLE_VAR_I32, 2, SL_MAX_VERSION),
+	SLE_CONDVAR(PlayerEconomyEntry, company_value,       SLE_INT64,                  2, SL_MAX_VERSION),
+
+	    SLE_VAR(PlayerEconomyEntry, delivered_cargo,     SLE_INT32),
+	    SLE_VAR(PlayerEconomyEntry, performance_history, SLE_INT32),
+
+	SLE_END()
+};
+
+static const SaveLoad _player_ai_desc[] = {
+	    SLE_VAR(PlayerAI, state,             SLE_UINT8),
+	    SLE_VAR(PlayerAI, tick,              SLE_UINT8),
+	SLE_CONDVAR(PlayerAI, state_counter,     SLE_FILE_U16 | SLE_VAR_U32,  0, 12),
+	SLE_CONDVAR(PlayerAI, state_counter,     SLE_UINT32,                 13, SL_MAX_VERSION),
+	    SLE_VAR(PlayerAI, timeout_counter,   SLE_UINT16),
+
+	    SLE_VAR(PlayerAI, state_mode,        SLE_UINT8),
+	    SLE_VAR(PlayerAI, banned_tile_count, SLE_UINT8),
+	    SLE_VAR(PlayerAI, railtype_to_use,   SLE_UINT8),
+
+	    SLE_VAR(PlayerAI, cargo_type,        SLE_UINT8),
+	    SLE_VAR(PlayerAI, num_wagons,        SLE_UINT8),
+	    SLE_VAR(PlayerAI, build_kind,        SLE_UINT8),
+	    SLE_VAR(PlayerAI, num_build_rec,     SLE_UINT8),
+	    SLE_VAR(PlayerAI, num_loco_to_build, SLE_UINT8),
+	    SLE_VAR(PlayerAI, num_want_fullload, SLE_UINT8),
+
+	    SLE_VAR(PlayerAI, route_type_mask,   SLE_UINT8),
+
+	SLE_CONDVAR(PlayerAI, start_tile_a,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(PlayerAI, start_tile_a,      SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(PlayerAI, cur_tile_a,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(PlayerAI, cur_tile_a,        SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLE_VAR(PlayerAI, start_dir_a,       SLE_UINT8),
+	    SLE_VAR(PlayerAI, cur_dir_a,         SLE_UINT8),
+
+	SLE_CONDVAR(PlayerAI, start_tile_b,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(PlayerAI, start_tile_b,      SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(PlayerAI, cur_tile_b,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
+	SLE_CONDVAR(PlayerAI, cur_tile_b,        SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLE_VAR(PlayerAI, start_dir_b,       SLE_UINT8),
+	    SLE_VAR(PlayerAI, cur_dir_b,         SLE_UINT8),
+
+	    SLE_REF(PlayerAI, cur_veh,           REF_VEHICLE),
+
+	    SLE_ARR(PlayerAI, wagon_list,        SLE_UINT16, 9),
+	    SLE_ARR(PlayerAI, order_list_blocks, SLE_UINT8, 20),
+	    SLE_ARR(PlayerAI, banned_tiles,      SLE_UINT16, 16),
+
+	SLE_CONDNULL(64, 2, SL_MAX_VERSION),
+	SLE_END()
+};
+
+static const SaveLoad _player_ai_build_rec_desc[] = {
+	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_UINT32,                 6, SL_MAX_VERSION),
+	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
+	    SLE_VAR(AiBuildRec, rand_rng,          SLE_UINT8),
+	    SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8),
+	    SLE_VAR(AiBuildRec, unk6,              SLE_UINT8),
+	    SLE_VAR(AiBuildRec, unk7,              SLE_UINT8),
+	    SLE_VAR(AiBuildRec, buildcmd_a,        SLE_UINT8),
+	    SLE_VAR(AiBuildRec, buildcmd_b,        SLE_UINT8),
+	    SLE_VAR(AiBuildRec, direction,         SLE_UINT8),
+	    SLE_VAR(AiBuildRec, cargo,             SLE_UINT8),
+	SLE_END()
+};
+
+static const SaveLoad _player_livery_desc[] = {
+	SLE_CONDVAR(Livery, in_use,  SLE_BOOL,  34, SL_MAX_VERSION),
+	SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION),
+	SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION),
+	SLE_END()
+};
+
+static void SaveLoad_PLYR(Player* p)
+{
+	int i;
+
+	SlObject(p, _player_desc);
+
+	// Write AI?
+	if (!IsHumanPlayer(p->index)) {
+		SlObject(&p->ai, _player_ai_desc);
+		for (i = 0; i != p->ai.num_build_rec; i++) {
+			SlObject(&p->ai.src + i, _player_ai_build_rec_desc);
+		}
+	}
+
+	// Write economy
+	SlObject(&p->cur_economy, _player_economy_desc);
+
+	// Write old economy entries.
+	for (i = 0; i < p->num_valid_stat_ent; i++) {
+		SlObject(&p->old_economy[i], _player_economy_desc);
+	}
+
+	// Write each livery entry.
+	for (i = 0; i < LS_END; i++) {
+		SlObject(&p->livery[i], _player_livery_desc);
+	}
+}
+
+static void Save_PLYR(void)
+{
+	Player *p;
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active) {
+			SlSetArrayIndex(p->index);
+			SlAutolength((AutolengthProc*)SaveLoad_PLYR, p);
+		}
+	}
+}
+
+static void Load_PLYR(void)
+{
+	int index;
+	while ((index = SlIterateArray()) != -1) {
+		Player *p = GetPlayer(index);
+		SaveLoad_PLYR(p);
+		_player_colors[index] = p->player_color;
+		UpdatePlayerMoney32(p);
+
+		/* This is needed so an AI is attached to a loaded AI */
+		if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
+			AI_StartNewAI(p->index);
+	}
+}
+
+const ChunkHandler _player_chunk_handlers[] = {
+	{ 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/queue.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "queue.h"
-
-static void Stack_Clear(Queue* q, bool free_values)
-{
-	if (free_values) {
-		uint i;
-
-		for (i = 0; i < q->data.stack.size; i++) free(q->data.stack.elements[i]);
-	}
-	q->data.stack.size = 0;
-}
-
-static void Stack_Free(Queue* q, bool free_values)
-{
-	q->clear(q, free_values);
-	free(q->data.stack.elements);
-	if (q->freeq) free(q);
-}
-
-static bool Stack_Push(Queue* q, void* item, int priority)
-{
-	if (q->data.stack.size == q->data.stack.max_size) return false;
-	q->data.stack.elements[q->data.stack.size++] = item;
-	return true;
-}
-
-static void* Stack_Pop(Queue* q)
-{
-	if (q->data.stack.size == 0) return NULL;
-	return q->data.stack.elements[--q->data.stack.size];
-}
-
-static bool Stack_Delete(Queue* q, void* item, int priority)
-{
-	return false;
-}
-
-static Queue* init_stack(Queue* q, uint max_size)
-{
-	q->push = Stack_Push;
-	q->pop = Stack_Pop;
-	q->del = Stack_Delete;
-	q->clear = Stack_Clear;
-	q->free = Stack_Free;
-	q->data.stack.max_size = max_size;
-	q->data.stack.size = 0;
-	q->data.stack.elements = malloc(max_size * sizeof(*q->data.stack.elements));
-	q->freeq = false;
-	return q;
-}
-
-Queue* new_Stack(uint max_size)
-{
-	Queue* q = malloc(sizeof(*q));
-
-	init_stack(q, max_size);
-	q->freeq = true;
-	return q;
-}
-
-/*
- * Fifo
- */
-
-static void Fifo_Clear(Queue* q, bool free_values)
-{
-	if (free_values) {
-		uint head = q->data.fifo.head;
-		uint tail = q->data.fifo.tail; /* cache for speed */
-
-		while (head != tail) {
-			free(q->data.fifo.elements[tail]);
-			tail = (tail + 1) % q->data.fifo.max_size;
-		}
-	}
-	q->data.fifo.head = 0;
-	q->data.fifo.tail = 0;
-}
-
-static void Fifo_Free(Queue* q, bool free_values)
-{
-	q->clear(q, free_values);
-	free(q->data.fifo.elements);
-	if (q->freeq) free(q);
-}
-
-static bool Fifo_Push(Queue* q, void* item, int priority)
-{
-	uint next = (q->data.fifo.head + 1) % q->data.fifo.max_size;
-
-	if (next == q->data.fifo.tail) return false;
-	q->data.fifo.elements[q->data.fifo.head] = item;
-
-	q->data.fifo.head = next;
-	return true;
-}
-
-static void* Fifo_Pop(Queue* q)
-{
-	void* result;
-
-	if (q->data.fifo.head == q->data.fifo.tail) return NULL;
-	result = q->data.fifo.elements[q->data.fifo.tail];
-
-	q->data.fifo.tail = (q->data.fifo.tail + 1) % q->data.fifo.max_size;
-	return result;
-}
-
-static bool Fifo_Delete(Queue* q, void* item, int priority)
-{
-	return false;
-}
-
-static Queue* init_fifo(Queue* q, uint max_size)
-{
-	q->push = Fifo_Push;
-	q->pop = Fifo_Pop;
-	q->del = Fifo_Delete;
-	q->clear = Fifo_Clear;
-	q->free = Fifo_Free;
-	q->data.fifo.max_size = max_size;
-	q->data.fifo.head = 0;
-	q->data.fifo.tail = 0;
-	q->data.fifo.elements = malloc(max_size * sizeof(*q->data.fifo.elements));
-	q->freeq = false;
-	return q;
-}
-
-Queue* new_Fifo(uint max_size)
-{
-	Queue* q = malloc(sizeof(*q));
-
-	init_fifo(q, max_size);
-	q->freeq = true;
-	return q;
-}
-
-
-/*
- * Insertion Sorter
- */
-
-static void InsSort_Clear(Queue* q, bool free_values)
-{
-	InsSortNode* node = q->data.inssort.first;
-	InsSortNode* prev;
-
-	while (node != NULL) {
-		if (free_values) free(node->item);
-		prev = node;
-		node = node->next;
-		free(prev);
-	}
-	q->data.inssort.first = NULL;
-}
-
-static void InsSort_Free(Queue* q, bool free_values)
-{
-	q->clear(q, free_values);
-	if (q->freeq) free(q);
-}
-
-static bool InsSort_Push(Queue* q, void* item, int priority)
-{
-	InsSortNode* newnode = malloc(sizeof(*newnode));
-
-	if (newnode == NULL) return false;
-	newnode->item = item;
-	newnode->priority = priority;
-	if (q->data.inssort.first == NULL ||
-			q->data.inssort.first->priority >= priority) {
-		newnode->next = q->data.inssort.first;
-		q->data.inssort.first = newnode;
-	} else {
-		InsSortNode* node = q->data.inssort.first;
-		while (node != NULL) {
-			if (node->next == NULL || node->next->priority >= priority) {
-				newnode->next = node->next;
-				node->next = newnode;
-				break;
-			}
-			node = node->next;
-		}
-	}
-	return true;
-}
-
-static void* InsSort_Pop(Queue* q)
-{
-	InsSortNode* node = q->data.inssort.first;
-	void* result;
-
-	if (node == NULL) return NULL;
-	result = node->item;
-	q->data.inssort.first = q->data.inssort.first->next;
-	assert(q->data.inssort.first == NULL || q->data.inssort.first->priority >= node->priority);
-	free(node);
-	return result;
-}
-
-static bool InsSort_Delete(Queue* q, void* item, int priority)
-{
-	return false;
-}
-
-void init_InsSort(Queue* q)
-{
-	q->push = InsSort_Push;
-	q->pop = InsSort_Pop;
-	q->del = InsSort_Delete;
-	q->clear = InsSort_Clear;
-	q->free = InsSort_Free;
-	q->data.inssort.first = NULL;
-	q->freeq = false;
-}
-
-Queue* new_InsSort(void)
-{
-	Queue* q = malloc(sizeof(*q));
-
-	init_InsSort(q);
-	q->freeq = true;
-	return q;
-}
-
-
-/*
- * Binary Heap
- * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
- */
-
-#define BINARY_HEAP_BLOCKSIZE (1 << BINARY_HEAP_BLOCKSIZE_BITS)
-#define BINARY_HEAP_BLOCKSIZE_MASK (BINARY_HEAP_BLOCKSIZE - 1)
-
-// To make our life easy, we make the next define
-//  Because Binary Heaps works with array from 1 to n,
-//  and C with array from 0 to n-1, and we don't like typing
-//  q->data.binaryheap.elements[i - 1] every time, we use this define.
-#define BIN_HEAP_ARR(i) q->data.binaryheap.elements[((i) - 1) >> BINARY_HEAP_BLOCKSIZE_BITS][((i) - 1) & BINARY_HEAP_BLOCKSIZE_MASK]
-
-static void BinaryHeap_Clear(Queue* q, bool free_values)
-{
-	/* Free all items if needed and free all but the first blocks of memory */
-	uint i;
-	uint j;
-
-	for (i = 0; i < q->data.binaryheap.blocks; i++) {
-		if (q->data.binaryheap.elements[i] == NULL) {
-			/* No more allocated blocks */
-			break;
-		}
-		/* For every allocated block */
-		if (free_values) {
-			for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
-				/* For every element in the block */
-				if ((q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
-						(q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
-					break; /* We're past the last element */
-				}
-				free(q->data.binaryheap.elements[i][j].item);
-			}
-		}
-		if (i != 0) {
-			/* Leave the first block of memory alone */
-			free(q->data.binaryheap.elements[i]);
-			q->data.binaryheap.elements[i] = NULL;
-		}
-	}
-	q->data.binaryheap.size = 0;
-	q->data.binaryheap.blocks = 1;
-}
-
-static void BinaryHeap_Free(Queue* q, bool free_values)
-{
-	uint i;
-
-	q->clear(q, free_values);
-	for (i = 0; i < q->data.binaryheap.blocks; i++) {
-		if (q->data.binaryheap.elements[i] == NULL) break;
-		free(q->data.binaryheap.elements[i]);
-	}
-	free(q->data.binaryheap.elements);
-	if (q->freeq) free(q);
-}
-
-static bool BinaryHeap_Push(Queue* q, void* item, int priority)
-{
-#ifdef QUEUE_DEBUG
-	printf("[BinaryHeap] Pushing an element. There are %d elements left\n", q->data.binaryheap.size);
-#endif
-
-	if (q->data.binaryheap.size == q->data.binaryheap.max_size) return false;
-	assert(q->data.binaryheap.size < q->data.binaryheap.max_size);
-
-	if (q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
-		/* The currently allocated blocks are full, allocate a new one */
-		assert((q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
-		q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] = malloc(BINARY_HEAP_BLOCKSIZE * sizeof(*q->data.binaryheap.elements[0]));
-		q->data.binaryheap.blocks++;
-#ifdef QUEUE_DEBUG
-		printf("[BinaryHeap] Increasing size of elements to %d nodes\n", q->data.binaryheap.blocks *  BINARY_HEAP_BLOCKSIZE);
-#endif
-	}
-
-	// Add the item at the end of the array
-	BIN_HEAP_ARR(q->data.binaryheap.size + 1).priority = priority;
-	BIN_HEAP_ARR(q->data.binaryheap.size + 1).item = item;
-	q->data.binaryheap.size++;
-
-	// Now we are going to check where it belongs. As long as the parent is
-	// bigger, we switch with the parent
-	{
-		BinaryHeapNode temp;
-		int i;
-		int j;
-
-		i = q->data.binaryheap.size;
-		while (i > 1) {
-			// Get the parent of this object (divide by 2)
-			j = i / 2;
-			// Is the parent bigger then the current, switch them
-			if (BIN_HEAP_ARR(i).priority <= BIN_HEAP_ARR(j).priority) {
-				temp = BIN_HEAP_ARR(j);
-				BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
-				BIN_HEAP_ARR(i) = temp;
-				i = j;
-			} else {
-				// It is not, we're done!
-				break;
-			}
-		}
-	}
-
-	return true;
-}
-
-static bool BinaryHeap_Delete(Queue* q, void* item, int priority)
-{
-	uint i = 0;
-
-#ifdef QUEUE_DEBUG
-	printf("[BinaryHeap] Deleting an element. There are %d elements left\n", q->data.binaryheap.size);
-#endif
-
-	// First, we try to find the item..
-	do {
-		if (BIN_HEAP_ARR(i + 1).item == item) break;
-		i++;
-	} while (i < q->data.binaryheap.size);
-	// We did not find the item, so we return false
-	if (i == q->data.binaryheap.size) return false;
-
-	// Now we put the last item over the current item while decreasing the size of the elements
-	q->data.binaryheap.size--;
-	BIN_HEAP_ARR(i + 1) = BIN_HEAP_ARR(q->data.binaryheap.size + 1);
-
-	// Now the only thing we have to do, is resort it..
-	// On place i there is the item to be sorted.. let's start there
-	{
-		uint j;
-		BinaryHeapNode temp;
-		/* Because of the fact that Binary Heap uses array from 1 to n, we need to
-		 * increase i by 1
-		 */
-		i++;
-
-		for (;;) {
-			j = i;
-			// Check if we have 2 childs
-			if (2 * j + 1 <= q->data.binaryheap.size) {
-				// Is this child smaller than the parent?
-				if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
-				// Yes, we _need_ to use i here, not j, because we want to have the smallest child
-				//  This way we get that straight away!
-				if (BIN_HEAP_ARR(i).priority >= BIN_HEAP_ARR(2 * j + 1).priority) i = 2 * j + 1;
-			// Do we have one child?
-			} else if (2 * j <= q->data.binaryheap.size) {
-				if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
-			}
-
-			// One of our childs is smaller than we are, switch
-			if (i != j) {
-				temp = BIN_HEAP_ARR(j);
-				BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
-				BIN_HEAP_ARR(i) = temp;
-			} else {
-				// None of our childs is smaller, so we stay here.. stop :)
-				break;
-			}
-		}
-	}
-
-	return true;
-}
-
-static void* BinaryHeap_Pop(Queue* q)
-{
-	void* result;
-
-#ifdef QUEUE_DEBUG
-	printf("[BinaryHeap] Popping an element. There are %d elements left\n", q->data.binaryheap.size);
-#endif
-
-	if (q->data.binaryheap.size == 0) return NULL;
-
-	// The best item is always on top, so give that as result
-	result = BIN_HEAP_ARR(1).item;
-	// And now we should get rid of this item...
-	BinaryHeap_Delete(q, BIN_HEAP_ARR(1).item, BIN_HEAP_ARR(1).priority);
-
-	return result;
-}
-
-void init_BinaryHeap(Queue* q, uint max_size)
-{
-	assert(q != NULL);
-	q->push = BinaryHeap_Push;
-	q->pop = BinaryHeap_Pop;
-	q->del = BinaryHeap_Delete;
-	q->clear = BinaryHeap_Clear;
-	q->free = BinaryHeap_Free;
-	q->data.binaryheap.max_size = max_size;
-	q->data.binaryheap.size = 0;
-	// We malloc memory in block of BINARY_HEAP_BLOCKSIZE
-	//   It autosizes when it runs out of memory
-	q->data.binaryheap.elements = calloc((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1, sizeof(*q->data.binaryheap.elements));
-	q->data.binaryheap.elements[0] = malloc(BINARY_HEAP_BLOCKSIZE * sizeof(*q->data.binaryheap.elements[0]));
-	q->data.binaryheap.blocks = 1;
-	q->freeq = false;
-#ifdef QUEUE_DEBUG
-	printf("[BinaryHeap] Initial size of elements is %d nodes\n", BINARY_HEAP_BLOCKSIZE);
-#endif
-}
-
-Queue* new_BinaryHeap(uint max_size)
-{
-	Queue* q = malloc(sizeof(*q));
-
-	init_BinaryHeap(q, max_size);
-	q->freeq = true;
-	return q;
-}
-
-// Because we don't want anyone else to bother with our defines
-#undef BIN_HEAP_ARR
-
-/*
- * Hash
- */
-
-void init_Hash(Hash* h, Hash_HashProc* hash, uint num_buckets)
-{
-	/* Allocate space for the Hash, the buckets and the bucket flags */
-	uint i;
-
-	assert(h != NULL);
-#ifdef HASH_DEBUG
-	debug("Allocated hash: %p", h);
-#endif
-	h->hash = hash;
-	h->size = 0;
-	h->num_buckets = num_buckets;
-	h->buckets = malloc(num_buckets * (sizeof(*h->buckets) + sizeof(*h->buckets_in_use)));
-#ifdef HASH_DEBUG
-	debug("Buckets = %p", h->buckets);
-#endif
-	h->buckets_in_use = (bool*)(h->buckets + num_buckets);
-	h->freeh = false;
-	for (i = 0; i < num_buckets; i++) h->buckets_in_use[i] = false;
-}
-
-Hash* new_Hash(Hash_HashProc* hash, int num_buckets)
-{
-	Hash* h = malloc(sizeof(*h));
-
-	init_Hash(h, hash, num_buckets);
-	h->freeh = true;
-	return h;
-}
-
-void delete_Hash(Hash* h, bool free_values)
-{
-	uint i;
-
-	/* Iterate all buckets */
-	for (i = 0; i < h->num_buckets; i++) {
-		if (h->buckets_in_use[i]) {
-			HashNode* node;
-
-			/* Free the first value */
-			if (free_values) free(h->buckets[i].value);
-			node = h->buckets[i].next;
-			while (node != NULL) {
-				HashNode* prev = node;
-
-				node = node->next;
-				/* Free the value */
-				if (free_values) free(prev->value);
-				/* Free the node */
-				free(prev);
-			}
-		}
-	}
-	free(h->buckets);
-	/* No need to free buckets_in_use, it is always allocated in one
-	 * malloc with buckets */
-#ifdef HASH_DEBUG
-	debug("Freeing Hash: %p", h);
-#endif
-	if (h->freeh) free(h);
-}
-
-#ifdef HASH_STATS
-static void stat_Hash(const Hash* h)
-{
-	uint used_buckets = 0;
-	uint max_collision = 0;
-	uint max_usage = 0;
-	uint usage[200];
-	uint i;
-
-	for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
-	for (i = 0; i < h->num_buckets; i++) {
-		uint collision = 0;
-		if (h->buckets_in_use[i]) {
-			const HashNode* node;
-
-			used_buckets++;
-			for (node = &h->buckets[i]; node != NULL; node = node->next) collision++;
-			if (collision > max_collision) max_collision = collision;
-		}
-		if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
-		usage[collision]++;
-		if (collision > 0 && usage[collision] >= max_usage) {
-			max_usage = usage[collision];
-		}
-	}
-	printf(
-		"---\n"
-		"Hash size: %d\n"
-		"Nodes used: %d\n"
-		"Non empty buckets: %d\n"
-		"Max collision: %d\n",
-		h->num_buckets, h->size, used_buckets, max_collision
-	);
-	printf("{ ");
-	for (i = 0; i <= max_collision; i++) {
-		if (usage[i] > 0) {
-			printf("%d:%d ", i, usage[i]);
-#if 0
-			if (i > 0) {
-				uint j;
-
-				for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
-			}
-			printf("\n");
-#endif
-		}
-	}
-	printf ("}\n");
-}
-#endif
-
-void clear_Hash(Hash* h, bool free_values)
-{
-	uint i;
-
-#ifdef HASH_STATS
-	if (h->size > 2000) stat_Hash(h);
-#endif
-
-	/* Iterate all buckets */
-	for (i = 0; i < h->num_buckets; i++) {
-		if (h->buckets_in_use[i]) {
-			HashNode* node;
-
-			h->buckets_in_use[i] = false;
-			/* Free the first value */
-			if (free_values) free(h->buckets[i].value);
-			node = h->buckets[i].next;
-			while (node != NULL) {
-				HashNode* prev = node;
-
-				node = node->next;
-				if (free_values) free(prev->value);
-				free(prev);
-			}
-		}
-	}
-	h->size = 0;
-}
-
-/* Finds the node that that saves this key pair. If it is not
- * found, returns NULL. If it is found, *prev is set to the
- * node before the one found, or if the node found was the first in the bucket
- * to NULL. If it is not found, *prev is set to the last HashNode in the
- * bucket, or NULL if it is empty. prev can also be NULL, in which case it is
- * not used for output.
- */
-static HashNode* Hash_FindNode(const Hash* h, uint key1, uint key2, HashNode** prev_out)
-{
-	uint hash = h->hash(key1, key2);
-	HashNode* result = NULL;
-
-#ifdef HASH_DEBUG
-	debug("Looking for %u, %u", key1, key2);
-#endif
-	/* Check if the bucket is empty */
-	if (!h->buckets_in_use[hash]) {
-		if (prev_out != NULL) *prev_out = NULL;
-		result = NULL;
-	/* Check the first node specially */
-	} else if (h->buckets[hash].key1 == key1 && h->buckets[hash].key2 == key2) {
-		/* Save the value */
-		result = h->buckets + hash;
-		if (prev_out != NULL) *prev_out = NULL;
-#ifdef HASH_DEBUG
-		debug("Found in first node: %p", result);
-#endif
-	/* Check all other nodes */
-	} else {
-		HashNode* prev = h->buckets + hash;
-		HashNode* node;
-
-		for (node = prev->next; node != NULL; node = node->next) {
-			if (node->key1 == key1 && node->key2 == key2) {
-				/* Found it */
-				result = node;
-#ifdef HASH_DEBUG
-				debug("Found in other node: %p", result);
-#endif
-				break;
-			}
-			prev = node;
-		}
-		if (prev_out != NULL) *prev_out = prev;
-	}
-#ifdef HASH_DEBUG
-	if (result == NULL) debug("Not found");
-#endif
-	return result;
-}
-
-void* Hash_Delete(Hash* h, uint key1, uint key2)
-{
-	void* result;
-	HashNode* prev; /* Used as output var for below function call */
-	HashNode* node = Hash_FindNode(h, key1, key2, &prev);
-
-	if (node == NULL) {
-		/* not found */
-		result = NULL;
-	} else if (prev == NULL) {
-		/* It is in the first node, we can't free that one, so we free
-		 * the next one instead (if there is any)*/
-		/* Save the value */
-		result = node->value;
-		if (node->next != NULL) {
-			HashNode* next = node->next;
-			/* Copy the second to the first */
-			*node = *next;
-			/* Free the second */
-#ifndef NOFREE
-			free(next);
-#endif
-		} else {
-			/* This was the last in this bucket */
-			/* Mark it as empty */
-			uint hash = h->hash(key1, key2);
-			h->buckets_in_use[hash] = false;
-		}
-	} else {
-		/* It is in another node */
-		/* Save the value */
-		result = node->value;
-		/* Link previous and next nodes */
-		prev->next = node->next;
-		/* Free the node */
-#ifndef NOFREE
-		free(node);
-#endif
-	}
-	if (result != NULL) h->size--;
-	return result;
-}
-
-
-void* Hash_Set(Hash* h, uint key1, uint key2, void* value)
-{
-	HashNode* prev;
-	HashNode* node = Hash_FindNode(h, key1, key2, &prev);
-
-	if (node != NULL) {
-		/* Found it */
-		void* result = node->value;
-
-		node->value = value;
-		return result;
-	}
-	/* It is not yet present, let's add it */
-	if (prev == NULL) {
-		/* The bucket is still empty */
-		uint hash = h->hash(key1, key2);
-		h->buckets_in_use[hash] = true;
-		node = h->buckets + hash;
-	} else {
-		/* Add it after prev */
-		node = malloc(sizeof(*node));
-		prev->next = node;
-	}
-	node->next = NULL;
-	node->key1 = key1;
-	node->key2 = key2;
-	node->value = value;
-	h->size++;
-	return NULL;
-}
-
-void* Hash_Get(const Hash* h, uint key1, uint key2)
-{
-	HashNode* node = Hash_FindNode(h, key1, key2, NULL);
-
-#ifdef HASH_DEBUG
-	debug("Found node: %p", node);
-#endif
-	return (node != NULL) ? node->value : NULL;
-}
-
-uint Hash_Size(const Hash* h)
-{
-	return h->size;
-}
new file mode 100644
--- /dev/null
+++ b/src/queue.cpp
@@ -0,0 +1,736 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "queue.h"
+
+static void Stack_Clear(Queue* q, bool free_values)
+{
+	if (free_values) {
+		uint i;
+
+		for (i = 0; i < q->data.stack.size; i++) free(q->data.stack.elements[i]);
+	}
+	q->data.stack.size = 0;
+}
+
+static void Stack_Free(Queue* q, bool free_values)
+{
+	q->clear(q, free_values);
+	free(q->data.stack.elements);
+	if (q->freeq) free(q);
+}
+
+static bool Stack_Push(Queue* q, void* item, int priority)
+{
+	if (q->data.stack.size == q->data.stack.max_size) return false;
+	q->data.stack.elements[q->data.stack.size++] = item;
+	return true;
+}
+
+static void* Stack_Pop(Queue* q)
+{
+	if (q->data.stack.size == 0) return NULL;
+	return q->data.stack.elements[--q->data.stack.size];
+}
+
+static bool Stack_Delete(Queue* q, void* item, int priority)
+{
+	return false;
+}
+
+static Queue* init_stack(Queue* q, uint max_size)
+{
+	q->push = Stack_Push;
+	q->pop = Stack_Pop;
+	q->del = Stack_Delete;
+	q->clear = Stack_Clear;
+	q->free = Stack_Free;
+	q->data.stack.max_size = max_size;
+	q->data.stack.size = 0;
+	q->data.stack.elements = malloc(max_size * sizeof(*q->data.stack.elements));
+	q->freeq = false;
+	return q;
+}
+
+Queue* new_Stack(uint max_size)
+{
+	Queue* q = malloc(sizeof(*q));
+
+	init_stack(q, max_size);
+	q->freeq = true;
+	return q;
+}
+
+/*
+ * Fifo
+ */
+
+static void Fifo_Clear(Queue* q, bool free_values)
+{
+	if (free_values) {
+		uint head = q->data.fifo.head;
+		uint tail = q->data.fifo.tail; /* cache for speed */
+
+		while (head != tail) {
+			free(q->data.fifo.elements[tail]);
+			tail = (tail + 1) % q->data.fifo.max_size;
+		}
+	}
+	q->data.fifo.head = 0;
+	q->data.fifo.tail = 0;
+}
+
+static void Fifo_Free(Queue* q, bool free_values)
+{
+	q->clear(q, free_values);
+	free(q->data.fifo.elements);
+	if (q->freeq) free(q);
+}
+
+static bool Fifo_Push(Queue* q, void* item, int priority)
+{
+	uint next = (q->data.fifo.head + 1) % q->data.fifo.max_size;
+
+	if (next == q->data.fifo.tail) return false;
+	q->data.fifo.elements[q->data.fifo.head] = item;
+
+	q->data.fifo.head = next;
+	return true;
+}
+
+static void* Fifo_Pop(Queue* q)
+{
+	void* result;
+
+	if (q->data.fifo.head == q->data.fifo.tail) return NULL;
+	result = q->data.fifo.elements[q->data.fifo.tail];
+
+	q->data.fifo.tail = (q->data.fifo.tail + 1) % q->data.fifo.max_size;
+	return result;
+}
+
+static bool Fifo_Delete(Queue* q, void* item, int priority)
+{
+	return false;
+}
+
+static Queue* init_fifo(Queue* q, uint max_size)
+{
+	q->push = Fifo_Push;
+	q->pop = Fifo_Pop;
+	q->del = Fifo_Delete;
+	q->clear = Fifo_Clear;
+	q->free = Fifo_Free;
+	q->data.fifo.max_size = max_size;
+	q->data.fifo.head = 0;
+	q->data.fifo.tail = 0;
+	q->data.fifo.elements = malloc(max_size * sizeof(*q->data.fifo.elements));
+	q->freeq = false;
+	return q;
+}
+
+Queue* new_Fifo(uint max_size)
+{
+	Queue* q = malloc(sizeof(*q));
+
+	init_fifo(q, max_size);
+	q->freeq = true;
+	return q;
+}
+
+
+/*
+ * Insertion Sorter
+ */
+
+static void InsSort_Clear(Queue* q, bool free_values)
+{
+	InsSortNode* node = q->data.inssort.first;
+	InsSortNode* prev;
+
+	while (node != NULL) {
+		if (free_values) free(node->item);
+		prev = node;
+		node = node->next;
+		free(prev);
+	}
+	q->data.inssort.first = NULL;
+}
+
+static void InsSort_Free(Queue* q, bool free_values)
+{
+	q->clear(q, free_values);
+	if (q->freeq) free(q);
+}
+
+static bool InsSort_Push(Queue* q, void* item, int priority)
+{
+	InsSortNode* newnode = malloc(sizeof(*newnode));
+
+	if (newnode == NULL) return false;
+	newnode->item = item;
+	newnode->priority = priority;
+	if (q->data.inssort.first == NULL ||
+			q->data.inssort.first->priority >= priority) {
+		newnode->next = q->data.inssort.first;
+		q->data.inssort.first = newnode;
+	} else {
+		InsSortNode* node = q->data.inssort.first;
+		while (node != NULL) {
+			if (node->next == NULL || node->next->priority >= priority) {
+				newnode->next = node->next;
+				node->next = newnode;
+				break;
+			}
+			node = node->next;
+		}
+	}
+	return true;
+}
+
+static void* InsSort_Pop(Queue* q)
+{
+	InsSortNode* node = q->data.inssort.first;
+	void* result;
+
+	if (node == NULL) return NULL;
+	result = node->item;
+	q->data.inssort.first = q->data.inssort.first->next;
+	assert(q->data.inssort.first == NULL || q->data.inssort.first->priority >= node->priority);
+	free(node);
+	return result;
+}
+
+static bool InsSort_Delete(Queue* q, void* item, int priority)
+{
+	return false;
+}
+
+void init_InsSort(Queue* q)
+{
+	q->push = InsSort_Push;
+	q->pop = InsSort_Pop;
+	q->del = InsSort_Delete;
+	q->clear = InsSort_Clear;
+	q->free = InsSort_Free;
+	q->data.inssort.first = NULL;
+	q->freeq = false;
+}
+
+Queue* new_InsSort(void)
+{
+	Queue* q = malloc(sizeof(*q));
+
+	init_InsSort(q);
+	q->freeq = true;
+	return q;
+}
+
+
+/*
+ * Binary Heap
+ * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
+ */
+
+#define BINARY_HEAP_BLOCKSIZE (1 << BINARY_HEAP_BLOCKSIZE_BITS)
+#define BINARY_HEAP_BLOCKSIZE_MASK (BINARY_HEAP_BLOCKSIZE - 1)
+
+// To make our life easy, we make the next define
+//  Because Binary Heaps works with array from 1 to n,
+//  and C with array from 0 to n-1, and we don't like typing
+//  q->data.binaryheap.elements[i - 1] every time, we use this define.
+#define BIN_HEAP_ARR(i) q->data.binaryheap.elements[((i) - 1) >> BINARY_HEAP_BLOCKSIZE_BITS][((i) - 1) & BINARY_HEAP_BLOCKSIZE_MASK]
+
+static void BinaryHeap_Clear(Queue* q, bool free_values)
+{
+	/* Free all items if needed and free all but the first blocks of memory */
+	uint i;
+	uint j;
+
+	for (i = 0; i < q->data.binaryheap.blocks; i++) {
+		if (q->data.binaryheap.elements[i] == NULL) {
+			/* No more allocated blocks */
+			break;
+		}
+		/* For every allocated block */
+		if (free_values) {
+			for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
+				/* For every element in the block */
+				if ((q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
+						(q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
+					break; /* We're past the last element */
+				}
+				free(q->data.binaryheap.elements[i][j].item);
+			}
+		}
+		if (i != 0) {
+			/* Leave the first block of memory alone */
+			free(q->data.binaryheap.elements[i]);
+			q->data.binaryheap.elements[i] = NULL;
+		}
+	}
+	q->data.binaryheap.size = 0;
+	q->data.binaryheap.blocks = 1;
+}
+
+static void BinaryHeap_Free(Queue* q, bool free_values)
+{
+	uint i;
+
+	q->clear(q, free_values);
+	for (i = 0; i < q->data.binaryheap.blocks; i++) {
+		if (q->data.binaryheap.elements[i] == NULL) break;
+		free(q->data.binaryheap.elements[i]);
+	}
+	free(q->data.binaryheap.elements);
+	if (q->freeq) free(q);
+}
+
+static bool BinaryHeap_Push(Queue* q, void* item, int priority)
+{
+#ifdef QUEUE_DEBUG
+	printf("[BinaryHeap] Pushing an element. There are %d elements left\n", q->data.binaryheap.size);
+#endif
+
+	if (q->data.binaryheap.size == q->data.binaryheap.max_size) return false;
+	assert(q->data.binaryheap.size < q->data.binaryheap.max_size);
+
+	if (q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
+		/* The currently allocated blocks are full, allocate a new one */
+		assert((q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
+		q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] = malloc(BINARY_HEAP_BLOCKSIZE * sizeof(*q->data.binaryheap.elements[0]));
+		q->data.binaryheap.blocks++;
+#ifdef QUEUE_DEBUG
+		printf("[BinaryHeap] Increasing size of elements to %d nodes\n", q->data.binaryheap.blocks *  BINARY_HEAP_BLOCKSIZE);
+#endif
+	}
+
+	// Add the item at the end of the array
+	BIN_HEAP_ARR(q->data.binaryheap.size + 1).priority = priority;
+	BIN_HEAP_ARR(q->data.binaryheap.size + 1).item = item;
+	q->data.binaryheap.size++;
+
+	// Now we are going to check where it belongs. As long as the parent is
+	// bigger, we switch with the parent
+	{
+		BinaryHeapNode temp;
+		int i;
+		int j;
+
+		i = q->data.binaryheap.size;
+		while (i > 1) {
+			// Get the parent of this object (divide by 2)
+			j = i / 2;
+			// Is the parent bigger then the current, switch them
+			if (BIN_HEAP_ARR(i).priority <= BIN_HEAP_ARR(j).priority) {
+				temp = BIN_HEAP_ARR(j);
+				BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
+				BIN_HEAP_ARR(i) = temp;
+				i = j;
+			} else {
+				// It is not, we're done!
+				break;
+			}
+		}
+	}
+
+	return true;
+}
+
+static bool BinaryHeap_Delete(Queue* q, void* item, int priority)
+{
+	uint i = 0;
+
+#ifdef QUEUE_DEBUG
+	printf("[BinaryHeap] Deleting an element. There are %d elements left\n", q->data.binaryheap.size);
+#endif
+
+	// First, we try to find the item..
+	do {
+		if (BIN_HEAP_ARR(i + 1).item == item) break;
+		i++;
+	} while (i < q->data.binaryheap.size);
+	// We did not find the item, so we return false
+	if (i == q->data.binaryheap.size) return false;
+
+	// Now we put the last item over the current item while decreasing the size of the elements
+	q->data.binaryheap.size--;
+	BIN_HEAP_ARR(i + 1) = BIN_HEAP_ARR(q->data.binaryheap.size + 1);
+
+	// Now the only thing we have to do, is resort it..
+	// On place i there is the item to be sorted.. let's start there
+	{
+		uint j;
+		BinaryHeapNode temp;
+		/* Because of the fact that Binary Heap uses array from 1 to n, we need to
+		 * increase i by 1
+		 */
+		i++;
+
+		for (;;) {
+			j = i;
+			// Check if we have 2 childs
+			if (2 * j + 1 <= q->data.binaryheap.size) {
+				// Is this child smaller than the parent?
+				if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
+				// Yes, we _need_ to use i here, not j, because we want to have the smallest child
+				//  This way we get that straight away!
+				if (BIN_HEAP_ARR(i).priority >= BIN_HEAP_ARR(2 * j + 1).priority) i = 2 * j + 1;
+			// Do we have one child?
+			} else if (2 * j <= q->data.binaryheap.size) {
+				if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
+			}
+
+			// One of our childs is smaller than we are, switch
+			if (i != j) {
+				temp = BIN_HEAP_ARR(j);
+				BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
+				BIN_HEAP_ARR(i) = temp;
+			} else {
+				// None of our childs is smaller, so we stay here.. stop :)
+				break;
+			}
+		}
+	}
+
+	return true;
+}
+
+static void* BinaryHeap_Pop(Queue* q)
+{
+	void* result;
+
+#ifdef QUEUE_DEBUG
+	printf("[BinaryHeap] Popping an element. There are %d elements left\n", q->data.binaryheap.size);
+#endif
+
+	if (q->data.binaryheap.size == 0) return NULL;
+
+	// The best item is always on top, so give that as result
+	result = BIN_HEAP_ARR(1).item;
+	// And now we should get rid of this item...
+	BinaryHeap_Delete(q, BIN_HEAP_ARR(1).item, BIN_HEAP_ARR(1).priority);
+
+	return result;
+}
+
+void init_BinaryHeap(Queue* q, uint max_size)
+{
+	assert(q != NULL);
+	q->push = BinaryHeap_Push;
+	q->pop = BinaryHeap_Pop;
+	q->del = BinaryHeap_Delete;
+	q->clear = BinaryHeap_Clear;
+	q->free = BinaryHeap_Free;
+	q->data.binaryheap.max_size = max_size;
+	q->data.binaryheap.size = 0;
+	// We malloc memory in block of BINARY_HEAP_BLOCKSIZE
+	//   It autosizes when it runs out of memory
+	q->data.binaryheap.elements = calloc((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1, sizeof(*q->data.binaryheap.elements));
+	q->data.binaryheap.elements[0] = malloc(BINARY_HEAP_BLOCKSIZE * sizeof(*q->data.binaryheap.elements[0]));
+	q->data.binaryheap.blocks = 1;
+	q->freeq = false;
+#ifdef QUEUE_DEBUG
+	printf("[BinaryHeap] Initial size of elements is %d nodes\n", BINARY_HEAP_BLOCKSIZE);
+#endif
+}
+
+Queue* new_BinaryHeap(uint max_size)
+{
+	Queue* q = malloc(sizeof(*q));
+
+	init_BinaryHeap(q, max_size);
+	q->freeq = true;
+	return q;
+}
+
+// Because we don't want anyone else to bother with our defines
+#undef BIN_HEAP_ARR
+
+/*
+ * Hash
+ */
+
+void init_Hash(Hash* h, Hash_HashProc* hash, uint num_buckets)
+{
+	/* Allocate space for the Hash, the buckets and the bucket flags */
+	uint i;
+
+	assert(h != NULL);
+#ifdef HASH_DEBUG
+	debug("Allocated hash: %p", h);
+#endif
+	h->hash = hash;
+	h->size = 0;
+	h->num_buckets = num_buckets;
+	h->buckets = malloc(num_buckets * (sizeof(*h->buckets) + sizeof(*h->buckets_in_use)));
+#ifdef HASH_DEBUG
+	debug("Buckets = %p", h->buckets);
+#endif
+	h->buckets_in_use = (bool*)(h->buckets + num_buckets);
+	h->freeh = false;
+	for (i = 0; i < num_buckets; i++) h->buckets_in_use[i] = false;
+}
+
+Hash* new_Hash(Hash_HashProc* hash, int num_buckets)
+{
+	Hash* h = malloc(sizeof(*h));
+
+	init_Hash(h, hash, num_buckets);
+	h->freeh = true;
+	return h;
+}
+
+void delete_Hash(Hash* h, bool free_values)
+{
+	uint i;
+
+	/* Iterate all buckets */
+	for (i = 0; i < h->num_buckets; i++) {
+		if (h->buckets_in_use[i]) {
+			HashNode* node;
+
+			/* Free the first value */
+			if (free_values) free(h->buckets[i].value);
+			node = h->buckets[i].next;
+			while (node != NULL) {
+				HashNode* prev = node;
+
+				node = node->next;
+				/* Free the value */
+				if (free_values) free(prev->value);
+				/* Free the node */
+				free(prev);
+			}
+		}
+	}
+	free(h->buckets);
+	/* No need to free buckets_in_use, it is always allocated in one
+	 * malloc with buckets */
+#ifdef HASH_DEBUG
+	debug("Freeing Hash: %p", h);
+#endif
+	if (h->freeh) free(h);
+}
+
+#ifdef HASH_STATS
+static void stat_Hash(const Hash* h)
+{
+	uint used_buckets = 0;
+	uint max_collision = 0;
+	uint max_usage = 0;
+	uint usage[200];
+	uint i;
+
+	for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
+	for (i = 0; i < h->num_buckets; i++) {
+		uint collision = 0;
+		if (h->buckets_in_use[i]) {
+			const HashNode* node;
+
+			used_buckets++;
+			for (node = &h->buckets[i]; node != NULL; node = node->next) collision++;
+			if (collision > max_collision) max_collision = collision;
+		}
+		if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
+		usage[collision]++;
+		if (collision > 0 && usage[collision] >= max_usage) {
+			max_usage = usage[collision];
+		}
+	}
+	printf(
+		"---\n"
+		"Hash size: %d\n"
+		"Nodes used: %d\n"
+		"Non empty buckets: %d\n"
+		"Max collision: %d\n",
+		h->num_buckets, h->size, used_buckets, max_collision
+	);
+	printf("{ ");
+	for (i = 0; i <= max_collision; i++) {
+		if (usage[i] > 0) {
+			printf("%d:%d ", i, usage[i]);
+#if 0
+			if (i > 0) {
+				uint j;
+
+				for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
+			}
+			printf("\n");
+#endif
+		}
+	}
+	printf ("}\n");
+}
+#endif
+
+void clear_Hash(Hash* h, bool free_values)
+{
+	uint i;
+
+#ifdef HASH_STATS
+	if (h->size > 2000) stat_Hash(h);
+#endif
+
+	/* Iterate all buckets */
+	for (i = 0; i < h->num_buckets; i++) {
+		if (h->buckets_in_use[i]) {
+			HashNode* node;
+
+			h->buckets_in_use[i] = false;
+			/* Free the first value */
+			if (free_values) free(h->buckets[i].value);
+			node = h->buckets[i].next;
+			while (node != NULL) {
+				HashNode* prev = node;
+
+				node = node->next;
+				if (free_values) free(prev->value);
+				free(prev);
+			}
+		}
+	}
+	h->size = 0;
+}
+
+/* Finds the node that that saves this key pair. If it is not
+ * found, returns NULL. If it is found, *prev is set to the
+ * node before the one found, or if the node found was the first in the bucket
+ * to NULL. If it is not found, *prev is set to the last HashNode in the
+ * bucket, or NULL if it is empty. prev can also be NULL, in which case it is
+ * not used for output.
+ */
+static HashNode* Hash_FindNode(const Hash* h, uint key1, uint key2, HashNode** prev_out)
+{
+	uint hash = h->hash(key1, key2);
+	HashNode* result = NULL;
+
+#ifdef HASH_DEBUG
+	debug("Looking for %u, %u", key1, key2);
+#endif
+	/* Check if the bucket is empty */
+	if (!h->buckets_in_use[hash]) {
+		if (prev_out != NULL) *prev_out = NULL;
+		result = NULL;
+	/* Check the first node specially */
+	} else if (h->buckets[hash].key1 == key1 && h->buckets[hash].key2 == key2) {
+		/* Save the value */
+		result = h->buckets + hash;
+		if (prev_out != NULL) *prev_out = NULL;
+#ifdef HASH_DEBUG
+		debug("Found in first node: %p", result);
+#endif
+	/* Check all other nodes */
+	} else {
+		HashNode* prev = h->buckets + hash;
+		HashNode* node;
+
+		for (node = prev->next; node != NULL; node = node->next) {
+			if (node->key1 == key1 && node->key2 == key2) {
+				/* Found it */
+				result = node;
+#ifdef HASH_DEBUG
+				debug("Found in other node: %p", result);
+#endif
+				break;
+			}
+			prev = node;
+		}
+		if (prev_out != NULL) *prev_out = prev;
+	}
+#ifdef HASH_DEBUG
+	if (result == NULL) debug("Not found");
+#endif
+	return result;
+}
+
+void* Hash_Delete(Hash* h, uint key1, uint key2)
+{
+	void* result;
+	HashNode* prev; /* Used as output var for below function call */
+	HashNode* node = Hash_FindNode(h, key1, key2, &prev);
+
+	if (node == NULL) {
+		/* not found */
+		result = NULL;
+	} else if (prev == NULL) {
+		/* It is in the first node, we can't free that one, so we free
+		 * the next one instead (if there is any)*/
+		/* Save the value */
+		result = node->value;
+		if (node->next != NULL) {
+			HashNode* next = node->next;
+			/* Copy the second to the first */
+			*node = *next;
+			/* Free the second */
+#ifndef NOFREE
+			free(next);
+#endif
+		} else {
+			/* This was the last in this bucket */
+			/* Mark it as empty */
+			uint hash = h->hash(key1, key2);
+			h->buckets_in_use[hash] = false;
+		}
+	} else {
+		/* It is in another node */
+		/* Save the value */
+		result = node->value;
+		/* Link previous and next nodes */
+		prev->next = node->next;
+		/* Free the node */
+#ifndef NOFREE
+		free(node);
+#endif
+	}
+	if (result != NULL) h->size--;
+	return result;
+}
+
+
+void* Hash_Set(Hash* h, uint key1, uint key2, void* value)
+{
+	HashNode* prev;
+	HashNode* node = Hash_FindNode(h, key1, key2, &prev);
+
+	if (node != NULL) {
+		/* Found it */
+		void* result = node->value;
+
+		node->value = value;
+		return result;
+	}
+	/* It is not yet present, let's add it */
+	if (prev == NULL) {
+		/* The bucket is still empty */
+		uint hash = h->hash(key1, key2);
+		h->buckets_in_use[hash] = true;
+		node = h->buckets + hash;
+	} else {
+		/* Add it after prev */
+		node = malloc(sizeof(*node));
+		prev->next = node;
+	}
+	node->next = NULL;
+	node->key1 = key1;
+	node->key2 = key2;
+	node->value = value;
+	h->size++;
+	return NULL;
+}
+
+void* Hash_Get(const Hash* h, uint key1, uint key2)
+{
+	HashNode* node = Hash_FindNode(h, key1, key2, NULL);
+
+#ifdef HASH_DEBUG
+	debug("Found node: %p", node);
+#endif
+	return (node != NULL) ? node->value : NULL;
+}
+
+uint Hash_Size(const Hash* h)
+{
+	return h->size;
+}
deleted file mode 100644
--- a/src/rail.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "rail.h"
-#include "station_map.h"
-#include "tunnel_map.h"
-
-/* XXX: Below 3 tables store duplicate data. Maybe remove some? */
-/* Maps a trackdir to the bit that stores its status in the map arrays, in the
- * direction along with the trackdir */
-const byte _signal_along_trackdir[] = {
-	0x80, 0x80, 0x80, 0x20, 0x40, 0x10, 0, 0,
-	0x40, 0x40, 0x40, 0x10, 0x80, 0x20
-};
-
-/* Maps a trackdir to the bit that stores its status in the map arrays, in the
- * direction against the trackdir */
-const byte _signal_against_trackdir[] = {
-	0x40, 0x40, 0x40, 0x10, 0x80, 0x20, 0, 0,
-	0x80, 0x80, 0x80, 0x20, 0x40, 0x10
-};
-
-/* Maps a Track to the bits that store the status of the two signals that can
- * be present on the given track */
-const byte _signal_on_track[] = {
-	0xC0, 0xC0, 0xC0, 0x30, 0xC0, 0x30
-};
-
-/* Maps a diagonal direction to the all trackdirs that are connected to any
- * track entering in this direction (including those making 90 degree turns)
- */
-const TrackdirBits _exitdir_reaches_trackdirs[] = {
-	TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N,  /* DIAGDIR_NE */
-	TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_LEFT_S  | TRACKDIR_BIT_UPPER_E, /* DIAGDIR_SE */
-	TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, /* DIAGDIR_SW */
-	TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W  /* DIAGDIR_NW */
-};
-
-const Trackdir _next_trackdir[] = {
-	TRACKDIR_X_NE,  TRACKDIR_Y_SE,  TRACKDIR_LOWER_E, TRACKDIR_UPPER_E, TRACKDIR_RIGHT_S, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR,
-	TRACKDIR_X_SW,  TRACKDIR_Y_NW,  TRACKDIR_LOWER_W, TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N
-};
-
-/* Maps a trackdir to all trackdirs that make 90 deg turns with it. */
-const TrackdirBits _track_crosses_trackdirs[] = {
-	TRACKDIR_BIT_Y_SE     | TRACKDIR_BIT_Y_NW,                                                   /* TRACK_X     */
-	TRACKDIR_BIT_X_NE     | TRACKDIR_BIT_X_SW,                                                   /* TRACK_Y     */
-	TRACKDIR_BIT_RIGHT_N  | TRACKDIR_BIT_RIGHT_S  | TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LEFT_S,  /* TRACK_UPPER */
-	TRACKDIR_BIT_RIGHT_N  | TRACKDIR_BIT_RIGHT_S  | TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LEFT_S,  /* TRACK_LOWER */
-	TRACKDIR_BIT_UPPER_W  | TRACKDIR_BIT_UPPER_E  | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E, /* TRACK_LEFT  */
-	TRACKDIR_BIT_UPPER_W  | TRACKDIR_BIT_UPPER_E  | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E  /* TRACK_RIGHT */
-};
-
-/* Maps a track to all tracks that make 90 deg turns with it. */
-const TrackBits _track_crosses_tracks[] = {
-	TRACK_BIT_Y,    /* TRACK_X     */
-	TRACK_BIT_X,    /* TRACK_Y     */
-	TRACK_BIT_VERT, /* TRACK_UPPER */
-	TRACK_BIT_VERT, /* TRACK_LOWER */
-	TRACK_BIT_HORZ, /* TRACK_LEFT  */
-	TRACK_BIT_HORZ  /* TRACK_RIGHT */
-};
-
-/* Maps a trackdir to the (4-way) direction the tile is exited when following
- * that trackdir */
-const DiagDirection _trackdir_to_exitdir[] = {
-	DIAGDIR_NE,DIAGDIR_SE,DIAGDIR_NE,DIAGDIR_SE,DIAGDIR_SW,DIAGDIR_SE, DIAGDIR_NE,DIAGDIR_NE,
-	DIAGDIR_SW,DIAGDIR_NW,DIAGDIR_NW,DIAGDIR_SW,DIAGDIR_NW,DIAGDIR_NE,
-};
-
-const Trackdir _track_exitdir_to_trackdir[][DIAGDIR_END] = {
-	{TRACKDIR_X_NE,     INVALID_TRACKDIR,  TRACKDIR_X_SW,     INVALID_TRACKDIR},
-	{INVALID_TRACKDIR,  TRACKDIR_Y_SE,     INVALID_TRACKDIR,  TRACKDIR_Y_NW},
-	{TRACKDIR_UPPER_E,  INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_UPPER_W},
-	{INVALID_TRACKDIR,  TRACKDIR_LOWER_E,  TRACKDIR_LOWER_W,  INVALID_TRACKDIR},
-	{INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_LEFT_S,   TRACKDIR_LEFT_N},
-	{TRACKDIR_RIGHT_N,  TRACKDIR_RIGHT_S,  INVALID_TRACKDIR,  INVALID_TRACKDIR}
-};
-
-const Trackdir _track_enterdir_to_trackdir[][DIAGDIR_END] = { // TODO: replace magic with enums
-	{TRACKDIR_X_NE,     INVALID_TRACKDIR,  TRACKDIR_X_SW,     INVALID_TRACKDIR},
-	{INVALID_TRACKDIR,  TRACKDIR_Y_SE,     INVALID_TRACKDIR,  TRACKDIR_Y_NW},
-	{INVALID_TRACKDIR,  TRACKDIR_UPPER_E,  TRACKDIR_UPPER_W,  INVALID_TRACKDIR},
-	{TRACKDIR_LOWER_E,  INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_LOWER_W},
-	{TRACKDIR_LEFT_N,   TRACKDIR_LEFT_S,   INVALID_TRACKDIR,  INVALID_TRACKDIR},
-	{INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_RIGHT_S,  TRACKDIR_RIGHT_N}
-};
-
-const Trackdir _track_direction_to_trackdir[][DIR_END] = {
-	{INVALID_TRACKDIR, TRACKDIR_X_NE,     INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_X_SW,     INVALID_TRACKDIR, INVALID_TRACKDIR},
-	{INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_Y_SE,     INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_Y_NW},
-	{INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_UPPER_E, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_UPPER_W, INVALID_TRACKDIR},
-	{INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LOWER_E, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LOWER_W, INVALID_TRACKDIR},
-	{TRACKDIR_LEFT_N,  INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LEFT_S,  INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR},
-	{TRACKDIR_RIGHT_N, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_RIGHT_S, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR}
-};
-
-const Trackdir _dir_to_diag_trackdir[] = {
-	TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW,
-};
-
-
-RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
-{
-	switch (GetTileType(tile)) {
-		case MP_RAILWAY:
-			return GetRailType(tile);
-
-		case MP_STREET:
-			/* rail/road crossing */
-			if (IsLevelCrossing(tile)) return GetRailTypeCrossing(tile);
-			break;
-
-		case MP_STATION:
-			if (IsRailwayStationTile(tile)) return GetRailType(tile);
-			break;
-
-		case MP_TUNNELBRIDGE:
-			if (IsTunnel(tile)) {
-				if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
-			} else {
-				if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
-			}
-			break;
-
-		default:
-			break;
-	}
-	return INVALID_RAILTYPE;
-}
new file mode 100644
--- /dev/null
+++ b/src/rail.cpp
@@ -0,0 +1,132 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "rail.h"
+#include "station_map.h"
+#include "tunnel_map.h"
+
+/* XXX: Below 3 tables store duplicate data. Maybe remove some? */
+/* Maps a trackdir to the bit that stores its status in the map arrays, in the
+ * direction along with the trackdir */
+const byte _signal_along_trackdir[] = {
+	0x80, 0x80, 0x80, 0x20, 0x40, 0x10, 0, 0,
+	0x40, 0x40, 0x40, 0x10, 0x80, 0x20
+};
+
+/* Maps a trackdir to the bit that stores its status in the map arrays, in the
+ * direction against the trackdir */
+const byte _signal_against_trackdir[] = {
+	0x40, 0x40, 0x40, 0x10, 0x80, 0x20, 0, 0,
+	0x80, 0x80, 0x80, 0x20, 0x40, 0x10
+};
+
+/* Maps a Track to the bits that store the status of the two signals that can
+ * be present on the given track */
+const byte _signal_on_track[] = {
+	0xC0, 0xC0, 0xC0, 0x30, 0xC0, 0x30
+};
+
+/* Maps a diagonal direction to the all trackdirs that are connected to any
+ * track entering in this direction (including those making 90 degree turns)
+ */
+const TrackdirBits _exitdir_reaches_trackdirs[] = {
+	TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N,  /* DIAGDIR_NE */
+	TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_LEFT_S  | TRACKDIR_BIT_UPPER_E, /* DIAGDIR_SE */
+	TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, /* DIAGDIR_SW */
+	TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W  /* DIAGDIR_NW */
+};
+
+const Trackdir _next_trackdir[] = {
+	TRACKDIR_X_NE,  TRACKDIR_Y_SE,  TRACKDIR_LOWER_E, TRACKDIR_UPPER_E, TRACKDIR_RIGHT_S, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR,
+	TRACKDIR_X_SW,  TRACKDIR_Y_NW,  TRACKDIR_LOWER_W, TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N
+};
+
+/* Maps a trackdir to all trackdirs that make 90 deg turns with it. */
+const TrackdirBits _track_crosses_trackdirs[] = {
+	TRACKDIR_BIT_Y_SE     | TRACKDIR_BIT_Y_NW,                                                   /* TRACK_X     */
+	TRACKDIR_BIT_X_NE     | TRACKDIR_BIT_X_SW,                                                   /* TRACK_Y     */
+	TRACKDIR_BIT_RIGHT_N  | TRACKDIR_BIT_RIGHT_S  | TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LEFT_S,  /* TRACK_UPPER */
+	TRACKDIR_BIT_RIGHT_N  | TRACKDIR_BIT_RIGHT_S  | TRACKDIR_BIT_LEFT_N  | TRACKDIR_BIT_LEFT_S,  /* TRACK_LOWER */
+	TRACKDIR_BIT_UPPER_W  | TRACKDIR_BIT_UPPER_E  | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E, /* TRACK_LEFT  */
+	TRACKDIR_BIT_UPPER_W  | TRACKDIR_BIT_UPPER_E  | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E  /* TRACK_RIGHT */
+};
+
+/* Maps a track to all tracks that make 90 deg turns with it. */
+const TrackBits _track_crosses_tracks[] = {
+	TRACK_BIT_Y,    /* TRACK_X     */
+	TRACK_BIT_X,    /* TRACK_Y     */
+	TRACK_BIT_VERT, /* TRACK_UPPER */
+	TRACK_BIT_VERT, /* TRACK_LOWER */
+	TRACK_BIT_HORZ, /* TRACK_LEFT  */
+	TRACK_BIT_HORZ  /* TRACK_RIGHT */
+};
+
+/* Maps a trackdir to the (4-way) direction the tile is exited when following
+ * that trackdir */
+const DiagDirection _trackdir_to_exitdir[] = {
+	DIAGDIR_NE,DIAGDIR_SE,DIAGDIR_NE,DIAGDIR_SE,DIAGDIR_SW,DIAGDIR_SE, DIAGDIR_NE,DIAGDIR_NE,
+	DIAGDIR_SW,DIAGDIR_NW,DIAGDIR_NW,DIAGDIR_SW,DIAGDIR_NW,DIAGDIR_NE,
+};
+
+const Trackdir _track_exitdir_to_trackdir[][DIAGDIR_END] = {
+	{TRACKDIR_X_NE,     INVALID_TRACKDIR,  TRACKDIR_X_SW,     INVALID_TRACKDIR},
+	{INVALID_TRACKDIR,  TRACKDIR_Y_SE,     INVALID_TRACKDIR,  TRACKDIR_Y_NW},
+	{TRACKDIR_UPPER_E,  INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_UPPER_W},
+	{INVALID_TRACKDIR,  TRACKDIR_LOWER_E,  TRACKDIR_LOWER_W,  INVALID_TRACKDIR},
+	{INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_LEFT_S,   TRACKDIR_LEFT_N},
+	{TRACKDIR_RIGHT_N,  TRACKDIR_RIGHT_S,  INVALID_TRACKDIR,  INVALID_TRACKDIR}
+};
+
+const Trackdir _track_enterdir_to_trackdir[][DIAGDIR_END] = { // TODO: replace magic with enums
+	{TRACKDIR_X_NE,     INVALID_TRACKDIR,  TRACKDIR_X_SW,     INVALID_TRACKDIR},
+	{INVALID_TRACKDIR,  TRACKDIR_Y_SE,     INVALID_TRACKDIR,  TRACKDIR_Y_NW},
+	{INVALID_TRACKDIR,  TRACKDIR_UPPER_E,  TRACKDIR_UPPER_W,  INVALID_TRACKDIR},
+	{TRACKDIR_LOWER_E,  INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_LOWER_W},
+	{TRACKDIR_LEFT_N,   TRACKDIR_LEFT_S,   INVALID_TRACKDIR,  INVALID_TRACKDIR},
+	{INVALID_TRACKDIR,  INVALID_TRACKDIR,  TRACKDIR_RIGHT_S,  TRACKDIR_RIGHT_N}
+};
+
+const Trackdir _track_direction_to_trackdir[][DIR_END] = {
+	{INVALID_TRACKDIR, TRACKDIR_X_NE,     INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_X_SW,     INVALID_TRACKDIR, INVALID_TRACKDIR},
+	{INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_Y_SE,     INVALID_TRACKDIR, INVALID_TRACKDIR,  INVALID_TRACKDIR, TRACKDIR_Y_NW},
+	{INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_UPPER_E, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_UPPER_W, INVALID_TRACKDIR},
+	{INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LOWER_E, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LOWER_W, INVALID_TRACKDIR},
+	{TRACKDIR_LEFT_N,  INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_LEFT_S,  INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR},
+	{TRACKDIR_RIGHT_N, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR,  TRACKDIR_RIGHT_S, INVALID_TRACKDIR,  INVALID_TRACKDIR, INVALID_TRACKDIR}
+};
+
+const Trackdir _dir_to_diag_trackdir[] = {
+	TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW,
+};
+
+
+RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
+{
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			return GetRailType(tile);
+
+		case MP_STREET:
+			/* rail/road crossing */
+			if (IsLevelCrossing(tile)) return GetRailTypeCrossing(tile);
+			break;
+
+		case MP_STATION:
+			if (IsRailwayStationTile(tile)) return GetRailType(tile);
+			break;
+
+		case MP_TUNNELBRIDGE:
+			if (IsTunnel(tile)) {
+				if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
+			} else {
+				if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
+			}
+			break;
+
+		default:
+			break;
+	}
+	return INVALID_RAILTYPE;
+}
deleted file mode 100644
--- a/src/rail_cmd.c
+++ /dev/null
@@ -1,1985 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "debug.h"
-#include "functions.h"
-#include "rail_map.h"
-#include "road_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "town_map.h"
-#include "tunnel_map.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
-#include "pathfind.h"
-#include "engine.h"
-#include "town.h"
-#include "sound.h"
-#include "station.h"
-#include "sprite.h"
-#include "depot.h"
-#include "waypoint.h"
-#include "window.h"
-#include "rail.h"
-#include "railtypes.h" // include table for railtypes
-#include "newgrf.h"
-#include "yapf/yapf.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_station.h"
-#include "train.h"
-
-const byte _track_sloped_sprites[14] = {
-	14, 15, 22, 13,
-	 0, 21, 17, 12,
-	23,  0, 18, 20,
-	19, 16
-};
-
-
-/*         4
- *     ---------
- *    |\       /|
- *    | \    1/ |
- *    |  \   /  |
- *    |   \ /   |
- *  16|    \    |32
- *    |   / \2  |
- *    |  /   \  |
- *    | /     \ |
- *    |/       \|
- *     ---------
- *         8
- */
-
-
-
-/* MAP2 byte:    abcd???? => Signal On? Same coding as map3lo
- * MAP3LO byte:  abcd???? => Signal Exists?
- *               a and b are for diagonals, upper and left,
- *               one for each direction. (ie a == NE->SW, b ==
- *               SW->NE, or v.v., I don't know. b and c are
- *               similar for lower and right.
- * MAP2 byte:    ????abcd => Type of ground.
- * MAP3LO byte:  ????abcd => Type of rail.
- * MAP5:         00abcdef => rail
- *               01abcdef => rail w/ signals
- *               10uuuuuu => unused
- *               11uuuudd => rail depot
- */
-
-static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
-{
-	TrackBits current; /* The current track layout */
-	TrackBits future; /* The track layout we want to build */
-	_error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION;
-
-	if (!IsPlainRailTile(tile)) return false;
-
-	/* So, we have a tile with tracks on it (and possibly signals). Let's see
-	 * what tracks first */
-	current = GetTrackBits(tile);
-	future = current | to_build;
-
-	/* Are we really building something new? */
-	if (current == future) {
-		/* Nothing new is being built */
-		_error_message = STR_1007_ALREADY_BUILT;
-		return false;
-	}
-
-	/* Let's see if we may build this */
-	if (flags & DC_NO_RAIL_OVERLAP || HasSignals(tile)) {
-		/* If we are not allowed to overlap (flag is on for ai players or we have
-		 * signals on the tile), check that */
-		return future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT;
-	} else {
-		/* Normally, we may overlap and any combination is valid */
-		return true;
-	}
-}
-
-
-static const TrackBits _valid_tileh_slopes[][15] = {
-
-// set of normal ones
-{
-	TRACK_BIT_ALL,
-	TRACK_BIT_RIGHT,
-	TRACK_BIT_UPPER,
-	TRACK_BIT_X,
-
-	TRACK_BIT_LEFT,
-	0,
-	TRACK_BIT_Y,
-	TRACK_BIT_LOWER,
-
-	TRACK_BIT_LOWER,
-	TRACK_BIT_Y,
-	0,
-	TRACK_BIT_LEFT,
-
-	TRACK_BIT_X,
-	TRACK_BIT_UPPER,
-	TRACK_BIT_RIGHT,
-},
-
-// allowed rail for an evenly raised platform
-{
-	0,
-	TRACK_BIT_LEFT,
-	TRACK_BIT_LOWER,
-	TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
-
-	TRACK_BIT_RIGHT,
-	TRACK_BIT_ALL,
-	TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
-	TRACK_BIT_ALL,
-
-	TRACK_BIT_UPPER,
-	TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
-	TRACK_BIT_ALL,
-	TRACK_BIT_ALL,
-
-	TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
-	TRACK_BIT_ALL,
-	TRACK_BIT_ALL
-}
-};
-
-uint GetRailFoundation(Slope tileh, TrackBits bits)
-{
-	uint i;
-
-	if (!IsSteepSlope(tileh)) {
-		if ((~_valid_tileh_slopes[0][tileh] & bits) == 0) return 0;
-		if ((~_valid_tileh_slopes[1][tileh] & bits) == 0) return tileh;
-	}
-
-	switch (bits) {
-		default: NOT_REACHED();
-		case TRACK_BIT_X: i = 0; break;
-		case TRACK_BIT_Y: i = 1; break;
-		case TRACK_BIT_LEFT:  return 15 + 8 + (tileh == SLOPE_STEEP_W ? 4 : 0);
-		case TRACK_BIT_LOWER: return 15 + 8 + (tileh == SLOPE_STEEP_S ? 5 : 1);
-		case TRACK_BIT_RIGHT: return 15 + 8 + (tileh == SLOPE_STEEP_E ? 6 : 2);
-		case TRACK_BIT_UPPER: return 15 + 8 + (tileh == SLOPE_STEEP_N ? 7 : 3);
-	}
-	switch (tileh) {
-		case SLOPE_W:
-		case SLOPE_STEEP_W: i += 0; break;
-		case SLOPE_S:
-		case SLOPE_STEEP_S: i += 2; break;
-		case SLOPE_E:
-		case SLOPE_STEEP_E: i += 4; break;
-		case SLOPE_N:
-		case SLOPE_STEEP_N: i += 6; break;
-		default: return 0;
-	}
-	return i + 15;
-}
-
-
-static uint32 CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
-{
-	if (IsSteepSlope(tileh)) {
-		if (existing == 0) {
-			TrackBits valid = TRACK_BIT_CROSS | (HASBIT(1 << SLOPE_STEEP_W | 1 << SLOPE_STEEP_E, tileh) ? TRACK_BIT_VERT : TRACK_BIT_HORZ);
-			if (valid & rail_bits) return _price.terraform;
-		}
-	} else {
-		rail_bits |= existing;
-
-		// don't allow building on the lower side of a coast
-		if (IsTileType(tile, MP_WATER) &&
-				~_valid_tileh_slopes[1][tileh] & rail_bits) {
-			return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
-		}
-
-		// no special foundation
-		if ((~_valid_tileh_slopes[0][tileh] & rail_bits) == 0)
-			return 0;
-
-		if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up
-					(rail_bits == TRACK_BIT_X || rail_bits == TRACK_BIT_Y) &&
-					(tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)
-				)) { // partly up
-			if (existing != 0) {
-				return 0;
-			} else if (!_patches.build_on_slopes || _is_old_ai_player) {
-				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-			} else {
-				return _price.terraform;
-			}
-		}
-	}
-	return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-}
-
-/* Validate functions for rail building */
-static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
-
-/** Build a single piece of rail
- * @param tile tile  to build on
- * @param p1 railtype of being built piece (normal, mono, maglev)
- * @param p2 rail track to build
- */
-int32 CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Slope tileh;
-	RailType railtype;
-	Track track;
-	TrackBits trackbit;
-	int32 cost = 0;
-	int32 ret;
-
-	if (!ValParamRailtype(p1) || !ValParamTrackOrientation(p2)) return CMD_ERROR;
-	railtype = (RailType)p1;
-	track = (Track)p2;
-
-	tileh = GetTileSlope(tile, NULL);
-	trackbit = TrackToTrackBits(track);
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	switch (GetTileType(tile)) {
-		case MP_RAILWAY:
-			if (!CheckTrackCombination(tile, trackbit, flags) ||
-					!EnsureNoVehicle(tile)) {
-				return CMD_ERROR;
-			}
-			if (!IsTileOwner(tile, _current_player) ||
-					!IsCompatibleRail(GetRailType(tile), railtype)) {
-				// Get detailed error message
-				return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			}
-
-			ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-
-			/* If the rail types don't match, try to convert only if engines of
-			 * the present rail type are powered on the new rail type. */
-			if (GetRailType(tile) != railtype && HasPowerOnRail(GetRailType(tile), railtype)) {
-				ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
-				if (CmdFailed(ret)) return ret;
-				cost += ret;
-			}
-
-			if (flags & DC_EXEC) {
-				SetRailGroundType(tile, RAIL_GROUND_BARREN);
-				SetTrackBits(tile, GetTrackBits(tile) | trackbit);
-			}
-			break;
-
-		case MP_STREET:
-#define M(x) (1 << (x))
-			/* Level crossings may only be built on these slopes */
-			if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
-				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-			}
-#undef M
-
-			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-			if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
-				if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
-
-				if ((track == TRACK_X && GetRoadBits(tile) == ROAD_Y) ||
-						(track == TRACK_Y && GetRoadBits(tile) == ROAD_X)) {
-					if (flags & DC_EXEC) {
-						MakeRoadCrossing(tile, GetTileOwner(tile), _current_player, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, GetTownIndex(tile));
-					}
-					break;
-				}
-			}
-
-			if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
-				return_cmd_error(STR_1007_ALREADY_BUILT);
-			}
-			/* FALLTHROUGH */
-
-		default:
-			ret = CheckRailSlope(tileh, trackbit, 0, tile);
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-
-			ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-
-			if (flags & DC_EXEC) MakeRailNormal(tile, _current_player, trackbit, railtype);
-			break;
-	}
-
-	if (flags & DC_EXEC) {
-		MarkTileDirtyByTile(tile);
-		SetSignalsOnBothDir(tile, track);
-		YapfNotifyTrackLayoutChange(tile, track);
-	}
-
-	return cost + _price.build_rail;
-}
-
-/** Remove a single piece of track
- * @param tile tile to remove track from
- * @param p1 unused
- * @param p2 rail orientation
- */
-int32 CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Track track = (Track)p2;
-	TrackBits trackbit;
-	int32 cost = _price.remove_rail;
-	bool crossing = false;
-
-	if (!ValParamTrackOrientation(p2)) return CMD_ERROR;
-	trackbit = TrackToTrackBits(track);
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	switch (GetTileType(tile)) {
-		case MP_STREET: {
-			if (!IsLevelCrossing(tile) ||
-					GetCrossingRailBits(tile) != trackbit ||
-					(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
-					!EnsureNoVehicle(tile)) {
-				return CMD_ERROR;
-			}
-
-			if (flags & DC_EXEC) {
-				MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile));
-			}
-			break;
-		}
-
-		case MP_RAILWAY: {
-			TrackBits present;
-
-			if (!IsPlainRailTile(tile) ||
-					(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
-					!EnsureNoVehicle(tile)) {
-				return CMD_ERROR;
-			}
-
-			present = GetTrackBits(tile);
-			if ((present & trackbit) == 0) return CMD_ERROR;
-			if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
-
-			/* Charge extra to remove signals on the track, if they are there */
-			if (HasSignalOnTrack(tile, track))
-				cost += DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS);
-
-			if (flags & DC_EXEC) {
-				present ^= trackbit;
-				if (present == 0) {
-					DoClearSquare(tile);
-				} else {
-					SetTrackBits(tile, present);
-				}
-			}
-			break;
-		}
-
-		default: return CMD_ERROR;
-	}
-
-	if (flags & DC_EXEC) {
-		MarkTileDirtyByTile(tile);
-		if (crossing) {
-			/* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we
-			 * are removing one of these pieces, we'll need to update signals for
-			 * both directions explicitly, as after the track is removed it won't
-			 * 'connect' with the other piece. */
-			SetSignalsOnBothDir(tile, TRACK_X);
-			SetSignalsOnBothDir(tile, TRACK_Y);
-			YapfNotifyTrackLayoutChange(tile, TRACK_X);
-			YapfNotifyTrackLayoutChange(tile, TRACK_Y);
-		} else {
-			SetSignalsOnBothDir(tile, track);
-			YapfNotifyTrackLayoutChange(tile, track);
-		}
-	}
-
-	return cost;
-}
-
-
-static const TileIndexDiffC _trackdelta[] = {
-	{ -1,  0 }, {  0,  1 }, { -1,  0 }, {  0,  1 }, {  1,  0 }, {  0,  1 },
-	{  0,  0 },
-	{  0,  0 },
-	{  1,  0 }, {  0, -1 }, {  0, -1 }, {  1,  0 }, {  0, -1 }, { -1,  0 },
-	{  0,  0 },
-	{  0,  0 }
-};
-
-
-static int32 ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
-{
-	int x = TileX(start);
-	int y = TileY(start);
-	int ex = TileX(end);
-	int ey = TileY(end);
-	int dx, dy, trdx, trdy;
-
-	if (!ValParamTrackOrientation(*trackdir)) return CMD_ERROR;
-
-	// calculate delta x,y from start to end tile
-	dx = ex - x;
-	dy = ey - y;
-
-	// calculate delta x,y for the first direction
-	trdx = _trackdelta[*trackdir].x;
-	trdy = _trackdelta[*trackdir].y;
-
-	if (!IsDiagonalTrackdir(*trackdir)) {
-		trdx += _trackdelta[*trackdir ^ 1].x;
-		trdy += _trackdelta[*trackdir ^ 1].y;
-	}
-
-	// validate the direction
-	while (
-		(trdx <= 0 && dx > 0) ||
-		(trdx >= 0 && dx < 0) ||
-		(trdy <= 0 && dy > 0) ||
-		(trdy >= 0 && dy < 0)
-	) {
-		if (!HASBIT(*trackdir, 3)) { // first direction is invalid, try the other
-			SETBIT(*trackdir, 3); // reverse the direction
-			trdx = -trdx;
-			trdy = -trdy;
-		} else { // other direction is invalid too, invalid drag
-			return CMD_ERROR;
-		}
-	}
-
-	// (for diagonal tracks, this is already made sure of by above test), but:
-	// for non-diagonal tracks, check if the start and end tile are on 1 line
-	if (!IsDiagonalTrackdir(*trackdir)) {
-		trdx = _trackdelta[*trackdir].x;
-		trdy = _trackdelta[*trackdir].y;
-		if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
-			return CMD_ERROR;
-	}
-
-	return 0;
-}
-
-/** Build a stretch of railroad tracks.
- * @param tile start tile of drag
- * @param p1 end tile of drag
- * @param p2 various bitstuffed elements
- * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev)
- * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum)
- * - p2 = (bit 7)   - 0 = build, 1 = remove tracks
- */
-static int32 CmdRailTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 ret, total_cost = 0;
-	Track track = (Track)GB(p2, 4, 3);
-	Trackdir trackdir;
-	byte mode = HASBIT(p2, 7);
-	RailType railtype = (RailType)GB(p2, 0, 4);
-	TileIndex end_tile;
-
-	if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
-	if (p1 >= MapSize()) return CMD_ERROR;
-	end_tile = p1;
-	trackdir = TrackToTrackdir(track);
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
-
-	if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
-
-	for (;;) {
-		ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL);
-
-		if (CmdFailed(ret)) {
-			if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0)) break;
-			_error_message = INVALID_STRING_ID;
-		} else {
-			total_cost += ret;
-		}
-
-		if (tile == end_tile) break;
-
-		tile += ToTileIndexDiff(_trackdelta[trackdir]);
-
-		// toggle railbit for the non-diagonal tracks
-		if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1;
-	}
-
-	return (total_cost == 0) ? CMD_ERROR : total_cost;
-}
-
-/** Build rail on a stretch of track.
- * Stub for the unified rail builder/remover
- * @see CmdRailTrackHelper
- */
-int32 CmdBuildRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	return CmdRailTrackHelper(tile, flags, p1, CLRBIT(p2, 7));
-}
-
-/** Build rail on a stretch of track.
- * Stub for the unified rail builder/remover
- * @see CmdRailTrackHelper
- */
-int32 CmdRemoveRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	return CmdRailTrackHelper(tile, flags, p1, SETBIT(p2, 7));
-}
-
-/** Build a train depot
- * @param tile position of the train depot
- * @param p1 rail type
- * @param p2 entrance direction (DiagDirection)
- *
- * @todo When checking for the tile slope,
- * distingush between "Flat land required" and "land sloped in wrong direction"
- */
-int32 CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Depot *d;
-	int32 cost, ret;
-	Slope tileh;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-	/* check railtype and valid direction for depot (0 through 3), 4 in total */
-	if (!ValParamRailtype(p1) || p2 > 3) return CMD_ERROR;
-
-	tileh = GetTileSlope(tile, NULL);
-
-	/* Prohibit construction if
-	 * The tile is non-flat AND
-	 * 1) The AI is "old-school"
-	 * 2) build-on-slopes is disabled
-	 * 3) the tile is steep i.e. spans two height levels
-	 * 4) the exit points in the wrong direction
-	 */
-
-	if (tileh != SLOPE_FLAT && (
-				_is_old_ai_player ||
-				!_patches.build_on_slopes ||
-				IsSteepSlope(tileh) ||
-				!CanBuildDepotByTileh(p2, tileh)
-			)) {
-		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-	}
-
-	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-	cost = ret;
-
-	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-	d = AllocateDepot();
-	if (d == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		MakeRailDepot(tile, _current_player, p2, p1);
-		MarkTileDirtyByTile(tile);
-
-		d->xy = tile;
-		d->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
-
-		UpdateSignalsOnSegment(tile, p2);
-		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(p2)));
-	}
-
-	return cost + _price.build_train_depot;
-}
-
-/** Build signals, alternate between double/single, signal/semaphore,
- * pre/exit/combo-signals, and what-else not
- * @param tile tile where to build the signals
- * @param p1 various bitstuffed elements
- * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum)
- * - p1 = (bit 3)   - choose semaphores/signals or cycle normal/pre/exit/combo depending on context
- * @param p2 used for CmdBuildManySignals() to copy direction of first signal
- * TODO: p2 should be replaced by two bits for "along" and "against" the track.
- */
-int32 CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	SignalVariant sigvar;
-	bool pre_signal;
-	Track track = (Track)(p1 & 0x7);
-	int32 cost;
-
-	// Same bit, used in different contexts
-	sigvar = HASBIT(p1, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC;
-	pre_signal = HASBIT(p1, 3);
-
-	if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicle(tile))
-		return CMD_ERROR;
-
-	/* Protect against invalid signal copying */
-	if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
-
-	/* You can only build signals on plain rail tiles, and the selected track must exist */
-	if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) return CMD_ERROR;
-
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
-
-	{
-		/* See if this is a valid track combination for signals, (ie, no overlap) */
-		TrackBits trackbits = GetTrackBits(tile);
-		if (KILL_FIRST_BIT(trackbits) != 0 && /* More than one track present */
-				trackbits != TRACK_BIT_HORZ &&
-				trackbits != TRACK_BIT_VERT) {
-			return CMD_ERROR;
-		}
-	}
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!HasSignalOnTrack(tile, track)) {
-		// build new signals
-		cost = _price.build_signals;
-	} else {
-		if (p2 != 0 && sigvar != GetSignalVariant(tile)) {
-			// convert signals <-> semaphores
-			cost = _price.build_signals + _price.remove_signals;
-		} else {
-			// it is free to change orientation/pre-exit-combo signals
-			cost = 0;
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		if (!HasSignals(tile)) {
-			// there are no signals at all on this tile yet
-			_m[tile].m5 |= RAIL_TILE_SIGNALS; // change into signals
-			_m[tile].m2 |= 0xF0;              // all signals are on
-			_m[tile].m3 &= ~0xF0;          // no signals built by default
-			SetSignalType(tile, SIGTYPE_NORMAL);
-			SetSignalVariant(tile, sigvar);
-		}
-
-		if (p2 == 0) {
-			if (!HasSignalOnTrack(tile, track)) {
-				// build new signals
-				_m[tile].m3 |= SignalOnTrack(track);
-			} else {
-				if (pre_signal) {
-					// cycle between normal -> pre -> exit -> combo -> ...
-					SignalType type = GetSignalType(tile);
-
-					SetSignalType(tile, type == SIGTYPE_COMBO ? SIGTYPE_NORMAL : type + 1);
-				} else {
-					CycleSignalSide(tile, track);
-				}
-			}
-		} else {
-			/* If CmdBuildManySignals is called with copying signals, just copy the
-			 * direction of the first signal given as parameter by CmdBuildManySignals */
-			_m[tile].m3 &= ~SignalOnTrack(track);
-			_m[tile].m3 |= p2 & SignalOnTrack(track);
-			SetSignalVariant(tile, sigvar);
-		}
-
-		MarkTileDirtyByTile(tile);
-		SetSignalsOnBothDir(tile, track);
-		YapfNotifyTrackLayoutChange(tile, track);
-	}
-
-	return cost;
-}
-
-/** Build many signals by dragging; AutoSignals
- * @param tile start tile of drag
- * @param p1  end tile of drag
- * @param p2 various bitstuffed elements
- * - p2 = (bit  0)    - 0 = build, 1 = remove signals
- * - p2 = (bit  3)    - 0 = signals, 1 = semaphores
- * - p2 = (bit  4- 6) - track-orientation, valid values: 0-5 (Track enum)
- * - p2 = (bit 24-31) - user defined signals_density
- */
-static int32 CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 ret, total_cost, signal_ctr;
-	byte signals;
-	bool error = true;
-	TileIndex end_tile;
-
-	int mode = p2 & 0x1;
-	Track track = GB(p2, 4, 3);
-	Trackdir trackdir = TrackToTrackdir(track);
-	byte semaphores = (HASBIT(p2, 3) ? 8 : 0);
-	byte signal_density = (p2 >> 24);
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-	end_tile = p1;
-	if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
-
-	if (!IsTileType(tile, MP_RAILWAY)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* for vertical/horizontal tracks, double the given signals density
-	 * since the original amount will be too dense (shorter tracks) */
-	if (!IsDiagonalTrack(track)) signal_density *= 2;
-
-	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
-
-	track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */
-
-	// copy the signal-style of the first rail-piece if existing
-	if (HasSignals(tile)) {
-		signals = _m[tile].m3 & SignalOnTrack(track);
-		if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */
-
-		// copy signal/semaphores style (independent of CTRL)
-		semaphores = (GetSignalVariant(tile) == SIG_ELECTRIC ? 0 : 8);
-	} else { // no signals exist, drag a two-way signal stretch
-		signals = SignalOnTrack(track);
-	}
-
-	/* signal_ctr         - amount of tiles already processed
-	 * signals_density    - patch setting to put signal on every Nth tile (double space on |, -- tracks)
-	 **********
-	 * trackdir   - trackdir to build with autorail
-	 * semaphores - semaphores or signals
-	 * signals    - is there a signal/semaphore on the first tile, copy its style (two-way/single-way)
-	 *              and convert all others to semaphore/signal
-	 * mode       - 1 remove signals, 0 build signals */
-	signal_ctr = total_cost = 0;
-	for (;;) {
-		// only build/remove signals with the specified density
-		if (signal_ctr % signal_density == 0) {
-			ret = DoCommand(tile, TrackdirToTrack(trackdir) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
-
-			/* Be user-friendly and try placing signals as much as possible */
-			if (!CmdFailed(ret)) {
-				error = false;
-				total_cost += ret;
-			}
-		}
-
-		if (tile == end_tile) break;
-
-		tile += ToTileIndexDiff(_trackdelta[trackdir]);
-		signal_ctr++;
-
-		// toggle railbit for the non-diagonal tracks (|, -- tracks)
-		if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1;
-	}
-
-	return error ? CMD_ERROR : total_cost;
-}
-
-/** Build signals on a stretch of track.
- * Stub for the unified signal builder/remover
- * @see CmdSignalTrackHelper
- */
-int32 CmdBuildSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	return CmdSignalTrackHelper(tile, flags, p1, p2);
-}
-
-/** Remove signals
- * @param tile coordinates where signal is being deleted from
- * @param p1 track to remove signal from (Track enum)
- */
-int32 CmdRemoveSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Track track = (Track)(p1 & 0x7);
-
-	if (!ValParamTrackOrientation(track) ||
-			!IsTileType(tile, MP_RAILWAY) ||
-			!EnsureNoVehicle(tile) ||
-			!HasSignalOnTrack(tile, track)) {
-		return CMD_ERROR;
-	}
-
-	/* Only water can remove signals from anyone */
-	if (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* Do it? */
-	if (flags & DC_EXEC) {
-		_m[tile].m3 &= ~SignalOnTrack(track);
-
-		/* removed last signal from tile? */
-		if (GB(_m[tile].m3, 4, 4) == 0) {
-			SB(_m[tile].m2, 4, 4, 0);
-			SB(_m[tile].m5, 6, 2, RAIL_TILE_NORMAL >> 6); // XXX >> because the constant is meant for direct application, not use with SB
-			SetSignalVariant(tile, SIG_ELECTRIC); // remove any possible semaphores
-		}
-
-		SetSignalsOnBothDir(tile, track);
-		YapfNotifyTrackLayoutChange(tile, track);
-
-		MarkTileDirtyByTile(tile);
-	}
-
-	return _price.remove_signals;
-}
-
-/** Remove signals on a stretch of track.
- * Stub for the unified signal builder/remover
- * @see CmdSignalTrackHelper
- */
-int32 CmdRemoveSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	return CmdSignalTrackHelper(tile, flags, p1, SETBIT(p2, 0));
-}
-
-typedef int32 DoConvertRailProc(TileIndex tile, RailType totype, bool exec);
-
-static int32 DoConvertRail(TileIndex tile, RailType totype, bool exec)
-{
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) return CMD_ERROR;
-
-	// tile is already of requested type?
-	if (GetRailType(tile) == totype) return CMD_ERROR;
-
-	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
-	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
-
-	// change type.
-	if (exec) {
-		TrackBits tracks;
-		SetRailType(tile, totype);
-		MarkTileDirtyByTile(tile);
-
-		// notify YAPF about the track layout change
-		for (tracks = GetTrackBits(tile); tracks != TRACK_BIT_NONE; tracks = KILL_FIRST_BIT(tracks))
-			YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(tracks));
-
-		if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
-			Vehicle *v;
-
-			/* Update build vehicle window related to this depot */
-			InvalidateWindowData(WC_BUILD_VEHICLE, tile);
-
-			/* update power of trains in this depot */
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == tile && v->u.rail.track == 0x80) {
-					TrainPowerChanged(v);
-				}
-			}
-		}
-	}
-
-	return _price.build_rail / 2;
-}
-
-extern int32 DoConvertStationRail(TileIndex tile, RailType totype, bool exec);
-extern int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec);
-extern int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec);
-
-/** Convert one rail type to the other. You can convert normal rail to
- * monorail/maglev easily or vice-versa.
- * @param tile end tile of rail conversion drag
- * @param p1 start tile of drag
- * @param p2 new railtype to convert to
- */
-int32 CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 ret, cost, money;
-	int ex;
-	int ey;
-	int sx, sy, x, y;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!ValParamRailtype(p2)) return CMD_ERROR;
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	// make sure sx,sy are smaller than ex,ey
-	ex = TileX(tile);
-	ey = TileY(tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-
-	money = GetAvailableMoneyForCommand();
-	cost = 0;
-	ret = 0;
-
-	for (x = sx; x <= ex; ++x) {
-		for (y = sy; y <= ey; ++y) {
-			TileIndex tile = TileXY(x, y);
-			DoConvertRailProc* proc;
-
-			switch (GetTileType(tile)) {
-				case MP_RAILWAY:      proc = DoConvertRail;             break;
-				case MP_STATION:      proc = DoConvertStationRail;      break;
-				case MP_STREET:       proc = DoConvertStreetRail;       break;
-				case MP_TUNNELBRIDGE: proc = DoConvertTunnelBridgeRail; break;
-				default: continue;
-			}
-
-			ret = proc(tile, p2, false);
-			if (CmdFailed(ret)) continue;
-			cost += ret;
-
-			if (flags & DC_EXEC) {
-				money -= ret;
-				if (money < 0) {
-					_additional_cash_required = ret;
-					return cost - ret;
-				}
-				proc(tile, p2, true);
-			}
-		}
-	}
-
-	return (cost == 0) ? ret : cost;
-}
-
-static int32 RemoveTrainDepot(TileIndex tile, uint32 flags)
-{
-	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
-		return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile))
-		return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		DiagDirection dir = GetRailDepotDirection(tile);
-
-		DeleteDepot(GetDepotByTile(tile));
-		UpdateSignalsOnSegment(tile, dir);
-		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
-	}
-
-	return _price.remove_train_depot;
-}
-
-static int32 ClearTile_Track(TileIndex tile, byte flags)
-{
-	int32 cost;
-	int32 ret;
-
-	if (flags & DC_AUTO) {
-		if (!IsTileOwner(tile, _current_player))
-			return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
-
-		if (IsPlainRailTile(tile)) {
-			return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
-		} else {
-			return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
-		}
-	}
-
-	cost = 0;
-
-	switch (GetRailTileType(tile)) {
-		case RAIL_TILE_SIGNALS:
-		case RAIL_TILE_NORMAL: {
-			TrackBits tracks = GetTrackBits(tile);
-			uint i;
-
-			for_each_bit (i, tracks) {
-				ret = DoCommand(tile, 0, i, flags, CMD_REMOVE_SINGLE_RAIL);
-				if (CmdFailed(ret)) return CMD_ERROR;
-				cost += ret;
-			}
-			return cost;
-		}
-
-		case RAIL_TILE_DEPOT_WAYPOINT:
-			if (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) {
-				return RemoveTrainDepot(tile, flags);
-			} else {
-				return RemoveTrainWaypoint(tile, flags, false);
-			}
-
-		default:
-			return CMD_ERROR;
-	}
-}
-
-#include "table/track_land.h"
-
-static void DrawSingleSignal(TileIndex tile, byte condition, uint image, uint pos)
-{
-	bool side = _opt.road_side & _patches.signal_side;
-	static const Point SignalPositions[2][12] = {
-		{      /* Signals on the left side */
-		/*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
-			{ 8,  5}, {14,  1}, { 1, 14}, { 9, 11}, { 1,  0}, { 3, 10},
-		/*  LOWER     LOWER     X         X         Y         Y     */
-			{11,  4}, {14, 14}, {11,  3}, { 4, 13}, { 3,  4}, {11, 13}
-		}, {   /* Signals on the right side */
-		/*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
-			{14,  1}, {12, 10}, { 4,  6}, { 1, 14}, {10,  4}, { 0,  1},
-		/*  LOWER     LOWER     X         X         Y         Y     */
-			{14, 14}, { 5, 12}, {11, 13}, { 4,  3}, {13,  4}, { 3, 11}
-		}
-	};
-
-	static const SpriteID SignalBase[2][2][4] = {
-		{    /* Signals on left side */
-			{  0x4FB, 0x1323, 0x1333, 0x1343}, /* light signals */
-			{ 0x1353, 0x1363, 0x1373, 0x1383}  /* semaphores    */
-		}, { /* Signals on right side */
-			{  0x4FB, 0x1323, 0x1333, 0x1343}, /* light signals */
-			{ 0x1446, 0x1456, 0x1466, 0x1476}  /* semaphores    */
-		/*         |       |       |       |     */
-		/*    normal,  entry,   exit,  combo     */
-		}
-	};
-
-	uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
-	uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
-
-	SpriteID sprite;
-
-	/* _signal_base is set by our NewGRF Action 5 loader. If it is 0 then we
-	 * just draw the standard signals, else we get the offset from _signal_base
-	 * and draw that sprite. All the signal sprites are loaded sequentially. */
-	if (_signal_base == 0 || (GetSignalType(tile) == 0 && GetSignalVariant(tile) == SIG_ELECTRIC)) {
-		sprite = SignalBase[side][GetSignalVariant(tile)][GetSignalType(tile)] + image + condition;
-	} else {
-		sprite = _signal_base + (GetSignalType(tile) - 1) * 16 + GetSignalVariant(tile) * 64 + image + condition;
-	}
-
-	AddSortableSpriteToDraw(sprite, x, y, 1, 1, 10, GetSlopeZ(x,y));
-}
-
-static uint32 _drawtile_track_palette;
-
-
-static void DrawTrackFence_NW(const TileInfo *ti)
-{
-	uint32 image = 0x515;
-	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x519 : 0x51B;
-	AddSortableSpriteToDraw(image | _drawtile_track_palette,
-		ti->x, ti->y + 1, 16, 1, 4, ti->z);
-}
-
-static void DrawTrackFence_SE(const TileInfo *ti)
-{
-	uint32 image = 0x515;
-	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x519 : 0x51B;
-	AddSortableSpriteToDraw(image | _drawtile_track_palette,
-		ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
-}
-
-static void DrawTrackFence_NW_SE(const TileInfo *ti)
-{
-	DrawTrackFence_NW(ti);
-	DrawTrackFence_SE(ti);
-}
-
-static void DrawTrackFence_NE(const TileInfo *ti)
-{
-	uint32 image = 0x516;
-	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x51A : 0x51C;
-	AddSortableSpriteToDraw(image | _drawtile_track_palette,
-		ti->x + 1, ti->y, 1, 16, 4, ti->z);
-}
-
-static void DrawTrackFence_SW(const TileInfo *ti)
-{
-	uint32 image = 0x516;
-	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x51A : 0x51C;
-	AddSortableSpriteToDraw(image | _drawtile_track_palette,
-		ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
-}
-
-static void DrawTrackFence_NE_SW(const TileInfo *ti)
-{
-	DrawTrackFence_NE(ti);
-	DrawTrackFence_SW(ti);
-}
-
-static void DrawTrackFence_NS_1(const TileInfo *ti)
-{
-	int z = ti->z;
-	if (ti->tileh & SLOPE_W) z += TILE_HEIGHT;
-	AddSortableSpriteToDraw(0x517 | _drawtile_track_palette,
-		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
-}
-
-static void DrawTrackFence_NS_2(const TileInfo *ti)
-{
-	int z = ti->z;
-	if (ti->tileh & SLOPE_E) z += TILE_HEIGHT;
-	AddSortableSpriteToDraw(0x517 | _drawtile_track_palette,
-		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
-}
-
-static void DrawTrackFence_WE_1(const TileInfo *ti)
-{
-	int z = ti->z;
-	if (ti->tileh & SLOPE_N) z += TILE_HEIGHT;
-	AddSortableSpriteToDraw(0x518 | _drawtile_track_palette,
-		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
-}
-
-static void DrawTrackFence_WE_2(const TileInfo *ti)
-{
-	int z = ti->z;
-	if (ti->tileh & SLOPE_S) z += TILE_HEIGHT;
-	AddSortableSpriteToDraw(0x518 | _drawtile_track_palette,
-		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
-}
-
-
-static void DrawTrackDetails(const TileInfo* ti)
-{
-	switch (GetRailGroundType(ti->tile)) {
-		case RAIL_GROUND_FENCE_NW:     DrawTrackFence_NW(ti);    break;
-		case RAIL_GROUND_FENCE_SE:     DrawTrackFence_SE(ti);    break;
-		case RAIL_GROUND_FENCE_SENW:   DrawTrackFence_NW_SE(ti); break;
-		case RAIL_GROUND_FENCE_NE:     DrawTrackFence_NE(ti);    break;
-		case RAIL_GROUND_FENCE_SW:     DrawTrackFence_SW(ti);    break;
-		case RAIL_GROUND_FENCE_NESW:   DrawTrackFence_NE_SW(ti); break;
-		case RAIL_GROUND_FENCE_VERT1:  DrawTrackFence_NS_1(ti);  break;
-		case RAIL_GROUND_FENCE_VERT2:  DrawTrackFence_NS_2(ti);  break;
-		case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti);  break;
-		case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti);  break;
-		default: break;
-	}
-}
-
-
-/**
- * Draw ground sprite and track bits
- * @param ti TileInfo
- * @param track TrackBits to draw
- * @param earth Draw as earth
- * @param snow Draw as snow
- * @param flat Always draw foundation
- */
-static void DrawTrackBits(TileInfo* ti, TrackBits track)
-{
-	const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
-	PalSpriteID image;
-	bool junction = false;
-
-	// Select the sprite to use.
-	(image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
-	(image++,                           track == TRACK_BIT_X) ||
-	(image++,                           track == TRACK_BIT_UPPER) ||
-	(image++,                           track == TRACK_BIT_LOWER) ||
-	(image++,                           track == TRACK_BIT_RIGHT) ||
-	(image++,                           track == TRACK_BIT_LEFT) ||
-	(image++,                           track == TRACK_BIT_CROSS) ||
-
-	(image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
-	(image++,                            track == TRACK_BIT_VERT) ||
-
-	(junction = true, false) ||
-	(image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
-	(image++,                          (track & TRACK_BIT_3WAY_SW) == 0) ||
-	(image++,                          (track & TRACK_BIT_3WAY_NW) == 0) ||
-	(image++,                          (track & TRACK_BIT_3WAY_SE) == 0) ||
-	(image++, true);
-
-	if (ti->tileh != SLOPE_FLAT) {
-		uint foundation = GetRailFoundation(ti->tileh, track);
-
-		if (foundation != 0) DrawFoundation(ti, foundation);
-
-		// DrawFoundation() modifies ti.
-		// Default sloped sprites..
-		if (ti->tileh != SLOPE_FLAT)
-			image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
-	}
-
-	switch (GetRailGroundType(ti->tile)) {
-		case RAIL_GROUND_BARREN:     image |= PALETTE_TO_BARE_LAND; break;
-		case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
-		default: break;
-	}
-
-	DrawGroundSprite(image);
-
-	// Draw track pieces individually for junction tiles
-	if (junction) {
-		if (track & TRACK_BIT_X)     DrawGroundSprite(rti->base_sprites.single_y);
-		if (track & TRACK_BIT_Y)     DrawGroundSprite(rti->base_sprites.single_x);
-		if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n);
-		if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s);
-		if (track & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w);
-		if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e);
-	}
-
-	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-}
-
-static void DrawSignals(TileIndex tile, TrackBits rails)
-{
-#define MAYBE_DRAW_SIGNAL(x,y,z) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, GetSingleSignalState(tile, x), y - 0x4FB, z)
-
-	if (!(rails & TRACK_BIT_Y)) {
-		if (!(rails & TRACK_BIT_X)) {
-			if (rails & TRACK_BIT_LEFT) {
-				MAYBE_DRAW_SIGNAL(2, 0x509, 0);
-				MAYBE_DRAW_SIGNAL(3, 0x507, 1);
-			}
-			if (rails & TRACK_BIT_RIGHT) {
-				MAYBE_DRAW_SIGNAL(0, 0x509, 2);
-				MAYBE_DRAW_SIGNAL(1, 0x507, 3);
-			}
-			if (rails & TRACK_BIT_UPPER) {
-				MAYBE_DRAW_SIGNAL(3, 0x505, 4);
-				MAYBE_DRAW_SIGNAL(2, 0x503, 5);
-			}
-			if (rails & TRACK_BIT_LOWER) {
-				MAYBE_DRAW_SIGNAL(1, 0x505, 6);
-				MAYBE_DRAW_SIGNAL(0, 0x503, 7);
-			}
-		} else {
-			MAYBE_DRAW_SIGNAL(3, 0x4FB, 8);
-			MAYBE_DRAW_SIGNAL(2, 0x4FD, 9);
-		}
-	} else {
-		MAYBE_DRAW_SIGNAL(3, 0x4FF, 10);
-		MAYBE_DRAW_SIGNAL(2, 0x501, 11);
-	}
-}
-
-static void DrawTile_Track(TileInfo *ti)
-{
-	const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
-	PalSpriteID image;
-
-	_drawtile_track_palette = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)));
-
-	if (IsPlainRailTile(ti->tile)) {
-		TrackBits rails = GetTrackBits(ti->tile);
-
-		DrawTrackBits(ti, rails);
-
-		if (_display_opt & DO_FULL_DETAIL) DrawTrackDetails(ti);
-
-		if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
-	} else {
-		// draw depot/waypoint
-		const DrawTileSprites* dts;
-		const DrawTileSeqStruct* dtss;
-		uint32 relocation;
-
-		if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-
-		if (GetRailTileSubtype(ti->tile) == RAIL_SUBTYPE_DEPOT) {
-			dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
-
-			relocation = rti->total_offset;
-
-			image = dts->ground_sprite;
-			if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
-
-			// adjust ground tile for desert
-			// don't adjust for snow, because snow in depots looks weird
-			if (IsSnowRailGround(ti->tile) && _opt.landscape == LT_DESERT) {
-				if (image != SPR_FLAT_GRASS_TILE) {
-					image += rti->snow_offset; // tile with tracks
-				} else {
-					image = SPR_FLAT_SNOWY_TILE; // flat ground
-				}
-			}
-		} else {
-			// look for customization
-			byte stat_id = GetWaypointByTile(ti->tile)->stat_id;
-			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id);
-
-			if (statspec != NULL) {
-				// emulate station tile - open with building
-				const Station* st = ComposeWaypointStation(ti->tile);
-				uint gfx = 2;
-
-				if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
-					uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
-					if (callback != CALLBACK_FAILED) gfx = callback;
-				}
-
-				if (statspec->renderdata == NULL) {
-					dts = GetStationTileLayout(gfx);
-				} else {
-					dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
-				}
-
-				if (dts != NULL && dts->seq != NULL) {
-					relocation = GetCustomStationRelocation(statspec, st, ti->tile);
-
-					image = dts->ground_sprite;
-					if (HASBIT(image, 31)) {
-						CLRBIT(image, 31);
-						image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
-						image += rti->custom_ground_offset;
-					} else {
-						image += rti->total_offset;
-					}
-				} else {
-					goto default_waypoint;
-				}
-			} else {
-default_waypoint:
-				// There is no custom layout, fall back to the default graphics
-				dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)];
-				relocation = 0;
-				image = dts->ground_sprite + rti->total_offset;
-				if (IsSnowRailGround(ti->tile)) image += rti->snow_offset;
-			}
-		}
-
-		DrawGroundSprite(image);
-
-		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-		foreach_draw_tile_seq(dtss, dts->seq) {
-			uint32 image = dtss->image + relocation;
-
-			if (_display_opt & DO_TRANS_BUILDINGS) {
-				MAKE_TRANSPARENT(image);
-			} else if (image & PALETTE_MODIFIER_COLOR) {
-				image |= _drawtile_track_palette;
-			}
-			AddSortableSpriteToDraw(
-				image,
-				ti->x + dtss->delta_x, ti->y + dtss->delta_y,
-				dtss->size_x, dtss->size_y,
-				dtss->size_z, ti->z + dtss->delta_z
-			);
-		}
-	}
-	DrawBridgeMiddle(ti);
-}
-
-
-static void DrawTileSequence(int x, int y, uint32 ground, const DrawTileSeqStruct* dtss, uint32 offset)
-{
-	uint32 palette = PLAYER_SPRITE_COLOR(_local_player);
-
-	DrawSprite(ground, x, y);
-	for (; dtss->image != 0; dtss++) {
-		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
-		uint32 image = dtss->image + offset;
-
-		if (image & PALETTE_MODIFIER_COLOR) image |= palette;
-		DrawSprite(image, x + pt.x, y + pt.y);
-	}
-}
-
-void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
-{
-	const DrawTileSprites* dts = &_depot_gfx_table[dir];
-	uint32 image = dts->ground_sprite;
-	uint32 offset = GetRailTypeInfo(railtype)->total_offset;
-
-	if (image != SPR_FLAT_GRASS_TILE) image += offset;
-	DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
-}
-
-void DrawDefaultWaypointSprite(int x, int y, RailType railtype)
-{
-	uint32 offset = GetRailTypeInfo(railtype)->total_offset;
-	const DrawTileSprites* dts = &_waypoint_gfx_table[AXIS_X];
-
-	DrawTileSequence(x, y, dts->ground_sprite + offset, dts->seq, 0);
-}
-
-typedef struct SetSignalsData {
-	int cur;
-	int cur_stack;
-	bool stop;
-	bool has_presignal;
-
-	// presignal info
-	int presignal_exits;
-	int presignal_exits_free;
-
-	// these are used to keep track of the signals that change.
-	byte bit[NUM_SSD_ENTRY];
-	TileIndex tile[NUM_SSD_ENTRY];
-
-	// these are used to keep track of the stack that modifies presignals recursively
-	TileIndex next_tile[NUM_SSD_STACK];
-	byte next_dir[NUM_SSD_STACK];
-
-} SetSignalsData;
-
-static bool SetSignalsEnumProc(TileIndex tile, void* data, int track, uint length, byte* state)
-{
-	SetSignalsData* ssd = data;
-
-	if (!IsTileType(tile, MP_RAILWAY)) return false;
-
-	// the tile has signals?
-	if (HasSignalOnTrack(tile, TrackdirToTrack(track))) {
-		if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
-			// yes, add the signal to the list of signals
-			if (ssd->cur != NUM_SSD_ENTRY) {
-				ssd->tile[ssd->cur] = tile; // remember the tile index
-				ssd->bit[ssd->cur] = track; // and the controlling bit number
-				ssd->cur++;
-			}
-
-			// remember if this block has a presignal.
-			ssd->has_presignal |= IsPresignalEntry(tile);
-		}
-
-		if (HasSignalOnTrackdir(tile, track) && IsPresignalExit(tile)) {
-			// this is an exit signal that points out from the segment
-			ssd->presignal_exits++;
-			if (GetSignalStateByTrackdir(tile, track) != SIGNAL_STATE_RED)
-				ssd->presignal_exits_free++;
-		}
-
-		return true;
-	} else if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
-		return true; // don't look further if the tile is a depot
-	}
-
-	return false;
-}
-
-/* Struct to parse data from VehicleFromPos to SignalVehicleCheckProc */
-typedef struct SignalVehicleCheckStruct {
-	TileIndex tile;
-	uint track;
-} SignalVehicleCheckStruct;
-
-static void *SignalVehicleCheckProc(Vehicle *v, void *data)
-{
-	const SignalVehicleCheckStruct* dest = data;
-
-	if (v->type != VEH_Train) return NULL;
-
-	/* Wrong tile, or no train? Not a match */
-	if (v->tile != dest->tile) return NULL;
-
-	/* Are we on the same piece of track? */
-	if (dest->track & v->u.rail.track * 0x101) return v;
-
-	return NULL;
-}
-
-/* Special check for SetSignalsAfterProc, to see if there is a vehicle on this tile */
-static bool SignalVehicleCheck(TileIndex tile, uint track)
-{
-	SignalVehicleCheckStruct dest;
-
-	dest.tile = tile;
-	dest.track = track;
-
-	/* Locate vehicles in tunnels or on bridges */
-	if (IsTunnelTile(tile) || IsBridgeTile(tile)) {
-		TileIndex end;
-		DiagDirection direction;
-
-		if (IsTunnelTile(tile)) {
-			end = GetOtherTunnelEnd(tile);
-			direction = GetTunnelDirection(tile);
-		} else {
-			end = GetOtherBridgeEnd(tile);
-			direction = GetBridgeRampDirection(tile);
-		}
-
-		dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible)
-
-		// check for a vehicle with that trackdir on the start tile of the tunnel
-		if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true;
-
-		// check for a vehicle with that trackdir on the end tile of the tunnel
-		if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
-
-		// now check all tiles from start to end for a warping vehicle
-		// NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile?
-		dest.track = 0x40;   //Vehicle inside a tunnel or on a bridge
-		for (; tile != end; tile += TileOffsByDiagDir(direction)) {
-			if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL)
-				return true;
-		}
-
-		// no vehicle found
-		return false;
-	}
-
-	return VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL;
-}
-
-static void SetSignalsAfterProc(TrackPathFinder *tpf)
-{
-	SetSignalsData *ssd = tpf->userdata;
-	const TrackPathFinderLink* link;
-	uint offs;
-	uint i;
-
-	ssd->stop = false;
-
-	/* Go through all the PF tiles */
-	for (i = 0; i < lengthof(tpf->hash_head); i++) {
-		/* Empty hash item */
-		if (tpf->hash_head[i] == 0) continue;
-
-		/* If 0x8000 is not set, there is only 1 item */
-		if (!(tpf->hash_head[i] & 0x8000)) {
-			/* Check if there is a vehicle on this tile */
-			if (SignalVehicleCheck(tpf->hash_tile[i], tpf->hash_head[i])) {
-				ssd->stop = true;
-				return;
-			}
-		} else {
-			/* There are multiple items, where hash_tile points to the first item in the list */
-			offs = tpf->hash_tile[i];
-			do {
-				/* Find the next item */
-				link = PATHFIND_GET_LINK_PTR(tpf, offs);
-				/* Check if there is a vehicle on this tile */
-				if (SignalVehicleCheck(link->tile, link->flags)) {
-					ssd->stop = true;
-					return;
-				}
-				/* Goto the next item */
-			} while ((offs = link->next) != 0xFFFF);
-		}
-	}
-}
-
-static const byte _dir_from_track[14] = {
-	0,1,0,1,2,1, 0,0,
-	2,3,3,2,3,0,
-};
-
-
-static void ChangeSignalStates(SetSignalsData *ssd)
-{
-	int i;
-
-	// thinking about presignals...
-	// the presignal is green if,
-	//   if no train is in the segment AND
-	//   there is at least one green exit signal OR
-	//   there are no exit signals in the segment
-
-	// then mark the signals in the segment accordingly
-	for (i = 0; i != ssd->cur; i++) {
-		TileIndex tile = ssd->tile[i];
-		byte bit = SignalAgainstTrackdir(ssd->bit[i]);
-		uint16 m2 = _m[tile].m2;
-
-		// presignals don't turn green if there is at least one presignal exit and none are free
-		if (IsPresignalEntry(tile)) {
-			int ex = ssd->presignal_exits, exfree = ssd->presignal_exits_free;
-
-			// subtract for dual combo signals so they don't count themselves
-			if (IsPresignalExit(tile) && HasSignalOnTrackdir(tile, ssd->bit[i])) {
-				ex--;
-				if (GetSignalStateByTrackdir(tile, ssd->bit[i]) != SIGNAL_STATE_RED) exfree--;
-			}
-
-			// if we have exits and none are free, make red.
-			if (ex && !exfree) goto make_red;
-		}
-
-		// check if the signal is unaffected.
-		if (ssd->stop) {
-make_red:
-			// turn red
-			if ((bit & m2) == 0) continue;
-		} else {
-			// turn green
-			if ((bit & m2) != 0) continue;
-		}
-
-		/* Update signals on the other side of this exit-combo signal; it changed. */
-		if (IsPresignalExit(tile)) {
-			if (ssd->cur_stack != NUM_SSD_STACK) {
-				ssd->next_tile[ssd->cur_stack] = tile;
-				ssd->next_dir[ssd->cur_stack] = _dir_from_track[ssd->bit[i]];
-				ssd->cur_stack++;
-			} else {
-				DEBUG(misc, 0, "NUM_SSD_STACK too small"); /// @todo WTF is this???
-			}
-		}
-
-		// it changed, so toggle it
-		_m[tile].m2 = m2 ^ bit;
-		MarkTileDirtyByTile(tile);
-	}
-}
-
-
-bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction)
-{
-	SetSignalsData ssd;
-	int result = -1;
-
-	ssd.cur_stack = 0;
-
-	for (;;) {
-		// go through one segment and update all signals pointing into that segment.
-		ssd.cur = ssd.presignal_exits = ssd.presignal_exits_free = 0;
-		ssd.has_presignal = false;
-
-		FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, SetSignalsEnumProc, SetSignalsAfterProc, &ssd);
-		ChangeSignalStates(&ssd);
-
-		// remember the result only for the first iteration.
-		if (result < 0) {
-			// stay in depot while segment is occupied or while all presignal exits are blocked
-			result = ssd.stop || (ssd.presignal_exits > 0 && ssd.presignal_exits_free == 0);
-		}
-
-		// if any exit signals were changed, we need to keep going to modify the stuff behind those.
-		if (ssd.cur_stack == 0) break;
-
-		// one or more exit signals were changed, so we need to update another segment too.
-		tile = ssd.next_tile[--ssd.cur_stack];
-		direction = ssd.next_dir[ssd.cur_stack];
-	}
-
-	return result != 0;
-}
-
-void SetSignalsOnBothDir(TileIndex tile, byte track)
-{
-	static const DiagDirection _search_dir_1[] = {
-		DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE
-	};
-	static const DiagDirection _search_dir_2[] = {
-		DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
-	};
-
-	UpdateSignalsOnSegment(tile, _search_dir_1[track]);
-	UpdateSignalsOnSegment(tile, _search_dir_2[track]);
-}
-
-static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	Slope tileh = GetTileSlope(tile, &z);
-
-	if (tileh == SLOPE_FLAT) return z;
-	if (IsPlainRailTile(tile)) {
-		uint f = GetRailFoundation(tileh, GetTrackBits(tile));
-
-		if (f != 0) {
-			if (IsSteepSlope(tileh)) {
-				z += TILE_HEIGHT;
-			} else if (f < 15) {
-				return z + TILE_HEIGHT; // leveled foundation
-			}
-			tileh = _inclined_tileh[f - 15]; // inclined foundation
-		}
-		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-	} else {
-		return z + TILE_HEIGHT;
-	}
-}
-
-static Slope GetSlopeTileh_Track(TileIndex tile, Slope tileh)
-{
-	if (tileh == SLOPE_FLAT) return SLOPE_FLAT;
-	if (IsPlainRailTile(tile)) {
-		uint f = GetRailFoundation(tileh, GetTrackBits(tile));
-
-		if (f == 0) return tileh;
-		if (f < 15) return SLOPE_FLAT; // leveled foundation
-		return _inclined_tileh[f - 15]; // inclined foundation
-	} else {
-		return SLOPE_FLAT;
-	}
-}
-
-static void GetAcceptedCargo_Track(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void AnimateTile_Track(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoop_Track(TileIndex tile)
-{
-	RailGroundType old_ground = GetRailGroundType(tile);
-	RailGroundType new_ground;
-
-	switch (_opt.landscape) {
-		case LT_HILLY:
-			if (GetTileZ(tile) > _opt.snow_line) {
-				new_ground = RAIL_GROUND_ICE_DESERT;
-				goto set_ground;
-			}
-			break;
-
-		case LT_DESERT:
-			if (GetTropicZone(tile) == TROPICZONE_DESERT) {
-				new_ground = RAIL_GROUND_ICE_DESERT;
-				goto set_ground;
-			}
-			break;
-	}
-
-	if (!IsPlainRailTile(tile)) return;
-
-	new_ground = RAIL_GROUND_GRASS;
-
-	if (old_ground != RAIL_GROUND_BARREN) { /* wait until bottom is green */
-		/* determine direction of fence */
-		TrackBits rail = GetTrackBits(tile);
-
-		switch (rail) {
-			case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
-			case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
-			case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
-			case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
-
-			default: {
-				PlayerID owner = GetTileOwner(tile);
-
-				if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
-							(rail & TRACK_BIT_3WAY_NW) == 0 &&
-							(rail & TRACK_BIT_X)
-						)) {
-					TileIndex n = tile + TileDiffXY(0, -1);
-					TrackBits nrail = GetTrackBits(n);
-
-					if (!IsTileType(n, MP_RAILWAY) ||
-							!IsTileOwner(n, owner) ||
-							nrail == TRACK_BIT_UPPER ||
-							nrail == TRACK_BIT_LEFT) {
-						new_ground = RAIL_GROUND_FENCE_NW;
-					}
-				}
-
-				if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
-							(rail & TRACK_BIT_3WAY_SE) == 0 &&
-							(rail & TRACK_BIT_X)
-						)) {
-					TileIndex n = tile + TileDiffXY(0, 1);
-					TrackBits nrail = GetTrackBits(n);
-
-					if (!IsTileType(n, MP_RAILWAY) ||
-							!IsTileOwner(n, owner) ||
-							nrail == TRACK_BIT_LOWER ||
-							nrail == TRACK_BIT_RIGHT) {
-						new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
-							RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
-					}
-				}
-
-				if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
-							(rail & TRACK_BIT_3WAY_NE) == 0 &&
-							(rail & TRACK_BIT_Y)
-						)) {
-					TileIndex n = tile + TileDiffXY(-1, 0);
-					TrackBits nrail = GetTrackBits(n);
-
-					if (!IsTileType(n, MP_RAILWAY) ||
-							!IsTileOwner(n, owner) ||
-							nrail == TRACK_BIT_UPPER ||
-							nrail == TRACK_BIT_RIGHT) {
-						new_ground = RAIL_GROUND_FENCE_NE;
-					}
-				}
-
-				if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
-							(rail & TRACK_BIT_3WAY_SW) == 0 &&
-							(rail & TRACK_BIT_Y)
-						)) {
-					TileIndex n = tile + TileDiffXY(1, 0);
-					TrackBits nrail = GetTrackBits(n);
-
-					if (!IsTileType(n, MP_RAILWAY) ||
-							!IsTileOwner(n, owner) ||
-							nrail == TRACK_BIT_LOWER ||
-							nrail == TRACK_BIT_LEFT) {
-						new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
-							RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
-					}
-				}
-				break;
-			}
-		}
-	}
-
-set_ground:
-	if (old_ground != new_ground) {
-		SetRailGroundType(tile, new_ground);
-		MarkTileDirtyByTile(tile);
-	}
-}
-
-
-static uint32 GetTileTrackStatus_Track(TileIndex tile, TransportType mode)
-{
-	byte a;
-	uint16 b;
-
-	if (mode != TRANSPORT_RAIL) return 0;
-
-	if (IsPlainRailTile(tile)) {
-		TrackBits rails = GetTrackBits(tile);
-		uint32 ret = rails * 0x101;
-
-		if (HasSignals(tile)) {
-			a = _m[tile].m3;
-			b = _m[tile].m2;
-
-			b &= a;
-
-			/* When signals are not present (in neither
-			 * direction), we pretend them to be green. (So if
-			 * signals are only one way, the other way will
-			 * implicitely become `red' */
-			if ((a & 0xC0) == 0) b |= 0xC0;
-			if ((a & 0x30) == 0) b |= 0x30;
-
-			if ((b & 0x80) == 0) ret |= 0x10070000;
-			if ((b & 0x40) == 0) ret |= 0x07100000;
-			if ((b & 0x20) == 0) ret |= 0x20080000;
-			if ((b & 0x10) == 0) ret |= 0x08200000;
-		} else {
-			if (rails == TRACK_BIT_CROSS) ret |= 0x40;
-		}
-		return ret;
-	} else {
-		if (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) {
-			return AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(tile))) * 0x101;
-		} else {
-			return GetRailWaypointBits(tile) * 0x101;
-		}
-	}
-}
-
-static void ClickTile_Track(TileIndex tile)
-{
-	if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
-		ShowDepotWindow(tile, VEH_Train);
-	} else if (IsRailWaypoint(tile)) {
-		ShowRenameWaypointWindow(GetWaypointByTile(tile));
-	}
-}
-
-static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
-{
-	td->owner = GetTileOwner(tile);
-	switch (GetRailTileType(tile)) {
-		case RAIL_TILE_NORMAL:
-			td->str = STR_1021_RAILROAD_TRACK;
-			break;
-
-		case RAIL_TILE_SIGNALS: {
-			const StringID signal_type[] = {
-				STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS,
-				STR_RAILROAD_TRACK_WITH_PRESIGNALS,
-				STR_RAILROAD_TRACK_WITH_EXITSIGNALS,
-				STR_RAILROAD_TRACK_WITH_COMBOSIGNALS
-			};
-
-			td->str = signal_type[GetSignalType(tile)];
-			break;
-		}
-
-		case RAIL_TILE_DEPOT_WAYPOINT:
-		default:
-			td->str = (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) ?
-				STR_1023_RAILROAD_TRAIN_DEPOT : STR_LANDINFO_WAYPOINT;
-			break;
-	}
-}
-
-static void ChangeTileOwner_Track(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (new_player != PLAYER_SPECTATOR) {
-		SetTileOwner(tile, new_player);
-	} else {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-	}
-}
-
-static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
-static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
-static const byte _deltacoord_leaveoffset[8] = {
-	-1,  0,  1,  0, /* x */
-	 0,  1,  0, -1  /* y */
-};
-
-static uint32 VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
-{
-	byte fract_coord;
-	byte fract_coord_leave;
-	DiagDirection dir;
-	int length;
-
-	// this routine applies only to trains in depot tiles
-	if (v->type != VEH_Train || !IsTileDepotType(tile, TRANSPORT_RAIL)) return 0;
-
-	/* depot direction */
-	dir = GetRailDepotDirection(tile);
-
-	/* calculate the point where the following wagon should be activated */
-	/* this depends on the length of the current vehicle */
-	length = v->u.rail.cached_veh_length;
-
-	fract_coord_leave =
-		((_fractcoords_enter[dir] & 0x0F) + // x
-			(length + 1) * _deltacoord_leaveoffset[dir]) +
-		(((_fractcoords_enter[dir] >> 4) +  // y
-			((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
-
-	fract_coord = (x & 0xF) + ((y & 0xF) << 4);
-
-	if (_fractcoords_behind[dir] == fract_coord) {
-		/* make sure a train is not entering the tile from behind */
-		return 8;
-	} else if (_fractcoords_enter[dir] == fract_coord) {
-		if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
-			/* enter the depot */
-			v->u.rail.track = 0x80,
-			v->vehstatus |= VS_HIDDEN; /* hide it */
-			v->direction = ReverseDir(v->direction);
-			if (v->next == NULL) VehicleEnterDepot(v);
-			v->tile = tile;
-
-			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-			return 4;
-		}
-	} else if (fract_coord_leave == fract_coord) {
-		if (DiagDirToDir(dir) == v->direction) {
-			/* leave the depot? */
-			if ((v = v->next) != NULL) {
-				v->vehstatus &= ~VS_HIDDEN;
-				v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
-			}
-		}
-	}
-
-	return 0;
-}
-
-
-const TileTypeProcs _tile_type_rail_procs = {
-	DrawTile_Track,           /* draw_tile_proc */
-	GetSlopeZ_Track,          /* get_slope_z_proc */
-	ClearTile_Track,          /* clear_tile_proc */
-	GetAcceptedCargo_Track,   /* get_accepted_cargo_proc */
-	GetTileDesc_Track,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Track, /* get_tile_track_status_proc */
-	ClickTile_Track,          /* click_tile_proc */
-	AnimateTile_Track,        /* animate_tile_proc */
-	TileLoop_Track,           /* tile_loop_clear */
-	ChangeTileOwner_Track,    /* change_tile_owner_clear */
-	NULL,                     /* get_produced_cargo_proc */
-	VehicleEnter_Track,       /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Track,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/rail_cmd.cpp
@@ -0,0 +1,1985 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "debug.h"
+#include "functions.h"
+#include "rail_map.h"
+#include "road_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "town_map.h"
+#include "tunnel_map.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "command.h"
+#include "pathfind.h"
+#include "engine.h"
+#include "town.h"
+#include "sound.h"
+#include "station.h"
+#include "sprite.h"
+#include "depot.h"
+#include "waypoint.h"
+#include "window.h"
+#include "rail.h"
+#include "railtypes.h" // include table for railtypes
+#include "newgrf.h"
+#include "yapf/yapf.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_station.h"
+#include "train.h"
+
+const byte _track_sloped_sprites[14] = {
+	14, 15, 22, 13,
+	 0, 21, 17, 12,
+	23,  0, 18, 20,
+	19, 16
+};
+
+
+/*         4
+ *     ---------
+ *    |\       /|
+ *    | \    1/ |
+ *    |  \   /  |
+ *    |   \ /   |
+ *  16|    \    |32
+ *    |   / \2  |
+ *    |  /   \  |
+ *    | /     \ |
+ *    |/       \|
+ *     ---------
+ *         8
+ */
+
+
+
+/* MAP2 byte:    abcd???? => Signal On? Same coding as map3lo
+ * MAP3LO byte:  abcd???? => Signal Exists?
+ *               a and b are for diagonals, upper and left,
+ *               one for each direction. (ie a == NE->SW, b ==
+ *               SW->NE, or v.v., I don't know. b and c are
+ *               similar for lower and right.
+ * MAP2 byte:    ????abcd => Type of ground.
+ * MAP3LO byte:  ????abcd => Type of rail.
+ * MAP5:         00abcdef => rail
+ *               01abcdef => rail w/ signals
+ *               10uuuuuu => unused
+ *               11uuuudd => rail depot
+ */
+
+static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
+{
+	TrackBits current; /* The current track layout */
+	TrackBits future; /* The track layout we want to build */
+	_error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION;
+
+	if (!IsPlainRailTile(tile)) return false;
+
+	/* So, we have a tile with tracks on it (and possibly signals). Let's see
+	 * what tracks first */
+	current = GetTrackBits(tile);
+	future = current | to_build;
+
+	/* Are we really building something new? */
+	if (current == future) {
+		/* Nothing new is being built */
+		_error_message = STR_1007_ALREADY_BUILT;
+		return false;
+	}
+
+	/* Let's see if we may build this */
+	if (flags & DC_NO_RAIL_OVERLAP || HasSignals(tile)) {
+		/* If we are not allowed to overlap (flag is on for ai players or we have
+		 * signals on the tile), check that */
+		return future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT;
+	} else {
+		/* Normally, we may overlap and any combination is valid */
+		return true;
+	}
+}
+
+
+static const TrackBits _valid_tileh_slopes[][15] = {
+
+// set of normal ones
+{
+	TRACK_BIT_ALL,
+	TRACK_BIT_RIGHT,
+	TRACK_BIT_UPPER,
+	TRACK_BIT_X,
+
+	TRACK_BIT_LEFT,
+	0,
+	TRACK_BIT_Y,
+	TRACK_BIT_LOWER,
+
+	TRACK_BIT_LOWER,
+	TRACK_BIT_Y,
+	0,
+	TRACK_BIT_LEFT,
+
+	TRACK_BIT_X,
+	TRACK_BIT_UPPER,
+	TRACK_BIT_RIGHT,
+},
+
+// allowed rail for an evenly raised platform
+{
+	0,
+	TRACK_BIT_LEFT,
+	TRACK_BIT_LOWER,
+	TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
+
+	TRACK_BIT_RIGHT,
+	TRACK_BIT_ALL,
+	TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
+	TRACK_BIT_ALL,
+
+	TRACK_BIT_UPPER,
+	TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
+	TRACK_BIT_ALL,
+	TRACK_BIT_ALL,
+
+	TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
+	TRACK_BIT_ALL,
+	TRACK_BIT_ALL
+}
+};
+
+uint GetRailFoundation(Slope tileh, TrackBits bits)
+{
+	uint i;
+
+	if (!IsSteepSlope(tileh)) {
+		if ((~_valid_tileh_slopes[0][tileh] & bits) == 0) return 0;
+		if ((~_valid_tileh_slopes[1][tileh] & bits) == 0) return tileh;
+	}
+
+	switch (bits) {
+		default: NOT_REACHED();
+		case TRACK_BIT_X: i = 0; break;
+		case TRACK_BIT_Y: i = 1; break;
+		case TRACK_BIT_LEFT:  return 15 + 8 + (tileh == SLOPE_STEEP_W ? 4 : 0);
+		case TRACK_BIT_LOWER: return 15 + 8 + (tileh == SLOPE_STEEP_S ? 5 : 1);
+		case TRACK_BIT_RIGHT: return 15 + 8 + (tileh == SLOPE_STEEP_E ? 6 : 2);
+		case TRACK_BIT_UPPER: return 15 + 8 + (tileh == SLOPE_STEEP_N ? 7 : 3);
+	}
+	switch (tileh) {
+		case SLOPE_W:
+		case SLOPE_STEEP_W: i += 0; break;
+		case SLOPE_S:
+		case SLOPE_STEEP_S: i += 2; break;
+		case SLOPE_E:
+		case SLOPE_STEEP_E: i += 4; break;
+		case SLOPE_N:
+		case SLOPE_STEEP_N: i += 6; break;
+		default: return 0;
+	}
+	return i + 15;
+}
+
+
+static uint32 CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
+{
+	if (IsSteepSlope(tileh)) {
+		if (existing == 0) {
+			TrackBits valid = TRACK_BIT_CROSS | (HASBIT(1 << SLOPE_STEEP_W | 1 << SLOPE_STEEP_E, tileh) ? TRACK_BIT_VERT : TRACK_BIT_HORZ);
+			if (valid & rail_bits) return _price.terraform;
+		}
+	} else {
+		rail_bits |= existing;
+
+		// don't allow building on the lower side of a coast
+		if (IsTileType(tile, MP_WATER) &&
+				~_valid_tileh_slopes[1][tileh] & rail_bits) {
+			return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
+		}
+
+		// no special foundation
+		if ((~_valid_tileh_slopes[0][tileh] & rail_bits) == 0)
+			return 0;
+
+		if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up
+					(rail_bits == TRACK_BIT_X || rail_bits == TRACK_BIT_Y) &&
+					(tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)
+				)) { // partly up
+			if (existing != 0) {
+				return 0;
+			} else if (!_patches.build_on_slopes || _is_old_ai_player) {
+				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+			} else {
+				return _price.terraform;
+			}
+		}
+	}
+	return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+}
+
+/* Validate functions for rail building */
+static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
+
+/** Build a single piece of rail
+ * @param tile tile  to build on
+ * @param p1 railtype of being built piece (normal, mono, maglev)
+ * @param p2 rail track to build
+ */
+int32 CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Slope tileh;
+	RailType railtype;
+	Track track;
+	TrackBits trackbit;
+	int32 cost = 0;
+	int32 ret;
+
+	if (!ValParamRailtype(p1) || !ValParamTrackOrientation(p2)) return CMD_ERROR;
+	railtype = (RailType)p1;
+	track = (Track)p2;
+
+	tileh = GetTileSlope(tile, NULL);
+	trackbit = TrackToTrackBits(track);
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			if (!CheckTrackCombination(tile, trackbit, flags) ||
+					!EnsureNoVehicle(tile)) {
+				return CMD_ERROR;
+			}
+			if (!IsTileOwner(tile, _current_player) ||
+					!IsCompatibleRail(GetRailType(tile), railtype)) {
+				// Get detailed error message
+				return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			}
+
+			ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
+			if (CmdFailed(ret)) return ret;
+			cost += ret;
+
+			/* If the rail types don't match, try to convert only if engines of
+			 * the present rail type are powered on the new rail type. */
+			if (GetRailType(tile) != railtype && HasPowerOnRail(GetRailType(tile), railtype)) {
+				ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
+				if (CmdFailed(ret)) return ret;
+				cost += ret;
+			}
+
+			if (flags & DC_EXEC) {
+				SetRailGroundType(tile, RAIL_GROUND_BARREN);
+				SetTrackBits(tile, GetTrackBits(tile) | trackbit);
+			}
+			break;
+
+		case MP_STREET:
+#define M(x) (1 << (x))
+			/* Level crossings may only be built on these slopes */
+			if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
+				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+			}
+#undef M
+
+			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+			if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
+				if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
+
+				if ((track == TRACK_X && GetRoadBits(tile) == ROAD_Y) ||
+						(track == TRACK_Y && GetRoadBits(tile) == ROAD_X)) {
+					if (flags & DC_EXEC) {
+						MakeRoadCrossing(tile, GetTileOwner(tile), _current_player, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, GetTownIndex(tile));
+					}
+					break;
+				}
+			}
+
+			if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
+				return_cmd_error(STR_1007_ALREADY_BUILT);
+			}
+			/* FALLTHROUGH */
+
+		default:
+			ret = CheckRailSlope(tileh, trackbit, 0, tile);
+			if (CmdFailed(ret)) return ret;
+			cost += ret;
+
+			ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			if (CmdFailed(ret)) return ret;
+			cost += ret;
+
+			if (flags & DC_EXEC) MakeRailNormal(tile, _current_player, trackbit, railtype);
+			break;
+	}
+
+	if (flags & DC_EXEC) {
+		MarkTileDirtyByTile(tile);
+		SetSignalsOnBothDir(tile, track);
+		YapfNotifyTrackLayoutChange(tile, track);
+	}
+
+	return cost + _price.build_rail;
+}
+
+/** Remove a single piece of track
+ * @param tile tile to remove track from
+ * @param p1 unused
+ * @param p2 rail orientation
+ */
+int32 CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Track track = (Track)p2;
+	TrackBits trackbit;
+	int32 cost = _price.remove_rail;
+	bool crossing = false;
+
+	if (!ValParamTrackOrientation(p2)) return CMD_ERROR;
+	trackbit = TrackToTrackBits(track);
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	switch (GetTileType(tile)) {
+		case MP_STREET: {
+			if (!IsLevelCrossing(tile) ||
+					GetCrossingRailBits(tile) != trackbit ||
+					(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
+					!EnsureNoVehicle(tile)) {
+				return CMD_ERROR;
+			}
+
+			if (flags & DC_EXEC) {
+				MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile));
+			}
+			break;
+		}
+
+		case MP_RAILWAY: {
+			TrackBits present;
+
+			if (!IsPlainRailTile(tile) ||
+					(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
+					!EnsureNoVehicle(tile)) {
+				return CMD_ERROR;
+			}
+
+			present = GetTrackBits(tile);
+			if ((present & trackbit) == 0) return CMD_ERROR;
+			if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
+
+			/* Charge extra to remove signals on the track, if they are there */
+			if (HasSignalOnTrack(tile, track))
+				cost += DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS);
+
+			if (flags & DC_EXEC) {
+				present ^= trackbit;
+				if (present == 0) {
+					DoClearSquare(tile);
+				} else {
+					SetTrackBits(tile, present);
+				}
+			}
+			break;
+		}
+
+		default: return CMD_ERROR;
+	}
+
+	if (flags & DC_EXEC) {
+		MarkTileDirtyByTile(tile);
+		if (crossing) {
+			/* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we
+			 * are removing one of these pieces, we'll need to update signals for
+			 * both directions explicitly, as after the track is removed it won't
+			 * 'connect' with the other piece. */
+			SetSignalsOnBothDir(tile, TRACK_X);
+			SetSignalsOnBothDir(tile, TRACK_Y);
+			YapfNotifyTrackLayoutChange(tile, TRACK_X);
+			YapfNotifyTrackLayoutChange(tile, TRACK_Y);
+		} else {
+			SetSignalsOnBothDir(tile, track);
+			YapfNotifyTrackLayoutChange(tile, track);
+		}
+	}
+
+	return cost;
+}
+
+
+static const TileIndexDiffC _trackdelta[] = {
+	{ -1,  0 }, {  0,  1 }, { -1,  0 }, {  0,  1 }, {  1,  0 }, {  0,  1 },
+	{  0,  0 },
+	{  0,  0 },
+	{  1,  0 }, {  0, -1 }, {  0, -1 }, {  1,  0 }, {  0, -1 }, { -1,  0 },
+	{  0,  0 },
+	{  0,  0 }
+};
+
+
+static int32 ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
+{
+	int x = TileX(start);
+	int y = TileY(start);
+	int ex = TileX(end);
+	int ey = TileY(end);
+	int dx, dy, trdx, trdy;
+
+	if (!ValParamTrackOrientation(*trackdir)) return CMD_ERROR;
+
+	// calculate delta x,y from start to end tile
+	dx = ex - x;
+	dy = ey - y;
+
+	// calculate delta x,y for the first direction
+	trdx = _trackdelta[*trackdir].x;
+	trdy = _trackdelta[*trackdir].y;
+
+	if (!IsDiagonalTrackdir(*trackdir)) {
+		trdx += _trackdelta[*trackdir ^ 1].x;
+		trdy += _trackdelta[*trackdir ^ 1].y;
+	}
+
+	// validate the direction
+	while (
+		(trdx <= 0 && dx > 0) ||
+		(trdx >= 0 && dx < 0) ||
+		(trdy <= 0 && dy > 0) ||
+		(trdy >= 0 && dy < 0)
+	) {
+		if (!HASBIT(*trackdir, 3)) { // first direction is invalid, try the other
+			SETBIT(*trackdir, 3); // reverse the direction
+			trdx = -trdx;
+			trdy = -trdy;
+		} else { // other direction is invalid too, invalid drag
+			return CMD_ERROR;
+		}
+	}
+
+	// (for diagonal tracks, this is already made sure of by above test), but:
+	// for non-diagonal tracks, check if the start and end tile are on 1 line
+	if (!IsDiagonalTrackdir(*trackdir)) {
+		trdx = _trackdelta[*trackdir].x;
+		trdy = _trackdelta[*trackdir].y;
+		if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
+			return CMD_ERROR;
+	}
+
+	return 0;
+}
+
+/** Build a stretch of railroad tracks.
+ * @param tile start tile of drag
+ * @param p1 end tile of drag
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev)
+ * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum)
+ * - p2 = (bit 7)   - 0 = build, 1 = remove tracks
+ */
+static int32 CmdRailTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 ret, total_cost = 0;
+	Track track = (Track)GB(p2, 4, 3);
+	Trackdir trackdir;
+	byte mode = HASBIT(p2, 7);
+	RailType railtype = (RailType)GB(p2, 0, 4);
+	TileIndex end_tile;
+
+	if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
+	if (p1 >= MapSize()) return CMD_ERROR;
+	end_tile = p1;
+	trackdir = TrackToTrackdir(track);
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
+
+	if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
+
+	for (;;) {
+		ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL);
+
+		if (CmdFailed(ret)) {
+			if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0)) break;
+			_error_message = INVALID_STRING_ID;
+		} else {
+			total_cost += ret;
+		}
+
+		if (tile == end_tile) break;
+
+		tile += ToTileIndexDiff(_trackdelta[trackdir]);
+
+		// toggle railbit for the non-diagonal tracks
+		if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1;
+	}
+
+	return (total_cost == 0) ? CMD_ERROR : total_cost;
+}
+
+/** Build rail on a stretch of track.
+ * Stub for the unified rail builder/remover
+ * @see CmdRailTrackHelper
+ */
+int32 CmdBuildRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdRailTrackHelper(tile, flags, p1, CLRBIT(p2, 7));
+}
+
+/** Build rail on a stretch of track.
+ * Stub for the unified rail builder/remover
+ * @see CmdRailTrackHelper
+ */
+int32 CmdRemoveRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdRailTrackHelper(tile, flags, p1, SETBIT(p2, 7));
+}
+
+/** Build a train depot
+ * @param tile position of the train depot
+ * @param p1 rail type
+ * @param p2 entrance direction (DiagDirection)
+ *
+ * @todo When checking for the tile slope,
+ * distingush between "Flat land required" and "land sloped in wrong direction"
+ */
+int32 CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Depot *d;
+	int32 cost, ret;
+	Slope tileh;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+	/* check railtype and valid direction for depot (0 through 3), 4 in total */
+	if (!ValParamRailtype(p1) || p2 > 3) return CMD_ERROR;
+
+	tileh = GetTileSlope(tile, NULL);
+
+	/* Prohibit construction if
+	 * The tile is non-flat AND
+	 * 1) The AI is "old-school"
+	 * 2) build-on-slopes is disabled
+	 * 3) the tile is steep i.e. spans two height levels
+	 * 4) the exit points in the wrong direction
+	 */
+
+	if (tileh != SLOPE_FLAT && (
+				_is_old_ai_player ||
+				!_patches.build_on_slopes ||
+				IsSteepSlope(tileh) ||
+				!CanBuildDepotByTileh(p2, tileh)
+			)) {
+		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+	}
+
+	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+	cost = ret;
+
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
+	d = AllocateDepot();
+	if (d == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		MakeRailDepot(tile, _current_player, p2, p1);
+		MarkTileDirtyByTile(tile);
+
+		d->xy = tile;
+		d->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
+
+		UpdateSignalsOnSegment(tile, p2);
+		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(p2)));
+	}
+
+	return cost + _price.build_train_depot;
+}
+
+/** Build signals, alternate between double/single, signal/semaphore,
+ * pre/exit/combo-signals, and what-else not
+ * @param tile tile where to build the signals
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum)
+ * - p1 = (bit 3)   - choose semaphores/signals or cycle normal/pre/exit/combo depending on context
+ * @param p2 used for CmdBuildManySignals() to copy direction of first signal
+ * TODO: p2 should be replaced by two bits for "along" and "against" the track.
+ */
+int32 CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	SignalVariant sigvar;
+	bool pre_signal;
+	Track track = (Track)(p1 & 0x7);
+	int32 cost;
+
+	// Same bit, used in different contexts
+	sigvar = HASBIT(p1, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC;
+	pre_signal = HASBIT(p1, 3);
+
+	if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicle(tile))
+		return CMD_ERROR;
+
+	/* Protect against invalid signal copying */
+	if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
+
+	/* You can only build signals on plain rail tiles, and the selected track must exist */
+	if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) return CMD_ERROR;
+
+	if (!CheckTileOwnership(tile)) return CMD_ERROR;
+
+	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
+
+	{
+		/* See if this is a valid track combination for signals, (ie, no overlap) */
+		TrackBits trackbits = GetTrackBits(tile);
+		if (KILL_FIRST_BIT(trackbits) != 0 && /* More than one track present */
+				trackbits != TRACK_BIT_HORZ &&
+				trackbits != TRACK_BIT_VERT) {
+			return CMD_ERROR;
+		}
+	}
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!HasSignalOnTrack(tile, track)) {
+		// build new signals
+		cost = _price.build_signals;
+	} else {
+		if (p2 != 0 && sigvar != GetSignalVariant(tile)) {
+			// convert signals <-> semaphores
+			cost = _price.build_signals + _price.remove_signals;
+		} else {
+			// it is free to change orientation/pre-exit-combo signals
+			cost = 0;
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		if (!HasSignals(tile)) {
+			// there are no signals at all on this tile yet
+			_m[tile].m5 |= RAIL_TILE_SIGNALS; // change into signals
+			_m[tile].m2 |= 0xF0;              // all signals are on
+			_m[tile].m3 &= ~0xF0;          // no signals built by default
+			SetSignalType(tile, SIGTYPE_NORMAL);
+			SetSignalVariant(tile, sigvar);
+		}
+
+		if (p2 == 0) {
+			if (!HasSignalOnTrack(tile, track)) {
+				// build new signals
+				_m[tile].m3 |= SignalOnTrack(track);
+			} else {
+				if (pre_signal) {
+					// cycle between normal -> pre -> exit -> combo -> ...
+					SignalType type = GetSignalType(tile);
+
+					SetSignalType(tile, type == SIGTYPE_COMBO ? SIGTYPE_NORMAL : type + 1);
+				} else {
+					CycleSignalSide(tile, track);
+				}
+			}
+		} else {
+			/* If CmdBuildManySignals is called with copying signals, just copy the
+			 * direction of the first signal given as parameter by CmdBuildManySignals */
+			_m[tile].m3 &= ~SignalOnTrack(track);
+			_m[tile].m3 |= p2 & SignalOnTrack(track);
+			SetSignalVariant(tile, sigvar);
+		}
+
+		MarkTileDirtyByTile(tile);
+		SetSignalsOnBothDir(tile, track);
+		YapfNotifyTrackLayoutChange(tile, track);
+	}
+
+	return cost;
+}
+
+/** Build many signals by dragging; AutoSignals
+ * @param tile start tile of drag
+ * @param p1  end tile of drag
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit  0)    - 0 = build, 1 = remove signals
+ * - p2 = (bit  3)    - 0 = signals, 1 = semaphores
+ * - p2 = (bit  4- 6) - track-orientation, valid values: 0-5 (Track enum)
+ * - p2 = (bit 24-31) - user defined signals_density
+ */
+static int32 CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 ret, total_cost, signal_ctr;
+	byte signals;
+	bool error = true;
+	TileIndex end_tile;
+
+	int mode = p2 & 0x1;
+	Track track = GB(p2, 4, 3);
+	Trackdir trackdir = TrackToTrackdir(track);
+	byte semaphores = (HASBIT(p2, 3) ? 8 : 0);
+	byte signal_density = (p2 >> 24);
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+	end_tile = p1;
+	if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
+
+	if (!IsTileType(tile, MP_RAILWAY)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* for vertical/horizontal tracks, double the given signals density
+	 * since the original amount will be too dense (shorter tracks) */
+	if (!IsDiagonalTrack(track)) signal_density *= 2;
+
+	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
+
+	track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */
+
+	// copy the signal-style of the first rail-piece if existing
+	if (HasSignals(tile)) {
+		signals = _m[tile].m3 & SignalOnTrack(track);
+		if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */
+
+		// copy signal/semaphores style (independent of CTRL)
+		semaphores = (GetSignalVariant(tile) == SIG_ELECTRIC ? 0 : 8);
+	} else { // no signals exist, drag a two-way signal stretch
+		signals = SignalOnTrack(track);
+	}
+
+	/* signal_ctr         - amount of tiles already processed
+	 * signals_density    - patch setting to put signal on every Nth tile (double space on |, -- tracks)
+	 **********
+	 * trackdir   - trackdir to build with autorail
+	 * semaphores - semaphores or signals
+	 * signals    - is there a signal/semaphore on the first tile, copy its style (two-way/single-way)
+	 *              and convert all others to semaphore/signal
+	 * mode       - 1 remove signals, 0 build signals */
+	signal_ctr = total_cost = 0;
+	for (;;) {
+		// only build/remove signals with the specified density
+		if (signal_ctr % signal_density == 0) {
+			ret = DoCommand(tile, TrackdirToTrack(trackdir) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
+
+			/* Be user-friendly and try placing signals as much as possible */
+			if (!CmdFailed(ret)) {
+				error = false;
+				total_cost += ret;
+			}
+		}
+
+		if (tile == end_tile) break;
+
+		tile += ToTileIndexDiff(_trackdelta[trackdir]);
+		signal_ctr++;
+
+		// toggle railbit for the non-diagonal tracks (|, -- tracks)
+		if (!IsDiagonalTrackdir(trackdir)) trackdir ^= 1;
+	}
+
+	return error ? CMD_ERROR : total_cost;
+}
+
+/** Build signals on a stretch of track.
+ * Stub for the unified signal builder/remover
+ * @see CmdSignalTrackHelper
+ */
+int32 CmdBuildSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdSignalTrackHelper(tile, flags, p1, p2);
+}
+
+/** Remove signals
+ * @param tile coordinates where signal is being deleted from
+ * @param p1 track to remove signal from (Track enum)
+ */
+int32 CmdRemoveSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Track track = (Track)(p1 & 0x7);
+
+	if (!ValParamTrackOrientation(track) ||
+			!IsTileType(tile, MP_RAILWAY) ||
+			!EnsureNoVehicle(tile) ||
+			!HasSignalOnTrack(tile, track)) {
+		return CMD_ERROR;
+	}
+
+	/* Only water can remove signals from anyone */
+	if (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* Do it? */
+	if (flags & DC_EXEC) {
+		_m[tile].m3 &= ~SignalOnTrack(track);
+
+		/* removed last signal from tile? */
+		if (GB(_m[tile].m3, 4, 4) == 0) {
+			SB(_m[tile].m2, 4, 4, 0);
+			SB(_m[tile].m5, 6, 2, RAIL_TILE_NORMAL >> 6); // XXX >> because the constant is meant for direct application, not use with SB
+			SetSignalVariant(tile, SIG_ELECTRIC); // remove any possible semaphores
+		}
+
+		SetSignalsOnBothDir(tile, track);
+		YapfNotifyTrackLayoutChange(tile, track);
+
+		MarkTileDirtyByTile(tile);
+	}
+
+	return _price.remove_signals;
+}
+
+/** Remove signals on a stretch of track.
+ * Stub for the unified signal builder/remover
+ * @see CmdSignalTrackHelper
+ */
+int32 CmdRemoveSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdSignalTrackHelper(tile, flags, p1, SETBIT(p2, 0));
+}
+
+typedef int32 DoConvertRailProc(TileIndex tile, RailType totype, bool exec);
+
+static int32 DoConvertRail(TileIndex tile, RailType totype, bool exec)
+{
+	if (!CheckTileOwnership(tile)) return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) return CMD_ERROR;
+
+	// tile is already of requested type?
+	if (GetRailType(tile) == totype) return CMD_ERROR;
+
+	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
+	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
+
+	// change type.
+	if (exec) {
+		TrackBits tracks;
+		SetRailType(tile, totype);
+		MarkTileDirtyByTile(tile);
+
+		// notify YAPF about the track layout change
+		for (tracks = GetTrackBits(tile); tracks != TRACK_BIT_NONE; tracks = KILL_FIRST_BIT(tracks))
+			YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(tracks));
+
+		if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
+			Vehicle *v;
+
+			/* Update build vehicle window related to this depot */
+			InvalidateWindowData(WC_BUILD_VEHICLE, tile);
+
+			/* update power of trains in this depot */
+			FOR_ALL_VEHICLES(v) {
+				if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == tile && v->u.rail.track == 0x80) {
+					TrainPowerChanged(v);
+				}
+			}
+		}
+	}
+
+	return _price.build_rail / 2;
+}
+
+extern int32 DoConvertStationRail(TileIndex tile, RailType totype, bool exec);
+extern int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec);
+extern int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec);
+
+/** Convert one rail type to the other. You can convert normal rail to
+ * monorail/maglev easily or vice-versa.
+ * @param tile end tile of rail conversion drag
+ * @param p1 start tile of drag
+ * @param p2 new railtype to convert to
+ */
+int32 CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 ret, cost, money;
+	int ex;
+	int ey;
+	int sx, sy, x, y;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!ValParamRailtype(p2)) return CMD_ERROR;
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	// make sure sx,sy are smaller than ex,ey
+	ex = TileX(tile);
+	ey = TileY(tile);
+	sx = TileX(p1);
+	sy = TileY(p1);
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+
+	money = GetAvailableMoneyForCommand();
+	cost = 0;
+	ret = 0;
+
+	for (x = sx; x <= ex; ++x) {
+		for (y = sy; y <= ey; ++y) {
+			TileIndex tile = TileXY(x, y);
+			DoConvertRailProc* proc;
+
+			switch (GetTileType(tile)) {
+				case MP_RAILWAY:      proc = DoConvertRail;             break;
+				case MP_STATION:      proc = DoConvertStationRail;      break;
+				case MP_STREET:       proc = DoConvertStreetRail;       break;
+				case MP_TUNNELBRIDGE: proc = DoConvertTunnelBridgeRail; break;
+				default: continue;
+			}
+
+			ret = proc(tile, p2, false);
+			if (CmdFailed(ret)) continue;
+			cost += ret;
+
+			if (flags & DC_EXEC) {
+				money -= ret;
+				if (money < 0) {
+					_additional_cash_required = ret;
+					return cost - ret;
+				}
+				proc(tile, p2, true);
+			}
+		}
+	}
+
+	return (cost == 0) ? ret : cost;
+}
+
+static int32 RemoveTrainDepot(TileIndex tile, uint32 flags)
+{
+	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
+		return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile))
+		return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		DiagDirection dir = GetRailDepotDirection(tile);
+
+		DeleteDepot(GetDepotByTile(tile));
+		UpdateSignalsOnSegment(tile, dir);
+		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
+	}
+
+	return _price.remove_train_depot;
+}
+
+static int32 ClearTile_Track(TileIndex tile, byte flags)
+{
+	int32 cost;
+	int32 ret;
+
+	if (flags & DC_AUTO) {
+		if (!IsTileOwner(tile, _current_player))
+			return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
+
+		if (IsPlainRailTile(tile)) {
+			return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
+		} else {
+			return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+		}
+	}
+
+	cost = 0;
+
+	switch (GetRailTileType(tile)) {
+		case RAIL_TILE_SIGNALS:
+		case RAIL_TILE_NORMAL: {
+			TrackBits tracks = GetTrackBits(tile);
+			uint i;
+
+			for_each_bit (i, tracks) {
+				ret = DoCommand(tile, 0, i, flags, CMD_REMOVE_SINGLE_RAIL);
+				if (CmdFailed(ret)) return CMD_ERROR;
+				cost += ret;
+			}
+			return cost;
+		}
+
+		case RAIL_TILE_DEPOT_WAYPOINT:
+			if (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) {
+				return RemoveTrainDepot(tile, flags);
+			} else {
+				return RemoveTrainWaypoint(tile, flags, false);
+			}
+
+		default:
+			return CMD_ERROR;
+	}
+}
+
+#include "table/track_land.h"
+
+static void DrawSingleSignal(TileIndex tile, byte condition, uint image, uint pos)
+{
+	bool side = _opt.road_side & _patches.signal_side;
+	static const Point SignalPositions[2][12] = {
+		{      /* Signals on the left side */
+		/*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
+			{ 8,  5}, {14,  1}, { 1, 14}, { 9, 11}, { 1,  0}, { 3, 10},
+		/*  LOWER     LOWER     X         X         Y         Y     */
+			{11,  4}, {14, 14}, {11,  3}, { 4, 13}, { 3,  4}, {11, 13}
+		}, {   /* Signals on the right side */
+		/*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
+			{14,  1}, {12, 10}, { 4,  6}, { 1, 14}, {10,  4}, { 0,  1},
+		/*  LOWER     LOWER     X         X         Y         Y     */
+			{14, 14}, { 5, 12}, {11, 13}, { 4,  3}, {13,  4}, { 3, 11}
+		}
+	};
+
+	static const SpriteID SignalBase[2][2][4] = {
+		{    /* Signals on left side */
+			{  0x4FB, 0x1323, 0x1333, 0x1343}, /* light signals */
+			{ 0x1353, 0x1363, 0x1373, 0x1383}  /* semaphores    */
+		}, { /* Signals on right side */
+			{  0x4FB, 0x1323, 0x1333, 0x1343}, /* light signals */
+			{ 0x1446, 0x1456, 0x1466, 0x1476}  /* semaphores    */
+		/*         |       |       |       |     */
+		/*    normal,  entry,   exit,  combo     */
+		}
+	};
+
+	uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
+	uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
+
+	SpriteID sprite;
+
+	/* _signal_base is set by our NewGRF Action 5 loader. If it is 0 then we
+	 * just draw the standard signals, else we get the offset from _signal_base
+	 * and draw that sprite. All the signal sprites are loaded sequentially. */
+	if (_signal_base == 0 || (GetSignalType(tile) == 0 && GetSignalVariant(tile) == SIG_ELECTRIC)) {
+		sprite = SignalBase[side][GetSignalVariant(tile)][GetSignalType(tile)] + image + condition;
+	} else {
+		sprite = _signal_base + (GetSignalType(tile) - 1) * 16 + GetSignalVariant(tile) * 64 + image + condition;
+	}
+
+	AddSortableSpriteToDraw(sprite, x, y, 1, 1, 10, GetSlopeZ(x,y));
+}
+
+static uint32 _drawtile_track_palette;
+
+
+static void DrawTrackFence_NW(const TileInfo *ti)
+{
+	uint32 image = 0x515;
+	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x519 : 0x51B;
+	AddSortableSpriteToDraw(image | _drawtile_track_palette,
+		ti->x, ti->y + 1, 16, 1, 4, ti->z);
+}
+
+static void DrawTrackFence_SE(const TileInfo *ti)
+{
+	uint32 image = 0x515;
+	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x519 : 0x51B;
+	AddSortableSpriteToDraw(image | _drawtile_track_palette,
+		ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
+}
+
+static void DrawTrackFence_NW_SE(const TileInfo *ti)
+{
+	DrawTrackFence_NW(ti);
+	DrawTrackFence_SE(ti);
+}
+
+static void DrawTrackFence_NE(const TileInfo *ti)
+{
+	uint32 image = 0x516;
+	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x51A : 0x51C;
+	AddSortableSpriteToDraw(image | _drawtile_track_palette,
+		ti->x + 1, ti->y, 1, 16, 4, ti->z);
+}
+
+static void DrawTrackFence_SW(const TileInfo *ti)
+{
+	uint32 image = 0x516;
+	if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? 0x51A : 0x51C;
+	AddSortableSpriteToDraw(image | _drawtile_track_palette,
+		ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
+}
+
+static void DrawTrackFence_NE_SW(const TileInfo *ti)
+{
+	DrawTrackFence_NE(ti);
+	DrawTrackFence_SW(ti);
+}
+
+static void DrawTrackFence_NS_1(const TileInfo *ti)
+{
+	int z = ti->z;
+	if (ti->tileh & SLOPE_W) z += TILE_HEIGHT;
+	AddSortableSpriteToDraw(0x517 | _drawtile_track_palette,
+		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
+}
+
+static void DrawTrackFence_NS_2(const TileInfo *ti)
+{
+	int z = ti->z;
+	if (ti->tileh & SLOPE_E) z += TILE_HEIGHT;
+	AddSortableSpriteToDraw(0x517 | _drawtile_track_palette,
+		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
+}
+
+static void DrawTrackFence_WE_1(const TileInfo *ti)
+{
+	int z = ti->z;
+	if (ti->tileh & SLOPE_N) z += TILE_HEIGHT;
+	AddSortableSpriteToDraw(0x518 | _drawtile_track_palette,
+		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
+}
+
+static void DrawTrackFence_WE_2(const TileInfo *ti)
+{
+	int z = ti->z;
+	if (ti->tileh & SLOPE_S) z += TILE_HEIGHT;
+	AddSortableSpriteToDraw(0x518 | _drawtile_track_palette,
+		ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
+}
+
+
+static void DrawTrackDetails(const TileInfo* ti)
+{
+	switch (GetRailGroundType(ti->tile)) {
+		case RAIL_GROUND_FENCE_NW:     DrawTrackFence_NW(ti);    break;
+		case RAIL_GROUND_FENCE_SE:     DrawTrackFence_SE(ti);    break;
+		case RAIL_GROUND_FENCE_SENW:   DrawTrackFence_NW_SE(ti); break;
+		case RAIL_GROUND_FENCE_NE:     DrawTrackFence_NE(ti);    break;
+		case RAIL_GROUND_FENCE_SW:     DrawTrackFence_SW(ti);    break;
+		case RAIL_GROUND_FENCE_NESW:   DrawTrackFence_NE_SW(ti); break;
+		case RAIL_GROUND_FENCE_VERT1:  DrawTrackFence_NS_1(ti);  break;
+		case RAIL_GROUND_FENCE_VERT2:  DrawTrackFence_NS_2(ti);  break;
+		case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti);  break;
+		case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti);  break;
+		default: break;
+	}
+}
+
+
+/**
+ * Draw ground sprite and track bits
+ * @param ti TileInfo
+ * @param track TrackBits to draw
+ * @param earth Draw as earth
+ * @param snow Draw as snow
+ * @param flat Always draw foundation
+ */
+static void DrawTrackBits(TileInfo* ti, TrackBits track)
+{
+	const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
+	PalSpriteID image;
+	bool junction = false;
+
+	// Select the sprite to use.
+	(image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
+	(image++,                           track == TRACK_BIT_X) ||
+	(image++,                           track == TRACK_BIT_UPPER) ||
+	(image++,                           track == TRACK_BIT_LOWER) ||
+	(image++,                           track == TRACK_BIT_RIGHT) ||
+	(image++,                           track == TRACK_BIT_LEFT) ||
+	(image++,                           track == TRACK_BIT_CROSS) ||
+
+	(image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
+	(image++,                            track == TRACK_BIT_VERT) ||
+
+	(junction = true, false) ||
+	(image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
+	(image++,                          (track & TRACK_BIT_3WAY_SW) == 0) ||
+	(image++,                          (track & TRACK_BIT_3WAY_NW) == 0) ||
+	(image++,                          (track & TRACK_BIT_3WAY_SE) == 0) ||
+	(image++, true);
+
+	if (ti->tileh != SLOPE_FLAT) {
+		uint foundation = GetRailFoundation(ti->tileh, track);
+
+		if (foundation != 0) DrawFoundation(ti, foundation);
+
+		// DrawFoundation() modifies ti.
+		// Default sloped sprites..
+		if (ti->tileh != SLOPE_FLAT)
+			image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
+	}
+
+	switch (GetRailGroundType(ti->tile)) {
+		case RAIL_GROUND_BARREN:     image |= PALETTE_TO_BARE_LAND; break;
+		case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
+		default: break;
+	}
+
+	DrawGroundSprite(image);
+
+	// Draw track pieces individually for junction tiles
+	if (junction) {
+		if (track & TRACK_BIT_X)     DrawGroundSprite(rti->base_sprites.single_y);
+		if (track & TRACK_BIT_Y)     DrawGroundSprite(rti->base_sprites.single_x);
+		if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n);
+		if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s);
+		if (track & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w);
+		if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e);
+	}
+
+	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+}
+
+static void DrawSignals(TileIndex tile, TrackBits rails)
+{
+#define MAYBE_DRAW_SIGNAL(x,y,z) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, GetSingleSignalState(tile, x), y - 0x4FB, z)
+
+	if (!(rails & TRACK_BIT_Y)) {
+		if (!(rails & TRACK_BIT_X)) {
+			if (rails & TRACK_BIT_LEFT) {
+				MAYBE_DRAW_SIGNAL(2, 0x509, 0);
+				MAYBE_DRAW_SIGNAL(3, 0x507, 1);
+			}
+			if (rails & TRACK_BIT_RIGHT) {
+				MAYBE_DRAW_SIGNAL(0, 0x509, 2);
+				MAYBE_DRAW_SIGNAL(1, 0x507, 3);
+			}
+			if (rails & TRACK_BIT_UPPER) {
+				MAYBE_DRAW_SIGNAL(3, 0x505, 4);
+				MAYBE_DRAW_SIGNAL(2, 0x503, 5);
+			}
+			if (rails & TRACK_BIT_LOWER) {
+				MAYBE_DRAW_SIGNAL(1, 0x505, 6);
+				MAYBE_DRAW_SIGNAL(0, 0x503, 7);
+			}
+		} else {
+			MAYBE_DRAW_SIGNAL(3, 0x4FB, 8);
+			MAYBE_DRAW_SIGNAL(2, 0x4FD, 9);
+		}
+	} else {
+		MAYBE_DRAW_SIGNAL(3, 0x4FF, 10);
+		MAYBE_DRAW_SIGNAL(2, 0x501, 11);
+	}
+}
+
+static void DrawTile_Track(TileInfo *ti)
+{
+	const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
+	PalSpriteID image;
+
+	_drawtile_track_palette = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)));
+
+	if (IsPlainRailTile(ti->tile)) {
+		TrackBits rails = GetTrackBits(ti->tile);
+
+		DrawTrackBits(ti, rails);
+
+		if (_display_opt & DO_FULL_DETAIL) DrawTrackDetails(ti);
+
+		if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
+	} else {
+		// draw depot/waypoint
+		const DrawTileSprites* dts;
+		const DrawTileSeqStruct* dtss;
+		uint32 relocation;
+
+		if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+
+		if (GetRailTileSubtype(ti->tile) == RAIL_SUBTYPE_DEPOT) {
+			dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
+
+			relocation = rti->total_offset;
+
+			image = dts->ground_sprite;
+			if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
+
+			// adjust ground tile for desert
+			// don't adjust for snow, because snow in depots looks weird
+			if (IsSnowRailGround(ti->tile) && _opt.landscape == LT_DESERT) {
+				if (image != SPR_FLAT_GRASS_TILE) {
+					image += rti->snow_offset; // tile with tracks
+				} else {
+					image = SPR_FLAT_SNOWY_TILE; // flat ground
+				}
+			}
+		} else {
+			// look for customization
+			byte stat_id = GetWaypointByTile(ti->tile)->stat_id;
+			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id);
+
+			if (statspec != NULL) {
+				// emulate station tile - open with building
+				const Station* st = ComposeWaypointStation(ti->tile);
+				uint gfx = 2;
+
+				if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
+					uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
+					if (callback != CALLBACK_FAILED) gfx = callback;
+				}
+
+				if (statspec->renderdata == NULL) {
+					dts = GetStationTileLayout(gfx);
+				} else {
+					dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
+				}
+
+				if (dts != NULL && dts->seq != NULL) {
+					relocation = GetCustomStationRelocation(statspec, st, ti->tile);
+
+					image = dts->ground_sprite;
+					if (HASBIT(image, 31)) {
+						CLRBIT(image, 31);
+						image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
+						image += rti->custom_ground_offset;
+					} else {
+						image += rti->total_offset;
+					}
+				} else {
+					goto default_waypoint;
+				}
+			} else {
+default_waypoint:
+				// There is no custom layout, fall back to the default graphics
+				dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)];
+				relocation = 0;
+				image = dts->ground_sprite + rti->total_offset;
+				if (IsSnowRailGround(ti->tile)) image += rti->snow_offset;
+			}
+		}
+
+		DrawGroundSprite(image);
+
+		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+		foreach_draw_tile_seq(dtss, dts->seq) {
+			uint32 image = dtss->image + relocation;
+
+			if (_display_opt & DO_TRANS_BUILDINGS) {
+				MAKE_TRANSPARENT(image);
+			} else if (image & PALETTE_MODIFIER_COLOR) {
+				image |= _drawtile_track_palette;
+			}
+			AddSortableSpriteToDraw(
+				image,
+				ti->x + dtss->delta_x, ti->y + dtss->delta_y,
+				dtss->size_x, dtss->size_y,
+				dtss->size_z, ti->z + dtss->delta_z
+			);
+		}
+	}
+	DrawBridgeMiddle(ti);
+}
+
+
+static void DrawTileSequence(int x, int y, uint32 ground, const DrawTileSeqStruct* dtss, uint32 offset)
+{
+	uint32 palette = PLAYER_SPRITE_COLOR(_local_player);
+
+	DrawSprite(ground, x, y);
+	for (; dtss->image != 0; dtss++) {
+		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
+		uint32 image = dtss->image + offset;
+
+		if (image & PALETTE_MODIFIER_COLOR) image |= palette;
+		DrawSprite(image, x + pt.x, y + pt.y);
+	}
+}
+
+void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
+{
+	const DrawTileSprites* dts = &_depot_gfx_table[dir];
+	uint32 image = dts->ground_sprite;
+	uint32 offset = GetRailTypeInfo(railtype)->total_offset;
+
+	if (image != SPR_FLAT_GRASS_TILE) image += offset;
+	DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
+}
+
+void DrawDefaultWaypointSprite(int x, int y, RailType railtype)
+{
+	uint32 offset = GetRailTypeInfo(railtype)->total_offset;
+	const DrawTileSprites* dts = &_waypoint_gfx_table[AXIS_X];
+
+	DrawTileSequence(x, y, dts->ground_sprite + offset, dts->seq, 0);
+}
+
+typedef struct SetSignalsData {
+	int cur;
+	int cur_stack;
+	bool stop;
+	bool has_presignal;
+
+	// presignal info
+	int presignal_exits;
+	int presignal_exits_free;
+
+	// these are used to keep track of the signals that change.
+	byte bit[NUM_SSD_ENTRY];
+	TileIndex tile[NUM_SSD_ENTRY];
+
+	// these are used to keep track of the stack that modifies presignals recursively
+	TileIndex next_tile[NUM_SSD_STACK];
+	byte next_dir[NUM_SSD_STACK];
+
+} SetSignalsData;
+
+static bool SetSignalsEnumProc(TileIndex tile, void* data, int track, uint length, byte* state)
+{
+	SetSignalsData* ssd = data;
+
+	if (!IsTileType(tile, MP_RAILWAY)) return false;
+
+	// the tile has signals?
+	if (HasSignalOnTrack(tile, TrackdirToTrack(track))) {
+		if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
+			// yes, add the signal to the list of signals
+			if (ssd->cur != NUM_SSD_ENTRY) {
+				ssd->tile[ssd->cur] = tile; // remember the tile index
+				ssd->bit[ssd->cur] = track; // and the controlling bit number
+				ssd->cur++;
+			}
+
+			// remember if this block has a presignal.
+			ssd->has_presignal |= IsPresignalEntry(tile);
+		}
+
+		if (HasSignalOnTrackdir(tile, track) && IsPresignalExit(tile)) {
+			// this is an exit signal that points out from the segment
+			ssd->presignal_exits++;
+			if (GetSignalStateByTrackdir(tile, track) != SIGNAL_STATE_RED)
+				ssd->presignal_exits_free++;
+		}
+
+		return true;
+	} else if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
+		return true; // don't look further if the tile is a depot
+	}
+
+	return false;
+}
+
+/* Struct to parse data from VehicleFromPos to SignalVehicleCheckProc */
+typedef struct SignalVehicleCheckStruct {
+	TileIndex tile;
+	uint track;
+} SignalVehicleCheckStruct;
+
+static void *SignalVehicleCheckProc(Vehicle *v, void *data)
+{
+	const SignalVehicleCheckStruct* dest = data;
+
+	if (v->type != VEH_Train) return NULL;
+
+	/* Wrong tile, or no train? Not a match */
+	if (v->tile != dest->tile) return NULL;
+
+	/* Are we on the same piece of track? */
+	if (dest->track & v->u.rail.track * 0x101) return v;
+
+	return NULL;
+}
+
+/* Special check for SetSignalsAfterProc, to see if there is a vehicle on this tile */
+static bool SignalVehicleCheck(TileIndex tile, uint track)
+{
+	SignalVehicleCheckStruct dest;
+
+	dest.tile = tile;
+	dest.track = track;
+
+	/* Locate vehicles in tunnels or on bridges */
+	if (IsTunnelTile(tile) || IsBridgeTile(tile)) {
+		TileIndex end;
+		DiagDirection direction;
+
+		if (IsTunnelTile(tile)) {
+			end = GetOtherTunnelEnd(tile);
+			direction = GetTunnelDirection(tile);
+		} else {
+			end = GetOtherBridgeEnd(tile);
+			direction = GetBridgeRampDirection(tile);
+		}
+
+		dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible)
+
+		// check for a vehicle with that trackdir on the start tile of the tunnel
+		if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true;
+
+		// check for a vehicle with that trackdir on the end tile of the tunnel
+		if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
+
+		// now check all tiles from start to end for a warping vehicle
+		// NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile?
+		dest.track = 0x40;   //Vehicle inside a tunnel or on a bridge
+		for (; tile != end; tile += TileOffsByDiagDir(direction)) {
+			if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL)
+				return true;
+		}
+
+		// no vehicle found
+		return false;
+	}
+
+	return VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL;
+}
+
+static void SetSignalsAfterProc(TrackPathFinder *tpf)
+{
+	SetSignalsData *ssd = tpf->userdata;
+	const TrackPathFinderLink* link;
+	uint offs;
+	uint i;
+
+	ssd->stop = false;
+
+	/* Go through all the PF tiles */
+	for (i = 0; i < lengthof(tpf->hash_head); i++) {
+		/* Empty hash item */
+		if (tpf->hash_head[i] == 0) continue;
+
+		/* If 0x8000 is not set, there is only 1 item */
+		if (!(tpf->hash_head[i] & 0x8000)) {
+			/* Check if there is a vehicle on this tile */
+			if (SignalVehicleCheck(tpf->hash_tile[i], tpf->hash_head[i])) {
+				ssd->stop = true;
+				return;
+			}
+		} else {
+			/* There are multiple items, where hash_tile points to the first item in the list */
+			offs = tpf->hash_tile[i];
+			do {
+				/* Find the next item */
+				link = PATHFIND_GET_LINK_PTR(tpf, offs);
+				/* Check if there is a vehicle on this tile */
+				if (SignalVehicleCheck(link->tile, link->flags)) {
+					ssd->stop = true;
+					return;
+				}
+				/* Goto the next item */
+			} while ((offs = link->next) != 0xFFFF);
+		}
+	}
+}
+
+static const byte _dir_from_track[14] = {
+	0,1,0,1,2,1, 0,0,
+	2,3,3,2,3,0,
+};
+
+
+static void ChangeSignalStates(SetSignalsData *ssd)
+{
+	int i;
+
+	// thinking about presignals...
+	// the presignal is green if,
+	//   if no train is in the segment AND
+	//   there is at least one green exit signal OR
+	//   there are no exit signals in the segment
+
+	// then mark the signals in the segment accordingly
+	for (i = 0; i != ssd->cur; i++) {
+		TileIndex tile = ssd->tile[i];
+		byte bit = SignalAgainstTrackdir(ssd->bit[i]);
+		uint16 m2 = _m[tile].m2;
+
+		// presignals don't turn green if there is at least one presignal exit and none are free
+		if (IsPresignalEntry(tile)) {
+			int ex = ssd->presignal_exits, exfree = ssd->presignal_exits_free;
+
+			// subtract for dual combo signals so they don't count themselves
+			if (IsPresignalExit(tile) && HasSignalOnTrackdir(tile, ssd->bit[i])) {
+				ex--;
+				if (GetSignalStateByTrackdir(tile, ssd->bit[i]) != SIGNAL_STATE_RED) exfree--;
+			}
+
+			// if we have exits and none are free, make red.
+			if (ex && !exfree) goto make_red;
+		}
+
+		// check if the signal is unaffected.
+		if (ssd->stop) {
+make_red:
+			// turn red
+			if ((bit & m2) == 0) continue;
+		} else {
+			// turn green
+			if ((bit & m2) != 0) continue;
+		}
+
+		/* Update signals on the other side of this exit-combo signal; it changed. */
+		if (IsPresignalExit(tile)) {
+			if (ssd->cur_stack != NUM_SSD_STACK) {
+				ssd->next_tile[ssd->cur_stack] = tile;
+				ssd->next_dir[ssd->cur_stack] = _dir_from_track[ssd->bit[i]];
+				ssd->cur_stack++;
+			} else {
+				DEBUG(misc, 0, "NUM_SSD_STACK too small"); /// @todo WTF is this???
+			}
+		}
+
+		// it changed, so toggle it
+		_m[tile].m2 = m2 ^ bit;
+		MarkTileDirtyByTile(tile);
+	}
+}
+
+
+bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction)
+{
+	SetSignalsData ssd;
+	int result = -1;
+
+	ssd.cur_stack = 0;
+
+	for (;;) {
+		// go through one segment and update all signals pointing into that segment.
+		ssd.cur = ssd.presignal_exits = ssd.presignal_exits_free = 0;
+		ssd.has_presignal = false;
+
+		FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, SetSignalsEnumProc, SetSignalsAfterProc, &ssd);
+		ChangeSignalStates(&ssd);
+
+		// remember the result only for the first iteration.
+		if (result < 0) {
+			// stay in depot while segment is occupied or while all presignal exits are blocked
+			result = ssd.stop || (ssd.presignal_exits > 0 && ssd.presignal_exits_free == 0);
+		}
+
+		// if any exit signals were changed, we need to keep going to modify the stuff behind those.
+		if (ssd.cur_stack == 0) break;
+
+		// one or more exit signals were changed, so we need to update another segment too.
+		tile = ssd.next_tile[--ssd.cur_stack];
+		direction = ssd.next_dir[ssd.cur_stack];
+	}
+
+	return result != 0;
+}
+
+void SetSignalsOnBothDir(TileIndex tile, byte track)
+{
+	static const DiagDirection _search_dir_1[] = {
+		DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE
+	};
+	static const DiagDirection _search_dir_2[] = {
+		DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
+	};
+
+	UpdateSignalsOnSegment(tile, _search_dir_1[track]);
+	UpdateSignalsOnSegment(tile, _search_dir_2[track]);
+}
+
+static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	Slope tileh = GetTileSlope(tile, &z);
+
+	if (tileh == SLOPE_FLAT) return z;
+	if (IsPlainRailTile(tile)) {
+		uint f = GetRailFoundation(tileh, GetTrackBits(tile));
+
+		if (f != 0) {
+			if (IsSteepSlope(tileh)) {
+				z += TILE_HEIGHT;
+			} else if (f < 15) {
+				return z + TILE_HEIGHT; // leveled foundation
+			}
+			tileh = _inclined_tileh[f - 15]; // inclined foundation
+		}
+		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+	} else {
+		return z + TILE_HEIGHT;
+	}
+}
+
+static Slope GetSlopeTileh_Track(TileIndex tile, Slope tileh)
+{
+	if (tileh == SLOPE_FLAT) return SLOPE_FLAT;
+	if (IsPlainRailTile(tile)) {
+		uint f = GetRailFoundation(tileh, GetTrackBits(tile));
+
+		if (f == 0) return tileh;
+		if (f < 15) return SLOPE_FLAT; // leveled foundation
+		return _inclined_tileh[f - 15]; // inclined foundation
+	} else {
+		return SLOPE_FLAT;
+	}
+}
+
+static void GetAcceptedCargo_Track(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void AnimateTile_Track(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoop_Track(TileIndex tile)
+{
+	RailGroundType old_ground = GetRailGroundType(tile);
+	RailGroundType new_ground;
+
+	switch (_opt.landscape) {
+		case LT_HILLY:
+			if (GetTileZ(tile) > _opt.snow_line) {
+				new_ground = RAIL_GROUND_ICE_DESERT;
+				goto set_ground;
+			}
+			break;
+
+		case LT_DESERT:
+			if (GetTropicZone(tile) == TROPICZONE_DESERT) {
+				new_ground = RAIL_GROUND_ICE_DESERT;
+				goto set_ground;
+			}
+			break;
+	}
+
+	if (!IsPlainRailTile(tile)) return;
+
+	new_ground = RAIL_GROUND_GRASS;
+
+	if (old_ground != RAIL_GROUND_BARREN) { /* wait until bottom is green */
+		/* determine direction of fence */
+		TrackBits rail = GetTrackBits(tile);
+
+		switch (rail) {
+			case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
+			case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
+			case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
+			case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
+
+			default: {
+				PlayerID owner = GetTileOwner(tile);
+
+				if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
+							(rail & TRACK_BIT_3WAY_NW) == 0 &&
+							(rail & TRACK_BIT_X)
+						)) {
+					TileIndex n = tile + TileDiffXY(0, -1);
+					TrackBits nrail = GetTrackBits(n);
+
+					if (!IsTileType(n, MP_RAILWAY) ||
+							!IsTileOwner(n, owner) ||
+							nrail == TRACK_BIT_UPPER ||
+							nrail == TRACK_BIT_LEFT) {
+						new_ground = RAIL_GROUND_FENCE_NW;
+					}
+				}
+
+				if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
+							(rail & TRACK_BIT_3WAY_SE) == 0 &&
+							(rail & TRACK_BIT_X)
+						)) {
+					TileIndex n = tile + TileDiffXY(0, 1);
+					TrackBits nrail = GetTrackBits(n);
+
+					if (!IsTileType(n, MP_RAILWAY) ||
+							!IsTileOwner(n, owner) ||
+							nrail == TRACK_BIT_LOWER ||
+							nrail == TRACK_BIT_RIGHT) {
+						new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
+							RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
+					}
+				}
+
+				if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
+							(rail & TRACK_BIT_3WAY_NE) == 0 &&
+							(rail & TRACK_BIT_Y)
+						)) {
+					TileIndex n = tile + TileDiffXY(-1, 0);
+					TrackBits nrail = GetTrackBits(n);
+
+					if (!IsTileType(n, MP_RAILWAY) ||
+							!IsTileOwner(n, owner) ||
+							nrail == TRACK_BIT_UPPER ||
+							nrail == TRACK_BIT_RIGHT) {
+						new_ground = RAIL_GROUND_FENCE_NE;
+					}
+				}
+
+				if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
+							(rail & TRACK_BIT_3WAY_SW) == 0 &&
+							(rail & TRACK_BIT_Y)
+						)) {
+					TileIndex n = tile + TileDiffXY(1, 0);
+					TrackBits nrail = GetTrackBits(n);
+
+					if (!IsTileType(n, MP_RAILWAY) ||
+							!IsTileOwner(n, owner) ||
+							nrail == TRACK_BIT_LOWER ||
+							nrail == TRACK_BIT_LEFT) {
+						new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
+							RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
+					}
+				}
+				break;
+			}
+		}
+	}
+
+set_ground:
+	if (old_ground != new_ground) {
+		SetRailGroundType(tile, new_ground);
+		MarkTileDirtyByTile(tile);
+	}
+}
+
+
+static uint32 GetTileTrackStatus_Track(TileIndex tile, TransportType mode)
+{
+	byte a;
+	uint16 b;
+
+	if (mode != TRANSPORT_RAIL) return 0;
+
+	if (IsPlainRailTile(tile)) {
+		TrackBits rails = GetTrackBits(tile);
+		uint32 ret = rails * 0x101;
+
+		if (HasSignals(tile)) {
+			a = _m[tile].m3;
+			b = _m[tile].m2;
+
+			b &= a;
+
+			/* When signals are not present (in neither
+			 * direction), we pretend them to be green. (So if
+			 * signals are only one way, the other way will
+			 * implicitely become `red' */
+			if ((a & 0xC0) == 0) b |= 0xC0;
+			if ((a & 0x30) == 0) b |= 0x30;
+
+			if ((b & 0x80) == 0) ret |= 0x10070000;
+			if ((b & 0x40) == 0) ret |= 0x07100000;
+			if ((b & 0x20) == 0) ret |= 0x20080000;
+			if ((b & 0x10) == 0) ret |= 0x08200000;
+		} else {
+			if (rails == TRACK_BIT_CROSS) ret |= 0x40;
+		}
+		return ret;
+	} else {
+		if (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) {
+			return AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(tile))) * 0x101;
+		} else {
+			return GetRailWaypointBits(tile) * 0x101;
+		}
+	}
+}
+
+static void ClickTile_Track(TileIndex tile)
+{
+	if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
+		ShowDepotWindow(tile, VEH_Train);
+	} else if (IsRailWaypoint(tile)) {
+		ShowRenameWaypointWindow(GetWaypointByTile(tile));
+	}
+}
+
+static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
+{
+	td->owner = GetTileOwner(tile);
+	switch (GetRailTileType(tile)) {
+		case RAIL_TILE_NORMAL:
+			td->str = STR_1021_RAILROAD_TRACK;
+			break;
+
+		case RAIL_TILE_SIGNALS: {
+			const StringID signal_type[] = {
+				STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS,
+				STR_RAILROAD_TRACK_WITH_PRESIGNALS,
+				STR_RAILROAD_TRACK_WITH_EXITSIGNALS,
+				STR_RAILROAD_TRACK_WITH_COMBOSIGNALS
+			};
+
+			td->str = signal_type[GetSignalType(tile)];
+			break;
+		}
+
+		case RAIL_TILE_DEPOT_WAYPOINT:
+		default:
+			td->str = (GetRailTileSubtype(tile) == RAIL_SUBTYPE_DEPOT) ?
+				STR_1023_RAILROAD_TRAIN_DEPOT : STR_LANDINFO_WAYPOINT;
+			break;
+	}
+}
+
+static void ChangeTileOwner_Track(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (new_player != PLAYER_SPECTATOR) {
+		SetTileOwner(tile, new_player);
+	} else {
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	}
+}
+
+static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
+static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
+static const byte _deltacoord_leaveoffset[8] = {
+	-1,  0,  1,  0, /* x */
+	 0,  1,  0, -1  /* y */
+};
+
+static uint32 VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
+{
+	byte fract_coord;
+	byte fract_coord_leave;
+	DiagDirection dir;
+	int length;
+
+	// this routine applies only to trains in depot tiles
+	if (v->type != VEH_Train || !IsTileDepotType(tile, TRANSPORT_RAIL)) return 0;
+
+	/* depot direction */
+	dir = GetRailDepotDirection(tile);
+
+	/* calculate the point where the following wagon should be activated */
+	/* this depends on the length of the current vehicle */
+	length = v->u.rail.cached_veh_length;
+
+	fract_coord_leave =
+		((_fractcoords_enter[dir] & 0x0F) + // x
+			(length + 1) * _deltacoord_leaveoffset[dir]) +
+		(((_fractcoords_enter[dir] >> 4) +  // y
+			((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
+
+	fract_coord = (x & 0xF) + ((y & 0xF) << 4);
+
+	if (_fractcoords_behind[dir] == fract_coord) {
+		/* make sure a train is not entering the tile from behind */
+		return 8;
+	} else if (_fractcoords_enter[dir] == fract_coord) {
+		if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
+			/* enter the depot */
+			v->u.rail.track = 0x80,
+			v->vehstatus |= VS_HIDDEN; /* hide it */
+			v->direction = ReverseDir(v->direction);
+			if (v->next == NULL) VehicleEnterDepot(v);
+			v->tile = tile;
+
+			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+			return 4;
+		}
+	} else if (fract_coord_leave == fract_coord) {
+		if (DiagDirToDir(dir) == v->direction) {
+			/* leave the depot? */
+			if ((v = v->next) != NULL) {
+				v->vehstatus &= ~VS_HIDDEN;
+				v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+const TileTypeProcs _tile_type_rail_procs = {
+	DrawTile_Track,           /* draw_tile_proc */
+	GetSlopeZ_Track,          /* get_slope_z_proc */
+	ClearTile_Track,          /* clear_tile_proc */
+	GetAcceptedCargo_Track,   /* get_accepted_cargo_proc */
+	GetTileDesc_Track,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Track, /* get_tile_track_status_proc */
+	ClickTile_Track,          /* click_tile_proc */
+	AnimateTile_Track,        /* animate_tile_proc */
+	TileLoop_Track,           /* tile_loop_clear */
+	ChangeTileOwner_Track,    /* change_tile_owner_clear */
+	NULL,                     /* get_produced_cargo_proc */
+	VehicleEnter_Track,       /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Track,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/rail_gui.c
+++ /dev/null
@@ -1,1180 +0,0 @@
-/* $Id$ */
-
-/** @file rail_gui.c File for dealing with rail construction user interface */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "sound.h"
-#include "command.h"
-#include "vehicle.h"
-#include "station.h"
-#include "waypoint.h"
-#include "debug.h"
-#include "variables.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_station.h"
-#include "train.h"
-
-static RailType _cur_railtype;
-static bool _remove_button_clicked;
-static DiagDirection _build_depot_direction;
-static byte _waypoint_count = 1;
-static byte _cur_waypoint_type;
-
-static struct {
-	byte orientation;
-	byte numtracks;
-	byte platlength;
-	bool dragdrop;
-
-	bool newstations;
-	byte station_class;
-	byte station_type;
-	byte station_count;
-} _railstation;
-
-
-static void HandleStationPlacement(TileIndex start, TileIndex end);
-static void ShowBuildTrainDepotPicker(void);
-static void ShowBuildWaypointPicker(void);
-static void ShowStationBuilder(void);
-
-void CcPlaySound1E(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) SndPlayTileFx(SND_20_SPLAT_2, tile);
-}
-
-static void GenericPlaceRail(TileIndex tile, int cmd)
-{
-	DoCommandP(tile, _cur_railtype, cmd, CcPlaySound1E,
-		_remove_button_clicked ?
-		CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) | CMD_AUTO | CMD_NO_WATER :
-		CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_AUTO | CMD_NO_WATER
-	);
-}
-
-static void PlaceRail_N(TileIndex tile)
-{
-	int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5;
-	GenericPlaceRail(tile, cmd);
-}
-
-static void PlaceRail_NE(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_FIX_Y);
-}
-
-static void PlaceRail_E(TileIndex tile)
-{
-	int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3;
-	GenericPlaceRail(tile, cmd);
-}
-
-static void PlaceRail_NW(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_FIX_X);
-}
-
-static void PlaceRail_AutoRail(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_RAILDIRS);
-}
-
-static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
-{
-	if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
-	if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
-
-	DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_AUTO | CMD_NO_WATER);
-}
-
-static const uint16 _place_depot_extra[12] = {
-	0x0604, 0x2102, 0x1202, 0x0505,
-	0x2400, 0x2801, 0x1800, 0x1401,
-	0x2203, 0x0904, 0x0A05, 0x1103,
-};
-
-
-void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		DiagDirection dir = p2;
-
-		SndPlayTileFx(SND_20_SPLAT_2, tile);
-		ResetObjectToPlace();
-
-		tile += TileOffsByDiagDir(dir);
-
-		if (IsTileType(tile, MP_RAILWAY)) {
-			PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
-			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
-			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
-		}
-	}
-}
-
-static void PlaceRail_Depot(TileIndex tile)
-{
-	DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
-		CMD_BUILD_TRAIN_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
-}
-
-static void PlaceRail_Waypoint(TileIndex tile)
-{
-	if (!_remove_button_clicked) {
-		DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
-	} else {
-		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
-	}
-}
-
-void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_20_SPLAT_2, tile);
-		/* Only close the station builder window if the default station is chosen. */
-		if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0) ResetObjectToPlace();
-	}
-}
-
-static void PlaceRail_Station(TileIndex tile)
-{
-	if (_remove_button_clicked) {
-		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
-	} else if (_railstation.dragdrop) {
-		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED);
-		VpSetPlaceSizingLimit(_patches.station_spread);
-	} else {
-		DoCommandP(tile,
-				_railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16),
-				_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
-				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
-	}
-}
-
-static void GenericPlaceSignals(TileIndex tile)
-{
-	uint trackstat;
-	uint i;
-
-	trackstat = (byte)GetTileTrackStatus(tile, TRANSPORT_RAIL);
-
-	if ((trackstat & 0x30)) // N-S direction
-		trackstat = (_tile_fract_coords.x <= _tile_fract_coords.y) ? 0x20 : 0x10;
-
-	if ((trackstat & 0x0C)) // E-W direction
-		trackstat = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? 4 : 8;
-
-	// Lookup the bit index
-	i = 0;
-	if (trackstat != 0) {
-		for (; !(trackstat & 1); trackstat >>= 1) i++;
-	}
-
-	if (!_remove_button_clicked) {
-		DoCommandP(tile, i + (_ctrl_pressed ? 8 : 0), 0, CcPlaySound1E,
-			CMD_BUILD_SIGNALS | CMD_AUTO | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE));
-	} else {
-		DoCommandP(tile, i, 0, CcPlaySound1E,
-			CMD_REMOVE_SIGNALS | CMD_AUTO | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM));
-	}
-}
-
-static void PlaceRail_Bridge(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_OR_Y);
-}
-
-void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_20_SPLAT_2, tile);
-		ResetObjectToPlace();
-	} else {
-		SetRedErrorSquare(_build_tunnel_endtile);
-	}
-}
-
-static void PlaceRail_Tunnel(TileIndex tile)
-{
-	DoCommandP(tile, _cur_railtype, 0, CcBuildRailTunnel,
-		CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
-}
-
-void PlaceProc_BuyLand(TileIndex tile)
-{
-	DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_PURCHASE_LAND_AREA | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_5806_CAN_T_PURCHASE_THIS_LAND));
-}
-
-static void PlaceRail_ConvertRail(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_ConvertRailArea);
-}
-
-static void PlaceRail_AutoSignals(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_SIGNALDIRS);
-}
-
-
-/** Enum referring to the widgets of the build rail toolbar */
-enum {
-	RTW_CAPTION        =  1,
-	RTW_BUILD_NS       =  4,
-	RTW_BUILD_X        =  5,
-	RTW_BUILD_EW       =  6,
-	RTW_BUILD_Y        =  7,
-	RTW_AUTORAIL       =  8,
-	RTW_DEMOLISH       =  9,
-	RTW_BUILD_DEPOT    = 10,
-	RTW_BUILD_WAYPOINT = 11,
-	RTW_BUILD_STATION  = 12,
-	RTW_BUILD_SIGNALS  = 13,
-	RTW_BUILD_BRIDGE   = 14,
-	RTW_BUILD_TUNNEL   = 15,
-	RTW_REMOVE         = 16,
-	RTW_CONVERT_RAIL   = 17
-};
-
-
-static void BuildRailClick_N(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, 1, PlaceRail_N);
-}
-
-static void BuildRailClick_NE(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, 1, PlaceRail_NE);
-}
-
-static void BuildRailClick_E(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, 1, PlaceRail_E);
-}
-
-static void BuildRailClick_NW(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, 1, PlaceRail_NW);
-}
-
-static void BuildRailClick_AutoRail(Window *w)
-{
-	HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
-}
-
-static void BuildRailClick_Demolish(Window *w)
-{
-	HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceProc_DemolishArea);
-}
-
-static void BuildRailClick_Depot(Window *w)
-{
-	if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, 1, PlaceRail_Depot)) {
-		ShowBuildTrainDepotPicker();
-	}
-}
-
-static void BuildRailClick_Waypoint(Window *w)
-{
-	_waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
-	if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, 1, PlaceRail_Waypoint) &&
-			_waypoint_count > 1) {
-		ShowBuildWaypointPicker();
-	}
-}
-
-static void BuildRailClick_Station(Window *w)
-{
-	if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, 1, PlaceRail_Station)) ShowStationBuilder();
-}
-
-static void BuildRailClick_AutoSignals(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
-}
-
-static void BuildRailClick_Bridge(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, 1, PlaceRail_Bridge);
-}
-
-static void BuildRailClick_Tunnel(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, 3, PlaceRail_Tunnel);
-}
-
-static void BuildRailClick_Remove(Window *w)
-{
-	if (IsWindowWidgetDisabled(w, RTW_REMOVE)) return;
-	SetWindowDirty(w);
-	SndPlayFx(SND_15_BEEP);
-
-	ToggleWidgetLoweredState(w, RTW_REMOVE);
-	_remove_button_clicked = IsWindowWidgetLowered(w, RTW_REMOVE);
-	SetSelectionRed(_remove_button_clicked);
-
-	// handle station builder
-	if (_remove_button_clicked) {
-		SetTileSelectSize(1, 1);
-	}
-}
-
-static void BuildRailClick_Convert(Window *w)
-{
-	HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, 1, PlaceRail_ConvertRail);
-}
-
-static void BuildRailClick_Landscaping(Window *w)
-{
-	ShowTerraformToolbar();
-}
-
-static void DoRailroadTrack(int mode)
-{
-	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
-		_remove_button_clicked ?
-		CMD_REMOVE_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
-		CMD_BUILD_RAILROAD_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
-	);
-}
-
-static void HandleAutodirPlacement(void)
-{
-	TileHighlightData *thd = &_thd;
-	int trackstat = thd->drawstyle & 0xF; // 0..5
-
-	if (thd->drawstyle & HT_RAIL) { // one tile case
-		GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
-		return;
-	}
-
-	DoRailroadTrack(trackstat);
-}
-
-static void HandleAutoSignalPlacement(void)
-{
-	TileHighlightData *thd = &_thd;
-	byte trackstat = thd->drawstyle & 0xF; // 0..5
-
-	if (thd->drawstyle == HT_RECT) { // one tile case
-		GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
-		return;
-	}
-
-	// _patches.drag_signals_density is given as a parameter such that each user in a network
-	// game can specify his/her own signal density
-	DoCommandP(
-		TileVirtXY(thd->selstart.x, thd->selstart.y),
-		TileVirtXY(thd->selend.x, thd->selend.y),
-		(_ctrl_pressed ? 1 << 3 : 0) | (trackstat << 4) | (_patches.drag_signals_density << 24),
-		CcPlaySound1E,
-		_remove_button_clicked ?
-			CMD_REMOVE_SIGNAL_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
-			CMD_BUILD_SIGNAL_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)
-	);
-}
-
-
-typedef void OnButtonClick(Window *w);
-
-static OnButtonClick * const _build_railroad_button_proc[] = {
-	BuildRailClick_N,
-	BuildRailClick_NE,
-	BuildRailClick_E,
-	BuildRailClick_NW,
-	BuildRailClick_AutoRail,
-	BuildRailClick_Demolish,
-	BuildRailClick_Depot,
-	BuildRailClick_Waypoint,
-	BuildRailClick_Station,
-	BuildRailClick_AutoSignals,
-	BuildRailClick_Bridge,
-	BuildRailClick_Tunnel,
-	BuildRailClick_Remove,
-	BuildRailClick_Convert,
-	BuildRailClick_Landscaping,
-};
-
-static const uint16 _rail_keycodes[] = {
-	'1',
-	'2',
-	'3',
-	'4',
-	'5',
-	'6',
-	'7', // depot
-	'8', // waypoint
-	'9', // station
-	'S', // signals
-	'B', // bridge
-	'T', // tunnel
-	'R', // remove
-	'C', // convert rail
-	'L', // landscaping
-};
-
-
-static void UpdateRemoveWidgetStatus(Window *w, int clicked_widget)
-{
-	/* If it is the removal button that has been clicked, do nothing,
-	 * as it is up to the other buttons to drive removal status */
-	if (clicked_widget == RTW_REMOVE) return;
-
-	switch (clicked_widget) {
-		case RTW_BUILD_NS:
-		case RTW_BUILD_X:
-		case RTW_BUILD_EW:
-		case RTW_BUILD_Y:
-		case RTW_AUTORAIL:
-		case RTW_BUILD_WAYPOINT:
-		case RTW_BUILD_STATION:
-		case RTW_BUILD_SIGNALS:
-			/* Removal button is enabled only if the rail/signal/waypoint/station
-			 * button is still lowered.  Once raised, it has to be disabled */
-			SetWindowWidgetDisabledState(w, RTW_REMOVE, !IsWindowWidgetLowered(w, clicked_widget));
-			break;
-
-		default:
-			/* When any other buttons than rail/signal/waypoint/station, raise and
-			 * disable the removal button*/
-			DisableWindowWidget(w, RTW_REMOVE);
-			RaiseWindowWidget(w, RTW_REMOVE);
-			break;
-	}
-}
-
-static void BuildRailToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: DisableWindowWidget(w, RTW_REMOVE); break;
-
-	case WE_PAINT: DrawWindowWidgets(w); break;
-
-	case WE_CLICK:
-		if (e->we.click.widget >= 4) {
-			_remove_button_clicked = false;
-			_build_railroad_button_proc[e->we.click.widget - 4](w);
-		}
-		UpdateRemoveWidgetStatus(w, e->we.click.widget);
-		break;
-
-	case WE_KEYPRESS: {
-		uint i;
-
-		for (i = 0; i != lengthof(_rail_keycodes); i++) {
-			if (e->we.keypress.keycode == _rail_keycodes[i]) {
-				e->we.keypress.cont = false;
-				_remove_button_clicked = false;
-				_build_railroad_button_proc[i](w);
-				UpdateRemoveWidgetStatus(w, i + 4);
-				break;
-			}
-		}
-		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
-		break;
-	}
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		return;
-
-	case WE_PLACE_DRAG: {
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
-		return;
-	}
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			TileIndex start_tile = e->we.place.starttile;
-			TileIndex end_tile = e->we.place.tile;
-
-			if (e->we.place.userdata == VPM_X_OR_Y) {
-				ResetObjectToPlace();
-				ShowBuildBridgeWindow(start_tile, end_tile, _cur_railtype);
-			} else if (e->we.place.userdata == VPM_RAILDIRS) {
-				bool old = _remove_button_clicked;
-				if (_ctrl_pressed) _remove_button_clicked = true;
-				HandleAutodirPlacement();
-				_remove_button_clicked = old;
-			} else if (e->we.place.userdata == VPM_SIGNALDIRS) {
-				HandleAutoSignalPlacement();
-			} else if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) {
-				if (GUIPlaceProcDragXY(e)) break;
-
-				if ((e->we.place.userdata >> 4) == GUI_PlaceProc_ConvertRailArea >> 4)
-					DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL));
-			} else if (e->we.place.userdata == VPM_X_AND_Y_LIMITED) {
-				HandleStationPlacement(start_tile, end_tile);
-			} else {
-				DoRailroadTrack(e->we.place.userdata & 1);
-			}
-		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		DisableWindowWidget(w, RTW_REMOVE);
-		InvalidateWidget(w, RTW_REMOVE);
-
-		w = FindWindowById(WC_BUILD_STATION, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		w = FindWindowById(WC_BUILD_DEPOT, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		break;
-
-	case WE_PLACE_PRESIZE: {
-		TileIndex tile = e->we.place.tile;
-
-		DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
-	} break;
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
-	}
-}
-
-
-static const Widget _build_rail_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   359,     0,    13, STR_100A_RAILROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   360,   371,     0,    13, 0x0,                            STR_STICKY_BUTTON},
-
-{      WWT_PANEL,   RESIZE_NONE,     7,   110,   113,    14,    35, 0x0,                            STR_NULL},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    0,     21,    14,    35, SPR_IMG_RAIL_NS,                STR_1018_BUILD_RAILROAD_TRACK},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_RAIL_NE,                STR_1018_BUILD_RAILROAD_TRACK},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_RAIL_EW,                STR_1018_BUILD_RAILROAD_TRACK},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,    87,    14,    35, SPR_IMG_RAIL_NW,                STR_1018_BUILD_RAILROAD_TRACK},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    88,   109,    14,    35, SPR_IMG_AUTORAIL,               STR_BUILD_AUTORAIL_TIP},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_DYNAMITE,               STR_018D_DEMOLISH_BUILDINGS_ETC},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   157,    14,    35, SPR_IMG_DEPOT_RAIL,             STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   158,   179,    14,    35, SPR_IMG_WAYPOINT,               STR_CONVERT_RAIL_TO_WAYPOINT_TIP},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   180,   221,    14,    35, SPR_IMG_RAIL_STATION,           STR_101A_BUILD_RAILROAD_STATION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   222,   243,    14,    35, SPR_IMG_RAIL_SIGNALS,           STR_101B_BUILD_RAILROAD_SIGNALS},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   244,   285,    14,    35, SPR_IMG_BRIDGE,                 STR_101C_BUILD_RAILROAD_BRIDGE},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   286,   305,    14,    35, SPR_IMG_TUNNEL_RAIL,            STR_101D_BUILD_RAILROAD_TUNNEL},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   306,   327,    14,    35, SPR_IMG_REMOVE,                 STR_101E_TOGGLE_BUILD_REMOVE_FOR},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   328,   349,    14,    35, SPR_IMG_CONVERT_RAIL,           STR_CONVERT_RAIL_TIP},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   350,   371,    14,    35, SPR_IMG_LANDSCAPING,            STR_LANDSCAPING_TOOLBAR_TIP},
-
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_rail_desc = {
-	WDP_ALIGN_TBR, 22, 372, 36,
-	WC_BUILD_TOOLBAR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_build_rail_widgets,
-	BuildRailToolbWndProc
-};
-
-
-/** Configures the rail toolbar for railtype given
- * @param railtype the railtype to display
- * @param w the window to modify
- */
-static void SetupRailToolbar(RailType railtype, Window *w)
-{
-	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
-
-	assert(railtype < RAILTYPE_END);
-	w->widget[RTW_CAPTION].data = rti->strings.toolbar_caption;
-	w->widget[RTW_BUILD_NS].data = rti->gui_sprites.build_ns_rail;
-	w->widget[RTW_BUILD_X].data = rti->gui_sprites.build_x_rail;
-	w->widget[RTW_BUILD_EW].data = rti->gui_sprites.build_ew_rail;
-	w->widget[RTW_BUILD_Y].data = rti->gui_sprites.build_y_rail;
-	w->widget[RTW_AUTORAIL].data = rti->gui_sprites.auto_rail;
-	w->widget[RTW_BUILD_DEPOT].data = rti->gui_sprites.build_depot;
-	w->widget[RTW_CONVERT_RAIL].data = rti->gui_sprites.convert_rail;
-	w->widget[RTW_BUILD_TUNNEL].data = rti->gui_sprites.build_tunnel;
-}
-
-void ShowBuildRailToolbar(RailType railtype, int button)
-{
-	Window *w;
-
-	if (!IsValidPlayer(_current_player)) return;
-	if (!ValParamRailtype(railtype)) return;
-
-	// don't recreate the window if we're clicking on a button and the window exists.
-	if (button < 0 || !(w = FindWindowById(WC_BUILD_TOOLBAR, 0)) || w->wndproc != BuildRailToolbWndProc) {
-		DeleteWindowById(WC_BUILD_TOOLBAR, 0);
-		_cur_railtype = railtype;
-		w = AllocateWindowDesc(&_build_rail_desc);
-		SetupRailToolbar(railtype, w);
-	}
-
-	_remove_button_clicked = false;
-	if (w != NULL && button >= 0) {
-		_build_railroad_button_proc[button](w);
-		UpdateRemoveWidgetStatus(w, button + 4);
-	}
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
-}
-
-/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
- * --pasky */
-
-static void HandleStationPlacement(TileIndex start, TileIndex end)
-{
-	uint sx = TileX(start);
-	uint sy = TileY(start);
-	uint ex = TileX(end);
-	uint ey = TileY(end);
-	uint w,h;
-
-	if (sx > ex) uintswap(sx,ex);
-	if (sy > ey) uintswap(sy,ey);
-	w = ex - sx + 1;
-	h = ey - sy + 1;
-	if (!_railstation.orientation) uintswap(w,h);
-
-	DoCommandP(TileXY(sx, sy),
-			_railstation.orientation | (w << 8) | (h << 16),
-			_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
-			CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
-}
-
-/* Check if the currently selected station size is allowed */
-static void CheckSelectedSize(Window *w, const StationSpec *statspec)
-{
-	if (statspec == NULL || _railstation.dragdrop) return;
-
-	if (HASBIT(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-		RaiseWindowWidget(w, _railstation.numtracks + 4);
-		_railstation.numtracks = 1;
-		while (HASBIT(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-			_railstation.numtracks++;
-		}
-		LowerWindowWidget(w, _railstation.numtracks + 4);
-	}
-
-	if (HASBIT(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-		RaiseWindowWidget(w, _railstation.platlength + 11);
-		_railstation.platlength = 1;
-		while (HASBIT(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-			_railstation.platlength++;
-		}
-		LowerWindowWidget(w, _railstation.platlength + 11);
-	}
-}
-
-static void StationBuildWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		LowerWindowWidget(w, _railstation.orientation + 3);
-		if (_railstation.dragdrop) {
-			LowerWindowWidget(w, 19);
-		} else {
-			LowerWindowWidget(w, _railstation.numtracks + 4);
-			LowerWindowWidget(w, _railstation.platlength + 11);
-		}
-		SetWindowWidgetLoweredState(w, 20, !_station_show_coverage);
-		SetWindowWidgetLoweredState(w, 21, _station_show_coverage);
-		break;
-
-	case WE_PAINT: {
-		int rad;
-		uint bits;
-		bool newstations = _railstation.newstations;
-		int y_offset;
-		DrawPixelInfo tmp_dpi, *old_dpi;
-		const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
-
-		if (WP(w,def_d).close) return;
-
-		if (_railstation.dragdrop) {
-			SetTileSelectSize(1, 1);
-		} else {
-			int x = _railstation.numtracks;
-			int y = _railstation.platlength;
-			if (_railstation.orientation == 0) intswap(x,y);
-			if (!_remove_button_clicked)
-				SetTileSelectSize(x, y);
-		}
-
-		rad = (_patches.modified_catchment) ? CA_TRAIN : 4;
-
-		if (_station_show_coverage)
-			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-
-		for (bits = 0; bits < 7; bits++) {
-			bool disable = bits >= _patches.station_spread;
-			if (statspec == NULL) {
-				SetWindowWidgetDisabledState(w, bits +  5, disable);
-				SetWindowWidgetDisabledState(w, bits + 12, disable);
-			} else {
-				SetWindowWidgetDisabledState(w, bits +  5, HASBIT(statspec->disallowed_platforms, bits) || disable);
-				SetWindowWidgetDisabledState(w, bits + 12, HASBIT(statspec->disallowed_lengths,   bits) || disable);
-			}
-		}
-
-		SetDParam(0, GetStationClassName(_railstation.station_class));
-		DrawWindowWidgets(w);
-
-		y_offset = newstations ? 90 : 0;
-
-		/* Set up a clipping area for the '/' station preview */
-		if (FillDrawPixelInfo(&tmp_dpi, 7, 26 + y_offset, 66, 48)) {
-			old_dpi = _cur_dpi;
-			_cur_dpi = &tmp_dpi;
-			if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) {
-				StationPickerDrawSprite(32, 16, _cur_railtype, 2);
-			}
-			_cur_dpi = old_dpi;
-		}
-
-		/* Set up a clipping area for the '\' station preview */
-		if (FillDrawPixelInfo(&tmp_dpi, 75, 26 + y_offset, 66, 48)) {
-			old_dpi = _cur_dpi;
-			_cur_dpi = &tmp_dpi;
-			if (!DrawStationTile(32, 16, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) {
-				StationPickerDrawSprite(32, 16, _cur_railtype, 3);
-			}
-			_cur_dpi = old_dpi;
-		}
-
-		DrawStringCentered(74, 15 + y_offset, STR_3002_ORIENTATION, 0);
-		DrawStringCentered(74, 76 + y_offset, STR_3003_NUMBER_OF_TRACKS, 0);
-		DrawStringCentered(74, 101 + y_offset, STR_3004_PLATFORM_LENGTH, 0);
-		DrawStringCentered(74, 141 + y_offset, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0);
-
-		DrawStationCoverageAreaText(2, 166 + y_offset, (uint)-1, rad);
-
-		if (newstations) {
-			uint16 i;
-			uint y = 35;
-
-			for (i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
-				const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
-
-				if (statspec != NULL && statspec->name != 0) {
-					if (HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
-						GfxFillRect(8, y - 2, 127, y + 10, PALETTE_MODIFIER_GREYOUT);
-					}
-
-					DrawStringTruncated(9, y, statspec->name, i == _railstation.station_type ? 12 : 16, 118);
-				} else {
-					DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _railstation.station_type ? 12 : 16, 118);
-				}
-
-				y += 14;
-			}
-		}
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3:
-		case 4:
-			RaiseWindowWidget(w, _railstation.orientation + 3);
-			_railstation.orientation = e->we.click.widget - 3;
-			LowerWindowWidget(w, _railstation.orientation + 3);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-
-		case 5:
-		case 6:
-		case 7:
-		case 8:
-		case 9:
-		case 10:
-		case 11:
-			RaiseWindowWidget(w, _railstation.numtracks + 4);
-			RaiseWindowWidget(w, 19);
-			_railstation.numtracks = (e->we.click.widget - 5) + 1;
-			_railstation.dragdrop = false;
-			LowerWindowWidget(w, _railstation.platlength + 11);
-			LowerWindowWidget(w, _railstation.numtracks + 4);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-
-		case 12:
-		case 13:
-		case 14:
-		case 15:
-		case 16:
-		case 17:
-		case 18:
-			RaiseWindowWidget(w, _railstation.platlength + 11);
-			RaiseWindowWidget(w, 19);
-			_railstation.platlength = (e->we.click.widget - 12) + 1;
-			_railstation.dragdrop = false;
-			LowerWindowWidget(w, _railstation.platlength + 11);
-			LowerWindowWidget(w, _railstation.numtracks + 4);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-
-		case 19:
-			_railstation.dragdrop ^= true;
-			ToggleWidgetLoweredState(w, 19);
-			SetWindowWidgetLoweredState(w, _railstation.numtracks + 4, !_railstation.dragdrop);
-			SetWindowWidgetLoweredState(w, _railstation.platlength + 11, !_railstation.dragdrop);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-
-		case 20:
-		case 21:
-			_station_show_coverage = e->we.click.widget - 20;
-			SetWindowWidgetLoweredState(w, 20, !_station_show_coverage);
-			SetWindowWidgetLoweredState(w, 21, _station_show_coverage);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-
-		case 22:
-		case 23:
-			ShowDropDownMenu(w, BuildStationClassDropdown(), _railstation.station_class, 23, 0, 1 << STAT_CLASS_WAYP);
-			break;
-
-		case 24: {
-			const StationSpec *statspec;
-			int y = (e->we.click.pt.y - 32) / 14;
-
-			if (y >= w->vscroll.cap) return;
-			y += w->vscroll.pos;
-			if (y >= _railstation.station_count) return;
-
-			/* Check station availability callback */
-			statspec = GetCustomStationSpec(_railstation.station_class, y);
-			if (statspec != NULL &&
-				HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
-				GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
-
-			_railstation.station_type = y;
-
-			CheckSelectedSize(w, statspec);
-
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		}
-		}
-	} break;
-
-	case WE_DROPDOWN_SELECT:
-		if (_railstation.station_class != e->we.dropdown.index) {
-			_railstation.station_class = e->we.dropdown.index;
-			_railstation.station_type  = 0;
-			_railstation.station_count = GetNumCustomStations(_railstation.station_class);
-
-			CheckSelectedSize(w, GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
-
-			w->vscroll.count = _railstation.station_count;
-			w->vscroll.pos   = _railstation.station_type;
-		}
-
-		SndPlayFx(SND_15_BEEP);
-		SetWindowDirty(w);
-		break;
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) {
-			DeleteWindow(w);
-			return;
-		}
-		CheckRedrawStationCoverage(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _station_builder_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   199, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,    87,    98, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,    87,    98, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,    87,    98, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,    87,    98, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,    87,    98, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,    87,    98, STR_0335_6,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,    87,    98, STR_0336_7,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   112,   123, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   112,   123, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   112,   123, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   112,   123, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   112,   123, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   112,   123, STR_0335_6,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   112,   123, STR_0336_7,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   126,   137, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   152,   163, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   152,   163, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{   WIDGETS_END},
-};
-
-static const Widget _newstation_builder_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   289, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   177,   188, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   177,   188, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   177,   188, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   177,   188, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   177,   188, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   177,   188, STR_0335_6,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   177,   188, STR_0336_7,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   202,   213, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   202,   213, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   202,   213, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   202,   213, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   202,   213, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   202,   213, STR_0335_6,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   202,   213, STR_0336_7,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   216,   227, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   242,   253, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   242,   253, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},
-
-/* newstations gui additions */
-{      WWT_INSET,   RESIZE_NONE,    14,     7,   140,    17,    28, STR_02BD,                        STR_SELECT_STATION_CLASS_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   129,   139,    18,    27, STR_0225,                        STR_SELECT_STATION_CLASS_TIP},
-{     WWT_MATRIX,   RESIZE_NONE,    14,     7,   128,    32,   102, 0x501,                           STR_SELECT_STATION_TYPE_TIP},
-{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   129,   140,    32,   102, 0x0,                             STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _station_builder_desc = {
-	WDP_AUTO, WDP_AUTO, 148, 200,
-	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_station_builder_widgets,
-	StationBuildWndProc
-};
-
-static const WindowDesc _newstation_builder_desc = {
-	WDP_AUTO, WDP_AUTO, 148, 290,
-	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_newstation_builder_widgets,
-	StationBuildWndProc
-};
-
-static void ShowStationBuilder(void)
-{
-	Window *w;
-	if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
-		w = AllocateWindowDesc(&_station_builder_desc);
-		_railstation.newstations = false;
-	} else {
-		w = AllocateWindowDesc(&_newstation_builder_desc);
-		_railstation.newstations = true;
-		_railstation.station_count = GetNumCustomStations(_railstation.station_class);
-
-		w->vscroll.count = _railstation.station_count;
-		w->vscroll.cap   = 5;
-		w->vscroll.pos   = clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
-	}
-}
-
-static void BuildTrainDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _build_depot_direction + 3); break;
-
-	case WE_PAINT: {
-		RailType r;
-
-		DrawWindowWidgets(w);
-
-		r = _cur_railtype;
-		DrawTrainDepotSprite(70, 17, 0, r);
-		DrawTrainDepotSprite(70, 69, 1, r);
-		DrawTrainDepotSprite( 2, 69, 2, r);
-		DrawTrainDepotSprite( 2, 17, 3, r);
-		break;
-		}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 3:
-			case 4:
-			case 5:
-			case 6:
-				RaiseWindowWidget(w, _build_depot_direction + 3);
-				_build_depot_direction = e->we.click.widget - 3;
-				LowerWindowWidget(w, _build_depot_direction + 3);
-				SndPlayFx(SND_15_BEEP);
-				SetWindowDirty(w);
-				break;
-		}
-		break;
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) DeleteWindow(w);
-		return;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_depot_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1014_TRAIN_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 140, 122,
-	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_depot_widgets,
-	BuildTrainDepotWndProc
-};
-
-static void ShowBuildTrainDepotPicker(void)
-{
-	AllocateWindowDesc(&_build_depot_desc);
-}
-
-
-static void BuildWaypointWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		uint i;
-
-		for (i = 0; i < w->hscroll.cap; i++) {
-			SetWindowWidgetLoweredState(w, i + 3, (w->hscroll.pos + i) == _cur_waypoint_type);
-		}
-
-		DrawWindowWidgets(w);
-
-		for (i = 0; i < w->hscroll.cap; i++) {
-			if (w->hscroll.pos + i < w->hscroll.count) {
-				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, w->hscroll.pos + i);
-
-				DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
-
-				if (statspec != NULL &&
-						HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
-						GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
-					GfxFillRect(4 + i * 68, 18, 67 + i * 68, 75, PALETTE_MODIFIER_GREYOUT);
-				}
-			}
-		}
-		break;
-	}
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3: case 4: case 5: case 6: case 7: {
-			byte type = e->we.click.widget - 3 + w->hscroll.pos;
-
-			/* Check station availability callback */
-			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
-			if (statspec != NULL &&
-					HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
-					GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
-
-			_cur_waypoint_type = type;
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		}
-		}
-		break;
-	}
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) DeleteWindow(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_waypoint_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   343,     0,    13, STR_WAYPOINT, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   343,    14,    91, 0x0,          0},
-
-{      WWT_PANEL,   RESIZE_NONE,     7,     3,    68,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
-{      WWT_PANEL,   RESIZE_NONE,     7,    71,   136,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
-{      WWT_PANEL,   RESIZE_NONE,     7,   139,   204,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
-{      WWT_PANEL,   RESIZE_NONE,     7,   207,   272,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
-{      WWT_PANEL,   RESIZE_NONE,     7,   275,   340,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
-
-{ WWT_HSCROLLBAR,   RESIZE_NONE,    7,     1,   343,     80,    91, 0x0,          STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _build_waypoint_desc = {
-	WDP_AUTO, WDP_AUTO, 344, 92,
-	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_waypoint_widgets,
-	BuildWaypointWndProc
-};
-
-static void ShowBuildWaypointPicker(void)
-{
-	Window *w = AllocateWindowDesc(&_build_waypoint_desc);
-	w->hscroll.cap = 5;
-	w->hscroll.count = _waypoint_count;
-}
-
-
-void InitializeRailGui(void)
-{
-	_build_depot_direction = DIAGDIR_NW;
-	_railstation.numtracks = 1;
-	_railstation.platlength = 1;
-	_railstation.dragdrop = true;
-}
-
-void ReinitGuiAfterToggleElrail(bool disable)
-{
-	extern RailType _last_built_railtype;
-	if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) {
-		Window *w;
-		_last_built_railtype = _cur_railtype = RAILTYPE_RAIL;
-		w = FindWindowById(WC_BUILD_TOOLBAR, 0);
-		if (w != NULL && w->wndproc == BuildRailToolbWndProc) {
-			SetupRailToolbar(_cur_railtype, w);
-			SetWindowDirty(w);
-		}
-	}
-	MarkWholeScreenDirty();
-}
-
-
new file mode 100644
--- /dev/null
+++ b/src/rail_gui.cpp
@@ -0,0 +1,1180 @@
+/* $Id$ */
+
+/** @file rail_gui.c File for dealing with rail construction user interface */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "sound.h"
+#include "command.h"
+#include "vehicle.h"
+#include "station.h"
+#include "waypoint.h"
+#include "debug.h"
+#include "variables.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_station.h"
+#include "train.h"
+
+static RailType _cur_railtype;
+static bool _remove_button_clicked;
+static DiagDirection _build_depot_direction;
+static byte _waypoint_count = 1;
+static byte _cur_waypoint_type;
+
+static struct {
+	byte orientation;
+	byte numtracks;
+	byte platlength;
+	bool dragdrop;
+
+	bool newstations;
+	byte station_class;
+	byte station_type;
+	byte station_count;
+} _railstation;
+
+
+static void HandleStationPlacement(TileIndex start, TileIndex end);
+static void ShowBuildTrainDepotPicker(void);
+static void ShowBuildWaypointPicker(void);
+static void ShowStationBuilder(void);
+
+void CcPlaySound1E(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) SndPlayTileFx(SND_20_SPLAT_2, tile);
+}
+
+static void GenericPlaceRail(TileIndex tile, int cmd)
+{
+	DoCommandP(tile, _cur_railtype, cmd, CcPlaySound1E,
+		_remove_button_clicked ?
+		CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) | CMD_AUTO | CMD_NO_WATER :
+		CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_AUTO | CMD_NO_WATER
+	);
+}
+
+static void PlaceRail_N(TileIndex tile)
+{
+	int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5;
+	GenericPlaceRail(tile, cmd);
+}
+
+static void PlaceRail_NE(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_FIX_Y);
+}
+
+static void PlaceRail_E(TileIndex tile)
+{
+	int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3;
+	GenericPlaceRail(tile, cmd);
+}
+
+static void PlaceRail_NW(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_FIX_X);
+}
+
+static void PlaceRail_AutoRail(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_RAILDIRS);
+}
+
+static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
+{
+	if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
+	if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
+
+	DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_AUTO | CMD_NO_WATER);
+}
+
+static const uint16 _place_depot_extra[12] = {
+	0x0604, 0x2102, 0x1202, 0x0505,
+	0x2400, 0x2801, 0x1800, 0x1401,
+	0x2203, 0x0904, 0x0A05, 0x1103,
+};
+
+
+void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		DiagDirection dir = p2;
+
+		SndPlayTileFx(SND_20_SPLAT_2, tile);
+		ResetObjectToPlace();
+
+		tile += TileOffsByDiagDir(dir);
+
+		if (IsTileType(tile, MP_RAILWAY)) {
+			PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
+			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
+			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
+		}
+	}
+}
+
+static void PlaceRail_Depot(TileIndex tile)
+{
+	DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
+		CMD_BUILD_TRAIN_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
+}
+
+static void PlaceRail_Waypoint(TileIndex tile)
+{
+	if (!_remove_button_clicked) {
+		DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
+	} else {
+		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
+	}
+}
+
+void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_20_SPLAT_2, tile);
+		/* Only close the station builder window if the default station is chosen. */
+		if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0) ResetObjectToPlace();
+	}
+}
+
+static void PlaceRail_Station(TileIndex tile)
+{
+	if (_remove_button_clicked) {
+		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
+	} else if (_railstation.dragdrop) {
+		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED);
+		VpSetPlaceSizingLimit(_patches.station_spread);
+	} else {
+		DoCommandP(tile,
+				_railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16),
+				_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
+				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
+	}
+}
+
+static void GenericPlaceSignals(TileIndex tile)
+{
+	uint trackstat;
+	uint i;
+
+	trackstat = (byte)GetTileTrackStatus(tile, TRANSPORT_RAIL);
+
+	if ((trackstat & 0x30)) // N-S direction
+		trackstat = (_tile_fract_coords.x <= _tile_fract_coords.y) ? 0x20 : 0x10;
+
+	if ((trackstat & 0x0C)) // E-W direction
+		trackstat = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? 4 : 8;
+
+	// Lookup the bit index
+	i = 0;
+	if (trackstat != 0) {
+		for (; !(trackstat & 1); trackstat >>= 1) i++;
+	}
+
+	if (!_remove_button_clicked) {
+		DoCommandP(tile, i + (_ctrl_pressed ? 8 : 0), 0, CcPlaySound1E,
+			CMD_BUILD_SIGNALS | CMD_AUTO | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE));
+	} else {
+		DoCommandP(tile, i, 0, CcPlaySound1E,
+			CMD_REMOVE_SIGNALS | CMD_AUTO | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM));
+	}
+}
+
+static void PlaceRail_Bridge(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_OR_Y);
+}
+
+void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_20_SPLAT_2, tile);
+		ResetObjectToPlace();
+	} else {
+		SetRedErrorSquare(_build_tunnel_endtile);
+	}
+}
+
+static void PlaceRail_Tunnel(TileIndex tile)
+{
+	DoCommandP(tile, _cur_railtype, 0, CcBuildRailTunnel,
+		CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
+}
+
+void PlaceProc_BuyLand(TileIndex tile)
+{
+	DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_PURCHASE_LAND_AREA | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_5806_CAN_T_PURCHASE_THIS_LAND));
+}
+
+static void PlaceRail_ConvertRail(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_ConvertRailArea);
+}
+
+static void PlaceRail_AutoSignals(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_SIGNALDIRS);
+}
+
+
+/** Enum referring to the widgets of the build rail toolbar */
+enum {
+	RTW_CAPTION        =  1,
+	RTW_BUILD_NS       =  4,
+	RTW_BUILD_X        =  5,
+	RTW_BUILD_EW       =  6,
+	RTW_BUILD_Y        =  7,
+	RTW_AUTORAIL       =  8,
+	RTW_DEMOLISH       =  9,
+	RTW_BUILD_DEPOT    = 10,
+	RTW_BUILD_WAYPOINT = 11,
+	RTW_BUILD_STATION  = 12,
+	RTW_BUILD_SIGNALS  = 13,
+	RTW_BUILD_BRIDGE   = 14,
+	RTW_BUILD_TUNNEL   = 15,
+	RTW_REMOVE         = 16,
+	RTW_CONVERT_RAIL   = 17
+};
+
+
+static void BuildRailClick_N(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, 1, PlaceRail_N);
+}
+
+static void BuildRailClick_NE(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, 1, PlaceRail_NE);
+}
+
+static void BuildRailClick_E(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, 1, PlaceRail_E);
+}
+
+static void BuildRailClick_NW(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, 1, PlaceRail_NW);
+}
+
+static void BuildRailClick_AutoRail(Window *w)
+{
+	HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
+}
+
+static void BuildRailClick_Demolish(Window *w)
+{
+	HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceProc_DemolishArea);
+}
+
+static void BuildRailClick_Depot(Window *w)
+{
+	if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, 1, PlaceRail_Depot)) {
+		ShowBuildTrainDepotPicker();
+	}
+}
+
+static void BuildRailClick_Waypoint(Window *w)
+{
+	_waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
+	if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, 1, PlaceRail_Waypoint) &&
+			_waypoint_count > 1) {
+		ShowBuildWaypointPicker();
+	}
+}
+
+static void BuildRailClick_Station(Window *w)
+{
+	if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, 1, PlaceRail_Station)) ShowStationBuilder();
+}
+
+static void BuildRailClick_AutoSignals(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
+}
+
+static void BuildRailClick_Bridge(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, 1, PlaceRail_Bridge);
+}
+
+static void BuildRailClick_Tunnel(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, 3, PlaceRail_Tunnel);
+}
+
+static void BuildRailClick_Remove(Window *w)
+{
+	if (IsWindowWidgetDisabled(w, RTW_REMOVE)) return;
+	SetWindowDirty(w);
+	SndPlayFx(SND_15_BEEP);
+
+	ToggleWidgetLoweredState(w, RTW_REMOVE);
+	_remove_button_clicked = IsWindowWidgetLowered(w, RTW_REMOVE);
+	SetSelectionRed(_remove_button_clicked);
+
+	// handle station builder
+	if (_remove_button_clicked) {
+		SetTileSelectSize(1, 1);
+	}
+}
+
+static void BuildRailClick_Convert(Window *w)
+{
+	HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, 1, PlaceRail_ConvertRail);
+}
+
+static void BuildRailClick_Landscaping(Window *w)
+{
+	ShowTerraformToolbar();
+}
+
+static void DoRailroadTrack(int mode)
+{
+	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
+		_remove_button_clicked ?
+		CMD_REMOVE_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
+		CMD_BUILD_RAILROAD_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
+	);
+}
+
+static void HandleAutodirPlacement(void)
+{
+	TileHighlightData *thd = &_thd;
+	int trackstat = thd->drawstyle & 0xF; // 0..5
+
+	if (thd->drawstyle & HT_RAIL) { // one tile case
+		GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
+		return;
+	}
+
+	DoRailroadTrack(trackstat);
+}
+
+static void HandleAutoSignalPlacement(void)
+{
+	TileHighlightData *thd = &_thd;
+	byte trackstat = thd->drawstyle & 0xF; // 0..5
+
+	if (thd->drawstyle == HT_RECT) { // one tile case
+		GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
+		return;
+	}
+
+	// _patches.drag_signals_density is given as a parameter such that each user in a network
+	// game can specify his/her own signal density
+	DoCommandP(
+		TileVirtXY(thd->selstart.x, thd->selstart.y),
+		TileVirtXY(thd->selend.x, thd->selend.y),
+		(_ctrl_pressed ? 1 << 3 : 0) | (trackstat << 4) | (_patches.drag_signals_density << 24),
+		CcPlaySound1E,
+		_remove_button_clicked ?
+			CMD_REMOVE_SIGNAL_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
+			CMD_BUILD_SIGNAL_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)
+	);
+}
+
+
+typedef void OnButtonClick(Window *w);
+
+static OnButtonClick * const _build_railroad_button_proc[] = {
+	BuildRailClick_N,
+	BuildRailClick_NE,
+	BuildRailClick_E,
+	BuildRailClick_NW,
+	BuildRailClick_AutoRail,
+	BuildRailClick_Demolish,
+	BuildRailClick_Depot,
+	BuildRailClick_Waypoint,
+	BuildRailClick_Station,
+	BuildRailClick_AutoSignals,
+	BuildRailClick_Bridge,
+	BuildRailClick_Tunnel,
+	BuildRailClick_Remove,
+	BuildRailClick_Convert,
+	BuildRailClick_Landscaping,
+};
+
+static const uint16 _rail_keycodes[] = {
+	'1',
+	'2',
+	'3',
+	'4',
+	'5',
+	'6',
+	'7', // depot
+	'8', // waypoint
+	'9', // station
+	'S', // signals
+	'B', // bridge
+	'T', // tunnel
+	'R', // remove
+	'C', // convert rail
+	'L', // landscaping
+};
+
+
+static void UpdateRemoveWidgetStatus(Window *w, int clicked_widget)
+{
+	/* If it is the removal button that has been clicked, do nothing,
+	 * as it is up to the other buttons to drive removal status */
+	if (clicked_widget == RTW_REMOVE) return;
+
+	switch (clicked_widget) {
+		case RTW_BUILD_NS:
+		case RTW_BUILD_X:
+		case RTW_BUILD_EW:
+		case RTW_BUILD_Y:
+		case RTW_AUTORAIL:
+		case RTW_BUILD_WAYPOINT:
+		case RTW_BUILD_STATION:
+		case RTW_BUILD_SIGNALS:
+			/* Removal button is enabled only if the rail/signal/waypoint/station
+			 * button is still lowered.  Once raised, it has to be disabled */
+			SetWindowWidgetDisabledState(w, RTW_REMOVE, !IsWindowWidgetLowered(w, clicked_widget));
+			break;
+
+		default:
+			/* When any other buttons than rail/signal/waypoint/station, raise and
+			 * disable the removal button*/
+			DisableWindowWidget(w, RTW_REMOVE);
+			RaiseWindowWidget(w, RTW_REMOVE);
+			break;
+	}
+}
+
+static void BuildRailToolbWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: DisableWindowWidget(w, RTW_REMOVE); break;
+
+	case WE_PAINT: DrawWindowWidgets(w); break;
+
+	case WE_CLICK:
+		if (e->we.click.widget >= 4) {
+			_remove_button_clicked = false;
+			_build_railroad_button_proc[e->we.click.widget - 4](w);
+		}
+		UpdateRemoveWidgetStatus(w, e->we.click.widget);
+		break;
+
+	case WE_KEYPRESS: {
+		uint i;
+
+		for (i = 0; i != lengthof(_rail_keycodes); i++) {
+			if (e->we.keypress.keycode == _rail_keycodes[i]) {
+				e->we.keypress.cont = false;
+				_remove_button_clicked = false;
+				_build_railroad_button_proc[i](w);
+				UpdateRemoveWidgetStatus(w, i + 4);
+				break;
+			}
+		}
+		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
+		break;
+	}
+
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		return;
+
+	case WE_PLACE_DRAG: {
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
+		return;
+	}
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			TileIndex start_tile = e->we.place.starttile;
+			TileIndex end_tile = e->we.place.tile;
+
+			if (e->we.place.userdata == VPM_X_OR_Y) {
+				ResetObjectToPlace();
+				ShowBuildBridgeWindow(start_tile, end_tile, _cur_railtype);
+			} else if (e->we.place.userdata == VPM_RAILDIRS) {
+				bool old = _remove_button_clicked;
+				if (_ctrl_pressed) _remove_button_clicked = true;
+				HandleAutodirPlacement();
+				_remove_button_clicked = old;
+			} else if (e->we.place.userdata == VPM_SIGNALDIRS) {
+				HandleAutoSignalPlacement();
+			} else if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) {
+				if (GUIPlaceProcDragXY(e)) break;
+
+				if ((e->we.place.userdata >> 4) == GUI_PlaceProc_ConvertRailArea >> 4)
+					DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL));
+			} else if (e->we.place.userdata == VPM_X_AND_Y_LIMITED) {
+				HandleStationPlacement(start_tile, end_tile);
+			} else {
+				DoRailroadTrack(e->we.place.userdata & 1);
+			}
+		}
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		DisableWindowWidget(w, RTW_REMOVE);
+		InvalidateWidget(w, RTW_REMOVE);
+
+		w = FindWindowById(WC_BUILD_STATION, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		w = FindWindowById(WC_BUILD_DEPOT, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		break;
+
+	case WE_PLACE_PRESIZE: {
+		TileIndex tile = e->we.place.tile;
+
+		DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
+	} break;
+
+	case WE_DESTROY:
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+		break;
+	}
+}
+
+
+static const Widget _build_rail_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   359,     0,    13, STR_100A_RAILROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   360,   371,     0,    13, 0x0,                            STR_STICKY_BUTTON},
+
+{      WWT_PANEL,   RESIZE_NONE,     7,   110,   113,    14,    35, 0x0,                            STR_NULL},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    0,     21,    14,    35, SPR_IMG_RAIL_NS,                STR_1018_BUILD_RAILROAD_TRACK},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_RAIL_NE,                STR_1018_BUILD_RAILROAD_TRACK},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_RAIL_EW,                STR_1018_BUILD_RAILROAD_TRACK},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,    87,    14,    35, SPR_IMG_RAIL_NW,                STR_1018_BUILD_RAILROAD_TRACK},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    88,   109,    14,    35, SPR_IMG_AUTORAIL,               STR_BUILD_AUTORAIL_TIP},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_DYNAMITE,               STR_018D_DEMOLISH_BUILDINGS_ETC},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   157,    14,    35, SPR_IMG_DEPOT_RAIL,             STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   158,   179,    14,    35, SPR_IMG_WAYPOINT,               STR_CONVERT_RAIL_TO_WAYPOINT_TIP},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   180,   221,    14,    35, SPR_IMG_RAIL_STATION,           STR_101A_BUILD_RAILROAD_STATION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   222,   243,    14,    35, SPR_IMG_RAIL_SIGNALS,           STR_101B_BUILD_RAILROAD_SIGNALS},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   244,   285,    14,    35, SPR_IMG_BRIDGE,                 STR_101C_BUILD_RAILROAD_BRIDGE},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   286,   305,    14,    35, SPR_IMG_TUNNEL_RAIL,            STR_101D_BUILD_RAILROAD_TUNNEL},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   306,   327,    14,    35, SPR_IMG_REMOVE,                 STR_101E_TOGGLE_BUILD_REMOVE_FOR},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   328,   349,    14,    35, SPR_IMG_CONVERT_RAIL,           STR_CONVERT_RAIL_TIP},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   350,   371,    14,    35, SPR_IMG_LANDSCAPING,            STR_LANDSCAPING_TOOLBAR_TIP},
+
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_rail_desc = {
+	WDP_ALIGN_TBR, 22, 372, 36,
+	WC_BUILD_TOOLBAR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_build_rail_widgets,
+	BuildRailToolbWndProc
+};
+
+
+/** Configures the rail toolbar for railtype given
+ * @param railtype the railtype to display
+ * @param w the window to modify
+ */
+static void SetupRailToolbar(RailType railtype, Window *w)
+{
+	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
+
+	assert(railtype < RAILTYPE_END);
+	w->widget[RTW_CAPTION].data = rti->strings.toolbar_caption;
+	w->widget[RTW_BUILD_NS].data = rti->gui_sprites.build_ns_rail;
+	w->widget[RTW_BUILD_X].data = rti->gui_sprites.build_x_rail;
+	w->widget[RTW_BUILD_EW].data = rti->gui_sprites.build_ew_rail;
+	w->widget[RTW_BUILD_Y].data = rti->gui_sprites.build_y_rail;
+	w->widget[RTW_AUTORAIL].data = rti->gui_sprites.auto_rail;
+	w->widget[RTW_BUILD_DEPOT].data = rti->gui_sprites.build_depot;
+	w->widget[RTW_CONVERT_RAIL].data = rti->gui_sprites.convert_rail;
+	w->widget[RTW_BUILD_TUNNEL].data = rti->gui_sprites.build_tunnel;
+}
+
+void ShowBuildRailToolbar(RailType railtype, int button)
+{
+	Window *w;
+
+	if (!IsValidPlayer(_current_player)) return;
+	if (!ValParamRailtype(railtype)) return;
+
+	// don't recreate the window if we're clicking on a button and the window exists.
+	if (button < 0 || !(w = FindWindowById(WC_BUILD_TOOLBAR, 0)) || w->wndproc != BuildRailToolbWndProc) {
+		DeleteWindowById(WC_BUILD_TOOLBAR, 0);
+		_cur_railtype = railtype;
+		w = AllocateWindowDesc(&_build_rail_desc);
+		SetupRailToolbar(railtype, w);
+	}
+
+	_remove_button_clicked = false;
+	if (w != NULL && button >= 0) {
+		_build_railroad_button_proc[button](w);
+		UpdateRemoveWidgetStatus(w, button + 4);
+	}
+	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
+}
+
+/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
+ * --pasky */
+
+static void HandleStationPlacement(TileIndex start, TileIndex end)
+{
+	uint sx = TileX(start);
+	uint sy = TileY(start);
+	uint ex = TileX(end);
+	uint ey = TileY(end);
+	uint w,h;
+
+	if (sx > ex) uintswap(sx,ex);
+	if (sy > ey) uintswap(sy,ey);
+	w = ex - sx + 1;
+	h = ey - sy + 1;
+	if (!_railstation.orientation) uintswap(w,h);
+
+	DoCommandP(TileXY(sx, sy),
+			_railstation.orientation | (w << 8) | (h << 16),
+			_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
+			CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
+}
+
+/* Check if the currently selected station size is allowed */
+static void CheckSelectedSize(Window *w, const StationSpec *statspec)
+{
+	if (statspec == NULL || _railstation.dragdrop) return;
+
+	if (HASBIT(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+		RaiseWindowWidget(w, _railstation.numtracks + 4);
+		_railstation.numtracks = 1;
+		while (HASBIT(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+			_railstation.numtracks++;
+		}
+		LowerWindowWidget(w, _railstation.numtracks + 4);
+	}
+
+	if (HASBIT(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+		RaiseWindowWidget(w, _railstation.platlength + 11);
+		_railstation.platlength = 1;
+		while (HASBIT(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+			_railstation.platlength++;
+		}
+		LowerWindowWidget(w, _railstation.platlength + 11);
+	}
+}
+
+static void StationBuildWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE:
+		LowerWindowWidget(w, _railstation.orientation + 3);
+		if (_railstation.dragdrop) {
+			LowerWindowWidget(w, 19);
+		} else {
+			LowerWindowWidget(w, _railstation.numtracks + 4);
+			LowerWindowWidget(w, _railstation.platlength + 11);
+		}
+		SetWindowWidgetLoweredState(w, 20, !_station_show_coverage);
+		SetWindowWidgetLoweredState(w, 21, _station_show_coverage);
+		break;
+
+	case WE_PAINT: {
+		int rad;
+		uint bits;
+		bool newstations = _railstation.newstations;
+		int y_offset;
+		DrawPixelInfo tmp_dpi, *old_dpi;
+		const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+
+		if (WP(w,def_d).close) return;
+
+		if (_railstation.dragdrop) {
+			SetTileSelectSize(1, 1);
+		} else {
+			int x = _railstation.numtracks;
+			int y = _railstation.platlength;
+			if (_railstation.orientation == 0) intswap(x,y);
+			if (!_remove_button_clicked)
+				SetTileSelectSize(x, y);
+		}
+
+		rad = (_patches.modified_catchment) ? CA_TRAIN : 4;
+
+		if (_station_show_coverage)
+			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+
+		for (bits = 0; bits < 7; bits++) {
+			bool disable = bits >= _patches.station_spread;
+			if (statspec == NULL) {
+				SetWindowWidgetDisabledState(w, bits +  5, disable);
+				SetWindowWidgetDisabledState(w, bits + 12, disable);
+			} else {
+				SetWindowWidgetDisabledState(w, bits +  5, HASBIT(statspec->disallowed_platforms, bits) || disable);
+				SetWindowWidgetDisabledState(w, bits + 12, HASBIT(statspec->disallowed_lengths,   bits) || disable);
+			}
+		}
+
+		SetDParam(0, GetStationClassName(_railstation.station_class));
+		DrawWindowWidgets(w);
+
+		y_offset = newstations ? 90 : 0;
+
+		/* Set up a clipping area for the '/' station preview */
+		if (FillDrawPixelInfo(&tmp_dpi, 7, 26 + y_offset, 66, 48)) {
+			old_dpi = _cur_dpi;
+			_cur_dpi = &tmp_dpi;
+			if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) {
+				StationPickerDrawSprite(32, 16, _cur_railtype, 2);
+			}
+			_cur_dpi = old_dpi;
+		}
+
+		/* Set up a clipping area for the '\' station preview */
+		if (FillDrawPixelInfo(&tmp_dpi, 75, 26 + y_offset, 66, 48)) {
+			old_dpi = _cur_dpi;
+			_cur_dpi = &tmp_dpi;
+			if (!DrawStationTile(32, 16, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) {
+				StationPickerDrawSprite(32, 16, _cur_railtype, 3);
+			}
+			_cur_dpi = old_dpi;
+		}
+
+		DrawStringCentered(74, 15 + y_offset, STR_3002_ORIENTATION, 0);
+		DrawStringCentered(74, 76 + y_offset, STR_3003_NUMBER_OF_TRACKS, 0);
+		DrawStringCentered(74, 101 + y_offset, STR_3004_PLATFORM_LENGTH, 0);
+		DrawStringCentered(74, 141 + y_offset, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0);
+
+		DrawStationCoverageAreaText(2, 166 + y_offset, (uint)-1, rad);
+
+		if (newstations) {
+			uint16 i;
+			uint y = 35;
+
+			for (i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
+				const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
+
+				if (statspec != NULL && statspec->name != 0) {
+					if (HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+						GfxFillRect(8, y - 2, 127, y + 10, PALETTE_MODIFIER_GREYOUT);
+					}
+
+					DrawStringTruncated(9, y, statspec->name, i == _railstation.station_type ? 12 : 16, 118);
+				} else {
+					DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _railstation.station_type ? 12 : 16, 118);
+				}
+
+				y += 14;
+			}
+		}
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3:
+		case 4:
+			RaiseWindowWidget(w, _railstation.orientation + 3);
+			_railstation.orientation = e->we.click.widget - 3;
+			LowerWindowWidget(w, _railstation.orientation + 3);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+
+		case 5:
+		case 6:
+		case 7:
+		case 8:
+		case 9:
+		case 10:
+		case 11:
+			RaiseWindowWidget(w, _railstation.numtracks + 4);
+			RaiseWindowWidget(w, 19);
+			_railstation.numtracks = (e->we.click.widget - 5) + 1;
+			_railstation.dragdrop = false;
+			LowerWindowWidget(w, _railstation.platlength + 11);
+			LowerWindowWidget(w, _railstation.numtracks + 4);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+
+		case 12:
+		case 13:
+		case 14:
+		case 15:
+		case 16:
+		case 17:
+		case 18:
+			RaiseWindowWidget(w, _railstation.platlength + 11);
+			RaiseWindowWidget(w, 19);
+			_railstation.platlength = (e->we.click.widget - 12) + 1;
+			_railstation.dragdrop = false;
+			LowerWindowWidget(w, _railstation.platlength + 11);
+			LowerWindowWidget(w, _railstation.numtracks + 4);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+
+		case 19:
+			_railstation.dragdrop ^= true;
+			ToggleWidgetLoweredState(w, 19);
+			SetWindowWidgetLoweredState(w, _railstation.numtracks + 4, !_railstation.dragdrop);
+			SetWindowWidgetLoweredState(w, _railstation.platlength + 11, !_railstation.dragdrop);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+
+		case 20:
+		case 21:
+			_station_show_coverage = e->we.click.widget - 20;
+			SetWindowWidgetLoweredState(w, 20, !_station_show_coverage);
+			SetWindowWidgetLoweredState(w, 21, _station_show_coverage);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+
+		case 22:
+		case 23:
+			ShowDropDownMenu(w, BuildStationClassDropdown(), _railstation.station_class, 23, 0, 1 << STAT_CLASS_WAYP);
+			break;
+
+		case 24: {
+			const StationSpec *statspec;
+			int y = (e->we.click.pt.y - 32) / 14;
+
+			if (y >= w->vscroll.cap) return;
+			y += w->vscroll.pos;
+			if (y >= _railstation.station_count) return;
+
+			/* Check station availability callback */
+			statspec = GetCustomStationSpec(_railstation.station_class, y);
+			if (statspec != NULL &&
+				HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
+				GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
+
+			_railstation.station_type = y;
+
+			CheckSelectedSize(w, statspec);
+
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		}
+		}
+	} break;
+
+	case WE_DROPDOWN_SELECT:
+		if (_railstation.station_class != e->we.dropdown.index) {
+			_railstation.station_class = e->we.dropdown.index;
+			_railstation.station_type  = 0;
+			_railstation.station_count = GetNumCustomStations(_railstation.station_class);
+
+			CheckSelectedSize(w, GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
+
+			w->vscroll.count = _railstation.station_count;
+			w->vscroll.pos   = _railstation.station_type;
+		}
+
+		SndPlayFx(SND_15_BEEP);
+		SetWindowDirty(w);
+		break;
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) {
+			DeleteWindow(w);
+			return;
+		}
+		CheckRedrawStationCoverage(w);
+		break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _station_builder_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   199, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,    87,    98, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,    87,    98, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,    87,    98, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,    87,    98, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,    87,    98, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,    87,    98, STR_0335_6,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,    87,    98, STR_0336_7,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   112,   123, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   112,   123, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   112,   123, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   112,   123, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   112,   123, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   112,   123, STR_0335_6,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   112,   123, STR_0336_7,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   126,   137, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   152,   163, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   152,   163, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{   WIDGETS_END},
+};
+
+static const Widget _newstation_builder_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   289, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   177,   188, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   177,   188, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   177,   188, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   177,   188, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   177,   188, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   177,   188, STR_0335_6,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   177,   188, STR_0336_7,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   202,   213, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   202,   213, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   202,   213, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   202,   213, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   202,   213, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   202,   213, STR_0335_6,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   202,   213, STR_0336_7,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   216,   227, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   242,   253, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   242,   253, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},
+
+/* newstations gui additions */
+{      WWT_INSET,   RESIZE_NONE,    14,     7,   140,    17,    28, STR_02BD,                        STR_SELECT_STATION_CLASS_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   129,   139,    18,    27, STR_0225,                        STR_SELECT_STATION_CLASS_TIP},
+{     WWT_MATRIX,   RESIZE_NONE,    14,     7,   128,    32,   102, 0x501,                           STR_SELECT_STATION_TYPE_TIP},
+{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   129,   140,    32,   102, 0x0,                             STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _station_builder_desc = {
+	WDP_AUTO, WDP_AUTO, 148, 200,
+	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_station_builder_widgets,
+	StationBuildWndProc
+};
+
+static const WindowDesc _newstation_builder_desc = {
+	WDP_AUTO, WDP_AUTO, 148, 290,
+	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_newstation_builder_widgets,
+	StationBuildWndProc
+};
+
+static void ShowStationBuilder(void)
+{
+	Window *w;
+	if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
+		w = AllocateWindowDesc(&_station_builder_desc);
+		_railstation.newstations = false;
+	} else {
+		w = AllocateWindowDesc(&_newstation_builder_desc);
+		_railstation.newstations = true;
+		_railstation.station_count = GetNumCustomStations(_railstation.station_class);
+
+		w->vscroll.count = _railstation.station_count;
+		w->vscroll.cap   = 5;
+		w->vscroll.pos   = clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
+	}
+}
+
+static void BuildTrainDepotWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _build_depot_direction + 3); break;
+
+	case WE_PAINT: {
+		RailType r;
+
+		DrawWindowWidgets(w);
+
+		r = _cur_railtype;
+		DrawTrainDepotSprite(70, 17, 0, r);
+		DrawTrainDepotSprite(70, 69, 1, r);
+		DrawTrainDepotSprite( 2, 69, 2, r);
+		DrawTrainDepotSprite( 2, 17, 3, r);
+		break;
+		}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+				RaiseWindowWidget(w, _build_depot_direction + 3);
+				_build_depot_direction = e->we.click.widget - 3;
+				LowerWindowWidget(w, _build_depot_direction + 3);
+				SndPlayFx(SND_15_BEEP);
+				SetWindowDirty(w);
+				break;
+		}
+		break;
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) DeleteWindow(w);
+		return;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_depot_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1014_TRAIN_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 140, 122,
+	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_depot_widgets,
+	BuildTrainDepotWndProc
+};
+
+static void ShowBuildTrainDepotPicker(void)
+{
+	AllocateWindowDesc(&_build_depot_desc);
+}
+
+
+static void BuildWaypointWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		uint i;
+
+		for (i = 0; i < w->hscroll.cap; i++) {
+			SetWindowWidgetLoweredState(w, i + 3, (w->hscroll.pos + i) == _cur_waypoint_type);
+		}
+
+		DrawWindowWidgets(w);
+
+		for (i = 0; i < w->hscroll.cap; i++) {
+			if (w->hscroll.pos + i < w->hscroll.count) {
+				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, w->hscroll.pos + i);
+
+				DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
+
+				if (statspec != NULL &&
+						HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
+						GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+					GfxFillRect(4 + i * 68, 18, 67 + i * 68, 75, PALETTE_MODIFIER_GREYOUT);
+				}
+			}
+		}
+		break;
+	}
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3: case 4: case 5: case 6: case 7: {
+			byte type = e->we.click.widget - 3 + w->hscroll.pos;
+
+			/* Check station availability callback */
+			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
+			if (statspec != NULL &&
+					HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) &&
+					GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
+
+			_cur_waypoint_type = type;
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		}
+		}
+		break;
+	}
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) DeleteWindow(w);
+		break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_waypoint_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   343,     0,    13, STR_WAYPOINT, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   343,    14,    91, 0x0,          0},
+
+{      WWT_PANEL,   RESIZE_NONE,     7,     3,    68,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
+{      WWT_PANEL,   RESIZE_NONE,     7,    71,   136,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
+{      WWT_PANEL,   RESIZE_NONE,     7,   139,   204,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
+{      WWT_PANEL,   RESIZE_NONE,     7,   207,   272,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
+{      WWT_PANEL,   RESIZE_NONE,     7,   275,   340,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},
+
+{ WWT_HSCROLLBAR,   RESIZE_NONE,    7,     1,   343,     80,    91, 0x0,          STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{    WIDGETS_END},
+};
+
+static const WindowDesc _build_waypoint_desc = {
+	WDP_AUTO, WDP_AUTO, 344, 92,
+	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_waypoint_widgets,
+	BuildWaypointWndProc
+};
+
+static void ShowBuildWaypointPicker(void)
+{
+	Window *w = AllocateWindowDesc(&_build_waypoint_desc);
+	w->hscroll.cap = 5;
+	w->hscroll.count = _waypoint_count;
+}
+
+
+void InitializeRailGui(void)
+{
+	_build_depot_direction = DIAGDIR_NW;
+	_railstation.numtracks = 1;
+	_railstation.platlength = 1;
+	_railstation.dragdrop = true;
+}
+
+void ReinitGuiAfterToggleElrail(bool disable)
+{
+	extern RailType _last_built_railtype;
+	if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) {
+		Window *w;
+		_last_built_railtype = _cur_railtype = RAILTYPE_RAIL;
+		w = FindWindowById(WC_BUILD_TOOLBAR, 0);
+		if (w != NULL && w->wndproc == BuildRailToolbWndProc) {
+			SetupRailToolbar(_cur_railtype, w);
+			SetWindowDirty(w);
+		}
+	}
+	MarkWholeScreenDirty();
+}
+
+
deleted file mode 100644
--- a/src/road_cmd.c
+++ /dev/null
@@ -1,1065 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "rail_map.h"
-#include "road_map.h"
-#include "sprite.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "town_map.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
-#include "player.h"
-#include "town.h"
-#include "gfx.h"
-#include "sound.h"
-#include "yapf/yapf.h"
-#include "depot.h"
-
-
-static uint CountRoadBits(RoadBits r)
-{
-	uint count = 0;
-
-	if (r & ROAD_NW) ++count;
-	if (r & ROAD_SW) ++count;
-	if (r & ROAD_SE) ++count;
-	if (r & ROAD_NE) ++count;
-	return count;
-}
-
-
-static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool* edge_road)
-{
-	RoadBits present;
-	RoadBits n;
-	Owner owner;
-	*edge_road = true;
-
-	if (_game_mode == GM_EDITOR) return true;
-
-	// Only do the special processing for actual players.
-	if (!IsValidPlayer(_current_player)) return true;
-
-	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
-
-	// Only do the special processing if the road is owned
-	// by a town
-	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
-
-	if (_cheats.magic_bulldozer.value) return true;
-
-	// Get a bitmask of which neighbouring roads has a tile
-	n = 0;
-	present = GetAnyRoadBits(tile);
-	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile,-1, 0)) & ROAD_SW) n |= ROAD_NE;
-	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE;
-	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW;
-	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0,-1)) & ROAD_SE) n |= ROAD_NW;
-
-	// If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
-	// then allow it
-	if ((n & (n - 1)) != 0 && (n & remove) != 0) {
-		Town *t;
-		*edge_road = false;
-		// you can remove all kind of roads with extra dynamite
-		if (_patches.extra_dynamite) return true;
-
-		t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-
-		SetDParam(0, t->index);
-		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
-		return false;
-	}
-
-	return true;
-}
-
-
-/** Delete a piece of road.
- * @param tile tile where to remove road from
- * @param p1 road piece flags
- * @param p2 unused
- */
-int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	// cost for removing inner/edge -roads
-	static const uint16 road_remove_cost[2] = {50, 18};
-
-	Owner owner;
-	Town *t;
-	/* true if the roadpiece was always removeable,
-	 * false if it was a center piece. Affects town ratings drop */
-	bool edge_road;
-	RoadBits pieces;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) */
-	if (p1 >> 4) return CMD_ERROR;
-	pieces = p1;
-
-	if (!IsTileType(tile, MP_STREET)) return CMD_ERROR;
-
-	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
-
-	if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) {
-		t = GetTownByTile(tile);
-	} else {
-		t = NULL;
-	}
-
-	if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	// check if you're allowed to remove the street owned by a town
-	// removal allowance depends on difficulty setting
-	if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
-
-	switch (GetRoadTileType(tile)) {
-		case ROAD_TILE_NORMAL: {
-			RoadBits present = GetRoadBits(tile);
-			RoadBits c = pieces;
-
-			if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
-
-			if (GetTileSlope(tile, NULL) != SLOPE_FLAT  &&
-					(present == ROAD_Y || present == ROAD_X)) {
-				c |= (c & 0xC) >> 2;
-				c |= (c & 0x3) << 2;
-			}
-
-			// limit the bits to delete to the existing bits.
-			c &= present;
-			if (c == 0) return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
-
-				present ^= c;
-				if (present == 0) {
-					DoClearSquare(tile);
-				} else {
-					SetRoadBits(tile, present);
-					MarkTileDirtyByTile(tile);
-				}
-			}
-			return CountRoadBits(c) * _price.remove_road;
-		}
-
-		case ROAD_TILE_CROSSING: {
-			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
-				return CMD_ERROR;
-			}
-
-			if (flags & DC_EXEC) {
-				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
-
-				MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
-				MarkTileDirtyByTile(tile);
-				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
-			}
-			return _price.remove_road * 2;
-		}
-
-		default:
-		case ROAD_TILE_DEPOT:
-			return CMD_ERROR;
-	}
-}
-
-
-static const RoadBits _valid_tileh_slopes_road[][15] = {
-	// set of normal ones
-	{
-		ROAD_ALL, 0, 0,
-		ROAD_X,   0, 0,  // 3, 4, 5
-		ROAD_Y,   0, 0,
-		ROAD_Y,   0, 0,  // 9, 10, 11
-		ROAD_X,   0, 0
-	},
-	// allowed road for an evenly raised platform
-	{
-		0,
-		ROAD_SW | ROAD_NW,
-		ROAD_SW | ROAD_SE,
-		ROAD_Y  | ROAD_SW,
-
-		ROAD_SE | ROAD_NE, // 4
-		ROAD_ALL,
-		ROAD_X  | ROAD_SE,
-		ROAD_ALL,
-
-		ROAD_NW | ROAD_NE, // 8
-		ROAD_X  | ROAD_NW,
-		ROAD_ALL,
-		ROAD_ALL,
-
-		ROAD_Y  | ROAD_NE, // 12
-		ROAD_ALL,
-		ROAD_ALL
-	},
-};
-
-
-static uint32 CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
-{
-	RoadBits road_bits;
-
-	if (IsSteepSlope(tileh)) {
-		if (existing == 0) {
-			// force full pieces.
-			*pieces |= (*pieces & 0xC) >> 2;
-			*pieces |= (*pieces & 0x3) << 2;
-			if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
-		}
-		return CMD_ERROR;
-	}
-	road_bits = *pieces | existing;
-
-	// no special foundation
-	if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == 0) {
-		// force that all bits are set when we have slopes
-		if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
-		return 0; // no extra cost
-	}
-
-	// foundation is used. Whole tile is leveled up
-	if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == 0) {
-		return existing != 0 ? 0 : _price.terraform;
-	}
-
-	// partly leveled up tile, only if there's no road on that tile
-	if (existing == 0 && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
-		// force full pieces.
-		*pieces |= (*pieces & 0xC) >> 2;
-		*pieces |= (*pieces & 0x3) << 2;
-		if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
-	}
-	return CMD_ERROR;
-}
-
-/** Build a piece of road.
- * @param tile tile where to build road
- * @param p1 road piece flags
- * @param p2 the town that is building the road (0 if not applicable)
- */
-int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost = 0;
-	int32 ret;
-	RoadBits existing = 0;
-	RoadBits pieces;
-	Slope tileh;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
-	 * if a non-player is building the road */
-	if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
-	pieces = p1;
-
-	tileh = GetTileSlope(tile, NULL);
-
-	switch (GetTileType(tile)) {
-		case MP_STREET:
-			switch (GetRoadTileType(tile)) {
-				case ROAD_TILE_NORMAL:
-					if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
-
-					existing = GetRoadBits(tile);
-					if ((existing & pieces) == pieces) {
-						return_cmd_error(STR_1007_ALREADY_BUILT);
-					}
-					if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-					break;
-
-				case ROAD_TILE_CROSSING:
-					if (pieces != GetCrossingRoadBits(tile)) { // XXX is this correct?
-						return_cmd_error(STR_1007_ALREADY_BUILT);
-					}
-					goto do_clear;
-
-				default:
-				case ROAD_TILE_DEPOT:
-					goto do_clear;
-			}
-			break;
-
-		case MP_RAILWAY: {
-			Axis roaddir;
-
-			if (IsSteepSlope(tileh)) {
-				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-			}
-
-#define M(x) (1 << (x))
-			/* Level crossings may only be built on these slopes */
-			if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
-				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-			}
-#undef M
-
-			if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
-			switch (GetTrackBits(tile)) {
-				case TRACK_BIT_X:
-					if (pieces & ROAD_X) goto do_clear;
-					roaddir = AXIS_Y;
-					break;
-
-				case TRACK_BIT_Y:
-					if (pieces & ROAD_Y) goto do_clear;
-					roaddir = AXIS_X;
-					break;
-
-				default: goto do_clear;
-			}
-
-			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
-				MakeRoadCrossing(tile, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), p2);
-				MarkTileDirtyByTile(tile);
-			}
-			return _price.build_road * 2;
-		}
-
-		default:
-do_clear:;
-			ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-	}
-
-	ret = CheckRoadSlope(tileh, &pieces, existing);
-	/* Return an error if we need to build a foundation (ret != 0) but the
-	 * current patch-setting is turned off (or stupid AI@work) */
-	if (CmdFailed(ret) || (ret != 0 && (!_patches.build_on_slopes || _is_old_ai_player)))
-		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-
-	cost += ret;
-
-	if (IsTileType(tile, MP_STREET)) {
-		// Don't put the pieces that already exist
-		pieces &= ComplementRoadBits(existing);
-	}
-
-	cost += CountRoadBits(pieces) * _price.build_road;
-
-	if (flags & DC_EXEC) {
-		if (IsTileType(tile, MP_STREET)) {
-			SetRoadBits(tile, existing | pieces);
-		} else {
-			MakeRoadNormal(tile, _current_player, pieces, p2);
-		}
-
-		MarkTileDirtyByTile(tile);
-	}
-	return cost;
-}
-
-int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec)
-{
-	// not a railroad crossing?
-	if (!IsLevelCrossing(tile)) return CMD_ERROR;
-
-	// not owned by me?
-	if (!CheckTileOwnership(tile) || !EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (GetRailTypeCrossing(tile) == totype) return CMD_ERROR;
-
-	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
-	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailTypeCrossing(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
-
-	if (exec) {
-		SetRailTypeCrossing(tile, totype);
-		MarkTileDirtyByTile(tile);
-		YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetCrossingRailBits(tile)));
-	}
-
-	return _price.build_rail >> 1;
-}
-
-
-/** Build a long piece of road.
- * @param end_tile end tile of drag
- * @param p1 start tile of drag
- * @param p2 various bitstuffed elements
- * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1)
- * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2)
- * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
- */
-int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TileIndex start_tile, tile;
-	int32 cost, ret;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	start_tile = p1;
-
-	/* Only drag in X or Y direction dictated by the direction variable */
-	if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
-	if (HASBIT(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
-
-	/* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
-	if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) {
-		TileIndex t = start_tile;
-		start_tile = end_tile;
-		end_tile = t;
-		p2 ^= IS_INT_INSIDE(p2&3, 1, 3) ? 3 : 0;
-	}
-
-	cost = 0;
-	tile = start_tile;
-	// Start tile is the small number.
-	for (;;) {
-		RoadBits bits = HASBIT(p2, 2) ? ROAD_Y : ROAD_X;
-
-		if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE;
-		if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW;
-
-		ret = DoCommand(tile, bits, 0, flags, CMD_BUILD_ROAD);
-		if (CmdFailed(ret)) {
-			if (_error_message != STR_1007_ALREADY_BUILT) return CMD_ERROR;
-			_error_message = INVALID_STRING_ID;
-		} else {
-			cost += ret;
-		}
-
-		if (tile == end_tile) break;
-
-		tile += HASBIT(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
-	}
-
-	return (cost == 0) ? CMD_ERROR : cost;
-}
-
-/** Remove a long piece of road.
- * @param end_tile end tile of drag
- * @param p1 start tile of drag
- * @param p2 various bitstuffed elements
- * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1)
- * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2)
- * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
- */
-int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TileIndex start_tile, tile;
-	int32 cost, ret;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	start_tile = p1;
-
-	/* Only drag in X or Y direction dictated by the direction variable */
-	if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
-	if (HASBIT(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
-
-	/* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
-	if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) {
-		TileIndex t = start_tile;
-		start_tile = end_tile;
-		end_tile = t;
-		p2 ^= IS_INT_INSIDE(p2 & 3, 1, 3) ? 3 : 0;
-	}
-
-	cost = 0;
-	tile = start_tile;
-	// Start tile is the small number.
-	for (;;) {
-		RoadBits bits = HASBIT(p2, 2) ? ROAD_Y : ROAD_X;
-
-		if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE;
-		if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW;
-
-		// try to remove the halves.
-		if (bits != 0) {
-			ret = DoCommand(tile, bits, 0, flags, CMD_REMOVE_ROAD);
-			if (!CmdFailed(ret)) cost += ret;
-		}
-
-		if (tile == end_tile) break;
-
-		tile += HASBIT(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
-	}
-
-	return (cost == 0) ? CMD_ERROR : cost;
-}
-
-/** Build a road depot.
- * @param tile tile where to build the depot
- * @param p1 entrance direction (DiagDirection)
- * @param p2 unused
- *
- * @todo When checking for the tile slope,
- * distingush between "Flat land required" and "land sloped in wrong direction"
- */
-int32 CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost;
-	Depot *dep;
-	Slope tileh;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (p1 > 3) return CMD_ERROR; // check direction
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	tileh = GetTileSlope(tile, NULL);
-	if (tileh != SLOPE_FLAT && (
-				!_patches.build_on_slopes ||
-				IsSteepSlope(tileh) ||
-				!CanBuildDepotByTileh(p1, tileh)
-			)) {
-		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-	}
-
-	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(cost)) return CMD_ERROR;
-
-	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-	dep = AllocateDepot();
-	if (dep == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		dep->xy = tile;
-		dep->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
-
-		MakeRoadDepot(tile, _current_player, p1);
-		MarkTileDirtyByTile(tile);
-	}
-	return cost + _price.build_road_depot;
-}
-
-static int32 RemoveRoadDepot(TileIndex tile, uint32 flags)
-{
-	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
-		return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) DeleteDepot(GetDepotByTile(tile));
-
-	return _price.remove_road_depot;
-}
-
-#define M(x) (1<<(x))
-
-static int32 ClearTile_Road(TileIndex tile, byte flags)
-{
-	switch (GetRoadTileType(tile)) {
-		case ROAD_TILE_NORMAL: {
-			RoadBits b = GetRoadBits(tile);
-
-			if (!((1 << b) & (M(1)|M(2)|M(4)|M(8))) &&
-					(!(flags & DC_AI_BUILDING) || !IsTileOwner(tile, OWNER_TOWN)) &&
-					flags & DC_AUTO) {
-				return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
-			}
-			return DoCommand(tile, b, 0, flags, CMD_REMOVE_ROAD);
-		}
-
-		case ROAD_TILE_CROSSING: {
-			int32 ret;
-
-			if (flags & DC_AUTO) return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
-
-			ret = DoCommand(tile, GetCrossingRoadBits(tile), 0, flags, CMD_REMOVE_ROAD);
-			if (CmdFailed(ret)) return CMD_ERROR;
-
-			if (flags & DC_EXEC) {
-				DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			}
-			return ret;
-		}
-
-		default:
-		case ROAD_TILE_DEPOT:
-			if (flags & DC_AUTO) {
-				return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
-			}
-			return RemoveRoadDepot(tile, flags);
-	}
-}
-
-
-typedef struct DrawRoadTileStruct {
-	uint16 image;
-	byte subcoord_x;
-	byte subcoord_y;
-} DrawRoadTileStruct;
-
-#include "table/road_land.h"
-
-
-uint GetRoadFoundation(Slope tileh, RoadBits bits)
-{
-	uint i;
-
-	// normal level sloped building
-	if (!IsSteepSlope(tileh) &&
-			(~_valid_tileh_slopes_road[1][tileh] & bits) == 0) {
-		return tileh;
-	}
-
-	// inclined sloped building
-	switch (bits) {
-		case ROAD_X: i = 0; break;
-		case ROAD_Y: i = 1; break;
-		default:     return 0;
-	}
-	switch (tileh) {
-		case SLOPE_W:
-		case SLOPE_STEEP_W: i += 0; break;
-		case SLOPE_S:
-		case SLOPE_STEEP_S: i += 2; break;
-		case SLOPE_E:
-		case SLOPE_STEEP_E: i += 4; break;
-		case SLOPE_N:
-		case SLOPE_STEEP_N: i += 6; break;
-		default: return 0;
-	}
-	return i + 15;
-}
-
-const byte _road_sloped_sprites[14] = {
-	0,  0,  2,  0,
-	0,  1,  0,  0,
-	3,  0,  0,  0,
-	0,  0
-};
-
-/**
- * Draw ground sprite and road pieces
- * @param ti TileInfo
- * @param road RoadBits to draw
- */
-static void DrawRoadBits(TileInfo* ti)
-{
-	RoadBits road = GetRoadBits(ti->tile);
-	const DrawRoadTileStruct *drts;
-	PalSpriteID image = 0;
-	Roadside roadside;
-
-	if (ti->tileh != SLOPE_FLAT) {
-		int foundation = GetRoadFoundation(ti->tileh, road);
-
-		if (foundation != 0) DrawFoundation(ti, foundation);
-
-		// DrawFoundation() modifies ti.
-		// Default sloped sprites..
-		if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
-	}
-
-	if (image == 0) image = _road_tile_sprites_1[road];
-
-	roadside = GetRoadside(ti->tile);
-
-	if (IsOnSnow(ti->tile)) {
-		image += 19;
-	} else {
-		switch (roadside) {
-			case ROADSIDE_BARREN:           image |= PALETTE_TO_BARE_LAND; break;
-			case ROADSIDE_GRASS:            break;
-			case ROADSIDE_GRASS_ROAD_WORKS: break;
-			default:                        image -= 19; break; // Paved
-		}
-	}
-
-	DrawGroundSprite(image);
-
-	if (HasRoadWorks(ti->tile)) {
-		// Road works
-		DrawGroundSprite(road & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y);
-		return;
-	}
-
-	// Return if full detail is disabled, or we are zoomed fully out.
-	if (!(_display_opt & DO_FULL_DETAIL) || _cur_dpi->zoom == 2) return;
-
-	// Draw extra details.
-	for (drts = _road_display_table[roadside][road]; drts->image != 0; drts++) {
-		int x = ti->x | drts->subcoord_x;
-		int y = ti->y | drts->subcoord_y;
-		byte z = ti->z;
-		if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y);
-		AddSortableSpriteToDraw(drts->image, x, y, 2, 2, 0x10, z);
-	}
-}
-
-static void DrawTile_Road(TileInfo *ti)
-{
-	switch (GetRoadTileType(ti->tile)) {
-		case ROAD_TILE_NORMAL:
-			DrawRoadBits(ti);
-			break;
-
-		case ROAD_TILE_CROSSING: {
-			PalSpriteID image;
-
-			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-
-			image = GetRailTypeInfo(GetRailTypeCrossing(ti->tile))->base_sprites.crossing;
-
-			if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++;
-			if (IsCrossingBarred(ti->tile)) image += 2;
-
-			if (IsOnSnow(ti->tile)) {
-				image += 8;
-			} else {
-				switch (GetRoadside(ti->tile)) {
-					case ROADSIDE_BARREN: image |= PALETTE_TO_BARE_LAND; break;
-					case ROADSIDE_GRASS:  break;
-					default:              image += 4; break; // Paved
-				}
-			}
-
-			DrawGroundSprite(image);
-			if (GetRailTypeCrossing(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-			break;
-		}
-
-		default:
-		case ROAD_TILE_DEPOT: {
-			const DrawTileSprites* dts;
-			const DrawTileSeqStruct* dtss;
-			uint32 palette;
-
-			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-
-			palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
-
-			dts =  &_road_depot[GetRoadDepotDirection(ti->tile)];
-			DrawGroundSprite(dts->ground_sprite);
-
-			for (dtss = dts->seq; dtss->image != 0; dtss++) {
-				uint32 image = dtss->image;
-
-				if (_display_opt & DO_TRANS_BUILDINGS) {
-					MAKE_TRANSPARENT(image);
-				} else if (image & PALETTE_MODIFIER_COLOR) {
-					image |= palette;
-				}
-
-				AddSortableSpriteToDraw(
-					image,
-					ti->x + dtss->delta_x, ti->y + dtss->delta_y,
-					dtss->size_x, dtss->size_y,
-					dtss->size_z, ti->z
-				);
-			}
-			break;
-		}
-	}
-	DrawBridgeMiddle(ti);
-}
-
-void DrawRoadDepotSprite(int x, int y, DiagDirection dir)
-{
-	uint32 palette = PLAYER_SPRITE_COLOR(_local_player);
-	const DrawTileSprites* dts =  &_road_depot[dir];
-	const DrawTileSeqStruct* dtss;
-
-	x += 33;
-	y += 17;
-
-	DrawSprite(dts->ground_sprite, x, y);
-
-	for (dtss = dts->seq; dtss->image != 0; dtss++) {
-		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
-		uint32 image = dtss->image;
-
-		if (image & PALETTE_MODIFIER_COLOR) image |= palette;
-
-		DrawSprite(image, x + pt.x, y + pt.y);
-	}
-}
-
-static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	Slope tileh = GetTileSlope(tile, &z);
-
-	if (tileh == SLOPE_FLAT) return z;
-	if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
-		uint f = GetRoadFoundation(tileh, GetRoadBits(tile));
-
-		if (f != 0) {
-			if (IsSteepSlope(tileh)) {
-				z += TILE_HEIGHT;
-			} else if (f < 15) {
-				return z + TILE_HEIGHT; // leveled foundation
-			}
-			tileh = _inclined_tileh[f - 15]; // inclined foundation
-		}
-		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-	} else {
-		return z + TILE_HEIGHT;
-	}
-}
-
-static Slope GetSlopeTileh_Road(TileIndex tile, Slope tileh)
-{
-	if (tileh == SLOPE_FLAT) return SLOPE_FLAT;
-	if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
-		uint f = GetRoadFoundation(tileh, GetRoadBits(tile));
-
-		if (f == 0) return tileh;
-		if (f < 15) return SLOPE_FLAT; // leveled foundation
-		return _inclined_tileh[f - 15]; // inclined foundation
-	} else {
-		return SLOPE_FLAT;
-	}
-}
-
-static void GetAcceptedCargo_Road(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void AnimateTile_Road(TileIndex tile)
-{
-	if (IsLevelCrossing(tile)) MarkTileDirtyByTile(tile);
-}
-
-
-static const Roadside _town_road_types[][2] = {
-	{ ROADSIDE_GRASS,         ROADSIDE_GRASS },
-	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
-	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
-	{ ROADSIDE_TREES,         ROADSIDE_TREES },
-	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
-};
-
-static const Roadside _town_road_types_2[][2] = {
-	{ ROADSIDE_GRASS,         ROADSIDE_GRASS },
-	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
-	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
-	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
-	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
-};
-
-
-static void TileLoop_Road(TileIndex tile)
-{
-	switch (_opt.landscape) {
-		case LT_HILLY:
-			if (IsOnSnow(tile) != (GetTileZ(tile) > _opt.snow_line)) {
-				ToggleSnow(tile);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		case LT_DESERT:
-			if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) {
-				ToggleDesert(tile);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-	}
-
-	if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) return;
-
-	if (!HasRoadWorks(tile)) {
-		const Town* t = ClosestTownFromTile(tile, (uint)-1);
-		int grp = 0;
-
-		if (t != NULL) {
-			grp = GetTownRadiusGroup(t, tile);
-
-			// Show an animation to indicate road work
-			if (t->road_build_months != 0 &&
-					(DistanceManhattan(t->xy, tile) < 8 || grp != 0) &&
-					GetRoadTileType(tile) == ROAD_TILE_NORMAL && (GetRoadBits(tile) == ROAD_X || GetRoadBits(tile) == ROAD_Y)) {
-				if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicle(tile) && CHANCE16(1, 20)) {
-					StartRoadWorks(tile);
-
-					SndPlayTileFx(SND_21_JACKHAMMER, tile);
-					CreateEffectVehicleAbove(
-						TileX(tile) * TILE_SIZE + 7,
-						TileY(tile) * TILE_SIZE + 7,
-						0,
-						EV_BULLDOZER);
-					MarkTileDirtyByTile(tile);
-					return;
-				}
-			}
-		}
-
-		{
-			/* Adjust road ground type depending on 'grp' (grp is the distance to the center) */
-			const Roadside* new_rs = (_opt.landscape == LT_CANDY) ? _town_road_types_2[grp] : _town_road_types[grp];
-			Roadside cur_rs = GetRoadside(tile);
-
-			/* We have our desired type, do nothing */
-			if (cur_rs == new_rs[0]) return;
-
-			/* We have the pre-type of the desired type, switch to the desired type */
-			if (cur_rs == new_rs[1]) {
-				cur_rs = new_rs[0];
-			/* We have barren land, install the pre-type */
-			} else if (cur_rs == ROADSIDE_BARREN) {
-				cur_rs = new_rs[1];
-			/* We're totally off limits, remove any installation and make barren land */
-			} else {
-				cur_rs = ROADSIDE_BARREN;
-			}
-			SetRoadside(tile, cur_rs);
-			MarkTileDirtyByTile(tile);
-		}
-	} else if (IncreaseRoadWorksCounter(tile)) {
-		TerminateRoadWorks(tile);
-		MarkTileDirtyByTile(tile);
-	}
-}
-
-static void ClickTile_Road(TileIndex tile)
-{
-	if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) ShowDepotWindow(tile, VEH_Road);
-}
-
-static const byte _road_trackbits[16] = {
-	0x0, 0x0, 0x0, 0x10, 0x0, 0x2, 0x8, 0x1A, 0x0, 0x4, 0x1, 0x15, 0x20, 0x26, 0x29, 0x3F,
-};
-
-static uint32 GetTileTrackStatus_Road(TileIndex tile, TransportType mode)
-{
-	switch (mode) {
-		case TRANSPORT_RAIL:
-			if (!IsLevelCrossing(tile)) return 0;
-			return GetCrossingRailBits(tile) * 0x101;
-
-		case TRANSPORT_ROAD:
-			switch (GetRoadTileType(tile)) {
-				case ROAD_TILE_NORMAL:
-					return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile)] * 0x101;
-
-				case ROAD_TILE_CROSSING: {
-					uint32 r = AxisToTrackBits(GetCrossingRoadAxis(tile)) * 0x101;
-
-					if (IsCrossingBarred(tile)) r *= 0x10001;
-					return r;
-				}
-
-				default:
-				case ROAD_TILE_DEPOT:
-					return AxisToTrackBits(DiagDirToAxis(GetRoadDepotDirection(tile))) * 0x101;
-			}
-			break;
-
-		default: break;
-	}
-	return 0;
-}
-
-static const StringID _road_tile_strings[] = {
-	STR_1814_ROAD,
-	STR_1814_ROAD,
-	STR_1814_ROAD,
-	STR_1815_ROAD_WITH_STREETLIGHTS,
-	STR_1814_ROAD,
-	STR_1816_TREE_LINED_ROAD,
-	STR_1814_ROAD,
-	STR_1814_ROAD,
-};
-
-static void GetTileDesc_Road(TileIndex tile, TileDesc *td)
-{
-	td->owner = GetTileOwner(tile);
-	switch (GetRoadTileType(tile)) {
-		case ROAD_TILE_CROSSING: td->str = STR_1818_ROAD_RAIL_LEVEL_CROSSING; break;
-		case ROAD_TILE_DEPOT: td->str = STR_1817_ROAD_VEHICLE_DEPOT; break;
-		default: td->str = _road_tile_strings[GetRoadside(tile)]; break;
-	}
-}
-
-static const byte _roadveh_enter_depot_unk0[4] = {
-	8, 9, 0, 1
-};
-
-static uint32 VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
-{
-	switch (GetRoadTileType(tile)) {
-		case ROAD_TILE_CROSSING:
-			if (v->type == VEH_Train && !IsCrossingBarred(tile)) {
-				/* train crossing a road */
-				SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
-				BarCrossing(tile);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		case ROAD_TILE_DEPOT:
-			if (v->type == VEH_Road &&
-					v->u.road.frame == 11 &&
-					_roadveh_enter_depot_unk0[GetRoadDepotDirection(tile)] == v->u.road.state) {
-				VehicleEnterDepot(v);
-				return 4;
-			}
-			break;
-
-		default: break;
-	}
-	return 0;
-}
-
-
-static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) == old_player) {
-		SetCrossingRoadOwner(tile, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player);
-	}
-
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (new_player != PLAYER_SPECTATOR) {
-		SetTileOwner(tile, new_player);
-	} else {
-		switch (GetRoadTileType(tile)) {
-			case ROAD_TILE_NORMAL:
-				SetTileOwner(tile, OWNER_NONE);
-				break;
-
-			case ROAD_TILE_CROSSING:
-				MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile));
-				break;
-
-			default:
-			case ROAD_TILE_DEPOT:
-				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-				break;
-		}
-	}
-}
-
-
-const TileTypeProcs _tile_type_road_procs = {
-	DrawTile_Road,           /* draw_tile_proc */
-	GetSlopeZ_Road,          /* get_slope_z_proc */
-	ClearTile_Road,          /* clear_tile_proc */
-	GetAcceptedCargo_Road,   /* get_accepted_cargo_proc */
-	GetTileDesc_Road,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Road, /* get_tile_track_status_proc */
-	ClickTile_Road,          /* click_tile_proc */
-	AnimateTile_Road,        /* animate_tile_proc */
-	TileLoop_Road,           /* tile_loop_clear */
-	ChangeTileOwner_Road,    /* change_tile_owner_clear */
-	NULL,                    /* get_produced_cargo_proc */
-	VehicleEnter_Road,       /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Road,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/road_cmd.cpp
@@ -0,0 +1,1065 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "rail_map.h"
+#include "road_map.h"
+#include "sprite.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "town_map.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "command.h"
+#include "player.h"
+#include "town.h"
+#include "gfx.h"
+#include "sound.h"
+#include "yapf/yapf.h"
+#include "depot.h"
+
+
+static uint CountRoadBits(RoadBits r)
+{
+	uint count = 0;
+
+	if (r & ROAD_NW) ++count;
+	if (r & ROAD_SW) ++count;
+	if (r & ROAD_SE) ++count;
+	if (r & ROAD_NE) ++count;
+	return count;
+}
+
+
+static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool* edge_road)
+{
+	RoadBits present;
+	RoadBits n;
+	Owner owner;
+	*edge_road = true;
+
+	if (_game_mode == GM_EDITOR) return true;
+
+	// Only do the special processing for actual players.
+	if (!IsValidPlayer(_current_player)) return true;
+
+	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
+
+	// Only do the special processing if the road is owned
+	// by a town
+	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
+
+	if (_cheats.magic_bulldozer.value) return true;
+
+	// Get a bitmask of which neighbouring roads has a tile
+	n = 0;
+	present = GetAnyRoadBits(tile);
+	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile,-1, 0)) & ROAD_SW) n |= ROAD_NE;
+	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE;
+	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW;
+	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0,-1)) & ROAD_SE) n |= ROAD_NW;
+
+	// If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
+	// then allow it
+	if ((n & (n - 1)) != 0 && (n & remove) != 0) {
+		Town *t;
+		*edge_road = false;
+		// you can remove all kind of roads with extra dynamite
+		if (_patches.extra_dynamite) return true;
+
+		t = ClosestTownFromTile(tile, _patches.dist_local_authority);
+
+		SetDParam(0, t->index);
+		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
+		return false;
+	}
+
+	return true;
+}
+
+
+/** Delete a piece of road.
+ * @param tile tile where to remove road from
+ * @param p1 road piece flags
+ * @param p2 unused
+ */
+int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	// cost for removing inner/edge -roads
+	static const uint16 road_remove_cost[2] = {50, 18};
+
+	Owner owner;
+	Town *t;
+	/* true if the roadpiece was always removeable,
+	 * false if it was a center piece. Affects town ratings drop */
+	bool edge_road;
+	RoadBits pieces;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) */
+	if (p1 >> 4) return CMD_ERROR;
+	pieces = p1;
+
+	if (!IsTileType(tile, MP_STREET)) return CMD_ERROR;
+
+	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
+
+	if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) {
+		t = GetTownByTile(tile);
+	} else {
+		t = NULL;
+	}
+
+	if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	// check if you're allowed to remove the street owned by a town
+	// removal allowance depends on difficulty setting
+	if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
+
+	switch (GetRoadTileType(tile)) {
+		case ROAD_TILE_NORMAL: {
+			RoadBits present = GetRoadBits(tile);
+			RoadBits c = pieces;
+
+			if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
+
+			if (GetTileSlope(tile, NULL) != SLOPE_FLAT  &&
+					(present == ROAD_Y || present == ROAD_X)) {
+				c |= (c & 0xC) >> 2;
+				c |= (c & 0x3) << 2;
+			}
+
+			// limit the bits to delete to the existing bits.
+			c &= present;
+			if (c == 0) return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
+
+				present ^= c;
+				if (present == 0) {
+					DoClearSquare(tile);
+				} else {
+					SetRoadBits(tile, present);
+					MarkTileDirtyByTile(tile);
+				}
+			}
+			return CountRoadBits(c) * _price.remove_road;
+		}
+
+		case ROAD_TILE_CROSSING: {
+			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
+				return CMD_ERROR;
+			}
+
+			if (flags & DC_EXEC) {
+				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
+
+				MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
+				MarkTileDirtyByTile(tile);
+				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
+			}
+			return _price.remove_road * 2;
+		}
+
+		default:
+		case ROAD_TILE_DEPOT:
+			return CMD_ERROR;
+	}
+}
+
+
+static const RoadBits _valid_tileh_slopes_road[][15] = {
+	// set of normal ones
+	{
+		ROAD_ALL, 0, 0,
+		ROAD_X,   0, 0,  // 3, 4, 5
+		ROAD_Y,   0, 0,
+		ROAD_Y,   0, 0,  // 9, 10, 11
+		ROAD_X,   0, 0
+	},
+	// allowed road for an evenly raised platform
+	{
+		0,
+		ROAD_SW | ROAD_NW,
+		ROAD_SW | ROAD_SE,
+		ROAD_Y  | ROAD_SW,
+
+		ROAD_SE | ROAD_NE, // 4
+		ROAD_ALL,
+		ROAD_X  | ROAD_SE,
+		ROAD_ALL,
+
+		ROAD_NW | ROAD_NE, // 8
+		ROAD_X  | ROAD_NW,
+		ROAD_ALL,
+		ROAD_ALL,
+
+		ROAD_Y  | ROAD_NE, // 12
+		ROAD_ALL,
+		ROAD_ALL
+	},
+};
+
+
+static uint32 CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
+{
+	RoadBits road_bits;
+
+	if (IsSteepSlope(tileh)) {
+		if (existing == 0) {
+			// force full pieces.
+			*pieces |= (*pieces & 0xC) >> 2;
+			*pieces |= (*pieces & 0x3) << 2;
+			if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
+		}
+		return CMD_ERROR;
+	}
+	road_bits = *pieces | existing;
+
+	// no special foundation
+	if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == 0) {
+		// force that all bits are set when we have slopes
+		if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
+		return 0; // no extra cost
+	}
+
+	// foundation is used. Whole tile is leveled up
+	if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == 0) {
+		return existing != 0 ? 0 : _price.terraform;
+	}
+
+	// partly leveled up tile, only if there's no road on that tile
+	if (existing == 0 && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
+		// force full pieces.
+		*pieces |= (*pieces & 0xC) >> 2;
+		*pieces |= (*pieces & 0x3) << 2;
+		if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
+	}
+	return CMD_ERROR;
+}
+
+/** Build a piece of road.
+ * @param tile tile where to build road
+ * @param p1 road piece flags
+ * @param p2 the town that is building the road (0 if not applicable)
+ */
+int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost = 0;
+	int32 ret;
+	RoadBits existing = 0;
+	RoadBits pieces;
+	Slope tileh;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
+	 * if a non-player is building the road */
+	if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
+	pieces = p1;
+
+	tileh = GetTileSlope(tile, NULL);
+
+	switch (GetTileType(tile)) {
+		case MP_STREET:
+			switch (GetRoadTileType(tile)) {
+				case ROAD_TILE_NORMAL:
+					if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
+
+					existing = GetRoadBits(tile);
+					if ((existing & pieces) == pieces) {
+						return_cmd_error(STR_1007_ALREADY_BUILT);
+					}
+					if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+					break;
+
+				case ROAD_TILE_CROSSING:
+					if (pieces != GetCrossingRoadBits(tile)) { // XXX is this correct?
+						return_cmd_error(STR_1007_ALREADY_BUILT);
+					}
+					goto do_clear;
+
+				default:
+				case ROAD_TILE_DEPOT:
+					goto do_clear;
+			}
+			break;
+
+		case MP_RAILWAY: {
+			Axis roaddir;
+
+			if (IsSteepSlope(tileh)) {
+				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+			}
+
+#define M(x) (1 << (x))
+			/* Level crossings may only be built on these slopes */
+			if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
+				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+			}
+#undef M
+
+			if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
+			switch (GetTrackBits(tile)) {
+				case TRACK_BIT_X:
+					if (pieces & ROAD_X) goto do_clear;
+					roaddir = AXIS_Y;
+					break;
+
+				case TRACK_BIT_Y:
+					if (pieces & ROAD_Y) goto do_clear;
+					roaddir = AXIS_X;
+					break;
+
+				default: goto do_clear;
+			}
+
+			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
+				MakeRoadCrossing(tile, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), p2);
+				MarkTileDirtyByTile(tile);
+			}
+			return _price.build_road * 2;
+		}
+
+		default:
+do_clear:;
+			ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			if (CmdFailed(ret)) return ret;
+			cost += ret;
+	}
+
+	ret = CheckRoadSlope(tileh, &pieces, existing);
+	/* Return an error if we need to build a foundation (ret != 0) but the
+	 * current patch-setting is turned off (or stupid AI@work) */
+	if (CmdFailed(ret) || (ret != 0 && (!_patches.build_on_slopes || _is_old_ai_player)))
+		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+
+	cost += ret;
+
+	if (IsTileType(tile, MP_STREET)) {
+		// Don't put the pieces that already exist
+		pieces &= ComplementRoadBits(existing);
+	}
+
+	cost += CountRoadBits(pieces) * _price.build_road;
+
+	if (flags & DC_EXEC) {
+		if (IsTileType(tile, MP_STREET)) {
+			SetRoadBits(tile, existing | pieces);
+		} else {
+			MakeRoadNormal(tile, _current_player, pieces, p2);
+		}
+
+		MarkTileDirtyByTile(tile);
+	}
+	return cost;
+}
+
+int32 DoConvertStreetRail(TileIndex tile, RailType totype, bool exec)
+{
+	// not a railroad crossing?
+	if (!IsLevelCrossing(tile)) return CMD_ERROR;
+
+	// not owned by me?
+	if (!CheckTileOwnership(tile) || !EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (GetRailTypeCrossing(tile) == totype) return CMD_ERROR;
+
+	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
+	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailTypeCrossing(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
+
+	if (exec) {
+		SetRailTypeCrossing(tile, totype);
+		MarkTileDirtyByTile(tile);
+		YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetCrossingRailBits(tile)));
+	}
+
+	return _price.build_rail >> 1;
+}
+
+
+/** Build a long piece of road.
+ * @param end_tile end tile of drag
+ * @param p1 start tile of drag
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1)
+ * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2)
+ * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
+ */
+int32 CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TileIndex start_tile, tile;
+	int32 cost, ret;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	start_tile = p1;
+
+	/* Only drag in X or Y direction dictated by the direction variable */
+	if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
+	if (HASBIT(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
+
+	/* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
+	if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) {
+		TileIndex t = start_tile;
+		start_tile = end_tile;
+		end_tile = t;
+		p2 ^= IS_INT_INSIDE(p2&3, 1, 3) ? 3 : 0;
+	}
+
+	cost = 0;
+	tile = start_tile;
+	// Start tile is the small number.
+	for (;;) {
+		RoadBits bits = HASBIT(p2, 2) ? ROAD_Y : ROAD_X;
+
+		if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE;
+		if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW;
+
+		ret = DoCommand(tile, bits, 0, flags, CMD_BUILD_ROAD);
+		if (CmdFailed(ret)) {
+			if (_error_message != STR_1007_ALREADY_BUILT) return CMD_ERROR;
+			_error_message = INVALID_STRING_ID;
+		} else {
+			cost += ret;
+		}
+
+		if (tile == end_tile) break;
+
+		tile += HASBIT(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
+	}
+
+	return (cost == 0) ? CMD_ERROR : cost;
+}
+
+/** Remove a long piece of road.
+ * @param end_tile end tile of drag
+ * @param p1 start tile of drag
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1)
+ * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2)
+ * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
+ */
+int32 CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TileIndex start_tile, tile;
+	int32 cost, ret;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	start_tile = p1;
+
+	/* Only drag in X or Y direction dictated by the direction variable */
+	if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
+	if (HASBIT(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
+
+	/* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
+	if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) {
+		TileIndex t = start_tile;
+		start_tile = end_tile;
+		end_tile = t;
+		p2 ^= IS_INT_INSIDE(p2 & 3, 1, 3) ? 3 : 0;
+	}
+
+	cost = 0;
+	tile = start_tile;
+	// Start tile is the small number.
+	for (;;) {
+		RoadBits bits = HASBIT(p2, 2) ? ROAD_Y : ROAD_X;
+
+		if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE;
+		if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW;
+
+		// try to remove the halves.
+		if (bits != 0) {
+			ret = DoCommand(tile, bits, 0, flags, CMD_REMOVE_ROAD);
+			if (!CmdFailed(ret)) cost += ret;
+		}
+
+		if (tile == end_tile) break;
+
+		tile += HASBIT(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
+	}
+
+	return (cost == 0) ? CMD_ERROR : cost;
+}
+
+/** Build a road depot.
+ * @param tile tile where to build the depot
+ * @param p1 entrance direction (DiagDirection)
+ * @param p2 unused
+ *
+ * @todo When checking for the tile slope,
+ * distingush between "Flat land required" and "land sloped in wrong direction"
+ */
+int32 CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost;
+	Depot *dep;
+	Slope tileh;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (p1 > 3) return CMD_ERROR; // check direction
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	tileh = GetTileSlope(tile, NULL);
+	if (tileh != SLOPE_FLAT && (
+				!_patches.build_on_slopes ||
+				IsSteepSlope(tileh) ||
+				!CanBuildDepotByTileh(p1, tileh)
+			)) {
+		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+	}
+
+	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(cost)) return CMD_ERROR;
+
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
+	dep = AllocateDepot();
+	if (dep == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		dep->xy = tile;
+		dep->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
+
+		MakeRoadDepot(tile, _current_player, p1);
+		MarkTileDirtyByTile(tile);
+	}
+	return cost + _price.build_road_depot;
+}
+
+static int32 RemoveRoadDepot(TileIndex tile, uint32 flags)
+{
+	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
+		return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) DeleteDepot(GetDepotByTile(tile));
+
+	return _price.remove_road_depot;
+}
+
+#define M(x) (1<<(x))
+
+static int32 ClearTile_Road(TileIndex tile, byte flags)
+{
+	switch (GetRoadTileType(tile)) {
+		case ROAD_TILE_NORMAL: {
+			RoadBits b = GetRoadBits(tile);
+
+			if (!((1 << b) & (M(1)|M(2)|M(4)|M(8))) &&
+					(!(flags & DC_AI_BUILDING) || !IsTileOwner(tile, OWNER_TOWN)) &&
+					flags & DC_AUTO) {
+				return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
+			}
+			return DoCommand(tile, b, 0, flags, CMD_REMOVE_ROAD);
+		}
+
+		case ROAD_TILE_CROSSING: {
+			int32 ret;
+
+			if (flags & DC_AUTO) return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
+
+			ret = DoCommand(tile, GetCrossingRoadBits(tile), 0, flags, CMD_REMOVE_ROAD);
+			if (CmdFailed(ret)) return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			}
+			return ret;
+		}
+
+		default:
+		case ROAD_TILE_DEPOT:
+			if (flags & DC_AUTO) {
+				return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+			}
+			return RemoveRoadDepot(tile, flags);
+	}
+}
+
+
+typedef struct DrawRoadTileStruct {
+	uint16 image;
+	byte subcoord_x;
+	byte subcoord_y;
+} DrawRoadTileStruct;
+
+#include "table/road_land.h"
+
+
+uint GetRoadFoundation(Slope tileh, RoadBits bits)
+{
+	uint i;
+
+	// normal level sloped building
+	if (!IsSteepSlope(tileh) &&
+			(~_valid_tileh_slopes_road[1][tileh] & bits) == 0) {
+		return tileh;
+	}
+
+	// inclined sloped building
+	switch (bits) {
+		case ROAD_X: i = 0; break;
+		case ROAD_Y: i = 1; break;
+		default:     return 0;
+	}
+	switch (tileh) {
+		case SLOPE_W:
+		case SLOPE_STEEP_W: i += 0; break;
+		case SLOPE_S:
+		case SLOPE_STEEP_S: i += 2; break;
+		case SLOPE_E:
+		case SLOPE_STEEP_E: i += 4; break;
+		case SLOPE_N:
+		case SLOPE_STEEP_N: i += 6; break;
+		default: return 0;
+	}
+	return i + 15;
+}
+
+const byte _road_sloped_sprites[14] = {
+	0,  0,  2,  0,
+	0,  1,  0,  0,
+	3,  0,  0,  0,
+	0,  0
+};
+
+/**
+ * Draw ground sprite and road pieces
+ * @param ti TileInfo
+ * @param road RoadBits to draw
+ */
+static void DrawRoadBits(TileInfo* ti)
+{
+	RoadBits road = GetRoadBits(ti->tile);
+	const DrawRoadTileStruct *drts;
+	PalSpriteID image = 0;
+	Roadside roadside;
+
+	if (ti->tileh != SLOPE_FLAT) {
+		int foundation = GetRoadFoundation(ti->tileh, road);
+
+		if (foundation != 0) DrawFoundation(ti, foundation);
+
+		// DrawFoundation() modifies ti.
+		// Default sloped sprites..
+		if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
+	}
+
+	if (image == 0) image = _road_tile_sprites_1[road];
+
+	roadside = GetRoadside(ti->tile);
+
+	if (IsOnSnow(ti->tile)) {
+		image += 19;
+	} else {
+		switch (roadside) {
+			case ROADSIDE_BARREN:           image |= PALETTE_TO_BARE_LAND; break;
+			case ROADSIDE_GRASS:            break;
+			case ROADSIDE_GRASS_ROAD_WORKS: break;
+			default:                        image -= 19; break; // Paved
+		}
+	}
+
+	DrawGroundSprite(image);
+
+	if (HasRoadWorks(ti->tile)) {
+		// Road works
+		DrawGroundSprite(road & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y);
+		return;
+	}
+
+	// Return if full detail is disabled, or we are zoomed fully out.
+	if (!(_display_opt & DO_FULL_DETAIL) || _cur_dpi->zoom == 2) return;
+
+	// Draw extra details.
+	for (drts = _road_display_table[roadside][road]; drts->image != 0; drts++) {
+		int x = ti->x | drts->subcoord_x;
+		int y = ti->y | drts->subcoord_y;
+		byte z = ti->z;
+		if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y);
+		AddSortableSpriteToDraw(drts->image, x, y, 2, 2, 0x10, z);
+	}
+}
+
+static void DrawTile_Road(TileInfo *ti)
+{
+	switch (GetRoadTileType(ti->tile)) {
+		case ROAD_TILE_NORMAL:
+			DrawRoadBits(ti);
+			break;
+
+		case ROAD_TILE_CROSSING: {
+			PalSpriteID image;
+
+			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+
+			image = GetRailTypeInfo(GetRailTypeCrossing(ti->tile))->base_sprites.crossing;
+
+			if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++;
+			if (IsCrossingBarred(ti->tile)) image += 2;
+
+			if (IsOnSnow(ti->tile)) {
+				image += 8;
+			} else {
+				switch (GetRoadside(ti->tile)) {
+					case ROADSIDE_BARREN: image |= PALETTE_TO_BARE_LAND; break;
+					case ROADSIDE_GRASS:  break;
+					default:              image += 4; break; // Paved
+				}
+			}
+
+			DrawGroundSprite(image);
+			if (GetRailTypeCrossing(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+			break;
+		}
+
+		default:
+		case ROAD_TILE_DEPOT: {
+			const DrawTileSprites* dts;
+			const DrawTileSeqStruct* dtss;
+			uint32 palette;
+
+			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+
+			palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
+
+			dts =  &_road_depot[GetRoadDepotDirection(ti->tile)];
+			DrawGroundSprite(dts->ground_sprite);
+
+			for (dtss = dts->seq; dtss->image != 0; dtss++) {
+				uint32 image = dtss->image;
+
+				if (_display_opt & DO_TRANS_BUILDINGS) {
+					MAKE_TRANSPARENT(image);
+				} else if (image & PALETTE_MODIFIER_COLOR) {
+					image |= palette;
+				}
+
+				AddSortableSpriteToDraw(
+					image,
+					ti->x + dtss->delta_x, ti->y + dtss->delta_y,
+					dtss->size_x, dtss->size_y,
+					dtss->size_z, ti->z
+				);
+			}
+			break;
+		}
+	}
+	DrawBridgeMiddle(ti);
+}
+
+void DrawRoadDepotSprite(int x, int y, DiagDirection dir)
+{
+	uint32 palette = PLAYER_SPRITE_COLOR(_local_player);
+	const DrawTileSprites* dts =  &_road_depot[dir];
+	const DrawTileSeqStruct* dtss;
+
+	x += 33;
+	y += 17;
+
+	DrawSprite(dts->ground_sprite, x, y);
+
+	for (dtss = dts->seq; dtss->image != 0; dtss++) {
+		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
+		uint32 image = dtss->image;
+
+		if (image & PALETTE_MODIFIER_COLOR) image |= palette;
+
+		DrawSprite(image, x + pt.x, y + pt.y);
+	}
+}
+
+static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	Slope tileh = GetTileSlope(tile, &z);
+
+	if (tileh == SLOPE_FLAT) return z;
+	if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
+		uint f = GetRoadFoundation(tileh, GetRoadBits(tile));
+
+		if (f != 0) {
+			if (IsSteepSlope(tileh)) {
+				z += TILE_HEIGHT;
+			} else if (f < 15) {
+				return z + TILE_HEIGHT; // leveled foundation
+			}
+			tileh = _inclined_tileh[f - 15]; // inclined foundation
+		}
+		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+	} else {
+		return z + TILE_HEIGHT;
+	}
+}
+
+static Slope GetSlopeTileh_Road(TileIndex tile, Slope tileh)
+{
+	if (tileh == SLOPE_FLAT) return SLOPE_FLAT;
+	if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
+		uint f = GetRoadFoundation(tileh, GetRoadBits(tile));
+
+		if (f == 0) return tileh;
+		if (f < 15) return SLOPE_FLAT; // leveled foundation
+		return _inclined_tileh[f - 15]; // inclined foundation
+	} else {
+		return SLOPE_FLAT;
+	}
+}
+
+static void GetAcceptedCargo_Road(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void AnimateTile_Road(TileIndex tile)
+{
+	if (IsLevelCrossing(tile)) MarkTileDirtyByTile(tile);
+}
+
+
+static const Roadside _town_road_types[][2] = {
+	{ ROADSIDE_GRASS,         ROADSIDE_GRASS },
+	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
+	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
+	{ ROADSIDE_TREES,         ROADSIDE_TREES },
+	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
+};
+
+static const Roadside _town_road_types_2[][2] = {
+	{ ROADSIDE_GRASS,         ROADSIDE_GRASS },
+	{ ROADSIDE_PAVED,         ROADSIDE_PAVED },
+	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
+	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
+	{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
+};
+
+
+static void TileLoop_Road(TileIndex tile)
+{
+	switch (_opt.landscape) {
+		case LT_HILLY:
+			if (IsOnSnow(tile) != (GetTileZ(tile) > _opt.snow_line)) {
+				ToggleSnow(tile);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		case LT_DESERT:
+			if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) {
+				ToggleDesert(tile);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+	}
+
+	if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) return;
+
+	if (!HasRoadWorks(tile)) {
+		const Town* t = ClosestTownFromTile(tile, (uint)-1);
+		int grp = 0;
+
+		if (t != NULL) {
+			grp = GetTownRadiusGroup(t, tile);
+
+			// Show an animation to indicate road work
+			if (t->road_build_months != 0 &&
+					(DistanceManhattan(t->xy, tile) < 8 || grp != 0) &&
+					GetRoadTileType(tile) == ROAD_TILE_NORMAL && (GetRoadBits(tile) == ROAD_X || GetRoadBits(tile) == ROAD_Y)) {
+				if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicle(tile) && CHANCE16(1, 20)) {
+					StartRoadWorks(tile);
+
+					SndPlayTileFx(SND_21_JACKHAMMER, tile);
+					CreateEffectVehicleAbove(
+						TileX(tile) * TILE_SIZE + 7,
+						TileY(tile) * TILE_SIZE + 7,
+						0,
+						EV_BULLDOZER);
+					MarkTileDirtyByTile(tile);
+					return;
+				}
+			}
+		}
+
+		{
+			/* Adjust road ground type depending on 'grp' (grp is the distance to the center) */
+			const Roadside* new_rs = (_opt.landscape == LT_CANDY) ? _town_road_types_2[grp] : _town_road_types[grp];
+			Roadside cur_rs = GetRoadside(tile);
+
+			/* We have our desired type, do nothing */
+			if (cur_rs == new_rs[0]) return;
+
+			/* We have the pre-type of the desired type, switch to the desired type */
+			if (cur_rs == new_rs[1]) {
+				cur_rs = new_rs[0];
+			/* We have barren land, install the pre-type */
+			} else if (cur_rs == ROADSIDE_BARREN) {
+				cur_rs = new_rs[1];
+			/* We're totally off limits, remove any installation and make barren land */
+			} else {
+				cur_rs = ROADSIDE_BARREN;
+			}
+			SetRoadside(tile, cur_rs);
+			MarkTileDirtyByTile(tile);
+		}
+	} else if (IncreaseRoadWorksCounter(tile)) {
+		TerminateRoadWorks(tile);
+		MarkTileDirtyByTile(tile);
+	}
+}
+
+static void ClickTile_Road(TileIndex tile)
+{
+	if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) ShowDepotWindow(tile, VEH_Road);
+}
+
+static const byte _road_trackbits[16] = {
+	0x0, 0x0, 0x0, 0x10, 0x0, 0x2, 0x8, 0x1A, 0x0, 0x4, 0x1, 0x15, 0x20, 0x26, 0x29, 0x3F,
+};
+
+static uint32 GetTileTrackStatus_Road(TileIndex tile, TransportType mode)
+{
+	switch (mode) {
+		case TRANSPORT_RAIL:
+			if (!IsLevelCrossing(tile)) return 0;
+			return GetCrossingRailBits(tile) * 0x101;
+
+		case TRANSPORT_ROAD:
+			switch (GetRoadTileType(tile)) {
+				case ROAD_TILE_NORMAL:
+					return HasRoadWorks(tile) ? 0 : _road_trackbits[GetRoadBits(tile)] * 0x101;
+
+				case ROAD_TILE_CROSSING: {
+					uint32 r = AxisToTrackBits(GetCrossingRoadAxis(tile)) * 0x101;
+
+					if (IsCrossingBarred(tile)) r *= 0x10001;
+					return r;
+				}
+
+				default:
+				case ROAD_TILE_DEPOT:
+					return AxisToTrackBits(DiagDirToAxis(GetRoadDepotDirection(tile))) * 0x101;
+			}
+			break;
+
+		default: break;
+	}
+	return 0;
+}
+
+static const StringID _road_tile_strings[] = {
+	STR_1814_ROAD,
+	STR_1814_ROAD,
+	STR_1814_ROAD,
+	STR_1815_ROAD_WITH_STREETLIGHTS,
+	STR_1814_ROAD,
+	STR_1816_TREE_LINED_ROAD,
+	STR_1814_ROAD,
+	STR_1814_ROAD,
+};
+
+static void GetTileDesc_Road(TileIndex tile, TileDesc *td)
+{
+	td->owner = GetTileOwner(tile);
+	switch (GetRoadTileType(tile)) {
+		case ROAD_TILE_CROSSING: td->str = STR_1818_ROAD_RAIL_LEVEL_CROSSING; break;
+		case ROAD_TILE_DEPOT: td->str = STR_1817_ROAD_VEHICLE_DEPOT; break;
+		default: td->str = _road_tile_strings[GetRoadside(tile)]; break;
+	}
+}
+
+static const byte _roadveh_enter_depot_unk0[4] = {
+	8, 9, 0, 1
+};
+
+static uint32 VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
+{
+	switch (GetRoadTileType(tile)) {
+		case ROAD_TILE_CROSSING:
+			if (v->type == VEH_Train && !IsCrossingBarred(tile)) {
+				/* train crossing a road */
+				SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
+				BarCrossing(tile);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		case ROAD_TILE_DEPOT:
+			if (v->type == VEH_Road &&
+					v->u.road.frame == 11 &&
+					_roadveh_enter_depot_unk0[GetRoadDepotDirection(tile)] == v->u.road.state) {
+				VehicleEnterDepot(v);
+				return 4;
+			}
+			break;
+
+		default: break;
+	}
+	return 0;
+}
+
+
+static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) == old_player) {
+		SetCrossingRoadOwner(tile, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player);
+	}
+
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (new_player != PLAYER_SPECTATOR) {
+		SetTileOwner(tile, new_player);
+	} else {
+		switch (GetRoadTileType(tile)) {
+			case ROAD_TILE_NORMAL:
+				SetTileOwner(tile, OWNER_NONE);
+				break;
+
+			case ROAD_TILE_CROSSING:
+				MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile));
+				break;
+
+			default:
+			case ROAD_TILE_DEPOT:
+				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+				break;
+		}
+	}
+}
+
+
+const TileTypeProcs _tile_type_road_procs = {
+	DrawTile_Road,           /* draw_tile_proc */
+	GetSlopeZ_Road,          /* get_slope_z_proc */
+	ClearTile_Road,          /* clear_tile_proc */
+	GetAcceptedCargo_Road,   /* get_accepted_cargo_proc */
+	GetTileDesc_Road,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Road, /* get_tile_track_status_proc */
+	ClickTile_Road,          /* click_tile_proc */
+	AnimateTile_Road,        /* animate_tile_proc */
+	TileLoop_Road,           /* tile_loop_clear */
+	ChangeTileOwner_Road,    /* change_tile_owner_clear */
+	NULL,                    /* get_produced_cargo_proc */
+	VehicleEnter_Road,       /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Road,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/road_gui.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "road_cmd.h"
-#include "road_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "sound.h"
-#include "command.h"
-#include "variables.h"
-//needed for catchments
-#include "station.h"
-
-
-static void ShowBusStationPicker(void);
-static void ShowTruckStationPicker(void);
-static void ShowRoadDepotPicker(void);
-
-static bool _remove_button_clicked;
-
-static byte _place_road_flag;
-
-static byte _road_depot_orientation;
-static byte _road_station_picker_orientation;
-
-void CcPlaySound1D(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) SndPlayTileFx(SND_1F_SPLAT, tile);
-}
-
-static void PlaceRoad_NE(TileIndex tile)
-{
-	_place_road_flag = (_tile_fract_coords.y >= 8) + 4;
-	VpStartPlaceSizing(tile, VPM_FIX_X);
-}
-
-static void PlaceRoad_NW(TileIndex tile)
-{
-	_place_road_flag = (_tile_fract_coords.x >= 8) + 0;
-	VpStartPlaceSizing(tile, VPM_FIX_Y);
-}
-
-static void PlaceRoad_Bridge(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_OR_Y);
-}
-
-
-void CcBuildRoadTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_20_SPLAT_2, tile);
-		ResetObjectToPlace();
-	} else {
-		SetRedErrorSquare(_build_tunnel_endtile);
-	}
-}
-
-static void PlaceRoad_Tunnel(TileIndex tile)
-{
-	DoCommandP(tile, 0x200, 0, CcBuildRoadTunnel, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
-}
-
-static void BuildRoadOutsideStation(TileIndex tile, DiagDirection direction)
-{
-	tile += TileOffsByDiagDir(direction);
-	// if there is a roadpiece just outside of the station entrance, build a connecting route
-	if (IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
-		DoCommandP(tile, DiagDirToRoadBits(ReverseDiagDir(direction)), 0, NULL, CMD_BUILD_ROAD);
-	}
-}
-
-void CcRoadDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_1F_SPLAT, tile);
-		ResetObjectToPlace();
-		BuildRoadOutsideStation(tile, p1);
-	}
-}
-
-static void PlaceRoad_Depot(TileIndex tile)
-{
-	DoCommandP(tile, _road_depot_orientation, 0, CcRoadDepot, CMD_BUILD_ROAD_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1807_CAN_T_BUILD_ROAD_VEHICLE));
-}
-
-static void PlaceRoad_BusStation(TileIndex tile)
-{
-	DoCommandP(tile, _road_station_picker_orientation, RS_BUS, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION));
-}
-
-static void PlaceRoad_TruckStation(TileIndex tile)
-{
-	DoCommandP(tile, _road_station_picker_orientation, RS_TRUCK, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION));
-}
-
-static void PlaceRoad_DemolishArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, 4);
-}
-
-
-enum {
-	RTW_ROAD_X        =  3,
-	RTW_ROAD_Y        =  4,
-	RTW_DEMOLISH      =  5,
-	RTW_DEPOT         =  6,
-	RTW_BUS_STATION   =  7,
-	RTW_TRUCK_STATION =  8,
-	RTW_BUILD_BRIDGE  =  9,
-	RTW_BUILD_TUNNEL  = 10,
-	RTW_REMOVE        = 11
-};
-
-
-typedef void OnButtonClick(Window *w);
-
-static void BuildRoadClick_NE(Window *w)
-{
-	HandlePlacePushButton(w, RTW_ROAD_X, SPR_CURSOR_ROAD_NESW, 1, PlaceRoad_NE);
-}
-
-static void BuildRoadClick_NW(Window *w)
-{
-	HandlePlacePushButton(w, RTW_ROAD_Y, SPR_CURSOR_ROAD_NWSE, 1, PlaceRoad_NW);
-}
-
-
-static void BuildRoadClick_Demolish(Window *w)
-{
-	HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceRoad_DemolishArea);
-}
-
-static void BuildRoadClick_Depot(Window *w)
-{
-	if (_game_mode == GM_EDITOR) return;
-	if (HandlePlacePushButton(w, RTW_DEPOT, SPR_CURSOR_ROAD_DEPOT, 1, PlaceRoad_Depot)) ShowRoadDepotPicker();
-}
-
-static void BuildRoadClick_BusStation(Window *w)
-{
-	if (_game_mode == GM_EDITOR) return;
-	if (HandlePlacePushButton(w, RTW_BUS_STATION, SPR_CURSOR_BUS_STATION, 1, PlaceRoad_BusStation)) ShowBusStationPicker();
-}
-
-static void BuildRoadClick_TruckStation(Window *w)
-{
-	if (_game_mode == GM_EDITOR) return;
-	if (HandlePlacePushButton(w, RTW_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, 1, PlaceRoad_TruckStation)) ShowTruckStationPicker();
-}
-
-static void BuildRoadClick_Bridge(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, 1, PlaceRoad_Bridge);
-}
-
-static void BuildRoadClick_Tunnel(Window *w)
-{
-	HandlePlacePushButton(w, RTW_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, 3, PlaceRoad_Tunnel);
-}
-
-static void BuildRoadClick_Remove(Window *w)
-{
-	if (IsWindowWidgetDisabled(w, RTW_REMOVE)) return;
-	SetWindowDirty(w);
-	SndPlayFx(SND_15_BEEP);
-	ToggleWidgetLoweredState(w, RTW_REMOVE);
-	SetSelectionRed(IsWindowWidgetLowered(w, RTW_REMOVE));
-}
-
-static void BuildRoadClick_Landscaping(Window *w)
-{
-	ShowTerraformToolbar();
-}
-
-static OnButtonClick* const _build_road_button_proc[] = {
-	BuildRoadClick_NE,
-	BuildRoadClick_NW,
-	BuildRoadClick_Demolish,
-	BuildRoadClick_Depot,
-	BuildRoadClick_BusStation,
-	BuildRoadClick_TruckStation,
-	BuildRoadClick_Bridge,
-	BuildRoadClick_Tunnel,
-	BuildRoadClick_Remove,
-	BuildRoadClick_Landscaping,
-};
-
-static void BuildRoadToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: DisableWindowWidget(w, RTW_REMOVE); break;
-
-	case WE_PAINT:
-		if (IsWindowWidgetLowered(w, RTW_ROAD_X) || IsWindowWidgetLowered(w, RTW_ROAD_Y)) {
-			EnableWindowWidget(w, RTW_REMOVE);
-		}
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK: {
-		if (e->we.click.widget >= 3) _build_road_button_proc[e->we.click.widget - 3](w);
-	}	break;
-
-	case WE_KEYPRESS:
-		switch (e->we.keypress.keycode) {
-			case '1': BuildRoadClick_NE(w);           break;
-			case '2': BuildRoadClick_NW(w);           break;
-			case '3': BuildRoadClick_Demolish(w);     break;
-			case '4': BuildRoadClick_Depot(w);        break;
-			case '5': BuildRoadClick_BusStation(w);   break;
-			case '6': BuildRoadClick_TruckStation(w); break;
-			case 'B': BuildRoadClick_Bridge(w);       break;
-			case 'T': BuildRoadClick_Tunnel(w);       break;
-			case 'R': BuildRoadClick_Remove(w);       break;
-			case 'L': BuildRoadClick_Landscaping(w);  break;
-			default: return;
-		}
-		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
-		e->we.keypress.cont = false;
-		break;
-
-	case WE_PLACE_OBJ:
-		_remove_button_clicked = IsWindowWidgetLowered(w, RTW_REMOVE);
-		_place_proc(e->we.place.tile);
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		DisableWindowWidget(w, RTW_REMOVE);
-		InvalidateWidget(w, RTW_REMOVE);
-
-		w = FindWindowById(WC_BUS_STATION, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		w = FindWindowById(WC_TRUCK_STATION, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		w = FindWindowById(WC_BUILD_DEPOT, 0);
-		if (w != NULL) WP(w,def_d).close = true;
-		break;
-
-	case WE_PLACE_DRAG: {
-		int sel_method;
-		switch (e->we.place.userdata) {
-			case 1:
-				sel_method = VPM_FIX_X;
-				_place_road_flag = (_place_road_flag & ~2) | ((e->we.place.pt.y & 8) >> 2);
-				break;
-
-			case 2:
-				sel_method = VPM_FIX_Y;
-				_place_road_flag = (_place_road_flag & ~2) | ((e->we.place.pt.x & 8) >> 2);
-				break;
-
-			case 4:
-				sel_method = VPM_X_AND_Y;
-				break;
-
-			default:
-				sel_method = VPM_X_OR_Y;
-				break;
-		}
-
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, sel_method);
-		return;
-	}
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			TileIndex start_tile = e->we.place.starttile;
-			TileIndex end_tile = e->we.place.tile;
-
-			if (e->we.place.userdata == 0) {
-				ResetObjectToPlace();
-				ShowBuildBridgeWindow(start_tile, end_tile, 0x80);
-			} else if (e->we.place.userdata != 4) {
-				DoCommandP(end_tile, start_tile, _place_road_flag, CcPlaySound1D,
-					_remove_button_clicked ?
-					CMD_REMOVE_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1805_CAN_T_REMOVE_ROAD_FROM) :
-					CMD_BUILD_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1804_CAN_T_BUILD_ROAD_HERE));
-			} else {
-				DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
-			}
-		}
-		break;
-
-	case WE_PLACE_PRESIZE: {
-		TileIndex tile = e->we.place.tile;
-
-		DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
-		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
-		break;
-	}
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
-	}
-}
-
-static const Widget _build_road_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   227,     0,    13, STR_1802_ROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   228,   239,     0,    13, 0x0,                        STR_STICKY_BUTTON},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_ROAD_NW,            STR_180B_BUILD_ROAD_SECTION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_ROAD_NE,            STR_180B_BUILD_ROAD_SECTION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,    87,    14,    35, SPR_IMG_ROAD_DEPOT,         STR_180C_BUILD_ROAD_VEHICLE_DEPOT},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    88,   109,    14,    35, SPR_IMG_BUS_STATION,        STR_180D_BUILD_BUS_STATION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   110,   131,    14,    35, SPR_IMG_TRUCK_BAY,          STR_180E_BUILD_TRUCK_LOADING_BAY},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   132,   173,    14,    35, SPR_IMG_BRIDGE,             STR_180F_BUILD_ROAD_BRIDGE},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   174,   195,    14,    35, SPR_IMG_ROAD_TUNNEL,        STR_1810_BUILD_ROAD_TUNNEL},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   196,   217,    14,    35, SPR_IMG_REMOVE,             STR_1811_TOGGLE_BUILD_REMOVE_FOR},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   218,   239,    14,    35, SPR_IMG_LANDSCAPING,        STR_LANDSCAPING_TOOLBAR_TIP},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_road_desc = {
-	WDP_ALIGN_TBR, 22, 240, 36,
-	WC_BUILD_TOOLBAR, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_build_road_widgets,
-	BuildRoadToolbWndProc
-};
-
-void ShowBuildRoadToolbar(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-
-	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
-	AllocateWindowDesc(&_build_road_desc);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
-}
-
-static const Widget _build_road_scen_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   140,     0,    13, STR_1802_ROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   141,   152,     0,    13, 0x0,                        STR_STICKY_BUTTON},
-
-{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_ROAD_NW,            STR_180B_BUILD_ROAD_SECTION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_ROAD_NE,            STR_180B_BUILD_ROAD_SECTION},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,   107,    14,    35, SPR_IMG_BRIDGE,             STR_180F_BUILD_ROAD_BRIDGE},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   108,   129,    14,    35, SPR_IMG_ROAD_TUNNEL,        STR_1810_BUILD_ROAD_TUNNEL},
-{     WWT_IMGBTN,   RESIZE_NONE,     7,   130,   151,    14,    35, SPR_IMG_REMOVE,             STR_1811_TOGGLE_BUILD_REMOVE_FOR},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_road_scen_desc = {
-	WDP_AUTO, WDP_AUTO, 152, 36,
-	WC_SCEN_BUILD_ROAD, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_build_road_scen_widgets,
-	BuildRoadToolbWndProc
-};
-
-void ShowBuildRoadScenToolbar(void)
-{
-	AllocateWindowDescFront(&_build_road_scen_desc, 0);
-}
-
-static void BuildRoadDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: LowerWindowWidget(w, _road_depot_orientation + 3); break;
-
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-
-		DrawRoadDepotSprite(70, 17, DIAGDIR_NE);
-		DrawRoadDepotSprite(70, 69, DIAGDIR_SE);
-		DrawRoadDepotSprite( 2, 69, DIAGDIR_SW);
-		DrawRoadDepotSprite( 2, 17, DIAGDIR_NW);
-		break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3: case 4: case 5: case 6:
-			RaiseWindowWidget(w, _road_depot_orientation + 3);
-			_road_depot_orientation = e->we.click.widget - 3;
-			LowerWindowWidget(w, _road_depot_orientation + 3);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		}
-	}	break;
-
-	case WE_MOUSELOOP:
-		if (WP(w,def_d).close) DeleteWindow(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _build_road_depot_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1806_ROAD_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _build_road_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 140, 122,
-	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_road_depot_widgets,
-	BuildRoadDepotWndProc
-};
-
-static void ShowRoadDepotPicker(void)
-{
-	AllocateWindowDesc(&_build_road_depot_desc);
-}
-
-static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		LowerWindowWidget(w, _road_station_picker_orientation + 3);
-		LowerWindowWidget(w, _station_show_coverage + 7);
-		break;
-
-	case WE_PAINT: {
-		int image;
-
-		if (WP(w,def_d).close) return;
-
-		DrawWindowWidgets(w);
-
-		if (_station_show_coverage) {
-			int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : 4;
-			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-		} else {
-			SetTileSelectSize(1, 1);
-		}
-
-		image = (w->window_class == WC_BUS_STATION) ? 0x47 : 0x43;
-
-		StationPickerDrawSprite(103, 35, 0, image);
-		StationPickerDrawSprite(103, 85, 0, image+1);
-		StationPickerDrawSprite(35, 85, 0, image+2);
-		StationPickerDrawSprite(35, 35, 0, image+3);
-
-		DrawStationCoverageAreaText(2, 146,
-			((w->window_class == WC_BUS_STATION) ? (1<<CT_PASSENGERS) : ~(1<<CT_PASSENGERS)),
-			3);
-
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3: case 4: case 5: case 6:
-			RaiseWindowWidget(w, _road_station_picker_orientation + 3);
-			_road_station_picker_orientation = e->we.click.widget - 3;
-			LowerWindowWidget(w, _road_station_picker_orientation + 3);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		case 7: case 8:
-			RaiseWindowWidget(w, _station_show_coverage + 7);
-			_station_show_coverage = e->we.click.widget - 7;
-			LowerWindowWidget(w, _station_show_coverage + 7);
-			SndPlayFx(SND_15_BEEP);
-			SetWindowDirty(w);
-			break;
-		}
-	} break;
-
-	case WE_MOUSELOOP: {
-		if (WP(w,def_d).close) {
-			DeleteWindow(w);
-			return;
-		}
-
-		CheckRedrawStationCoverage(w);
-	} break;
-
-	case WE_DESTROY:
-		if (!WP(w,def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
-
-static const Widget _bus_station_picker_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_3042_BUS_STATION_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   176, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    10,    69,   133,   144, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    70,   129,   133,   144, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   139,   120,   133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _bus_station_picker_desc = {
-	WDP_AUTO, WDP_AUTO, 140, 177,
-	WC_BUS_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_bus_station_picker_widgets,
-	RoadStationPickerWndProc
-};
-
-static void ShowBusStationPicker(void)
-{
-	AllocateWindowDesc(&_bus_station_picker_desc);
-}
-
-static const Widget _truck_station_picker_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_3043_TRUCK_STATION_ORIENT,    STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   176, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    10,    69,   133,   144, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    70,   129,   133,   144, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   139,   120,   133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _truck_station_picker_desc = {
-	WDP_AUTO, WDP_AUTO, 140, 177,
-	WC_TRUCK_STATION, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_truck_station_picker_widgets,
-	RoadStationPickerWndProc
-};
-
-static void ShowTruckStationPicker(void)
-{
-	AllocateWindowDesc(&_truck_station_picker_desc);
-}
-
-void InitializeRoadGui(void)
-{
-	_road_depot_orientation = 3;
-	_road_station_picker_orientation = 3;
-}
new file mode 100644
--- /dev/null
+++ b/src/road_gui.cpp
@@ -0,0 +1,560 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "road_cmd.h"
+#include "road_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "sound.h"
+#include "command.h"
+#include "variables.h"
+//needed for catchments
+#include "station.h"
+
+
+static void ShowBusStationPicker(void);
+static void ShowTruckStationPicker(void);
+static void ShowRoadDepotPicker(void);
+
+static bool _remove_button_clicked;
+
+static byte _place_road_flag;
+
+static byte _road_depot_orientation;
+static byte _road_station_picker_orientation;
+
+void CcPlaySound1D(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) SndPlayTileFx(SND_1F_SPLAT, tile);
+}
+
+static void PlaceRoad_NE(TileIndex tile)
+{
+	_place_road_flag = (_tile_fract_coords.y >= 8) + 4;
+	VpStartPlaceSizing(tile, VPM_FIX_X);
+}
+
+static void PlaceRoad_NW(TileIndex tile)
+{
+	_place_road_flag = (_tile_fract_coords.x >= 8) + 0;
+	VpStartPlaceSizing(tile, VPM_FIX_Y);
+}
+
+static void PlaceRoad_Bridge(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_OR_Y);
+}
+
+
+void CcBuildRoadTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_20_SPLAT_2, tile);
+		ResetObjectToPlace();
+	} else {
+		SetRedErrorSquare(_build_tunnel_endtile);
+	}
+}
+
+static void PlaceRoad_Tunnel(TileIndex tile)
+{
+	DoCommandP(tile, 0x200, 0, CcBuildRoadTunnel, CMD_BUILD_TUNNEL | CMD_AUTO | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
+}
+
+static void BuildRoadOutsideStation(TileIndex tile, DiagDirection direction)
+{
+	tile += TileOffsByDiagDir(direction);
+	// if there is a roadpiece just outside of the station entrance, build a connecting route
+	if (IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
+		DoCommandP(tile, DiagDirToRoadBits(ReverseDiagDir(direction)), 0, NULL, CMD_BUILD_ROAD);
+	}
+}
+
+void CcRoadDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_1F_SPLAT, tile);
+		ResetObjectToPlace();
+		BuildRoadOutsideStation(tile, p1);
+	}
+}
+
+static void PlaceRoad_Depot(TileIndex tile)
+{
+	DoCommandP(tile, _road_depot_orientation, 0, CcRoadDepot, CMD_BUILD_ROAD_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1807_CAN_T_BUILD_ROAD_VEHICLE));
+}
+
+static void PlaceRoad_BusStation(TileIndex tile)
+{
+	DoCommandP(tile, _road_station_picker_orientation, RS_BUS, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION));
+}
+
+static void PlaceRoad_TruckStation(TileIndex tile)
+{
+	DoCommandP(tile, _road_station_picker_orientation, RS_TRUCK, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION));
+}
+
+static void PlaceRoad_DemolishArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, 4);
+}
+
+
+enum {
+	RTW_ROAD_X        =  3,
+	RTW_ROAD_Y        =  4,
+	RTW_DEMOLISH      =  5,
+	RTW_DEPOT         =  6,
+	RTW_BUS_STATION   =  7,
+	RTW_TRUCK_STATION =  8,
+	RTW_BUILD_BRIDGE  =  9,
+	RTW_BUILD_TUNNEL  = 10,
+	RTW_REMOVE        = 11
+};
+
+
+typedef void OnButtonClick(Window *w);
+
+static void BuildRoadClick_NE(Window *w)
+{
+	HandlePlacePushButton(w, RTW_ROAD_X, SPR_CURSOR_ROAD_NESW, 1, PlaceRoad_NE);
+}
+
+static void BuildRoadClick_NW(Window *w)
+{
+	HandlePlacePushButton(w, RTW_ROAD_Y, SPR_CURSOR_ROAD_NWSE, 1, PlaceRoad_NW);
+}
+
+
+static void BuildRoadClick_Demolish(Window *w)
+{
+	HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceRoad_DemolishArea);
+}
+
+static void BuildRoadClick_Depot(Window *w)
+{
+	if (_game_mode == GM_EDITOR) return;
+	if (HandlePlacePushButton(w, RTW_DEPOT, SPR_CURSOR_ROAD_DEPOT, 1, PlaceRoad_Depot)) ShowRoadDepotPicker();
+}
+
+static void BuildRoadClick_BusStation(Window *w)
+{
+	if (_game_mode == GM_EDITOR) return;
+	if (HandlePlacePushButton(w, RTW_BUS_STATION, SPR_CURSOR_BUS_STATION, 1, PlaceRoad_BusStation)) ShowBusStationPicker();
+}
+
+static void BuildRoadClick_TruckStation(Window *w)
+{
+	if (_game_mode == GM_EDITOR) return;
+	if (HandlePlacePushButton(w, RTW_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, 1, PlaceRoad_TruckStation)) ShowTruckStationPicker();
+}
+
+static void BuildRoadClick_Bridge(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, 1, PlaceRoad_Bridge);
+}
+
+static void BuildRoadClick_Tunnel(Window *w)
+{
+	HandlePlacePushButton(w, RTW_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, 3, PlaceRoad_Tunnel);
+}
+
+static void BuildRoadClick_Remove(Window *w)
+{
+	if (IsWindowWidgetDisabled(w, RTW_REMOVE)) return;
+	SetWindowDirty(w);
+	SndPlayFx(SND_15_BEEP);
+	ToggleWidgetLoweredState(w, RTW_REMOVE);
+	SetSelectionRed(IsWindowWidgetLowered(w, RTW_REMOVE));
+}
+
+static void BuildRoadClick_Landscaping(Window *w)
+{
+	ShowTerraformToolbar();
+}
+
+static OnButtonClick* const _build_road_button_proc[] = {
+	BuildRoadClick_NE,
+	BuildRoadClick_NW,
+	BuildRoadClick_Demolish,
+	BuildRoadClick_Depot,
+	BuildRoadClick_BusStation,
+	BuildRoadClick_TruckStation,
+	BuildRoadClick_Bridge,
+	BuildRoadClick_Tunnel,
+	BuildRoadClick_Remove,
+	BuildRoadClick_Landscaping,
+};
+
+static void BuildRoadToolbWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: DisableWindowWidget(w, RTW_REMOVE); break;
+
+	case WE_PAINT:
+		if (IsWindowWidgetLowered(w, RTW_ROAD_X) || IsWindowWidgetLowered(w, RTW_ROAD_Y)) {
+			EnableWindowWidget(w, RTW_REMOVE);
+		}
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK: {
+		if (e->we.click.widget >= 3) _build_road_button_proc[e->we.click.widget - 3](w);
+	}	break;
+
+	case WE_KEYPRESS:
+		switch (e->we.keypress.keycode) {
+			case '1': BuildRoadClick_NE(w);           break;
+			case '2': BuildRoadClick_NW(w);           break;
+			case '3': BuildRoadClick_Demolish(w);     break;
+			case '4': BuildRoadClick_Depot(w);        break;
+			case '5': BuildRoadClick_BusStation(w);   break;
+			case '6': BuildRoadClick_TruckStation(w); break;
+			case 'B': BuildRoadClick_Bridge(w);       break;
+			case 'T': BuildRoadClick_Tunnel(w);       break;
+			case 'R': BuildRoadClick_Remove(w);       break;
+			case 'L': BuildRoadClick_Landscaping(w);  break;
+			default: return;
+		}
+		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
+		e->we.keypress.cont = false;
+		break;
+
+	case WE_PLACE_OBJ:
+		_remove_button_clicked = IsWindowWidgetLowered(w, RTW_REMOVE);
+		_place_proc(e->we.place.tile);
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		DisableWindowWidget(w, RTW_REMOVE);
+		InvalidateWidget(w, RTW_REMOVE);
+
+		w = FindWindowById(WC_BUS_STATION, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		w = FindWindowById(WC_TRUCK_STATION, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		w = FindWindowById(WC_BUILD_DEPOT, 0);
+		if (w != NULL) WP(w,def_d).close = true;
+		break;
+
+	case WE_PLACE_DRAG: {
+		int sel_method;
+		switch (e->we.place.userdata) {
+			case 1:
+				sel_method = VPM_FIX_X;
+				_place_road_flag = (_place_road_flag & ~2) | ((e->we.place.pt.y & 8) >> 2);
+				break;
+
+			case 2:
+				sel_method = VPM_FIX_Y;
+				_place_road_flag = (_place_road_flag & ~2) | ((e->we.place.pt.x & 8) >> 2);
+				break;
+
+			case 4:
+				sel_method = VPM_X_AND_Y;
+				break;
+
+			default:
+				sel_method = VPM_X_OR_Y;
+				break;
+		}
+
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, sel_method);
+		return;
+	}
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1) {
+			TileIndex start_tile = e->we.place.starttile;
+			TileIndex end_tile = e->we.place.tile;
+
+			if (e->we.place.userdata == 0) {
+				ResetObjectToPlace();
+				ShowBuildBridgeWindow(start_tile, end_tile, 0x80);
+			} else if (e->we.place.userdata != 4) {
+				DoCommandP(end_tile, start_tile, _place_road_flag, CcPlaySound1D,
+					_remove_button_clicked ?
+					CMD_REMOVE_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1805_CAN_T_REMOVE_ROAD_FROM) :
+					CMD_BUILD_LONG_ROAD | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1804_CAN_T_BUILD_ROAD_HERE));
+			} else {
+				DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
+			}
+		}
+		break;
+
+	case WE_PLACE_PRESIZE: {
+		TileIndex tile = e->we.place.tile;
+
+		DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL);
+		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
+		break;
+	}
+
+	case WE_DESTROY:
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+		break;
+	}
+}
+
+static const Widget _build_road_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   227,     0,    13, STR_1802_ROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   228,   239,     0,    13, 0x0,                        STR_STICKY_BUTTON},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_ROAD_NW,            STR_180B_BUILD_ROAD_SECTION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_ROAD_NE,            STR_180B_BUILD_ROAD_SECTION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,    87,    14,    35, SPR_IMG_ROAD_DEPOT,         STR_180C_BUILD_ROAD_VEHICLE_DEPOT},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    88,   109,    14,    35, SPR_IMG_BUS_STATION,        STR_180D_BUILD_BUS_STATION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   110,   131,    14,    35, SPR_IMG_TRUCK_BAY,          STR_180E_BUILD_TRUCK_LOADING_BAY},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   132,   173,    14,    35, SPR_IMG_BRIDGE,             STR_180F_BUILD_ROAD_BRIDGE},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   174,   195,    14,    35, SPR_IMG_ROAD_TUNNEL,        STR_1810_BUILD_ROAD_TUNNEL},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   196,   217,    14,    35, SPR_IMG_REMOVE,             STR_1811_TOGGLE_BUILD_REMOVE_FOR},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   218,   239,    14,    35, SPR_IMG_LANDSCAPING,        STR_LANDSCAPING_TOOLBAR_TIP},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_road_desc = {
+	WDP_ALIGN_TBR, 22, 240, 36,
+	WC_BUILD_TOOLBAR, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_build_road_widgets,
+	BuildRoadToolbWndProc
+};
+
+void ShowBuildRoadToolbar(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+
+	DeleteWindowById(WC_BUILD_TOOLBAR, 0);
+	AllocateWindowDesc(&_build_road_desc);
+	if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
+}
+
+static const Widget _build_road_scen_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   140,     0,    13, STR_1802_ROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   141,   152,     0,    13, 0x0,                        STR_STICKY_BUTTON},
+
+{     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_ROAD_NW,            STR_180B_BUILD_ROAD_SECTION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_ROAD_NE,            STR_180B_BUILD_ROAD_SECTION},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_DYNAMITE,           STR_018D_DEMOLISH_BUILDINGS_ETC},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,                        STR_NULL},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,    66,   107,    14,    35, SPR_IMG_BRIDGE,             STR_180F_BUILD_ROAD_BRIDGE},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   108,   129,    14,    35, SPR_IMG_ROAD_TUNNEL,        STR_1810_BUILD_ROAD_TUNNEL},
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   130,   151,    14,    35, SPR_IMG_REMOVE,             STR_1811_TOGGLE_BUILD_REMOVE_FOR},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_road_scen_desc = {
+	WDP_AUTO, WDP_AUTO, 152, 36,
+	WC_SCEN_BUILD_ROAD, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_build_road_scen_widgets,
+	BuildRoadToolbWndProc
+};
+
+void ShowBuildRoadScenToolbar(void)
+{
+	AllocateWindowDescFront(&_build_road_scen_desc, 0);
+}
+
+static void BuildRoadDepotWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: LowerWindowWidget(w, _road_depot_orientation + 3); break;
+
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+
+		DrawRoadDepotSprite(70, 17, DIAGDIR_NE);
+		DrawRoadDepotSprite(70, 69, DIAGDIR_SE);
+		DrawRoadDepotSprite( 2, 69, DIAGDIR_SW);
+		DrawRoadDepotSprite( 2, 17, DIAGDIR_NW);
+		break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3: case 4: case 5: case 6:
+			RaiseWindowWidget(w, _road_depot_orientation + 3);
+			_road_depot_orientation = e->we.click.widget - 3;
+			LowerWindowWidget(w, _road_depot_orientation + 3);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		}
+	}	break;
+
+	case WE_MOUSELOOP:
+		if (WP(w,def_d).close) DeleteWindow(w);
+		break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _build_road_depot_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1806_ROAD_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                             STR_1813_SELECT_ROAD_VEHICLE_DEPOT},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _build_road_depot_desc = {
+	WDP_AUTO, WDP_AUTO, 140, 122,
+	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_build_road_depot_widgets,
+	BuildRoadDepotWndProc
+};
+
+static void ShowRoadDepotPicker(void)
+{
+	AllocateWindowDesc(&_build_road_depot_desc);
+}
+
+static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE:
+		LowerWindowWidget(w, _road_station_picker_orientation + 3);
+		LowerWindowWidget(w, _station_show_coverage + 7);
+		break;
+
+	case WE_PAINT: {
+		int image;
+
+		if (WP(w,def_d).close) return;
+
+		DrawWindowWidgets(w);
+
+		if (_station_show_coverage) {
+			int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : 4;
+			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+		} else {
+			SetTileSelectSize(1, 1);
+		}
+
+		image = (w->window_class == WC_BUS_STATION) ? 0x47 : 0x43;
+
+		StationPickerDrawSprite(103, 35, 0, image);
+		StationPickerDrawSprite(103, 85, 0, image+1);
+		StationPickerDrawSprite(35, 85, 0, image+2);
+		StationPickerDrawSprite(35, 35, 0, image+3);
+
+		DrawStationCoverageAreaText(2, 146,
+			((w->window_class == WC_BUS_STATION) ? (1<<CT_PASSENGERS) : ~(1<<CT_PASSENGERS)),
+			3);
+
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case 3: case 4: case 5: case 6:
+			RaiseWindowWidget(w, _road_station_picker_orientation + 3);
+			_road_station_picker_orientation = e->we.click.widget - 3;
+			LowerWindowWidget(w, _road_station_picker_orientation + 3);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		case 7: case 8:
+			RaiseWindowWidget(w, _station_show_coverage + 7);
+			_station_show_coverage = e->we.click.widget - 7;
+			LowerWindowWidget(w, _station_show_coverage + 7);
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
+		}
+	} break;
+
+	case WE_MOUSELOOP: {
+		if (WP(w,def_d).close) {
+			DeleteWindow(w);
+			return;
+		}
+
+		CheckRedrawStationCoverage(w);
+	} break;
+
+	case WE_DESTROY:
+		if (!WP(w,def_d).close) ResetObjectToPlace();
+		break;
+	}
+}
+
+static const Widget _bus_station_picker_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_3042_BUS_STATION_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   176, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_3051_SELECT_BUS_STATION_ORIENTATION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    10,    69,   133,   144, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    70,   129,   133,   144, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   139,   120,   133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _bus_station_picker_desc = {
+	WDP_AUTO, WDP_AUTO, 140, 177,
+	WC_BUS_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_bus_station_picker_widgets,
+	RoadStationPickerWndProc
+};
+
+static void ShowBusStationPicker(void)
+{
+	AllocateWindowDesc(&_bus_station_picker_desc);
+}
+
+static const Widget _truck_station_picker_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_3043_TRUCK_STATION_ORIENT,    STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   176, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
+{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_3052_SELECT_TRUCK_LOADING_BAY},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    10,    69,   133,   144, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    70,   129,   133,   144, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   139,   120,   133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _truck_station_picker_desc = {
+	WDP_AUTO, WDP_AUTO, 140, 177,
+	WC_TRUCK_STATION, WC_BUILD_TOOLBAR,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_truck_station_picker_widgets,
+	RoadStationPickerWndProc
+};
+
+static void ShowTruckStationPicker(void)
+{
+	AllocateWindowDesc(&_truck_station_picker_desc);
+}
+
+void InitializeRoadGui(void)
+{
+	_road_depot_orientation = 3;
+	_road_station_picker_orientation = 3;
+}
deleted file mode 100644
--- a/src/road_map.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "functions.h"
-#include "road_map.h"
-#include "station.h"
-#include "tunnel_map.h"
-#include "station_map.h"
-#include "depot.h"
-
-
-RoadBits GetAnyRoadBits(TileIndex tile)
-{
-	switch (GetTileType(tile)) {
-		case MP_STREET:
-			switch (GetRoadTileType(tile)) {
-				default:
-				case ROAD_TILE_NORMAL:   return GetRoadBits(tile);
-				case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile);
-				case ROAD_TILE_DEPOT:    return DiagDirToRoadBits(GetRoadDepotDirection(tile));
-			}
-
-		case MP_STATION:
-			if (!IsRoadStopTile(tile)) return 0;
-			return DiagDirToRoadBits(GetRoadStopDir(tile));
-
-		case MP_TUNNELBRIDGE:
-			if (IsTunnel(tile)) {
-				if (GetTunnelTransportType(tile) != TRANSPORT_ROAD) return 0;
-				return DiagDirToRoadBits(ReverseDiagDir(GetTunnelDirection(tile)));
-			} else {
-				if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
-				return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
-			}
-
-		default: return 0;
-	}
-}
-
-
-TrackBits GetAnyRoadTrackBits(TileIndex tile)
-{
-	uint32 r;
-
-	// Don't allow local authorities to build roads through road depots or road stops.
-	if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || IsTileType(tile, MP_STATION)) {
-		return 0;
-	}
-
-	r = GetTileTrackStatus(tile, TRANSPORT_ROAD);
-	return (byte)(r | (r >> 8));
-}
new file mode 100644
--- /dev/null
+++ b/src/road_map.cpp
@@ -0,0 +1,54 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "functions.h"
+#include "road_map.h"
+#include "station.h"
+#include "tunnel_map.h"
+#include "station_map.h"
+#include "depot.h"
+
+
+RoadBits GetAnyRoadBits(TileIndex tile)
+{
+	switch (GetTileType(tile)) {
+		case MP_STREET:
+			switch (GetRoadTileType(tile)) {
+				default:
+				case ROAD_TILE_NORMAL:   return GetRoadBits(tile);
+				case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile);
+				case ROAD_TILE_DEPOT:    return DiagDirToRoadBits(GetRoadDepotDirection(tile));
+			}
+
+		case MP_STATION:
+			if (!IsRoadStopTile(tile)) return 0;
+			return DiagDirToRoadBits(GetRoadStopDir(tile));
+
+		case MP_TUNNELBRIDGE:
+			if (IsTunnel(tile)) {
+				if (GetTunnelTransportType(tile) != TRANSPORT_ROAD) return 0;
+				return DiagDirToRoadBits(ReverseDiagDir(GetTunnelDirection(tile)));
+			} else {
+				if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
+				return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
+			}
+
+		default: return 0;
+	}
+}
+
+
+TrackBits GetAnyRoadTrackBits(TileIndex tile)
+{
+	uint32 r;
+
+	// Don't allow local authorities to build roads through road depots or road stops.
+	if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || IsTileType(tile, MP_STATION)) {
+		return 0;
+	}
+
+	r = GetTileTrackStatus(tile, TRANSPORT_ROAD);
+	return (byte)(r | (r >> 8));
+}
deleted file mode 100644
--- a/src/roadveh_cmd.c
+++ /dev/null
@@ -1,1826 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include <limits.h>
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "road_map.h"
-#include "roadveh.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
-#include "engine.h"
-#include "command.h"
-#include "station.h"
-#include "news.h"
-#include "pathfind.h"
-#include "npf.h"
-#include "player.h"
-#include "sound.h"
-#include "depot.h"
-#include "bridge.h"
-#include "tunnel_map.h"
-#include "bridge_map.h"
-#include "vehicle_gui.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_engine.h"
-#include "newgrf_text.h"
-#include "newgrf_sound.h"
-#include "yapf/yapf.h"
-#include "date.h"
-
-static const uint16 _roadveh_images[63] = {
-	0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
-	0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
-	0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
-	0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
-	0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
-	0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
-	0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
-	0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
-};
-
-static const uint16 _roadveh_full_adder[63] = {
-	 0,  88,   0,   0,   0,   0,  48,  48,
-	48,  48,   0,   0,  64,  64,   0,  16,
-	16,   0,  88,   0,   0,   0,   0,  48,
-	48,  48,  48,   0,   0,  64,  64,   0,
-	16,  16,   0,  88,   0,   0,   0,   0,
-	48,  48,  48,  48,   0,   0,  64,  64,
-	 0,  16,  16,   0,   8,   8,   8,   8,
-	 0,   0,   0,   8,   8,   8,   8
-};
-
-
-static const uint16 _road_veh_fp_ax_and[4] = {
-	0x1009, 0x16, 0x520, 0x2A00
-};
-
-static const byte _road_reverse_table[4] = {
-	6, 7, 14, 15
-};
-
-static const uint16 _road_pf_table_3[4] = {
-	0x910, 0x1600, 0x2005, 0x2A
-};
-
-int GetRoadVehImage(const Vehicle* v, Direction direction)
-{
-	int img = v->spritenum;
-	int image;
-
-	if (is_custom_sprite(img)) {
-		image = GetCustomVehicleSprite(v, direction);
-		if (image != 0) return image;
-		img = orig_road_vehicle_info[v->engine_type - ROAD_ENGINES_INDEX].image_index;
-	}
-
-	image = direction + _roadveh_images[img];
-	if (v->cargo_count >= v->cargo_cap / 2) image += _roadveh_full_adder[img];
-	return image;
-}
-
-void DrawRoadVehEngine(int x, int y, EngineID engine, uint32 image_ormod)
-{
-	int spritenum = RoadVehInfo(engine)->image_index;
-
-	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleIcon(engine, DIR_W);
-
-		if (sprite != 0) {
-			DrawSprite(sprite | image_ormod, x, y);
-			return;
-		}
-		spritenum = orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index;
-	}
-	DrawSprite((6 + _roadveh_images[spritenum]) | image_ormod, x, y);
-}
-
-static int32 EstimateRoadVehCost(EngineID engine_type)
-{
-	return ((_price.roadveh_base >> 3) * RoadVehInfo(engine_type)->base_cost) >> 5;
-}
-
-/** Build a road vehicle.
- * @param tile tile of depot where road vehicle is built
- * @param p1 bus/truck type being built (engine)
- * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number
- */
-int32 CmdBuildRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost;
-	Vehicle *v;
-	UnitID unit_num;
-	Engine *e;
-
-	if (!IsEngineBuildable(p1, VEH_Road, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	cost = EstimateRoadVehCost(p1);
-	if (flags & DC_QUERY_COST) return cost;
-
-	/* The ai_new queries the vehicle cost before building the route,
-	 * so we must check against cheaters no sooner than now. --pasky */
-	if (!IsTileDepotType(tile, TRANSPORT_ROAD)) return CMD_ERROR;
-	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
-
-	v = AllocateVehicle();
-	if (v == NULL || IsOrderPoolFull())
-		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-	/* find the first free roadveh id */
-	unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Road);
-	if (unit_num > _patches.max_roadveh)
-		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-	if (flags & DC_EXEC) {
-		int x;
-		int y;
-
-		const RoadVehicleInfo *rvi = RoadVehInfo(p1);
-
-		v->unitnumber = unit_num;
-		v->direction = 0;
-		v->owner = _current_player;
-
-		v->tile = tile;
-		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
-		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
-		v->x_pos = x;
-		v->y_pos = y;
-		v->z_pos = GetSlopeZ(x,y);
-		v->z_height = 6;
-
-		v->u.road.state = 254;
-		v->vehstatus = VS_HIDDEN|VS_STOPPED|VS_DEFPAL;
-
-		v->spritenum = rvi->image_index;
-		v->cargo_type = rvi->cargo_type;
-		v->cargo_subtype = 0;
-		v->cargo_cap = rvi->capacity;
-//		v->cargo_count = 0;
-		v->value = cost;
-//		v->day_counter = 0;
-//		v->next_order_param = v->next_order = 0;
-//		v->load_unload_time_rem = 0;
-//		v->progress = 0;
-
-//	v->u.road.unk2 = 0;
-//	v->u.road.overtaking = 0;
-
-		v->last_station_visited = INVALID_STATION;
-		v->max_speed = rvi->max_speed;
-		v->engine_type = (byte)p1;
-
-		e = GetEngine(p1);
-		v->reliability = e->reliability;
-		v->reliability_spd_dec = e->reliability_spd_dec;
-		v->max_age = e->lifelength * 366;
-		_new_vehicle_id = v->index;
-
-		v->string_id = STR_SV_ROADVEH_NAME;
-
-		v->service_interval = _patches.servint_roadveh;
-
-		v->date_of_last_service = _date;
-		v->build_year = _cur_year;
-
-		v->type = VEH_Road;
-		v->cur_image = 0xC15;
-		v->random_bits = VehicleRandomBits();
-
-		VehiclePositionChanged(v);
-		GetPlayer(_current_player)->num_engines[p1]++;
-
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-		InvalidateWindow(WC_COMPANY, v->owner);
-		if (IsLocalPlayer())
-			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road); // updates the replace Road window
-	}
-
-	return cost;
-}
-
-/** Start/Stop a road vehicle.
- * @param tile unused
- * @param p1 road vehicle ID to start/stop
- * @param p2 unused
- */
-int32 CmdStartStopRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	uint16 callback;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* Check if this road veh can be started/stopped. The callback will fail or
-	 * return 0xFF if it can. */
-	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
-		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
-		return_cmd_error(error);
-	}
-
-	if (flags & DC_EXEC) {
-		if (IsRoadVehInDepotStopped(v)) {
-			DeleteVehicleNews(p1, STR_9016_ROAD_VEHICLE_IS_WAITING);
-		}
-
-		v->vehstatus ^= VS_STOPPED;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-	}
-
-	return 0;
-}
-
-void ClearSlot(Vehicle *v)
-{
-	RoadStop *rs = v->u.road.slot;
-	if (v->u.road.slot == NULL) return;
-
-	v->u.road.slot = NULL;
-	v->u.road.slot_age = 0;
-
-	assert(rs->num_vehicles != 0);
-	rs->num_vehicles--;
-
-	DEBUG(ms, 3, "Clearing slot at 0x%X", rs->xy);
-}
-
-/** Sell a road vehicle.
- * @param tile unused
- * @param p1 vehicle ID to be sold
- * @param p2 unused
- */
-int32 CmdSellRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	if (!IsRoadVehInDepotStopped(v)) {
-		return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
-	}
-
-	if (flags & DC_EXEC) {
-		// Invalidate depot
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-		InvalidateWindow(WC_COMPANY, v->owner);
-		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-		ClearSlot(v);
-		DeleteDepotHighlightOfVehicle(v);
-		DeleteVehicle(v);
-		if (IsLocalPlayer()) InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road);
-	}
-
-	return -(int32)v->value;
-}
-
-typedef struct RoadFindDepotData {
-	uint best_length;
-	TileIndex tile;
-	byte owner;
-} RoadFindDepotData;
-
-static const DiagDirection _road_pf_directions[] = {
-	DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, 255, 255,
-	DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, 255, 255
-};
-
-static bool EnumRoadSignalFindDepot(TileIndex tile, void* data, int track, uint length, byte* state)
-{
-	RoadFindDepotData* rfdd = data;
-
-	tile += TileOffsByDiagDir(_road_pf_directions[track]);
-
-	if (IsTileType(tile, MP_STREET) &&
-			GetRoadTileType(tile) == ROAD_TILE_DEPOT &&
-			IsTileOwner(tile, rfdd->owner) &&
-			length < rfdd->best_length) {
-		rfdd->best_length = length;
-		rfdd->tile = tile;
-	}
-	return false;
-}
-
-static const Depot* FindClosestRoadDepot(const Vehicle* v)
-{
-	TileIndex tile = v->tile;
-
-	if (_patches.yapf.road_use_yapf) {
-		Depot* ret = YapfFindNearestRoadDepot(v);
-		return ret;
-	} else if (_patches.new_pathfinding_all) {
-		NPFFoundTargetData ftd;
-		/* See where we are now */
-		Trackdir trackdir = GetVehicleTrackdir(v);
-
-		ftd = NPFRouteToDepotBreadthFirst(v->tile, trackdir, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE);
-		if (ftd.best_bird_dist == 0) {
-			return GetDepotByTile(ftd.node.tile); /* Target found */
-		} else {
-			return NULL; /* Target not found */
-		}
-		/* We do not search in two directions here, why should we? We can't reverse right now can we? */
-	} else {
-		RoadFindDepotData rfdd;
-		DiagDirection i;
-
-		rfdd.owner = v->owner;
-		rfdd.best_length = (uint)-1;
-
-		/* search in all directions */
-		for (i = 0; i != 4; i++) {
-			FollowTrack(tile, 0x2000 | TRANSPORT_ROAD, i, EnumRoadSignalFindDepot, NULL, &rfdd);
-		}
-
-		if (rfdd.best_length == (uint)-1) return NULL;
-
-		return GetDepotByTile(rfdd.tile);
-	}
-}
-
-/** Send a road vehicle to the depot.
- * @param tile unused
- * @param p1 vehicle ID to send to the depot
- * @param p2 various bitmasked elements
- * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
- * - p2 bit 8-10 - VLW flag (for mass goto depot)
- */
-int32 CmdSendRoadVehToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	const Depot *dep;
-
-	if (p2 & DEPOT_MASS_SEND) {
-		/* Mass goto depot requested */
-		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
-		return SendAllVehiclesToDepot(VEH_Road, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
-	}
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
-
-	if (IsRoadVehInDepot(v)) return CMD_ERROR;
-
-	/* If the current orders are already goto-depot */
-	if (v->current_order.type == OT_GOTO_DEPOT) {
-		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
-			/* We called with a different DEPOT_SERVICE setting.
-			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
-			 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
-			if (flags & DC_EXEC) {
-				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-			}
-			return 0;
-		}
-
-		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
-		if (flags & DC_EXEC) {
-			/* If the orders to 'goto depot' are in the orders list (forced servicing),
-			 * then skip to the next order; effectively cancelling this forced service */
-			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS))
-				v->cur_order_index++;
-
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return 0;
-	}
-
-	dep = FindClosestRoadDepot(v);
-	if (dep == NULL) return_cmd_error(STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT);
-
-	if (flags & DC_EXEC) {
-		ClearSlot(v);
-		v->current_order.type = OT_GOTO_DEPOT;
-		v->current_order.flags = OF_NON_STOP;
-		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-		v->current_order.refit_cargo = CT_INVALID;
-		v->current_order.dest = dep->index;
-		v->dest_tile = dep->xy;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-
-	return 0;
-}
-
-/** Turn a roadvehicle around.
- * @param tile unused
- * @param p1 vehicle ID to turn
- * @param p2 unused
- */
-int32 CmdTurnRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (v->vehstatus & VS_STOPPED ||
-			v->u.road.crashed_ctr != 0 ||
-			v->breakdown_ctr != 0 ||
-			v->u.road.overtaking != 0 ||
-			v->u.road.state == 255 ||
-			IsRoadVehInDepot(v) ||
-			v->cur_speed < 5) {
-		return CMD_ERROR;
-	}
-
-	if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR;
-	if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
-
-	return 0;
-}
-
-
-static void MarkRoadVehDirty(Vehicle *v)
-{
-	v->cur_image = GetRoadVehImage(v, v->direction);
-	MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
-}
-
-static void UpdateRoadVehDeltaXY(Vehicle *v)
-{
-#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
-	static const uint32 _delta_xy_table[8] = {
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
-	};
-#undef MKIT
-	uint32 x = _delta_xy_table[v->direction];
-	v->x_offs        = GB(x,  0, 8);
-	v->y_offs        = GB(x,  8, 8);
-	v->sprite_width  = GB(x, 16, 8);
-	v->sprite_height = GB(x, 24, 8);
-}
-
-static void ClearCrashedStation(Vehicle *v)
-{
-	RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
-
-	// mark station as not busy
-	CLRBIT(rs->status, 7);
-
-	// free parking bay
-	SETBIT(rs->status, HASBIT(v->u.road.state, 1) ? 1 : 0);
-}
-
-static void RoadVehDelete(Vehicle *v)
-{
-	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-	RebuildVehicleLists();
-	InvalidateWindow(WC_COMPANY, v->owner);
-
-	if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
-
-	BeginVehicleMove(v);
-	EndVehicleMove(v);
-
-	ClearSlot(v);
-	DeleteVehicle(v);
-}
-
-static byte SetRoadVehPosition(Vehicle *v, int x, int y)
-{
-	byte new_z, old_z;
-
-	// need this hint so it returns the right z coordinate on bridges.
-	v->x_pos = x;
-	v->y_pos = y;
-	new_z = GetSlopeZ(x, y);
-
-	old_z = v->z_pos;
-	v->z_pos = new_z;
-
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-	return old_z;
-}
-
-static void RoadVehSetRandomDirection(Vehicle *v)
-{
-	static const DirDiff delta[] = {
-		DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
-	};
-
-	uint32 r = Random();
-
-	v->direction = ChangeDir(v->direction, delta[r & 3]);
-	BeginVehicleMove(v);
-	UpdateRoadVehDeltaXY(v);
-	v->cur_image = GetRoadVehImage(v, v->direction);
-	SetRoadVehPosition(v, v->x_pos, v->y_pos);
-}
-
-static void RoadVehIsCrashed(Vehicle *v)
-{
-	v->u.road.crashed_ctr++;
-	if (v->u.road.crashed_ctr == 2) {
-		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
-	} else if (v->u.road.crashed_ctr <= 45) {
-		if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
-	} else if (v->u.road.crashed_ctr >= 2220) {
-		RoadVehDelete(v);
-	}
-}
-
-static void* EnumCheckRoadVehCrashTrain(Vehicle* v, void* data)
-{
-	const Vehicle* u = data;
-
-	return
-		v->type == VEH_Train &&
-		myabs(v->z_pos - u->z_pos) <= 6 &&
-		myabs(v->x_pos - u->x_pos) <= 4 &&
-		myabs(v->y_pos - u->y_pos) <= 4 ?
-			v : NULL;
-}
-
-static void RoadVehCrash(Vehicle *v)
-{
-	uint16 pass;
-
-	v->u.road.crashed_ctr++;
-	v->vehstatus |= VS_CRASHED;
-	ClearSlot(v);
-
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-
-	pass = 1;
-	if (v->cargo_type == CT_PASSENGERS) pass += v->cargo_count;
-	v->cargo_count = 0;
-
-	SetDParam(0, pass);
-	AddNewsItem(
-		(pass == 1) ?
-			STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE,
-		NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
-		v->index,
-		0
-	);
-
-	ModifyStationRatingAround(v->tile, v->owner, -160, 22);
-	SndPlayVehicleFx(SND_12_EXPLOSION, v);
-}
-
-static void RoadVehCheckTrainCrash(Vehicle *v)
-{
-	TileIndex tile;
-
-	if (v->u.road.state == 255) return;
-
-	tile = v->tile;
-
-	if (!IsLevelCrossingTile(tile)) return;
-
-	if (VehicleFromPos(tile, v, EnumCheckRoadVehCrashTrain) != NULL)
-		RoadVehCrash(v);
-}
-
-static void HandleBrokenRoadVeh(Vehicle *v)
-{
-	if (v->breakdown_ctr != 1) {
-		v->breakdown_ctr = 1;
-		v->cur_speed = 0;
-
-		if (v->breakdowns_since_last_service != 255)
-			v->breakdowns_since_last_service++;
-
-		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
-			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
-				SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
-		}
-
-		if (!(v->vehstatus & VS_HIDDEN)) {
-			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
-		}
-	}
-
-	if ((v->tick_counter & 1) == 0) {
-		if (--v->breakdown_delay == 0) {
-			v->breakdown_ctr = 0;
-			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		}
-	}
-}
-
-static void ProcessRoadVehOrder(Vehicle *v)
-{
-	const Order *order;
-
-	switch (v->current_order.type) {
-		case OT_GOTO_DEPOT:
-			// Let a depot order in the orderlist interrupt.
-			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return;
-			if (v->current_order.flags & OF_SERVICE_IF_NEEDED &&
-					!VehicleNeedsService(v)) {
-				v->cur_order_index++;
-			}
-			break;
-
-		case OT_LOADING:
-		case OT_LEAVESTATION:
-			return;
-
-		default: break;
-	}
-
-	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
-
-	order = GetVehicleOrder(v, v->cur_order_index);
-
-	if (order == NULL) {
-		v->current_order.type = OT_NOTHING;
-		v->current_order.flags = 0;
-		v->dest_tile = 0;
-		ClearSlot(v);
-		return;
-	}
-
-	if (order->type  == v->current_order.type &&
-			order->flags == v->current_order.flags &&
-			order->dest  == v->current_order.dest) {
-		return;
-	}
-
-	v->current_order = *order;
-
-	switch (order->type) {
-		case OT_GOTO_STATION: {
-			const RoadStop* rs;
-
-			if (order->dest == v->last_station_visited) {
-				v->last_station_visited = INVALID_STATION;
-			}
-
-			rs = GetPrimaryRoadStop(
-				GetStation(order->dest),
-				v->cargo_type == CT_PASSENGERS ? RS_BUS : RS_TRUCK
-			);
-
-			if (rs != NULL) {
-				TileIndex dest = rs->xy;
-				uint mindist = DistanceManhattan(v->tile, rs->xy);
-
-				for (rs = rs->next; rs != NULL; rs = rs->next) {
-					uint dist = DistanceManhattan(v->tile, rs->xy);
-
-					if (dist < mindist) {
-						mindist = dist;
-						dest = rs->xy;
-					}
-				}
-				v->dest_tile = dest;
-			} else {
-				// There is no stop left at the station, so don't even TRY to go there
-				v->cur_order_index++;
-				v->dest_tile = 0;
-			}
-			break;
-		}
-
-		case OT_GOTO_DEPOT:
-			v->dest_tile = GetDepot(order->dest)->xy;
-			break;
-
-		default:
-			v->dest_tile = 0;
-			break;
-	}
-
-	InvalidateVehicleOrder(v);
-}
-
-static void HandleRoadVehLoading(Vehicle *v)
-{
-	switch (v->current_order.type) {
-		case OT_LOADING: {
-			Order b;
-
-			if (--v->load_unload_time_rem != 0) return;
-
-			if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
-					(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
-				SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC);
-				if (LoadUnloadVehicle(v, false)) {
-					InvalidateWindow(WC_ROADVEH_LIST, v->owner);
-					MarkRoadVehDirty(v);
-				}
-				return;
-			}
-
-			b = v->current_order;
-			v->current_order.type = OT_LEAVESTATION;
-			v->current_order.flags = 0;
-			if (!(b.flags & OF_NON_STOP)) return;
-			break;
-		}
-
-		case OT_DUMMY: break;
-
-		default: return;
-	}
-
-	v->cur_order_index++;
-	InvalidateVehicleOrder(v);
-}
-
-static void StartRoadVehSound(const Vehicle* v)
-{
-	if (!PlayVehicleSound(v, VSE_START)) {
-		SoundFx s = RoadVehInfo(v->engine_type)->sfx;
-		if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
-			s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
-		SndPlayVehicleFx(s, v);
-	}
-}
-
-typedef struct RoadVehFindData {
-	int x;
-	int y;
-	const Vehicle* veh;
-	Direction dir;
-} RoadVehFindData;
-
-static void* EnumCheckRoadVehClose(Vehicle *v, void* data)
-{
-	static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
-	static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
-
-	const RoadVehFindData* rvf = data;
-
-	short x_diff = v->x_pos - rvf->x;
-	short y_diff = v->y_pos - rvf->y;
-
-	return
-		rvf->veh != v &&
-		v->type == VEH_Road &&
-		!IsRoadVehInDepot(v) &&
-		myabs(v->z_pos - rvf->veh->z_pos) < 6 &&
-		v->direction == rvf->dir &&
-		(dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
-		(dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
-		(dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
-		(dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0)) ?
-			v : NULL;
-}
-
-static Vehicle* RoadVehFindCloseTo(Vehicle* v, int x, int y, Direction dir)
-{
-	RoadVehFindData rvf;
-	Vehicle *u;
-
-	if (v->u.road.reverse_ctr != 0) return NULL;
-
-	rvf.x = x;
-	rvf.y = y;
-	rvf.dir = dir;
-	rvf.veh = v;
-	u = VehicleFromPos(TileVirtXY(x, y), &rvf, EnumCheckRoadVehClose);
-
-	// This code protects a roadvehicle from being blocked for ever
-	//  If more than 1480 / 74 days a road vehicle is blocked, it will
-	//  drive just through it. The ultimate backup-code of TTD.
-	// It can be disabled.
-	if (u == NULL) {
-		v->u.road.blocked_ctr = 0;
-		return NULL;
-	}
-
-	if (++v->u.road.blocked_ctr > 1480) return NULL;
-
-	return u;
-}
-
-static void RoadVehArrivesAt(const Vehicle* v, Station* st)
-{
-	if (v->cargo_type == CT_PASSENGERS) {
-		/* Check if station was ever visited before */
-		if (!(st->had_vehicle_of_type & HVOT_BUS)) {
-			uint32 flags;
-
-			st->had_vehicle_of_type |= HVOT_BUS;
-			SetDParam(0, st->index);
-			flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
-			AddNewsItem(
-				STR_902F_CITIZENS_CELEBRATE_FIRST,
-				flags,
-				v->index,
-				0);
-		}
-	} else {
-		/* Check if station was ever visited before */
-		if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
-			uint32 flags;
-
-			st->had_vehicle_of_type |= HVOT_TRUCK;
-			SetDParam(0, st->index);
-			flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
-			AddNewsItem(
-				STR_9030_CITIZENS_CELEBRATE_FIRST,
-				flags,
-				v->index,
-				0
-			);
-		}
-	}
-}
-
-static bool RoadVehAccelerate(Vehicle *v)
-{
-	uint spd = v->cur_speed + 1 + (v->u.road.overtaking != 0 ? 1 : 0);
-	byte t;
-
-	// Clamp
-	spd = min(spd, v->max_speed);
-	if (v->u.road.state == 255) spd = min(spd, SetSpeedLimitOnBridge(v));
-
-	//updates statusbar only if speed have changed to save CPU time
-	if (spd != v->cur_speed) {
-		v->cur_speed = spd;
-		if (_patches.vehicle_speed) {
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-	}
-
-	// Decrease somewhat when turning
-	if (!(v->direction & 1)) spd = spd * 3 >> 2;
-
-	if (spd == 0) return false;
-
-	if ((byte)++spd == 0) return true;
-
-	v->progress = (t = v->progress) - (byte)spd;
-
-	return (t < v->progress);
-}
-
-static Direction RoadVehGetNewDirection(const Vehicle* v, int x, int y)
-{
-	static const Direction _roadveh_new_dir[] = {
-		DIR_N , DIR_NW, DIR_W , 0,
-		DIR_NE, DIR_N , DIR_SW, 0,
-		DIR_E , DIR_SE, DIR_S
-	};
-
-	x = x - v->x_pos + 1;
-	y = y - v->y_pos + 1;
-
-	if ((uint)x > 2 || (uint)y > 2) return v->direction;
-	return _roadveh_new_dir[y * 4 + x];
-}
-
-static Direction RoadVehGetSlidingDirection(const Vehicle* v, int x, int y)
-{
-	Direction new = RoadVehGetNewDirection(v, x, y);
-	Direction old = v->direction;
-	DirDiff delta;
-
-	if (new == old) return old;
-	delta = (DirDifference(new, old) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
-	return ChangeDir(old, delta);
-}
-
-typedef struct OvertakeData {
-	const Vehicle* u;
-	const Vehicle* v;
-	TileIndex tile;
-	byte tilebits;
-} OvertakeData;
-
-static void* EnumFindVehToOvertake(Vehicle* v, void* data)
-{
-	const OvertakeData* od = data;
-
-	return
-		v->tile == od->tile && v->type == VEH_Road && v != od->u && v != od->v ?
-			v : NULL;
-}
-
-static bool FindRoadVehToOvertake(OvertakeData *od)
-{
-	uint32 bits;
-
-	bits = GetTileTrackStatus(od->tile, TRANSPORT_ROAD) & 0x3F;
-
-	if (!(od->tilebits & bits) || (bits & 0x3C) || (bits & 0x3F3F0000))
-		return true;
-	return VehicleFromPos(od->tile, od, EnumFindVehToOvertake) != NULL;
-}
-
-static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
-{
-	OvertakeData od;
-	byte tt;
-
-	od.v = v;
-	od.u = u;
-
-	if (u->max_speed >= v->max_speed &&
-			!(u->vehstatus & VS_STOPPED) &&
-			u->cur_speed != 0) {
-		return;
-	}
-
-	if (v->direction != u->direction || !(v->direction & 1)) return;
-
-	if (v->u.road.state >= 32 || (v->u.road.state & 7) > 1) return;
-
-	tt = GetTileTrackStatus(v->tile, TRANSPORT_ROAD) & 0x3F;
-	if ((tt & 3) == 0) return;
-	if ((tt & 0x3C) != 0) return;
-
-	if (tt == 3) tt = (v->direction & 2) ? 2 : 1;
-	od.tilebits = tt;
-
-	od.tile = v->tile;
-	if (FindRoadVehToOvertake(&od)) return;
-
-	od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
-	if (FindRoadVehToOvertake(&od)) return;
-
-	if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
-		v->u.road.overtaking_ctr = 0x11;
-		v->u.road.overtaking = 0x10;
-	} else {
-//		if (FindRoadVehToOvertake(&od)) return;
-		v->u.road.overtaking_ctr = 0;
-		v->u.road.overtaking = 0x10;
-	}
-}
-
-static void RoadZPosAffectSpeed(Vehicle *v, byte old_z)
-{
-	if (old_z == v->z_pos) return;
-
-	if (old_z < v->z_pos) {
-		v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
-	} else {
-		uint16 spd = v->cur_speed + 2;
-		if (spd <= v->max_speed) v->cur_speed = spd;
-	}
-}
-
-static int PickRandomBit(uint bits)
-{
-	uint num = 0;
-	uint b = bits;
-	uint i;
-
-	do {
-		if (b & 1) num++;
-	} while (b >>= 1);
-
-	num = RandomRange(num);
-
-	for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
-	return i;
-}
-
-typedef struct {
-	TileIndex dest;
-	uint maxtracklen;
-	uint mindist;
-} FindRoadToChooseData;
-
-static bool EnumRoadTrackFindDist(TileIndex tile, void* data, int track, uint length, byte* state)
-{
-	FindRoadToChooseData* frd = data;
-	uint dist = DistanceManhattan(tile, frd->dest);
-
-	if (dist <= frd->mindist) {
-		if (dist != frd->mindist || length < frd->maxtracklen) {
-			frd->maxtracklen = length;
-		}
-		frd->mindist = dist;
-	}
-	return false;
-}
-
-static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-
-	void* perf = NpfBeginInterval();
-	NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, owner, railtypes);
-	int t = NpfEndInterval(perf);
-	DEBUG(yapf, 4, "[NPFR] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
-	return ret;
-}
-
-// Returns direction to choose
-// or -1 if the direction is currently blocked
-static int RoadFindPathToDest(Vehicle* v, TileIndex tile, DiagDirection enterdir)
-{
-#define return_track(x) {best_track = x; goto found_best_track; }
-
-	uint16 signal;
-	uint bitmask;
-	TileIndex desttile;
-	FindRoadToChooseData frd;
-	int best_track;
-	uint best_dist, best_maxlen;
-	uint i;
-
-	{
-		uint32 r = GetTileTrackStatus(tile, TRANSPORT_ROAD);
-		signal  = GB(r, 16, 16);
-		bitmask = GB(r,  0, 16);
-	}
-
-	if (IsTileType(tile, MP_STREET)) {
-		if (GetRoadTileType(tile) == ROAD_TILE_DEPOT && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) {
-			/* Road depot owned by another player or with the wrong orientation */
-			bitmask = 0;
-		}
-	} else if (IsTileType(tile, MP_STATION) && IsRoadStopTile(tile)) {
-		if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir) {
-			/* different station owner or wrong orientation */
-			bitmask = 0;
-		} else {
-			/* Our station */
-			RoadStopType rstype = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK;
-
-			if (GetRoadStopType(tile) != rstype) {
-				// wrong station type
-				bitmask = 0;
-			} else {
-				// proper station type, check if there is free loading bay
-				const RoadStop *rs = GetRoadStopByTile(tile, rstype);
-				if (rs == NULL || (!_patches.roadveh_queue && GB(rs->status, 0, 2) == 0)) {
-					// station is full and RV queuing is off
-					bitmask = 0;
-				}
-			}
-		}
-	}
-	/* The above lookups should be moved to GetTileTrackStatus in the
-	 * future, but that requires more changes to the pathfinder and other
-	 * stuff, probably even more arguments to GTTS.
-	 */
-
-	/* remove unreachable tracks */
-	bitmask &= _road_veh_fp_ax_and[enterdir];
-	if (bitmask == 0) {
-		/* No reachable tracks, so we'll reverse */
-		return_track(_road_reverse_table[enterdir]);
-	}
-
-	if (v->u.road.reverse_ctr != 0) {
-		/* What happens here?? */
-		v->u.road.reverse_ctr = 0;
-		if (v->tile != tile) {
-			return_track(_road_reverse_table[enterdir]);
-		}
-	}
-
-	desttile = v->dest_tile;
-	if (desttile == 0) {
-		// Pick a random track
-		return_track(PickRandomBit(bitmask));
-	}
-
-	// Only one track to choose between?
-	if (!(KillFirstBit2x64(bitmask))) {
-		return_track(FindFirstBit2x64(bitmask));
-	}
-
-	if (_patches.yapf.road_use_yapf) {
-		Trackdir trackdir = YapfChooseRoadTrack(v, tile, enterdir);
-		if (trackdir != INVALID_TRACKDIR) return_track(trackdir);
-		return_track(PickRandomBit(bitmask));
-	} else if (_patches.new_pathfinding_all) {
-		NPFFindStationOrTileData fstd;
-		NPFFoundTargetData ftd;
-		byte trackdir;
-
-		NPFFillWithOrderData(&fstd, v);
-		trackdir = DiagdirToDiagTrackdir(enterdir);
-		//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
-
-		ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE);
-		if (ftd.best_trackdir == 0xff) {
-			/* We are already at our target. Just do something */
-			//TODO: maybe display error?
-			//TODO: go straight ahead if possible?
-			return_track(FindFirstBit2x64(bitmask));
-		} else {
-			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
-			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
-			we did not find our target, but ftd.best_trackdir contains the direction leading
-			to the tile closest to our target. */
-			return_track(ftd.best_trackdir);
-		}
-	} else {
-		DiagDirection dir;
-
-		if (IsTileType(desttile, MP_STREET)) {
-			if (GetRoadTileType(desttile) == ROAD_TILE_DEPOT) {
-				dir = GetRoadDepotDirection(desttile);
-				goto do_it;
-			}
-		} else if (IsTileType(desttile, MP_STATION)) {
-			if (IsRoadStop(desttile)) {
-				dir = GetRoadStopDir(desttile);
-do_it:;
-				/* When we are heading for a depot or station, we just
-				 * pretend we are heading for the tile in front, we'll
-				 * see from there */
-				desttile += TileOffsByDiagDir(dir);
-				if (desttile == tile && bitmask & _road_pf_table_3[dir]) {
-					/* If we are already in front of the
-					 * station/depot and we can get in from here,
-					 * we enter */
-					return_track(FindFirstBit2x64(bitmask & _road_pf_table_3[dir]));
-				}
-			}
-		}
-		// do pathfind
-		frd.dest = desttile;
-
-		best_track = -1;
-		best_dist = (uint)-1;
-		best_maxlen = (uint)-1;
-		i = 0;
-		do {
-			if (bitmask & 1) {
-				if (best_track == -1) best_track = i; // in case we don't find the path, just pick a track
-				frd.maxtracklen = (uint)-1;
-				frd.mindist = (uint)-1;
-				FollowTrack(tile, 0x2000 | TRANSPORT_ROAD, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
-
-				if (frd.mindist < best_dist || (frd.mindist==best_dist && frd.maxtracklen < best_maxlen)) {
-					best_dist = frd.mindist;
-					best_maxlen = frd.maxtracklen;
-					best_track = i;
-				}
-			}
-		} while (++i,(bitmask>>=1) != 0);
-	}
-
-found_best_track:;
-
-	if (HASBIT(signal, best_track)) return -1;
-
-	return best_track;
-}
-
-static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile)
-{
-	uint dist;
-	if (_patches.yapf.road_use_yapf) {
-		// use YAPF
-		dist = YapfRoadVehDistanceToTile(v, tile);
-	} else {
-		// use NPF
-		NPFFindStationOrTileData fstd;
-		byte trackdir = GetVehicleTrackdir(v);
-		assert(trackdir != 0xFF);
-
-		fstd.dest_coords = tile;
-		fstd.station_index = INVALID_STATION; // indicates that the destination is a tile, not a station
-
-		dist = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE).best_path_dist;
-		// change units from NPF_TILE_LENGTH to # of tiles
-		if (dist != UINT_MAX)
-			dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH;
-	}
-	return dist;
-}
-
-typedef struct RoadDriveEntry {
-	byte x,y;
-} RoadDriveEntry;
-
-#include "table/roadveh.h"
-
-static const byte _road_veh_data_1[] = {
-	20, 20, 16, 16, 0, 0, 0, 0,
-	19, 19, 15, 15, 0, 0, 0, 0,
-	16, 16, 12, 12, 0, 0, 0, 0,
-	15, 15, 11, 11
-};
-
-static const byte _roadveh_data_2[4] = { 0, 1, 8, 9 };
-
-static void RoadVehController(Vehicle *v)
-{
-	Direction new_dir;
-	Direction old_dir;
-	RoadDriveEntry rd;
-	int x,y;
-	uint32 r;
-
-	// decrease counters
-	v->tick_counter++;
-	if (v->u.road.reverse_ctr != 0) v->u.road.reverse_ctr--;
-
-	// handle crashed
-	if (v->u.road.crashed_ctr != 0) {
-		RoadVehIsCrashed(v);
-		return;
-	}
-
-	RoadVehCheckTrainCrash(v);
-
-	// road vehicle has broken down?
-	if (v->breakdown_ctr != 0) {
-		if (v->breakdown_ctr <= 2) {
-			HandleBrokenRoadVeh(v);
-			return;
-		}
-		v->breakdown_ctr--;
-	}
-
-	if (v->vehstatus & VS_STOPPED) return;
-
-	ProcessRoadVehOrder(v);
-	HandleRoadVehLoading(v);
-
-	if (v->current_order.type == OT_LOADING) return;
-
-	if (IsRoadVehInDepot(v)) {
-		DiagDirection dir;
-		const RoadDriveEntry* rdp;
-		byte rd2;
-
-		v->cur_speed = 0;
-
-		dir = GetRoadDepotDirection(v->tile);
-		v->direction = DiagDirToDir(dir);
-
-		rd2 = _roadveh_data_2[dir];
-		rdp = _road_drive_data[(_opt.road_side << 4) + rd2];
-
-		x = TileX(v->tile) * TILE_SIZE + (rdp[6].x & 0xF);
-		y = TileY(v->tile) * TILE_SIZE + (rdp[6].y & 0xF);
-
-		if (RoadVehFindCloseTo(v, x, y, v->direction) != NULL) return;
-
-		VehicleServiceInDepot(v);
-
-		StartRoadVehSound(v);
-
-		BeginVehicleMove(v);
-
-		v->vehstatus &= ~VS_HIDDEN;
-		v->u.road.state = rd2;
-		v->u.road.frame = 6;
-
-		v->cur_image = GetRoadVehImage(v, v->direction);
-		UpdateRoadVehDeltaXY(v);
-		SetRoadVehPosition(v,x,y);
-
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		return;
-	}
-
-	if (!RoadVehAccelerate(v)) return;
-
-	if (v->u.road.overtaking != 0)  {
-		if (++v->u.road.overtaking_ctr >= 35)
-			/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
-			 *  if the vehicle started a corner. To protect that, only allow an abort of
-			 *  overtake if we are on straight road, which are the 8 states below */
-			if (v->u.road.state == 0  || v->u.road.state == 1  ||
-					v->u.road.state == 8  || v->u.road.state == 9  ||
-					v->u.road.state == 16 || v->u.road.state == 17 ||
-					v->u.road.state == 24 || v->u.road.state == 25) {
-				v->u.road.overtaking = 0;
-			}
-	}
-
-	BeginVehicleMove(v);
-
-	if (v->u.road.state == 255) {
-		GetNewVehiclePosResult gp;
-
-		GetNewVehiclePos(v, &gp);
-
-		if (RoadVehFindCloseTo(v, gp.x, gp.y, v->direction) != NULL) {
-			v->cur_speed = 0;
-			return;
-		}
-
-		if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
-			//new_dir = RoadGetNewDirection(v, gp.x, gp.y)
-			v->cur_image = GetRoadVehImage(v, v->direction);
-			UpdateRoadVehDeltaXY(v);
-			SetRoadVehPosition(v,gp.x,gp.y);
-			return;
-		}
-
-		v->x_pos = gp.x;
-		v->y_pos = gp.y;
-		VehiclePositionChanged(v);
-		if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
-		return;
-	}
-
-	rd = _road_drive_data[(v->u.road.state + (_opt.road_side << 4)) ^ v->u.road.overtaking][v->u.road.frame + 1];
-
-// switch to another tile
-	if (rd.x & 0x80) {
-		TileIndex tile = v->tile + TileOffsByDiagDir(rd.x & 3);
-		int dir = RoadFindPathToDest(v, tile, rd.x & 3);
-		uint32 r;
-		Direction newdir;
-		const RoadDriveEntry *rdp;
-
-		if (dir == -1) {
-			v->cur_speed = 0;
-			return;
-		}
-
-again:
-		if ((dir & 7) >= 6) {
-			/* Turning around */
-			tile = v->tile;
-		}
-
-		rdp = _road_drive_data[(dir + (_opt.road_side << 4)) ^ v->u.road.overtaking];
-
-		x = TileX(tile) * TILE_SIZE + rdp[0].x;
-		y = TileY(tile) * TILE_SIZE + rdp[0].y;
-
-		newdir = RoadVehGetSlidingDirection(v, x, y);
-		if (RoadVehFindCloseTo(v, x, y, newdir) != NULL) return;
-
-		r = VehicleEnterTile(v, tile, x, y);
-		if (r & 8) {
-			if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
-				v->cur_speed = 0;
-				return;
-			}
-			dir = _road_reverse_table[rd.x&3];
-			goto again;
-		}
-
-		if (IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30) && IsTileType(v->tile, MP_STATION)) {
-			if ((dir & 7) >= 6) {
-				v->cur_speed = 0;
-				return;
-			}
-			if (IsRoadStop(v->tile)) {
-				RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
-
-				// reached a loading bay, mark it as used and clear the usage bit
-				SETBIT(rs->status, v->u.road.state & 2 ? 1 : 0); // occupied bay
-				CLRBIT(rs->status, 7); // usage bit
-			}
-		}
-
-		if (!(r & 4)) {
-			v->tile = tile;
-			v->u.road.state = (byte)dir;
-			v->u.road.frame = 0;
-		}
-		if (newdir != v->direction) {
-			v->direction = newdir;
-			v->cur_speed -= v->cur_speed >> 2;
-		}
-
-		v->cur_image = GetRoadVehImage(v, newdir);
-		UpdateRoadVehDeltaXY(v);
-		RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
-		return;
-	}
-
-	if (rd.x & 0x40) {
-		int dir = RoadFindPathToDest(v, v->tile, rd.x & 3);
-		uint32 r;
-		int tmp;
-		Direction newdir;
-		const RoadDriveEntry *rdp;
-
-		if (dir == -1) {
-			v->cur_speed = 0;
-			return;
-		}
-
-		tmp = (_opt.road_side << 4) + dir;
-		rdp = _road_drive_data[tmp];
-
-		x = TileX(v->tile) * TILE_SIZE + rdp[1].x;
-		y = TileY(v->tile) * TILE_SIZE + rdp[1].y;
-
-		newdir = RoadVehGetSlidingDirection(v, x, y);
-		if (RoadVehFindCloseTo(v, x, y, newdir) != NULL) return;
-
-		r = VehicleEnterTile(v, v->tile, x, y);
-		if (r & 8) {
-			v->cur_speed = 0;
-			return;
-		}
-
-		v->u.road.state = tmp & ~16;
-		v->u.road.frame = 1;
-
-		if (newdir != v->direction) {
-			v->direction = newdir;
-			v->cur_speed -= v->cur_speed >> 2;
-		}
-
-		v->cur_image = GetRoadVehImage(v, newdir);
-		UpdateRoadVehDeltaXY(v);
-		RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
-		return;
-	}
-
-	x = (v->x_pos & ~15) + (rd.x & 15);
-	y = (v->y_pos & ~15) + (rd.y & 15);
-
-	new_dir = RoadVehGetSlidingDirection(v, x, y);
-
-	if (!IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30)) {
-		Vehicle* u = RoadVehFindCloseTo(v, x, y, new_dir);
-
-		if (u != NULL) {
-			if (v->u.road.overtaking == 0) RoadVehCheckOvertake(v, u);
-			return;
-		}
-	}
-
-	old_dir = v->direction;
-	if (new_dir != old_dir) {
-		v->direction = new_dir;
-		v->cur_speed -= (v->cur_speed >> 2);
-		if (old_dir != v->u.road.state) {
-			v->cur_image = GetRoadVehImage(v, new_dir);
-			UpdateRoadVehDeltaXY(v);
-			SetRoadVehPosition(v, v->x_pos, v->y_pos);
-			return;
-		}
-	}
-
-	if (v->u.road.state >= 0x20 &&
-			_road_veh_data_1[v->u.road.state - 0x20 + (_opt.road_side<<4)] == v->u.road.frame) {
-		RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
-		Station* st = GetStationByTile(v->tile);
-
-		if (v->current_order.type != OT_LEAVESTATION &&
-				v->current_order.type != OT_GOTO_DEPOT) {
-			Order old_order;
-
-			CLRBIT(rs->status, 7);
-
-			v->last_station_visited = GetStationIndex(v->tile);
-
-			RoadVehArrivesAt(v, st);
-
-			old_order = v->current_order;
-			v->current_order.type = OT_LOADING;
-			v->current_order.flags = 0;
-
-			if (old_order.type == OT_GOTO_STATION &&
-					v->current_order.dest == v->last_station_visited) {
-				v->current_order.flags =
-					(old_order.flags & (OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER)) | OF_NON_STOP;
-			}
-
-			SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC);
-			if (LoadUnloadVehicle(v, true)) {
-				InvalidateWindow(WC_ROADVEH_LIST, v->owner);
-				MarkRoadVehDirty(v);
-			}
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-			return;
-		}
-
-		if (v->current_order.type != OT_GOTO_DEPOT) {
-			if (HASBIT(rs->status, 7)) {
-				v->cur_speed = 0;
-				return;
-			}
-			v->current_order.type = OT_NOTHING;
-			v->current_order.flags = 0;
-			ClearSlot(v);
-		}
-		SETBIT(rs->status, 7);
-
-		if (rs == v->u.road.slot) {
-			//we have arrived at the correct station
-			ClearSlot(v);
-		} else if (v->u.road.slot != NULL) {
-			//we have arrived at the wrong station
-			//XXX The question is .. what to do? Actually we shouldn't be here
-			//but I guess we need to clear the slot
-			DEBUG(ms, 0, "Vehicle %d (index %d) arrived at wrong stop", v->unitnumber, v->index);
-			if (v->tile != v->dest_tile) {
-				DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
-			}
-			if (v->dest_tile != v->u.road.slot->xy) {
-				DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
-			}
-			if (v->current_order.type != OT_GOTO_STATION) {
-				DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.type);
-			} else {
-				if (v->current_order.dest != st->index)
-					DEBUG(ms, 2, " current station %d is not target station in current_order.station (%d)",
-							st->index, v->current_order.dest);
-			}
-
-			DEBUG(ms, 2, " force a slot clearing");
-			ClearSlot(v);
-		}
-
-		StartRoadVehSound(v);
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-
-	r = VehicleEnterTile(v, v->tile, x, y);
-	if (r & 8) {
-		v->cur_speed = 0;
-		return;
-	}
-
-	if ((r & 4) == 0) v->u.road.frame++;
-
-	v->cur_image = GetRoadVehImage(v, v->direction);
-	UpdateRoadVehDeltaXY(v);
-	RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
-}
-
-static void AgeRoadVehCargo(Vehicle *v)
-{
-	if (_age_cargo_skip_counter != 0) return;
-	if (v->cargo_days != 255) v->cargo_days++;
-}
-
-void RoadVeh_Tick(Vehicle *v)
-{
-	AgeRoadVehCargo(v);
-	RoadVehController(v);
-}
-
-static void CheckIfRoadVehNeedsService(Vehicle *v)
-{
-	const Depot* depot;
-
-	if (_patches.servint_roadveh == 0) return;
-	if (!VehicleNeedsService(v)) return;
-	if (v->vehstatus & VS_STOPPED) return;
-	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
-
-	// Don't interfere with a depot visit scheduled by the user, or a
-	// depot visit by the order list.
-	if (v->current_order.type == OT_GOTO_DEPOT &&
-			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
-		return;
-
-	// If we already got a slot at a stop, use that FIRST, and go to a depot later
-	if (v->u.road.slot != NULL) return;
-
-	if (IsRoadVehInDepot(v)) {
-		VehicleServiceInDepot(v);
-		return;
-	}
-
-	// XXX If we already have a depot order, WHY do we search over and over?
-	depot = FindClosestRoadDepot(v);
-
-	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
-		if (v->current_order.type == OT_GOTO_DEPOT) {
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return;
-	}
-
-	if (v->current_order.type == OT_GOTO_DEPOT &&
-			v->current_order.flags & OF_NON_STOP &&
-			!CHANCE16(1, 20)) {
-		return;
-	}
-
-	v->current_order.type = OT_GOTO_DEPOT;
-	v->current_order.flags = OF_NON_STOP;
-	v->current_order.dest = depot->index;
-	v->dest_tile = depot->xy;
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-}
-
-void OnNewDay_RoadVeh(Vehicle *v)
-{
-	int32 cost;
-
-	if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v);
-	if (v->u.road.blocked_ctr == 0) CheckVehicleBreakdown(v);
-
-	AgeVehicle(v);
-	CheckIfRoadVehNeedsService(v);
-
-	CheckOrders(v);
-
-	//Current slot has expired
-	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot != NULL && v->u.road.slot_age-- == 0) {
-		DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
-			v->unitnumber, v->index, v->u.road.slot->xy);
-		ClearSlot(v);
-	}
-
-	if (v->vehstatus & VS_STOPPED) return;
-
-	/* update destination */
-	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot == NULL && !(v->vehstatus & VS_CRASHED)) {
-		Station* st = GetStation(v->current_order.dest);
-		RoadStop* rs = GetPrimaryRoadStop(st, v->cargo_type == CT_PASSENGERS ? RS_BUS : RS_TRUCK);
-		RoadStop* best = NULL;
-
-		if (rs != NULL) {
-			if (DistanceManhattan(v->tile, st->xy) < 16) {
-				uint dist, badness;
-				uint minbadness = UINT_MAX;
-
-				DEBUG(ms, 2, "Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%X)",
-					v->unitnumber, v->index, st->index, st->xy
-				);
-				/* Now we find the nearest road stop that has a free slot */
-				for (; rs != NULL; rs = rs->next) {
-					dist = RoadFindPathToStop(v, rs->xy);
-					if (dist == UINT_MAX) {
-						DEBUG(ms, 4, " stop 0x%X is unreachable, not treating further", rs->xy);
-						continue;
-					}
-					badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist;
-
-					DEBUG(ms, 4, " stop 0x%X has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s");
-					DEBUG(ms, 4, " distance is %u", dist);
-					DEBUG(ms, 4, " badness %u", badness);
-
-					if (badness < minbadness) {
-						best = rs;
-						minbadness = badness;
-					}
-				}
-
-				if (best != NULL) {
-					best->num_vehicles++;
-					DEBUG(ms, 3, "Assigned to stop 0x%X", best->xy);
-
-					v->u.road.slot = best;
-					v->dest_tile = best->xy;
-					v->u.road.slot_age = 14;
-				} else {
-					DEBUG(ms, 3, "Could not find a suitable stop");
-				}
-			} else {
-				DEBUG(ms, 5, "Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%X)",
-						v->unitnumber, v->index, st->index, st->xy);
-			}
-		} else {
-			DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)",
-					v->unitnumber, v->index, st->index, st->xy);
-		}
-	}
-
-	cost = RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running / 364;
-
-	v->profit_this_year -= cost >> 8;
-
-	SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN);
-	SubtractMoneyFromPlayerFract(v->owner, cost);
-
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-	InvalidateWindowClasses(WC_ROADVEH_LIST);
-}
-
-
-void RoadVehiclesYearlyLoop(void)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Road) {
-			v->profit_last_year = v->profit_this_year;
-			v->profit_this_year = 0;
-			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		}
-	}
-}
-
-/** Refit a road vehicle to the specified cargo type
- * @param tile unused
- * @param p1 Vehicle ID of the vehicle to refit
- * @param p2 Bitstuffed elements
- * - p2 = (bit 0-7) - the new cargo type to refit to
- * - p2 = (bit 8-15) - the new cargo subtype to refit to
- */
-int32 CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	int32 cost;
-	CargoID new_cid = GB(p2, 0, 8);
-	byte new_subtype = GB(p2, 8, 8);
-	uint16 capacity = CALLBACK_FAILED;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
-	if (!IsRoadVehInDepotStopped(v)) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
-
-	if (new_cid > NUM_CARGO || !CanRefitTo(v->engine_type, new_cid)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN);
-
-	if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
-		/* Back up the cargo type */
-		CargoID temp_cid = v->cargo_type;
-		byte temp_subtype = v->cargo_subtype;
-		v->cargo_type = new_cid;
-		v->cargo_subtype = new_subtype;
-
-		/* Check the refit capacity callback */
-		capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
-
-		/* Restore the original cargo type */
-		v->cargo_type = temp_cid;
-		v->cargo_subtype = temp_subtype;
-	}
-
-	if (capacity == CALLBACK_FAILED) {
-		/* callback failed or not used, use default capacity */
-		const RoadVehicleInfo *rvi = RoadVehInfo(v->engine_type);
-
-		CargoID old_cid = rvi->cargo_type;
-		/* normally, the capacity depends on the cargo type, a vehicle can
-		 * carry twice as much mail/goods as normal cargo, and four times as
-		 * many passengers
-		 */
-		capacity = rvi->capacity;
-		switch (old_cid) {
-			case CT_PASSENGERS: break;
-			case CT_MAIL:
-			case CT_GOODS: capacity *= 2; break;
-			default:       capacity *= 4; break;
-		}
-		switch (new_cid) {
-			case CT_PASSENGERS: break;
-			case CT_MAIL:
-			case CT_GOODS: capacity /= 2; break;
-			default:       capacity /= 4; break;
-		}
-	}
-	_returned_refit_capacity = capacity;
-
-	cost = 0;
-	if (IsHumanPlayer(v->owner) && new_cid != v->cargo_type) {
-		cost = GetRefitCost(v->engine_type);
-	}
-
-	if (flags & DC_EXEC) {
-		v->cargo_cap = capacity;
-		v->cargo_count = (v->cargo_type == new_cid) ? min(capacity, v->cargo_count) : 0;
-		v->cargo_type = new_cid;
-		v->cargo_subtype = new_subtype;
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-	}
-
-	return cost;
-}
new file mode 100644
--- /dev/null
+++ b/src/roadveh_cmd.cpp
@@ -0,0 +1,1826 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include <limits.h>
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "road_map.h"
+#include "roadveh.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "vehicle.h"
+#include "engine.h"
+#include "command.h"
+#include "station.h"
+#include "news.h"
+#include "pathfind.h"
+#include "npf.h"
+#include "player.h"
+#include "sound.h"
+#include "depot.h"
+#include "bridge.h"
+#include "tunnel_map.h"
+#include "bridge_map.h"
+#include "vehicle_gui.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_text.h"
+#include "newgrf_sound.h"
+#include "yapf/yapf.h"
+#include "date.h"
+
+static const uint16 _roadveh_images[63] = {
+	0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
+	0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
+	0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
+	0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
+	0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
+	0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
+	0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
+	0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
+};
+
+static const uint16 _roadveh_full_adder[63] = {
+	 0,  88,   0,   0,   0,   0,  48,  48,
+	48,  48,   0,   0,  64,  64,   0,  16,
+	16,   0,  88,   0,   0,   0,   0,  48,
+	48,  48,  48,   0,   0,  64,  64,   0,
+	16,  16,   0,  88,   0,   0,   0,   0,
+	48,  48,  48,  48,   0,   0,  64,  64,
+	 0,  16,  16,   0,   8,   8,   8,   8,
+	 0,   0,   0,   8,   8,   8,   8
+};
+
+
+static const uint16 _road_veh_fp_ax_and[4] = {
+	0x1009, 0x16, 0x520, 0x2A00
+};
+
+static const byte _road_reverse_table[4] = {
+	6, 7, 14, 15
+};
+
+static const uint16 _road_pf_table_3[4] = {
+	0x910, 0x1600, 0x2005, 0x2A
+};
+
+int GetRoadVehImage(const Vehicle* v, Direction direction)
+{
+	int img = v->spritenum;
+	int image;
+
+	if (is_custom_sprite(img)) {
+		image = GetCustomVehicleSprite(v, direction);
+		if (image != 0) return image;
+		img = orig_road_vehicle_info[v->engine_type - ROAD_ENGINES_INDEX].image_index;
+	}
+
+	image = direction + _roadveh_images[img];
+	if (v->cargo_count >= v->cargo_cap / 2) image += _roadveh_full_adder[img];
+	return image;
+}
+
+void DrawRoadVehEngine(int x, int y, EngineID engine, uint32 image_ormod)
+{
+	int spritenum = RoadVehInfo(engine)->image_index;
+
+	if (is_custom_sprite(spritenum)) {
+		int sprite = GetCustomVehicleIcon(engine, DIR_W);
+
+		if (sprite != 0) {
+			DrawSprite(sprite | image_ormod, x, y);
+			return;
+		}
+		spritenum = orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index;
+	}
+	DrawSprite((6 + _roadveh_images[spritenum]) | image_ormod, x, y);
+}
+
+static int32 EstimateRoadVehCost(EngineID engine_type)
+{
+	return ((_price.roadveh_base >> 3) * RoadVehInfo(engine_type)->base_cost) >> 5;
+}
+
+/** Build a road vehicle.
+ * @param tile tile of depot where road vehicle is built
+ * @param p1 bus/truck type being built (engine)
+ * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number
+ */
+int32 CmdBuildRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost;
+	Vehicle *v;
+	UnitID unit_num;
+	Engine *e;
+
+	if (!IsEngineBuildable(p1, VEH_Road, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	cost = EstimateRoadVehCost(p1);
+	if (flags & DC_QUERY_COST) return cost;
+
+	/* The ai_new queries the vehicle cost before building the route,
+	 * so we must check against cheaters no sooner than now. --pasky */
+	if (!IsTileDepotType(tile, TRANSPORT_ROAD)) return CMD_ERROR;
+	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
+
+	v = AllocateVehicle();
+	if (v == NULL || IsOrderPoolFull())
+		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+	/* find the first free roadveh id */
+	unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Road);
+	if (unit_num > _patches.max_roadveh)
+		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+	if (flags & DC_EXEC) {
+		int x;
+		int y;
+
+		const RoadVehicleInfo *rvi = RoadVehInfo(p1);
+
+		v->unitnumber = unit_num;
+		v->direction = 0;
+		v->owner = _current_player;
+
+		v->tile = tile;
+		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
+		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
+		v->x_pos = x;
+		v->y_pos = y;
+		v->z_pos = GetSlopeZ(x,y);
+		v->z_height = 6;
+
+		v->u.road.state = 254;
+		v->vehstatus = VS_HIDDEN|VS_STOPPED|VS_DEFPAL;
+
+		v->spritenum = rvi->image_index;
+		v->cargo_type = rvi->cargo_type;
+		v->cargo_subtype = 0;
+		v->cargo_cap = rvi->capacity;
+//		v->cargo_count = 0;
+		v->value = cost;
+//		v->day_counter = 0;
+//		v->next_order_param = v->next_order = 0;
+//		v->load_unload_time_rem = 0;
+//		v->progress = 0;
+
+//	v->u.road.unk2 = 0;
+//	v->u.road.overtaking = 0;
+
+		v->last_station_visited = INVALID_STATION;
+		v->max_speed = rvi->max_speed;
+		v->engine_type = (byte)p1;
+
+		e = GetEngine(p1);
+		v->reliability = e->reliability;
+		v->reliability_spd_dec = e->reliability_spd_dec;
+		v->max_age = e->lifelength * 366;
+		_new_vehicle_id = v->index;
+
+		v->string_id = STR_SV_ROADVEH_NAME;
+
+		v->service_interval = _patches.servint_roadveh;
+
+		v->date_of_last_service = _date;
+		v->build_year = _cur_year;
+
+		v->type = VEH_Road;
+		v->cur_image = 0xC15;
+		v->random_bits = VehicleRandomBits();
+
+		VehiclePositionChanged(v);
+		GetPlayer(_current_player)->num_engines[p1]++;
+
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+		InvalidateWindow(WC_COMPANY, v->owner);
+		if (IsLocalPlayer())
+			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road); // updates the replace Road window
+	}
+
+	return cost;
+}
+
+/** Start/Stop a road vehicle.
+ * @param tile unused
+ * @param p1 road vehicle ID to start/stop
+ * @param p2 unused
+ */
+int32 CmdStartStopRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	uint16 callback;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* Check if this road veh can be started/stopped. The callback will fail or
+	 * return 0xFF if it can. */
+	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
+	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
+		return_cmd_error(error);
+	}
+
+	if (flags & DC_EXEC) {
+		if (IsRoadVehInDepotStopped(v)) {
+			DeleteVehicleNews(p1, STR_9016_ROAD_VEHICLE_IS_WAITING);
+		}
+
+		v->vehstatus ^= VS_STOPPED;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+	}
+
+	return 0;
+}
+
+void ClearSlot(Vehicle *v)
+{
+	RoadStop *rs = v->u.road.slot;
+	if (v->u.road.slot == NULL) return;
+
+	v->u.road.slot = NULL;
+	v->u.road.slot_age = 0;
+
+	assert(rs->num_vehicles != 0);
+	rs->num_vehicles--;
+
+	DEBUG(ms, 3, "Clearing slot at 0x%X", rs->xy);
+}
+
+/** Sell a road vehicle.
+ * @param tile unused
+ * @param p1 vehicle ID to be sold
+ * @param p2 unused
+ */
+int32 CmdSellRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	if (!IsRoadVehInDepotStopped(v)) {
+		return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
+	}
+
+	if (flags & DC_EXEC) {
+		// Invalidate depot
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+		InvalidateWindow(WC_COMPANY, v->owner);
+		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
+		ClearSlot(v);
+		DeleteDepotHighlightOfVehicle(v);
+		DeleteVehicle(v);
+		if (IsLocalPlayer()) InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Road);
+	}
+
+	return -(int32)v->value;
+}
+
+typedef struct RoadFindDepotData {
+	uint best_length;
+	TileIndex tile;
+	byte owner;
+} RoadFindDepotData;
+
+static const DiagDirection _road_pf_directions[] = {
+	DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, 255, 255,
+	DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, 255, 255
+};
+
+static bool EnumRoadSignalFindDepot(TileIndex tile, void* data, int track, uint length, byte* state)
+{
+	RoadFindDepotData* rfdd = data;
+
+	tile += TileOffsByDiagDir(_road_pf_directions[track]);
+
+	if (IsTileType(tile, MP_STREET) &&
+			GetRoadTileType(tile) == ROAD_TILE_DEPOT &&
+			IsTileOwner(tile, rfdd->owner) &&
+			length < rfdd->best_length) {
+		rfdd->best_length = length;
+		rfdd->tile = tile;
+	}
+	return false;
+}
+
+static const Depot* FindClosestRoadDepot(const Vehicle* v)
+{
+	TileIndex tile = v->tile;
+
+	if (_patches.yapf.road_use_yapf) {
+		Depot* ret = YapfFindNearestRoadDepot(v);
+		return ret;
+	} else if (_patches.new_pathfinding_all) {
+		NPFFoundTargetData ftd;
+		/* See where we are now */
+		Trackdir trackdir = GetVehicleTrackdir(v);
+
+		ftd = NPFRouteToDepotBreadthFirst(v->tile, trackdir, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE);
+		if (ftd.best_bird_dist == 0) {
+			return GetDepotByTile(ftd.node.tile); /* Target found */
+		} else {
+			return NULL; /* Target not found */
+		}
+		/* We do not search in two directions here, why should we? We can't reverse right now can we? */
+	} else {
+		RoadFindDepotData rfdd;
+		DiagDirection i;
+
+		rfdd.owner = v->owner;
+		rfdd.best_length = (uint)-1;
+
+		/* search in all directions */
+		for (i = 0; i != 4; i++) {
+			FollowTrack(tile, 0x2000 | TRANSPORT_ROAD, i, EnumRoadSignalFindDepot, NULL, &rfdd);
+		}
+
+		if (rfdd.best_length == (uint)-1) return NULL;
+
+		return GetDepotByTile(rfdd.tile);
+	}
+}
+
+/** Send a road vehicle to the depot.
+ * @param tile unused
+ * @param p1 vehicle ID to send to the depot
+ * @param p2 various bitmasked elements
+ * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
+ * - p2 bit 8-10 - VLW flag (for mass goto depot)
+ */
+int32 CmdSendRoadVehToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	const Depot *dep;
+
+	if (p2 & DEPOT_MASS_SEND) {
+		/* Mass goto depot requested */
+		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
+		return SendAllVehiclesToDepot(VEH_Road, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
+	}
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
+
+	if (IsRoadVehInDepot(v)) return CMD_ERROR;
+
+	/* If the current orders are already goto-depot */
+	if (v->current_order.type == OT_GOTO_DEPOT) {
+		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
+			/* We called with a different DEPOT_SERVICE setting.
+			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
+			 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
+			if (flags & DC_EXEC) {
+				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			}
+			return 0;
+		}
+
+		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
+		if (flags & DC_EXEC) {
+			/* If the orders to 'goto depot' are in the orders list (forced servicing),
+			 * then skip to the next order; effectively cancelling this forced service */
+			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS))
+				v->cur_order_index++;
+
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return 0;
+	}
+
+	dep = FindClosestRoadDepot(v);
+	if (dep == NULL) return_cmd_error(STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT);
+
+	if (flags & DC_EXEC) {
+		ClearSlot(v);
+		v->current_order.type = OT_GOTO_DEPOT;
+		v->current_order.flags = OF_NON_STOP;
+		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+		v->current_order.refit_cargo = CT_INVALID;
+		v->current_order.dest = dep->index;
+		v->dest_tile = dep->xy;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+
+	return 0;
+}
+
+/** Turn a roadvehicle around.
+ * @param tile unused
+ * @param p1 vehicle ID to turn
+ * @param p2 unused
+ */
+int32 CmdTurnRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (v->vehstatus & VS_STOPPED ||
+			v->u.road.crashed_ctr != 0 ||
+			v->breakdown_ctr != 0 ||
+			v->u.road.overtaking != 0 ||
+			v->u.road.state == 255 ||
+			IsRoadVehInDepot(v) ||
+			v->cur_speed < 5) {
+		return CMD_ERROR;
+	}
+
+	if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR;
+	if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
+
+	return 0;
+}
+
+
+static void MarkRoadVehDirty(Vehicle *v)
+{
+	v->cur_image = GetRoadVehImage(v, v->direction);
+	MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
+}
+
+static void UpdateRoadVehDeltaXY(Vehicle *v)
+{
+#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
+	static const uint32 _delta_xy_table[8] = {
+		MKIT(3, 3, -1, -1),
+		MKIT(3, 7, -1, -3),
+		MKIT(3, 3, -1, -1),
+		MKIT(7, 3, -3, -1),
+		MKIT(3, 3, -1, -1),
+		MKIT(3, 7, -1, -3),
+		MKIT(3, 3, -1, -1),
+		MKIT(7, 3, -3, -1),
+	};
+#undef MKIT
+	uint32 x = _delta_xy_table[v->direction];
+	v->x_offs        = GB(x,  0, 8);
+	v->y_offs        = GB(x,  8, 8);
+	v->sprite_width  = GB(x, 16, 8);
+	v->sprite_height = GB(x, 24, 8);
+}
+
+static void ClearCrashedStation(Vehicle *v)
+{
+	RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
+
+	// mark station as not busy
+	CLRBIT(rs->status, 7);
+
+	// free parking bay
+	SETBIT(rs->status, HASBIT(v->u.road.state, 1) ? 1 : 0);
+}
+
+static void RoadVehDelete(Vehicle *v)
+{
+	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+	RebuildVehicleLists();
+	InvalidateWindow(WC_COMPANY, v->owner);
+
+	if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
+
+	BeginVehicleMove(v);
+	EndVehicleMove(v);
+
+	ClearSlot(v);
+	DeleteVehicle(v);
+}
+
+static byte SetRoadVehPosition(Vehicle *v, int x, int y)
+{
+	byte new_z, old_z;
+
+	// need this hint so it returns the right z coordinate on bridges.
+	v->x_pos = x;
+	v->y_pos = y;
+	new_z = GetSlopeZ(x, y);
+
+	old_z = v->z_pos;
+	v->z_pos = new_z;
+
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+	return old_z;
+}
+
+static void RoadVehSetRandomDirection(Vehicle *v)
+{
+	static const DirDiff delta[] = {
+		DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
+	};
+
+	uint32 r = Random();
+
+	v->direction = ChangeDir(v->direction, delta[r & 3]);
+	BeginVehicleMove(v);
+	UpdateRoadVehDeltaXY(v);
+	v->cur_image = GetRoadVehImage(v, v->direction);
+	SetRoadVehPosition(v, v->x_pos, v->y_pos);
+}
+
+static void RoadVehIsCrashed(Vehicle *v)
+{
+	v->u.road.crashed_ctr++;
+	if (v->u.road.crashed_ctr == 2) {
+		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
+	} else if (v->u.road.crashed_ctr <= 45) {
+		if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
+	} else if (v->u.road.crashed_ctr >= 2220) {
+		RoadVehDelete(v);
+	}
+}
+
+static void* EnumCheckRoadVehCrashTrain(Vehicle* v, void* data)
+{
+	const Vehicle* u = data;
+
+	return
+		v->type == VEH_Train &&
+		myabs(v->z_pos - u->z_pos) <= 6 &&
+		myabs(v->x_pos - u->x_pos) <= 4 &&
+		myabs(v->y_pos - u->y_pos) <= 4 ?
+			v : NULL;
+}
+
+static void RoadVehCrash(Vehicle *v)
+{
+	uint16 pass;
+
+	v->u.road.crashed_ctr++;
+	v->vehstatus |= VS_CRASHED;
+	ClearSlot(v);
+
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+
+	pass = 1;
+	if (v->cargo_type == CT_PASSENGERS) pass += v->cargo_count;
+	v->cargo_count = 0;
+
+	SetDParam(0, pass);
+	AddNewsItem(
+		(pass == 1) ?
+			STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE,
+		NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
+		v->index,
+		0
+	);
+
+	ModifyStationRatingAround(v->tile, v->owner, -160, 22);
+	SndPlayVehicleFx(SND_12_EXPLOSION, v);
+}
+
+static void RoadVehCheckTrainCrash(Vehicle *v)
+{
+	TileIndex tile;
+
+	if (v->u.road.state == 255) return;
+
+	tile = v->tile;
+
+	if (!IsLevelCrossingTile(tile)) return;
+
+	if (VehicleFromPos(tile, v, EnumCheckRoadVehCrashTrain) != NULL)
+		RoadVehCrash(v);
+}
+
+static void HandleBrokenRoadVeh(Vehicle *v)
+{
+	if (v->breakdown_ctr != 1) {
+		v->breakdown_ctr = 1;
+		v->cur_speed = 0;
+
+		if (v->breakdowns_since_last_service != 255)
+			v->breakdowns_since_last_service++;
+
+		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+				SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
+		}
+
+		if (!(v->vehstatus & VS_HIDDEN)) {
+			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
+			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
+		}
+	}
+
+	if ((v->tick_counter & 1) == 0) {
+		if (--v->breakdown_delay == 0) {
+			v->breakdown_ctr = 0;
+			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		}
+	}
+}
+
+static void ProcessRoadVehOrder(Vehicle *v)
+{
+	const Order *order;
+
+	switch (v->current_order.type) {
+		case OT_GOTO_DEPOT:
+			// Let a depot order in the orderlist interrupt.
+			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return;
+			if (v->current_order.flags & OF_SERVICE_IF_NEEDED &&
+					!VehicleNeedsService(v)) {
+				v->cur_order_index++;
+			}
+			break;
+
+		case OT_LOADING:
+		case OT_LEAVESTATION:
+			return;
+
+		default: break;
+	}
+
+	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
+
+	order = GetVehicleOrder(v, v->cur_order_index);
+
+	if (order == NULL) {
+		v->current_order.type = OT_NOTHING;
+		v->current_order.flags = 0;
+		v->dest_tile = 0;
+		ClearSlot(v);
+		return;
+	}
+
+	if (order->type  == v->current_order.type &&
+			order->flags == v->current_order.flags &&
+			order->dest  == v->current_order.dest) {
+		return;
+	}
+
+	v->current_order = *order;
+
+	switch (order->type) {
+		case OT_GOTO_STATION: {
+			const RoadStop* rs;
+
+			if (order->dest == v->last_station_visited) {
+				v->last_station_visited = INVALID_STATION;
+			}
+
+			rs = GetPrimaryRoadStop(
+				GetStation(order->dest),
+				v->cargo_type == CT_PASSENGERS ? RS_BUS : RS_TRUCK
+			);
+
+			if (rs != NULL) {
+				TileIndex dest = rs->xy;
+				uint mindist = DistanceManhattan(v->tile, rs->xy);
+
+				for (rs = rs->next; rs != NULL; rs = rs->next) {
+					uint dist = DistanceManhattan(v->tile, rs->xy);
+
+					if (dist < mindist) {
+						mindist = dist;
+						dest = rs->xy;
+					}
+				}
+				v->dest_tile = dest;
+			} else {
+				// There is no stop left at the station, so don't even TRY to go there
+				v->cur_order_index++;
+				v->dest_tile = 0;
+			}
+			break;
+		}
+
+		case OT_GOTO_DEPOT:
+			v->dest_tile = GetDepot(order->dest)->xy;
+			break;
+
+		default:
+			v->dest_tile = 0;
+			break;
+	}
+
+	InvalidateVehicleOrder(v);
+}
+
+static void HandleRoadVehLoading(Vehicle *v)
+{
+	switch (v->current_order.type) {
+		case OT_LOADING: {
+			Order b;
+
+			if (--v->load_unload_time_rem != 0) return;
+
+			if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
+					(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
+				SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC);
+				if (LoadUnloadVehicle(v, false)) {
+					InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+					MarkRoadVehDirty(v);
+				}
+				return;
+			}
+
+			b = v->current_order;
+			v->current_order.type = OT_LEAVESTATION;
+			v->current_order.flags = 0;
+			if (!(b.flags & OF_NON_STOP)) return;
+			break;
+		}
+
+		case OT_DUMMY: break;
+
+		default: return;
+	}
+
+	v->cur_order_index++;
+	InvalidateVehicleOrder(v);
+}
+
+static void StartRoadVehSound(const Vehicle* v)
+{
+	if (!PlayVehicleSound(v, VSE_START)) {
+		SoundFx s = RoadVehInfo(v->engine_type)->sfx;
+		if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
+			s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
+		SndPlayVehicleFx(s, v);
+	}
+}
+
+typedef struct RoadVehFindData {
+	int x;
+	int y;
+	const Vehicle* veh;
+	Direction dir;
+} RoadVehFindData;
+
+static void* EnumCheckRoadVehClose(Vehicle *v, void* data)
+{
+	static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
+	static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
+
+	const RoadVehFindData* rvf = data;
+
+	short x_diff = v->x_pos - rvf->x;
+	short y_diff = v->y_pos - rvf->y;
+
+	return
+		rvf->veh != v &&
+		v->type == VEH_Road &&
+		!IsRoadVehInDepot(v) &&
+		myabs(v->z_pos - rvf->veh->z_pos) < 6 &&
+		v->direction == rvf->dir &&
+		(dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
+		(dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
+		(dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
+		(dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0)) ?
+			v : NULL;
+}
+
+static Vehicle* RoadVehFindCloseTo(Vehicle* v, int x, int y, Direction dir)
+{
+	RoadVehFindData rvf;
+	Vehicle *u;
+
+	if (v->u.road.reverse_ctr != 0) return NULL;
+
+	rvf.x = x;
+	rvf.y = y;
+	rvf.dir = dir;
+	rvf.veh = v;
+	u = VehicleFromPos(TileVirtXY(x, y), &rvf, EnumCheckRoadVehClose);
+
+	// This code protects a roadvehicle from being blocked for ever
+	//  If more than 1480 / 74 days a road vehicle is blocked, it will
+	//  drive just through it. The ultimate backup-code of TTD.
+	// It can be disabled.
+	if (u == NULL) {
+		v->u.road.blocked_ctr = 0;
+		return NULL;
+	}
+
+	if (++v->u.road.blocked_ctr > 1480) return NULL;
+
+	return u;
+}
+
+static void RoadVehArrivesAt(const Vehicle* v, Station* st)
+{
+	if (v->cargo_type == CT_PASSENGERS) {
+		/* Check if station was ever visited before */
+		if (!(st->had_vehicle_of_type & HVOT_BUS)) {
+			uint32 flags;
+
+			st->had_vehicle_of_type |= HVOT_BUS;
+			SetDParam(0, st->index);
+			flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
+			AddNewsItem(
+				STR_902F_CITIZENS_CELEBRATE_FIRST,
+				flags,
+				v->index,
+				0);
+		}
+	} else {
+		/* Check if station was ever visited before */
+		if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
+			uint32 flags;
+
+			st->had_vehicle_of_type |= HVOT_TRUCK;
+			SetDParam(0, st->index);
+			flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
+			AddNewsItem(
+				STR_9030_CITIZENS_CELEBRATE_FIRST,
+				flags,
+				v->index,
+				0
+			);
+		}
+	}
+}
+
+static bool RoadVehAccelerate(Vehicle *v)
+{
+	uint spd = v->cur_speed + 1 + (v->u.road.overtaking != 0 ? 1 : 0);
+	byte t;
+
+	// Clamp
+	spd = min(spd, v->max_speed);
+	if (v->u.road.state == 255) spd = min(spd, SetSpeedLimitOnBridge(v));
+
+	//updates statusbar only if speed have changed to save CPU time
+	if (spd != v->cur_speed) {
+		v->cur_speed = spd;
+		if (_patches.vehicle_speed) {
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+	}
+
+	// Decrease somewhat when turning
+	if (!(v->direction & 1)) spd = spd * 3 >> 2;
+
+	if (spd == 0) return false;
+
+	if ((byte)++spd == 0) return true;
+
+	v->progress = (t = v->progress) - (byte)spd;
+
+	return (t < v->progress);
+}
+
+static Direction RoadVehGetNewDirection(const Vehicle* v, int x, int y)
+{
+	static const Direction _roadveh_new_dir[] = {
+		DIR_N , DIR_NW, DIR_W , 0,
+		DIR_NE, DIR_N , DIR_SW, 0,
+		DIR_E , DIR_SE, DIR_S
+	};
+
+	x = x - v->x_pos + 1;
+	y = y - v->y_pos + 1;
+
+	if ((uint)x > 2 || (uint)y > 2) return v->direction;
+	return _roadveh_new_dir[y * 4 + x];
+}
+
+static Direction RoadVehGetSlidingDirection(const Vehicle* v, int x, int y)
+{
+	Direction new = RoadVehGetNewDirection(v, x, y);
+	Direction old = v->direction;
+	DirDiff delta;
+
+	if (new == old) return old;
+	delta = (DirDifference(new, old) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
+	return ChangeDir(old, delta);
+}
+
+typedef struct OvertakeData {
+	const Vehicle* u;
+	const Vehicle* v;
+	TileIndex tile;
+	byte tilebits;
+} OvertakeData;
+
+static void* EnumFindVehToOvertake(Vehicle* v, void* data)
+{
+	const OvertakeData* od = data;
+
+	return
+		v->tile == od->tile && v->type == VEH_Road && v != od->u && v != od->v ?
+			v : NULL;
+}
+
+static bool FindRoadVehToOvertake(OvertakeData *od)
+{
+	uint32 bits;
+
+	bits = GetTileTrackStatus(od->tile, TRANSPORT_ROAD) & 0x3F;
+
+	if (!(od->tilebits & bits) || (bits & 0x3C) || (bits & 0x3F3F0000))
+		return true;
+	return VehicleFromPos(od->tile, od, EnumFindVehToOvertake) != NULL;
+}
+
+static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
+{
+	OvertakeData od;
+	byte tt;
+
+	od.v = v;
+	od.u = u;
+
+	if (u->max_speed >= v->max_speed &&
+			!(u->vehstatus & VS_STOPPED) &&
+			u->cur_speed != 0) {
+		return;
+	}
+
+	if (v->direction != u->direction || !(v->direction & 1)) return;
+
+	if (v->u.road.state >= 32 || (v->u.road.state & 7) > 1) return;
+
+	tt = GetTileTrackStatus(v->tile, TRANSPORT_ROAD) & 0x3F;
+	if ((tt & 3) == 0) return;
+	if ((tt & 0x3C) != 0) return;
+
+	if (tt == 3) tt = (v->direction & 2) ? 2 : 1;
+	od.tilebits = tt;
+
+	od.tile = v->tile;
+	if (FindRoadVehToOvertake(&od)) return;
+
+	od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
+	if (FindRoadVehToOvertake(&od)) return;
+
+	if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
+		v->u.road.overtaking_ctr = 0x11;
+		v->u.road.overtaking = 0x10;
+	} else {
+//		if (FindRoadVehToOvertake(&od)) return;
+		v->u.road.overtaking_ctr = 0;
+		v->u.road.overtaking = 0x10;
+	}
+}
+
+static void RoadZPosAffectSpeed(Vehicle *v, byte old_z)
+{
+	if (old_z == v->z_pos) return;
+
+	if (old_z < v->z_pos) {
+		v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
+	} else {
+		uint16 spd = v->cur_speed + 2;
+		if (spd <= v->max_speed) v->cur_speed = spd;
+	}
+}
+
+static int PickRandomBit(uint bits)
+{
+	uint num = 0;
+	uint b = bits;
+	uint i;
+
+	do {
+		if (b & 1) num++;
+	} while (b >>= 1);
+
+	num = RandomRange(num);
+
+	for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
+	return i;
+}
+
+typedef struct {
+	TileIndex dest;
+	uint maxtracklen;
+	uint mindist;
+} FindRoadToChooseData;
+
+static bool EnumRoadTrackFindDist(TileIndex tile, void* data, int track, uint length, byte* state)
+{
+	FindRoadToChooseData* frd = data;
+	uint dist = DistanceManhattan(tile, frd->dest);
+
+	if (dist <= frd->mindist) {
+		if (dist != frd->mindist || length < frd->maxtracklen) {
+			frd->maxtracklen = length;
+		}
+		frd->mindist = dist;
+	}
+	return false;
+}
+
+static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+
+	void* perf = NpfBeginInterval();
+	NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, owner, railtypes);
+	int t = NpfEndInterval(perf);
+	DEBUG(yapf, 4, "[NPFR] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
+	return ret;
+}
+
+// Returns direction to choose
+// or -1 if the direction is currently blocked
+static int RoadFindPathToDest(Vehicle* v, TileIndex tile, DiagDirection enterdir)
+{
+#define return_track(x) {best_track = x; goto found_best_track; }
+
+	uint16 signal;
+	uint bitmask;
+	TileIndex desttile;
+	FindRoadToChooseData frd;
+	int best_track;
+	uint best_dist, best_maxlen;
+	uint i;
+
+	{
+		uint32 r = GetTileTrackStatus(tile, TRANSPORT_ROAD);
+		signal  = GB(r, 16, 16);
+		bitmask = GB(r,  0, 16);
+	}
+
+	if (IsTileType(tile, MP_STREET)) {
+		if (GetRoadTileType(tile) == ROAD_TILE_DEPOT && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) {
+			/* Road depot owned by another player or with the wrong orientation */
+			bitmask = 0;
+		}
+	} else if (IsTileType(tile, MP_STATION) && IsRoadStopTile(tile)) {
+		if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir) {
+			/* different station owner or wrong orientation */
+			bitmask = 0;
+		} else {
+			/* Our station */
+			RoadStopType rstype = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK;
+
+			if (GetRoadStopType(tile) != rstype) {
+				// wrong station type
+				bitmask = 0;
+			} else {
+				// proper station type, check if there is free loading bay
+				const RoadStop *rs = GetRoadStopByTile(tile, rstype);
+				if (rs == NULL || (!_patches.roadveh_queue && GB(rs->status, 0, 2) == 0)) {
+					// station is full and RV queuing is off
+					bitmask = 0;
+				}
+			}
+		}
+	}
+	/* The above lookups should be moved to GetTileTrackStatus in the
+	 * future, but that requires more changes to the pathfinder and other
+	 * stuff, probably even more arguments to GTTS.
+	 */
+
+	/* remove unreachable tracks */
+	bitmask &= _road_veh_fp_ax_and[enterdir];
+	if (bitmask == 0) {
+		/* No reachable tracks, so we'll reverse */
+		return_track(_road_reverse_table[enterdir]);
+	}
+
+	if (v->u.road.reverse_ctr != 0) {
+		/* What happens here?? */
+		v->u.road.reverse_ctr = 0;
+		if (v->tile != tile) {
+			return_track(_road_reverse_table[enterdir]);
+		}
+	}
+
+	desttile = v->dest_tile;
+	if (desttile == 0) {
+		// Pick a random track
+		return_track(PickRandomBit(bitmask));
+	}
+
+	// Only one track to choose between?
+	if (!(KillFirstBit2x64(bitmask))) {
+		return_track(FindFirstBit2x64(bitmask));
+	}
+
+	if (_patches.yapf.road_use_yapf) {
+		Trackdir trackdir = YapfChooseRoadTrack(v, tile, enterdir);
+		if (trackdir != INVALID_TRACKDIR) return_track(trackdir);
+		return_track(PickRandomBit(bitmask));
+	} else if (_patches.new_pathfinding_all) {
+		NPFFindStationOrTileData fstd;
+		NPFFoundTargetData ftd;
+		byte trackdir;
+
+		NPFFillWithOrderData(&fstd, v);
+		trackdir = DiagdirToDiagTrackdir(enterdir);
+		//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
+
+		ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE);
+		if (ftd.best_trackdir == 0xff) {
+			/* We are already at our target. Just do something */
+			//TODO: maybe display error?
+			//TODO: go straight ahead if possible?
+			return_track(FindFirstBit2x64(bitmask));
+		} else {
+			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
+			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
+			we did not find our target, but ftd.best_trackdir contains the direction leading
+			to the tile closest to our target. */
+			return_track(ftd.best_trackdir);
+		}
+	} else {
+		DiagDirection dir;
+
+		if (IsTileType(desttile, MP_STREET)) {
+			if (GetRoadTileType(desttile) == ROAD_TILE_DEPOT) {
+				dir = GetRoadDepotDirection(desttile);
+				goto do_it;
+			}
+		} else if (IsTileType(desttile, MP_STATION)) {
+			if (IsRoadStop(desttile)) {
+				dir = GetRoadStopDir(desttile);
+do_it:;
+				/* When we are heading for a depot or station, we just
+				 * pretend we are heading for the tile in front, we'll
+				 * see from there */
+				desttile += TileOffsByDiagDir(dir);
+				if (desttile == tile && bitmask & _road_pf_table_3[dir]) {
+					/* If we are already in front of the
+					 * station/depot and we can get in from here,
+					 * we enter */
+					return_track(FindFirstBit2x64(bitmask & _road_pf_table_3[dir]));
+				}
+			}
+		}
+		// do pathfind
+		frd.dest = desttile;
+
+		best_track = -1;
+		best_dist = (uint)-1;
+		best_maxlen = (uint)-1;
+		i = 0;
+		do {
+			if (bitmask & 1) {
+				if (best_track == -1) best_track = i; // in case we don't find the path, just pick a track
+				frd.maxtracklen = (uint)-1;
+				frd.mindist = (uint)-1;
+				FollowTrack(tile, 0x2000 | TRANSPORT_ROAD, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
+
+				if (frd.mindist < best_dist || (frd.mindist==best_dist && frd.maxtracklen < best_maxlen)) {
+					best_dist = frd.mindist;
+					best_maxlen = frd.maxtracklen;
+					best_track = i;
+				}
+			}
+		} while (++i,(bitmask>>=1) != 0);
+	}
+
+found_best_track:;
+
+	if (HASBIT(signal, best_track)) return -1;
+
+	return best_track;
+}
+
+static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile)
+{
+	uint dist;
+	if (_patches.yapf.road_use_yapf) {
+		// use YAPF
+		dist = YapfRoadVehDistanceToTile(v, tile);
+	} else {
+		// use NPF
+		NPFFindStationOrTileData fstd;
+		byte trackdir = GetVehicleTrackdir(v);
+		assert(trackdir != 0xFF);
+
+		fstd.dest_coords = tile;
+		fstd.station_index = INVALID_STATION; // indicates that the destination is a tile, not a station
+
+		dist = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE).best_path_dist;
+		// change units from NPF_TILE_LENGTH to # of tiles
+		if (dist != UINT_MAX)
+			dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH;
+	}
+	return dist;
+}
+
+typedef struct RoadDriveEntry {
+	byte x,y;
+} RoadDriveEntry;
+
+#include "table/roadveh.h"
+
+static const byte _road_veh_data_1[] = {
+	20, 20, 16, 16, 0, 0, 0, 0,
+	19, 19, 15, 15, 0, 0, 0, 0,
+	16, 16, 12, 12, 0, 0, 0, 0,
+	15, 15, 11, 11
+};
+
+static const byte _roadveh_data_2[4] = { 0, 1, 8, 9 };
+
+static void RoadVehController(Vehicle *v)
+{
+	Direction new_dir;
+	Direction old_dir;
+	RoadDriveEntry rd;
+	int x,y;
+	uint32 r;
+
+	// decrease counters
+	v->tick_counter++;
+	if (v->u.road.reverse_ctr != 0) v->u.road.reverse_ctr--;
+
+	// handle crashed
+	if (v->u.road.crashed_ctr != 0) {
+		RoadVehIsCrashed(v);
+		return;
+	}
+
+	RoadVehCheckTrainCrash(v);
+
+	// road vehicle has broken down?
+	if (v->breakdown_ctr != 0) {
+		if (v->breakdown_ctr <= 2) {
+			HandleBrokenRoadVeh(v);
+			return;
+		}
+		v->breakdown_ctr--;
+	}
+
+	if (v->vehstatus & VS_STOPPED) return;
+
+	ProcessRoadVehOrder(v);
+	HandleRoadVehLoading(v);
+
+	if (v->current_order.type == OT_LOADING) return;
+
+	if (IsRoadVehInDepot(v)) {
+		DiagDirection dir;
+		const RoadDriveEntry* rdp;
+		byte rd2;
+
+		v->cur_speed = 0;
+
+		dir = GetRoadDepotDirection(v->tile);
+		v->direction = DiagDirToDir(dir);
+
+		rd2 = _roadveh_data_2[dir];
+		rdp = _road_drive_data[(_opt.road_side << 4) + rd2];
+
+		x = TileX(v->tile) * TILE_SIZE + (rdp[6].x & 0xF);
+		y = TileY(v->tile) * TILE_SIZE + (rdp[6].y & 0xF);
+
+		if (RoadVehFindCloseTo(v, x, y, v->direction) != NULL) return;
+
+		VehicleServiceInDepot(v);
+
+		StartRoadVehSound(v);
+
+		BeginVehicleMove(v);
+
+		v->vehstatus &= ~VS_HIDDEN;
+		v->u.road.state = rd2;
+		v->u.road.frame = 6;
+
+		v->cur_image = GetRoadVehImage(v, v->direction);
+		UpdateRoadVehDeltaXY(v);
+		SetRoadVehPosition(v,x,y);
+
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+		return;
+	}
+
+	if (!RoadVehAccelerate(v)) return;
+
+	if (v->u.road.overtaking != 0)  {
+		if (++v->u.road.overtaking_ctr >= 35)
+			/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
+			 *  if the vehicle started a corner. To protect that, only allow an abort of
+			 *  overtake if we are on straight road, which are the 8 states below */
+			if (v->u.road.state == 0  || v->u.road.state == 1  ||
+					v->u.road.state == 8  || v->u.road.state == 9  ||
+					v->u.road.state == 16 || v->u.road.state == 17 ||
+					v->u.road.state == 24 || v->u.road.state == 25) {
+				v->u.road.overtaking = 0;
+			}
+	}
+
+	BeginVehicleMove(v);
+
+	if (v->u.road.state == 255) {
+		GetNewVehiclePosResult gp;
+
+		GetNewVehiclePos(v, &gp);
+
+		if (RoadVehFindCloseTo(v, gp.x, gp.y, v->direction) != NULL) {
+			v->cur_speed = 0;
+			return;
+		}
+
+		if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
+			//new_dir = RoadGetNewDirection(v, gp.x, gp.y)
+			v->cur_image = GetRoadVehImage(v, v->direction);
+			UpdateRoadVehDeltaXY(v);
+			SetRoadVehPosition(v,gp.x,gp.y);
+			return;
+		}
+
+		v->x_pos = gp.x;
+		v->y_pos = gp.y;
+		VehiclePositionChanged(v);
+		if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
+		return;
+	}
+
+	rd = _road_drive_data[(v->u.road.state + (_opt.road_side << 4)) ^ v->u.road.overtaking][v->u.road.frame + 1];
+
+// switch to another tile
+	if (rd.x & 0x80) {
+		TileIndex tile = v->tile + TileOffsByDiagDir(rd.x & 3);
+		int dir = RoadFindPathToDest(v, tile, rd.x & 3);
+		uint32 r;
+		Direction newdir;
+		const RoadDriveEntry *rdp;
+
+		if (dir == -1) {
+			v->cur_speed = 0;
+			return;
+		}
+
+again:
+		if ((dir & 7) >= 6) {
+			/* Turning around */
+			tile = v->tile;
+		}
+
+		rdp = _road_drive_data[(dir + (_opt.road_side << 4)) ^ v->u.road.overtaking];
+
+		x = TileX(tile) * TILE_SIZE + rdp[0].x;
+		y = TileY(tile) * TILE_SIZE + rdp[0].y;
+
+		newdir = RoadVehGetSlidingDirection(v, x, y);
+		if (RoadVehFindCloseTo(v, x, y, newdir) != NULL) return;
+
+		r = VehicleEnterTile(v, tile, x, y);
+		if (r & 8) {
+			if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
+				v->cur_speed = 0;
+				return;
+			}
+			dir = _road_reverse_table[rd.x&3];
+			goto again;
+		}
+
+		if (IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30) && IsTileType(v->tile, MP_STATION)) {
+			if ((dir & 7) >= 6) {
+				v->cur_speed = 0;
+				return;
+			}
+			if (IsRoadStop(v->tile)) {
+				RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
+
+				// reached a loading bay, mark it as used and clear the usage bit
+				SETBIT(rs->status, v->u.road.state & 2 ? 1 : 0); // occupied bay
+				CLRBIT(rs->status, 7); // usage bit
+			}
+		}
+
+		if (!(r & 4)) {
+			v->tile = tile;
+			v->u.road.state = (byte)dir;
+			v->u.road.frame = 0;
+		}
+		if (newdir != v->direction) {
+			v->direction = newdir;
+			v->cur_speed -= v->cur_speed >> 2;
+		}
+
+		v->cur_image = GetRoadVehImage(v, newdir);
+		UpdateRoadVehDeltaXY(v);
+		RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
+		return;
+	}
+
+	if (rd.x & 0x40) {
+		int dir = RoadFindPathToDest(v, v->tile, rd.x & 3);
+		uint32 r;
+		int tmp;
+		Direction newdir;
+		const RoadDriveEntry *rdp;
+
+		if (dir == -1) {
+			v->cur_speed = 0;
+			return;
+		}
+
+		tmp = (_opt.road_side << 4) + dir;
+		rdp = _road_drive_data[tmp];
+
+		x = TileX(v->tile) * TILE_SIZE + rdp[1].x;
+		y = TileY(v->tile) * TILE_SIZE + rdp[1].y;
+
+		newdir = RoadVehGetSlidingDirection(v, x, y);
+		if (RoadVehFindCloseTo(v, x, y, newdir) != NULL) return;
+
+		r = VehicleEnterTile(v, v->tile, x, y);
+		if (r & 8) {
+			v->cur_speed = 0;
+			return;
+		}
+
+		v->u.road.state = tmp & ~16;
+		v->u.road.frame = 1;
+
+		if (newdir != v->direction) {
+			v->direction = newdir;
+			v->cur_speed -= v->cur_speed >> 2;
+		}
+
+		v->cur_image = GetRoadVehImage(v, newdir);
+		UpdateRoadVehDeltaXY(v);
+		RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
+		return;
+	}
+
+	x = (v->x_pos & ~15) + (rd.x & 15);
+	y = (v->y_pos & ~15) + (rd.y & 15);
+
+	new_dir = RoadVehGetSlidingDirection(v, x, y);
+
+	if (!IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30)) {
+		Vehicle* u = RoadVehFindCloseTo(v, x, y, new_dir);
+
+		if (u != NULL) {
+			if (v->u.road.overtaking == 0) RoadVehCheckOvertake(v, u);
+			return;
+		}
+	}
+
+	old_dir = v->direction;
+	if (new_dir != old_dir) {
+		v->direction = new_dir;
+		v->cur_speed -= (v->cur_speed >> 2);
+		if (old_dir != v->u.road.state) {
+			v->cur_image = GetRoadVehImage(v, new_dir);
+			UpdateRoadVehDeltaXY(v);
+			SetRoadVehPosition(v, v->x_pos, v->y_pos);
+			return;
+		}
+	}
+
+	if (v->u.road.state >= 0x20 &&
+			_road_veh_data_1[v->u.road.state - 0x20 + (_opt.road_side<<4)] == v->u.road.frame) {
+		RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
+		Station* st = GetStationByTile(v->tile);
+
+		if (v->current_order.type != OT_LEAVESTATION &&
+				v->current_order.type != OT_GOTO_DEPOT) {
+			Order old_order;
+
+			CLRBIT(rs->status, 7);
+
+			v->last_station_visited = GetStationIndex(v->tile);
+
+			RoadVehArrivesAt(v, st);
+
+			old_order = v->current_order;
+			v->current_order.type = OT_LOADING;
+			v->current_order.flags = 0;
+
+			if (old_order.type == OT_GOTO_STATION &&
+					v->current_order.dest == v->last_station_visited) {
+				v->current_order.flags =
+					(old_order.flags & (OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER)) | OF_NON_STOP;
+			}
+
+			SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC);
+			if (LoadUnloadVehicle(v, true)) {
+				InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+				MarkRoadVehDirty(v);
+			}
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			return;
+		}
+
+		if (v->current_order.type != OT_GOTO_DEPOT) {
+			if (HASBIT(rs->status, 7)) {
+				v->cur_speed = 0;
+				return;
+			}
+			v->current_order.type = OT_NOTHING;
+			v->current_order.flags = 0;
+			ClearSlot(v);
+		}
+		SETBIT(rs->status, 7);
+
+		if (rs == v->u.road.slot) {
+			//we have arrived at the correct station
+			ClearSlot(v);
+		} else if (v->u.road.slot != NULL) {
+			//we have arrived at the wrong station
+			//XXX The question is .. what to do? Actually we shouldn't be here
+			//but I guess we need to clear the slot
+			DEBUG(ms, 0, "Vehicle %d (index %d) arrived at wrong stop", v->unitnumber, v->index);
+			if (v->tile != v->dest_tile) {
+				DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
+			}
+			if (v->dest_tile != v->u.road.slot->xy) {
+				DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
+			}
+			if (v->current_order.type != OT_GOTO_STATION) {
+				DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.type);
+			} else {
+				if (v->current_order.dest != st->index)
+					DEBUG(ms, 2, " current station %d is not target station in current_order.station (%d)",
+							st->index, v->current_order.dest);
+			}
+
+			DEBUG(ms, 2, " force a slot clearing");
+			ClearSlot(v);
+		}
+
+		StartRoadVehSound(v);
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+
+	r = VehicleEnterTile(v, v->tile, x, y);
+	if (r & 8) {
+		v->cur_speed = 0;
+		return;
+	}
+
+	if ((r & 4) == 0) v->u.road.frame++;
+
+	v->cur_image = GetRoadVehImage(v, v->direction);
+	UpdateRoadVehDeltaXY(v);
+	RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
+}
+
+static void AgeRoadVehCargo(Vehicle *v)
+{
+	if (_age_cargo_skip_counter != 0) return;
+	if (v->cargo_days != 255) v->cargo_days++;
+}
+
+void RoadVeh_Tick(Vehicle *v)
+{
+	AgeRoadVehCargo(v);
+	RoadVehController(v);
+}
+
+static void CheckIfRoadVehNeedsService(Vehicle *v)
+{
+	const Depot* depot;
+
+	if (_patches.servint_roadveh == 0) return;
+	if (!VehicleNeedsService(v)) return;
+	if (v->vehstatus & VS_STOPPED) return;
+	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
+
+	// Don't interfere with a depot visit scheduled by the user, or a
+	// depot visit by the order list.
+	if (v->current_order.type == OT_GOTO_DEPOT &&
+			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
+		return;
+
+	// If we already got a slot at a stop, use that FIRST, and go to a depot later
+	if (v->u.road.slot != NULL) return;
+
+	if (IsRoadVehInDepot(v)) {
+		VehicleServiceInDepot(v);
+		return;
+	}
+
+	// XXX If we already have a depot order, WHY do we search over and over?
+	depot = FindClosestRoadDepot(v);
+
+	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
+		if (v->current_order.type == OT_GOTO_DEPOT) {
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return;
+	}
+
+	if (v->current_order.type == OT_GOTO_DEPOT &&
+			v->current_order.flags & OF_NON_STOP &&
+			!CHANCE16(1, 20)) {
+		return;
+	}
+
+	v->current_order.type = OT_GOTO_DEPOT;
+	v->current_order.flags = OF_NON_STOP;
+	v->current_order.dest = depot->index;
+	v->dest_tile = depot->xy;
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+}
+
+void OnNewDay_RoadVeh(Vehicle *v)
+{
+	int32 cost;
+
+	if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v);
+	if (v->u.road.blocked_ctr == 0) CheckVehicleBreakdown(v);
+
+	AgeVehicle(v);
+	CheckIfRoadVehNeedsService(v);
+
+	CheckOrders(v);
+
+	//Current slot has expired
+	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot != NULL && v->u.road.slot_age-- == 0) {
+		DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
+			v->unitnumber, v->index, v->u.road.slot->xy);
+		ClearSlot(v);
+	}
+
+	if (v->vehstatus & VS_STOPPED) return;
+
+	/* update destination */
+	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot == NULL && !(v->vehstatus & VS_CRASHED)) {
+		Station* st = GetStation(v->current_order.dest);
+		RoadStop* rs = GetPrimaryRoadStop(st, v->cargo_type == CT_PASSENGERS ? RS_BUS : RS_TRUCK);
+		RoadStop* best = NULL;
+
+		if (rs != NULL) {
+			if (DistanceManhattan(v->tile, st->xy) < 16) {
+				uint dist, badness;
+				uint minbadness = UINT_MAX;
+
+				DEBUG(ms, 2, "Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%X)",
+					v->unitnumber, v->index, st->index, st->xy
+				);
+				/* Now we find the nearest road stop that has a free slot */
+				for (; rs != NULL; rs = rs->next) {
+					dist = RoadFindPathToStop(v, rs->xy);
+					if (dist == UINT_MAX) {
+						DEBUG(ms, 4, " stop 0x%X is unreachable, not treating further", rs->xy);
+						continue;
+					}
+					badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist;
+
+					DEBUG(ms, 4, " stop 0x%X has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s");
+					DEBUG(ms, 4, " distance is %u", dist);
+					DEBUG(ms, 4, " badness %u", badness);
+
+					if (badness < minbadness) {
+						best = rs;
+						minbadness = badness;
+					}
+				}
+
+				if (best != NULL) {
+					best->num_vehicles++;
+					DEBUG(ms, 3, "Assigned to stop 0x%X", best->xy);
+
+					v->u.road.slot = best;
+					v->dest_tile = best->xy;
+					v->u.road.slot_age = 14;
+				} else {
+					DEBUG(ms, 3, "Could not find a suitable stop");
+				}
+			} else {
+				DEBUG(ms, 5, "Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%X)",
+						v->unitnumber, v->index, st->index, st->xy);
+			}
+		} else {
+			DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)",
+					v->unitnumber, v->index, st->index, st->xy);
+		}
+	}
+
+	cost = RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running / 364;
+
+	v->profit_this_year -= cost >> 8;
+
+	SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN);
+	SubtractMoneyFromPlayerFract(v->owner, cost);
+
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+	InvalidateWindowClasses(WC_ROADVEH_LIST);
+}
+
+
+void RoadVehiclesYearlyLoop(void)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Road) {
+			v->profit_last_year = v->profit_this_year;
+			v->profit_this_year = 0;
+			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		}
+	}
+}
+
+/** Refit a road vehicle to the specified cargo type
+ * @param tile unused
+ * @param p1 Vehicle ID of the vehicle to refit
+ * @param p2 Bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to
+ * - p2 = (bit 8-15) - the new cargo subtype to refit to
+ */
+int32 CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	int32 cost;
+	CargoID new_cid = GB(p2, 0, 8);
+	byte new_subtype = GB(p2, 8, 8);
+	uint16 capacity = CALLBACK_FAILED;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (!IsRoadVehInDepotStopped(v)) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
+
+	if (new_cid > NUM_CARGO || !CanRefitTo(v->engine_type, new_cid)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN);
+
+	if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
+		/* Back up the cargo type */
+		CargoID temp_cid = v->cargo_type;
+		byte temp_subtype = v->cargo_subtype;
+		v->cargo_type = new_cid;
+		v->cargo_subtype = new_subtype;
+
+		/* Check the refit capacity callback */
+		capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
+
+		/* Restore the original cargo type */
+		v->cargo_type = temp_cid;
+		v->cargo_subtype = temp_subtype;
+	}
+
+	if (capacity == CALLBACK_FAILED) {
+		/* callback failed or not used, use default capacity */
+		const RoadVehicleInfo *rvi = RoadVehInfo(v->engine_type);
+
+		CargoID old_cid = rvi->cargo_type;
+		/* normally, the capacity depends on the cargo type, a vehicle can
+		 * carry twice as much mail/goods as normal cargo, and four times as
+		 * many passengers
+		 */
+		capacity = rvi->capacity;
+		switch (old_cid) {
+			case CT_PASSENGERS: break;
+			case CT_MAIL:
+			case CT_GOODS: capacity *= 2; break;
+			default:       capacity *= 4; break;
+		}
+		switch (new_cid) {
+			case CT_PASSENGERS: break;
+			case CT_MAIL:
+			case CT_GOODS: capacity /= 2; break;
+			default:       capacity /= 4; break;
+		}
+	}
+	_returned_refit_capacity = capacity;
+
+	cost = 0;
+	if (IsHumanPlayer(v->owner) && new_cid != v->cargo_type) {
+		cost = GetRefitCost(v->engine_type);
+	}
+
+	if (flags & DC_EXEC) {
+		v->cargo_cap = capacity;
+		v->cargo_count = (v->cargo_type == new_cid) ? min(capacity, v->cargo_count) : 0;
+		v->cargo_type = new_cid;
+		v->cargo_subtype = new_subtype;
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+	}
+
+	return cost;
+}
deleted file mode 100644
--- a/src/roadveh_gui.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "roadveh.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "station.h"
-#include "command.h"
-#include "player.h"
-#include "engine.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "newgrf_engine.h"
-#include "date.h"
-
-/**
- * Draw the purchase info details of road vehicle at a given location.
- * @param x,y location where to draw the info
- * @param engine_number the engine of which to draw the info of
- */
-void DrawRoadVehPurchaseInfo(int x, int y, uint w, EngineID engine_number)
-{
-	const RoadVehicleInfo *rvi = RoadVehInfo(engine_number);
-	const Engine *e = GetEngine(engine_number);
-	bool refittable = (_engine_info[engine_number].refit_mask != 0);
-	YearMonthDay ymd;
-	ConvertDateToYMD(e->intro_date, &ymd);
-
-	/* Purchase cost - Max speed */
-	SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5);
-	SetDParam(1, rvi->max_speed / 2);
-	DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
-	y += 10;
-
-	/* Running cost */
-	SetDParam(0, rvi->running_cost * _price.roadveh_running >> 8);
-	DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
-	y += 10;
-
-	/* Cargo type + capacity */
-	SetDParam(0, rvi->cargo_type);
-	SetDParam(1, rvi->capacity);
-	SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
-	DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
-	y += 10;
-
-	/* Design date - Life length */
-	SetDParam(0, ymd.year);
-	SetDParam(1, e->lifelength);
-	DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
-	y += 10;
-
-	/* Reliability */
-	SetDParam(0, e->reliability * 100 >> 16);
-	DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
-	y += 10;
-
-	/* Additional text from NewGRF */
-	y += ShowAdditionalText(x, y, w, engine_number);
-	y += ShowRefitOptionsList(x, y, w, engine_number);
-}
-
-void DrawRoadVehImage(const Vehicle *v, int x, int y, VehicleID selection)
-{
-	PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-	DrawSprite(GetRoadVehImage(v, DIR_W) | pal, x + 14, y + 6);
-
-	if (v->index == selection) {
-		DrawFrameRect(x - 1, y - 1, x + 28, y + 12, 15, FR_BORDERONLY);
-	}
-}
-
-static void RoadVehDetailsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		StringID str;
-
-		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
-		// disable service-scroller when interval is set to disabled
-		SetWindowWidgetDisabledState(w, 5, !_patches.servint_roadveh);
-		SetWindowWidgetDisabledState(w, 6, !_patches.servint_roadveh);
-
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		/* Draw running cost */
-		{
-			int year = v->age / 366;
-
-			SetDParam(1, year);
-
-			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
-			SetDParam(2, v->max_age / 366);
-			SetDParam(3, RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running >> 8);
-			DrawString(2, 15, STR_900D_AGE_RUNNING_COST_YR, 0);
-		}
-
-		/* Draw max speed */
-		{
-			SetDParam(0, v->max_speed / 2);
-			DrawString(2, 25, STR_900E_MAX_SPEED, 0);
-		}
-
-		/* Draw profit */
-		{
-			SetDParam(0, v->profit_this_year);
-			SetDParam(1, v->profit_last_year);
-			DrawString(2, 35, STR_900F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
-		}
-
-		/* Draw breakdown & reliability */
-		{
-			SetDParam(0, v->reliability * 100 >> 16);
-			SetDParam(1, v->breakdowns_since_last_service);
-			DrawString(2, 45, STR_9010_RELIABILITY_BREAKDOWNS, 0);
-		}
-
-		/* Draw service interval text */
-		{
-			SetDParam(0, v->service_interval);
-			SetDParam(1, v->date_of_last_service);
-			DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
-		}
-
-		DrawRoadVehImage(v, 3, 57, INVALID_VEHICLE);
-
-		SetDParam(0, GetCustomEngineName(v->engine_type));
-		SetDParam(1, v->build_year);
-		SetDParam(2, v->value);
-		DrawString(34, 57, STR_9011_BUILT_VALUE, 0);
-
-		SetDParam(0, v->cargo_type);
-		SetDParam(1, v->cargo_cap);
-		DrawString(34, 67, STR_9012_CAPACITY, 0);
-
-		str = STR_8812_EMPTY;
-		if (v->cargo_count != 0) {
-			SetDParam(0, v->cargo_type);
-			SetDParam(1, v->cargo_count);
-			SetDParam(2, v->cargo_source);
-			str = STR_8813_FROM;
-		}
-		DrawString(34, 78, str, 0);
-	} break;
-
-	case WE_CLICK: {
-		int mod;
-		const Vehicle *v;
-		switch (e->we.click.widget) {
-		case 2: /* rename */
-			v = GetVehicle(w->window_number);
-			SetDParam(0, v->unitnumber);
-			ShowQueryString(v->string_id, STR_902C_NAME_ROAD_VEHICLE, 31, 150, w, CS_ALPHANUMERAL);
-			break;
-
-		case 5: /* increase int */
-			mod = _ctrl_pressed? 5 : 10;
-			goto do_change_service_int;
-		case 6: /* decrease int */
-			mod = _ctrl_pressed? -5 : -10;
-do_change_service_int:
-			v = GetVehicle(w->window_number);
-
-			mod = GetServiceIntervalClamped(mod + v->service_interval);
-			if (mod == v->service_interval) return;
-
-			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
-			break;
-		}
-	} break;
-
-	case WE_ON_EDIT_TEXT: {
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_NAME_VEHICLE | CMD_MSG(STR_902D_CAN_T_NAME_ROAD_VEHICLE));
-		}
-	} break;
-
-	}
-}
-
-static const Widget _roadveh_details_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   339,     0,    13, STR_900C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   340,   379,     0,    13, STR_01AA_NAME,    STR_902E_NAME_ROAD_VEHICLE},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   379,    14,    55, 0x0,              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   379,    56,    88, 0x0,              STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    89,    94, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    95,   100, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    11,   379,    89,   100, 0x0,              STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _roadveh_details_desc = {
-	WDP_AUTO, WDP_AUTO, 380, 101,
-	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_roadveh_details_widgets,
-	RoadVehDetailsWndProc
-};
-
-static void ShowRoadVehDetailsWindow(const Vehicle *v)
-{
-	Window *w;
-	VehicleID veh = v->index;
-
-	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
-	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
-
-	w = AllocateWindowDescFront(&_roadveh_details_desc, veh);
-	w->caption_color = v->owner;
-}
-
-void CcCloneRoadVeh(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) ShowRoadVehViewWindow(GetVehicle(_new_vehicle_id));
-}
-
-static void RoadVehViewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		Vehicle *v = GetVehicle(w->window_number);
-		StringID str;
-		bool is_localplayer = v->owner == _local_player;
-
-		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
-		SetWindowWidgetDisabledState(w,  8, !is_localplayer);
-		SetWindowWidgetDisabledState(w, 11, !is_localplayer);
-		/* Disable refit button if vehicle not refittable */
-		SetWindowWidgetDisabledState(w, 12, !is_localplayer ||
-				_engine_info[v->engine_type].refit_mask == 0);
-
-		/* draw widgets & caption */
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		if (v->u.road.crashed_ctr != 0) {
-			str = STR_8863_CRASHED;
-		} else if (v->breakdown_ctr == 1) {
-			str = STR_885C_BROKEN_DOWN;
-		} else if (v->vehstatus & VS_STOPPED) {
-			str = STR_8861_STOPPED;
-		} else {
-			switch (v->current_order.type) {
-			case OT_GOTO_STATION: {
-				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->cur_speed / 2);
-				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
-			} break;
-
-			case OT_GOTO_DEPOT: {
-				Depot *depot = GetDepot(v->current_order.dest);
-				SetDParam(0, depot->town_index);
-				SetDParam(1, v->cur_speed / 2);
-				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-					str = STR_HEADING_FOR_ROAD_DEPOT + _patches.vehicle_speed;
-				} else {
-					str = STR_HEADING_FOR_ROAD_DEPOT_SERVICE + _patches.vehicle_speed;
-				}
-			} break;
-
-			case OT_LOADING:
-			case OT_LEAVESTATION:
-				str = STR_882F_LOADING_UNLOADING;
-				break;
-
-			default:
-				if (v->num_orders == 0) {
-					str = STR_NO_ORDERS + _patches.vehicle_speed;
-					SetDParam(0, v->cur_speed / 2);
-				} else {
-					str = STR_EMPTY;
-				}
-				break;
-			}
-		}
-
-		/* draw the flag plus orders */
-		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
-		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
-		DrawWindowViewport(w);
-	} break;
-
-	case WE_CLICK: {
-		const Vehicle *v = GetVehicle(w->window_number);
-
-		switch (e->we.click.widget) {
-		case 5: /* start stop */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE));
-			break;
-		case 6: /* center main view */
-			ScrollMainWindowTo(v->x_pos, v->y_pos);
-			break;
-		case 7: /* goto depot */
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_ROADVEH_TO_DEPOT | CMD_MSG(STR_9018_CAN_T_SEND_VEHICLE_TO_DEPOT));
-			break;
-		case 8: /* turn around */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_TURN_ROADVEH | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
-			break;
-		case 9: /* show orders */
-			ShowOrdersWindow(v);
-			break;
-		case 10: /* show details */
-			ShowRoadVehDetailsWindow(v);
-			break;
-		case 11: /* clone vehicle */
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneRoadVeh, CMD_CLONE_VEHICLE | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
-			break;
-		case 12: /* Refit vehicle */
-			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
-			break;
-		}
-	} break;
-
-	case WE_RESIZE:
-		w->viewport->width          += e->we.sizing.diff.x;
-		w->viewport->height         += e->we.sizing.diff.y;
-		w->viewport->virtual_width  += e->we.sizing.diff.x;
-		w->viewport->virtual_height += e->we.sizing.diff.y;
-		break;
-
-	case WE_DESTROY:
-		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
-		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
-		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
-		break;
-
-	case WE_MOUSELOOP: {
-			const Vehicle *v = GetVehicle(w->window_number);
-			bool rv_stopped = IsRoadVehInDepotStopped(v);
-
-			/* Widget 7 (send to depot) must be hidden if the truck/bus is already stopped in depot.
-			 * Widget 11 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
-			 * This sytem allows to have two buttons, on top of each other.
-			 * The same system applies to widget 8 and 12, force turn around and refit. */
-			if (rv_stopped != IsWindowWidgetHidden(w, 7) || rv_stopped == IsWindowWidgetHidden(w, 11)) {
-				SetWindowWidgetHiddenState(w,  7, rv_stopped);  // send to depot
-				SetWindowWidgetHiddenState(w,  8, rv_stopped);  // force turn around
-				SetWindowWidgetHiddenState(w, 11, !rv_stopped); // clone
-				SetWindowWidgetHiddenState(w, 12, !rv_stopped); // refit
-				SetWindowDirty(w);
-			}
-		}
-	}
-}
-
-static const Widget _roadveh_view_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_9002,                STR_018C_WINDOW_TITLE_DRAG_THIS },
-{  WWT_STICKYBOX, RESIZE_LR,    14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON },
-{      WWT_PANEL, RESIZE_RB,    14,   0, 231,  14, 103, 0x0,                     STR_NULL },
-{      WWT_INSET, RESIZE_RB,    14,   2, 229,  16, 101, 0x0,                     STR_NULL },
-{    WWT_PUSHBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,                     STR_901C_CURRENT_VEHICLE_ACTION },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_SEND_ROADVEH_TODEPOT,STR_901F_SEND_VEHICLE_TO_DEPOT },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_FORCE_VEHICLE_TURN,  STR_9020_FORCE_VEHICLE_TO_TURN_AROUND },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, SPR_SHOW_ORDERS,         STR_901D_SHOW_VEHICLE_S_ORDERS },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS,STR_9021_SHOW_ROAD_VEHICLE_DETAILS },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_ROADVEH,       STR_CLONE_ROAD_VEHICLE_INFO },
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,       STR_REFIT_ROAD_VEHICLE_TO_CARRY },
-{      WWT_PANEL, RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,                     STR_NULL },
-{  WWT_RESIZEBOX, RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                     STR_NULL },
-{ WIDGETS_END }
-};
-
-static const WindowDesc _roadveh_view_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 116,
-	WC_VEHICLE_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_roadveh_view_widgets,
-	RoadVehViewWndProc,
-};
-
-void ShowRoadVehViewWindow(const Vehicle *v)
-{
-	Window *w = AllocateWindowDescFront(&_roadveh_view_desc, v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
-	}
-}
-
-
-static void DrawNewRoadVehWindow(Window *w)
-{
-	EngineID selected_id;
-	EngineID e;
-	uint count;
-	int pos;
-	int sel;
-	int y;
-
-	SetWindowWidgetDisabledState(w, 5, w->window_number == 0);
-
-	count = 0;
-	for (e = ROAD_ENGINES_INDEX; e < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; e++) {
-		if (HASBIT(GetEngine(e)->player_avail, _local_player)) count++;
-	}
-	SetVScrollCount(w, count);
-
-	DrawWindowWidgets(w);
-
-	y = 15;
-	sel = WP(w,buildvehicle_d).sel_index;
-	pos = w->vscroll.pos;
-	selected_id = INVALID_ENGINE;
-	for (e = ROAD_ENGINES_INDEX; e < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; e++) {
-		if (!HASBIT(GetEngine(e)->player_avail, _local_player)) continue;
-		if (sel == 0) selected_id = e;
-		if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
-			DrawString(60, y + 2, GetCustomEngineName(e), sel == 0 ? 0xC : 0x10);
-			DrawRoadVehEngine(30, y + 6, e, GetEnginePalette(e, _local_player));
-			y += 14;
-		}
-		sel--;
-	}
-
-	WP(w,buildvehicle_d).sel_engine = selected_id;
-	if (selected_id != INVALID_ENGINE) {
-		const Widget *wi = &w->widget[4];
-		DrawRoadVehPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
-	}
-}
-
-void CcBuildRoadVeh(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	const Vehicle *v;
-
-	if (!success) return;
-
-	v = GetVehicle(_new_vehicle_id);
-	if (v->tile == _backup_orders_tile) {
-		_backup_orders_tile = 0;
-		RestoreVehicleOrders(v, _backup_orders_data);
-	}
-	ShowRoadVehViewWindow(v);
-}
-
-static void NewRoadVehWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawNewRoadVehWindow(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: { /* listbox */
-			uint i = (e->we.click.pt.y - 14) / 14;
-			if (i < w->vscroll.cap) {
-				WP(w,buildvehicle_d).sel_index = i + w->vscroll.pos;
-				SetWindowDirty(w);
-			}
-		} break;
-
-		case 5: { /* build */
-			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
-			if (sel_eng != INVALID_ENGINE)
-				DoCommandP(w->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
-		} break;
-
-		case 6: { /* rename */
-			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				WP(w,buildvehicle_d).rename_engine = sel_eng;
-				ShowQueryString(GetCustomEngineName(sel_eng), STR_9036_RENAME_ROAD_VEHICLE_TYPE, 31, 160, w, CS_ALPHANUMERAL);
-			}
-		}	break;
-		}
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, WP(w, buildvehicle_d).rename_engine, 0, NULL,
-				CMD_RENAME_ENGINE | CMD_MSG(STR_9037_CAN_T_RENAME_ROAD_VEHICLE));
-		}
-		break;
-
-	case WE_RESIZE: {
-		if (e->we.sizing.diff.y == 0) break;
-
-		w->vscroll.cap += e->we.sizing.diff.y / 14;
-		w->widget[2].data = (w->vscroll.cap << 8) + 1;
-	} break;
-
-	}
-}
-
-static const Widget _new_road_veh_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   247,     0,    13, STR_9006_NEW_ROAD_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   235,    14,   125, 0x801,                      STR_9026_ROAD_VEHICLE_SELECTION},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   236,   247,    14,   125, 0x0,                        STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    14,     0,   247,   126,   217, 0x0,                        STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   117,   218,   229, STR_9007_BUILD_VEHICLE,     STR_9027_BUILD_THE_HIGHLIGHTED_ROAD},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   118,   235,   218,   229, STR_9034_RENAME,            STR_9035_RENAME_ROAD_VEHICLE_TYPE},
-{  WWT_RESIZEBOX,     RESIZE_TB,    14,   236,   247,   218,   229, 0x0,                        STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _new_road_veh_desc = {
-	WDP_AUTO, WDP_AUTO, 248, 230,
-	WC_BUILD_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_new_road_veh_widgets,
-	NewRoadVehWndProc
-};
-
-void ShowBuildRoadVehWindow(TileIndex tile)
-{
-	Window *w;
-
-	DeleteWindowById(WC_BUILD_VEHICLE, tile);
-
-	w = AllocateWindowDescFront(&_new_road_veh_desc, tile);
-	w->vscroll.cap = 8;
-	w->widget[2].data = (w->vscroll.cap << 8) + 1;
-
-	w->resize.step_height = 14;
-	w->resize.height = w->height - 14 * 4; /* Minimum of 4 vehicles in the display */
-
-	if (tile != 0) {
-		w->caption_color = GetTileOwner(tile);
-	} else {
-		w->caption_color = _local_player;
-	}
-}
-
-
new file mode 100644
--- /dev/null
+++ b/src/roadveh_gui.cpp
@@ -0,0 +1,546 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "roadveh.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "station.h"
+#include "command.h"
+#include "player.h"
+#include "engine.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "newgrf_engine.h"
+#include "date.h"
+
+/**
+ * Draw the purchase info details of road vehicle at a given location.
+ * @param x,y location where to draw the info
+ * @param engine_number the engine of which to draw the info of
+ */
+void DrawRoadVehPurchaseInfo(int x, int y, uint w, EngineID engine_number)
+{
+	const RoadVehicleInfo *rvi = RoadVehInfo(engine_number);
+	const Engine *e = GetEngine(engine_number);
+	bool refittable = (_engine_info[engine_number].refit_mask != 0);
+	YearMonthDay ymd;
+	ConvertDateToYMD(e->intro_date, &ymd);
+
+	/* Purchase cost - Max speed */
+	SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5);
+	SetDParam(1, rvi->max_speed / 2);
+	DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
+	y += 10;
+
+	/* Running cost */
+	SetDParam(0, rvi->running_cost * _price.roadveh_running >> 8);
+	DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
+	y += 10;
+
+	/* Cargo type + capacity */
+	SetDParam(0, rvi->cargo_type);
+	SetDParam(1, rvi->capacity);
+	SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
+	DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
+	y += 10;
+
+	/* Design date - Life length */
+	SetDParam(0, ymd.year);
+	SetDParam(1, e->lifelength);
+	DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
+	y += 10;
+
+	/* Reliability */
+	SetDParam(0, e->reliability * 100 >> 16);
+	DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
+	y += 10;
+
+	/* Additional text from NewGRF */
+	y += ShowAdditionalText(x, y, w, engine_number);
+	y += ShowRefitOptionsList(x, y, w, engine_number);
+}
+
+void DrawRoadVehImage(const Vehicle *v, int x, int y, VehicleID selection)
+{
+	PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
+	DrawSprite(GetRoadVehImage(v, DIR_W) | pal, x + 14, y + 6);
+
+	if (v->index == selection) {
+		DrawFrameRect(x - 1, y - 1, x + 28, y + 12, 15, FR_BORDERONLY);
+	}
+}
+
+static void RoadVehDetailsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		StringID str;
+
+		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
+		// disable service-scroller when interval is set to disabled
+		SetWindowWidgetDisabledState(w, 5, !_patches.servint_roadveh);
+		SetWindowWidgetDisabledState(w, 6, !_patches.servint_roadveh);
+
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		/* Draw running cost */
+		{
+			int year = v->age / 366;
+
+			SetDParam(1, year);
+
+			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+			SetDParam(2, v->max_age / 366);
+			SetDParam(3, RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running >> 8);
+			DrawString(2, 15, STR_900D_AGE_RUNNING_COST_YR, 0);
+		}
+
+		/* Draw max speed */
+		{
+			SetDParam(0, v->max_speed / 2);
+			DrawString(2, 25, STR_900E_MAX_SPEED, 0);
+		}
+
+		/* Draw profit */
+		{
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(2, 35, STR_900F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+		}
+
+		/* Draw breakdown & reliability */
+		{
+			SetDParam(0, v->reliability * 100 >> 16);
+			SetDParam(1, v->breakdowns_since_last_service);
+			DrawString(2, 45, STR_9010_RELIABILITY_BREAKDOWNS, 0);
+		}
+
+		/* Draw service interval text */
+		{
+			SetDParam(0, v->service_interval);
+			SetDParam(1, v->date_of_last_service);
+			DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
+		}
+
+		DrawRoadVehImage(v, 3, 57, INVALID_VEHICLE);
+
+		SetDParam(0, GetCustomEngineName(v->engine_type));
+		SetDParam(1, v->build_year);
+		SetDParam(2, v->value);
+		DrawString(34, 57, STR_9011_BUILT_VALUE, 0);
+
+		SetDParam(0, v->cargo_type);
+		SetDParam(1, v->cargo_cap);
+		DrawString(34, 67, STR_9012_CAPACITY, 0);
+
+		str = STR_8812_EMPTY;
+		if (v->cargo_count != 0) {
+			SetDParam(0, v->cargo_type);
+			SetDParam(1, v->cargo_count);
+			SetDParam(2, v->cargo_source);
+			str = STR_8813_FROM;
+		}
+		DrawString(34, 78, str, 0);
+	} break;
+
+	case WE_CLICK: {
+		int mod;
+		const Vehicle *v;
+		switch (e->we.click.widget) {
+		case 2: /* rename */
+			v = GetVehicle(w->window_number);
+			SetDParam(0, v->unitnumber);
+			ShowQueryString(v->string_id, STR_902C_NAME_ROAD_VEHICLE, 31, 150, w, CS_ALPHANUMERAL);
+			break;
+
+		case 5: /* increase int */
+			mod = _ctrl_pressed? 5 : 10;
+			goto do_change_service_int;
+		case 6: /* decrease int */
+			mod = _ctrl_pressed? -5 : -10;
+do_change_service_int:
+			v = GetVehicle(w->window_number);
+
+			mod = GetServiceIntervalClamped(mod + v->service_interval);
+			if (mod == v->service_interval) return;
+
+			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+			break;
+		}
+	} break;
+
+	case WE_ON_EDIT_TEXT: {
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_NAME_VEHICLE | CMD_MSG(STR_902D_CAN_T_NAME_ROAD_VEHICLE));
+		}
+	} break;
+
+	}
+}
+
+static const Widget _roadveh_details_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   339,     0,    13, STR_900C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   340,   379,     0,    13, STR_01AA_NAME,    STR_902E_NAME_ROAD_VEHICLE},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   379,    14,    55, 0x0,              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   379,    56,    88, 0x0,              STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    89,    94, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    95,   100, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    11,   379,    89,   100, 0x0,              STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _roadveh_details_desc = {
+	WDP_AUTO, WDP_AUTO, 380, 101,
+	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_roadveh_details_widgets,
+	RoadVehDetailsWndProc
+};
+
+static void ShowRoadVehDetailsWindow(const Vehicle *v)
+{
+	Window *w;
+	VehicleID veh = v->index;
+
+	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
+	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
+
+	w = AllocateWindowDescFront(&_roadveh_details_desc, veh);
+	w->caption_color = v->owner;
+}
+
+void CcCloneRoadVeh(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) ShowRoadVehViewWindow(GetVehicle(_new_vehicle_id));
+}
+
+static void RoadVehViewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		Vehicle *v = GetVehicle(w->window_number);
+		StringID str;
+		bool is_localplayer = v->owner == _local_player;
+
+		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
+		SetWindowWidgetDisabledState(w,  8, !is_localplayer);
+		SetWindowWidgetDisabledState(w, 11, !is_localplayer);
+		/* Disable refit button if vehicle not refittable */
+		SetWindowWidgetDisabledState(w, 12, !is_localplayer ||
+				_engine_info[v->engine_type].refit_mask == 0);
+
+		/* draw widgets & caption */
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		if (v->u.road.crashed_ctr != 0) {
+			str = STR_8863_CRASHED;
+		} else if (v->breakdown_ctr == 1) {
+			str = STR_885C_BROKEN_DOWN;
+		} else if (v->vehstatus & VS_STOPPED) {
+			str = STR_8861_STOPPED;
+		} else {
+			switch (v->current_order.type) {
+			case OT_GOTO_STATION: {
+				SetDParam(0, v->current_order.dest);
+				SetDParam(1, v->cur_speed / 2);
+				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+			} break;
+
+			case OT_GOTO_DEPOT: {
+				Depot *depot = GetDepot(v->current_order.dest);
+				SetDParam(0, depot->town_index);
+				SetDParam(1, v->cur_speed / 2);
+				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
+					str = STR_HEADING_FOR_ROAD_DEPOT + _patches.vehicle_speed;
+				} else {
+					str = STR_HEADING_FOR_ROAD_DEPOT_SERVICE + _patches.vehicle_speed;
+				}
+			} break;
+
+			case OT_LOADING:
+			case OT_LEAVESTATION:
+				str = STR_882F_LOADING_UNLOADING;
+				break;
+
+			default:
+				if (v->num_orders == 0) {
+					str = STR_NO_ORDERS + _patches.vehicle_speed;
+					SetDParam(0, v->cur_speed / 2);
+				} else {
+					str = STR_EMPTY;
+				}
+				break;
+			}
+		}
+
+		/* draw the flag plus orders */
+		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
+		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
+		DrawWindowViewport(w);
+	} break;
+
+	case WE_CLICK: {
+		const Vehicle *v = GetVehicle(w->window_number);
+
+		switch (e->we.click.widget) {
+		case 5: /* start stop */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE));
+			break;
+		case 6: /* center main view */
+			ScrollMainWindowTo(v->x_pos, v->y_pos);
+			break;
+		case 7: /* goto depot */
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_ROADVEH_TO_DEPOT | CMD_MSG(STR_9018_CAN_T_SEND_VEHICLE_TO_DEPOT));
+			break;
+		case 8: /* turn around */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_TURN_ROADVEH | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
+			break;
+		case 9: /* show orders */
+			ShowOrdersWindow(v);
+			break;
+		case 10: /* show details */
+			ShowRoadVehDetailsWindow(v);
+			break;
+		case 11: /* clone vehicle */
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneRoadVeh, CMD_CLONE_VEHICLE | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
+			break;
+		case 12: /* Refit vehicle */
+			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+			break;
+		}
+	} break;
+
+	case WE_RESIZE:
+		w->viewport->width          += e->we.sizing.diff.x;
+		w->viewport->height         += e->we.sizing.diff.y;
+		w->viewport->virtual_width  += e->we.sizing.diff.x;
+		w->viewport->virtual_height += e->we.sizing.diff.y;
+		break;
+
+	case WE_DESTROY:
+		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
+		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
+		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
+		break;
+
+	case WE_MOUSELOOP: {
+			const Vehicle *v = GetVehicle(w->window_number);
+			bool rv_stopped = IsRoadVehInDepotStopped(v);
+
+			/* Widget 7 (send to depot) must be hidden if the truck/bus is already stopped in depot.
+			 * Widget 11 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
+			 * This sytem allows to have two buttons, on top of each other.
+			 * The same system applies to widget 8 and 12, force turn around and refit. */
+			if (rv_stopped != IsWindowWidgetHidden(w, 7) || rv_stopped == IsWindowWidgetHidden(w, 11)) {
+				SetWindowWidgetHiddenState(w,  7, rv_stopped);  // send to depot
+				SetWindowWidgetHiddenState(w,  8, rv_stopped);  // force turn around
+				SetWindowWidgetHiddenState(w, 11, !rv_stopped); // clone
+				SetWindowWidgetHiddenState(w, 12, !rv_stopped); // refit
+				SetWindowDirty(w);
+			}
+		}
+	}
+}
+
+static const Widget _roadveh_view_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_9002,                STR_018C_WINDOW_TITLE_DRAG_THIS },
+{  WWT_STICKYBOX, RESIZE_LR,    14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON },
+{      WWT_PANEL, RESIZE_RB,    14,   0, 231,  14, 103, 0x0,                     STR_NULL },
+{      WWT_INSET, RESIZE_RB,    14,   2, 229,  16, 101, 0x0,                     STR_NULL },
+{    WWT_PUSHBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,                     STR_901C_CURRENT_VEHICLE_ACTION },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_SEND_ROADVEH_TODEPOT,STR_901F_SEND_VEHICLE_TO_DEPOT },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_FORCE_VEHICLE_TURN,  STR_9020_FORCE_VEHICLE_TO_TURN_AROUND },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, SPR_SHOW_ORDERS,         STR_901D_SHOW_VEHICLE_S_ORDERS },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS,STR_9021_SHOW_ROAD_VEHICLE_DETAILS },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_ROADVEH,       STR_CLONE_ROAD_VEHICLE_INFO },
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,       STR_REFIT_ROAD_VEHICLE_TO_CARRY },
+{      WWT_PANEL, RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,                     STR_NULL },
+{  WWT_RESIZEBOX, RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                     STR_NULL },
+{ WIDGETS_END }
+};
+
+static const WindowDesc _roadveh_view_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 116,
+	WC_VEHICLE_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_roadveh_view_widgets,
+	RoadVehViewWndProc,
+};
+
+void ShowRoadVehViewWindow(const Vehicle *v)
+{
+	Window *w = AllocateWindowDescFront(&_roadveh_view_desc, v->index);
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
+	}
+}
+
+
+static void DrawNewRoadVehWindow(Window *w)
+{
+	EngineID selected_id;
+	EngineID e;
+	uint count;
+	int pos;
+	int sel;
+	int y;
+
+	SetWindowWidgetDisabledState(w, 5, w->window_number == 0);
+
+	count = 0;
+	for (e = ROAD_ENGINES_INDEX; e < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; e++) {
+		if (HASBIT(GetEngine(e)->player_avail, _local_player)) count++;
+	}
+	SetVScrollCount(w, count);
+
+	DrawWindowWidgets(w);
+
+	y = 15;
+	sel = WP(w,buildvehicle_d).sel_index;
+	pos = w->vscroll.pos;
+	selected_id = INVALID_ENGINE;
+	for (e = ROAD_ENGINES_INDEX; e < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; e++) {
+		if (!HASBIT(GetEngine(e)->player_avail, _local_player)) continue;
+		if (sel == 0) selected_id = e;
+		if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
+			DrawString(60, y + 2, GetCustomEngineName(e), sel == 0 ? 0xC : 0x10);
+			DrawRoadVehEngine(30, y + 6, e, GetEnginePalette(e, _local_player));
+			y += 14;
+		}
+		sel--;
+	}
+
+	WP(w,buildvehicle_d).sel_engine = selected_id;
+	if (selected_id != INVALID_ENGINE) {
+		const Widget *wi = &w->widget[4];
+		DrawRoadVehPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
+	}
+}
+
+void CcBuildRoadVeh(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	const Vehicle *v;
+
+	if (!success) return;
+
+	v = GetVehicle(_new_vehicle_id);
+	if (v->tile == _backup_orders_tile) {
+		_backup_orders_tile = 0;
+		RestoreVehicleOrders(v, _backup_orders_data);
+	}
+	ShowRoadVehViewWindow(v);
+}
+
+static void NewRoadVehWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawNewRoadVehWindow(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: { /* listbox */
+			uint i = (e->we.click.pt.y - 14) / 14;
+			if (i < w->vscroll.cap) {
+				WP(w,buildvehicle_d).sel_index = i + w->vscroll.pos;
+				SetWindowDirty(w);
+			}
+		} break;
+
+		case 5: { /* build */
+			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
+			if (sel_eng != INVALID_ENGINE)
+				DoCommandP(w->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
+		} break;
+
+		case 6: { /* rename */
+			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
+			if (sel_eng != INVALID_ENGINE) {
+				WP(w,buildvehicle_d).rename_engine = sel_eng;
+				ShowQueryString(GetCustomEngineName(sel_eng), STR_9036_RENAME_ROAD_VEHICLE_TYPE, 31, 160, w, CS_ALPHANUMERAL);
+			}
+		}	break;
+		}
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, WP(w, buildvehicle_d).rename_engine, 0, NULL,
+				CMD_RENAME_ENGINE | CMD_MSG(STR_9037_CAN_T_RENAME_ROAD_VEHICLE));
+		}
+		break;
+
+	case WE_RESIZE: {
+		if (e->we.sizing.diff.y == 0) break;
+
+		w->vscroll.cap += e->we.sizing.diff.y / 14;
+		w->widget[2].data = (w->vscroll.cap << 8) + 1;
+	} break;
+
+	}
+}
+
+static const Widget _new_road_veh_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   247,     0,    13, STR_9006_NEW_ROAD_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   235,    14,   125, 0x801,                      STR_9026_ROAD_VEHICLE_SELECTION},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   236,   247,    14,   125, 0x0,                        STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    14,     0,   247,   126,   217, 0x0,                        STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   117,   218,   229, STR_9007_BUILD_VEHICLE,     STR_9027_BUILD_THE_HIGHLIGHTED_ROAD},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   118,   235,   218,   229, STR_9034_RENAME,            STR_9035_RENAME_ROAD_VEHICLE_TYPE},
+{  WWT_RESIZEBOX,     RESIZE_TB,    14,   236,   247,   218,   229, 0x0,                        STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _new_road_veh_desc = {
+	WDP_AUTO, WDP_AUTO, 248, 230,
+	WC_BUILD_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_new_road_veh_widgets,
+	NewRoadVehWndProc
+};
+
+void ShowBuildRoadVehWindow(TileIndex tile)
+{
+	Window *w;
+
+	DeleteWindowById(WC_BUILD_VEHICLE, tile);
+
+	w = AllocateWindowDescFront(&_new_road_veh_desc, tile);
+	w->vscroll.cap = 8;
+	w->widget[2].data = (w->vscroll.cap << 8) + 1;
+
+	w->resize.step_height = 14;
+	w->resize.height = w->height - 14 * 4; /* Minimum of 4 vehicles in the display */
+
+	if (tile != 0) {
+		w->caption_color = GetTileOwner(tile);
+	} else {
+		w->caption_color = _local_player;
+	}
+}
+
+
deleted file mode 100644
--- a/src/saveload.c
+++ /dev/null
@@ -1,1686 +0,0 @@
-/* $Id$ */
-
-/** @file
- * All actions handling saving and loading goes on in this file. The general actions
- * are as follows for saving a game (loading is analogous):
- * <ol>
- * <li>initialize the writer by creating a temporary memory-buffer for it
- * <li>go through all to-be saved elements, each 'chunk' (ChunkHandler) prefixed by a label
- * <li>use their description array (SaveLoad) to know what elements to save and in what version
- *    of the game it was active (used when loading)
- * <li>write all data byte-by-byte to the temporary buffer so it is endian-safe
- * <li>when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe)
- * <li>repeat this until everything is done, and flush any remaining output to file
- * </ol>
- * @see ChunkHandler
- * @see SaveLoad
- */
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "hal.h"
-#include "vehicle.h"
-#include "station.h"
-#include "thread.h"
-#include "town.h"
-#include "player.h"
-#include "saveload.h"
-#include "network/network.h"
-#include "variables.h"
-#include <setjmp.h>
-
-const uint16 SAVEGAME_VERSION = 43;
-uint16 _sl_version;       /// the major savegame version identifier
-byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
-
-typedef void WriterProc(uint len);
-typedef uint ReaderProc(void);
-
-/** The saveload struct, containing reader-writer functions, bufffer, version, etc. */
-static struct {
-	bool save;                           /// are we doing a save or a load atm. True when saving
-	byte need_length;                    /// ???
-	byte block_mode;                     /// ???
-	bool error;                          /// did an error occur or not
-
-	int obj_len;                         /// the length of the current object we are busy with
-	int array_index, last_array_index;   /// in the case of an array, the current and last positions
-
-	uint32 offs_base;                    /// the offset in number of bytes since we started writing data (eg uncompressed savegame size)
-
-	WriterProc *write_bytes;             /// savegame writer function
-	ReaderProc *read_bytes;              /// savegame loader function
-
-	const ChunkHandler* const *chs;      /// the chunk of data that is being processed atm (vehicles, signs, etc.)
-	const SaveLoad* const *includes;     /// the internal layouf of the given chunk
-
-	/** When saving/loading savegames, they are always saved to a temporary memory-place
-	 * to be flushed to file (save) or to final place (load) when full. */
-	byte *bufp, *bufe;                   /// bufp(ointer) gives the current position in the buffer bufe(nd) gives the end of the buffer
-
-	// these 3 may be used by compressor/decompressors.
-	byte *buf;                           /// pointer to temporary memory to read/write, initialized by SaveLoadFormat->initread/write
-	byte *buf_ori;                       /// pointer to the original memory location of buf, used to free it afterwards
-	uint bufsize;                        /// the size of the temporary memory *buf
-	FILE *fh;                            /// the file from which is read or written to
-
-	void (*excpt_uninit)(void);          /// the function to execute on any encountered error
-	const char *excpt_msg;               /// the error message
-	jmp_buf excpt;                       /// @todo used to jump to "exception handler";  really ugly
-} _sl;
-
-
-enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
-
-/**
- * Fill the input buffer by reading from the file with the given reader
- */
-static void SlReadFill(void)
-{
-	uint len = _sl.read_bytes();
-	assert(len != 0);
-
-	_sl.bufp = _sl.buf;
-	_sl.bufe = _sl.buf + len;
-	_sl.offs_base += len;
-}
-
-static inline uint32 SlGetOffs(void) {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
-
-/** Return the size in bytes of a certain type of normal/atomic variable
- * as it appears in memory. @see VarTypes
- * @param conv @VarType type of variable that is used for calculating the size
- * @return Return the size of this type in bytes */
-static inline byte SlCalcConvMemLen(VarType conv)
-{
-	static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
-	byte length = GB(conv, 4, 4);
-	assert(length < lengthof(conv_mem_size));
-	return conv_mem_size[length];
-}
-
-/** Return the size in bytes of a certain type of normal/atomic variable
- * as it appears in a saved game. @see VarTypes
- * @param conv @VarType type of variable that is used for calculating the size
- * @return Return the size of this type in bytes */
-static inline byte SlCalcConvFileLen(VarType conv)
-{
-	static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
-	byte length = GB(conv, 0, 4);
-	assert(length < lengthof(conv_file_size));
-	return conv_file_size[length];
-}
-
-/* Return the size in bytes of a reference (pointer) */
-static inline size_t SlCalcRefLen(void) {return 2;}
-
-/** Flush the output buffer by writing to disk with the given reader.
- * If the buffer pointer has not yet been set up, set it up now. Usually
- * only called when the buffer is full, or there is no more data to be processed
- */
-static void SlWriteFill(void)
-{
-	// flush the buffer to disk (the writer)
-	if (_sl.bufp != NULL) {
-		uint len = _sl.bufp - _sl.buf;
-		_sl.offs_base += len;
-		if (len) _sl.write_bytes(len);
-	}
-
-	/* All the data from the buffer has been written away, rewind to the beginning
-	* to start reading in more data */
-	_sl.bufp = _sl.buf;
-	_sl.bufe = _sl.buf + _sl.bufsize;
-}
-
-/** Error handler, calls longjmp to simulate an exception.
- * @todo this was used to have a central place to handle errors, but it is
- * pretty ugly, and seriously interferes with any multithreaded approaches */
-static void NORETURN SlError(const char *msg)
-{
-	_sl.excpt_msg = msg;
-	longjmp(_sl.excpt, 0);
-}
-
-/** Read in a single byte from file. If the temporary buffer is full,
- * flush it to its final destination
- * @return return the read byte from file
- */
-static inline byte SlReadByteInternal(void)
-{
-	if (_sl.bufp == _sl.bufe) SlReadFill();
-	return *_sl.bufp++;
-}
-
-/** Wrapper for SlReadByteInternal */
-byte SlReadByte(void) {return SlReadByteInternal();}
-
-/** Write away a single byte from memory. If the temporary buffer is full,
- * flush it to its destination (file)
- * @param b the byte that is currently written
- */
-static inline void SlWriteByteInternal(byte b)
-{
-	if (_sl.bufp == _sl.bufe) SlWriteFill();
-	*_sl.bufp++ = b;
-}
-
-/** Wrapper for SlWriteByteInternal */
-void SlWriteByte(byte b) {SlWriteByteInternal(b);}
-
-static inline int SlReadUint16(void)
-{
-	int x = SlReadByte() << 8;
-	return x | SlReadByte();
-}
-
-static inline uint32 SlReadUint32(void)
-{
-	uint32 x = SlReadUint16() << 16;
-	return x | SlReadUint16();
-}
-
-static inline uint64 SlReadUint64(void)
-{
-	uint32 x = SlReadUint32();
-	uint32 y = SlReadUint32();
-	return (uint64)x << 32 | y;
-}
-
-static inline void SlWriteUint16(uint16 v)
-{
-	SlWriteByte(GB(v, 8, 8));
-	SlWriteByte(GB(v, 0, 8));
-}
-
-static inline void SlWriteUint32(uint32 v)
-{
-	SlWriteUint16(GB(v, 16, 16));
-	SlWriteUint16(GB(v,  0, 16));
-}
-
-static inline void SlWriteUint64(uint64 x)
-{
-	SlWriteUint32((uint32)(x >> 32));
-	SlWriteUint32((uint32)x);
-}
-
-/**
- * Read in the header descriptor of an object or an array.
- * If the highest bit is set (7), then the index is bigger than 127
- * elements, so use the next byte to read in the real value.
- * The actual value is then both bytes added with the first shifted
- * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
- * x = ((x & 0x7F) << 8) + SlReadByte();
- * @return Return the value of the index
- */
-static uint SlReadSimpleGamma(void)
-{
-	uint i = SlReadByte();
-	if (HASBIT(i, 7)) {
-		i &= ~0x80;
-		if (HASBIT(i, 6)) {
-			i &= ~0x40;
-			if (HASBIT(i, 5)) {
-				i &= ~0x20;
-				if (HASBIT(i, 4))
-					SlError("Unsupported gamma");
-				i = (i << 8) | SlReadByte();
-			}
-			i = (i << 8) | SlReadByte();
-		}
-		i = (i << 8) | SlReadByte();
-	}
-	return i;
-}
-
-/**
- * Write the header descriptor of an object or an array.
- * If the element is bigger than 127, use 2 bytes for saving
- * and use the highest byte of the first written one as a notice
- * that the length consists of 2 bytes, etc.. like this:
- * 0xxxxxxx
- * 10xxxxxx xxxxxxxx
- * 110xxxxx xxxxxxxx xxxxxxxx
- * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
- * @param i Index being written
- */
-
-static void SlWriteSimpleGamma(uint i)
-{
-	if (i >= (1 << 7)) {
-		if (i >= (1 << 14)) {
-			if (i >= (1 << 21)) {
-				assert(i < (1 << 28));
-				SlWriteByte((byte)0xE0 | (i>>24));
-				SlWriteByte((byte)(i>>16));
-			} else {
-				SlWriteByte((byte)0xC0 | (i>>16));
-			}
-			SlWriteByte((byte)(i>>8));
-		} else {
-			SlWriteByte((byte)(0x80 | (i>>8)));
-		}
-	}
-	SlWriteByte(i);
-}
-
-/** Return how many bytes used to encode a gamma value */
-static inline uint SlGetGammaLength(uint i) {
-	return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
-}
-
-static inline uint SlReadSparseIndex(void) {return SlReadSimpleGamma();}
-static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
-
-static inline uint SlReadArrayLength(void) {return SlReadSimpleGamma();}
-static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
-static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
-
-void SlSetArrayIndex(uint index)
-{
-	_sl.need_length = NL_WANTLENGTH;
-	_sl.array_index = index;
-}
-
-/**
- * Iterate through the elements of an array and read the whole thing
- * @return The index of the object, or -1 if we have reached the end of current block
- */
-int SlIterateArray(void)
-{
-	int index;
-	static uint32 next_offs;
-
-	/* After reading in the whole array inside the loop
-	 * we must have read in all the data, so we must be at end of current block. */
-	assert(next_offs == 0 || SlGetOffs() == next_offs);
-
-	while (true) {
-		uint length = SlReadArrayLength();
-		if (length == 0) {
-			next_offs = 0;
-			return -1;
-		}
-
-		_sl.obj_len = --length;
-		next_offs = SlGetOffs() + length;
-
-		switch (_sl.block_mode) {
-		case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
-		case CH_ARRAY:        index = _sl.array_index++; break;
-		default:
-			DEBUG(sl, 0, "SlIterateArray error");
-			return -1; // error
-		}
-
-		if (length != 0) return index;
-	}
-}
-
-/**
- * Sets the length of either a RIFF object or the number of items in an array.
- * This lets us load an object or an array of arbitrary size
- * @param length The length of the sought object/array
- */
-void SlSetLength(size_t length)
-{
-	assert(_sl.save);
-
-	switch (_sl.need_length) {
-	case NL_WANTLENGTH:
-		_sl.need_length = NL_NONE;
-		switch (_sl.block_mode) {
-		case CH_RIFF:
-			// Ugly encoding of >16M RIFF chunks
-			// The lower 24 bits are normal
-			// The uppermost 4 bits are bits 24:27
-			assert(length < (1<<28));
-			SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
-			break;
-		case CH_ARRAY:
-			assert(_sl.last_array_index <= _sl.array_index);
-			while (++_sl.last_array_index <= _sl.array_index)
-				SlWriteArrayLength(1);
-			SlWriteArrayLength(length + 1);
-			break;
-		case CH_SPARSE_ARRAY:
-			SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
-			SlWriteSparseIndex(_sl.array_index);
-			break;
-		default: NOT_REACHED();
-		} break;
-	case NL_CALCLENGTH:
-		_sl.obj_len += length;
-		break;
-	}
-}
-
-/**
- * Save/Load bytes. These do not need to be converted to Little/Big Endian
- * so directly write them or read them to/from file
- * @param ptr The source or destination of the object being manipulated
- * @param length number of bytes this fast CopyBytes lasts
- */
-static void SlCopyBytes(void *ptr, size_t length)
-{
-	byte *p = (byte*)ptr;
-
-	if (_sl.save) {
-		for (; length != 0; length--) {SlWriteByteInternal(*p++);}
-	} else {
-		for (; length != 0; length--) {*p++ = SlReadByteInternal();}
-	}
-}
-
-/** Read in bytes from the file/data structure but don't do
- * anything with them, discarding them in effect
- * @param length The amount of bytes that is being treated this way
- */
-static inline void SlSkipBytes(size_t length)
-{
-	for (; length != 0; length--) SlReadByte();
-}
-
-/* Get the length of the current object */
-uint SlGetFieldLength(void) {return _sl.obj_len;}
-
-/** Return a signed-long version of the value of a setting
- * @param ptr pointer to the variable
- * @param conv type of variable, can be a non-clean
- * type, eg one with other flags because it is parsed
- * @return returns the value of the pointer-setting */
-int64 ReadValue(const void *ptr, VarType conv)
-{
-	switch (GetVarMemType(conv)) {
-	case SLE_VAR_BL:  return (*(bool*)ptr != 0);
-	case SLE_VAR_I8:  return *(int8*  )ptr;
-	case SLE_VAR_U8:  return *(byte*  )ptr;
-	case SLE_VAR_I16: return *(int16* )ptr;
-	case SLE_VAR_U16: return *(uint16*)ptr;
-	case SLE_VAR_I32: return *(int32* )ptr;
-	case SLE_VAR_U32: return *(uint32*)ptr;
-	case SLE_VAR_I64: return *(int64* )ptr;
-	case SLE_VAR_U64: return *(uint64*)ptr;
-	case SLE_VAR_NULL:return 0;
-	default: NOT_REACHED();
-	}
-
-	/* useless, but avoids compiler warning this way */
-	return 0;
-}
-
-/** Write the value of a setting
- * @param ptr pointer to the variable
- * @param conv type of variable, can be a non-clean type, eg
- * with other flags. It is parsed upon read
- * @param var the new value being given to the variable */
-void WriteValue(void *ptr, VarType conv, int64 val)
-{
-	switch (GetVarMemType(conv)) {
-	case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
-	case SLE_VAR_I8:  *(int8  *)ptr = val; break;
-	case SLE_VAR_U8:  *(byte  *)ptr = val; break;
-	case SLE_VAR_I16: *(int16 *)ptr = val; break;
-	case SLE_VAR_U16: *(uint16*)ptr = val; break;
-	case SLE_VAR_I32: *(int32 *)ptr = val; break;
-	case SLE_VAR_U32: *(uint32*)ptr = val; break;
-	case SLE_VAR_I64: *(int64 *)ptr = val; break;
-	case SLE_VAR_U64: *(uint64*)ptr = val; break;
-	case SLE_VAR_NULL: break;
-	default: NOT_REACHED();
-	}
-}
-
-/**
- * Handle all conversion and typechecking of variables here.
- * In the case of saving, read in the actual value from the struct
- * and then write them to file, endian safely. Loading a value
- * goes exactly the opposite way
- * @param ptr The object being filled/read
- * @param conv @VarType type of the current element of the struct
- */
-static void SlSaveLoadConv(void *ptr, VarType conv)
-{
-	int64 x = 0;
-
-	if (_sl.save) { /* SAVE values */
-		/* Read a value from the struct. These ARE endian safe. */
-		x = ReadValue(ptr, conv);
-
-		/* Write the value to the file and check if its value is in the desired range */
-		switch (GetVarFileType(conv)) {
-		case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
-		case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
-		case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
-		case SLE_FILE_STRINGID:
-		case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
-		case SLE_FILE_I32:
-		case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
-		case SLE_FILE_I64:
-		case SLE_FILE_U64:                                   SlWriteUint64(x);break;
-		default: NOT_REACHED();
-		}
-	} else { /* LOAD values */
-
-		/* Read a value from the file */
-		switch (GetVarFileType(conv)) {
-		case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
-		case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
-		case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
-		case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
-		case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
-		case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
-		case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
-		case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
-		case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
-		default: NOT_REACHED();
-		}
-
-		/* Write The value to the struct. These ARE endian safe. */
-		WriteValue(ptr, conv, x);
-	}
-}
-
-/** Calculate the net length of a string. This is in almost all cases
- * just strlen(), but if the string is not properly terminated, we'll
- * resort to the maximum length of the buffer.
- * @param ptr pointer to the stringbuffer
- * @param length maximum length of the string (buffer). If -1 we don't care
- * about a maximum length, but take string length as it is.
- * @return return the net length of the string */
-static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
-{
-	return minu(strlen(ptr), length - 1);
-}
-
-/** Calculate the gross length of the string that it
- * will occupy in the savegame. This includes the real length, returned
- * by SlCalcNetStringLen and the length that the index will occupy.
- * @param ptr pointer to the stringbuffer
- * @param length maximum length of the string (buffer size, etc.)
- * @return return the gross length of the string */
-static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
-{
-	size_t len;
-	const char *str;
-
-	switch (GetVarMemType(conv)) {
-		default: NOT_REACHED();
-		case SLE_VAR_STR:
-		case SLE_VAR_STRQ:
-			str = *(const char**)ptr;
-			len = -1;
-			break;
-		case SLE_VAR_STRB:
-		case SLE_VAR_STRBQ:
-			str = (const char*)ptr;
-			len = length;
-			break;
-	}
-
-	len = SlCalcNetStringLen(str, len);
-	return len + SlGetArrayLength(len); // also include the length of the index
-}
-
-/**
- * Save/Load a string.
- * @param ptr the string being manipulated
- * @param the length of the string (full length)
- * @param conv must be SLE_FILE_STRING */
-static void SlString(void *ptr, size_t length, VarType conv)
-{
-	size_t len;
-
-	if (_sl.save) { /* SAVE string */
-		switch (GetVarMemType(conv)) {
-			default: NOT_REACHED();
-			case SLE_VAR_STRB:
-			case SLE_VAR_STRBQ:
-				len = SlCalcNetStringLen(ptr, length);
-				break;
-			case SLE_VAR_STR:
-			case SLE_VAR_STRQ:
-				ptr = *(char**)ptr;
-				len = SlCalcNetStringLen(ptr, -1);
-				break;
-		}
-
-		SlWriteArrayLength(len);
-		SlCopyBytes(ptr, len);
-	} else { /* LOAD string */
-		len = SlReadArrayLength();
-
-		switch (GetVarMemType(conv)) {
-			default: NOT_REACHED();
-			case SLE_VAR_STRB:
-			case SLE_VAR_STRBQ:
-				if (len >= length) {
-					DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
-					SlCopyBytes(ptr, length);
-					SlSkipBytes(len - length);
-					len = length - 1;
-				} else {
-					SlCopyBytes(ptr, len);
-				}
-				break;
-			case SLE_VAR_STR:
-			case SLE_VAR_STRQ: /* Malloc'd string, free previous incarnation, and allocate */
-				free(*(char**)ptr);
-				*(char**)ptr = malloc(len + 1); // terminating '\0'
-				ptr = *(char**)ptr;
-				SlCopyBytes(ptr, len);
-				break;
-		}
-
-		((char*)ptr)[len] = '\0'; // properly terminate the string
-	}
-}
-
-/**
- * Return the size in bytes of a certain type of atomic array
- * @param length The length of the array counted in elements
- * @param conv @VarType type of the variable that is used in calculating the size
- */
-static inline size_t SlCalcArrayLen(uint length, VarType conv)
-{
-	return SlCalcConvFileLen(conv) * length;
-}
-
-/**
- * Save/Load an array.
- * @param array The array being manipulated
- * @param length The length of the array in elements
- * @param conv @VarType type of the atomic array (int, byte, uint64, etc.)
- */
-void SlArray(void *array, uint length, VarType conv)
-{
-	// Automatically calculate the length?
-	if (_sl.need_length != NL_NONE) {
-		SlSetLength(SlCalcArrayLen(length, conv));
-		// Determine length only?
-		if (_sl.need_length == NL_CALCLENGTH) return;
-	}
-
-	/* NOTICE - handle some buggy stuff, in really old versions everything was saved
-	 * as a byte-type. So detect this, and adjust array size accordingly */
-	if (!_sl.save && _sl_version == 0) {
-		if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
-				conv == SLE_INT32 || conv == SLE_UINT32) {
-			length *= SlCalcConvFileLen(conv);
-			conv = SLE_INT8;
-		}
-	}
-
-	/* If the size of elements is 1 byte both in file and memory, no special
-	 * conversion is needed, use specialized copy-copy function to speed up things */
-	if (conv == SLE_INT8 || conv == SLE_UINT8) {
-		SlCopyBytes(array, length);
-	} else {
-		byte *a = (byte*)array;
-		byte mem_size = SlCalcConvMemLen(conv);
-
-		for (; length != 0; length --) {
-			SlSaveLoadConv(a, conv);
-			a += mem_size; // get size
-		}
-	}
-}
-
-/* Are we going to save this object or not? */
-static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
-{
-	if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
-	if (sld->conv & SLF_SAVE_NO) return false;
-
-	return true;
-}
-
-/** Are we going to load this variable when loading a savegame or not?
- * @note If the variable is skipped it is skipped in the savegame
- * bytestream itself as well, so there is no need to skip it somewhere else */
-static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
-{
-	if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
-		SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
-		return true;
-	}
-
-	return false;
-}
-
-/**
- * Calculate the size of an object.
- * @param sld The @SaveLoad description of the object so we know how to manipulate it
- */
-static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
-{
-	size_t length = 0;
-
-	// Need to determine the length and write a length tag.
-	for (; sld->cmd != SL_END; sld++) {
-		length += SlCalcObjMemberLength(object, sld);
-	}
-	return length;
-}
-
-size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
-{
-	assert(_sl.save);
-
-	switch (sld->cmd) {
-		case SL_VAR:
-		case SL_REF:
-		case SL_ARR:
-		case SL_STR:
-			/* CONDITIONAL saveload types depend on the savegame version */
-			if (!SlIsObjectValidInSavegame(sld)) break;
-
-			switch (sld->cmd) {
-			case SL_VAR: return SlCalcConvFileLen(sld->conv);
-			case SL_REF: return SlCalcRefLen();
-			case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
-			case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
-			default: NOT_REACHED();
-			}
-			break;
-		case SL_WRITEBYTE: return 1; // a byte is logically of size 1
-		case SL_INCLUDE: return SlCalcObjLength(object, _sl.includes[sld->version_from]);
-		default: NOT_REACHED();
-	}
-	return 0;
-}
-
-
-static uint ReferenceToInt(const void* obj, SLRefType rt);
-static void* IntToReference(uint index, SLRefType rt);
-
-
-bool SlObjectMember(void *ptr, const SaveLoad *sld)
-{
-	VarType conv = GB(sld->conv, 0, 8);
-	switch (sld->cmd) {
-	case SL_VAR:
-	case SL_REF:
-	case SL_ARR:
-	case SL_STR:
-		/* CONDITIONAL saveload types depend on the savegame version */
-		if (!SlIsObjectValidInSavegame(sld)) return false;
-		if (SlSkipVariableOnLoad(sld)) return false;
-
-		switch (sld->cmd) {
-		case SL_VAR: SlSaveLoadConv(ptr, conv); break;
-		case SL_REF: /* Reference variable, translate */
-			/// @todo XXX - another artificial limitof 65K elements of pointers?
-			if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces?
-				SlWriteUint16(ReferenceToInt(*(void**)ptr, conv));
-			} else {
-				*(void**)ptr = IntToReference(SlReadUint16(), conv);
-			}
-			break;
-		case SL_ARR: SlArray(ptr, sld->length, conv); break;
-		case SL_STR: SlString(ptr, sld->length, conv); break;
-		default: NOT_REACHED();
-		}
-		break;
-
-	/* SL_WRITEBYTE translates a value of a variable to another one upon
-   * saving or loading.
-   * XXX - variable renaming abuse
-   * game_value: the value of the variable ingame is abused by sld->version_from
-   * file_value: the value of the variable in the savegame is abused by sld->version_to */
-	case SL_WRITEBYTE:
-		if (_sl.save) {
-			SlWriteByte(sld->version_to);
-		} else {
-			*(byte*)ptr = sld->version_from;
-		}
-		break;
-
-	/* SL_INCLUDE loads common code for a type
-	 * XXX - variable renaming abuse
-	 * include_index: common code to include from _desc_includes[], abused by sld->version_from */
-	case SL_INCLUDE:
-		SlObject(ptr, _sl.includes[sld->version_from]);
-		break;
-	default: NOT_REACHED();
-	}
-	return true;
-}
-
-/**
- * Main SaveLoad function.
- * @param object The object that is being saved or loaded
- * @param sld The @SaveLoad description of the object so we know how to manipulate it
- */
-void SlObject(void *object, const SaveLoad *sld)
-{
-	// Automatically calculate the length?
-	if (_sl.need_length != NL_NONE) {
-		SlSetLength(SlCalcObjLength(object, sld));
-		if (_sl.need_length == NL_CALCLENGTH) return;
-	}
-
-	for (; sld->cmd != SL_END; sld++) {
-		void *ptr = GetVariableAddress(object, sld);
-		SlObjectMember(ptr, sld);
-	}
-}
-
-/**
- * Save or Load (a list of) global variables
- * @param desc The global variable that is being loaded or saved
- */
-void SlGlobList(const SaveLoadGlobVarList *sldg)
-{
-	if (_sl.need_length != NL_NONE) {
-		SlSetLength(SlCalcObjLength(NULL, (const SaveLoad*)sldg));
-		if (_sl.need_length == NL_CALCLENGTH) return;
-	}
-
-	for (; sldg->cmd != SL_END; sldg++) {
-		SlObjectMember(sldg->address, (const SaveLoad*)sldg);
-	}
-}
-
-/**
- * Do something of which I have no idea what it is :P
- * @param proc The callback procedure that is called
- * @param arg The variable that will be used for the callback procedure
- */
-void SlAutolength(AutolengthProc *proc, void *arg)
-{
-	uint32 offs;
-
-	assert(_sl.save);
-
-	// Tell it to calculate the length
-	_sl.need_length = NL_CALCLENGTH;
-	_sl.obj_len = 0;
-	proc(arg);
-
-	// Setup length
-	_sl.need_length = NL_WANTLENGTH;
-	SlSetLength(_sl.obj_len);
-
-	offs = SlGetOffs() + _sl.obj_len;
-
-	// And write the stuff
-	proc(arg);
-
-	assert(offs == SlGetOffs());
-}
-
-/**
- * Load a chunk of data (eg vehicles, stations, etc.)
- * @param ch The chunkhandler that will be used for the operation
- */
-static void SlLoadChunk(const ChunkHandler *ch)
-{
-	byte m = SlReadByte();
-	size_t len;
-	uint32 endoffs;
-
-	_sl.block_mode = m;
-	_sl.obj_len = 0;
-
-	switch (m) {
-	case CH_ARRAY:
-		_sl.array_index = 0;
-		ch->load_proc();
-		break;
-	case CH_SPARSE_ARRAY:
-		ch->load_proc();
-		break;
-	default:
-		if ((m & 0xF) == CH_RIFF) {
-			// Read length
-			len = (SlReadByte() << 16) | ((m >> 4) << 24);
-			len += SlReadUint16();
-			_sl.obj_len = len;
-			endoffs = SlGetOffs() + len;
-			ch->load_proc();
-			assert(SlGetOffs() == endoffs);
-		} else {
-			SlError("Invalid chunk type");
-		}
-		break;
-	}
-}
-
-/* Stub Chunk handlers to only calculate length and do nothing else */
-static ChunkSaveLoadProc *_tmp_proc_1;
-static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
-static void SlStubSaveProc(void) {SlAutolength(SlStubSaveProc2, NULL);}
-
-/** Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
- * prefixed by an ID identifying it, followed by data, and terminator where appropiate
- * @param ch The chunkhandler that will be used for the operation
- */
-static void SlSaveChunk(const ChunkHandler *ch)
-{
-	ChunkSaveLoadProc *proc = ch->save_proc;
-
-	SlWriteUint32(ch->id);
-	DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
-
-	if (ch->flags & CH_AUTO_LENGTH) {
-		// Need to calculate the length. Solve that by calling SlAutoLength in the save_proc.
-		_tmp_proc_1 = proc;
-		proc = SlStubSaveProc;
-	}
-
-	_sl.block_mode = ch->flags & CH_TYPE_MASK;
-	switch (ch->flags & CH_TYPE_MASK) {
-	case CH_RIFF:
-		_sl.need_length = NL_WANTLENGTH;
-		proc();
-		break;
-	case CH_ARRAY:
-		_sl.last_array_index = 0;
-		SlWriteByte(CH_ARRAY);
-		proc();
-		SlWriteArrayLength(0); // Terminate arrays
-		break;
-	case CH_SPARSE_ARRAY:
-		SlWriteByte(CH_SPARSE_ARRAY);
-		proc();
-		SlWriteArrayLength(0); // Terminate arrays
-		break;
-	default: NOT_REACHED();
-	}
-}
-
-/** Save all chunks */
-static void SlSaveChunks(void)
-{
-	const ChunkHandler *ch;
-	const ChunkHandler* const *chsc;
-	uint p;
-
-	for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
-		for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
-			while (true) {
-				if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
-					SlSaveChunk(ch);
-				if (ch->flags & CH_LAST)
-					break;
-				ch++;
-			}
-		}
-	}
-
-	// Terminator
-	SlWriteUint32(0);
-}
-
-/** Find the ChunkHandler that will be used for processing the found
- * chunk in the savegame or in memory
- * @param id the chunk in question
- * @return returns the appropiate chunkhandler
- */
-static const ChunkHandler *SlFindChunkHandler(uint32 id)
-{
-	const ChunkHandler *ch;
-	const ChunkHandler *const *chsc;
-	for (chsc = _sl.chs; (ch=*chsc++) != NULL;) {
-		for (;;) {
-			if (ch->id == id) return ch;
-			if (ch->flags & CH_LAST) break;
-			ch++;
-		}
-	}
-	return NULL;
-}
-
-/** Load all chunks */
-static void SlLoadChunks(void)
-{
-	uint32 id;
-	const ChunkHandler *ch;
-
-	for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
-		DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
-
-		ch = SlFindChunkHandler(id);
-		if (ch == NULL) SlError("found unknown tag in savegame (sync error)");
-		SlLoadChunk(ch);
-	}
-}
-
-//*******************************************
-//********** START OF LZO CODE **************
-//*******************************************
-#define LZO_SIZE 8192
-
-#include "minilzo.h"
-
-static uint ReadLZO(void)
-{
-	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
-	uint32 tmp[2];
-	uint32 size;
-	uint len;
-
-	// Read header
-	if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError("file read failed");
-
-	// Check if size is bad
-	((uint32*)out)[0] = size = tmp[1];
-
-	if (_sl_version != 0) {
-		tmp[0] = TO_BE32(tmp[0]);
-		size = TO_BE32(size);
-	}
-
-	if (size >= sizeof(out)) SlError("inconsistent size");
-
-	// Read block
-	if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError("file read failed");
-
-	// Verify checksum
-	if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError("bad checksum");
-
-	// Decompress
-	lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
-	return len;
-}
-
-// p contains the pointer to the buffer, len contains the pointer to the length.
-// len bytes will be written, p and l will be updated to reflect the next buffer.
-static void WriteLZO(uint size)
-{
-	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
-	byte wrkmem[sizeof(byte*)*4096];
-	uint outlen;
-
-	lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
-	((uint32*)out)[1] = TO_BE32(outlen);
-	((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
-	if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError("file write failed");
-}
-
-static bool InitLZO(void)
-{
-	_sl.bufsize = LZO_SIZE;
-	_sl.buf = _sl.buf_ori = (byte*)malloc(LZO_SIZE);
-	return true;
-}
-
-static void UninitLZO(void)
-{
-	free(_sl.buf_ori);
-}
-
-//*********************************************
-//******** START OF NOCOMP CODE (uncompressed)*
-//*********************************************
-static uint ReadNoComp(void)
-{
-	return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
-}
-
-static void WriteNoComp(uint size)
-{
-	fwrite(_sl.buf, 1, size, _sl.fh);
-}
-
-static bool InitNoComp(void)
-{
-	_sl.bufsize = LZO_SIZE;
-	_sl.buf = _sl.buf_ori =(byte*)malloc(LZO_SIZE);
-	return true;
-}
-
-static void UninitNoComp(void)
-{
-	free(_sl.buf_ori);
-}
-
-//********************************************
-//********** START OF MEMORY CODE (in ram)****
-//********************************************
-
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "gfx.h"
-#include "gui.h"
-
-typedef struct ThreadedSave {
-	uint count;
-	bool ff_state;
-	bool saveinprogress;
-	CursorID cursor;
-} ThreadedSave;
-
-/* A maximum size of of 128K * 500 = 64.000KB savegames */
-STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
-static ThreadedSave _ts;
-
-static bool InitMem(void)
-{
-	_ts.count = 0;
-
-	CleanPool(&_Savegame_pool);
-	AddBlockToPool(&_Savegame_pool);
-
-	/* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
-	_sl.bufsize = GetSavegamePoolSize();
-	_sl.buf = GetSavegame(_ts.count);
-	return true;
-}
-
-static void UnInitMem(void)
-{
-	CleanPool(&_Savegame_pool);
-}
-
-static void WriteMem(uint size)
-{
-	_ts.count += size;
-	/* Allocate new block and new buffer-pointer */
-	AddBlockIfNeeded(&_Savegame_pool, _ts.count);
-	_sl.buf = GetSavegame(_ts.count);
-}
-
-//********************************************
-//********** START OF ZLIB CODE **************
-//********************************************
-
-#if defined(WITH_ZLIB)
-#include <zlib.h>
-
-static z_stream _z;
-
-static bool InitReadZlib(void)
-{
-	memset(&_z, 0, sizeof(_z));
-	if (inflateInit(&_z) != Z_OK) return false;
-
-	_sl.bufsize = 4096;
-	_sl.buf = _sl.buf_ori = (byte*)malloc(4096 + 4096); // also contains fread buffer
-	return true;
-}
-
-static uint ReadZlib(void)
-{
-	int r;
-
-	_z.next_out = _sl.buf;
-	_z.avail_out = 4096;
-
-	do {
-		// read more bytes from the file?
-		if (_z.avail_in == 0) {
-			_z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
-		}
-
-		// inflate the data
-		r = inflate(&_z, 0);
-		if (r == Z_STREAM_END)
-			break;
-
-		if (r != Z_OK)
-			SlError("inflate() failed");
-	} while (_z.avail_out);
-
-	return 4096 - _z.avail_out;
-}
-
-static void UninitReadZlib(void)
-{
-	inflateEnd(&_z);
-	free(_sl.buf_ori);
-}
-
-static bool InitWriteZlib(void)
-{
-	memset(&_z, 0, sizeof(_z));
-	if (deflateInit(&_z, 6) != Z_OK) return false;
-
-	_sl.bufsize = 4096;
-	_sl.buf = _sl.buf_ori = (byte*)malloc(4096); // also contains fread buffer
-	return true;
-}
-
-static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
-{
-	byte buf[1024]; // output buffer
-	int r;
-	uint n;
-	z->next_in = p;
-	z->avail_in = len;
-	do {
-		z->next_out = buf;
-		z->avail_out = sizeof(buf);
-		r = deflate(z, mode);
-			// bytes were emitted?
-		if ((n=sizeof(buf) - z->avail_out) != 0) {
-			if (fwrite(buf, n, 1, _sl.fh) != 1) SlError("file write error");
-		}
-		if (r == Z_STREAM_END)
-			break;
-		if (r != Z_OK) SlError("zlib returned error code");
-	} while (z->avail_in || !z->avail_out);
-}
-
-static void WriteZlib(uint len)
-{
-	WriteZlibLoop(&_z, _sl.buf, len, 0);
-}
-
-static void UninitWriteZlib(void)
-{
-	// flush any pending output.
-	if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
-	deflateEnd(&_z);
-	free(_sl.buf_ori);
-}
-
-#endif /* WITH_ZLIB */
-
-//*******************************************
-//************* END OF CODE *****************
-//*******************************************
-
-// these define the chunks
-extern const ChunkHandler _misc_chunk_handlers[];
-extern const ChunkHandler _setting_chunk_handlers[];
-extern const ChunkHandler _player_chunk_handlers[];
-extern const ChunkHandler _engine_chunk_handlers[];
-extern const ChunkHandler _veh_chunk_handlers[];
-extern const ChunkHandler _waypoint_chunk_handlers[];
-extern const ChunkHandler _depot_chunk_handlers[];
-extern const ChunkHandler _order_chunk_handlers[];
-extern const ChunkHandler _town_chunk_handlers[];
-extern const ChunkHandler _sign_chunk_handlers[];
-extern const ChunkHandler _station_chunk_handlers[];
-extern const ChunkHandler _industry_chunk_handlers[];
-extern const ChunkHandler _economy_chunk_handlers[];
-extern const ChunkHandler _animated_tile_chunk_handlers[];
-extern const ChunkHandler _newgrf_chunk_handlers[];
-
-static const ChunkHandler * const _chunk_handlers[] = {
-	_misc_chunk_handlers,
-	_setting_chunk_handlers,
-	_veh_chunk_handlers,
-	_waypoint_chunk_handlers,
-	_depot_chunk_handlers,
-	_order_chunk_handlers,
-	_industry_chunk_handlers,
-	_economy_chunk_handlers,
-	_engine_chunk_handlers,
-	_town_chunk_handlers,
-	_sign_chunk_handlers,
-	_station_chunk_handlers,
-	_player_chunk_handlers,
-	_animated_tile_chunk_handlers,
-	_newgrf_chunk_handlers,
-	NULL,
-};
-
-// used to include a vehicle desc in another desc.
-extern const SaveLoad _common_veh_desc[];
-static const SaveLoad* const _desc_includes[] = {
-	_common_veh_desc
-};
-
-/**
- * Pointers cannot be saved to a savegame, so this functions gets
- * the index of the item, and if not available, it hussles with
- * pointers (looks really bad :()
- * Remember that a NULL item has value 0, and all
- * indeces have +1, so vehicle 0 is saved as index 1.
- * @param obj The object that we want to get the index of
- * @param rt @SLRefType type of the object the index is being sought of
- * @return Return the pointer converted to an index of the type pointed to
- */
-static uint ReferenceToInt(const void *obj, SLRefType rt)
-{
-	if (obj == NULL) return 0;
-
-	switch (rt) {
-		case REF_VEHICLE_OLD: // Old vehicles we save as new onces
-		case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
-		case REF_STATION:   return ((const  Station*)obj)->index + 1;
-		case REF_TOWN:      return ((const     Town*)obj)->index + 1;
-		case REF_ORDER:     return ((const    Order*)obj)->index + 1;
-		case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
-		case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
-		default: NOT_REACHED();
-	}
-
-	return 0; // avoid compiler warning
-}
-
-/**
- * Pointers cannot be loaded from a savegame, so this function
- * gets the index from the savegame and returns the appropiate
- * pointer from the already loaded base.
- * Remember that an index of 0 is a NULL pointer so all indeces
- * are +1 so vehicle 0 is saved as 1.
- * @param index The index that is being converted to a pointer
- * @param rt @SLRefType type of the object the pointer is sought of
- * @return Return the index converted to a pointer of any type
- */
-static void *IntToReference(uint index, SLRefType rt)
-{
-	/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
-	 * and should be loaded like that */
-	if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4))
-		rt = REF_VEHICLE;
-
-	/* No need to look up NULL pointers, just return immediately */
-	if (rt != REF_VEHICLE_OLD && index == 0)
-		return NULL;
-
-	index--; // correct for the NULL index
-
-	switch (rt) {
-		case REF_ORDER: {
-			if (!AddBlockIfNeeded(&_Order_pool, index))
-				error("Orders: failed loading savegame: too many orders");
-			return GetOrder(index);
-		}
-		case REF_VEHICLE: {
-			if (!AddBlockIfNeeded(&_Vehicle_pool, index))
-				error("Vehicles: failed loading savegame: too many vehicles");
-			return GetVehicle(index);
-		}
-		case REF_STATION: {
-			if (!AddBlockIfNeeded(&_Station_pool, index))
-				error("Stations: failed loading savegame: too many stations");
-			return GetStation(index);
-		}
-		case REF_TOWN: {
-			if (!AddBlockIfNeeded(&_Town_pool, index))
-				error("Towns: failed loading savegame: too many towns");
-			return GetTown(index);
-		}
-		case REF_ROADSTOPS: {
-			if (!AddBlockIfNeeded(&_RoadStop_pool, index))
-				error("RoadStops: failed loading savegame: too many RoadStops");
-			return GetRoadStop(index);
-		}
-		case REF_ENGINE_RENEWS: {
-			if (!AddBlockIfNeeded(&_EngineRenew_pool, index))
-				error("EngineRenews: failed loading savegame: too many EngineRenews");
-			return GetEngineRenew(index);
-		}
-
-		case REF_VEHICLE_OLD: {
-			/* Old vehicles were saved differently:
-			 * invalid vehicle was 0xFFFF,
-			 * and the index was not - 1.. correct for this */
-			index++;
-			if (index == INVALID_VEHICLE)
-				return NULL;
-
-			if (!AddBlockIfNeeded(&_Vehicle_pool, index))
-				error("Vehicles: failed loading savegame: too many vehicles");
-			return GetVehicle(index);
-		}
-		default: NOT_REACHED();
-	}
-
-	return NULL;
-}
-
-/** The format for a reader/writer type of a savegame */
-typedef struct {
-	const char *name;           /// name of the compressor/decompressor (debug-only)
-	uint32 tag;                 /// the 4-letter tag by which it is identified in the savegame
-
-	bool (*init_read)(void);    /// function executed upon initalization of the loader
-	ReaderProc *reader;         /// function that loads the data from the file
-	void (*uninit_read)(void);  /// function executed when reading is finished
-
-	bool (*init_write)(void);   /// function executed upon intialization of the saver
-	WriterProc *writer;         /// function that saves the data to the file
-	void (*uninit_write)(void); /// function executed when writing is done
-} SaveLoadFormat;
-
-static const SaveLoadFormat _saveload_formats[] = {
-	{"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
-	{"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
-	{"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
-#if defined(WITH_ZLIB)
-	{"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
-#else
-	{"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
-#endif
-};
-
-/**
- * Return the savegameformat of the game. Whether it was create with ZLIB compression
- * uncompressed, or another type
- * @param s Name of the savegame format. If NULL it picks the first available one
- * @return Pointer to @SaveLoadFormat struct giving all characteristics of this type of savegame
- */
-static const SaveLoadFormat *GetSavegameFormat(const char *s)
-{
-	const SaveLoadFormat *def = endof(_saveload_formats) - 1;
-
-	// find default savegame format, the highest one with which files can be written
-	while (!def->init_write) def--;
-
-	if (s != NULL && s[0] != '\0') {
-		const SaveLoadFormat *slf;
-		for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
-			if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
-				return slf;
-		}
-
-		ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
-	}
-	return def;
-}
-
-// actual loader/saver function
-void InitializeGame(int mode, uint size_x, uint size_y);
-extern bool AfterLoadGame(void);
-extern void BeforeSaveGame(void);
-extern bool LoadOldSaveGame(const char *file);
-
-/** Small helper function to close the to be loaded savegame an signal error */
-static inline SaveOrLoadResult AbortSaveLoad(void)
-{
-	if (_sl.fh != NULL) fclose(_sl.fh);
-
-	_sl.fh = NULL;
-	return SL_ERROR;
-}
-
-/** Update the gui accordingly when starting saving
- * and set locks on saveload. Also turn off fast-forward cause with that
- * saving takes Aaaaages */
-void SaveFileStart(void)
-{
-	_ts.ff_state = _fast_forward;
-	_fast_forward = false;
-	if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ);
-
-	SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
-	_ts.saveinprogress = true;
-}
-
-/** Update the gui accordingly when saving is done and release locks
- * on saveload */
-void SaveFileDone(void)
-{
-	_fast_forward = _ts.ff_state;
-	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
-
-	SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
-	_ts.saveinprogress = false;
-}
-
-/** Show a gui message when saving has failed */
-void SaveFileError(void)
-{
-	ShowErrorMessage(STR_4007_GAME_SAVE_FAILED, STR_NULL, 0, 0);
-	SaveFileDone();
-}
-
-static OTTDThread* save_thread;
-
-/** We have written the whole game into memory, _Savegame_pool, now find
- * and appropiate compressor and start writing to file.
- */
-static void* SaveFileToDisk(void *arg)
-{
-	const SaveLoadFormat *fmt;
-	uint32 hdr[2];
-
-	/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
-	 * loading/saving execute a longjmp() and continue execution here */
-	if (setjmp(_sl.excpt)) {
-		AbortSaveLoad();
-		_sl.excpt_uninit();
-
-		fprintf(stderr, "Save game failed: %s.", _sl.excpt_msg);
-		if (arg != NULL) {
-			OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
-		} else {
-			SaveFileError();
-		}
-		return NULL;
-	}
-
-	fmt = GetSavegameFormat(_savegame_format);
-
-	/* We have written our stuff to memory, now write it to file! */
-	hdr[0] = fmt->tag;
-	hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
-	if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError("file write failed");
-
-	if (!fmt->init_write()) SlError("cannot initialize compressor");
-
-	{
-		uint i;
-		uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
-
-		assert(_ts.count == _sl.offs_base);
-		for (i = 0; i != _Savegame_pool.current_blocks - 1; i++) {
-			_sl.buf = _Savegame_pool.blocks[i];
-			fmt->writer(count);
-		}
-
-		/* The last block is (almost) always not fully filled, so only write away
-		 * as much data as it is in there */
-		_sl.buf = _Savegame_pool.blocks[i];
-		fmt->writer(_ts.count - (i * count));
-	}
-
-	fmt->uninit_write();
-	assert(_ts.count == _sl.offs_base);
-	GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
-	fclose(_sl.fh);
-
-	if (arg != NULL) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
-	return NULL;
-}
-
-void WaitTillSaved(void)
-{
-	OTTDJoinThread(save_thread);
-	save_thread = NULL;
-}
-
-/**
- * Main Save or Load function where the high-level saveload functions are
- * handled. It opens the savegame, selects format and checks versions
- * @param filename The name of the savegame being created/loaded
- * @param mode Save or load. Load can also be a TTD(Patch) game. Use SL_LOAD, SL_OLD_LOAD or SL_SAVE
- * @return Return the results of the action. SL_OK, SL_ERROR or SL_REINIT ("unload" the game)
- */
-SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
-{
-	uint32 hdr[2];
-	const SaveLoadFormat *fmt;
-
-	/* An instance of saving is already active, so don't go saving again */
-	if (_ts.saveinprogress && mode == SL_SAVE) {
-		// if not an autosave, but a user action, show error message
-		if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
-		return SL_OK;
-	}
-	WaitTillSaved();
-
-	/* Load a TTDLX or TTDPatch game */
-	if (mode == SL_OLD_LOAD) {
-		InitializeGame(IG_DATE_RESET, 256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused
-		if (!LoadOldSaveGame(filename)) return SL_REINIT;
-		_sl_version = 0;
-		AfterLoadGame();
-		return SL_OK;
-	}
-
-	_sl.fh = (mode == SL_SAVE) ? fopen(filename, "wb") : fopen(filename, "rb");
-	if (_sl.fh == NULL) {
-		DEBUG(sl, 0, "Cannot open savegame '%s' for saving/loading.", filename);
-		return SL_ERROR;
-	}
-
-	_sl.bufe = _sl.bufp = NULL;
-	_sl.offs_base = 0;
-	_sl.save = mode;
-	_sl.includes = _desc_includes;
-	_sl.chs = _chunk_handlers;
-
-	/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
-	 * loading/saving execute a longjmp() and continue execution here */
-	if (setjmp(_sl.excpt)) {
-		AbortSaveLoad();
-
-		// deinitialize compressor.
-		_sl.excpt_uninit();
-
-		/* A saver/loader exception!! reinitialize all variables to prevent crash! */
-		if (mode == SL_LOAD) {
-			ShowInfoF("Load game failed: %s.", _sl.excpt_msg);
-			return SL_REINIT;
-		}
-
-		ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
-		return SL_ERROR;
-	}
-
-	/* General tactic is to first save the game to memory, then use an available writer
-	 * to write it to file, either in threaded mode if possible, or single-threaded */
-	if (mode == SL_SAVE) { /* SAVE game */
-		fmt = GetSavegameFormat("memory"); // write to memory
-
-		_sl.write_bytes = fmt->writer;
-		_sl.excpt_uninit = fmt->uninit_write;
-		if (!fmt->init_write()) {
-			DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
-			return AbortSaveLoad();
-		}
-
-		_sl_version = SAVEGAME_VERSION;
-
-		BeforeSaveGame();
-		SlSaveChunks();
-		SlWriteFill(); // flush the save buffer
-
-		SaveFileStart();
-		if (_network_server ||
-					(save_thread = OTTDCreateThread(&SaveFileToDisk, (void*)"")) == NULL) {
-			DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
-			SaveFileToDisk(NULL);
-			SaveFileDone();
-		}
-
-	} else { /* LOAD game */
-		assert(mode == SL_LOAD);
-
-		if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) {
-			DEBUG(sl, 0, "Cannot read savegame header, aborting");
-			return AbortSaveLoad();
-		}
-
-		// see if we have any loader for this type.
-		for (fmt = _saveload_formats; ; fmt++) {
-			/* No loader found, treat as version 0 and use LZO format */
-			if (fmt == endof(_saveload_formats)) {
-				DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
-				rewind(_sl.fh);
-				_sl_version = 0;
-				_sl_minor_version = 0;
-				fmt = _saveload_formats + 1; // LZO
-				break;
-			}
-
-			if (fmt->tag == hdr[0]) {
-				// check version number
-				_sl_version = TO_BE32(hdr[1]) >> 16;
-				/* Minor is not used anymore from version 18.0, but it is still needed
-				 *  in versions before that (4 cases) which can't be removed easy.
-				 *  Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
-				 *  So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
-				_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
-
-				DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
-
-				/* Is the version higher than the current? */
-				if (_sl_version > SAVEGAME_VERSION) {
-					DEBUG(sl, 0, "Savegame version invalid");
-					return AbortSaveLoad();
-				}
-				break;
-			}
-		}
-
-		_sl.read_bytes = fmt->reader;
-		_sl.excpt_uninit = fmt->uninit_read;
-
-		// loader for this savegame type is not implemented?
-		if (fmt->init_read == NULL) {
-			ShowInfoF("Loader for '%s' is not available.", fmt->name);
-			return AbortSaveLoad();
-		}
-
-		if (!fmt->init_read()) {
-			DEBUG(sl, 0, "Initializing loader '%s' failed", fmt->name);
-			return AbortSaveLoad();
-		}
-
-		/* Old maps were hardcoded to 256x256 and thus did not contain
-		 * any mapsize information. Pre-initialize to 256x256 to not to
-		 * confuse old games */
-		InitializeGame(IG_DATE_RESET, 256, 256);
-
-		SlLoadChunks();
-		fmt->uninit_read();
-		fclose(_sl.fh);
-
-		/* After loading fix up savegame for any internal changes that
-		 * might've occured since then. If it fails, load back the old game */
-		if (!AfterLoadGame()) return SL_REINIT;
-	}
-
-	return SL_OK;
-}
-
-/** Do a save when exiting the game (patch option) _patches.autosave_on_exit */
-void DoExitSave(void)
-{
-	char buf[200];
-	snprintf(buf, sizeof(buf), "%s%sexit.sav", _paths.autosave_dir, PATHSEP);
-	SaveOrLoad(buf, SL_SAVE);
-}
-
-#if 0
-/**
- * Function to get the type of the savegame by looking at the file header.
- * NOTICE: Not used right now, but could be used if extensions of savegames are garbled
- * @param file Savegame to be checked
- * @return SL_OLD_LOAD or SL_LOAD of the file
- */
-int GetSavegameType(char *file)
-{
-	const SaveLoadFormat *fmt;
-	uint32 hdr;
-	FILE *f;
-	int mode = SL_OLD_LOAD;
-
-	f = fopen(file, "rb");
-	if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
-		DEBUG(sl, 0, "Savegame is obsolete or invalid format");
-		mode = SL_LOAD; // don't try to get filename, just show name as it is written
-	} else {
-		// see if we have any loader for this type.
-		for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
-			if (fmt->tag == hdr) {
-				mode = SL_LOAD; // new type of savegame
-				break;
-			}
-		}
-	}
-
-	fclose(f);
-	return mode;
-}
-#endif
new file mode 100644
--- /dev/null
+++ b/src/saveload.cpp
@@ -0,0 +1,1686 @@
+/* $Id$ */
+
+/** @file
+ * All actions handling saving and loading goes on in this file. The general actions
+ * are as follows for saving a game (loading is analogous):
+ * <ol>
+ * <li>initialize the writer by creating a temporary memory-buffer for it
+ * <li>go through all to-be saved elements, each 'chunk' (ChunkHandler) prefixed by a label
+ * <li>use their description array (SaveLoad) to know what elements to save and in what version
+ *    of the game it was active (used when loading)
+ * <li>write all data byte-by-byte to the temporary buffer so it is endian-safe
+ * <li>when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe)
+ * <li>repeat this until everything is done, and flush any remaining output to file
+ * </ol>
+ * @see ChunkHandler
+ * @see SaveLoad
+ */
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "hal.h"
+#include "vehicle.h"
+#include "station.h"
+#include "thread.h"
+#include "town.h"
+#include "player.h"
+#include "saveload.h"
+#include "network/network.h"
+#include "variables.h"
+#include <setjmp.h>
+
+const uint16 SAVEGAME_VERSION = 43;
+uint16 _sl_version;       /// the major savegame version identifier
+byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
+
+typedef void WriterProc(uint len);
+typedef uint ReaderProc(void);
+
+/** The saveload struct, containing reader-writer functions, bufffer, version, etc. */
+static struct {
+	bool save;                           /// are we doing a save or a load atm. True when saving
+	byte need_length;                    /// ???
+	byte block_mode;                     /// ???
+	bool error;                          /// did an error occur or not
+
+	int obj_len;                         /// the length of the current object we are busy with
+	int array_index, last_array_index;   /// in the case of an array, the current and last positions
+
+	uint32 offs_base;                    /// the offset in number of bytes since we started writing data (eg uncompressed savegame size)
+
+	WriterProc *write_bytes;             /// savegame writer function
+	ReaderProc *read_bytes;              /// savegame loader function
+
+	const ChunkHandler* const *chs;      /// the chunk of data that is being processed atm (vehicles, signs, etc.)
+	const SaveLoad* const *includes;     /// the internal layouf of the given chunk
+
+	/** When saving/loading savegames, they are always saved to a temporary memory-place
+	 * to be flushed to file (save) or to final place (load) when full. */
+	byte *bufp, *bufe;                   /// bufp(ointer) gives the current position in the buffer bufe(nd) gives the end of the buffer
+
+	// these 3 may be used by compressor/decompressors.
+	byte *buf;                           /// pointer to temporary memory to read/write, initialized by SaveLoadFormat->initread/write
+	byte *buf_ori;                       /// pointer to the original memory location of buf, used to free it afterwards
+	uint bufsize;                        /// the size of the temporary memory *buf
+	FILE *fh;                            /// the file from which is read or written to
+
+	void (*excpt_uninit)(void);          /// the function to execute on any encountered error
+	const char *excpt_msg;               /// the error message
+	jmp_buf excpt;                       /// @todo used to jump to "exception handler";  really ugly
+} _sl;
+
+
+enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
+
+/**
+ * Fill the input buffer by reading from the file with the given reader
+ */
+static void SlReadFill(void)
+{
+	uint len = _sl.read_bytes();
+	assert(len != 0);
+
+	_sl.bufp = _sl.buf;
+	_sl.bufe = _sl.buf + len;
+	_sl.offs_base += len;
+}
+
+static inline uint32 SlGetOffs(void) {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
+
+/** Return the size in bytes of a certain type of normal/atomic variable
+ * as it appears in memory. @see VarTypes
+ * @param conv @VarType type of variable that is used for calculating the size
+ * @return Return the size of this type in bytes */
+static inline byte SlCalcConvMemLen(VarType conv)
+{
+	static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
+	byte length = GB(conv, 4, 4);
+	assert(length < lengthof(conv_mem_size));
+	return conv_mem_size[length];
+}
+
+/** Return the size in bytes of a certain type of normal/atomic variable
+ * as it appears in a saved game. @see VarTypes
+ * @param conv @VarType type of variable that is used for calculating the size
+ * @return Return the size of this type in bytes */
+static inline byte SlCalcConvFileLen(VarType conv)
+{
+	static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
+	byte length = GB(conv, 0, 4);
+	assert(length < lengthof(conv_file_size));
+	return conv_file_size[length];
+}
+
+/* Return the size in bytes of a reference (pointer) */
+static inline size_t SlCalcRefLen(void) {return 2;}
+
+/** Flush the output buffer by writing to disk with the given reader.
+ * If the buffer pointer has not yet been set up, set it up now. Usually
+ * only called when the buffer is full, or there is no more data to be processed
+ */
+static void SlWriteFill(void)
+{
+	// flush the buffer to disk (the writer)
+	if (_sl.bufp != NULL) {
+		uint len = _sl.bufp - _sl.buf;
+		_sl.offs_base += len;
+		if (len) _sl.write_bytes(len);
+	}
+
+	/* All the data from the buffer has been written away, rewind to the beginning
+	* to start reading in more data */
+	_sl.bufp = _sl.buf;
+	_sl.bufe = _sl.buf + _sl.bufsize;
+}
+
+/** Error handler, calls longjmp to simulate an exception.
+ * @todo this was used to have a central place to handle errors, but it is
+ * pretty ugly, and seriously interferes with any multithreaded approaches */
+static void NORETURN SlError(const char *msg)
+{
+	_sl.excpt_msg = msg;
+	longjmp(_sl.excpt, 0);
+}
+
+/** Read in a single byte from file. If the temporary buffer is full,
+ * flush it to its final destination
+ * @return return the read byte from file
+ */
+static inline byte SlReadByteInternal(void)
+{
+	if (_sl.bufp == _sl.bufe) SlReadFill();
+	return *_sl.bufp++;
+}
+
+/** Wrapper for SlReadByteInternal */
+byte SlReadByte(void) {return SlReadByteInternal();}
+
+/** Write away a single byte from memory. If the temporary buffer is full,
+ * flush it to its destination (file)
+ * @param b the byte that is currently written
+ */
+static inline void SlWriteByteInternal(byte b)
+{
+	if (_sl.bufp == _sl.bufe) SlWriteFill();
+	*_sl.bufp++ = b;
+}
+
+/** Wrapper for SlWriteByteInternal */
+void SlWriteByte(byte b) {SlWriteByteInternal(b);}
+
+static inline int SlReadUint16(void)
+{
+	int x = SlReadByte() << 8;
+	return x | SlReadByte();
+}
+
+static inline uint32 SlReadUint32(void)
+{
+	uint32 x = SlReadUint16() << 16;
+	return x | SlReadUint16();
+}
+
+static inline uint64 SlReadUint64(void)
+{
+	uint32 x = SlReadUint32();
+	uint32 y = SlReadUint32();
+	return (uint64)x << 32 | y;
+}
+
+static inline void SlWriteUint16(uint16 v)
+{
+	SlWriteByte(GB(v, 8, 8));
+	SlWriteByte(GB(v, 0, 8));
+}
+
+static inline void SlWriteUint32(uint32 v)
+{
+	SlWriteUint16(GB(v, 16, 16));
+	SlWriteUint16(GB(v,  0, 16));
+}
+
+static inline void SlWriteUint64(uint64 x)
+{
+	SlWriteUint32((uint32)(x >> 32));
+	SlWriteUint32((uint32)x);
+}
+
+/**
+ * Read in the header descriptor of an object or an array.
+ * If the highest bit is set (7), then the index is bigger than 127
+ * elements, so use the next byte to read in the real value.
+ * The actual value is then both bytes added with the first shifted
+ * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
+ * x = ((x & 0x7F) << 8) + SlReadByte();
+ * @return Return the value of the index
+ */
+static uint SlReadSimpleGamma(void)
+{
+	uint i = SlReadByte();
+	if (HASBIT(i, 7)) {
+		i &= ~0x80;
+		if (HASBIT(i, 6)) {
+			i &= ~0x40;
+			if (HASBIT(i, 5)) {
+				i &= ~0x20;
+				if (HASBIT(i, 4))
+					SlError("Unsupported gamma");
+				i = (i << 8) | SlReadByte();
+			}
+			i = (i << 8) | SlReadByte();
+		}
+		i = (i << 8) | SlReadByte();
+	}
+	return i;
+}
+
+/**
+ * Write the header descriptor of an object or an array.
+ * If the element is bigger than 127, use 2 bytes for saving
+ * and use the highest byte of the first written one as a notice
+ * that the length consists of 2 bytes, etc.. like this:
+ * 0xxxxxxx
+ * 10xxxxxx xxxxxxxx
+ * 110xxxxx xxxxxxxx xxxxxxxx
+ * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
+ * @param i Index being written
+ */
+
+static void SlWriteSimpleGamma(uint i)
+{
+	if (i >= (1 << 7)) {
+		if (i >= (1 << 14)) {
+			if (i >= (1 << 21)) {
+				assert(i < (1 << 28));
+				SlWriteByte((byte)0xE0 | (i>>24));
+				SlWriteByte((byte)(i>>16));
+			} else {
+				SlWriteByte((byte)0xC0 | (i>>16));
+			}
+			SlWriteByte((byte)(i>>8));
+		} else {
+			SlWriteByte((byte)(0x80 | (i>>8)));
+		}
+	}
+	SlWriteByte(i);
+}
+
+/** Return how many bytes used to encode a gamma value */
+static inline uint SlGetGammaLength(uint i) {
+	return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
+}
+
+static inline uint SlReadSparseIndex(void) {return SlReadSimpleGamma();}
+static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
+
+static inline uint SlReadArrayLength(void) {return SlReadSimpleGamma();}
+static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
+static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
+
+void SlSetArrayIndex(uint index)
+{
+	_sl.need_length = NL_WANTLENGTH;
+	_sl.array_index = index;
+}
+
+/**
+ * Iterate through the elements of an array and read the whole thing
+ * @return The index of the object, or -1 if we have reached the end of current block
+ */
+int SlIterateArray(void)
+{
+	int index;
+	static uint32 next_offs;
+
+	/* After reading in the whole array inside the loop
+	 * we must have read in all the data, so we must be at end of current block. */
+	assert(next_offs == 0 || SlGetOffs() == next_offs);
+
+	while (true) {
+		uint length = SlReadArrayLength();
+		if (length == 0) {
+			next_offs = 0;
+			return -1;
+		}
+
+		_sl.obj_len = --length;
+		next_offs = SlGetOffs() + length;
+
+		switch (_sl.block_mode) {
+		case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
+		case CH_ARRAY:        index = _sl.array_index++; break;
+		default:
+			DEBUG(sl, 0, "SlIterateArray error");
+			return -1; // error
+		}
+
+		if (length != 0) return index;
+	}
+}
+
+/**
+ * Sets the length of either a RIFF object or the number of items in an array.
+ * This lets us load an object or an array of arbitrary size
+ * @param length The length of the sought object/array
+ */
+void SlSetLength(size_t length)
+{
+	assert(_sl.save);
+
+	switch (_sl.need_length) {
+	case NL_WANTLENGTH:
+		_sl.need_length = NL_NONE;
+		switch (_sl.block_mode) {
+		case CH_RIFF:
+			// Ugly encoding of >16M RIFF chunks
+			// The lower 24 bits are normal
+			// The uppermost 4 bits are bits 24:27
+			assert(length < (1<<28));
+			SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
+			break;
+		case CH_ARRAY:
+			assert(_sl.last_array_index <= _sl.array_index);
+			while (++_sl.last_array_index <= _sl.array_index)
+				SlWriteArrayLength(1);
+			SlWriteArrayLength(length + 1);
+			break;
+		case CH_SPARSE_ARRAY:
+			SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
+			SlWriteSparseIndex(_sl.array_index);
+			break;
+		default: NOT_REACHED();
+		} break;
+	case NL_CALCLENGTH:
+		_sl.obj_len += length;
+		break;
+	}
+}
+
+/**
+ * Save/Load bytes. These do not need to be converted to Little/Big Endian
+ * so directly write them or read them to/from file
+ * @param ptr The source or destination of the object being manipulated
+ * @param length number of bytes this fast CopyBytes lasts
+ */
+static void SlCopyBytes(void *ptr, size_t length)
+{
+	byte *p = (byte*)ptr;
+
+	if (_sl.save) {
+		for (; length != 0; length--) {SlWriteByteInternal(*p++);}
+	} else {
+		for (; length != 0; length--) {*p++ = SlReadByteInternal();}
+	}
+}
+
+/** Read in bytes from the file/data structure but don't do
+ * anything with them, discarding them in effect
+ * @param length The amount of bytes that is being treated this way
+ */
+static inline void SlSkipBytes(size_t length)
+{
+	for (; length != 0; length--) SlReadByte();
+}
+
+/* Get the length of the current object */
+uint SlGetFieldLength(void) {return _sl.obj_len;}
+
+/** Return a signed-long version of the value of a setting
+ * @param ptr pointer to the variable
+ * @param conv type of variable, can be a non-clean
+ * type, eg one with other flags because it is parsed
+ * @return returns the value of the pointer-setting */
+int64 ReadValue(const void *ptr, VarType conv)
+{
+	switch (GetVarMemType(conv)) {
+	case SLE_VAR_BL:  return (*(bool*)ptr != 0);
+	case SLE_VAR_I8:  return *(int8*  )ptr;
+	case SLE_VAR_U8:  return *(byte*  )ptr;
+	case SLE_VAR_I16: return *(int16* )ptr;
+	case SLE_VAR_U16: return *(uint16*)ptr;
+	case SLE_VAR_I32: return *(int32* )ptr;
+	case SLE_VAR_U32: return *(uint32*)ptr;
+	case SLE_VAR_I64: return *(int64* )ptr;
+	case SLE_VAR_U64: return *(uint64*)ptr;
+	case SLE_VAR_NULL:return 0;
+	default: NOT_REACHED();
+	}
+
+	/* useless, but avoids compiler warning this way */
+	return 0;
+}
+
+/** Write the value of a setting
+ * @param ptr pointer to the variable
+ * @param conv type of variable, can be a non-clean type, eg
+ * with other flags. It is parsed upon read
+ * @param var the new value being given to the variable */
+void WriteValue(void *ptr, VarType conv, int64 val)
+{
+	switch (GetVarMemType(conv)) {
+	case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
+	case SLE_VAR_I8:  *(int8  *)ptr = val; break;
+	case SLE_VAR_U8:  *(byte  *)ptr = val; break;
+	case SLE_VAR_I16: *(int16 *)ptr = val; break;
+	case SLE_VAR_U16: *(uint16*)ptr = val; break;
+	case SLE_VAR_I32: *(int32 *)ptr = val; break;
+	case SLE_VAR_U32: *(uint32*)ptr = val; break;
+	case SLE_VAR_I64: *(int64 *)ptr = val; break;
+	case SLE_VAR_U64: *(uint64*)ptr = val; break;
+	case SLE_VAR_NULL: break;
+	default: NOT_REACHED();
+	}
+}
+
+/**
+ * Handle all conversion and typechecking of variables here.
+ * In the case of saving, read in the actual value from the struct
+ * and then write them to file, endian safely. Loading a value
+ * goes exactly the opposite way
+ * @param ptr The object being filled/read
+ * @param conv @VarType type of the current element of the struct
+ */
+static void SlSaveLoadConv(void *ptr, VarType conv)
+{
+	int64 x = 0;
+
+	if (_sl.save) { /* SAVE values */
+		/* Read a value from the struct. These ARE endian safe. */
+		x = ReadValue(ptr, conv);
+
+		/* Write the value to the file and check if its value is in the desired range */
+		switch (GetVarFileType(conv)) {
+		case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
+		case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
+		case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
+		case SLE_FILE_STRINGID:
+		case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
+		case SLE_FILE_I32:
+		case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
+		case SLE_FILE_I64:
+		case SLE_FILE_U64:                                   SlWriteUint64(x);break;
+		default: NOT_REACHED();
+		}
+	} else { /* LOAD values */
+
+		/* Read a value from the file */
+		switch (GetVarFileType(conv)) {
+		case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
+		case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
+		case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
+		case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
+		case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
+		case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
+		case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
+		case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
+		case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
+		default: NOT_REACHED();
+		}
+
+		/* Write The value to the struct. These ARE endian safe. */
+		WriteValue(ptr, conv, x);
+	}
+}
+
+/** Calculate the net length of a string. This is in almost all cases
+ * just strlen(), but if the string is not properly terminated, we'll
+ * resort to the maximum length of the buffer.
+ * @param ptr pointer to the stringbuffer
+ * @param length maximum length of the string (buffer). If -1 we don't care
+ * about a maximum length, but take string length as it is.
+ * @return return the net length of the string */
+static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
+{
+	return minu(strlen(ptr), length - 1);
+}
+
+/** Calculate the gross length of the string that it
+ * will occupy in the savegame. This includes the real length, returned
+ * by SlCalcNetStringLen and the length that the index will occupy.
+ * @param ptr pointer to the stringbuffer
+ * @param length maximum length of the string (buffer size, etc.)
+ * @return return the gross length of the string */
+static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
+{
+	size_t len;
+	const char *str;
+
+	switch (GetVarMemType(conv)) {
+		default: NOT_REACHED();
+		case SLE_VAR_STR:
+		case SLE_VAR_STRQ:
+			str = *(const char**)ptr;
+			len = -1;
+			break;
+		case SLE_VAR_STRB:
+		case SLE_VAR_STRBQ:
+			str = (const char*)ptr;
+			len = length;
+			break;
+	}
+
+	len = SlCalcNetStringLen(str, len);
+	return len + SlGetArrayLength(len); // also include the length of the index
+}
+
+/**
+ * Save/Load a string.
+ * @param ptr the string being manipulated
+ * @param the length of the string (full length)
+ * @param conv must be SLE_FILE_STRING */
+static void SlString(void *ptr, size_t length, VarType conv)
+{
+	size_t len;
+
+	if (_sl.save) { /* SAVE string */
+		switch (GetVarMemType(conv)) {
+			default: NOT_REACHED();
+			case SLE_VAR_STRB:
+			case SLE_VAR_STRBQ:
+				len = SlCalcNetStringLen(ptr, length);
+				break;
+			case SLE_VAR_STR:
+			case SLE_VAR_STRQ:
+				ptr = *(char**)ptr;
+				len = SlCalcNetStringLen(ptr, -1);
+				break;
+		}
+
+		SlWriteArrayLength(len);
+		SlCopyBytes(ptr, len);
+	} else { /* LOAD string */
+		len = SlReadArrayLength();
+
+		switch (GetVarMemType(conv)) {
+			default: NOT_REACHED();
+			case SLE_VAR_STRB:
+			case SLE_VAR_STRBQ:
+				if (len >= length) {
+					DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
+					SlCopyBytes(ptr, length);
+					SlSkipBytes(len - length);
+					len = length - 1;
+				} else {
+					SlCopyBytes(ptr, len);
+				}
+				break;
+			case SLE_VAR_STR:
+			case SLE_VAR_STRQ: /* Malloc'd string, free previous incarnation, and allocate */
+				free(*(char**)ptr);
+				*(char**)ptr = malloc(len + 1); // terminating '\0'
+				ptr = *(char**)ptr;
+				SlCopyBytes(ptr, len);
+				break;
+		}
+
+		((char*)ptr)[len] = '\0'; // properly terminate the string
+	}
+}
+
+/**
+ * Return the size in bytes of a certain type of atomic array
+ * @param length The length of the array counted in elements
+ * @param conv @VarType type of the variable that is used in calculating the size
+ */
+static inline size_t SlCalcArrayLen(uint length, VarType conv)
+{
+	return SlCalcConvFileLen(conv) * length;
+}
+
+/**
+ * Save/Load an array.
+ * @param array The array being manipulated
+ * @param length The length of the array in elements
+ * @param conv @VarType type of the atomic array (int, byte, uint64, etc.)
+ */
+void SlArray(void *array, uint length, VarType conv)
+{
+	// Automatically calculate the length?
+	if (_sl.need_length != NL_NONE) {
+		SlSetLength(SlCalcArrayLen(length, conv));
+		// Determine length only?
+		if (_sl.need_length == NL_CALCLENGTH) return;
+	}
+
+	/* NOTICE - handle some buggy stuff, in really old versions everything was saved
+	 * as a byte-type. So detect this, and adjust array size accordingly */
+	if (!_sl.save && _sl_version == 0) {
+		if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
+				conv == SLE_INT32 || conv == SLE_UINT32) {
+			length *= SlCalcConvFileLen(conv);
+			conv = SLE_INT8;
+		}
+	}
+
+	/* If the size of elements is 1 byte both in file and memory, no special
+	 * conversion is needed, use specialized copy-copy function to speed up things */
+	if (conv == SLE_INT8 || conv == SLE_UINT8) {
+		SlCopyBytes(array, length);
+	} else {
+		byte *a = (byte*)array;
+		byte mem_size = SlCalcConvMemLen(conv);
+
+		for (; length != 0; length --) {
+			SlSaveLoadConv(a, conv);
+			a += mem_size; // get size
+		}
+	}
+}
+
+/* Are we going to save this object or not? */
+static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
+{
+	if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
+	if (sld->conv & SLF_SAVE_NO) return false;
+
+	return true;
+}
+
+/** Are we going to load this variable when loading a savegame or not?
+ * @note If the variable is skipped it is skipped in the savegame
+ * bytestream itself as well, so there is no need to skip it somewhere else */
+static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
+{
+	if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
+		SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Calculate the size of an object.
+ * @param sld The @SaveLoad description of the object so we know how to manipulate it
+ */
+static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
+{
+	size_t length = 0;
+
+	// Need to determine the length and write a length tag.
+	for (; sld->cmd != SL_END; sld++) {
+		length += SlCalcObjMemberLength(object, sld);
+	}
+	return length;
+}
+
+size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
+{
+	assert(_sl.save);
+
+	switch (sld->cmd) {
+		case SL_VAR:
+		case SL_REF:
+		case SL_ARR:
+		case SL_STR:
+			/* CONDITIONAL saveload types depend on the savegame version */
+			if (!SlIsObjectValidInSavegame(sld)) break;
+
+			switch (sld->cmd) {
+			case SL_VAR: return SlCalcConvFileLen(sld->conv);
+			case SL_REF: return SlCalcRefLen();
+			case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
+			case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
+			default: NOT_REACHED();
+			}
+			break;
+		case SL_WRITEBYTE: return 1; // a byte is logically of size 1
+		case SL_INCLUDE: return SlCalcObjLength(object, _sl.includes[sld->version_from]);
+		default: NOT_REACHED();
+	}
+	return 0;
+}
+
+
+static uint ReferenceToInt(const void* obj, SLRefType rt);
+static void* IntToReference(uint index, SLRefType rt);
+
+
+bool SlObjectMember(void *ptr, const SaveLoad *sld)
+{
+	VarType conv = GB(sld->conv, 0, 8);
+	switch (sld->cmd) {
+	case SL_VAR:
+	case SL_REF:
+	case SL_ARR:
+	case SL_STR:
+		/* CONDITIONAL saveload types depend on the savegame version */
+		if (!SlIsObjectValidInSavegame(sld)) return false;
+		if (SlSkipVariableOnLoad(sld)) return false;
+
+		switch (sld->cmd) {
+		case SL_VAR: SlSaveLoadConv(ptr, conv); break;
+		case SL_REF: /* Reference variable, translate */
+			/// @todo XXX - another artificial limitof 65K elements of pointers?
+			if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces?
+				SlWriteUint16(ReferenceToInt(*(void**)ptr, conv));
+			} else {
+				*(void**)ptr = IntToReference(SlReadUint16(), conv);
+			}
+			break;
+		case SL_ARR: SlArray(ptr, sld->length, conv); break;
+		case SL_STR: SlString(ptr, sld->length, conv); break;
+		default: NOT_REACHED();
+		}
+		break;
+
+	/* SL_WRITEBYTE translates a value of a variable to another one upon
+   * saving or loading.
+   * XXX - variable renaming abuse
+   * game_value: the value of the variable ingame is abused by sld->version_from
+   * file_value: the value of the variable in the savegame is abused by sld->version_to */
+	case SL_WRITEBYTE:
+		if (_sl.save) {
+			SlWriteByte(sld->version_to);
+		} else {
+			*(byte*)ptr = sld->version_from;
+		}
+		break;
+
+	/* SL_INCLUDE loads common code for a type
+	 * XXX - variable renaming abuse
+	 * include_index: common code to include from _desc_includes[], abused by sld->version_from */
+	case SL_INCLUDE:
+		SlObject(ptr, _sl.includes[sld->version_from]);
+		break;
+	default: NOT_REACHED();
+	}
+	return true;
+}
+
+/**
+ * Main SaveLoad function.
+ * @param object The object that is being saved or loaded
+ * @param sld The @SaveLoad description of the object so we know how to manipulate it
+ */
+void SlObject(void *object, const SaveLoad *sld)
+{
+	// Automatically calculate the length?
+	if (_sl.need_length != NL_NONE) {
+		SlSetLength(SlCalcObjLength(object, sld));
+		if (_sl.need_length == NL_CALCLENGTH) return;
+	}
+
+	for (; sld->cmd != SL_END; sld++) {
+		void *ptr = GetVariableAddress(object, sld);
+		SlObjectMember(ptr, sld);
+	}
+}
+
+/**
+ * Save or Load (a list of) global variables
+ * @param desc The global variable that is being loaded or saved
+ */
+void SlGlobList(const SaveLoadGlobVarList *sldg)
+{
+	if (_sl.need_length != NL_NONE) {
+		SlSetLength(SlCalcObjLength(NULL, (const SaveLoad*)sldg));
+		if (_sl.need_length == NL_CALCLENGTH) return;
+	}
+
+	for (; sldg->cmd != SL_END; sldg++) {
+		SlObjectMember(sldg->address, (const SaveLoad*)sldg);
+	}
+}
+
+/**
+ * Do something of which I have no idea what it is :P
+ * @param proc The callback procedure that is called
+ * @param arg The variable that will be used for the callback procedure
+ */
+void SlAutolength(AutolengthProc *proc, void *arg)
+{
+	uint32 offs;
+
+	assert(_sl.save);
+
+	// Tell it to calculate the length
+	_sl.need_length = NL_CALCLENGTH;
+	_sl.obj_len = 0;
+	proc(arg);
+
+	// Setup length
+	_sl.need_length = NL_WANTLENGTH;
+	SlSetLength(_sl.obj_len);
+
+	offs = SlGetOffs() + _sl.obj_len;
+
+	// And write the stuff
+	proc(arg);
+
+	assert(offs == SlGetOffs());
+}
+
+/**
+ * Load a chunk of data (eg vehicles, stations, etc.)
+ * @param ch The chunkhandler that will be used for the operation
+ */
+static void SlLoadChunk(const ChunkHandler *ch)
+{
+	byte m = SlReadByte();
+	size_t len;
+	uint32 endoffs;
+
+	_sl.block_mode = m;
+	_sl.obj_len = 0;
+
+	switch (m) {
+	case CH_ARRAY:
+		_sl.array_index = 0;
+		ch->load_proc();
+		break;
+	case CH_SPARSE_ARRAY:
+		ch->load_proc();
+		break;
+	default:
+		if ((m & 0xF) == CH_RIFF) {
+			// Read length
+			len = (SlReadByte() << 16) | ((m >> 4) << 24);
+			len += SlReadUint16();
+			_sl.obj_len = len;
+			endoffs = SlGetOffs() + len;
+			ch->load_proc();
+			assert(SlGetOffs() == endoffs);
+		} else {
+			SlError("Invalid chunk type");
+		}
+		break;
+	}
+}
+
+/* Stub Chunk handlers to only calculate length and do nothing else */
+static ChunkSaveLoadProc *_tmp_proc_1;
+static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
+static void SlStubSaveProc(void) {SlAutolength(SlStubSaveProc2, NULL);}
+
+/** Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
+ * prefixed by an ID identifying it, followed by data, and terminator where appropiate
+ * @param ch The chunkhandler that will be used for the operation
+ */
+static void SlSaveChunk(const ChunkHandler *ch)
+{
+	ChunkSaveLoadProc *proc = ch->save_proc;
+
+	SlWriteUint32(ch->id);
+	DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
+
+	if (ch->flags & CH_AUTO_LENGTH) {
+		// Need to calculate the length. Solve that by calling SlAutoLength in the save_proc.
+		_tmp_proc_1 = proc;
+		proc = SlStubSaveProc;
+	}
+
+	_sl.block_mode = ch->flags & CH_TYPE_MASK;
+	switch (ch->flags & CH_TYPE_MASK) {
+	case CH_RIFF:
+		_sl.need_length = NL_WANTLENGTH;
+		proc();
+		break;
+	case CH_ARRAY:
+		_sl.last_array_index = 0;
+		SlWriteByte(CH_ARRAY);
+		proc();
+		SlWriteArrayLength(0); // Terminate arrays
+		break;
+	case CH_SPARSE_ARRAY:
+		SlWriteByte(CH_SPARSE_ARRAY);
+		proc();
+		SlWriteArrayLength(0); // Terminate arrays
+		break;
+	default: NOT_REACHED();
+	}
+}
+
+/** Save all chunks */
+static void SlSaveChunks(void)
+{
+	const ChunkHandler *ch;
+	const ChunkHandler* const *chsc;
+	uint p;
+
+	for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
+		for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
+			while (true) {
+				if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
+					SlSaveChunk(ch);
+				if (ch->flags & CH_LAST)
+					break;
+				ch++;
+			}
+		}
+	}
+
+	// Terminator
+	SlWriteUint32(0);
+}
+
+/** Find the ChunkHandler that will be used for processing the found
+ * chunk in the savegame or in memory
+ * @param id the chunk in question
+ * @return returns the appropiate chunkhandler
+ */
+static const ChunkHandler *SlFindChunkHandler(uint32 id)
+{
+	const ChunkHandler *ch;
+	const ChunkHandler *const *chsc;
+	for (chsc = _sl.chs; (ch=*chsc++) != NULL;) {
+		for (;;) {
+			if (ch->id == id) return ch;
+			if (ch->flags & CH_LAST) break;
+			ch++;
+		}
+	}
+	return NULL;
+}
+
+/** Load all chunks */
+static void SlLoadChunks(void)
+{
+	uint32 id;
+	const ChunkHandler *ch;
+
+	for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
+		DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
+
+		ch = SlFindChunkHandler(id);
+		if (ch == NULL) SlError("found unknown tag in savegame (sync error)");
+		SlLoadChunk(ch);
+	}
+}
+
+//*******************************************
+//********** START OF LZO CODE **************
+//*******************************************
+#define LZO_SIZE 8192
+
+#include "minilzo.h"
+
+static uint ReadLZO(void)
+{
+	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
+	uint32 tmp[2];
+	uint32 size;
+	uint len;
+
+	// Read header
+	if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError("file read failed");
+
+	// Check if size is bad
+	((uint32*)out)[0] = size = tmp[1];
+
+	if (_sl_version != 0) {
+		tmp[0] = TO_BE32(tmp[0]);
+		size = TO_BE32(size);
+	}
+
+	if (size >= sizeof(out)) SlError("inconsistent size");
+
+	// Read block
+	if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError("file read failed");
+
+	// Verify checksum
+	if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError("bad checksum");
+
+	// Decompress
+	lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
+	return len;
+}
+
+// p contains the pointer to the buffer, len contains the pointer to the length.
+// len bytes will be written, p and l will be updated to reflect the next buffer.
+static void WriteLZO(uint size)
+{
+	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
+	byte wrkmem[sizeof(byte*)*4096];
+	uint outlen;
+
+	lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
+	((uint32*)out)[1] = TO_BE32(outlen);
+	((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
+	if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError("file write failed");
+}
+
+static bool InitLZO(void)
+{
+	_sl.bufsize = LZO_SIZE;
+	_sl.buf = _sl.buf_ori = (byte*)malloc(LZO_SIZE);
+	return true;
+}
+
+static void UninitLZO(void)
+{
+	free(_sl.buf_ori);
+}
+
+//*********************************************
+//******** START OF NOCOMP CODE (uncompressed)*
+//*********************************************
+static uint ReadNoComp(void)
+{
+	return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
+}
+
+static void WriteNoComp(uint size)
+{
+	fwrite(_sl.buf, 1, size, _sl.fh);
+}
+
+static bool InitNoComp(void)
+{
+	_sl.bufsize = LZO_SIZE;
+	_sl.buf = _sl.buf_ori =(byte*)malloc(LZO_SIZE);
+	return true;
+}
+
+static void UninitNoComp(void)
+{
+	free(_sl.buf_ori);
+}
+
+//********************************************
+//********** START OF MEMORY CODE (in ram)****
+//********************************************
+
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "gfx.h"
+#include "gui.h"
+
+typedef struct ThreadedSave {
+	uint count;
+	bool ff_state;
+	bool saveinprogress;
+	CursorID cursor;
+} ThreadedSave;
+
+/* A maximum size of of 128K * 500 = 64.000KB savegames */
+STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
+static ThreadedSave _ts;
+
+static bool InitMem(void)
+{
+	_ts.count = 0;
+
+	CleanPool(&_Savegame_pool);
+	AddBlockToPool(&_Savegame_pool);
+
+	/* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
+	_sl.bufsize = GetSavegamePoolSize();
+	_sl.buf = GetSavegame(_ts.count);
+	return true;
+}
+
+static void UnInitMem(void)
+{
+	CleanPool(&_Savegame_pool);
+}
+
+static void WriteMem(uint size)
+{
+	_ts.count += size;
+	/* Allocate new block and new buffer-pointer */
+	AddBlockIfNeeded(&_Savegame_pool, _ts.count);
+	_sl.buf = GetSavegame(_ts.count);
+}
+
+//********************************************
+//********** START OF ZLIB CODE **************
+//********************************************
+
+#if defined(WITH_ZLIB)
+#include <zlib.h>
+
+static z_stream _z;
+
+static bool InitReadZlib(void)
+{
+	memset(&_z, 0, sizeof(_z));
+	if (inflateInit(&_z) != Z_OK) return false;
+
+	_sl.bufsize = 4096;
+	_sl.buf = _sl.buf_ori = (byte*)malloc(4096 + 4096); // also contains fread buffer
+	return true;
+}
+
+static uint ReadZlib(void)
+{
+	int r;
+
+	_z.next_out = _sl.buf;
+	_z.avail_out = 4096;
+
+	do {
+		// read more bytes from the file?
+		if (_z.avail_in == 0) {
+			_z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
+		}
+
+		// inflate the data
+		r = inflate(&_z, 0);
+		if (r == Z_STREAM_END)
+			break;
+
+		if (r != Z_OK)
+			SlError("inflate() failed");
+	} while (_z.avail_out);
+
+	return 4096 - _z.avail_out;
+}
+
+static void UninitReadZlib(void)
+{
+	inflateEnd(&_z);
+	free(_sl.buf_ori);
+}
+
+static bool InitWriteZlib(void)
+{
+	memset(&_z, 0, sizeof(_z));
+	if (deflateInit(&_z, 6) != Z_OK) return false;
+
+	_sl.bufsize = 4096;
+	_sl.buf = _sl.buf_ori = (byte*)malloc(4096); // also contains fread buffer
+	return true;
+}
+
+static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
+{
+	byte buf[1024]; // output buffer
+	int r;
+	uint n;
+	z->next_in = p;
+	z->avail_in = len;
+	do {
+		z->next_out = buf;
+		z->avail_out = sizeof(buf);
+		r = deflate(z, mode);
+			// bytes were emitted?
+		if ((n=sizeof(buf) - z->avail_out) != 0) {
+			if (fwrite(buf, n, 1, _sl.fh) != 1) SlError("file write error");
+		}
+		if (r == Z_STREAM_END)
+			break;
+		if (r != Z_OK) SlError("zlib returned error code");
+	} while (z->avail_in || !z->avail_out);
+}
+
+static void WriteZlib(uint len)
+{
+	WriteZlibLoop(&_z, _sl.buf, len, 0);
+}
+
+static void UninitWriteZlib(void)
+{
+	// flush any pending output.
+	if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
+	deflateEnd(&_z);
+	free(_sl.buf_ori);
+}
+
+#endif /* WITH_ZLIB */
+
+//*******************************************
+//************* END OF CODE *****************
+//*******************************************
+
+// these define the chunks
+extern const ChunkHandler _misc_chunk_handlers[];
+extern const ChunkHandler _setting_chunk_handlers[];
+extern const ChunkHandler _player_chunk_handlers[];
+extern const ChunkHandler _engine_chunk_handlers[];
+extern const ChunkHandler _veh_chunk_handlers[];
+extern const ChunkHandler _waypoint_chunk_handlers[];
+extern const ChunkHandler _depot_chunk_handlers[];
+extern const ChunkHandler _order_chunk_handlers[];
+extern const ChunkHandler _town_chunk_handlers[];
+extern const ChunkHandler _sign_chunk_handlers[];
+extern const ChunkHandler _station_chunk_handlers[];
+extern const ChunkHandler _industry_chunk_handlers[];
+extern const ChunkHandler _economy_chunk_handlers[];
+extern const ChunkHandler _animated_tile_chunk_handlers[];
+extern const ChunkHandler _newgrf_chunk_handlers[];
+
+static const ChunkHandler * const _chunk_handlers[] = {
+	_misc_chunk_handlers,
+	_setting_chunk_handlers,
+	_veh_chunk_handlers,
+	_waypoint_chunk_handlers,
+	_depot_chunk_handlers,
+	_order_chunk_handlers,
+	_industry_chunk_handlers,
+	_economy_chunk_handlers,
+	_engine_chunk_handlers,
+	_town_chunk_handlers,
+	_sign_chunk_handlers,
+	_station_chunk_handlers,
+	_player_chunk_handlers,
+	_animated_tile_chunk_handlers,
+	_newgrf_chunk_handlers,
+	NULL,
+};
+
+// used to include a vehicle desc in another desc.
+extern const SaveLoad _common_veh_desc[];
+static const SaveLoad* const _desc_includes[] = {
+	_common_veh_desc
+};
+
+/**
+ * Pointers cannot be saved to a savegame, so this functions gets
+ * the index of the item, and if not available, it hussles with
+ * pointers (looks really bad :()
+ * Remember that a NULL item has value 0, and all
+ * indeces have +1, so vehicle 0 is saved as index 1.
+ * @param obj The object that we want to get the index of
+ * @param rt @SLRefType type of the object the index is being sought of
+ * @return Return the pointer converted to an index of the type pointed to
+ */
+static uint ReferenceToInt(const void *obj, SLRefType rt)
+{
+	if (obj == NULL) return 0;
+
+	switch (rt) {
+		case REF_VEHICLE_OLD: // Old vehicles we save as new onces
+		case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
+		case REF_STATION:   return ((const  Station*)obj)->index + 1;
+		case REF_TOWN:      return ((const     Town*)obj)->index + 1;
+		case REF_ORDER:     return ((const    Order*)obj)->index + 1;
+		case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
+		case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
+		default: NOT_REACHED();
+	}
+
+	return 0; // avoid compiler warning
+}
+
+/**
+ * Pointers cannot be loaded from a savegame, so this function
+ * gets the index from the savegame and returns the appropiate
+ * pointer from the already loaded base.
+ * Remember that an index of 0 is a NULL pointer so all indeces
+ * are +1 so vehicle 0 is saved as 1.
+ * @param index The index that is being converted to a pointer
+ * @param rt @SLRefType type of the object the pointer is sought of
+ * @return Return the index converted to a pointer of any type
+ */
+static void *IntToReference(uint index, SLRefType rt)
+{
+	/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
+	 * and should be loaded like that */
+	if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4))
+		rt = REF_VEHICLE;
+
+	/* No need to look up NULL pointers, just return immediately */
+	if (rt != REF_VEHICLE_OLD && index == 0)
+		return NULL;
+
+	index--; // correct for the NULL index
+
+	switch (rt) {
+		case REF_ORDER: {
+			if (!AddBlockIfNeeded(&_Order_pool, index))
+				error("Orders: failed loading savegame: too many orders");
+			return GetOrder(index);
+		}
+		case REF_VEHICLE: {
+			if (!AddBlockIfNeeded(&_Vehicle_pool, index))
+				error("Vehicles: failed loading savegame: too many vehicles");
+			return GetVehicle(index);
+		}
+		case REF_STATION: {
+			if (!AddBlockIfNeeded(&_Station_pool, index))
+				error("Stations: failed loading savegame: too many stations");
+			return GetStation(index);
+		}
+		case REF_TOWN: {
+			if (!AddBlockIfNeeded(&_Town_pool, index))
+				error("Towns: failed loading savegame: too many towns");
+			return GetTown(index);
+		}
+		case REF_ROADSTOPS: {
+			if (!AddBlockIfNeeded(&_RoadStop_pool, index))
+				error("RoadStops: failed loading savegame: too many RoadStops");
+			return GetRoadStop(index);
+		}
+		case REF_ENGINE_RENEWS: {
+			if (!AddBlockIfNeeded(&_EngineRenew_pool, index))
+				error("EngineRenews: failed loading savegame: too many EngineRenews");
+			return GetEngineRenew(index);
+		}
+
+		case REF_VEHICLE_OLD: {
+			/* Old vehicles were saved differently:
+			 * invalid vehicle was 0xFFFF,
+			 * and the index was not - 1.. correct for this */
+			index++;
+			if (index == INVALID_VEHICLE)
+				return NULL;
+
+			if (!AddBlockIfNeeded(&_Vehicle_pool, index))
+				error("Vehicles: failed loading savegame: too many vehicles");
+			return GetVehicle(index);
+		}
+		default: NOT_REACHED();
+	}
+
+	return NULL;
+}
+
+/** The format for a reader/writer type of a savegame */
+typedef struct {
+	const char *name;           /// name of the compressor/decompressor (debug-only)
+	uint32 tag;                 /// the 4-letter tag by which it is identified in the savegame
+
+	bool (*init_read)(void);    /// function executed upon initalization of the loader
+	ReaderProc *reader;         /// function that loads the data from the file
+	void (*uninit_read)(void);  /// function executed when reading is finished
+
+	bool (*init_write)(void);   /// function executed upon intialization of the saver
+	WriterProc *writer;         /// function that saves the data to the file
+	void (*uninit_write)(void); /// function executed when writing is done
+} SaveLoadFormat;
+
+static const SaveLoadFormat _saveload_formats[] = {
+	{"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
+	{"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
+	{"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
+#if defined(WITH_ZLIB)
+	{"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
+#else
+	{"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
+#endif
+};
+
+/**
+ * Return the savegameformat of the game. Whether it was create with ZLIB compression
+ * uncompressed, or another type
+ * @param s Name of the savegame format. If NULL it picks the first available one
+ * @return Pointer to @SaveLoadFormat struct giving all characteristics of this type of savegame
+ */
+static const SaveLoadFormat *GetSavegameFormat(const char *s)
+{
+	const SaveLoadFormat *def = endof(_saveload_formats) - 1;
+
+	// find default savegame format, the highest one with which files can be written
+	while (!def->init_write) def--;
+
+	if (s != NULL && s[0] != '\0') {
+		const SaveLoadFormat *slf;
+		for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
+			if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
+				return slf;
+		}
+
+		ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
+	}
+	return def;
+}
+
+// actual loader/saver function
+void InitializeGame(int mode, uint size_x, uint size_y);
+extern bool AfterLoadGame(void);
+extern void BeforeSaveGame(void);
+extern bool LoadOldSaveGame(const char *file);
+
+/** Small helper function to close the to be loaded savegame an signal error */
+static inline SaveOrLoadResult AbortSaveLoad(void)
+{
+	if (_sl.fh != NULL) fclose(_sl.fh);
+
+	_sl.fh = NULL;
+	return SL_ERROR;
+}
+
+/** Update the gui accordingly when starting saving
+ * and set locks on saveload. Also turn off fast-forward cause with that
+ * saving takes Aaaaages */
+void SaveFileStart(void)
+{
+	_ts.ff_state = _fast_forward;
+	_fast_forward = false;
+	if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ);
+
+	SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
+	_ts.saveinprogress = true;
+}
+
+/** Update the gui accordingly when saving is done and release locks
+ * on saveload */
+void SaveFileDone(void)
+{
+	_fast_forward = _ts.ff_state;
+	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
+
+	SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
+	_ts.saveinprogress = false;
+}
+
+/** Show a gui message when saving has failed */
+void SaveFileError(void)
+{
+	ShowErrorMessage(STR_4007_GAME_SAVE_FAILED, STR_NULL, 0, 0);
+	SaveFileDone();
+}
+
+static OTTDThread* save_thread;
+
+/** We have written the whole game into memory, _Savegame_pool, now find
+ * and appropiate compressor and start writing to file.
+ */
+static void* SaveFileToDisk(void *arg)
+{
+	const SaveLoadFormat *fmt;
+	uint32 hdr[2];
+
+	/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
+	 * loading/saving execute a longjmp() and continue execution here */
+	if (setjmp(_sl.excpt)) {
+		AbortSaveLoad();
+		_sl.excpt_uninit();
+
+		fprintf(stderr, "Save game failed: %s.", _sl.excpt_msg);
+		if (arg != NULL) {
+			OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
+		} else {
+			SaveFileError();
+		}
+		return NULL;
+	}
+
+	fmt = GetSavegameFormat(_savegame_format);
+
+	/* We have written our stuff to memory, now write it to file! */
+	hdr[0] = fmt->tag;
+	hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
+	if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError("file write failed");
+
+	if (!fmt->init_write()) SlError("cannot initialize compressor");
+
+	{
+		uint i;
+		uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
+
+		assert(_ts.count == _sl.offs_base);
+		for (i = 0; i != _Savegame_pool.current_blocks - 1; i++) {
+			_sl.buf = _Savegame_pool.blocks[i];
+			fmt->writer(count);
+		}
+
+		/* The last block is (almost) always not fully filled, so only write away
+		 * as much data as it is in there */
+		_sl.buf = _Savegame_pool.blocks[i];
+		fmt->writer(_ts.count - (i * count));
+	}
+
+	fmt->uninit_write();
+	assert(_ts.count == _sl.offs_base);
+	GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
+	fclose(_sl.fh);
+
+	if (arg != NULL) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
+	return NULL;
+}
+
+void WaitTillSaved(void)
+{
+	OTTDJoinThread(save_thread);
+	save_thread = NULL;
+}
+
+/**
+ * Main Save or Load function where the high-level saveload functions are
+ * handled. It opens the savegame, selects format and checks versions
+ * @param filename The name of the savegame being created/loaded
+ * @param mode Save or load. Load can also be a TTD(Patch) game. Use SL_LOAD, SL_OLD_LOAD or SL_SAVE
+ * @return Return the results of the action. SL_OK, SL_ERROR or SL_REINIT ("unload" the game)
+ */
+SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
+{
+	uint32 hdr[2];
+	const SaveLoadFormat *fmt;
+
+	/* An instance of saving is already active, so don't go saving again */
+	if (_ts.saveinprogress && mode == SL_SAVE) {
+		// if not an autosave, but a user action, show error message
+		if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
+		return SL_OK;
+	}
+	WaitTillSaved();
+
+	/* Load a TTDLX or TTDPatch game */
+	if (mode == SL_OLD_LOAD) {
+		InitializeGame(IG_DATE_RESET, 256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused
+		if (!LoadOldSaveGame(filename)) return SL_REINIT;
+		_sl_version = 0;
+		AfterLoadGame();
+		return SL_OK;
+	}
+
+	_sl.fh = (mode == SL_SAVE) ? fopen(filename, "wb") : fopen(filename, "rb");
+	if (_sl.fh == NULL) {
+		DEBUG(sl, 0, "Cannot open savegame '%s' for saving/loading.", filename);
+		return SL_ERROR;
+	}
+
+	_sl.bufe = _sl.bufp = NULL;
+	_sl.offs_base = 0;
+	_sl.save = mode;
+	_sl.includes = _desc_includes;
+	_sl.chs = _chunk_handlers;
+
+	/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
+	 * loading/saving execute a longjmp() and continue execution here */
+	if (setjmp(_sl.excpt)) {
+		AbortSaveLoad();
+
+		// deinitialize compressor.
+		_sl.excpt_uninit();
+
+		/* A saver/loader exception!! reinitialize all variables to prevent crash! */
+		if (mode == SL_LOAD) {
+			ShowInfoF("Load game failed: %s.", _sl.excpt_msg);
+			return SL_REINIT;
+		}
+
+		ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
+		return SL_ERROR;
+	}
+
+	/* General tactic is to first save the game to memory, then use an available writer
+	 * to write it to file, either in threaded mode if possible, or single-threaded */
+	if (mode == SL_SAVE) { /* SAVE game */
+		fmt = GetSavegameFormat("memory"); // write to memory
+
+		_sl.write_bytes = fmt->writer;
+		_sl.excpt_uninit = fmt->uninit_write;
+		if (!fmt->init_write()) {
+			DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
+			return AbortSaveLoad();
+		}
+
+		_sl_version = SAVEGAME_VERSION;
+
+		BeforeSaveGame();
+		SlSaveChunks();
+		SlWriteFill(); // flush the save buffer
+
+		SaveFileStart();
+		if (_network_server ||
+					(save_thread = OTTDCreateThread(&SaveFileToDisk, (void*)"")) == NULL) {
+			DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
+			SaveFileToDisk(NULL);
+			SaveFileDone();
+		}
+
+	} else { /* LOAD game */
+		assert(mode == SL_LOAD);
+
+		if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) {
+			DEBUG(sl, 0, "Cannot read savegame header, aborting");
+			return AbortSaveLoad();
+		}
+
+		// see if we have any loader for this type.
+		for (fmt = _saveload_formats; ; fmt++) {
+			/* No loader found, treat as version 0 and use LZO format */
+			if (fmt == endof(_saveload_formats)) {
+				DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
+				rewind(_sl.fh);
+				_sl_version = 0;
+				_sl_minor_version = 0;
+				fmt = _saveload_formats + 1; // LZO
+				break;
+			}
+
+			if (fmt->tag == hdr[0]) {
+				// check version number
+				_sl_version = TO_BE32(hdr[1]) >> 16;
+				/* Minor is not used anymore from version 18.0, but it is still needed
+				 *  in versions before that (4 cases) which can't be removed easy.
+				 *  Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
+				 *  So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
+				_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
+
+				DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
+
+				/* Is the version higher than the current? */
+				if (_sl_version > SAVEGAME_VERSION) {
+					DEBUG(sl, 0, "Savegame version invalid");
+					return AbortSaveLoad();
+				}
+				break;
+			}
+		}
+
+		_sl.read_bytes = fmt->reader;
+		_sl.excpt_uninit = fmt->uninit_read;
+
+		// loader for this savegame type is not implemented?
+		if (fmt->init_read == NULL) {
+			ShowInfoF("Loader for '%s' is not available.", fmt->name);
+			return AbortSaveLoad();
+		}
+
+		if (!fmt->init_read()) {
+			DEBUG(sl, 0, "Initializing loader '%s' failed", fmt->name);
+			return AbortSaveLoad();
+		}
+
+		/* Old maps were hardcoded to 256x256 and thus did not contain
+		 * any mapsize information. Pre-initialize to 256x256 to not to
+		 * confuse old games */
+		InitializeGame(IG_DATE_RESET, 256, 256);
+
+		SlLoadChunks();
+		fmt->uninit_read();
+		fclose(_sl.fh);
+
+		/* After loading fix up savegame for any internal changes that
+		 * might've occured since then. If it fails, load back the old game */
+		if (!AfterLoadGame()) return SL_REINIT;
+	}
+
+	return SL_OK;
+}
+
+/** Do a save when exiting the game (patch option) _patches.autosave_on_exit */
+void DoExitSave(void)
+{
+	char buf[200];
+	snprintf(buf, sizeof(buf), "%s%sexit.sav", _paths.autosave_dir, PATHSEP);
+	SaveOrLoad(buf, SL_SAVE);
+}
+
+#if 0
+/**
+ * Function to get the type of the savegame by looking at the file header.
+ * NOTICE: Not used right now, but could be used if extensions of savegames are garbled
+ * @param file Savegame to be checked
+ * @return SL_OLD_LOAD or SL_LOAD of the file
+ */
+int GetSavegameType(char *file)
+{
+	const SaveLoadFormat *fmt;
+	uint32 hdr;
+	FILE *f;
+	int mode = SL_OLD_LOAD;
+
+	f = fopen(file, "rb");
+	if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
+		DEBUG(sl, 0, "Savegame is obsolete or invalid format");
+		mode = SL_LOAD; // don't try to get filename, just show name as it is written
+	} else {
+		// see if we have any loader for this type.
+		for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
+			if (fmt->tag == hdr) {
+				mode = SL_LOAD; // new type of savegame
+				break;
+			}
+		}
+	}
+
+	fclose(f);
+	return mode;
+}
+#endif
deleted file mode 100644
--- a/src/screenshot.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "strings.h"
-#include "table/strings.h"
-#include "gfx.h"
-#include "hal.h"
-#include "viewport.h"
-#include "player.h"
-#include "screenshot.h"
-#include "variables.h"
-#include "date.h"
-
-char _screenshot_format_name[8];
-uint _num_screenshot_formats;
-uint _cur_screenshot_format;
-ScreenshotType current_screenshot_type;
-
-// called by the ScreenShot proc to generate screenshot lines.
-typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n);
-typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
-
-typedef struct {
-	const char *name;
-	const char *extension;
-	ScreenshotHandlerProc *proc;
-} ScreenshotFormat;
-
-//************************************************
-//*** SCREENSHOT CODE FOR WINDOWS BITMAP (.BMP)
-//************************************************
-#if defined(_MSC_VER) || defined(__WATCOMC__)
-#pragma pack(push, 1)
-#endif
-
-typedef struct BitmapFileHeader {
-	uint16 type;
-	uint32 size;
-	uint32 reserved;
-	uint32 off_bits;
-} GCC_PACK BitmapFileHeader;
-assert_compile(sizeof(BitmapFileHeader) == 14);
-
-#if defined(_MSC_VER) || defined(__WATCOMC__)
-#pragma pack(pop)
-#endif
-
-typedef struct BitmapInfoHeader {
-	uint32 size;
-	int32 width, height;
-	uint16 planes, bitcount;
-	uint32 compression, sizeimage, xpels, ypels, clrused, clrimp;
-} BitmapInfoHeader;
-assert_compile(sizeof(BitmapInfoHeader) == 40);
-
-typedef struct RgbQuad {
-	byte blue, green, red, reserved;
-} RgbQuad;
-assert_compile(sizeof(RgbQuad) == 4);
-
-// generic .BMP writer
-static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
-{
-	BitmapFileHeader bfh;
-	BitmapInfoHeader bih;
-	RgbQuad rq[256];
-	Pixel *buff;
-	FILE *f;
-	uint i, padw;
-	uint n, maxlines;
-
-	// only implemented for 8bit images so far.
-	if (pixelformat != 8)
-		return false;
-
-	f = fopen(name, "wb");
-	if (f == NULL) return false;
-
-	// each scanline must be aligned on a 32bit boundary
-	padw = ALIGN(w, 4);
-
-	// setup the file header
-	bfh.type = TO_LE16('MB');
-	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
-	bfh.reserved = 0;
-	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
-
-	// setup the info header
-	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
-	bih.width = TO_LE32(w);
-	bih.height = TO_LE32(h);
-	bih.planes = TO_LE16(1);
-	bih.bitcount = TO_LE16(8);
-	bih.compression = 0;
-	bih.sizeimage = 0;
-	bih.xpels = 0;
-	bih.ypels = 0;
-	bih.clrused = 0;
-	bih.clrimp = 0;
-
-	// convert the palette to the windows format
-	for (i = 0; i != 256; i++) {
-		rq[i].red   = palette[i].r;
-		rq[i].green = palette[i].g;
-		rq[i].blue  = palette[i].b;
-		rq[i].reserved = 0;
-	}
-
-	// write file header and info header and palette
-	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
-	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
-	if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
-
-	// use by default 64k temp memory
-	maxlines = clamp(65536 / padw, 16, 128);
-
-	// now generate the bitmap bits
-	buff = malloc(padw * maxlines); // by default generate 128 lines at a time.
-	if (buff == NULL) {
-		fclose(f);
-		return false;
-	}
-	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
-
-	// start at the bottom, since bitmaps are stored bottom up.
-	do {
-		// determine # lines
-		n = min(h, maxlines);
-		h -= n;
-
-		// render the pixels
-		callb(userdata, buff, h, padw, n);
-
-		// write each line
-		while (n)
-			if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
-				free(buff);
-				fclose(f);
-				return false;
-			}
-	} while (h != 0);
-
-	free(buff);
-	fclose(f);
-
-	return true;
-}
-
-//********************************************************
-//*** SCREENSHOT CODE FOR PORTABLE NETWORK GRAPHICS (.PNG)
-//********************************************************
-#if defined(WITH_PNG)
-#include <png.h>
-
-static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
-{
-	DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
-	longjmp(png_ptr->jmpbuf, 1);
-}
-
-static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
-{
-	DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
-}
-
-static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
-{
-	png_color rq[256];
-	Pixel *buff;
-	FILE *f;
-	uint i, y, n;
-	uint maxlines;
-	png_structp png_ptr;
-	png_infop info_ptr;
-
-	// only implemented for 8bit images so far.
-	if (pixelformat != 8)
-		return false;
-
-	f = fopen(name, "wb");
-	if (f == NULL) return false;
-
-	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (char *)name, png_my_error, png_my_warning);
-
-	if (png_ptr == NULL) {
-		fclose(f);
-		return false;
-	}
-
-	info_ptr = png_create_info_struct(png_ptr);
-	if (info_ptr == NULL) {
-		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-		fclose(f);
-		return false;
-	}
-
-	if (setjmp(png_jmpbuf(png_ptr))) {
-		png_destroy_write_struct(&png_ptr, &info_ptr);
-		fclose(f);
-		return false;
-	}
-
-	png_init_io(png_ptr, f);
-
-	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
-
-	png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
-		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
-	// convert the palette to the .PNG format.
-	for (i = 0; i != 256; i++) {
-		rq[i].red   = palette[i].r;
-		rq[i].green = palette[i].g;
-		rq[i].blue  = palette[i].b;
-	}
-
-	png_set_PLTE(png_ptr, info_ptr, rq, 256);
-	png_write_info(png_ptr, info_ptr);
-	png_set_flush(png_ptr, 512);
-
-	// use by default 64k temp memory
-	maxlines = clamp(65536 / w, 16, 128);
-
-	// now generate the bitmap bits
-	buff = malloc(w * maxlines); // by default generate 128 lines at a time.
-	if (buff == NULL) {
-		png_destroy_write_struct(&png_ptr, &info_ptr);
-		fclose(f);
-		return false;
-	}
-	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
-
-	y = 0;
-	do {
-		// determine # lines to write
-		n = min(h - y, maxlines);
-
-		// render the pixels into the buffer
-		callb(userdata, buff, y, w, n);
-		y += n;
-
-		// write them to png
-		for (i = 0; i != n; i++)
-			png_write_row(png_ptr, buff + i * w);
-	} while (y != h);
-
-	png_write_end(png_ptr, info_ptr);
-	png_destroy_write_struct(&png_ptr, &info_ptr);
-
-	free(buff);
-	fclose(f);
-	return true;
-}
-#endif /* WITH_PNG */
-
-
-//************************************************
-//*** SCREENSHOT CODE FOR ZSOFT PAINTBRUSH (.PCX)
-//************************************************
-
-typedef struct {
-	byte manufacturer;
-	byte version;
-	byte rle;
-	byte bpp;
-	uint32 unused;
-	uint16 xmax, ymax;
-	uint16 hdpi, vdpi;
-	byte pal_small[16*3];
-	byte reserved;
-	byte planes;
-	uint16 pitch;
-	uint16 cpal;
-	uint16 width;
-	uint16 height;
-	byte filler[54];
-} PcxHeader;
-assert_compile(sizeof(PcxHeader) == 128);
-
-static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
-{
-	Pixel *buff;
-	FILE *f;
-	uint maxlines;
-	uint y;
-	PcxHeader pcx;
-	bool success;
-
-	if (pixelformat != 8 || w == 0)
-		return false;
-
-	f = fopen(name, "wb");
-	if (f == NULL) return false;
-
-	memset(&pcx, 0, sizeof(pcx));
-
-	// setup pcx header
-	pcx.manufacturer = 10;
-	pcx.version = 5;
-	pcx.rle = 1;
-	pcx.bpp = 8;
-	pcx.xmax = TO_LE16(w - 1);
-	pcx.ymax = TO_LE16(h - 1);
-	pcx.hdpi = TO_LE16(320);
-	pcx.vdpi = TO_LE16(320);
-
-	pcx.planes = 1;
-	pcx.cpal = TO_LE16(1);
-	pcx.width = pcx.pitch = TO_LE16(w);
-	pcx.height = TO_LE16(h);
-
-	// write pcx header
-	if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
-		fclose(f);
-		return false;
-	}
-
-	// use by default 64k temp memory
-	maxlines = clamp(65536 / w, 16, 128);
-
-	// now generate the bitmap bits
-	buff = malloc(w * maxlines); // by default generate 128 lines at a time.
-	if (buff == NULL) {
-		fclose(f);
-		return false;
-	}
-	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
-
-	y = 0;
-	do {
-		// determine # lines to write
-		uint n = min(h - y, maxlines);
-		uint i;
-
-		// render the pixels into the buffer
-		callb(userdata, buff, y, w, n);
-		y += n;
-
-		// write them to pcx
-		for (i = 0; i != n; i++) {
-			const Pixel* bufp = buff + i * w;
-			byte runchar = bufp[0];
-			uint runcount = 1;
-			uint j;
-
-			// for each pixel...
-			for (j = 1; j < w; j++) {
-				Pixel ch = bufp[j];
-
-				if (ch != runchar || runcount >= 0x3f) {
-					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
-						if (fputc(0xC0 | runcount, f) == EOF) {
-							free(buff);
-							fclose(f);
-							return false;
-						}
-					if (fputc(runchar, f) == EOF) {
-						free(buff);
-						fclose(f);
-						return false;
-					}
-					runcount = 0;
-					runchar = ch;
-				}
-				runcount++;
-			}
-
-			// write remaining bytes..
-			if (runcount > 1 || (runchar & 0xC0) == 0xC0)
-				if (fputc(0xC0 | runcount, f) == EOF) {
-					free(buff);
-					fclose(f);
-					return false;
-				}
-			if (fputc(runchar, f) == EOF) {
-				free(buff);
-				fclose(f);
-				return false;
-			}
-		}
-	} while (y != h);
-
-	free(buff);
-
-	// write 8-bit color palette
-	if (fputc(12, f) == EOF) {
-		fclose(f);
-		return false;
-	}
-
-	if (sizeof(*palette) == 3) {
-		success = fwrite(palette, 256 * sizeof(*palette), 1, f) == 1;
-	} else {
-		/* If the palette is word-aligned, copy it to a temporary byte array */
-		byte tmp[256 * 3];
-		uint i;
-
-		for (i = 0; i < 256; i++) {
-			tmp[i * 3 + 0] = palette[i].r;
-			tmp[i * 3 + 1] = palette[i].g;
-			tmp[i * 3 + 2] = palette[i].b;
-		}
-		success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
-	}
-
-	fclose(f);
-
-	return success;
-}
-
-//************************************************
-//*** GENERIC SCREENSHOT CODE
-//************************************************
-
-static const ScreenshotFormat _screenshot_formats[] = {
-#if defined(WITH_PNG)
-	{"PNG", "png", &MakePNGImage},
-#endif
-	{"BMP", "bmp", &MakeBmpImage},
-	{"PCX", "pcx", &MakePCXImage},
-};
-
-void InitializeScreenshotFormats(void)
-{
-	int i, j;
-	for (i = 0, j = 0; i != lengthof(_screenshot_formats); i++)
-		if (!strcmp(_screenshot_format_name, _screenshot_formats[i].extension)) {
-			j = i;
-			break;
-		}
-	_cur_screenshot_format = j;
-	_num_screenshot_formats = lengthof(_screenshot_formats);
-	current_screenshot_type = SC_NONE;
-}
-
-const char *GetScreenshotFormatDesc(int i)
-{
-	return _screenshot_formats[i].name;
-}
-
-void SetScreenshotFormat(int i)
-{
-	_cur_screenshot_format = i;
-	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
-}
-
-// screenshot generator that dumps the current video buffer
-static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
-{
-	for (; n > 0; --n) {
-		memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width);
-		++y;
-		buf += pitch;
-	}
-}
-
-// generate a large piece of the world
-static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
-{
-	ViewPort *vp = (ViewPort *)userdata;
-	DrawPixelInfo dpi, *old_dpi;
-	int wx, left;
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = &dpi;
-
-	dpi.dst_ptr = buf;
-	dpi.height = n;
-	dpi.width = vp->width;
-	dpi.pitch = pitch;
-	dpi.zoom = 0;
-	dpi.left = 0;
-	dpi.top = y;
-
-	left = 0;
-	while (vp->width - left != 0) {
-		wx = min(vp->width - left, 1600);
-		left += wx;
-
-		ViewportDoDraw(vp,
-			((left - wx - vp->left) << vp->zoom) + vp->virtual_left,
-			((y - vp->top) << vp->zoom) + vp->virtual_top,
-			((left - vp->left) << vp->zoom) + vp->virtual_left,
-			(((y + n) - vp->top) << vp->zoom) + vp->virtual_top
-		);
-	}
-
-	_cur_dpi = old_dpi;
-}
-
-static char *MakeScreenshotName(const char *ext)
-{
-	static char filename[256];
-	char *base;
-	int serial;
-
-	if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_player == PLAYER_SPECTATOR) {
-		sprintf(_screenshot_name, "screenshot");
-	} else {
-		const Player* p = GetPlayer(_local_player);
-		SetDParam(0, p->name_1);
-		SetDParam(1, p->name_2);
-		SetDParam(2, _date);
-		GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
-	}
-
-	base = strchr(_screenshot_name, 0);
-	base[0] = '.'; strcpy(base + 1, ext);
-
-	serial = 0;
-	for (;;) {
-		snprintf(filename, sizeof(filename), "%s%s", _paths.personal_dir, _screenshot_name);
-		if (!FileExists(filename))
-			break;
-		sprintf(base, " #%d.%s", ++serial, ext);
-	}
-
-	return filename;
-}
-
-void SetScreenshotType(ScreenshotType t)
-{
-	current_screenshot_type = t;
-}
-
-bool IsScreenshotRequested(void)
-{
-	return (current_screenshot_type != SC_NONE);
-}
-
-static bool MakeSmallScreenshot(void)
-{
-	const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
-	return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, 8, _cur_palette);
-}
-
-static bool MakeWorldScreenshot(void)
-{
-	ViewPort vp;
-	const ScreenshotFormat *sf;
-
-	vp.zoom = 0;
-	vp.left = 0;
-	vp.top = 0;
-	vp.virtual_left = -(int)MapMaxX() * TILE_PIXELS;
-	vp.virtual_top = 0;
-	vp.virtual_width = (MapMaxX() + MapMaxY()) * TILE_PIXELS;
-	vp.width = vp.virtual_width;
-	vp.virtual_height = (MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1;
-	vp.height = vp.virtual_height;
-
-	sf = _screenshot_formats + _cur_screenshot_format;
-	return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, 8, _cur_palette);
-}
-
-bool MakeScreenshot(void)
-{
-	switch (current_screenshot_type) {
-		case SC_VIEWPORT:
-			UndrawMouseCursor();
-			DrawDirtyBlocks();
-			current_screenshot_type = SC_NONE;
-			return MakeSmallScreenshot();
-		case SC_WORLD:
-			current_screenshot_type = SC_NONE;
-			return MakeWorldScreenshot();
-		default: return false;
-	}
-}
-
-
-
new file mode 100644
--- /dev/null
+++ b/src/screenshot.cpp
@@ -0,0 +1,575 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "gfx.h"
+#include "hal.h"
+#include "viewport.h"
+#include "player.h"
+#include "screenshot.h"
+#include "variables.h"
+#include "date.h"
+
+char _screenshot_format_name[8];
+uint _num_screenshot_formats;
+uint _cur_screenshot_format;
+ScreenshotType current_screenshot_type;
+
+// called by the ScreenShot proc to generate screenshot lines.
+typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n);
+typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
+
+typedef struct {
+	const char *name;
+	const char *extension;
+	ScreenshotHandlerProc *proc;
+} ScreenshotFormat;
+
+//************************************************
+//*** SCREENSHOT CODE FOR WINDOWS BITMAP (.BMP)
+//************************************************
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+#pragma pack(push, 1)
+#endif
+
+typedef struct BitmapFileHeader {
+	uint16 type;
+	uint32 size;
+	uint32 reserved;
+	uint32 off_bits;
+} GCC_PACK BitmapFileHeader;
+assert_compile(sizeof(BitmapFileHeader) == 14);
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+#pragma pack(pop)
+#endif
+
+typedef struct BitmapInfoHeader {
+	uint32 size;
+	int32 width, height;
+	uint16 planes, bitcount;
+	uint32 compression, sizeimage, xpels, ypels, clrused, clrimp;
+} BitmapInfoHeader;
+assert_compile(sizeof(BitmapInfoHeader) == 40);
+
+typedef struct RgbQuad {
+	byte blue, green, red, reserved;
+} RgbQuad;
+assert_compile(sizeof(RgbQuad) == 4);
+
+// generic .BMP writer
+static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
+{
+	BitmapFileHeader bfh;
+	BitmapInfoHeader bih;
+	RgbQuad rq[256];
+	Pixel *buff;
+	FILE *f;
+	uint i, padw;
+	uint n, maxlines;
+
+	// only implemented for 8bit images so far.
+	if (pixelformat != 8)
+		return false;
+
+	f = fopen(name, "wb");
+	if (f == NULL) return false;
+
+	// each scanline must be aligned on a 32bit boundary
+	padw = ALIGN(w, 4);
+
+	// setup the file header
+	bfh.type = TO_LE16('MB');
+	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
+	bfh.reserved = 0;
+	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
+
+	// setup the info header
+	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
+	bih.width = TO_LE32(w);
+	bih.height = TO_LE32(h);
+	bih.planes = TO_LE16(1);
+	bih.bitcount = TO_LE16(8);
+	bih.compression = 0;
+	bih.sizeimage = 0;
+	bih.xpels = 0;
+	bih.ypels = 0;
+	bih.clrused = 0;
+	bih.clrimp = 0;
+
+	// convert the palette to the windows format
+	for (i = 0; i != 256; i++) {
+		rq[i].red   = palette[i].r;
+		rq[i].green = palette[i].g;
+		rq[i].blue  = palette[i].b;
+		rq[i].reserved = 0;
+	}
+
+	// write file header and info header and palette
+	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
+	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
+	if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
+
+	// use by default 64k temp memory
+	maxlines = clamp(65536 / padw, 16, 128);
+
+	// now generate the bitmap bits
+	buff = malloc(padw * maxlines); // by default generate 128 lines at a time.
+	if (buff == NULL) {
+		fclose(f);
+		return false;
+	}
+	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
+
+	// start at the bottom, since bitmaps are stored bottom up.
+	do {
+		// determine # lines
+		n = min(h, maxlines);
+		h -= n;
+
+		// render the pixels
+		callb(userdata, buff, h, padw, n);
+
+		// write each line
+		while (n)
+			if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
+				free(buff);
+				fclose(f);
+				return false;
+			}
+	} while (h != 0);
+
+	free(buff);
+	fclose(f);
+
+	return true;
+}
+
+//********************************************************
+//*** SCREENSHOT CODE FOR PORTABLE NETWORK GRAPHICS (.PNG)
+//********************************************************
+#if defined(WITH_PNG)
+#include <png.h>
+
+static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
+{
+	DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
+	longjmp(png_ptr->jmpbuf, 1);
+}
+
+static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
+{
+	DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
+}
+
+static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
+{
+	png_color rq[256];
+	Pixel *buff;
+	FILE *f;
+	uint i, y, n;
+	uint maxlines;
+	png_structp png_ptr;
+	png_infop info_ptr;
+
+	// only implemented for 8bit images so far.
+	if (pixelformat != 8)
+		return false;
+
+	f = fopen(name, "wb");
+	if (f == NULL) return false;
+
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (char *)name, png_my_error, png_my_warning);
+
+	if (png_ptr == NULL) {
+		fclose(f);
+		return false;
+	}
+
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+		fclose(f);
+		return false;
+	}
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		png_destroy_write_struct(&png_ptr, &info_ptr);
+		fclose(f);
+		return false;
+	}
+
+	png_init_io(png_ptr, f);
+
+	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+
+	png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
+		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+	// convert the palette to the .PNG format.
+	for (i = 0; i != 256; i++) {
+		rq[i].red   = palette[i].r;
+		rq[i].green = palette[i].g;
+		rq[i].blue  = palette[i].b;
+	}
+
+	png_set_PLTE(png_ptr, info_ptr, rq, 256);
+	png_write_info(png_ptr, info_ptr);
+	png_set_flush(png_ptr, 512);
+
+	// use by default 64k temp memory
+	maxlines = clamp(65536 / w, 16, 128);
+
+	// now generate the bitmap bits
+	buff = malloc(w * maxlines); // by default generate 128 lines at a time.
+	if (buff == NULL) {
+		png_destroy_write_struct(&png_ptr, &info_ptr);
+		fclose(f);
+		return false;
+	}
+	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
+
+	y = 0;
+	do {
+		// determine # lines to write
+		n = min(h - y, maxlines);
+
+		// render the pixels into the buffer
+		callb(userdata, buff, y, w, n);
+		y += n;
+
+		// write them to png
+		for (i = 0; i != n; i++)
+			png_write_row(png_ptr, buff + i * w);
+	} while (y != h);
+
+	png_write_end(png_ptr, info_ptr);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+
+	free(buff);
+	fclose(f);
+	return true;
+}
+#endif /* WITH_PNG */
+
+
+//************************************************
+//*** SCREENSHOT CODE FOR ZSOFT PAINTBRUSH (.PCX)
+//************************************************
+
+typedef struct {
+	byte manufacturer;
+	byte version;
+	byte rle;
+	byte bpp;
+	uint32 unused;
+	uint16 xmax, ymax;
+	uint16 hdpi, vdpi;
+	byte pal_small[16*3];
+	byte reserved;
+	byte planes;
+	uint16 pitch;
+	uint16 cpal;
+	uint16 width;
+	uint16 height;
+	byte filler[54];
+} PcxHeader;
+assert_compile(sizeof(PcxHeader) == 128);
+
+static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
+{
+	Pixel *buff;
+	FILE *f;
+	uint maxlines;
+	uint y;
+	PcxHeader pcx;
+	bool success;
+
+	if (pixelformat != 8 || w == 0)
+		return false;
+
+	f = fopen(name, "wb");
+	if (f == NULL) return false;
+
+	memset(&pcx, 0, sizeof(pcx));
+
+	// setup pcx header
+	pcx.manufacturer = 10;
+	pcx.version = 5;
+	pcx.rle = 1;
+	pcx.bpp = 8;
+	pcx.xmax = TO_LE16(w - 1);
+	pcx.ymax = TO_LE16(h - 1);
+	pcx.hdpi = TO_LE16(320);
+	pcx.vdpi = TO_LE16(320);
+
+	pcx.planes = 1;
+	pcx.cpal = TO_LE16(1);
+	pcx.width = pcx.pitch = TO_LE16(w);
+	pcx.height = TO_LE16(h);
+
+	// write pcx header
+	if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
+		fclose(f);
+		return false;
+	}
+
+	// use by default 64k temp memory
+	maxlines = clamp(65536 / w, 16, 128);
+
+	// now generate the bitmap bits
+	buff = malloc(w * maxlines); // by default generate 128 lines at a time.
+	if (buff == NULL) {
+		fclose(f);
+		return false;
+	}
+	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
+
+	y = 0;
+	do {
+		// determine # lines to write
+		uint n = min(h - y, maxlines);
+		uint i;
+
+		// render the pixels into the buffer
+		callb(userdata, buff, y, w, n);
+		y += n;
+
+		// write them to pcx
+		for (i = 0; i != n; i++) {
+			const Pixel* bufp = buff + i * w;
+			byte runchar = bufp[0];
+			uint runcount = 1;
+			uint j;
+
+			// for each pixel...
+			for (j = 1; j < w; j++) {
+				Pixel ch = bufp[j];
+
+				if (ch != runchar || runcount >= 0x3f) {
+					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
+						if (fputc(0xC0 | runcount, f) == EOF) {
+							free(buff);
+							fclose(f);
+							return false;
+						}
+					if (fputc(runchar, f) == EOF) {
+						free(buff);
+						fclose(f);
+						return false;
+					}
+					runcount = 0;
+					runchar = ch;
+				}
+				runcount++;
+			}
+
+			// write remaining bytes..
+			if (runcount > 1 || (runchar & 0xC0) == 0xC0)
+				if (fputc(0xC0 | runcount, f) == EOF) {
+					free(buff);
+					fclose(f);
+					return false;
+				}
+			if (fputc(runchar, f) == EOF) {
+				free(buff);
+				fclose(f);
+				return false;
+			}
+		}
+	} while (y != h);
+
+	free(buff);
+
+	// write 8-bit color palette
+	if (fputc(12, f) == EOF) {
+		fclose(f);
+		return false;
+	}
+
+	if (sizeof(*palette) == 3) {
+		success = fwrite(palette, 256 * sizeof(*palette), 1, f) == 1;
+	} else {
+		/* If the palette is word-aligned, copy it to a temporary byte array */
+		byte tmp[256 * 3];
+		uint i;
+
+		for (i = 0; i < 256; i++) {
+			tmp[i * 3 + 0] = palette[i].r;
+			tmp[i * 3 + 1] = palette[i].g;
+			tmp[i * 3 + 2] = palette[i].b;
+		}
+		success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
+	}
+
+	fclose(f);
+
+	return success;
+}
+
+//************************************************
+//*** GENERIC SCREENSHOT CODE
+//************************************************
+
+static const ScreenshotFormat _screenshot_formats[] = {
+#if defined(WITH_PNG)
+	{"PNG", "png", &MakePNGImage},
+#endif
+	{"BMP", "bmp", &MakeBmpImage},
+	{"PCX", "pcx", &MakePCXImage},
+};
+
+void InitializeScreenshotFormats(void)
+{
+	int i, j;
+	for (i = 0, j = 0; i != lengthof(_screenshot_formats); i++)
+		if (!strcmp(_screenshot_format_name, _screenshot_formats[i].extension)) {
+			j = i;
+			break;
+		}
+	_cur_screenshot_format = j;
+	_num_screenshot_formats = lengthof(_screenshot_formats);
+	current_screenshot_type = SC_NONE;
+}
+
+const char *GetScreenshotFormatDesc(int i)
+{
+	return _screenshot_formats[i].name;
+}
+
+void SetScreenshotFormat(int i)
+{
+	_cur_screenshot_format = i;
+	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
+}
+
+// screenshot generator that dumps the current video buffer
+static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
+{
+	for (; n > 0; --n) {
+		memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width);
+		++y;
+		buf += pitch;
+	}
+}
+
+// generate a large piece of the world
+static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
+{
+	ViewPort *vp = (ViewPort *)userdata;
+	DrawPixelInfo dpi, *old_dpi;
+	int wx, left;
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = &dpi;
+
+	dpi.dst_ptr = buf;
+	dpi.height = n;
+	dpi.width = vp->width;
+	dpi.pitch = pitch;
+	dpi.zoom = 0;
+	dpi.left = 0;
+	dpi.top = y;
+
+	left = 0;
+	while (vp->width - left != 0) {
+		wx = min(vp->width - left, 1600);
+		left += wx;
+
+		ViewportDoDraw(vp,
+			((left - wx - vp->left) << vp->zoom) + vp->virtual_left,
+			((y - vp->top) << vp->zoom) + vp->virtual_top,
+			((left - vp->left) << vp->zoom) + vp->virtual_left,
+			(((y + n) - vp->top) << vp->zoom) + vp->virtual_top
+		);
+	}
+
+	_cur_dpi = old_dpi;
+}
+
+static char *MakeScreenshotName(const char *ext)
+{
+	static char filename[256];
+	char *base;
+	int serial;
+
+	if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_player == PLAYER_SPECTATOR) {
+		sprintf(_screenshot_name, "screenshot");
+	} else {
+		const Player* p = GetPlayer(_local_player);
+		SetDParam(0, p->name_1);
+		SetDParam(1, p->name_2);
+		SetDParam(2, _date);
+		GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
+	}
+
+	base = strchr(_screenshot_name, 0);
+	base[0] = '.'; strcpy(base + 1, ext);
+
+	serial = 0;
+	for (;;) {
+		snprintf(filename, sizeof(filename), "%s%s", _paths.personal_dir, _screenshot_name);
+		if (!FileExists(filename))
+			break;
+		sprintf(base, " #%d.%s", ++serial, ext);
+	}
+
+	return filename;
+}
+
+void SetScreenshotType(ScreenshotType t)
+{
+	current_screenshot_type = t;
+}
+
+bool IsScreenshotRequested(void)
+{
+	return (current_screenshot_type != SC_NONE);
+}
+
+static bool MakeSmallScreenshot(void)
+{
+	const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
+	return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, 8, _cur_palette);
+}
+
+static bool MakeWorldScreenshot(void)
+{
+	ViewPort vp;
+	const ScreenshotFormat *sf;
+
+	vp.zoom = 0;
+	vp.left = 0;
+	vp.top = 0;
+	vp.virtual_left = -(int)MapMaxX() * TILE_PIXELS;
+	vp.virtual_top = 0;
+	vp.virtual_width = (MapMaxX() + MapMaxY()) * TILE_PIXELS;
+	vp.width = vp.virtual_width;
+	vp.virtual_height = (MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1;
+	vp.height = vp.virtual_height;
+
+	sf = _screenshot_formats + _cur_screenshot_format;
+	return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, 8, _cur_palette);
+}
+
+bool MakeScreenshot(void)
+{
+	switch (current_screenshot_type) {
+		case SC_VIEWPORT:
+			UndrawMouseCursor();
+			DrawDirtyBlocks();
+			current_screenshot_type = SC_NONE;
+			return MakeSmallScreenshot();
+		case SC_WORLD:
+			current_screenshot_type = SC_NONE;
+			return MakeWorldScreenshot();
+		default: return false;
+	}
+}
+
+
+
deleted file mode 100644
--- a/src/sdl.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-
-#ifdef WITH_SDL
-
-#include "openttd.h"
-#include "sdl.h"
-#include <SDL.h>
-
-#ifdef UNIX
-#include <signal.h>
-
-#ifdef __MORPHOS__
-	// The system supplied definition of SIG_DFL is wrong on MorphOS
-	#undef SIG_DFL
-	#define SIG_DFL (void (*)(int))0
-#endif
-#endif
-
-static int _sdl_usage;
-
-#ifdef DYNAMICALLY_LOADED_SDL
-
-#include "win32.h"
-
-#define M(x) x "\0"
-static const char sdl_files[] =
-	M("sdl.dll")
-	M("SDL_Init")
-	M("SDL_InitSubSystem")
-	M("SDL_GetError")
-	M("SDL_QuitSubSystem")
-	M("SDL_UpdateRect")
-	M("SDL_UpdateRects")
-	M("SDL_SetColors")
-	M("SDL_WM_SetCaption")
-	M("SDL_ShowCursor")
-	M("SDL_FreeSurface")
-	M("SDL_PollEvent")
-	M("SDL_WarpMouse")
-	M("SDL_GetTicks")
-	M("SDL_OpenAudio")
-	M("SDL_PauseAudio")
-	M("SDL_CloseAudio")
-	M("SDL_LockSurface")
-	M("SDL_UnlockSurface")
-	M("SDL_GetModState")
-	M("SDL_Delay")
-	M("SDL_Quit")
-	M("SDL_SetVideoMode")
-	M("SDL_EnableKeyRepeat")
-	M("SDL_EnableUNICODE")
-	M("SDL_VideoDriverName")
-	M("SDL_ListModes")
-	M("SDL_GetKeyState")
-	M("SDL_LoadBMP_RW")
-	M("SDL_RWFromFile")
-	M("SDL_SetColorKey")
-	M("SDL_WM_SetIcon")
-	M("SDL_MapRGB")
-	M("")
-;
-#undef M
-
-SDLProcs sdl_proc;
-
-static const char *LoadSdlDLL(void)
-{
-	if (sdl_proc.SDL_Init != NULL)
-		return NULL;
-	if (!LoadLibraryList((Function *)(void *)&sdl_proc, sdl_files))
-		return "Unable to load sdl.dll";
-	return NULL;
-}
-
-#endif // DYNAMICALLY_LOADED_SDL
-
-
-#ifdef UNIX
-static void SdlAbort(int sig)
-{
-	/* Own hand-made parachute for the cases of failed assertions. */
-	SDL_CALL SDL_Quit();
-
-	switch (sig) {
-		case SIGSEGV:
-		case SIGFPE:
-			signal(sig, SIG_DFL);
-			raise(sig);
-			break;
-
-		default:
-			break;
-	}
-}
-#endif
-
-
-const char* SdlOpen(uint32 x)
-{
-#ifdef DYNAMICALLY_LOADED_SDL
-	{
-		const char *s = LoadSdlDLL();
-		if (s != NULL) return s;
-	}
-#endif
-	if (_sdl_usage++ == 0) {
-		if (SDL_CALL SDL_Init(x) == -1)
-			return SDL_CALL SDL_GetError();
-	} else if (x != 0) {
-		if (SDL_CALL SDL_InitSubSystem(x) == -1)
-			return SDL_CALL SDL_GetError();
-	}
-
-#ifdef UNIX
-	signal(SIGABRT, SdlAbort);
-	signal(SIGSEGV, SdlAbort);
-	signal(SIGFPE, SdlAbort);
-#endif
-
-	return NULL;
-}
-
-void SdlClose(uint32 x)
-{
-	if (x != 0)
-		SDL_CALL SDL_QuitSubSystem(x);
-	if (--_sdl_usage == 0) {
-		SDL_CALL SDL_Quit();
-		#ifdef UNIX
-		signal(SIGABRT, SIG_DFL);
-		signal(SIGSEGV, SIG_DFL);
-		signal(SIGFPE, SIG_DFL);
-		#endif
-	}
-}
-
-#endif
new file mode 100644
--- /dev/null
+++ b/src/sdl.cpp
@@ -0,0 +1,139 @@
+/* $Id$ */
+
+#include "stdafx.h"
+
+#ifdef WITH_SDL
+
+#include "openttd.h"
+#include "sdl.h"
+#include <SDL.h>
+
+#ifdef UNIX
+#include <signal.h>
+
+#ifdef __MORPHOS__
+	// The system supplied definition of SIG_DFL is wrong on MorphOS
+	#undef SIG_DFL
+	#define SIG_DFL (void (*)(int))0
+#endif
+#endif
+
+static int _sdl_usage;
+
+#ifdef DYNAMICALLY_LOADED_SDL
+
+#include "win32.h"
+
+#define M(x) x "\0"
+static const char sdl_files[] =
+	M("sdl.dll")
+	M("SDL_Init")
+	M("SDL_InitSubSystem")
+	M("SDL_GetError")
+	M("SDL_QuitSubSystem")
+	M("SDL_UpdateRect")
+	M("SDL_UpdateRects")
+	M("SDL_SetColors")
+	M("SDL_WM_SetCaption")
+	M("SDL_ShowCursor")
+	M("SDL_FreeSurface")
+	M("SDL_PollEvent")
+	M("SDL_WarpMouse")
+	M("SDL_GetTicks")
+	M("SDL_OpenAudio")
+	M("SDL_PauseAudio")
+	M("SDL_CloseAudio")
+	M("SDL_LockSurface")
+	M("SDL_UnlockSurface")
+	M("SDL_GetModState")
+	M("SDL_Delay")
+	M("SDL_Quit")
+	M("SDL_SetVideoMode")
+	M("SDL_EnableKeyRepeat")
+	M("SDL_EnableUNICODE")
+	M("SDL_VideoDriverName")
+	M("SDL_ListModes")
+	M("SDL_GetKeyState")
+	M("SDL_LoadBMP_RW")
+	M("SDL_RWFromFile")
+	M("SDL_SetColorKey")
+	M("SDL_WM_SetIcon")
+	M("SDL_MapRGB")
+	M("")
+;
+#undef M
+
+SDLProcs sdl_proc;
+
+static const char *LoadSdlDLL(void)
+{
+	if (sdl_proc.SDL_Init != NULL)
+		return NULL;
+	if (!LoadLibraryList((Function *)(void *)&sdl_proc, sdl_files))
+		return "Unable to load sdl.dll";
+	return NULL;
+}
+
+#endif // DYNAMICALLY_LOADED_SDL
+
+
+#ifdef UNIX
+static void SdlAbort(int sig)
+{
+	/* Own hand-made parachute for the cases of failed assertions. */
+	SDL_CALL SDL_Quit();
+
+	switch (sig) {
+		case SIGSEGV:
+		case SIGFPE:
+			signal(sig, SIG_DFL);
+			raise(sig);
+			break;
+
+		default:
+			break;
+	}
+}
+#endif
+
+
+const char* SdlOpen(uint32 x)
+{
+#ifdef DYNAMICALLY_LOADED_SDL
+	{
+		const char *s = LoadSdlDLL();
+		if (s != NULL) return s;
+	}
+#endif
+	if (_sdl_usage++ == 0) {
+		if (SDL_CALL SDL_Init(x) == -1)
+			return SDL_CALL SDL_GetError();
+	} else if (x != 0) {
+		if (SDL_CALL SDL_InitSubSystem(x) == -1)
+			return SDL_CALL SDL_GetError();
+	}
+
+#ifdef UNIX
+	signal(SIGABRT, SdlAbort);
+	signal(SIGSEGV, SdlAbort);
+	signal(SIGFPE, SdlAbort);
+#endif
+
+	return NULL;
+}
+
+void SdlClose(uint32 x)
+{
+	if (x != 0)
+		SDL_CALL SDL_QuitSubSystem(x);
+	if (--_sdl_usage == 0) {
+		SDL_CALL SDL_Quit();
+		#ifdef UNIX
+		signal(SIGABRT, SIG_DFL);
+		signal(SIGSEGV, SIG_DFL);
+		signal(SIGFPE, SIG_DFL);
+		#endif
+	}
+}
+
+#endif
deleted file mode 100644
--- a/src/settings.c
+++ /dev/null
@@ -1,1861 +0,0 @@
-/* $Id$ */
-
-/** @file
- * All actions handling saving and loading of the settings/configuration goes on in this file.
- * The file consists of four parts:
- * <ol>
- * <li>Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which
- *     handle various types, such as normal 'key = value' pairs, lists and value combinations of
- *     lists, strings, integers, 'bit'-masks and element selections.
- * <li>Defining the data structures that go into the configuration. These include for example
- *     the _patches struct, but also network-settings, banlists, newgrf, etc. There are a lot
- *     of helper macros available for the various types, and also saving/loading of these settings
- *     in a savegame is handled inside these structures.
- * <li>Handle reading and writing to the setting-structures from inside the game either from
- *     the console for example or through the gui with CMD_ functions.
- * <li>Handle saving/loading of the PATS chunk inside the savegame.
- * </ol>
- * @see SettingDesc
- * @see SaveLoad
- */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "functions.h"
-#include "macros.h"
-#include "screenshot.h"
-#include "sound.h"
-#include "string.h"
-#include "variables.h"
-#include "network/network.h"
-#include "settings.h"
-#include "command.h"
-#include "console.h"
-#include "saveload.h"
-#include "npf.h"
-#include "yapf/yapf.h"
-#include "newgrf.h"
-#include "newgrf_config.h"
-#include "genworld.h"
-#include "date.h"
-#include "rail.h"
-#ifdef WITH_FREETYPE
-#include "gfx.h"
-#include "fontcache.h"
-#endif
-
-/** The patch values that are used for new games and/or modified in config file */
-Patches _patches_newgame;
-
-typedef struct IniFile IniFile;
-typedef struct IniItem IniItem;
-typedef struct IniGroup IniGroup;
-typedef struct SettingsMemoryPool SettingsMemoryPool;
-
-typedef const char *SettingListCallbackProc(const IniItem *item, uint index);
-typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object);
-typedef void SettingDescProcList(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc);
-
-static void pool_init(SettingsMemoryPool **pool);
-static void *pool_alloc(SettingsMemoryPool **pool, uint size);
-static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size);
-static void pool_free(SettingsMemoryPool **pool);
-static bool IsSignedVarMemType(VarType vt);
-
-struct SettingsMemoryPool {
-	uint pos,size;
-	SettingsMemoryPool *next;
-	byte mem[1];
-};
-
-static SettingsMemoryPool *pool_new(uint minsize)
-{
-	SettingsMemoryPool *p;
-	if (minsize < 4096 - 12) minsize = 4096 - 12;
-
-	p = malloc(sizeof(SettingsMemoryPool) - 1 + minsize);
-	p->pos = 0;
-	p->size = minsize;
-	p->next = NULL;
-	return p;
-}
-
-static void pool_init(SettingsMemoryPool **pool)
-{
-	*pool = pool_new(0);
-}
-
-static void *pool_alloc(SettingsMemoryPool **pool, uint size)
-{
-	uint pos;
-	SettingsMemoryPool *p = *pool;
-
-	size = ALIGN(size, sizeof(void*));
-
-	// first check if there's memory in the next pool
-	if (p->next && p->next->pos + size <= p->next->size) {
-		p = p->next;
-	// then check if there's not memory in the cur pool
-	} else if (p->pos + size > p->size) {
-		SettingsMemoryPool *n = pool_new(size);
-		*pool = n;
-		n->next = p;
-		p = n;
-	}
-
-	pos = p->pos;
-	p->pos += size;
-	return p->mem + pos;
-}
-
-static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size)
-{
-	byte *p = pool_alloc(pool, size + 1);
-	p[size] = 0;
-	memcpy(p, mem, size);
-	return p;
-}
-
-static void pool_free(SettingsMemoryPool **pool)
-{
-	SettingsMemoryPool *p = *pool, *n;
-	*pool = NULL;
-	while (p) {
-		n = p->next;
-		free(p);
-		p = n;
-	}
-}
-
-// structs describing the ini format.
-struct IniItem {
-	char *name;
-	char *value;
-	char *comment;
-	IniItem *next;
-};
-
-struct IniGroup {
-	char *name; // name of group
-	char *comment; //comment for group
-	IniItem *item, **last_item;
-	IniGroup *next;
-	IniFile *ini;
-	IniGroupType type; // type of group
-};
-
-struct IniFile {
-	SettingsMemoryPool *pool;
-	IniGroup *group, **last_group;
-	char *comment; // last comment in file
-};
-
-// allocate an inifile object
-static IniFile *ini_alloc(void)
-{
-	IniFile *ini;
-	SettingsMemoryPool *pool;
-	pool_init(&pool);
-	ini = (IniFile*)pool_alloc(&pool, sizeof(IniFile));
-	ini->pool = pool;
-	ini->group = NULL;
-	ini->last_group = &ini->group;
-	ini->comment = NULL;
-	return ini;
-}
-
-// allocate an ini group object
-static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
-{
-	IniGroup *grp = pool_alloc(&ini->pool, sizeof(IniGroup));
-	grp->ini = ini;
-	grp->name = pool_strdup(&ini->pool, grpt, len);
-	if (!strcmp(grp->name, "newgrf") || !strcmp(grp->name, "servers") || !strcmp(grp->name, "bans")) {
-		grp->type = IGT_LIST;
-	} else {
-		grp->type = IGT_VARIABLES;
-	}
-	grp->next = NULL;
-	grp->item = NULL;
-	grp->comment = NULL;
-	grp->last_item = &grp->item;
-	*ini->last_group = grp;
-	ini->last_group = &grp->next;
-	return grp;
-}
-
-static IniItem *ini_item_alloc(IniGroup *group, const char *name, int len)
-{
-	IniItem *item = pool_alloc(&group->ini->pool, sizeof(IniItem));
-	item->name = pool_strdup(&group->ini->pool, name, len);
-	item->next = NULL;
-	item->comment = NULL;
-	item->value = NULL;
-	*group->last_item = item;
-	group->last_item = &item->next;
-	return item;
-}
-
-// load an ini file into the "abstract" format
-static IniFile *ini_load(const char *filename)
-{
-	char buffer[1024], c, *s, *t, *e;
-	FILE *in;
-	IniFile *ini;
-	IniGroup *group = NULL;
-	IniItem *item;
-
-	char *comment = NULL;
-	uint comment_size = 0;
-	uint comment_alloc = 0;
-
-	ini = ini_alloc();
-
-	in = fopen(filename, "r");
-	if (in == NULL) return ini;
-
-	// for each line in the file
-	while (fgets(buffer, sizeof(buffer), in)) {
-
-		// trim whitespace from the left side
-		for (s = buffer; *s == ' ' || *s == '\t'; s++);
-
-		// trim whitespace from right side.
-		e = s + strlen(s);
-		while (e > s && ((c=e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
-		*e = '\0';
-
-		// skip comments and empty lines
-		if (*s == '#' || *s == ';' || *s == '\0') {
-			uint ns = comment_size + (e - s + 1);
-			uint a = comment_alloc;
-			uint pos;
-			// add to comment
-			if (ns > a) {
-				a = max(a, 128);
-				do a*=2; while (a < ns);
-				comment = realloc(comment, comment_alloc = a);
-			}
-			pos = comment_size;
-			comment_size += (e - s + 1);
-			comment[pos + e - s] = '\n'; // comment newline
-			memcpy(comment + pos, s, e - s); // copy comment contents
-			continue;
-		}
-
-		// it's a group?
-		if (s[0] == '[') {
-			if (e[-1] != ']') {
-				ShowInfoF("ini: invalid group name '%s'", buffer);
-			} else {
-				e--;
-			}
-			s++; // skip [
-			group = ini_group_alloc(ini, s, e - s);
-			if (comment_size) {
-				group->comment = pool_strdup(&ini->pool, comment, comment_size);
-				comment_size = 0;
-			}
-		} else if (group) {
-			// find end of keyname
-			for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
-
-			// it's an item in an existing group
-			item = ini_item_alloc(group, s, t-s);
-			if (comment_size) {
-				item->comment = pool_strdup(&ini->pool, comment, comment_size);
-				comment_size = 0;
-			}
-
-			// find start of parameter
-			while (*t == '=' || *t == ' ' || *t == '\t') t++;
-
-
-			// remove starting quotation marks
-			if (*t == '\"') t++;
-			// remove ending quotation marks
-			e = t + strlen(t);
-			if (e > t && e[-1] == '\"') e--;
-			*e = '\0';
-
-			item->value = pool_strdup(&ini->pool, t, e - t);
-		} else {
-			// it's an orphan item
-			ShowInfoF("ini: '%s' outside of group", buffer);
-		}
-	}
-
-	if (comment_size > 0) {
-		ini->comment = pool_strdup(&ini->pool, comment, comment_size);
-		comment_size = 0;
-	}
-
-	free(comment);
-	fclose(in);
-
-	return ini;
-}
-
-// lookup a group or make a new one
-static IniGroup *ini_getgroup(IniFile *ini, const char *name, int len)
-{
-	IniGroup *group;
-
-	if (len == -1) len = strlen(name);
-
-	// does it exist already?
-	for (group = ini->group; group; group = group->next)
-		if (!memcmp(group->name, name, len) && group->name[len] == 0)
-			return group;
-
-	// otherwise make a new one
-	group = ini_group_alloc(ini, name, len);
-	group->comment = pool_strdup(&ini->pool, "\n", 1);
-	return group;
-}
-
-// lookup an item or make a new one
-static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
-{
-	IniItem *item;
-	uint len = strlen(name);
-
-	for (item = group->item; item; item = item->next)
-		if (strcmp(item->name, name) == 0) return item;
-
-	if (!create) return NULL;
-
-	// otherwise make a new one
-	return ini_item_alloc(group, name, len);
-}
-
-// save ini file from the "abstract" format.
-static bool ini_save(const char *filename, IniFile *ini)
-{
-	FILE *f;
-	IniGroup *group;
-	IniItem *item;
-
-	f = fopen(filename, "w");
-	if (f == NULL) return false;
-
-	for (group = ini->group; group != NULL; group = group->next) {
-		if (group->comment) fputs(group->comment, f);
-		fprintf(f, "[%s]\n", group->name);
-		for (item = group->item; item != NULL; item = item->next) {
-			assert(item->value != NULL);
-			if (item->comment != NULL) fputs(item->comment, f);
-
-			/* Don't give an equal sign to list items that don't have a parameter */
-			if (group->type == IGT_LIST && *item->value == '\0') {
-				fprintf(f, "%s\n", item->name);
-			} else {
-				fprintf(f, "%s = %s\n", item->name, item->value);
-			}
-		}
-	}
-	if (ini->comment) fputs(ini->comment, f);
-
-	fclose(f);
-	return true;
-}
-
-static void ini_free(IniFile *ini)
-{
-	pool_free(&ini->pool);
-}
-
-/** Find the index value of a ONEofMANY type in a string seperated by |
- * @param many full domain of values the ONEofMANY setting can have
- * @param one the current value of the setting for which a value needs found
- * @param onelen force calculation of the *one parameter
- * @return the integer index of the full-list, or -1 if not found */
-static int lookup_oneofmany(const char *many, const char *one, int onelen)
-{
-	const char *s;
-	int idx;
-
-	if (onelen == -1) onelen = strlen(one);
-
-	// check if it's an integer
-	if (*one >= '0' && *one <= '9')
-		return strtoul(one, NULL, 0);
-
-	idx = 0;
-	for (;;) {
-		// find end of item
-		s = many;
-		while (*s != '|' && *s != 0) s++;
-		if (s - many == onelen && !memcmp(one, many, onelen)) return idx;
-		if (*s == 0) return -1;
-		many = s + 1;
-		idx++;
-	}
-}
-
-/** Find the set-integer value MANYofMANY type in a string
- * @param many full domain of values the MANYofMANY setting can have
- * @param str the current string value of the setting, each individual
- * of seperated by a whitespace\tab or | character
- * @return the 'fully' set integer, or -1 if a set is not found */
-static uint32 lookup_manyofmany(const char *many, const char *str)
-{
-	const char *s;
-	int r;
-	uint32 res = 0;
-
-	for (;;) {
-		// skip "whitespace"
-		while (*str == ' ' || *str == '\t' || *str == '|') str++;
-		if (*str == 0) break;
-
-		s = str;
-		while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
-
-		r = lookup_oneofmany(many, str, s - str);
-		if (r == -1) return (uint32)-1;
-
-		SETBIT(res, r); // value found, set it
-		if (*s == 0) break;
-		str = s + 1;
-	}
-	return res;
-}
-
-/** Parse an integerlist string and set each found value
- * @param p the string to be parsed. Each element in the list is seperated by a
- * comma or a space character
- * @param items pointer to the integerlist-array that will be filled with values
- * @param maxitems the maximum number of elements the integerlist-array has
- * @return returns the number of items found, or -1 on an error */
-static int parse_intlist(const char *p, int *items, int maxitems)
-{
-	int n = 0, v;
-	char *end;
-
-	for (;;) {
-		v = strtol(p, &end, 0);
-		if (p == end || n == maxitems) return -1;
-		p = end;
-		items[n++] = v;
-		if (*p == '\0') break;
-		if (*p != ',' && *p != ' ') return -1;
-		p++;
-	}
-
-	return n;
-}
-
-/** Load parsed string-values into an integer-array (intlist)
- * @param str the string that contains the values (and will be parsed)
- * @param array pointer to the integer-arrays that will be filled
- * @param nelems the number of elements the array holds. Maximum is 64 elements
- * @param type the type of elements the array holds (eg INT8, UINT16, etc.)
- * @return return true on success and false on error */
-static bool load_intlist(const char *str, void *array, int nelems, VarType type)
-{
-	int items[64];
-	int i, nitems;
-
-	if (str == NULL) {
-		memset(items, 0, sizeof(items));
-		nitems = nelems;
-	} else {
-		nitems = parse_intlist(str, items, lengthof(items));
-		if (nitems != nelems) return false;
-	}
-
-	switch (type) {
-	case SLE_VAR_BL:
-	case SLE_VAR_I8:
-	case SLE_VAR_U8:
-		for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i];
-		break;
-	case SLE_VAR_I16:
-	case SLE_VAR_U16:
-		for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i];
-		break;
-	case SLE_VAR_I32:
-	case SLE_VAR_U32:
-		for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i];
-		break;
-	default: NOT_REACHED();
-	}
-
-	return true;
-}
-
-/** Convert an integer-array (intlist) to a string representation. Each value
- * is seperated by a comma or a space character
- * @param buf output buffer where the string-representation will be stored
- * @param array pointer to the integer-arrays that is read from
- * @param nelems the number of elements the array holds.
- * @param type the type of elements the array holds (eg INT8, UINT16, etc.) */
-static void make_intlist(char *buf, const void *array, int nelems, VarType type)
-{
-	int i, v = 0;
-	const byte *p = (const byte*)array;
-
-	for (i = 0; i != nelems; i++) {
-		switch (type) {
-		case SLE_VAR_BL:
-		case SLE_VAR_I8:  v = *(int8*)p;   p += 1; break;
-		case SLE_VAR_U8:  v = *(byte*)p;   p += 1; break;
-		case SLE_VAR_I16: v = *(int16*)p;  p += 2; break;
-		case SLE_VAR_U16: v = *(uint16*)p; p += 2; break;
-		case SLE_VAR_I32: v = *(int32*)p;  p += 4; break;
-		case SLE_VAR_U32: v = *(uint32*)p; p += 4; break;
-		default: NOT_REACHED();
-		}
-		buf += sprintf(buf, (i == 0) ? "%d" : ",%d", v);
-	}
-}
-
-/** Convert a ONEofMANY structure to a string representation.
- * @param buf output buffer where the string-representation will be stored
- * @param many the full-domain string of possible values
- * @param id the value of the variable and whose string-representation must be found */
-static void make_oneofmany(char *buf, const char *many, int id)
-{
-	int orig_id = id;
-
-	// Look for the id'th element
-	while (--id >= 0) {
-		for (; *many != '|'; many++) {
-			if (*many == '\0') { // not found
-				sprintf(buf, "%d", orig_id);
-				return;
-			}
-		}
-		many++; // pass the |-character
-	}
-
-	// copy string until next item (|) or the end of the list if this is the last one
-	while (*many != '\0' && *many != '|') *buf++ = *many++;
-	*buf = '\0';
-}
-
-/** Convert a MANYofMANY structure to a string representation.
- * @param buf output buffer where the string-representation will be stored
- * @param many the full-domain string of possible values
- * @param x the value of the variable and whose string-representation must
- *        be found in the bitmasked many string */
-static void make_manyofmany(char *buf, const char *many, uint32 x)
-{
-	const char *start;
-	int i = 0;
-	bool init = true;
-
-	for (; x != 0; x >>= 1, i++) {
-		start = many;
-		while (*many != 0 && *many != '|') many++; // advance to the next element
-
-		if (HASBIT(x, 0)) { // item found, copy it
-			if (!init) *buf++ = '|';
-			init = false;
-			if (start == many) {
-				buf += sprintf(buf, "%d", i);
-			} else {
-				memcpy(buf, start, many - start);
-				buf += many - start;
-			}
-		}
-
-		if (*many == '|') many++;
-	}
-
-	*buf = '\0';
-}
-
-/** Convert a string representation (external) of a setting to the internal rep.
- * @param desc SettingDesc struct that holds all information about the variable
- * @param str input string that will be parsed based on the type of desc
- * @return return the parsed value of the setting */
-static const void *string_to_val(const SettingDescBase *desc, const char *str)
-{
-	switch (desc->cmd) {
-	case SDT_NUMX: {
-		char *end;
-		unsigned long val = strtoul(str, &end, 0);
-		if (*end != '\0') ShowInfoF("ini: trailing characters at end of setting '%s'", desc->name);
-		return (void*)val;
-	}
-	case SDT_ONEOFMANY: {
-		long r = lookup_oneofmany(desc->many, str, -1);
-		if (r != -1) return (void*)r;
-		ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
-		return 0;
-	}
-	case SDT_MANYOFMANY: {
-		unsigned long r = lookup_manyofmany(desc->many, str);
-		if (r != (unsigned long)-1) return (void*)r;
-		ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
-		return 0;
-	}
-	case SDT_BOOLX:
-		if (strcmp(str, "true")  == 0 || strcmp(str, "on")  == 0 || strcmp(str, "1") == 0)
-			return (void*)true;
-		if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0)
-			return (void*)false;
-		ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
-		break;
-
-	case SDT_STRING:
-	case SDT_INTLIST: return str;
-	}
-
-	return NULL;
-}
-
-/** Set the value of a setting and if needed clamp the value to
- * the preset minimum and maximum.
- * @param ptr the variable itself
- * @param sd pointer to the 'information'-database of the variable
- * @param val signed long version of the new value
- * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX,
- * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now */
-static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val)
-{
-	const SettingDescBase *sdb = &sd->desc;
-
-	if (sdb->cmd != SDT_BOOLX &&
-			sdb->cmd != SDT_NUMX &&
-			sdb->cmd != SDT_ONEOFMANY &&
-			sdb->cmd != SDT_MANYOFMANY) {
-		return;
-	}
-
-	/* We cannot know the maximum value of a bitset variable, so just have faith */
-	if (sdb->cmd != SDT_MANYOFMANY) {
-		/* We need to take special care of the uint32 type as we receive from the function
-		 * a signed integer. While here also bail out on 64-bit settings as those are not
-		 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
-		 * 32-bit variable
-		 * TODO: Support 64-bit settings/variables */
-		switch (GetVarMemType(sd->save.conv)) {
-			case SLE_VAR_BL:
-			case SLE_VAR_I8:
-			case SLE_VAR_U8:
-			case SLE_VAR_I16:
-			case SLE_VAR_U16:
-			case SLE_VAR_I32: {
-				/* Override the minimum value. No value below sdb->min, except special value 0 */
-				int32 min = ((sdb->flags & SGF_0ISDISABLED) && val <= sdb->min) ? 0 : sdb->min;
-				val = clamp(val, min, sdb->max);
-			} break;
-			case SLE_VAR_U32: {
-				/* Override the minimum value. No value below sdb->min, except special value 0 */
-				uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min;
-				WriteValue(ptr, SLE_VAR_U32, (int64)clampu(val, min, sdb->max));
-				return;
-			}
-			case SLE_VAR_I64:
-			case SLE_VAR_U64:
-			default: NOT_REACHED(); break;
-		}
-	}
-
-	WriteValue(ptr, sd->save.conv, (int64)val);
-}
-
-/** Load values from a group of an IniFile structure into the internal representation
- * @param ini pointer to IniFile structure that holds administrative information
- * @param sd pointer to SettingDesc structure whose internally pointed variables will
- *        be given values
- * @param grpname the group of the IniFile to search in for the new values */
-static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
-{
-	IniGroup *group;
-	IniGroup *group_def = ini_getgroup(ini, grpname, -1);
-	IniItem *item;
-	const void *p;
-	void *ptr;
-	const char *s;
-
-	for (; sd->save.cmd != SL_END; sd++) {
-		const SettingDescBase *sdb = &sd->desc;
-		const SaveLoad        *sld = &sd->save;
-
-		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
-
-		// XXX - wtf is this?? (group override?)
-		s = strchr(sdb->name, '.');
-		if (s != NULL) {
-			group = ini_getgroup(ini, sdb->name, s - sdb->name);
-			s++;
-		} else {
-			s = sdb->name;
-			group = group_def;
-		}
-
-		item = ini_getitem(group, s, false);
-		p = (item == NULL) ? sdb->def : string_to_val(sdb, item->value);
-		ptr = GetVariableAddress(object, sld);
-
-		switch (sdb->cmd) {
-		case SDT_BOOLX: /* All four are various types of (integer) numbers */
-		case SDT_NUMX:
-		case SDT_ONEOFMANY:
-		case SDT_MANYOFMANY:
-			Write_ValidateSetting(ptr, sd, (unsigned long)p); break;
-
-		case SDT_STRING:
-			switch (GetVarMemType(sld->conv)) {
-				case SLE_VAR_STRB:
-				case SLE_VAR_STRBQ:
-					if (p != NULL) ttd_strlcpy((char*)ptr, p, sld->length);
-					break;
-				case SLE_VAR_STR:
-				case SLE_VAR_STRQ:
-					if (p != NULL) {
-						free(*(char**)ptr);
-						*(char**)ptr = strdup((const char*)p);
-					}
-					break;
-				case SLE_VAR_CHAR: *(char*)ptr = *(char*)p; break;
-				default: NOT_REACHED(); break;
-			}
-			break;
-
-		case SDT_INTLIST: {
-			if (!load_intlist(p, ptr, sld->length, GetVarMemType(sld->conv)))
-				ShowInfoF("ini: error in array '%s'", sdb->name);
-			break;
-		}
-		default: NOT_REACHED(); break;
-		}
-	}
-}
-
-/** Save the values of settings to the inifile.
- * @param ini pointer to IniFile structure
- * @param sd read-only SettingDesc structure which contains the unmodified,
- *        loaded values of the configuration file and various information about it
- * @param grpname holds the name of the group (eg. [network]) where these will be saved
- * The function works as follows: for each item in the SettingDesc structure we
- * have a look if the value has changed since we started the game (the original
- * values are reloaded when saving). If settings indeed have changed, we get
- * these and save them.
- */
-static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
-{
-	IniGroup *group_def = NULL, *group;
-	IniItem *item;
-	char buf[512];
-	const char *s;
-	void *ptr;
-
-	for (; sd->save.cmd != SL_END; sd++) {
-		const SettingDescBase *sdb = &sd->desc;
-		const SaveLoad        *sld = &sd->save;
-
-		/* If the setting is not saved to the configuration
-		 * file, just continue with the next setting */
-		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
-		if (sld->conv & SLF_CONFIG_NO) continue;
-
-		// XXX - wtf is this?? (group override?)
-		s = strchr(sdb->name, '.');
-		if (s != NULL) {
-			group = ini_getgroup(ini, sdb->name, s - sdb->name);
-			s++;
-		} else {
-			if (group_def == NULL) group_def = ini_getgroup(ini, grpname, -1);
-			s = sdb->name;
-			group = group_def;
-		}
-
-		item = ini_getitem(group, s, true);
-		ptr = GetVariableAddress(object, sld);
-
-		if (item->value != NULL) {
-			// check if the value is the same as the old value
-			const void *p = string_to_val(sdb, item->value);
-
-			/* The main type of a variable/setting is in bytes 8-15
-			 * The subtype (what kind of numbers do we have there) is in 0-7 */
-			switch (sdb->cmd) {
-			case SDT_BOOLX:
-			case SDT_NUMX:
-			case SDT_ONEOFMANY:
-			case SDT_MANYOFMANY:
-				switch (GetVarMemType(sld->conv)) {
-				case SLE_VAR_BL:
-					if (*(bool*)ptr == (bool)(unsigned long)p) continue;
-					break;
-				case SLE_VAR_I8:
-				case SLE_VAR_U8:
-					if (*(byte*)ptr == (byte)(unsigned long)p) continue;
-					break;
-				case SLE_VAR_I16:
-				case SLE_VAR_U16:
-					if (*(uint16*)ptr == (uint16)(unsigned long)p) continue;
-					break;
-				case SLE_VAR_I32:
-				case SLE_VAR_U32:
-					if (*(uint32*)ptr == (uint32)(unsigned long)p) continue;
-					break;
-				default: NOT_REACHED();
-				}
-				break;
-			default: break; /* Assume the other types are always changed */
-			}
-		}
-
-		/* Value has changed, get the new value and put it into a buffer */
-		switch (sdb->cmd) {
-		case SDT_BOOLX:
-		case SDT_NUMX:
-		case SDT_ONEOFMANY:
-		case SDT_MANYOFMANY: {
-			uint32 i = (uint32)ReadValue(ptr, sld->conv);
-
-			switch (sdb->cmd) {
-			case SDT_BOOLX:      strcpy(buf, (i != 0) ? "true" : "false"); break;
-			case SDT_NUMX:       sprintf(buf, IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break;
-			case SDT_ONEOFMANY:  make_oneofmany(buf, sdb->many, i); break;
-			case SDT_MANYOFMANY: make_manyofmany(buf, sdb->many, i); break;
-			default: NOT_REACHED();
-			}
-		} break;
-
-		case SDT_STRING:
-			switch (GetVarMemType(sld->conv)) {
-			case SLE_VAR_STRB: strcpy(buf, (char*)ptr); break;
-			case SLE_VAR_STRBQ:sprintf(buf, "\"%s\"", (char*)ptr); break;
-			case SLE_VAR_STR:  strcpy(buf, *(char**)ptr); break;
-			case SLE_VAR_STRQ: sprintf(buf, "\"%s\"", *(char**)ptr); break;
-			case SLE_VAR_CHAR: sprintf(buf, "\"%c\"", *(char*)ptr); break;
-			default: NOT_REACHED();
-			}
-			break;
-
-		case SDT_INTLIST:
-			make_intlist(buf, ptr, sld->length, GetVarMemType(sld->conv));
-			break;
-		default: NOT_REACHED();
-		}
-
-		/* The value is different, that means we have to write it to the ini */
-		item->value = pool_strdup(&ini->pool, buf, strlen(buf));
-	}
-}
-
-/** Loads all items from a 'grpname' section into a list
- * The list parameter can be a NULL pointer, in this case nothing will be
- * saved and a callback function should be defined that will take over the
- * list-handling and store the data itself somewhere.
- * @param IniFile handle to the ini file with the source data
- * @param grpname character string identifying the section-header of the ini
- * file that will be parsed
- * @param list pointer to an string(pointer) array that will store the parsed
- * entries of the given section
- * @param len the maximum number of items available for the above list
- * @param proc callback function that can override how the values are stored
- * inside the list */
-static void ini_load_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
-{
-	IniGroup *group = ini_getgroup(ini, grpname, -1);
-	IniItem *item;
-	const char *entry;
-	uint i, j;
-
-	if (group == NULL) return;
-
-	for (i = j = 0, item = group->item; item != NULL; item = item->next) {
-		entry = (proc != NULL) ? proc(item, i++) : item->name;
-
-		if (entry == NULL || list == NULL) continue;
-
-		if (j == len) break;
-		list[j++] = strdup(entry);
-	}
-}
-
-/** Saves all items from a list into the 'grpname' section
- * The list parameter can be a NULL pointer, in this case a callback function
- * should be defined that will provide the source data to be saved.
- * @param IniFile handle to the ini file where the destination data is saved
- * @param grpname character string identifying the section-header of the ini file
- * @param list pointer to an string(pointer) array that will be used as the
- * source to be saved into the relevant ini section
- * @param len the maximum number of items available for the above list
- * @param proc callback function that can will provide the source data if defined */
-static void ini_save_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
-{
-	IniGroup *group = ini_getgroup(ini, grpname, -1);
-	IniItem *item = NULL;
-	const char *entry;
-	uint i;
-	bool first = true;
-
-	if (proc == NULL && list == NULL) return;
-	if (group == NULL) return;
-	group->item = NULL;
-
-	for (i = 0; i != len; i++) {
-		entry = (proc != NULL) ? proc(NULL, i) : list[i];
-
-		if (entry == NULL || *entry == '\0') continue;
-
-		if (first) { // add first item to the head of the group
-			item = ini_item_alloc(group, entry, strlen(entry));
-			item->value = item->name;
-			group->item = item;
-			first = false;
-		} else { // all other items are attached to the previous one
-			item->next = ini_item_alloc(group, entry, strlen(entry));
-			item = item->next;
-			item->value = item->name;
-		}
-	}
-}
-
-//***************************
-// OTTD specific INI stuff
-//***************************
-
-/** Settings-macro usage:
- * The list might look daunting at first, but is in general easy to understand.
- * We have two types of list:
- * 1. SDTG_something
- * 2. SDT_something
- * The 'G' stands for global, so this is the one you will use for a
- * SettingDescGlobVarList section meaning global variables. The other uses a
- * Base/Offset and runtime variable selection mechanism, known from the saveload * convention (it also has global so it should not be hard).
- * Of each type there are again two versions, the normal one and one prefixed
- * with 'COND'.
- * COND means that the setting is only valid in certain savegame versions
- * (since patches are saved to the savegame, this bookkeeping is necessary.
- * Now there are a lot of types. Easy ones are:
- * - VAR:  any number type, 'type' field specifies what number. eg int8 or uint32
- * - BOOL: a boolean number type
- * - STR:  a string or character. 'type' field specifies what string. Normal, string, or quoted
- * A bit more difficult to use are MMANY (meaning ManyOfMany) and OMANY (OneOfMany)
- * These are actually normal numbers, only bitmasked. In MMANY several bits can
- * be set, in the other only one.
- * The most complex type is INTLIST. This is basically an array of numbers. If
- * the intlist is only valid in certain savegame versions because for example
- * it has grown in size its length cannot be automatically be calculated so
- * use SDT(G)_CONDLISTO() meaning Old.
- * If nothing fits you, you can use the GENERAL macros, but it exposes the
- * internal structure somewhat so it needs a little looking. There are _NULL()
- * macros as well, these fill up space so you can add more patches there (in
- * place) and you DON'T have to increase the savegame version. */
-
-#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, proc)\
-	{name, (const void*)(def), cmd, guiflags, min, max, interval, many, str, proc}
-
-/* Macros for various objects to go in the configuration file.
- * This section is for global variables */
-#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, proc, from, to)\
-{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
-
-#define SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, proc, from, to)
-#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc)\
-	SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_UINT8, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, proc, from, to)
-#define SDTG_BOOL(name, flags, guiflags, var, def, str, proc)\
-	SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDLIST(name, type, length, flags, guiflags, var, def, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
-#define SDTG_LIST(name, type, flags, guiflags, var, def, str, proc)\
-	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDSTR(name, type, length, flags, guiflags, var, def, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
-#define SDTG_STR(name, type, flags, guiflags, var, def, str, proc)\
-	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max, full, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, proc, from, to)
-#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, proc)\
-	SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max full, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, from, to)\
-	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
-#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
-	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
-
-#define SDTG_CONDNULL(length, from, to)\
-	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_CONDNULL(length, from, to)}
-
-#define SDTG_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_END()}
-
-/* Macros for various objects to go in the configuration file.
- * This section is for structures where their various members are saved */
-#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, proc, from, to)\
-	{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)}
-
-#define SDT_CONDVAR(base, var, type, from, to, flags, guiflags, def, min, max, interval, str, proc)\
-	SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, proc, from, to)
-#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, proc)\
-	SDT_CONDVAR(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, min, max, interval, str, proc)
-
-#define SDT_CONDBOOL(base, var, from, to, flags, guiflags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, proc, from, to)
-#define SDT_BOOL(base, var, flags, guiflags, def, str, proc)\
-	SDT_CONDBOOL(base, var, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
-
-#define SDT_CONDLIST(base, var, type, from, to, flags, guiflags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, proc, from, to)
-#define SDT_LIST(base, var, type, flags, guiflags, def, str, proc)\
-	SDT_CONDLIST(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
-#define SDT_CONDLISTO(base, var, length, type, from, to, flags, guiflags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
-
-#define SDT_CONDSTR(base, var, type, from, to, flags, guiflags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, proc, from, to)
-#define SDT_STR(base, var, type, flags, guiflags, def, str, proc)\
-	SDT_CONDSTR(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
-#define SDT_CONDSTRO(base, var, length, type, from, to, flags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, 0, base, var, length, def, 0, 0, NULL, str, proc, from, to)
-
-#define SDT_CONDCHR(base, var, from, to, flags, guiflags, def, str, proc)\
-	SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, proc, from, to)
-#define SDT_CHR(base, var, flags, guiflags, def, str, proc)\
-	SDT_CONDCHR(base, var, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
-
-#define SDT_CONDOMANY(base, var, type, from, to, flags, guiflags, def, max, full, str, proc)\
-	SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, proc, from, to)
-#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, proc)\
-	SDT_CONDOMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, max, full, str, proc)
-
-#define SDT_CONDMMANY(base, var, type, from, to, flags, guiflags, def, full, str, proc)\
-	SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, proc, from, to)
-#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc)\
-	SDT_CONDMMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, full, str, proc)
-
-#define SDT_CONDNULL(length, from, to)\
-	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_CONDNULL(length, from, to)}
-
-#define SDT_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_END()}
-
-/* Shortcuts for macros below. Logically if we don't save the value
- * we also don't sync it in a network game */
-#define S SLF_SAVE_NO | SLF_NETWORK_NO
-#define NS SLF_SAVE_NO
-#define C SLF_CONFIG_NO
-#define N SLF_NETWORK_NO
-
-#define D0 SGF_0ISDISABLED
-#define NC SGF_NOCOMMA
-#define MS SGF_MULTISTRING
-#define NO SGF_NETWORK_ONLY
-#define CR SGF_CURRENCY
-
-#include "table/strings.h"
-
-/* Begin - Callback Functions for the various settings */
-#include "window.h"
-#include "gui.h"
-#include "town.h"
-#include "gfx.h"
-// virtual PositionMainToolbar function, calls the right one.
-static int32 v_PositionMainToolbar(int32 p1)
-{
-	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
-	return 0;
-}
-
-static int32 AiNew_PatchActive_Warning(int32 p1)
-{
-	if (p1 == 1) ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_ACTIVATED, 0, 0);
-	return 0;
-}
-
-static int32 Ai_In_Multiplayer_Warning(int32 p1)
-{
-	if (p1 == 1) {
-		ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_MULTIPLAYER, 0, 0);
-		_patches.ainew_active = true;
-	}
-	return 0;
-}
-
-static int32 PopulationInLabelActive(int32 p1)
-{
-	Town* t;
-
-	FOR_ALL_TOWNS(t) UpdateTownVirtCoord(t);
-
-	return 0;
-}
-
-static int32 RedrawScreen(int32 p1)
-{
-	MarkWholeScreenDirty();
-	return 0;
-}
-
-static int32 InValidateDetailsWindow(int32 p1)
-{
-	InvalidateWindowClasses(WC_VEHICLE_DETAILS);
-	return 0;
-}
-
-static int32 InvalidateStationBuildWindow(int32 p1)
-{
-	InvalidateWindow(WC_BUILD_STATION, 0);
-	return 0;
-}
-
-/* Check service intervals of vehicles, p1 is value of % or day based servicing */
-static int32 CheckInterval(int32 p1)
-{
-	bool warning;
-	const Patches *ptc = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-
-	if (p1) {
-		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   5, 90+1) || ptc->servint_trains   == 0) &&
-								(IS_INT_INSIDE(ptc->servint_roadveh,  5, 90+1) || ptc->servint_roadveh  == 0) &&
-								(IS_INT_INSIDE(ptc->servint_aircraft, 5, 90+1) || ptc->servint_aircraft == 0) &&
-								(IS_INT_INSIDE(ptc->servint_ships,    5, 90+1) || ptc->servint_ships    == 0) );
-	} else {
-		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   30, 800+1) || ptc->servint_trains   == 0) &&
-								(IS_INT_INSIDE(ptc->servint_roadveh,  30, 800+1) || ptc->servint_roadveh  == 0) &&
-								(IS_INT_INSIDE(ptc->servint_aircraft, 30, 800+1) || ptc->servint_aircraft == 0) &&
-								(IS_INT_INSIDE(ptc->servint_ships,    30, 800+1) || ptc->servint_ships    == 0) );
-	}
-
-	if (!warning)
-		ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE, 0, 0);
-
-	return InValidateDetailsWindow(0);
-}
-
-static int32 EngineRenewUpdate(int32 p1)
-{
-	DoCommandP(0, 0, _patches.autorenew, NULL, CMD_SET_AUTOREPLACE);
-	return 0;
-}
-
-static int32 EngineRenewMonthsUpdate(int32 p1)
-{
-	DoCommandP(0, 1, _patches.autorenew_months, NULL, CMD_SET_AUTOREPLACE);
-	return 0;
-}
-
-static int32 EngineRenewMoneyUpdate(int32 p1)
-{
-	DoCommandP(0, 2, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
-	return 0;
-}
-/* End - Callback Functions */
-
-#ifndef EXTERNAL_PLAYER
-#define EXTERNAL_PLAYER "timidity"
-#endif
-
-static const SettingDesc _music_settings[] = {
-	 SDT_VAR(MusicFileSettings, playlist,   SLE_UINT8, S, 0,   0, 0,   5, 1,  STR_NULL, NULL),
-	 SDT_VAR(MusicFileSettings, music_vol,  SLE_UINT8, S, 0, 128, 0, 100, 1,  STR_NULL, NULL),
-	 SDT_VAR(MusicFileSettings, effect_vol, SLE_UINT8, S, 0, 128, 0, 100, 1,  STR_NULL, NULL),
-	SDT_LIST(MusicFileSettings, custom_1,   SLE_UINT8, S, 0, NULL,            STR_NULL, NULL),
-	SDT_LIST(MusicFileSettings, custom_2,   SLE_UINT8, S, 0, NULL,            STR_NULL, NULL),
-	SDT_BOOL(MusicFileSettings, playing,               S, 0, true,            STR_NULL, NULL),
-	SDT_BOOL(MusicFileSettings, shuffle,               S, 0, false,           STR_NULL, NULL),
-	 SDT_STR(MusicFileSettings, extmidi,     SLE_STRB, S, 0, EXTERNAL_PLAYER, STR_NULL, NULL),
-	 SDT_END()
-};
-
-/* win32_v.c only settings */
-#ifdef WIN32
-extern bool _force_full_redraw, _double_size, _window_maximize;
-extern uint _display_hz, _fullscreen_bpp;
-
-static const SettingDescGlobVarList _win32_settings[] = {
-	 SDTG_VAR("display_hz",     SLE_UINT, S, 0, _display_hz,       0, 0, 120, 0, STR_NULL, NULL),
-	SDTG_BOOL("force_full_redraw",        S, 0, _force_full_redraw,false,        STR_NULL, NULL),
-	 SDTG_VAR("fullscreen_bpp", SLE_UINT, S, 0, _fullscreen_bpp,   8, 8,  32, 0, STR_NULL, NULL),
-	SDTG_BOOL("double_size",              S, 0, _double_size,      false,        STR_NULL, NULL),
-	SDTG_BOOL("window_maximize",          S, 0, _window_maximize,  false,        STR_NULL, NULL),
-	 SDTG_END()
-};
-#endif /* WIN32 */
-
-static const SettingDescGlobVarList _misc_settings[] = {
-	SDTG_MMANY("display_opt",     SLE_UINT8, S, 0, _display_opt,       (DO_SHOW_TOWN_NAMES|DO_SHOW_STATION_NAMES|DO_SHOW_SIGNS|DO_FULL_ANIMATION|DO_FULL_DETAIL|DO_TRANS_BUILDINGS|DO_WAYPOINTS), "SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION|TRANS_BUILDINGS|FULL_DETAIL|WAYPOINTS", STR_NULL, NULL),
-	  SDTG_VAR("news_display_opt", SLE_UINT, S, 0, _news_display_opt,0xAAAAAAAA,0,0xAAAAAAAA,0,STR_NULL, NULL), // default to all full messages: 10101010101010101010 = 0xAAAAAAAA
-	 SDTG_BOOL("news_ticker_sound",          S, 0, _news_ticker_sound,     true,    STR_NULL, NULL),
-	 SDTG_BOOL("fullscreen",                 S, 0, _fullscreen,           false,    STR_NULL, NULL),
-	  SDTG_STR("videodriver",      SLE_STRB,C|S,0, _ini_videodriver,       NULL,    STR_NULL, NULL),
-	  SDTG_STR("musicdriver",      SLE_STRB,C|S,0, _ini_musicdriver,       NULL,    STR_NULL, NULL),
-	  SDTG_STR("sounddriver",      SLE_STRB,C|S,0, _ini_sounddriver,       NULL,    STR_NULL, NULL),
-	  SDTG_STR("language",         SLE_STRB, S, 0, _dynlang.curr_file,     NULL,    STR_NULL, NULL),
-	 SDTG_LIST("resolution",     SLE_UINT16, S, 0, _cur_resolution,   "640,480",    STR_NULL, NULL),
-	  SDTG_STR("screenshot_format",SLE_STRB, S, 0, _screenshot_format_name,NULL,    STR_NULL, NULL),
-	  SDTG_STR("savegame_format",  SLE_STRB, S, 0, _savegame_format,       NULL,    STR_NULL, NULL),
-	 SDTG_BOOL("rightclick_emulate",         S, 0, _rightclick_emulate,   false,    STR_NULL, NULL),
-#ifdef WITH_FREETYPE
-	  SDTG_STR("small_font",       SLE_STRB, S, 0, _freetype.small_font,   NULL,    STR_NULL, NULL),
-	  SDTG_STR("medium_font",      SLE_STRB, S, 0, _freetype.medium_font,  NULL,    STR_NULL, NULL),
-	  SDTG_STR("large_font",       SLE_STRB, S, 0, _freetype.large_font,   NULL,    STR_NULL, NULL),
-	  SDTG_VAR("small_size",       SLE_UINT, S, 0, _freetype.small_size,   6, 0, 72, 0, STR_NULL, NULL),
-	  SDTG_VAR("medium_size",      SLE_UINT, S, 0, _freetype.medium_size, 10, 0, 72, 0, STR_NULL, NULL),
-	  SDTG_VAR("large_size",       SLE_UINT, S, 0, _freetype.large_size,  16, 0, 72, 0, STR_NULL, NULL),
-#endif
-	  SDTG_END()
-};
-
-#ifdef ENABLE_NETWORK
-static const SettingDescGlobVarList _network_settings[] = {
-	 SDTG_VAR("sync_freq",           SLE_UINT16,C|S,0, _network_sync_freq,            100, 0,   100,   0, STR_NULL, NULL),
-	 SDTG_VAR("frame_freq",           SLE_UINT8,C|S,0, _network_frame_freq,             0, 0,   100,   0, STR_NULL, NULL),
-	 SDTG_VAR("max_join_time",       SLE_UINT16, S, 0, _network_max_join_time,        500, 0, 32000,   0, STR_NULL, NULL),
-	SDTG_BOOL("pause_on_join",                   S, 0, _network_pause_on_join,        true,               STR_NULL, NULL),
-	 SDTG_STR("server_bind_ip",        SLE_STRB, S, 0, _network_server_bind_ip_host,  "0.0.0.0",          STR_NULL, NULL),
-	 SDTG_VAR("server_port",         SLE_UINT16, S, 0, _network_server_port,          NETWORK_DEFAULT_PORT, 0, 65535, 0, STR_NULL, NULL),
-	SDTG_BOOL("server_advertise",                S, 0, _network_advertise,            false,              STR_NULL, NULL),
-	 SDTG_VAR("lan_internet",         SLE_UINT8, S, 0, _network_lan_internet,           0, 0,     1,   0, STR_NULL, NULL),
-	 SDTG_STR("player_name",           SLE_STRB, S, 0, _network_player_name,          NULL,               STR_NULL, NULL),
-	 SDTG_STR("server_password",       SLE_STRB, S, 0, _network_server_password,      NULL,               STR_NULL, NULL),
-	 SDTG_STR("rcon_password",         SLE_STRB, S, 0, _network_rcon_password,        NULL,               STR_NULL, NULL),
-	 SDTG_STR("server_name",           SLE_STRB, S, 0, _network_server_name,          NULL,               STR_NULL, NULL),
-	 SDTG_STR("connect_to_ip",         SLE_STRB, S, 0, _network_default_ip,           NULL,               STR_NULL, NULL),
-	 SDTG_STR("network_id",            SLE_STRB, S, 0, _network_unique_id,            NULL,               STR_NULL, NULL),
-	SDTG_BOOL("autoclean_companies",             S, 0, _network_autoclean_companies,  false,              STR_NULL, NULL),
-	 SDTG_VAR("autoclean_unprotected",SLE_UINT8, S, 0, _network_autoclean_unprotected,12, 0,     60,   0, STR_NULL, NULL),
-	 SDTG_VAR("autoclean_protected",  SLE_UINT8, S, 0, _network_autoclean_protected,  36, 0,    180,   0, STR_NULL, NULL),
-	 SDTG_VAR("max_companies",        SLE_UINT8, S, 0, _network_game_info.companies_max,   8, 0,  8,   0, STR_NULL, NULL),
-	 SDTG_VAR("max_clients",          SLE_UINT8, S, 0, _network_game_info.clients_max,    10, 0, 10,   0, STR_NULL, NULL),
-	 SDTG_VAR("max_spectators",       SLE_UINT8, S, 0, _network_game_info.spectators_max, 10, 0, 10,   0, STR_NULL, NULL),
-	 SDTG_VAR("restart_game_year",    SLE_INT32, S,D0, _network_restart_game_year,    0, MIN_YEAR, MAX_YEAR, 1, STR_NULL, NULL),
-	 SDTG_VAR("min_players",          SLE_UINT8, S, 0, _network_min_players,               0, 0, 10,   0, STR_NULL, NULL),
-	 SDTG_END()
-};
-#endif /* ENABLE_NETWORK */
-
-static const SettingDesc _gameopt_settings[] = {
-	/* In version 4 a new difficulty setting has been added to the difficulty settings,
-	 * town attitude towards demolishing. Needs special handling because some dimwit thought
-	 * it funny to have the GameDifficulty struct be an array while it is a struct of
-	 * same-sized members
-	 * XXX - To save file-space and since values are never bigger than about 10? only
-	 * save the first 16 bits in the savegame. Question is why the values are still int32
-	 * and why not byte for example? */
-	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, 0, 3),
-	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, 4, SL_MAX_VERSION),
-	    SDT_VAR(GameOptions, diff_level,SLE_UINT8, 0, 0, 9, 0,  9, 0, STR_NULL, NULL),
-	  SDT_OMANY(GameOptions, currency,  SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL),
-	  SDT_OMANY(GameOptions, units,     SLE_UINT8, N, 0, 1,     2, "imperial|metric|si", STR_NULL, NULL),
-	  SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0,    20, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL),
-	  SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0,     3, "normal|hilly|desert|candy", STR_NULL, NULL),
-	    SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 1, 0, 56, 0, STR_NULL, NULL),
-	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8, 0, 22,             N, 0, 0, 0, "", STR_NULL, NULL),
-	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8,23, SL_MAX_VERSION, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL),
-	  SDT_OMANY(GameOptions, road_side, SLE_UINT8, 0, 0, 1,   1, "left|right", STR_NULL, NULL),
-	    SDT_END()
-};
-
-/* Some patches do not need to be synchronised when playing in multiplayer.
- * These include for example the GUI settings and will not be saved with the
- * savegame.
- * It is also a bit tricky since you would think that service_interval
- * for example doesn't need to be synched. Every client assigns the
- * service_interval value to the v->service_interval, meaning that every client
- * assigns his value. If the setting was player-based, that would mean that
- * vehicles could decide on different moments that they are heading back to a
- * service depot, causing desyncs on a massive scale. */
-const SettingDesc _patch_settings[] = {
-	/***************************************************************************/
-	/* User-interface section of the GUI-configure patches window */
-	SDT_BOOL(Patches, vehicle_speed,                 S, 0,  true,        STR_CONFIG_PATCHES_VEHICLESPEED,          NULL),
-	SDT_BOOL(Patches, status_long_date,              S, 0,  true,        STR_CONFIG_PATCHES_LONGDATE,              NULL),
-	SDT_BOOL(Patches, show_finances,                 S, 0,  true,        STR_CONFIG_PATCHES_SHOWFINANCES,          NULL),
-	SDT_BOOL(Patches, autoscroll,                    S, 0, false,        STR_CONFIG_PATCHES_AUTOSCROLL,            NULL),
-	SDT_BOOL(Patches, reverse_scroll,                S, 0, false,        STR_CONFIG_PATCHES_REVERSE_SCROLLING,     NULL),
-	SDT_BOOL(Patches, measure_tooltip,               S, 0, false,        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,       NULL),
-	 SDT_VAR(Patches, errmsg_duration,    SLE_UINT8, S, 0,  5, 0, 20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,       NULL),
-	 SDT_VAR(Patches, toolbar_pos,        SLE_UINT8, S,MS,  0, 0,  2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,           v_PositionMainToolbar),
-	 SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1, 32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,           NULL),
-	SDT_BOOL(Patches, invisible_trees,               S, 0, false,        STR_CONFIG_PATCHES_INVISIBLE_TREES,       RedrawScreen),
-	SDT_BOOL(Patches, population_in_label,           S, 0,  true,        STR_CONFIG_PATCHES_POPULATION_IN_LABEL,   PopulationInLabelActive),
-	 SDT_VAR(Patches, map_x,              SLE_UINT8, S, 0,  8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_X,                 NULL),
-	 SDT_VAR(Patches, map_y,              SLE_UINT8, S, 0,  8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_Y,                 NULL),
-	SDT_BOOL(Patches, link_terraform_toolbar,        S, 0, false,        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL),
-	 SDT_VAR(Patches, liveries,           SLE_UINT8, S,MS,  2, 0,  2, 0, STR_CONFIG_PATCHES_LIVERIES,              RedrawScreen),
-	SDT_BOOL(Patches, prefer_teamchat,               S, 0, false,        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,       NULL),
-
-	/***************************************************************************/
-	/* Construction section of the GUI-configure patches window */
-	SDT_BOOL(Patches, build_on_slopes,               0, 0,  true,        STR_CONFIG_PATCHES_BUILDONSLOPES,       NULL),
-	SDT_BOOL(Patches, extra_dynamite,                0, 0, false,        STR_CONFIG_PATCHES_EXTRADYNAMITE,       NULL),
-	SDT_BOOL(Patches, longbridges,                   0, 0,  true,        STR_CONFIG_PATCHES_LONGBRIDGES,         NULL),
-	SDT_BOOL(Patches, signal_side,                   N, 0,  true,        STR_CONFIG_PATCHES_SIGNALSIDE,          RedrawScreen),
-	SDT_BOOL(Patches, always_small_airport,          0, 0, false,        STR_CONFIG_PATCHES_SMALL_AIRPORTS,      NULL),
-	 SDT_VAR(Patches, drag_signals_density,SLE_UINT8,S, 0,  4, 1, 20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,NULL),
-
-	/***************************************************************************/
-	/* Vehicle section of the GUI-configure patches window */
-	SDT_BOOL(Patches, realistic_acceleration,        0, 0, false,                    STR_CONFIG_PATCHES_REALISTICACCEL,       NULL),
-	SDT_BOOL(Patches, forbid_90_deg,                 0, 0, false,                    STR_CONFIG_PATCHES_FORBID_90_DEG,        NULL),
-	SDT_BOOL(Patches, mammoth_trains,                0, 0,  true,                    STR_CONFIG_PATCHES_MAMMOTHTRAINS,        NULL),
-	SDT_BOOL(Patches, gotodepot,                     0, 0,  true,                    STR_CONFIG_PATCHES_GOTODEPOT,            NULL),
-	SDT_BOOL(Patches, roadveh_queue,                 0, 0,  true,                    STR_CONFIG_PATCHES_ROADVEH_QUEUE,        NULL),
-	SDT_BOOL(Patches, new_pathfinding_all,           0, 0, false,                    STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL,  NULL),
-
-	SDT_CONDBOOL(Patches, yapf.ship_use_yapf,      28, SL_MAX_VERSION, 0, 0, false,  STR_CONFIG_PATCHES_YAPF_SHIPS,      NULL),
-	SDT_CONDBOOL(Patches, yapf.road_use_yapf,      28, SL_MAX_VERSION, 0, 0,  true,  STR_CONFIG_PATCHES_YAPF_ROAD,       NULL),
-	SDT_CONDBOOL(Patches, yapf.rail_use_yapf,      28, SL_MAX_VERSION, 0, 0,  true,  STR_CONFIG_PATCHES_YAPF_RAIL,       NULL),
-
-	SDT_BOOL(Patches, train_income_warn,             S, 0,  true,                    STR_CONFIG_PATCHES_WARN_INCOME_LESS,     NULL),
-	 SDT_VAR(Patches, order_review_system,SLE_UINT8, S,MS,     2,     0,       2, 0, STR_CONFIG_PATCHES_ORDER_REVIEW,         NULL),
-	SDT_BOOL(Patches, never_expire_vehicles,         0, 0, false,                    STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES,NULL),
-	SDT_BOOL(Patches, lost_train_warn,               S, 0,  true,                    STR_CONFIG_PATCHES_WARN_LOST_TRAIN,      NULL),
-	SDT_BOOL(Patches, autorenew,                     S, 0, false,                    STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,    EngineRenewUpdate),
-	 SDT_VAR(Patches, autorenew_months,   SLE_INT16, S, 0,     6,   -12,      12, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS,     EngineRenewMonthsUpdate),
-	 SDT_VAR(Patches, autorenew_money,     SLE_UINT, S,CR,100000,     0, 2000000, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY,      EngineRenewMoneyUpdate),
-	 SDT_VAR(Patches, max_trains,        SLE_UINT16, 0, 0,   500,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_TRAINS,           NULL),
-	 SDT_VAR(Patches, max_roadveh,       SLE_UINT16, 0, 0,   500,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_ROADVEH,          NULL),
-	 SDT_VAR(Patches, max_aircraft,      SLE_UINT16, 0, 0,   200,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_AIRCRAFT,         NULL),
-	 SDT_VAR(Patches, max_ships,         SLE_UINT16, 0, 0,   300,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_SHIPS,            NULL),
-	SDT_BOOL(Patches, servint_ispercent,             0, 0, false,                    STR_CONFIG_PATCHES_SERVINT_ISPERCENT,    CheckInterval),
-	 SDT_VAR(Patches, servint_trains,    SLE_UINT16, 0,D0,   150,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_TRAINS,       InValidateDetailsWindow),
-	 SDT_VAR(Patches, servint_roadveh,   SLE_UINT16, 0,D0,   150,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_ROADVEH,      InValidateDetailsWindow),
-	 SDT_VAR(Patches, servint_ships,     SLE_UINT16, 0,D0,   360,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_SHIPS,        InValidateDetailsWindow),
-	 SDT_VAR(Patches, servint_aircraft,  SLE_UINT16, 0,D0,   100,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_AIRCRAFT,     InValidateDetailsWindow),
-	SDT_BOOL(Patches, no_servicing_if_no_breakdowns, 0, 0, false,                    STR_CONFIG_PATCHES_NOSERVICE,            NULL),
-	SDT_BOOL(Patches, wagon_speed_limits,            0, 0,  true,                    STR_CONFIG_PATCHES_WAGONSPEEDLIMITS,     NULL),
-	SDT_CONDBOOL(Patches, disable_elrails, 38, SL_MAX_VERSION, 0, 0, false,          STR_CONFIG_PATCHES_DISABLE_ELRAILS,      SettingsDisableElrail),
-	SDT_CONDVAR(Patches, freight_trains, SLE_UINT8, 39, SL_MAX_VERSION, 0, 0, 1, 1, 255, 1, STR_CONFIG_PATCHES_FREIGHT_TRAINS, NULL),
-
-	/***************************************************************************/
-	/* Station section of the GUI-configure patches window */
-	SDT_BOOL(Patches, join_stations,           0, 0,  true,        STR_CONFIG_PATCHES_JOINSTATIONS,       NULL),
-	SDT_BOOL(Patches, full_load_any,           0, 0,  true,        STR_CONFIG_PATCHES_FULLLOADANY,        NULL),
-	SDT_BOOL(Patches, improved_load,           0, 0, false,        STR_CONFIG_PATCHES_IMPROVEDLOAD,       NULL),
-	SDT_BOOL(Patches, selectgoods,             0, 0,  true,        STR_CONFIG_PATCHES_SELECTGOODS,        NULL),
-	SDT_BOOL(Patches, new_nonstop,             0, 0, false,        STR_CONFIG_PATCHES_NEW_NONSTOP,        NULL),
-	SDT_BOOL(Patches, nonuniform_stations,     0, 0,  true,        STR_CONFIG_PATCHES_NONUNIFORM_STATIONS,NULL),
-	 SDT_VAR(Patches, station_spread,SLE_UINT8,0, 0, 12, 4, 64, 0, STR_CONFIG_PATCHES_STATION_SPREAD,     InvalidateStationBuildWindow),
-	SDT_BOOL(Patches, serviceathelipad,        0, 0,  true,        STR_CONFIG_PATCHES_SERVICEATHELIPAD,   NULL),
-	SDT_BOOL(Patches, modified_catchment,      0, 0,  true,        STR_CONFIG_PATCHES_CATCHMENT,          NULL),
-	SDT_CONDBOOL(Patches, gradual_loading, 40, SL_MAX_VERSION, 0, 0,  true, STR_CONFIG_PATCHES_GRADUAL_LOADING,    NULL),
-
-	/***************************************************************************/
-	/* Economy section of the GUI-configure patches window */
-	SDT_BOOL(Patches, inflation,                  0, 0,  true,            STR_CONFIG_PATCHES_INFLATION,        NULL),
-	SDT_BOOL(Patches, build_rawmaterial_ind,      0, 0, false,            STR_CONFIG_PATCHES_BUILDXTRAIND,     NULL),
-	SDT_BOOL(Patches, multiple_industry_per_town, 0, 0, false,            STR_CONFIG_PATCHES_MULTIPINDTOWN,    NULL),
-	SDT_BOOL(Patches, same_industry_close,        0, 0, false,            STR_CONFIG_PATCHES_SAMEINDCLOSE,     NULL),
-	SDT_BOOL(Patches, bribe,                      0, 0,  true,            STR_CONFIG_PATCHES_BRIBE,            NULL),
-	 SDT_VAR(Patches, snow_line_height,SLE_UINT8, 0, 0,     7,  2, 13, 0, STR_CONFIG_PATCHES_SNOWLINE_HEIGHT,  NULL),
-	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
-	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
-	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
-	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
-	SDT_BOOL(Patches, allow_shares,               0, 0,  true,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
-
-	/***************************************************************************/
-	/* AI section of the GUI-configure patches window */
-	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
-	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
-	SDT_BOOL(Patches, ai_disable_veh_train,   0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_TRAINS,  NULL),
-	SDT_BOOL(Patches, ai_disable_veh_roadveh, 0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_ROADVEH, NULL),
-	SDT_BOOL(Patches, ai_disable_veh_aircraft,0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_AIRCRAFT,NULL),
-	SDT_BOOL(Patches, ai_disable_veh_ship,    0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_SHIPS,   NULL),
-
-	/***************************************************************************/
-	/* Patches without any GUI representation */
-	SDT_BOOL(Patches, keep_all_autosave,              S, 0, false,         STR_NULL, NULL),
-	SDT_BOOL(Patches, autosave_on_exit,               S, 0, false,         STR_NULL, NULL),
-	 SDT_VAR(Patches, max_num_autosaves,   SLE_UINT8, S, 0, 16, 0, 255, 0, STR_NULL, NULL),
-	SDT_BOOL(Patches, bridge_pillars,                 S, 0,  true,         STR_NULL, NULL),
-	 SDT_VAR(Patches, extend_vehicle_life, SLE_UINT8, 0, 0,  0, 0, 100, 0, STR_NULL, NULL),
-	SDT_BOOL(Patches, auto_euro,                      S, 0,  true,         STR_NULL, NULL),
-	 SDT_VAR(Patches, dist_local_authority,SLE_UINT8, 0, 0, 20, 5,  60, 0, STR_NULL, NULL),
-	 SDT_VAR(Patches, wait_oneway_signal,  SLE_UINT8, 0, 0, 15, 2, 100, 0, STR_NULL, NULL),
-	 SDT_VAR(Patches, wait_twoway_signal,  SLE_UINT8, 0, 0, 41, 2, 100, 0, STR_NULL, NULL),
-
-	/***************************************************************************/
-	/* New Pathfinding patch settings */
-	SDT_VAR(Patches, pf_maxlength,      SLE_UINT16, 0, 0,  4096,  64,  65535, 0, STR_NULL, NULL),
-	SDT_VAR(Patches, pf_maxdepth,        SLE_UINT8, 0, 0,    48,   4,    255, 0, STR_NULL, NULL),
-	/* The maximum number of nodes to search */
-	SDT_VAR(Patches, npf_max_search_nodes,SLE_UINT, 0, 0, 10000, 500, 100000, 0, STR_NULL, NULL),
-
-	/* When a red signal is encountered, a small detour can be made around
-	 * it. This specifically occurs when a track is doubled, in which case
-	 * the detour is typically 2 tiles. It is also often used at station
-	 * entrances, when there is a choice of multiple platforms. If we take
-	 * a typical 4 platform station, the detour is 4 tiles. To properly
-	 * support larger stations we increase this value.
-	 * We want to prevent that trains that want to leave at one side of a
-	 * station, leave through the other side, turn around, enter the
-	 * station on another platform and exit the station on the right side
-	 * again, just because the sign at the right side was red. If we take
-	 * a typical 5 length station, this detour is 10 or 11 tiles (not
-	 * sure), so we set the default penalty at 10 (the station tile
-	 * penalty will further prevent this.
-	 * We give presignal exits (and combo's) a different (larger) penalty, because
-	 * we really don't want trains waiting in front of a presignal exit. */
-	SDT_VAR(Patches, npf_rail_firstred_penalty,     SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
-	SDT_VAR(Patches, npf_rail_firstred_exit_penalty,SLE_UINT, 0, 0, (100 * NPF_TILE_LENGTH),0, 100000, 0, STR_NULL, NULL),
-	/* This penalty is for when the last signal before the target is red.
-	 * This is useful for train stations, where there are multiple
-	 * platforms to choose from, which lie in different signal blocks.
-	 * Every target in a occupied signal block (ie an occupied platform)
-	 * will get this penalty. */
-	SDT_VAR(Patches, npf_rail_lastred_penalty, SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
-	/* When a train plans a route over a station tile, this penalty is
-	 * applied. We want that trains plan a route around a typical, 4x5
-	 * station, which means two tiles to the right, and two tiles back to
-	 * the left around it, or 5 tiles of station through it. If we assign
-	 * a penalty of 1 tile for every station tile passed, the route will
-	 * be around it. */
-	SDT_VAR(Patches, npf_rail_station_penalty, SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
-	SDT_VAR(Patches, npf_rail_slope_penalty,   SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
-	/* This penalty is applied when a train makes a turn. Its value of 1 makes
-	 * sure that it has a minimal impact on the pathfinding, only when two
-	 * paths have equal length it will make a difference */
-	SDT_VAR(Patches, npf_rail_curve_penalty,        SLE_UINT, 0, 0, 1,                      0, 100000, 0, STR_NULL, NULL),
-	/* Ths penalty is applied when a vehicle reverses inside a depot (doesn't
-	 * apply to ships, as they can just come out the other end). XXX: Is this a
-	 * good value? */
-	SDT_VAR(Patches, npf_rail_depot_reverse_penalty,SLE_UINT, 0, 0, (NPF_TILE_LENGTH * 50), 0, 100000, 0, STR_NULL, NULL),
-	SDT_VAR(Patches, npf_buoy_penalty,              SLE_UINT, 0, 0, (2 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
-	/* This penalty is applied when a ship makes a turn. It is bigger than the
-	 * rail curve penalty, since ships (realisticly) have more trouble with
-	 * making turns */
-	SDT_VAR(Patches, npf_water_curve_penalty,       SLE_UINT, 0, 0, (NPF_TILE_LENGTH / 4),  0, 100000, 0, STR_NULL, NULL),
-	/* This is the penalty for road, same as for rail. */
-	SDT_VAR(Patches, npf_road_curve_penalty,        SLE_UINT, 0, 0, 1,                      0, 100000, 0, STR_NULL, NULL),
-	/* This is the penalty for level crossings, for both road and rail vehicles */
-	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
-
-
-	// The maximum number of nodes to search
-	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_firstred_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_firstred_exit_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_lastred_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_lastred_exit_penalty  , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_station_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    30 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_slope_penalty         , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     2 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_curve45_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     1 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_curve90_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     6 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	// This penalty is applied when a train reverses inside a depot
-	SDT_CONDVAR (Patches, yapf.rail_depot_reverse_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    50 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	// This is the penalty for level crossings (for trains only)
-	SDT_CONDVAR (Patches, yapf.rail_crossing_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     3 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
-	// look-ahead how many signals are checked
-	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
-	// look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0
-	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
-	// penalties for too long or too short station platforms
-	SDT_CONDVAR (Patches, yapf.rail_longer_platform_penalty,           SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_longer_platform_per_tile_penalty,  SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_penalty,          SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 40 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_per_tile_penalty, SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
-	// road vehicles - penalties
-	SDT_CONDVAR (Patches, yapf.road_slope_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  2 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.road_curve_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  1 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
-	SDT_CONDVAR (Patches, yapf.road_crossing_penalty                 , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  3 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
-
-	/***************************************************************************/
-	/* Terrain genation related patch options */
-	SDT_CONDVAR(Patches,      land_generator,           SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   1,                   0,    1,               0, STR_CONFIG_PATCHES_LAND_GENERATOR,           NULL),
-	SDT_CONDVAR(Patches,      oil_refinery_limit,       SLE_UINT8,  30, SL_MAX_VERSION, 0, 0,   16,                  12,   48,               0, STR_CONFIG_PATCHES_OIL_REF_EDGE_DISTANCE,    NULL),
-	SDT_CONDVAR(Patches,      tgen_smoothness,          SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   1,                   0,    3,               0, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN,     NULL),
-	SDT_CONDVAR(Patches,      generation_seed,          SLE_UINT32, 30, SL_MAX_VERSION, 0, 0,    GENERATE_NEW_SEED,   0, MAX_UVALUE(uint32), 0, STR_NULL,                                    NULL),
-	SDT_CONDVAR(Patches,      tree_placer,              SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   2,                   0,    2,               0, STR_CONFIG_PATCHES_TREE_PLACER,              NULL),
-	SDT_VAR    (Patches,      heightmap_rotation,       SLE_UINT8,                      S, MS,   0,                   0,    1,               0, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION,       NULL),
-	SDT_VAR    (Patches,      se_flat_world_height,     SLE_UINT8,                      S, 0,    0,                   0,   15,               0, STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT,     NULL),
-
-	SDT_END()
-};
-
-static const SettingDesc _currency_settings[] = {
-	SDT_VAR(CurrencySpec, rate,    SLE_UINT16, S, 0,  1, 0, 100, 0, STR_NULL, NULL),
-	SDT_CHR(CurrencySpec, separator,           S, 0,        ".",    STR_NULL, NULL),
-	SDT_VAR(CurrencySpec, to_euro,  SLE_INT32, S, 0,  0, 0,1000, 0, STR_NULL, NULL),
-	SDT_STR(CurrencySpec, prefix,   SLE_STRBQ, S, 0,       NULL,    STR_NULL, NULL),
-	SDT_STR(CurrencySpec, suffix,   SLE_STRBQ, S, 0, " credits",    STR_NULL, NULL),
-	SDT_END()
-};
-
-/* Undefine for the shortcut macros above */
-#undef S
-#undef C
-#undef N
-
-#undef D0
-#undef NC
-#undef MS
-#undef NO
-#undef CR
-
-
-/* Load a GRF configuration from the given group name */
-static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static)
-{
-	IniGroup *group = ini_getgroup(ini, grpname, -1);
-	IniItem *item;
-	GRFConfig *first = NULL;
-	GRFConfig **curr = &first;
-
-	if (group == NULL) return NULL;
-
-	for (item = group->item; item != NULL; item = item->next) {
-		GRFConfig *c = calloc(1, sizeof(*c));
-		c->filename = strdup(item->name);
-
-		/* Parse parameters */
-		if (*item->value != '\0') {
-			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
-			if (c->num_params == (byte)-1) {
-				ShowInfoF("ini: error in array '%s'", item->name);
-				c->num_params = 0;
-			}
-		}
-
-		/* Check if item is valid */
-		if (!FillGRFDetails(c, is_static)) {
-			const char *msg;
-
-			if (HASBIT(c->flags, GCF_NOT_FOUND)) {
-				msg = "not found";
-			} else if (HASBIT(c->flags, GCF_UNSAFE)) {
-				msg = "unsafe for static use";
-			} else if (HASBIT(c->flags, GCF_SYSTEM)) {
-				msg = "system NewGRF";
-			} else {
-				msg = "unknown";
-			}
-
-			ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg);
-			ClearGRFConfig(&c);
-			continue;
-		}
-
-		/* Mark file as static to avoid saving in savegame. */
-		if (is_static) SETBIT(c->flags, GCF_STATIC);
-
-		/* Add item to list */
-		*curr = c;
-		curr = &c->next;
-	}
-
-	return first;
-}
-
-
-/* Save a GRF configuration to the given group name */
-static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list)
-{
-	IniGroup *group = ini_getgroup(ini, grpname, -1);
-	IniItem **item;
-	const GRFConfig *c;
-
-	if (group == NULL) return;
-	group->item = NULL;
-	item = &group->item;
-
-	for (c = list; c != NULL; c = c->next) {
-		char params[512];
-		GRFBuildParamList(params, c, lastof(params));
-
-		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
-		(*item)->value = pool_strdup(&ini->pool, params, strlen(params));
-		item = &(*item)->next;
-	}
-}
-
-/* Common handler for saving/loading variables to the configuration file */
-static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list)
-{
-	proc(ini, (const SettingDesc*)_misc_settings,    "misc",  NULL);
-	proc(ini, (const SettingDesc*)_music_settings,   "music", &msf);
-#ifdef WIN32
-	proc(ini, (const SettingDesc*)_win32_settings,   "win32", NULL);
-#endif /* WIN32 */
-
-	proc(ini, _gameopt_settings, "gameopt",  &_opt_newgame);
-	proc(ini, _patch_settings,   "patches",  &_patches_newgame);
-	proc(ini, _currency_settings,"currency", &_custom_currency);
-
-#ifdef ENABLE_NETWORK
-	proc(ini, (const SettingDesc*)_network_settings, "network", NULL);
-	proc_list(ini, "servers", _network_host_list, lengthof(_network_host_list), NULL);
-	proc_list(ini, "bans",    _network_ban_list,  lengthof(_network_ban_list), NULL);
-#endif /* ENABLE_NETWORK */
-}
-
-/** Load the values from the configuration files */
-void LoadFromConfig(void)
-{
-	IniFile *ini = ini_load(_config_file);
-	HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
-	_grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
-	_grfconfig_static  = GRFLoadConfig(ini, "newgrf-static", true);
-	ini_free(ini);
-}
-
-/** Save the values to the configuration file */
-void SaveToConfig(void)
-{
-	IniFile *ini = ini_load(_config_file);
-	HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
-	GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
-	GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
-	ini_save(_config_file, ini);
-	ini_free(ini);
-}
-
-static const SettingDesc *GetSettingDescription(uint index)
-{
-	if (index >= lengthof(_patch_settings)) return NULL;
-	return &_patch_settings[index];
-}
-
-/** Network-safe changing of patch-settings (server-only).
- * @param p1 the index of the patch in the SettingDesc array which identifies it
- * @param p2 the new value for the patch
- * The new value is properly clamped to its minimum/maximum when setting
- * @see _patch_settings
- */
-int32 CmdChangePatchSetting(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	const SettingDesc *sd = GetSettingDescription(p1);
-
-	if (sd == NULL) return CMD_ERROR;
-	if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		Patches *patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-		void *var = GetVariableAddress(patches_ptr, &sd->save);
-		Write_ValidateSetting(var, sd, (int32)p2);
-		if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
-
-		InvalidateWindow(WC_GAME_OPTIONS, 0);
-	}
-
-	return 0;
-}
-
-/** Top function to save the new value of an element of the Patches struct
- * @param index offset in the SettingDesc array of the Patches struct which
- * identifies the patch member we want to change
- * @param object pointer to a valid patches struct that has its settings change.
- * This only affects patch-members that are not needed to be the same on all
- * clients in a network game.
- * @param value new value of the patch */
-bool SetPatchValue(uint index, const Patches *object, int32 value)
-{
-	const SettingDesc *sd = &_patch_settings[index];
-	/* If an item is player-based, we do not send it over the network
-	 * (if any) to change. Also *hack*hack* we update the _newgame version
-	 * of patches because changing a player-based setting in a game also
-	 * changes its defaults. At least that is the convention we have chosen */
-	if (sd->save.conv & SLF_NETWORK_NO) {
-		void *var = GetVariableAddress(object, &sd->save);
-		Write_ValidateSetting(var, sd, value);
-
-		if (_game_mode != GM_MENU) {
-			void *var2 = GetVariableAddress(&_patches_newgame, &sd->save);
-			Write_ValidateSetting(var2, sd, value);
-		}
-		if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
-		InvalidateWindow(WC_GAME_OPTIONS, 0);
-		return true;
-	}
-
-	/* send non-player-based settings over the network */
-	if (!_networking || (_networking && _network_server)) {
-		return DoCommandP(0, index, value, NULL, CMD_CHANGE_PATCH_SETTING);
-	}
-	return false;
-}
-
-const SettingDesc *GetPatchFromName(const char *name, uint *i)
-{
-	const SettingDesc *sd;
-
-	for (*i = 0, sd = _patch_settings; sd->save.cmd != SL_END; sd++, (*i)++) {
-		if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
-		if (strcmp(sd->desc.name, name) == 0) return sd;
-	}
-
-	return NULL;
-}
-
-/* Those 2 functions need to be here, else we have to make some stuff non-static
- * and besides, it is also better to keep stuff like this at the same place */
-bool IConsoleSetPatchSetting(const char *name, int32 value)
-{
-	bool success;
-	uint index;
-	const SettingDesc *sd = GetPatchFromName(name, &index);
-	const Patches *patches_ptr;
-	void *ptr;
-
-	if (sd == NULL) {
-		IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
-		return true;
-	}
-
-	patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-	ptr = GetVariableAddress(patches_ptr, &sd->save);
-
-	success = SetPatchValue(index, patches_ptr, value);
-	return success;
-}
-
-void IConsoleGetPatchSetting(const char *name)
-{
-	char value[20];
-	uint index;
-	const SettingDesc *sd = GetPatchFromName(name, &index);
-	const void *ptr;
-
-	if (sd == NULL) {
-		IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
-		return;
-	}
-
-	ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_patches_newgame : &_patches, &sd->save);
-
-	if (sd->desc.cmd == SDT_BOOLX) {
-		snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
-	} else {
-		snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
-	}
-
-	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
-		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
-}
-
-/** Save and load handler for patches/settings
- * @param osd SettingDesc struct containing all information
- * @param object can be either NULL in which case we load global variables or
- * a pointer to a struct which is getting saved */
-static void LoadSettings(const SettingDesc *osd, void *object)
-{
-	for (; osd->save.cmd != SL_END; osd++) {
-		const SaveLoad *sld = &osd->save;
-		void *ptr = GetVariableAddress(object, sld);
-
-		if (!SlObjectMember(ptr, sld)) continue;
-	}
-}
-
-/** Loadhandler for a list of global variables
- * @note this is actually a stub for LoadSettings with the
- * object pointer set to NULL */
-static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
-{
-	LoadSettings((const SettingDesc*)sdg, NULL);
-}
-
-/** Save and load handler for patches/settings
- * @param osd SettingDesc struct containing all information
- * @param object can be either NULL in which case we load global variables or
- * a pointer to a struct which is getting saved */
-static void SaveSettings(const SettingDesc *sd, void *object)
-{
-	/* We need to write the CH_RIFF header, but unfortunately can't call
-	 * SlCalcLength() because we have a different format. So do this manually */
-	const SettingDesc *i;
-	size_t length = 0;
-	for (i = sd; i->save.cmd != SL_END; i++) {
-		const void *ptr = GetVariableAddress(object, &i->save);
-		length += SlCalcObjMemberLength(ptr, &i->save);
-	}
-	SlSetLength(length);
-
-	for (i = sd; i->save.cmd != SL_END; i++) {
-		void *ptr = GetVariableAddress(object, &i->save);
-		SlObjectMember(ptr, &i->save);
-	}
-}
-
-/** Savehandler for a list of global variables
- * @note this is actually a stub for SaveSettings with the
- * object pointer set to NULL */
-static inline void SaveSettingsGlobList(const SettingDescGlobVarList *sdg)
-{
-	SaveSettings((const SettingDesc*)sdg, NULL);
-}
-
-static void Load_OPTS(void)
-{
-	/* Copy over default setting since some might not get loaded in
-	 * a networking environment. This ensures for example that the local
-	 * autosave-frequency stays when joining a network-server */
-	_opt = _opt_newgame;
-	LoadSettings(_gameopt_settings, &_opt);
-}
-
-static void Save_OPTS(void)
-{
-	SaveSettings(_gameopt_settings, &_opt);
-}
-
-static void Load_PATS(void)
-{
-	/* Copy over default setting since some might not get loaded in
-	 * a networking environment. This ensures for example that the local
-	 * signal_side stays when joining a network-server */
-	_patches = _patches_newgame;
-	LoadSettings(_patch_settings, &_patches);
-}
-
-static void Save_PATS(void)
-{
-	SaveSettings(_patch_settings, &_patches);
-}
-
-void CheckConfig(void)
-{
-	// fix up news_display_opt from old to new
-	int i;
-	uint32 tmp;
-	for (i = 0, tmp = _news_display_opt; i != 10; i++, tmp >>= 2) {
-		if ((tmp & 0x3) == 0x3) { // old settings
-			_news_display_opt = 0xAAAAAAAA; // set all news-messages to full 1010101010...
-			break;
-		}
-	}
-
-	// Increase old default values for pf_maxdepth and pf_maxlength
-	// to support big networks.
-	if (_patches_newgame.pf_maxdepth == 16 && _patches_newgame.pf_maxlength == 512) {
-		_patches_newgame.pf_maxdepth = 48;
-		_patches_newgame.pf_maxlength = 4096;
-	}
-}
-
-void UpdatePatches(void)
-{
-	/* Since old(er) savegames don't have any patches saved, we initialise
-	 * them with the default values just as it was in the old days.
-	 * Also new games need this copying-over */
-	_patches = _patches_newgame; /* backwards compatibility */
-}
-
-const ChunkHandler _setting_chunk_handlers[] = {
-	{ 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF},
-	{ 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST},
-};
-
-static bool IsSignedVarMemType(VarType vt)
-{
-	switch (GetVarMemType(vt)) {
-		case SLE_VAR_I8:
-		case SLE_VAR_I16:
-		case SLE_VAR_I32:
-		case SLE_VAR_I64:
-			return true;
-	}
-	return false;
-}
new file mode 100644
--- /dev/null
+++ b/src/settings.cpp
@@ -0,0 +1,1861 @@
+/* $Id$ */
+
+/** @file
+ * All actions handling saving and loading of the settings/configuration goes on in this file.
+ * The file consists of four parts:
+ * <ol>
+ * <li>Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which
+ *     handle various types, such as normal 'key = value' pairs, lists and value combinations of
+ *     lists, strings, integers, 'bit'-masks and element selections.
+ * <li>Defining the data structures that go into the configuration. These include for example
+ *     the _patches struct, but also network-settings, banlists, newgrf, etc. There are a lot
+ *     of helper macros available for the various types, and also saving/loading of these settings
+ *     in a savegame is handled inside these structures.
+ * <li>Handle reading and writing to the setting-structures from inside the game either from
+ *     the console for example or through the gui with CMD_ functions.
+ * <li>Handle saving/loading of the PATS chunk inside the savegame.
+ * </ol>
+ * @see SettingDesc
+ * @see SaveLoad
+ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "functions.h"
+#include "macros.h"
+#include "screenshot.h"
+#include "sound.h"
+#include "string.h"
+#include "variables.h"
+#include "network/network.h"
+#include "settings.h"
+#include "command.h"
+#include "console.h"
+#include "saveload.h"
+#include "npf.h"
+#include "yapf/yapf.h"
+#include "newgrf.h"
+#include "newgrf_config.h"
+#include "genworld.h"
+#include "date.h"
+#include "rail.h"
+#ifdef WITH_FREETYPE
+#include "gfx.h"
+#include "fontcache.h"
+#endif
+
+/** The patch values that are used for new games and/or modified in config file */
+Patches _patches_newgame;
+
+typedef struct IniFile IniFile;
+typedef struct IniItem IniItem;
+typedef struct IniGroup IniGroup;
+typedef struct SettingsMemoryPool SettingsMemoryPool;
+
+typedef const char *SettingListCallbackProc(const IniItem *item, uint index);
+typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object);
+typedef void SettingDescProcList(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc);
+
+static void pool_init(SettingsMemoryPool **pool);
+static void *pool_alloc(SettingsMemoryPool **pool, uint size);
+static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size);
+static void pool_free(SettingsMemoryPool **pool);
+static bool IsSignedVarMemType(VarType vt);
+
+struct SettingsMemoryPool {
+	uint pos,size;
+	SettingsMemoryPool *next;
+	byte mem[1];
+};
+
+static SettingsMemoryPool *pool_new(uint minsize)
+{
+	SettingsMemoryPool *p;
+	if (minsize < 4096 - 12) minsize = 4096 - 12;
+
+	p = malloc(sizeof(SettingsMemoryPool) - 1 + minsize);
+	p->pos = 0;
+	p->size = minsize;
+	p->next = NULL;
+	return p;
+}
+
+static void pool_init(SettingsMemoryPool **pool)
+{
+	*pool = pool_new(0);
+}
+
+static void *pool_alloc(SettingsMemoryPool **pool, uint size)
+{
+	uint pos;
+	SettingsMemoryPool *p = *pool;
+
+	size = ALIGN(size, sizeof(void*));
+
+	// first check if there's memory in the next pool
+	if (p->next && p->next->pos + size <= p->next->size) {
+		p = p->next;
+	// then check if there's not memory in the cur pool
+	} else if (p->pos + size > p->size) {
+		SettingsMemoryPool *n = pool_new(size);
+		*pool = n;
+		n->next = p;
+		p = n;
+	}
+
+	pos = p->pos;
+	p->pos += size;
+	return p->mem + pos;
+}
+
+static void *pool_strdup(SettingsMemoryPool **pool, const char *mem, uint size)
+{
+	byte *p = pool_alloc(pool, size + 1);
+	p[size] = 0;
+	memcpy(p, mem, size);
+	return p;
+}
+
+static void pool_free(SettingsMemoryPool **pool)
+{
+	SettingsMemoryPool *p = *pool, *n;
+	*pool = NULL;
+	while (p) {
+		n = p->next;
+		free(p);
+		p = n;
+	}
+}
+
+// structs describing the ini format.
+struct IniItem {
+	char *name;
+	char *value;
+	char *comment;
+	IniItem *next;
+};
+
+struct IniGroup {
+	char *name; // name of group
+	char *comment; //comment for group
+	IniItem *item, **last_item;
+	IniGroup *next;
+	IniFile *ini;
+	IniGroupType type; // type of group
+};
+
+struct IniFile {
+	SettingsMemoryPool *pool;
+	IniGroup *group, **last_group;
+	char *comment; // last comment in file
+};
+
+// allocate an inifile object
+static IniFile *ini_alloc(void)
+{
+	IniFile *ini;
+	SettingsMemoryPool *pool;
+	pool_init(&pool);
+	ini = (IniFile*)pool_alloc(&pool, sizeof(IniFile));
+	ini->pool = pool;
+	ini->group = NULL;
+	ini->last_group = &ini->group;
+	ini->comment = NULL;
+	return ini;
+}
+
+// allocate an ini group object
+static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
+{
+	IniGroup *grp = pool_alloc(&ini->pool, sizeof(IniGroup));
+	grp->ini = ini;
+	grp->name = pool_strdup(&ini->pool, grpt, len);
+	if (!strcmp(grp->name, "newgrf") || !strcmp(grp->name, "servers") || !strcmp(grp->name, "bans")) {
+		grp->type = IGT_LIST;
+	} else {
+		grp->type = IGT_VARIABLES;
+	}
+	grp->next = NULL;
+	grp->item = NULL;
+	grp->comment = NULL;
+	grp->last_item = &grp->item;
+	*ini->last_group = grp;
+	ini->last_group = &grp->next;
+	return grp;
+}
+
+static IniItem *ini_item_alloc(IniGroup *group, const char *name, int len)
+{
+	IniItem *item = pool_alloc(&group->ini->pool, sizeof(IniItem));
+	item->name = pool_strdup(&group->ini->pool, name, len);
+	item->next = NULL;
+	item->comment = NULL;
+	item->value = NULL;
+	*group->last_item = item;
+	group->last_item = &item->next;
+	return item;
+}
+
+// load an ini file into the "abstract" format
+static IniFile *ini_load(const char *filename)
+{
+	char buffer[1024], c, *s, *t, *e;
+	FILE *in;
+	IniFile *ini;
+	IniGroup *group = NULL;
+	IniItem *item;
+
+	char *comment = NULL;
+	uint comment_size = 0;
+	uint comment_alloc = 0;
+
+	ini = ini_alloc();
+
+	in = fopen(filename, "r");
+	if (in == NULL) return ini;
+
+	// for each line in the file
+	while (fgets(buffer, sizeof(buffer), in)) {
+
+		// trim whitespace from the left side
+		for (s = buffer; *s == ' ' || *s == '\t'; s++);
+
+		// trim whitespace from right side.
+		e = s + strlen(s);
+		while (e > s && ((c=e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
+		*e = '\0';
+
+		// skip comments and empty lines
+		if (*s == '#' || *s == ';' || *s == '\0') {
+			uint ns = comment_size + (e - s + 1);
+			uint a = comment_alloc;
+			uint pos;
+			// add to comment
+			if (ns > a) {
+				a = max(a, 128);
+				do a*=2; while (a < ns);
+				comment = realloc(comment, comment_alloc = a);
+			}
+			pos = comment_size;
+			comment_size += (e - s + 1);
+			comment[pos + e - s] = '\n'; // comment newline
+			memcpy(comment + pos, s, e - s); // copy comment contents
+			continue;
+		}
+
+		// it's a group?
+		if (s[0] == '[') {
+			if (e[-1] != ']') {
+				ShowInfoF("ini: invalid group name '%s'", buffer);
+			} else {
+				e--;
+			}
+			s++; // skip [
+			group = ini_group_alloc(ini, s, e - s);
+			if (comment_size) {
+				group->comment = pool_strdup(&ini->pool, comment, comment_size);
+				comment_size = 0;
+			}
+		} else if (group) {
+			// find end of keyname
+			for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
+
+			// it's an item in an existing group
+			item = ini_item_alloc(group, s, t-s);
+			if (comment_size) {
+				item->comment = pool_strdup(&ini->pool, comment, comment_size);
+				comment_size = 0;
+			}
+
+			// find start of parameter
+			while (*t == '=' || *t == ' ' || *t == '\t') t++;
+
+
+			// remove starting quotation marks
+			if (*t == '\"') t++;
+			// remove ending quotation marks
+			e = t + strlen(t);
+			if (e > t && e[-1] == '\"') e--;
+			*e = '\0';
+
+			item->value = pool_strdup(&ini->pool, t, e - t);
+		} else {
+			// it's an orphan item
+			ShowInfoF("ini: '%s' outside of group", buffer);
+		}
+	}
+
+	if (comment_size > 0) {
+		ini->comment = pool_strdup(&ini->pool, comment, comment_size);
+		comment_size = 0;
+	}
+
+	free(comment);
+	fclose(in);
+
+	return ini;
+}
+
+// lookup a group or make a new one
+static IniGroup *ini_getgroup(IniFile *ini, const char *name, int len)
+{
+	IniGroup *group;
+
+	if (len == -1) len = strlen(name);
+
+	// does it exist already?
+	for (group = ini->group; group; group = group->next)
+		if (!memcmp(group->name, name, len) && group->name[len] == 0)
+			return group;
+
+	// otherwise make a new one
+	group = ini_group_alloc(ini, name, len);
+	group->comment = pool_strdup(&ini->pool, "\n", 1);
+	return group;
+}
+
+// lookup an item or make a new one
+static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
+{
+	IniItem *item;
+	uint len = strlen(name);
+
+	for (item = group->item; item; item = item->next)
+		if (strcmp(item->name, name) == 0) return item;
+
+	if (!create) return NULL;
+
+	// otherwise make a new one
+	return ini_item_alloc(group, name, len);
+}
+
+// save ini file from the "abstract" format.
+static bool ini_save(const char *filename, IniFile *ini)
+{
+	FILE *f;
+	IniGroup *group;
+	IniItem *item;
+
+	f = fopen(filename, "w");
+	if (f == NULL) return false;
+
+	for (group = ini->group; group != NULL; group = group->next) {
+		if (group->comment) fputs(group->comment, f);
+		fprintf(f, "[%s]\n", group->name);
+		for (item = group->item; item != NULL; item = item->next) {
+			assert(item->value != NULL);
+			if (item->comment != NULL) fputs(item->comment, f);
+
+			/* Don't give an equal sign to list items that don't have a parameter */
+			if (group->type == IGT_LIST && *item->value == '\0') {
+				fprintf(f, "%s\n", item->name);
+			} else {
+				fprintf(f, "%s = %s\n", item->name, item->value);
+			}
+		}
+	}
+	if (ini->comment) fputs(ini->comment, f);
+
+	fclose(f);
+	return true;
+}
+
+static void ini_free(IniFile *ini)
+{
+	pool_free(&ini->pool);
+}
+
+/** Find the index value of a ONEofMANY type in a string seperated by |
+ * @param many full domain of values the ONEofMANY setting can have
+ * @param one the current value of the setting for which a value needs found
+ * @param onelen force calculation of the *one parameter
+ * @return the integer index of the full-list, or -1 if not found */
+static int lookup_oneofmany(const char *many, const char *one, int onelen)
+{
+	const char *s;
+	int idx;
+
+	if (onelen == -1) onelen = strlen(one);
+
+	// check if it's an integer
+	if (*one >= '0' && *one <= '9')
+		return strtoul(one, NULL, 0);
+
+	idx = 0;
+	for (;;) {
+		// find end of item
+		s = many;
+		while (*s != '|' && *s != 0) s++;
+		if (s - many == onelen && !memcmp(one, many, onelen)) return idx;
+		if (*s == 0) return -1;
+		many = s + 1;
+		idx++;
+	}
+}
+
+/** Find the set-integer value MANYofMANY type in a string
+ * @param many full domain of values the MANYofMANY setting can have
+ * @param str the current string value of the setting, each individual
+ * of seperated by a whitespace\tab or | character
+ * @return the 'fully' set integer, or -1 if a set is not found */
+static uint32 lookup_manyofmany(const char *many, const char *str)
+{
+	const char *s;
+	int r;
+	uint32 res = 0;
+
+	for (;;) {
+		// skip "whitespace"
+		while (*str == ' ' || *str == '\t' || *str == '|') str++;
+		if (*str == 0) break;
+
+		s = str;
+		while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
+
+		r = lookup_oneofmany(many, str, s - str);
+		if (r == -1) return (uint32)-1;
+
+		SETBIT(res, r); // value found, set it
+		if (*s == 0) break;
+		str = s + 1;
+	}
+	return res;
+}
+
+/** Parse an integerlist string and set each found value
+ * @param p the string to be parsed. Each element in the list is seperated by a
+ * comma or a space character
+ * @param items pointer to the integerlist-array that will be filled with values
+ * @param maxitems the maximum number of elements the integerlist-array has
+ * @return returns the number of items found, or -1 on an error */
+static int parse_intlist(const char *p, int *items, int maxitems)
+{
+	int n = 0, v;
+	char *end;
+
+	for (;;) {
+		v = strtol(p, &end, 0);
+		if (p == end || n == maxitems) return -1;
+		p = end;
+		items[n++] = v;
+		if (*p == '\0') break;
+		if (*p != ',' && *p != ' ') return -1;
+		p++;
+	}
+
+	return n;
+}
+
+/** Load parsed string-values into an integer-array (intlist)
+ * @param str the string that contains the values (and will be parsed)
+ * @param array pointer to the integer-arrays that will be filled
+ * @param nelems the number of elements the array holds. Maximum is 64 elements
+ * @param type the type of elements the array holds (eg INT8, UINT16, etc.)
+ * @return return true on success and false on error */
+static bool load_intlist(const char *str, void *array, int nelems, VarType type)
+{
+	int items[64];
+	int i, nitems;
+
+	if (str == NULL) {
+		memset(items, 0, sizeof(items));
+		nitems = nelems;
+	} else {
+		nitems = parse_intlist(str, items, lengthof(items));
+		if (nitems != nelems) return false;
+	}
+
+	switch (type) {
+	case SLE_VAR_BL:
+	case SLE_VAR_I8:
+	case SLE_VAR_U8:
+		for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i];
+		break;
+	case SLE_VAR_I16:
+	case SLE_VAR_U16:
+		for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i];
+		break;
+	case SLE_VAR_I32:
+	case SLE_VAR_U32:
+		for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i];
+		break;
+	default: NOT_REACHED();
+	}
+
+	return true;
+}
+
+/** Convert an integer-array (intlist) to a string representation. Each value
+ * is seperated by a comma or a space character
+ * @param buf output buffer where the string-representation will be stored
+ * @param array pointer to the integer-arrays that is read from
+ * @param nelems the number of elements the array holds.
+ * @param type the type of elements the array holds (eg INT8, UINT16, etc.) */
+static void make_intlist(char *buf, const void *array, int nelems, VarType type)
+{
+	int i, v = 0;
+	const byte *p = (const byte*)array;
+
+	for (i = 0; i != nelems; i++) {
+		switch (type) {
+		case SLE_VAR_BL:
+		case SLE_VAR_I8:  v = *(int8*)p;   p += 1; break;
+		case SLE_VAR_U8:  v = *(byte*)p;   p += 1; break;
+		case SLE_VAR_I16: v = *(int16*)p;  p += 2; break;
+		case SLE_VAR_U16: v = *(uint16*)p; p += 2; break;
+		case SLE_VAR_I32: v = *(int32*)p;  p += 4; break;
+		case SLE_VAR_U32: v = *(uint32*)p; p += 4; break;
+		default: NOT_REACHED();
+		}
+		buf += sprintf(buf, (i == 0) ? "%d" : ",%d", v);
+	}
+}
+
+/** Convert a ONEofMANY structure to a string representation.
+ * @param buf output buffer where the string-representation will be stored
+ * @param many the full-domain string of possible values
+ * @param id the value of the variable and whose string-representation must be found */
+static void make_oneofmany(char *buf, const char *many, int id)
+{
+	int orig_id = id;
+
+	// Look for the id'th element
+	while (--id >= 0) {
+		for (; *many != '|'; many++) {
+			if (*many == '\0') { // not found
+				sprintf(buf, "%d", orig_id);
+				return;
+			}
+		}
+		many++; // pass the |-character
+	}
+
+	// copy string until next item (|) or the end of the list if this is the last one
+	while (*many != '\0' && *many != '|') *buf++ = *many++;
+	*buf = '\0';
+}
+
+/** Convert a MANYofMANY structure to a string representation.
+ * @param buf output buffer where the string-representation will be stored
+ * @param many the full-domain string of possible values
+ * @param x the value of the variable and whose string-representation must
+ *        be found in the bitmasked many string */
+static void make_manyofmany(char *buf, const char *many, uint32 x)
+{
+	const char *start;
+	int i = 0;
+	bool init = true;
+
+	for (; x != 0; x >>= 1, i++) {
+		start = many;
+		while (*many != 0 && *many != '|') many++; // advance to the next element
+
+		if (HASBIT(x, 0)) { // item found, copy it
+			if (!init) *buf++ = '|';
+			init = false;
+			if (start == many) {
+				buf += sprintf(buf, "%d", i);
+			} else {
+				memcpy(buf, start, many - start);
+				buf += many - start;
+			}
+		}
+
+		if (*many == '|') many++;
+	}
+
+	*buf = '\0';
+}
+
+/** Convert a string representation (external) of a setting to the internal rep.
+ * @param desc SettingDesc struct that holds all information about the variable
+ * @param str input string that will be parsed based on the type of desc
+ * @return return the parsed value of the setting */
+static const void *string_to_val(const SettingDescBase *desc, const char *str)
+{
+	switch (desc->cmd) {
+	case SDT_NUMX: {
+		char *end;
+		unsigned long val = strtoul(str, &end, 0);
+		if (*end != '\0') ShowInfoF("ini: trailing characters at end of setting '%s'", desc->name);
+		return (void*)val;
+	}
+	case SDT_ONEOFMANY: {
+		long r = lookup_oneofmany(desc->many, str, -1);
+		if (r != -1) return (void*)r;
+		ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
+		return 0;
+	}
+	case SDT_MANYOFMANY: {
+		unsigned long r = lookup_manyofmany(desc->many, str);
+		if (r != (unsigned long)-1) return (void*)r;
+		ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
+		return 0;
+	}
+	case SDT_BOOLX:
+		if (strcmp(str, "true")  == 0 || strcmp(str, "on")  == 0 || strcmp(str, "1") == 0)
+			return (void*)true;
+		if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0)
+			return (void*)false;
+		ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
+		break;
+
+	case SDT_STRING:
+	case SDT_INTLIST: return str;
+	}
+
+	return NULL;
+}
+
+/** Set the value of a setting and if needed clamp the value to
+ * the preset minimum and maximum.
+ * @param ptr the variable itself
+ * @param sd pointer to the 'information'-database of the variable
+ * @param val signed long version of the new value
+ * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX,
+ * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now */
+static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val)
+{
+	const SettingDescBase *sdb = &sd->desc;
+
+	if (sdb->cmd != SDT_BOOLX &&
+			sdb->cmd != SDT_NUMX &&
+			sdb->cmd != SDT_ONEOFMANY &&
+			sdb->cmd != SDT_MANYOFMANY) {
+		return;
+	}
+
+	/* We cannot know the maximum value of a bitset variable, so just have faith */
+	if (sdb->cmd != SDT_MANYOFMANY) {
+		/* We need to take special care of the uint32 type as we receive from the function
+		 * a signed integer. While here also bail out on 64-bit settings as those are not
+		 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
+		 * 32-bit variable
+		 * TODO: Support 64-bit settings/variables */
+		switch (GetVarMemType(sd->save.conv)) {
+			case SLE_VAR_BL:
+			case SLE_VAR_I8:
+			case SLE_VAR_U8:
+			case SLE_VAR_I16:
+			case SLE_VAR_U16:
+			case SLE_VAR_I32: {
+				/* Override the minimum value. No value below sdb->min, except special value 0 */
+				int32 min = ((sdb->flags & SGF_0ISDISABLED) && val <= sdb->min) ? 0 : sdb->min;
+				val = clamp(val, min, sdb->max);
+			} break;
+			case SLE_VAR_U32: {
+				/* Override the minimum value. No value below sdb->min, except special value 0 */
+				uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min;
+				WriteValue(ptr, SLE_VAR_U32, (int64)clampu(val, min, sdb->max));
+				return;
+			}
+			case SLE_VAR_I64:
+			case SLE_VAR_U64:
+			default: NOT_REACHED(); break;
+		}
+	}
+
+	WriteValue(ptr, sd->save.conv, (int64)val);
+}
+
+/** Load values from a group of an IniFile structure into the internal representation
+ * @param ini pointer to IniFile structure that holds administrative information
+ * @param sd pointer to SettingDesc structure whose internally pointed variables will
+ *        be given values
+ * @param grpname the group of the IniFile to search in for the new values */
+static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
+{
+	IniGroup *group;
+	IniGroup *group_def = ini_getgroup(ini, grpname, -1);
+	IniItem *item;
+	const void *p;
+	void *ptr;
+	const char *s;
+
+	for (; sd->save.cmd != SL_END; sd++) {
+		const SettingDescBase *sdb = &sd->desc;
+		const SaveLoad        *sld = &sd->save;
+
+		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
+
+		// XXX - wtf is this?? (group override?)
+		s = strchr(sdb->name, '.');
+		if (s != NULL) {
+			group = ini_getgroup(ini, sdb->name, s - sdb->name);
+			s++;
+		} else {
+			s = sdb->name;
+			group = group_def;
+		}
+
+		item = ini_getitem(group, s, false);
+		p = (item == NULL) ? sdb->def : string_to_val(sdb, item->value);
+		ptr = GetVariableAddress(object, sld);
+
+		switch (sdb->cmd) {
+		case SDT_BOOLX: /* All four are various types of (integer) numbers */
+		case SDT_NUMX:
+		case SDT_ONEOFMANY:
+		case SDT_MANYOFMANY:
+			Write_ValidateSetting(ptr, sd, (unsigned long)p); break;
+
+		case SDT_STRING:
+			switch (GetVarMemType(sld->conv)) {
+				case SLE_VAR_STRB:
+				case SLE_VAR_STRBQ:
+					if (p != NULL) ttd_strlcpy((char*)ptr, p, sld->length);
+					break;
+				case SLE_VAR_STR:
+				case SLE_VAR_STRQ:
+					if (p != NULL) {
+						free(*(char**)ptr);
+						*(char**)ptr = strdup((const char*)p);
+					}
+					break;
+				case SLE_VAR_CHAR: *(char*)ptr = *(char*)p; break;
+				default: NOT_REACHED(); break;
+			}
+			break;
+
+		case SDT_INTLIST: {
+			if (!load_intlist(p, ptr, sld->length, GetVarMemType(sld->conv)))
+				ShowInfoF("ini: error in array '%s'", sdb->name);
+			break;
+		}
+		default: NOT_REACHED(); break;
+		}
+	}
+}
+
+/** Save the values of settings to the inifile.
+ * @param ini pointer to IniFile structure
+ * @param sd read-only SettingDesc structure which contains the unmodified,
+ *        loaded values of the configuration file and various information about it
+ * @param grpname holds the name of the group (eg. [network]) where these will be saved
+ * The function works as follows: for each item in the SettingDesc structure we
+ * have a look if the value has changed since we started the game (the original
+ * values are reloaded when saving). If settings indeed have changed, we get
+ * these and save them.
+ */
+static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
+{
+	IniGroup *group_def = NULL, *group;
+	IniItem *item;
+	char buf[512];
+	const char *s;
+	void *ptr;
+
+	for (; sd->save.cmd != SL_END; sd++) {
+		const SettingDescBase *sdb = &sd->desc;
+		const SaveLoad        *sld = &sd->save;
+
+		/* If the setting is not saved to the configuration
+		 * file, just continue with the next setting */
+		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
+		if (sld->conv & SLF_CONFIG_NO) continue;
+
+		// XXX - wtf is this?? (group override?)
+		s = strchr(sdb->name, '.');
+		if (s != NULL) {
+			group = ini_getgroup(ini, sdb->name, s - sdb->name);
+			s++;
+		} else {
+			if (group_def == NULL) group_def = ini_getgroup(ini, grpname, -1);
+			s = sdb->name;
+			group = group_def;
+		}
+
+		item = ini_getitem(group, s, true);
+		ptr = GetVariableAddress(object, sld);
+
+		if (item->value != NULL) {
+			// check if the value is the same as the old value
+			const void *p = string_to_val(sdb, item->value);
+
+			/* The main type of a variable/setting is in bytes 8-15
+			 * The subtype (what kind of numbers do we have there) is in 0-7 */
+			switch (sdb->cmd) {
+			case SDT_BOOLX:
+			case SDT_NUMX:
+			case SDT_ONEOFMANY:
+			case SDT_MANYOFMANY:
+				switch (GetVarMemType(sld->conv)) {
+				case SLE_VAR_BL:
+					if (*(bool*)ptr == (bool)(unsigned long)p) continue;
+					break;
+				case SLE_VAR_I8:
+				case SLE_VAR_U8:
+					if (*(byte*)ptr == (byte)(unsigned long)p) continue;
+					break;
+				case SLE_VAR_I16:
+				case SLE_VAR_U16:
+					if (*(uint16*)ptr == (uint16)(unsigned long)p) continue;
+					break;
+				case SLE_VAR_I32:
+				case SLE_VAR_U32:
+					if (*(uint32*)ptr == (uint32)(unsigned long)p) continue;
+					break;
+				default: NOT_REACHED();
+				}
+				break;
+			default: break; /* Assume the other types are always changed */
+			}
+		}
+
+		/* Value has changed, get the new value and put it into a buffer */
+		switch (sdb->cmd) {
+		case SDT_BOOLX:
+		case SDT_NUMX:
+		case SDT_ONEOFMANY:
+		case SDT_MANYOFMANY: {
+			uint32 i = (uint32)ReadValue(ptr, sld->conv);
+
+			switch (sdb->cmd) {
+			case SDT_BOOLX:      strcpy(buf, (i != 0) ? "true" : "false"); break;
+			case SDT_NUMX:       sprintf(buf, IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break;
+			case SDT_ONEOFMANY:  make_oneofmany(buf, sdb->many, i); break;
+			case SDT_MANYOFMANY: make_manyofmany(buf, sdb->many, i); break;
+			default: NOT_REACHED();
+			}
+		} break;
+
+		case SDT_STRING:
+			switch (GetVarMemType(sld->conv)) {
+			case SLE_VAR_STRB: strcpy(buf, (char*)ptr); break;
+			case SLE_VAR_STRBQ:sprintf(buf, "\"%s\"", (char*)ptr); break;
+			case SLE_VAR_STR:  strcpy(buf, *(char**)ptr); break;
+			case SLE_VAR_STRQ: sprintf(buf, "\"%s\"", *(char**)ptr); break;
+			case SLE_VAR_CHAR: sprintf(buf, "\"%c\"", *(char*)ptr); break;
+			default: NOT_REACHED();
+			}
+			break;
+
+		case SDT_INTLIST:
+			make_intlist(buf, ptr, sld->length, GetVarMemType(sld->conv));
+			break;
+		default: NOT_REACHED();
+		}
+
+		/* The value is different, that means we have to write it to the ini */
+		item->value = pool_strdup(&ini->pool, buf, strlen(buf));
+	}
+}
+
+/** Loads all items from a 'grpname' section into a list
+ * The list parameter can be a NULL pointer, in this case nothing will be
+ * saved and a callback function should be defined that will take over the
+ * list-handling and store the data itself somewhere.
+ * @param IniFile handle to the ini file with the source data
+ * @param grpname character string identifying the section-header of the ini
+ * file that will be parsed
+ * @param list pointer to an string(pointer) array that will store the parsed
+ * entries of the given section
+ * @param len the maximum number of items available for the above list
+ * @param proc callback function that can override how the values are stored
+ * inside the list */
+static void ini_load_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
+{
+	IniGroup *group = ini_getgroup(ini, grpname, -1);
+	IniItem *item;
+	const char *entry;
+	uint i, j;
+
+	if (group == NULL) return;
+
+	for (i = j = 0, item = group->item; item != NULL; item = item->next) {
+		entry = (proc != NULL) ? proc(item, i++) : item->name;
+
+		if (entry == NULL || list == NULL) continue;
+
+		if (j == len) break;
+		list[j++] = strdup(entry);
+	}
+}
+
+/** Saves all items from a list into the 'grpname' section
+ * The list parameter can be a NULL pointer, in this case a callback function
+ * should be defined that will provide the source data to be saved.
+ * @param IniFile handle to the ini file where the destination data is saved
+ * @param grpname character string identifying the section-header of the ini file
+ * @param list pointer to an string(pointer) array that will be used as the
+ * source to be saved into the relevant ini section
+ * @param len the maximum number of items available for the above list
+ * @param proc callback function that can will provide the source data if defined */
+static void ini_save_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
+{
+	IniGroup *group = ini_getgroup(ini, grpname, -1);
+	IniItem *item = NULL;
+	const char *entry;
+	uint i;
+	bool first = true;
+
+	if (proc == NULL && list == NULL) return;
+	if (group == NULL) return;
+	group->item = NULL;
+
+	for (i = 0; i != len; i++) {
+		entry = (proc != NULL) ? proc(NULL, i) : list[i];
+
+		if (entry == NULL || *entry == '\0') continue;
+
+		if (first) { // add first item to the head of the group
+			item = ini_item_alloc(group, entry, strlen(entry));
+			item->value = item->name;
+			group->item = item;
+			first = false;
+		} else { // all other items are attached to the previous one
+			item->next = ini_item_alloc(group, entry, strlen(entry));
+			item = item->next;
+			item->value = item->name;
+		}
+	}
+}
+
+//***************************
+// OTTD specific INI stuff
+//***************************
+
+/** Settings-macro usage:
+ * The list might look daunting at first, but is in general easy to understand.
+ * We have two types of list:
+ * 1. SDTG_something
+ * 2. SDT_something
+ * The 'G' stands for global, so this is the one you will use for a
+ * SettingDescGlobVarList section meaning global variables. The other uses a
+ * Base/Offset and runtime variable selection mechanism, known from the saveload * convention (it also has global so it should not be hard).
+ * Of each type there are again two versions, the normal one and one prefixed
+ * with 'COND'.
+ * COND means that the setting is only valid in certain savegame versions
+ * (since patches are saved to the savegame, this bookkeeping is necessary.
+ * Now there are a lot of types. Easy ones are:
+ * - VAR:  any number type, 'type' field specifies what number. eg int8 or uint32
+ * - BOOL: a boolean number type
+ * - STR:  a string or character. 'type' field specifies what string. Normal, string, or quoted
+ * A bit more difficult to use are MMANY (meaning ManyOfMany) and OMANY (OneOfMany)
+ * These are actually normal numbers, only bitmasked. In MMANY several bits can
+ * be set, in the other only one.
+ * The most complex type is INTLIST. This is basically an array of numbers. If
+ * the intlist is only valid in certain savegame versions because for example
+ * it has grown in size its length cannot be automatically be calculated so
+ * use SDT(G)_CONDLISTO() meaning Old.
+ * If nothing fits you, you can use the GENERAL macros, but it exposes the
+ * internal structure somewhat so it needs a little looking. There are _NULL()
+ * macros as well, these fill up space so you can add more patches there (in
+ * place) and you DON'T have to increase the savegame version. */
+
+#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, proc)\
+	{name, (const void*)(def), cmd, guiflags, min, max, interval, many, str, proc}
+
+/* Macros for various objects to go in the configuration file.
+ * This section is for global variables */
+#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, proc, from, to)\
+{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)}
+
+#define SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, proc, from, to)
+#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc)\
+	SDTG_CONDVAR(name, type, flags, guiflags, var, def, min, max, interval, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_UINT8, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, proc, from, to)
+#define SDTG_BOOL(name, flags, guiflags, var, def, str, proc)\
+	SDTG_CONDBOOL(name, flags, guiflags, var, def, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDLIST(name, type, length, flags, guiflags, var, def, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
+#define SDTG_LIST(name, type, flags, guiflags, var, def, str, proc)\
+	SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDSTR(name, type, length, flags, guiflags, var, def, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
+#define SDTG_STR(name, type, flags, guiflags, var, def, str, proc)\
+	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max, full, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, proc, from, to)
+#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, proc)\
+	SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max full, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, from, to)\
+	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
+#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
+	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
+
+#define SDTG_CONDNULL(length, from, to)\
+	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_CONDNULL(length, from, to)}
+
+#define SDTG_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLEG_END()}
+
+/* Macros for various objects to go in the configuration file.
+ * This section is for structures where their various members are saved */
+#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, proc, from, to)\
+	{NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, proc), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)}
+
+#define SDT_CONDVAR(base, var, type, from, to, flags, guiflags, def, min, max, interval, str, proc)\
+	SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, proc, from, to)
+#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, proc)\
+	SDT_CONDVAR(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, min, max, interval, str, proc)
+
+#define SDT_CONDBOOL(base, var, from, to, flags, guiflags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, proc, from, to)
+#define SDT_BOOL(base, var, flags, guiflags, def, str, proc)\
+	SDT_CONDBOOL(base, var, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
+
+#define SDT_CONDLIST(base, var, type, from, to, flags, guiflags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, proc, from, to)
+#define SDT_LIST(base, var, type, flags, guiflags, def, str, proc)\
+	SDT_CONDLIST(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
+#define SDT_CONDLISTO(base, var, length, type, from, to, flags, guiflags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, length, def, 0, 0, 0, NULL, str, proc, from, to)
+
+#define SDT_CONDSTR(base, var, type, from, to, flags, guiflags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, proc, from, to)
+#define SDT_STR(base, var, type, flags, guiflags, def, str, proc)\
+	SDT_CONDSTR(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
+#define SDT_CONDSTRO(base, var, length, type, from, to, flags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, 0, base, var, length, def, 0, 0, NULL, str, proc, from, to)
+
+#define SDT_CONDCHR(base, var, from, to, flags, guiflags, def, str, proc)\
+	SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, proc, from, to)
+#define SDT_CHR(base, var, flags, guiflags, def, str, proc)\
+	SDT_CONDCHR(base, var, 0, SL_MAX_VERSION, flags, guiflags, def, str, proc)
+
+#define SDT_CONDOMANY(base, var, type, from, to, flags, guiflags, def, max, full, str, proc)\
+	SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, proc, from, to)
+#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, proc)\
+	SDT_CONDOMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, max, full, str, proc)
+
+#define SDT_CONDMMANY(base, var, type, from, to, flags, guiflags, def, full, str, proc)\
+	SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, proc, from, to)
+#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc)\
+	SDT_CONDMMANY(base, var, type, 0, SL_MAX_VERSION, flags, guiflags, def, full, str, proc)
+
+#define SDT_CONDNULL(length, from, to)\
+	{{"", NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_CONDNULL(length, from, to)}
+
+#define SDT_END() {{NULL, NULL, 0, 0, 0, 0, 0, NULL, STR_NULL, NULL}, SLE_END()}
+
+/* Shortcuts for macros below. Logically if we don't save the value
+ * we also don't sync it in a network game */
+#define S SLF_SAVE_NO | SLF_NETWORK_NO
+#define NS SLF_SAVE_NO
+#define C SLF_CONFIG_NO
+#define N SLF_NETWORK_NO
+
+#define D0 SGF_0ISDISABLED
+#define NC SGF_NOCOMMA
+#define MS SGF_MULTISTRING
+#define NO SGF_NETWORK_ONLY
+#define CR SGF_CURRENCY
+
+#include "table/strings.h"
+
+/* Begin - Callback Functions for the various settings */
+#include "window.h"
+#include "gui.h"
+#include "town.h"
+#include "gfx.h"
+// virtual PositionMainToolbar function, calls the right one.
+static int32 v_PositionMainToolbar(int32 p1)
+{
+	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
+	return 0;
+}
+
+static int32 AiNew_PatchActive_Warning(int32 p1)
+{
+	if (p1 == 1) ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_ACTIVATED, 0, 0);
+	return 0;
+}
+
+static int32 Ai_In_Multiplayer_Warning(int32 p1)
+{
+	if (p1 == 1) {
+		ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_MULTIPLAYER, 0, 0);
+		_patches.ainew_active = true;
+	}
+	return 0;
+}
+
+static int32 PopulationInLabelActive(int32 p1)
+{
+	Town* t;
+
+	FOR_ALL_TOWNS(t) UpdateTownVirtCoord(t);
+
+	return 0;
+}
+
+static int32 RedrawScreen(int32 p1)
+{
+	MarkWholeScreenDirty();
+	return 0;
+}
+
+static int32 InValidateDetailsWindow(int32 p1)
+{
+	InvalidateWindowClasses(WC_VEHICLE_DETAILS);
+	return 0;
+}
+
+static int32 InvalidateStationBuildWindow(int32 p1)
+{
+	InvalidateWindow(WC_BUILD_STATION, 0);
+	return 0;
+}
+
+/* Check service intervals of vehicles, p1 is value of % or day based servicing */
+static int32 CheckInterval(int32 p1)
+{
+	bool warning;
+	const Patches *ptc = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
+
+	if (p1) {
+		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   5, 90+1) || ptc->servint_trains   == 0) &&
+								(IS_INT_INSIDE(ptc->servint_roadveh,  5, 90+1) || ptc->servint_roadveh  == 0) &&
+								(IS_INT_INSIDE(ptc->servint_aircraft, 5, 90+1) || ptc->servint_aircraft == 0) &&
+								(IS_INT_INSIDE(ptc->servint_ships,    5, 90+1) || ptc->servint_ships    == 0) );
+	} else {
+		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   30, 800+1) || ptc->servint_trains   == 0) &&
+								(IS_INT_INSIDE(ptc->servint_roadveh,  30, 800+1) || ptc->servint_roadveh  == 0) &&
+								(IS_INT_INSIDE(ptc->servint_aircraft, 30, 800+1) || ptc->servint_aircraft == 0) &&
+								(IS_INT_INSIDE(ptc->servint_ships,    30, 800+1) || ptc->servint_ships    == 0) );
+	}
+
+	if (!warning)
+		ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE, 0, 0);
+
+	return InValidateDetailsWindow(0);
+}
+
+static int32 EngineRenewUpdate(int32 p1)
+{
+	DoCommandP(0, 0, _patches.autorenew, NULL, CMD_SET_AUTOREPLACE);
+	return 0;
+}
+
+static int32 EngineRenewMonthsUpdate(int32 p1)
+{
+	DoCommandP(0, 1, _patches.autorenew_months, NULL, CMD_SET_AUTOREPLACE);
+	return 0;
+}
+
+static int32 EngineRenewMoneyUpdate(int32 p1)
+{
+	DoCommandP(0, 2, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
+	return 0;
+}
+/* End - Callback Functions */
+
+#ifndef EXTERNAL_PLAYER
+#define EXTERNAL_PLAYER "timidity"
+#endif
+
+static const SettingDesc _music_settings[] = {
+	 SDT_VAR(MusicFileSettings, playlist,   SLE_UINT8, S, 0,   0, 0,   5, 1,  STR_NULL, NULL),
+	 SDT_VAR(MusicFileSettings, music_vol,  SLE_UINT8, S, 0, 128, 0, 100, 1,  STR_NULL, NULL),
+	 SDT_VAR(MusicFileSettings, effect_vol, SLE_UINT8, S, 0, 128, 0, 100, 1,  STR_NULL, NULL),
+	SDT_LIST(MusicFileSettings, custom_1,   SLE_UINT8, S, 0, NULL,            STR_NULL, NULL),
+	SDT_LIST(MusicFileSettings, custom_2,   SLE_UINT8, S, 0, NULL,            STR_NULL, NULL),
+	SDT_BOOL(MusicFileSettings, playing,               S, 0, true,            STR_NULL, NULL),
+	SDT_BOOL(MusicFileSettings, shuffle,               S, 0, false,           STR_NULL, NULL),
+	 SDT_STR(MusicFileSettings, extmidi,     SLE_STRB, S, 0, EXTERNAL_PLAYER, STR_NULL, NULL),
+	 SDT_END()
+};
+
+/* win32_v.c only settings */
+#ifdef WIN32
+extern bool _force_full_redraw, _double_size, _window_maximize;
+extern uint _display_hz, _fullscreen_bpp;
+
+static const SettingDescGlobVarList _win32_settings[] = {
+	 SDTG_VAR("display_hz",     SLE_UINT, S, 0, _display_hz,       0, 0, 120, 0, STR_NULL, NULL),
+	SDTG_BOOL("force_full_redraw",        S, 0, _force_full_redraw,false,        STR_NULL, NULL),
+	 SDTG_VAR("fullscreen_bpp", SLE_UINT, S, 0, _fullscreen_bpp,   8, 8,  32, 0, STR_NULL, NULL),
+	SDTG_BOOL("double_size",              S, 0, _double_size,      false,        STR_NULL, NULL),
+	SDTG_BOOL("window_maximize",          S, 0, _window_maximize,  false,        STR_NULL, NULL),
+	 SDTG_END()
+};
+#endif /* WIN32 */
+
+static const SettingDescGlobVarList _misc_settings[] = {
+	SDTG_MMANY("display_opt",     SLE_UINT8, S, 0, _display_opt,       (DO_SHOW_TOWN_NAMES|DO_SHOW_STATION_NAMES|DO_SHOW_SIGNS|DO_FULL_ANIMATION|DO_FULL_DETAIL|DO_TRANS_BUILDINGS|DO_WAYPOINTS), "SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION|TRANS_BUILDINGS|FULL_DETAIL|WAYPOINTS", STR_NULL, NULL),
+	  SDTG_VAR("news_display_opt", SLE_UINT, S, 0, _news_display_opt,0xAAAAAAAA,0,0xAAAAAAAA,0,STR_NULL, NULL), // default to all full messages: 10101010101010101010 = 0xAAAAAAAA
+	 SDTG_BOOL("news_ticker_sound",          S, 0, _news_ticker_sound,     true,    STR_NULL, NULL),
+	 SDTG_BOOL("fullscreen",                 S, 0, _fullscreen,           false,    STR_NULL, NULL),
+	  SDTG_STR("videodriver",      SLE_STRB,C|S,0, _ini_videodriver,       NULL,    STR_NULL, NULL),
+	  SDTG_STR("musicdriver",      SLE_STRB,C|S,0, _ini_musicdriver,       NULL,    STR_NULL, NULL),
+	  SDTG_STR("sounddriver",      SLE_STRB,C|S,0, _ini_sounddriver,       NULL,    STR_NULL, NULL),
+	  SDTG_STR("language",         SLE_STRB, S, 0, _dynlang.curr_file,     NULL,    STR_NULL, NULL),
+	 SDTG_LIST("resolution",     SLE_UINT16, S, 0, _cur_resolution,   "640,480",    STR_NULL, NULL),
+	  SDTG_STR("screenshot_format",SLE_STRB, S, 0, _screenshot_format_name,NULL,    STR_NULL, NULL),
+	  SDTG_STR("savegame_format",  SLE_STRB, S, 0, _savegame_format,       NULL,    STR_NULL, NULL),
+	 SDTG_BOOL("rightclick_emulate",         S, 0, _rightclick_emulate,   false,    STR_NULL, NULL),
+#ifdef WITH_FREETYPE
+	  SDTG_STR("small_font",       SLE_STRB, S, 0, _freetype.small_font,   NULL,    STR_NULL, NULL),
+	  SDTG_STR("medium_font",      SLE_STRB, S, 0, _freetype.medium_font,  NULL,    STR_NULL, NULL),
+	  SDTG_STR("large_font",       SLE_STRB, S, 0, _freetype.large_font,   NULL,    STR_NULL, NULL),
+	  SDTG_VAR("small_size",       SLE_UINT, S, 0, _freetype.small_size,   6, 0, 72, 0, STR_NULL, NULL),
+	  SDTG_VAR("medium_size",      SLE_UINT, S, 0, _freetype.medium_size, 10, 0, 72, 0, STR_NULL, NULL),
+	  SDTG_VAR("large_size",       SLE_UINT, S, 0, _freetype.large_size,  16, 0, 72, 0, STR_NULL, NULL),
+#endif
+	  SDTG_END()
+};
+
+#ifdef ENABLE_NETWORK
+static const SettingDescGlobVarList _network_settings[] = {
+	 SDTG_VAR("sync_freq",           SLE_UINT16,C|S,0, _network_sync_freq,            100, 0,   100,   0, STR_NULL, NULL),
+	 SDTG_VAR("frame_freq",           SLE_UINT8,C|S,0, _network_frame_freq,             0, 0,   100,   0, STR_NULL, NULL),
+	 SDTG_VAR("max_join_time",       SLE_UINT16, S, 0, _network_max_join_time,        500, 0, 32000,   0, STR_NULL, NULL),
+	SDTG_BOOL("pause_on_join",                   S, 0, _network_pause_on_join,        true,               STR_NULL, NULL),
+	 SDTG_STR("server_bind_ip",        SLE_STRB, S, 0, _network_server_bind_ip_host,  "0.0.0.0",          STR_NULL, NULL),
+	 SDTG_VAR("server_port",         SLE_UINT16, S, 0, _network_server_port,          NETWORK_DEFAULT_PORT, 0, 65535, 0, STR_NULL, NULL),
+	SDTG_BOOL("server_advertise",                S, 0, _network_advertise,            false,              STR_NULL, NULL),
+	 SDTG_VAR("lan_internet",         SLE_UINT8, S, 0, _network_lan_internet,           0, 0,     1,   0, STR_NULL, NULL),
+	 SDTG_STR("player_name",           SLE_STRB, S, 0, _network_player_name,          NULL,               STR_NULL, NULL),
+	 SDTG_STR("server_password",       SLE_STRB, S, 0, _network_server_password,      NULL,               STR_NULL, NULL),
+	 SDTG_STR("rcon_password",         SLE_STRB, S, 0, _network_rcon_password,        NULL,               STR_NULL, NULL),
+	 SDTG_STR("server_name",           SLE_STRB, S, 0, _network_server_name,          NULL,               STR_NULL, NULL),
+	 SDTG_STR("connect_to_ip",         SLE_STRB, S, 0, _network_default_ip,           NULL,               STR_NULL, NULL),
+	 SDTG_STR("network_id",            SLE_STRB, S, 0, _network_unique_id,            NULL,               STR_NULL, NULL),
+	SDTG_BOOL("autoclean_companies",             S, 0, _network_autoclean_companies,  false,              STR_NULL, NULL),
+	 SDTG_VAR("autoclean_unprotected",SLE_UINT8, S, 0, _network_autoclean_unprotected,12, 0,     60,   0, STR_NULL, NULL),
+	 SDTG_VAR("autoclean_protected",  SLE_UINT8, S, 0, _network_autoclean_protected,  36, 0,    180,   0, STR_NULL, NULL),
+	 SDTG_VAR("max_companies",        SLE_UINT8, S, 0, _network_game_info.companies_max,   8, 0,  8,   0, STR_NULL, NULL),
+	 SDTG_VAR("max_clients",          SLE_UINT8, S, 0, _network_game_info.clients_max,    10, 0, 10,   0, STR_NULL, NULL),
+	 SDTG_VAR("max_spectators",       SLE_UINT8, S, 0, _network_game_info.spectators_max, 10, 0, 10,   0, STR_NULL, NULL),
+	 SDTG_VAR("restart_game_year",    SLE_INT32, S,D0, _network_restart_game_year,    0, MIN_YEAR, MAX_YEAR, 1, STR_NULL, NULL),
+	 SDTG_VAR("min_players",          SLE_UINT8, S, 0, _network_min_players,               0, 0, 10,   0, STR_NULL, NULL),
+	 SDTG_END()
+};
+#endif /* ENABLE_NETWORK */
+
+static const SettingDesc _gameopt_settings[] = {
+	/* In version 4 a new difficulty setting has been added to the difficulty settings,
+	 * town attitude towards demolishing. Needs special handling because some dimwit thought
+	 * it funny to have the GameDifficulty struct be an array while it is a struct of
+	 * same-sized members
+	 * XXX - To save file-space and since values are never bigger than about 10? only
+	 * save the first 16 bits in the savegame. Question is why the values are still int32
+	 * and why not byte for example? */
+	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, 0, 3),
+	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, 4, SL_MAX_VERSION),
+	    SDT_VAR(GameOptions, diff_level,SLE_UINT8, 0, 0, 9, 0,  9, 0, STR_NULL, NULL),
+	  SDT_OMANY(GameOptions, currency,  SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL),
+	  SDT_OMANY(GameOptions, units,     SLE_UINT8, N, 0, 1,     2, "imperial|metric|si", STR_NULL, NULL),
+	  SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0,    20, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL),
+	  SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0,     3, "normal|hilly|desert|candy", STR_NULL, NULL),
+	    SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 1, 0, 56, 0, STR_NULL, NULL),
+	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8, 0, 22,             N, 0, 0, 0, "", STR_NULL, NULL),
+	SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8,23, SL_MAX_VERSION, S, 0, 1, 4, "off|monthly|quarterly|half year|yearly", STR_NULL, NULL),
+	  SDT_OMANY(GameOptions, road_side, SLE_UINT8, 0, 0, 1,   1, "left|right", STR_NULL, NULL),
+	    SDT_END()
+};
+
+/* Some patches do not need to be synchronised when playing in multiplayer.
+ * These include for example the GUI settings and will not be saved with the
+ * savegame.
+ * It is also a bit tricky since you would think that service_interval
+ * for example doesn't need to be synched. Every client assigns the
+ * service_interval value to the v->service_interval, meaning that every client
+ * assigns his value. If the setting was player-based, that would mean that
+ * vehicles could decide on different moments that they are heading back to a
+ * service depot, causing desyncs on a massive scale. */
+const SettingDesc _patch_settings[] = {
+	/***************************************************************************/
+	/* User-interface section of the GUI-configure patches window */
+	SDT_BOOL(Patches, vehicle_speed,                 S, 0,  true,        STR_CONFIG_PATCHES_VEHICLESPEED,          NULL),
+	SDT_BOOL(Patches, status_long_date,              S, 0,  true,        STR_CONFIG_PATCHES_LONGDATE,              NULL),
+	SDT_BOOL(Patches, show_finances,                 S, 0,  true,        STR_CONFIG_PATCHES_SHOWFINANCES,          NULL),
+	SDT_BOOL(Patches, autoscroll,                    S, 0, false,        STR_CONFIG_PATCHES_AUTOSCROLL,            NULL),
+	SDT_BOOL(Patches, reverse_scroll,                S, 0, false,        STR_CONFIG_PATCHES_REVERSE_SCROLLING,     NULL),
+	SDT_BOOL(Patches, measure_tooltip,               S, 0, false,        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,       NULL),
+	 SDT_VAR(Patches, errmsg_duration,    SLE_UINT8, S, 0,  5, 0, 20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,       NULL),
+	 SDT_VAR(Patches, toolbar_pos,        SLE_UINT8, S,MS,  0, 0,  2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,           v_PositionMainToolbar),
+	 SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1, 32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,           NULL),
+	SDT_BOOL(Patches, invisible_trees,               S, 0, false,        STR_CONFIG_PATCHES_INVISIBLE_TREES,       RedrawScreen),
+	SDT_BOOL(Patches, population_in_label,           S, 0,  true,        STR_CONFIG_PATCHES_POPULATION_IN_LABEL,   PopulationInLabelActive),
+	 SDT_VAR(Patches, map_x,              SLE_UINT8, S, 0,  8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_X,                 NULL),
+	 SDT_VAR(Patches, map_y,              SLE_UINT8, S, 0,  8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_Y,                 NULL),
+	SDT_BOOL(Patches, link_terraform_toolbar,        S, 0, false,        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL),
+	 SDT_VAR(Patches, liveries,           SLE_UINT8, S,MS,  2, 0,  2, 0, STR_CONFIG_PATCHES_LIVERIES,              RedrawScreen),
+	SDT_BOOL(Patches, prefer_teamchat,               S, 0, false,        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,       NULL),
+
+	/***************************************************************************/
+	/* Construction section of the GUI-configure patches window */
+	SDT_BOOL(Patches, build_on_slopes,               0, 0,  true,        STR_CONFIG_PATCHES_BUILDONSLOPES,       NULL),
+	SDT_BOOL(Patches, extra_dynamite,                0, 0, false,        STR_CONFIG_PATCHES_EXTRADYNAMITE,       NULL),
+	SDT_BOOL(Patches, longbridges,                   0, 0,  true,        STR_CONFIG_PATCHES_LONGBRIDGES,         NULL),
+	SDT_BOOL(Patches, signal_side,                   N, 0,  true,        STR_CONFIG_PATCHES_SIGNALSIDE,          RedrawScreen),
+	SDT_BOOL(Patches, always_small_airport,          0, 0, false,        STR_CONFIG_PATCHES_SMALL_AIRPORTS,      NULL),
+	 SDT_VAR(Patches, drag_signals_density,SLE_UINT8,S, 0,  4, 1, 20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,NULL),
+
+	/***************************************************************************/
+	/* Vehicle section of the GUI-configure patches window */
+	SDT_BOOL(Patches, realistic_acceleration,        0, 0, false,                    STR_CONFIG_PATCHES_REALISTICACCEL,       NULL),
+	SDT_BOOL(Patches, forbid_90_deg,                 0, 0, false,                    STR_CONFIG_PATCHES_FORBID_90_DEG,        NULL),
+	SDT_BOOL(Patches, mammoth_trains,                0, 0,  true,                    STR_CONFIG_PATCHES_MAMMOTHTRAINS,        NULL),
+	SDT_BOOL(Patches, gotodepot,                     0, 0,  true,                    STR_CONFIG_PATCHES_GOTODEPOT,            NULL),
+	SDT_BOOL(Patches, roadveh_queue,                 0, 0,  true,                    STR_CONFIG_PATCHES_ROADVEH_QUEUE,        NULL),
+	SDT_BOOL(Patches, new_pathfinding_all,           0, 0, false,                    STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL,  NULL),
+
+	SDT_CONDBOOL(Patches, yapf.ship_use_yapf,      28, SL_MAX_VERSION, 0, 0, false,  STR_CONFIG_PATCHES_YAPF_SHIPS,      NULL),
+	SDT_CONDBOOL(Patches, yapf.road_use_yapf,      28, SL_MAX_VERSION, 0, 0,  true,  STR_CONFIG_PATCHES_YAPF_ROAD,       NULL),
+	SDT_CONDBOOL(Patches, yapf.rail_use_yapf,      28, SL_MAX_VERSION, 0, 0,  true,  STR_CONFIG_PATCHES_YAPF_RAIL,       NULL),
+
+	SDT_BOOL(Patches, train_income_warn,             S, 0,  true,                    STR_CONFIG_PATCHES_WARN_INCOME_LESS,     NULL),
+	 SDT_VAR(Patches, order_review_system,SLE_UINT8, S,MS,     2,     0,       2, 0, STR_CONFIG_PATCHES_ORDER_REVIEW,         NULL),
+	SDT_BOOL(Patches, never_expire_vehicles,         0, 0, false,                    STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES,NULL),
+	SDT_BOOL(Patches, lost_train_warn,               S, 0,  true,                    STR_CONFIG_PATCHES_WARN_LOST_TRAIN,      NULL),
+	SDT_BOOL(Patches, autorenew,                     S, 0, false,                    STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,    EngineRenewUpdate),
+	 SDT_VAR(Patches, autorenew_months,   SLE_INT16, S, 0,     6,   -12,      12, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS,     EngineRenewMonthsUpdate),
+	 SDT_VAR(Patches, autorenew_money,     SLE_UINT, S,CR,100000,     0, 2000000, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY,      EngineRenewMoneyUpdate),
+	 SDT_VAR(Patches, max_trains,        SLE_UINT16, 0, 0,   500,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_TRAINS,           NULL),
+	 SDT_VAR(Patches, max_roadveh,       SLE_UINT16, 0, 0,   500,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_ROADVEH,          NULL),
+	 SDT_VAR(Patches, max_aircraft,      SLE_UINT16, 0, 0,   200,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_AIRCRAFT,         NULL),
+	 SDT_VAR(Patches, max_ships,         SLE_UINT16, 0, 0,   300,     0,    5000, 0, STR_CONFIG_PATCHES_MAX_SHIPS,            NULL),
+	SDT_BOOL(Patches, servint_ispercent,             0, 0, false,                    STR_CONFIG_PATCHES_SERVINT_ISPERCENT,    CheckInterval),
+	 SDT_VAR(Patches, servint_trains,    SLE_UINT16, 0,D0,   150,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_TRAINS,       InValidateDetailsWindow),
+	 SDT_VAR(Patches, servint_roadveh,   SLE_UINT16, 0,D0,   150,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_ROADVEH,      InValidateDetailsWindow),
+	 SDT_VAR(Patches, servint_ships,     SLE_UINT16, 0,D0,   360,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_SHIPS,        InValidateDetailsWindow),
+	 SDT_VAR(Patches, servint_aircraft,  SLE_UINT16, 0,D0,   100,     5,     800, 0, STR_CONFIG_PATCHES_SERVINT_AIRCRAFT,     InValidateDetailsWindow),
+	SDT_BOOL(Patches, no_servicing_if_no_breakdowns, 0, 0, false,                    STR_CONFIG_PATCHES_NOSERVICE,            NULL),
+	SDT_BOOL(Patches, wagon_speed_limits,            0, 0,  true,                    STR_CONFIG_PATCHES_WAGONSPEEDLIMITS,     NULL),
+	SDT_CONDBOOL(Patches, disable_elrails, 38, SL_MAX_VERSION, 0, 0, false,          STR_CONFIG_PATCHES_DISABLE_ELRAILS,      SettingsDisableElrail),
+	SDT_CONDVAR(Patches, freight_trains, SLE_UINT8, 39, SL_MAX_VERSION, 0, 0, 1, 1, 255, 1, STR_CONFIG_PATCHES_FREIGHT_TRAINS, NULL),
+
+	/***************************************************************************/
+	/* Station section of the GUI-configure patches window */
+	SDT_BOOL(Patches, join_stations,           0, 0,  true,        STR_CONFIG_PATCHES_JOINSTATIONS,       NULL),
+	SDT_BOOL(Patches, full_load_any,           0, 0,  true,        STR_CONFIG_PATCHES_FULLLOADANY,        NULL),
+	SDT_BOOL(Patches, improved_load,           0, 0, false,        STR_CONFIG_PATCHES_IMPROVEDLOAD,       NULL),
+	SDT_BOOL(Patches, selectgoods,             0, 0,  true,        STR_CONFIG_PATCHES_SELECTGOODS,        NULL),
+	SDT_BOOL(Patches, new_nonstop,             0, 0, false,        STR_CONFIG_PATCHES_NEW_NONSTOP,        NULL),
+	SDT_BOOL(Patches, nonuniform_stations,     0, 0,  true,        STR_CONFIG_PATCHES_NONUNIFORM_STATIONS,NULL),
+	 SDT_VAR(Patches, station_spread,SLE_UINT8,0, 0, 12, 4, 64, 0, STR_CONFIG_PATCHES_STATION_SPREAD,     InvalidateStationBuildWindow),
+	SDT_BOOL(Patches, serviceathelipad,        0, 0,  true,        STR_CONFIG_PATCHES_SERVICEATHELIPAD,   NULL),
+	SDT_BOOL(Patches, modified_catchment,      0, 0,  true,        STR_CONFIG_PATCHES_CATCHMENT,          NULL),
+	SDT_CONDBOOL(Patches, gradual_loading, 40, SL_MAX_VERSION, 0, 0,  true, STR_CONFIG_PATCHES_GRADUAL_LOADING,    NULL),
+
+	/***************************************************************************/
+	/* Economy section of the GUI-configure patches window */
+	SDT_BOOL(Patches, inflation,                  0, 0,  true,            STR_CONFIG_PATCHES_INFLATION,        NULL),
+	SDT_BOOL(Patches, build_rawmaterial_ind,      0, 0, false,            STR_CONFIG_PATCHES_BUILDXTRAIND,     NULL),
+	SDT_BOOL(Patches, multiple_industry_per_town, 0, 0, false,            STR_CONFIG_PATCHES_MULTIPINDTOWN,    NULL),
+	SDT_BOOL(Patches, same_industry_close,        0, 0, false,            STR_CONFIG_PATCHES_SAMEINDCLOSE,     NULL),
+	SDT_BOOL(Patches, bribe,                      0, 0,  true,            STR_CONFIG_PATCHES_BRIBE,            NULL),
+	 SDT_VAR(Patches, snow_line_height,SLE_UINT8, 0, 0,     7,  2, 13, 0, STR_CONFIG_PATCHES_SNOWLINE_HEIGHT,  NULL),
+	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
+	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
+	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
+	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
+	SDT_BOOL(Patches, allow_shares,               0, 0,  true,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
+
+	/***************************************************************************/
+	/* AI section of the GUI-configure patches window */
+	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
+	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
+	SDT_BOOL(Patches, ai_disable_veh_train,   0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_TRAINS,  NULL),
+	SDT_BOOL(Patches, ai_disable_veh_roadveh, 0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_ROADVEH, NULL),
+	SDT_BOOL(Patches, ai_disable_veh_aircraft,0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_AIRCRAFT,NULL),
+	SDT_BOOL(Patches, ai_disable_veh_ship,    0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_SHIPS,   NULL),
+
+	/***************************************************************************/
+	/* Patches without any GUI representation */
+	SDT_BOOL(Patches, keep_all_autosave,              S, 0, false,         STR_NULL, NULL),
+	SDT_BOOL(Patches, autosave_on_exit,               S, 0, false,         STR_NULL, NULL),
+	 SDT_VAR(Patches, max_num_autosaves,   SLE_UINT8, S, 0, 16, 0, 255, 0, STR_NULL, NULL),
+	SDT_BOOL(Patches, bridge_pillars,                 S, 0,  true,         STR_NULL, NULL),
+	 SDT_VAR(Patches, extend_vehicle_life, SLE_UINT8, 0, 0,  0, 0, 100, 0, STR_NULL, NULL),
+	SDT_BOOL(Patches, auto_euro,                      S, 0,  true,         STR_NULL, NULL),
+	 SDT_VAR(Patches, dist_local_authority,SLE_UINT8, 0, 0, 20, 5,  60, 0, STR_NULL, NULL),
+	 SDT_VAR(Patches, wait_oneway_signal,  SLE_UINT8, 0, 0, 15, 2, 100, 0, STR_NULL, NULL),
+	 SDT_VAR(Patches, wait_twoway_signal,  SLE_UINT8, 0, 0, 41, 2, 100, 0, STR_NULL, NULL),
+
+	/***************************************************************************/
+	/* New Pathfinding patch settings */
+	SDT_VAR(Patches, pf_maxlength,      SLE_UINT16, 0, 0,  4096,  64,  65535, 0, STR_NULL, NULL),
+	SDT_VAR(Patches, pf_maxdepth,        SLE_UINT8, 0, 0,    48,   4,    255, 0, STR_NULL, NULL),
+	/* The maximum number of nodes to search */
+	SDT_VAR(Patches, npf_max_search_nodes,SLE_UINT, 0, 0, 10000, 500, 100000, 0, STR_NULL, NULL),
+
+	/* When a red signal is encountered, a small detour can be made around
+	 * it. This specifically occurs when a track is doubled, in which case
+	 * the detour is typically 2 tiles. It is also often used at station
+	 * entrances, when there is a choice of multiple platforms. If we take
+	 * a typical 4 platform station, the detour is 4 tiles. To properly
+	 * support larger stations we increase this value.
+	 * We want to prevent that trains that want to leave at one side of a
+	 * station, leave through the other side, turn around, enter the
+	 * station on another platform and exit the station on the right side
+	 * again, just because the sign at the right side was red. If we take
+	 * a typical 5 length station, this detour is 10 or 11 tiles (not
+	 * sure), so we set the default penalty at 10 (the station tile
+	 * penalty will further prevent this.
+	 * We give presignal exits (and combo's) a different (larger) penalty, because
+	 * we really don't want trains waiting in front of a presignal exit. */
+	SDT_VAR(Patches, npf_rail_firstred_penalty,     SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
+	SDT_VAR(Patches, npf_rail_firstred_exit_penalty,SLE_UINT, 0, 0, (100 * NPF_TILE_LENGTH),0, 100000, 0, STR_NULL, NULL),
+	/* This penalty is for when the last signal before the target is red.
+	 * This is useful for train stations, where there are multiple
+	 * platforms to choose from, which lie in different signal blocks.
+	 * Every target in a occupied signal block (ie an occupied platform)
+	 * will get this penalty. */
+	SDT_VAR(Patches, npf_rail_lastred_penalty, SLE_UINT, 0, 0, (10 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
+	/* When a train plans a route over a station tile, this penalty is
+	 * applied. We want that trains plan a route around a typical, 4x5
+	 * station, which means two tiles to the right, and two tiles back to
+	 * the left around it, or 5 tiles of station through it. If we assign
+	 * a penalty of 1 tile for every station tile passed, the route will
+	 * be around it. */
+	SDT_VAR(Patches, npf_rail_station_penalty, SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
+	SDT_VAR(Patches, npf_rail_slope_penalty,   SLE_UINT, 0, 0, (1 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL),
+	/* This penalty is applied when a train makes a turn. Its value of 1 makes
+	 * sure that it has a minimal impact on the pathfinding, only when two
+	 * paths have equal length it will make a difference */
+	SDT_VAR(Patches, npf_rail_curve_penalty,        SLE_UINT, 0, 0, 1,                      0, 100000, 0, STR_NULL, NULL),
+	/* Ths penalty is applied when a vehicle reverses inside a depot (doesn't
+	 * apply to ships, as they can just come out the other end). XXX: Is this a
+	 * good value? */
+	SDT_VAR(Patches, npf_rail_depot_reverse_penalty,SLE_UINT, 0, 0, (NPF_TILE_LENGTH * 50), 0, 100000, 0, STR_NULL, NULL),
+	SDT_VAR(Patches, npf_buoy_penalty,              SLE_UINT, 0, 0, (2 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
+	/* This penalty is applied when a ship makes a turn. It is bigger than the
+	 * rail curve penalty, since ships (realisticly) have more trouble with
+	 * making turns */
+	SDT_VAR(Patches, npf_water_curve_penalty,       SLE_UINT, 0, 0, (NPF_TILE_LENGTH / 4),  0, 100000, 0, STR_NULL, NULL),
+	/* This is the penalty for road, same as for rail. */
+	SDT_VAR(Patches, npf_road_curve_penalty,        SLE_UINT, 0, 0, 1,                      0, 100000, 0, STR_NULL, NULL),
+	/* This is the penalty for level crossings, for both road and rail vehicles */
+	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
+
+
+	// The maximum number of nodes to search
+	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_firstred_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_firstred_exit_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_lastred_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_lastred_exit_penalty  , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_station_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    30 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_slope_penalty         , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     2 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_curve45_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     1 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_curve90_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     6 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	// This penalty is applied when a train reverses inside a depot
+	SDT_CONDVAR (Patches, yapf.rail_depot_reverse_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    50 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	// This is the penalty for level crossings (for trains only)
+	SDT_CONDVAR (Patches, yapf.rail_crossing_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     3 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
+	// look-ahead how many signals are checked
+	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
+	// look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0
+	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
+	// penalties for too long or too short station platforms
+	SDT_CONDVAR (Patches, yapf.rail_longer_platform_penalty,           SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_longer_platform_per_tile_penalty,  SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_penalty,          SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 40 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_per_tile_penalty, SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
+	// road vehicles - penalties
+	SDT_CONDVAR (Patches, yapf.road_slope_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  2 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.road_curve_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  1 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
+	SDT_CONDVAR (Patches, yapf.road_crossing_penalty                 , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  3 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
+
+	/***************************************************************************/
+	/* Terrain genation related patch options */
+	SDT_CONDVAR(Patches,      land_generator,           SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   1,                   0,    1,               0, STR_CONFIG_PATCHES_LAND_GENERATOR,           NULL),
+	SDT_CONDVAR(Patches,      oil_refinery_limit,       SLE_UINT8,  30, SL_MAX_VERSION, 0, 0,   16,                  12,   48,               0, STR_CONFIG_PATCHES_OIL_REF_EDGE_DISTANCE,    NULL),
+	SDT_CONDVAR(Patches,      tgen_smoothness,          SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   1,                   0,    3,               0, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN,     NULL),
+	SDT_CONDVAR(Patches,      generation_seed,          SLE_UINT32, 30, SL_MAX_VERSION, 0, 0,    GENERATE_NEW_SEED,   0, MAX_UVALUE(uint32), 0, STR_NULL,                                    NULL),
+	SDT_CONDVAR(Patches,      tree_placer,              SLE_UINT8,  30, SL_MAX_VERSION, 0, MS,   2,                   0,    2,               0, STR_CONFIG_PATCHES_TREE_PLACER,              NULL),
+	SDT_VAR    (Patches,      heightmap_rotation,       SLE_UINT8,                      S, MS,   0,                   0,    1,               0, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION,       NULL),
+	SDT_VAR    (Patches,      se_flat_world_height,     SLE_UINT8,                      S, 0,    0,                   0,   15,               0, STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT,     NULL),
+
+	SDT_END()
+};
+
+static const SettingDesc _currency_settings[] = {
+	SDT_VAR(CurrencySpec, rate,    SLE_UINT16, S, 0,  1, 0, 100, 0, STR_NULL, NULL),
+	SDT_CHR(CurrencySpec, separator,           S, 0,        ".",    STR_NULL, NULL),
+	SDT_VAR(CurrencySpec, to_euro,  SLE_INT32, S, 0,  0, 0,1000, 0, STR_NULL, NULL),
+	SDT_STR(CurrencySpec, prefix,   SLE_STRBQ, S, 0,       NULL,    STR_NULL, NULL),
+	SDT_STR(CurrencySpec, suffix,   SLE_STRBQ, S, 0, " credits",    STR_NULL, NULL),
+	SDT_END()
+};
+
+/* Undefine for the shortcut macros above */
+#undef S
+#undef C
+#undef N
+
+#undef D0
+#undef NC
+#undef MS
+#undef NO
+#undef CR
+
+
+/* Load a GRF configuration from the given group name */
+static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static)
+{
+	IniGroup *group = ini_getgroup(ini, grpname, -1);
+	IniItem *item;
+	GRFConfig *first = NULL;
+	GRFConfig **curr = &first;
+
+	if (group == NULL) return NULL;
+
+	for (item = group->item; item != NULL; item = item->next) {
+		GRFConfig *c = calloc(1, sizeof(*c));
+		c->filename = strdup(item->name);
+
+		/* Parse parameters */
+		if (*item->value != '\0') {
+			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
+			if (c->num_params == (byte)-1) {
+				ShowInfoF("ini: error in array '%s'", item->name);
+				c->num_params = 0;
+			}
+		}
+
+		/* Check if item is valid */
+		if (!FillGRFDetails(c, is_static)) {
+			const char *msg;
+
+			if (HASBIT(c->flags, GCF_NOT_FOUND)) {
+				msg = "not found";
+			} else if (HASBIT(c->flags, GCF_UNSAFE)) {
+				msg = "unsafe for static use";
+			} else if (HASBIT(c->flags, GCF_SYSTEM)) {
+				msg = "system NewGRF";
+			} else {
+				msg = "unknown";
+			}
+
+			ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg);
+			ClearGRFConfig(&c);
+			continue;
+		}
+
+		/* Mark file as static to avoid saving in savegame. */
+		if (is_static) SETBIT(c->flags, GCF_STATIC);
+
+		/* Add item to list */
+		*curr = c;
+		curr = &c->next;
+	}
+
+	return first;
+}
+
+
+/* Save a GRF configuration to the given group name */
+static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list)
+{
+	IniGroup *group = ini_getgroup(ini, grpname, -1);
+	IniItem **item;
+	const GRFConfig *c;
+
+	if (group == NULL) return;
+	group->item = NULL;
+	item = &group->item;
+
+	for (c = list; c != NULL; c = c->next) {
+		char params[512];
+		GRFBuildParamList(params, c, lastof(params));
+
+		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
+		(*item)->value = pool_strdup(&ini->pool, params, strlen(params));
+		item = &(*item)->next;
+	}
+}
+
+/* Common handler for saving/loading variables to the configuration file */
+static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list)
+{
+	proc(ini, (const SettingDesc*)_misc_settings,    "misc",  NULL);
+	proc(ini, (const SettingDesc*)_music_settings,   "music", &msf);
+#ifdef WIN32
+	proc(ini, (const SettingDesc*)_win32_settings,   "win32", NULL);
+#endif /* WIN32 */
+
+	proc(ini, _gameopt_settings, "gameopt",  &_opt_newgame);
+	proc(ini, _patch_settings,   "patches",  &_patches_newgame);
+	proc(ini, _currency_settings,"currency", &_custom_currency);
+
+#ifdef ENABLE_NETWORK
+	proc(ini, (const SettingDesc*)_network_settings, "network", NULL);
+	proc_list(ini, "servers", _network_host_list, lengthof(_network_host_list), NULL);
+	proc_list(ini, "bans",    _network_ban_list,  lengthof(_network_ban_list), NULL);
+#endif /* ENABLE_NETWORK */
+}
+
+/** Load the values from the configuration files */
+void LoadFromConfig(void)
+{
+	IniFile *ini = ini_load(_config_file);
+	HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
+	_grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
+	_grfconfig_static  = GRFLoadConfig(ini, "newgrf-static", true);
+	ini_free(ini);
+}
+
+/** Save the values to the configuration file */
+void SaveToConfig(void)
+{
+	IniFile *ini = ini_load(_config_file);
+	HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
+	GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
+	GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
+	ini_save(_config_file, ini);
+	ini_free(ini);
+}
+
+static const SettingDesc *GetSettingDescription(uint index)
+{
+	if (index >= lengthof(_patch_settings)) return NULL;
+	return &_patch_settings[index];
+}
+
+/** Network-safe changing of patch-settings (server-only).
+ * @param p1 the index of the patch in the SettingDesc array which identifies it
+ * @param p2 the new value for the patch
+ * The new value is properly clamped to its minimum/maximum when setting
+ * @see _patch_settings
+ */
+int32 CmdChangePatchSetting(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	const SettingDesc *sd = GetSettingDescription(p1);
+
+	if (sd == NULL) return CMD_ERROR;
+	if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		Patches *patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
+		void *var = GetVariableAddress(patches_ptr, &sd->save);
+		Write_ValidateSetting(var, sd, (int32)p2);
+		if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
+
+		InvalidateWindow(WC_GAME_OPTIONS, 0);
+	}
+
+	return 0;
+}
+
+/** Top function to save the new value of an element of the Patches struct
+ * @param index offset in the SettingDesc array of the Patches struct which
+ * identifies the patch member we want to change
+ * @param object pointer to a valid patches struct that has its settings change.
+ * This only affects patch-members that are not needed to be the same on all
+ * clients in a network game.
+ * @param value new value of the patch */
+bool SetPatchValue(uint index, const Patches *object, int32 value)
+{
+	const SettingDesc *sd = &_patch_settings[index];
+	/* If an item is player-based, we do not send it over the network
+	 * (if any) to change. Also *hack*hack* we update the _newgame version
+	 * of patches because changing a player-based setting in a game also
+	 * changes its defaults. At least that is the convention we have chosen */
+	if (sd->save.conv & SLF_NETWORK_NO) {
+		void *var = GetVariableAddress(object, &sd->save);
+		Write_ValidateSetting(var, sd, value);
+
+		if (_game_mode != GM_MENU) {
+			void *var2 = GetVariableAddress(&_patches_newgame, &sd->save);
+			Write_ValidateSetting(var2, sd, value);
+		}
+		if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
+		InvalidateWindow(WC_GAME_OPTIONS, 0);
+		return true;
+	}
+
+	/* send non-player-based settings over the network */
+	if (!_networking || (_networking && _network_server)) {
+		return DoCommandP(0, index, value, NULL, CMD_CHANGE_PATCH_SETTING);
+	}
+	return false;
+}
+
+const SettingDesc *GetPatchFromName(const char *name, uint *i)
+{
+	const SettingDesc *sd;
+
+	for (*i = 0, sd = _patch_settings; sd->save.cmd != SL_END; sd++, (*i)++) {
+		if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
+		if (strcmp(sd->desc.name, name) == 0) return sd;
+	}
+
+	return NULL;
+}
+
+/* Those 2 functions need to be here, else we have to make some stuff non-static
+ * and besides, it is also better to keep stuff like this at the same place */
+bool IConsoleSetPatchSetting(const char *name, int32 value)
+{
+	bool success;
+	uint index;
+	const SettingDesc *sd = GetPatchFromName(name, &index);
+	const Patches *patches_ptr;
+	void *ptr;
+
+	if (sd == NULL) {
+		IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
+		return true;
+	}
+
+	patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
+	ptr = GetVariableAddress(patches_ptr, &sd->save);
+
+	success = SetPatchValue(index, patches_ptr, value);
+	return success;
+}
+
+void IConsoleGetPatchSetting(const char *name)
+{
+	char value[20];
+	uint index;
+	const SettingDesc *sd = GetPatchFromName(name, &index);
+	const void *ptr;
+
+	if (sd == NULL) {
+		IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
+		return;
+	}
+
+	ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_patches_newgame : &_patches, &sd->save);
+
+	if (sd->desc.cmd == SDT_BOOLX) {
+		snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
+	} else {
+		snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
+	}
+
+	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
+		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
+}
+
+/** Save and load handler for patches/settings
+ * @param osd SettingDesc struct containing all information
+ * @param object can be either NULL in which case we load global variables or
+ * a pointer to a struct which is getting saved */
+static void LoadSettings(const SettingDesc *osd, void *object)
+{
+	for (; osd->save.cmd != SL_END; osd++) {
+		const SaveLoad *sld = &osd->save;
+		void *ptr = GetVariableAddress(object, sld);
+
+		if (!SlObjectMember(ptr, sld)) continue;
+	}
+}
+
+/** Loadhandler for a list of global variables
+ * @note this is actually a stub for LoadSettings with the
+ * object pointer set to NULL */
+static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
+{
+	LoadSettings((const SettingDesc*)sdg, NULL);
+}
+
+/** Save and load handler for patches/settings
+ * @param osd SettingDesc struct containing all information
+ * @param object can be either NULL in which case we load global variables or
+ * a pointer to a struct which is getting saved */
+static void SaveSettings(const SettingDesc *sd, void *object)
+{
+	/* We need to write the CH_RIFF header, but unfortunately can't call
+	 * SlCalcLength() because we have a different format. So do this manually */
+	const SettingDesc *i;
+	size_t length = 0;
+	for (i = sd; i->save.cmd != SL_END; i++) {
+		const void *ptr = GetVariableAddress(object, &i->save);
+		length += SlCalcObjMemberLength(ptr, &i->save);
+	}
+	SlSetLength(length);
+
+	for (i = sd; i->save.cmd != SL_END; i++) {
+		void *ptr = GetVariableAddress(object, &i->save);
+		SlObjectMember(ptr, &i->save);
+	}
+}
+
+/** Savehandler for a list of global variables
+ * @note this is actually a stub for SaveSettings with the
+ * object pointer set to NULL */
+static inline void SaveSettingsGlobList(const SettingDescGlobVarList *sdg)
+{
+	SaveSettings((const SettingDesc*)sdg, NULL);
+}
+
+static void Load_OPTS(void)
+{
+	/* Copy over default setting since some might not get loaded in
+	 * a networking environment. This ensures for example that the local
+	 * autosave-frequency stays when joining a network-server */
+	_opt = _opt_newgame;
+	LoadSettings(_gameopt_settings, &_opt);
+}
+
+static void Save_OPTS(void)
+{
+	SaveSettings(_gameopt_settings, &_opt);
+}
+
+static void Load_PATS(void)
+{
+	/* Copy over default setting since some might not get loaded in
+	 * a networking environment. This ensures for example that the local
+	 * signal_side stays when joining a network-server */
+	_patches = _patches_newgame;
+	LoadSettings(_patch_settings, &_patches);
+}
+
+static void Save_PATS(void)
+{
+	SaveSettings(_patch_settings, &_patches);
+}
+
+void CheckConfig(void)
+{
+	// fix up news_display_opt from old to new
+	int i;
+	uint32 tmp;
+	for (i = 0, tmp = _news_display_opt; i != 10; i++, tmp >>= 2) {
+		if ((tmp & 0x3) == 0x3) { // old settings
+			_news_display_opt = 0xAAAAAAAA; // set all news-messages to full 1010101010...
+			break;
+		}
+	}
+
+	// Increase old default values for pf_maxdepth and pf_maxlength
+	// to support big networks.
+	if (_patches_newgame.pf_maxdepth == 16 && _patches_newgame.pf_maxlength == 512) {
+		_patches_newgame.pf_maxdepth = 48;
+		_patches_newgame.pf_maxlength = 4096;
+	}
+}
+
+void UpdatePatches(void)
+{
+	/* Since old(er) savegames don't have any patches saved, we initialise
+	 * them with the default values just as it was in the old days.
+	 * Also new games need this copying-over */
+	_patches = _patches_newgame; /* backwards compatibility */
+}
+
+const ChunkHandler _setting_chunk_handlers[] = {
+	{ 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF},
+	{ 'PATS', Save_PATS, Load_PATS, CH_RIFF | CH_LAST},
+};
+
+static bool IsSignedVarMemType(VarType vt)
+{
+	switch (GetVarMemType(vt)) {
+		case SLE_VAR_I8:
+		case SLE_VAR_I16:
+		case SLE_VAR_I32:
+		case SLE_VAR_I64:
+			return true;
+	}
+	return false;
+}
deleted file mode 100644
--- a/src/settings_gui.c
+++ /dev/null
@@ -1,1140 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "functions.h"
-#include "string.h"
-#include "strings.h" // XXX GetCurrentCurrencyRate()
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "command.h"
-#include "engine.h"
-#include "screenshot.h"
-#include "newgrf.h"
-#include "network/network.h"
-#include "town.h"
-#include "variables.h"
-#include "settings.h"
-#include "vehicle.h"
-#include "date.h"
-
-static uint32 _difficulty_click_a;
-static uint32 _difficulty_click_b;
-static byte _difficulty_timeout;
-
-static const StringID _units_dropdown[] = {
-	STR_UNITS_IMPERIAL,
-	STR_UNITS_METRIC,
-	STR_UNITS_SI,
-	INVALID_STRING_ID
-};
-
-static const StringID _driveside_dropdown[] = {
-	STR_02E9_DRIVE_ON_LEFT,
-	STR_02EA_DRIVE_ON_RIGHT,
-	INVALID_STRING_ID
-};
-
-static const StringID _autosave_dropdown[] = {
-	STR_02F7_OFF,
-	STR_AUTOSAVE_1_MONTH,
-	STR_02F8_EVERY_3_MONTHS,
-	STR_02F9_EVERY_6_MONTHS,
-	STR_02FA_EVERY_12_MONTHS,
-	INVALID_STRING_ID,
-};
-
-static const StringID _designnames_dropdown[] = {
-	STR_02BE_DEFAULT,
-	STR_02BF_CUSTOM,
-	INVALID_STRING_ID
-};
-
-static StringID *BuildDynamicDropdown(StringID base, int num)
-{
-	static StringID buf[32 + 1];
-	StringID *p = buf;
-	while (--num>=0) *p++ = base++;
-	*p = INVALID_STRING_ID;
-	return buf;
-}
-
-static int GetCurRes(void)
-{
-	int i;
-
-	for (i = 0; i != _num_resolutions; i++) {
-		if (_resolutions[i][0] == _screen.width &&
-				_resolutions[i][1] == _screen.height) {
-			break;
-		}
-	}
-	return i;
-}
-
-static inline bool RoadVehiclesAreBuilt(void)
-{
-	const Vehicle* v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Road) return true;
-	}
-	return false;
-}
-
-
-static void ShowCustCurrency(void);
-
-static void GameOptionsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		int i;
-		StringID str = STR_02BE_DEFAULT;
-
-		SetWindowWidgetDisabledState(w, 21, !(_vehicle_design_names & 1));
-		if (!IsWindowWidgetDisabled(w, 21)) str = STR_02BF_CUSTOM;
-		SetDParam(0, str);
-		SetDParam(1, _currency_specs[_opt_ptr->currency].name);
-		SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
-		SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
-		SetDParam(4, STR_TOWNNAME_ORIGINAL_ENGLISH + _opt_ptr->town_name);
-		SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
-		SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
-		i = GetCurRes();
-		SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
-		SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
-		SetWindowWidgetLoweredState(w, 28, _fullscreen);
-
-		DrawWindowWidgets(w);
-		DrawString(20, 175, STR_OPTIONS_FULLSCREEN, 0); // fullscreen
-	}	break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 4: case 5: /* Setup currencies dropdown */
-			ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, 5, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);;
-			return;
-		case 7: case 8: /* Setup distance unit dropdown */
-			ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, 8, 0, 0);
-			return;
-		case 10: case 11: { /* Setup road-side dropdown */
-			int i = 0;
-
-			/* You can only change the drive side if you are in the menu or ingame with
-			 * no vehicles present. In a networking game only the server can change it */
-			if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
-				i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
-
-			ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, 11, i, 0);
-		} return;
-		case 13: case 14: { /* Setup townname dropdown */
-			int i = _opt_ptr->town_name;
-			ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, 14, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0);
-			return;
-		}
-		case 16: case 17: /* Setup autosave dropdown */
-			ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, 17, 0, 0);
-			return;
-		case 19: case 20: /* Setup customized vehicle-names dropdown */
-			ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, 20, (_vehicle_design_names & 2) ? 0 : 2, 0);
-			return;
-		case 21: /* Save customized vehicle-names to disk */
-			return;
-		case 23: case 24: /* Setup interface language dropdown */
-			ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, 24, 0, 0);
-			return;
-		case 26: case 27: /* Setup resolution dropdown */
-			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), 27, 0, 0);
-			return;
-		case 28: /* Click fullscreen on/off */
-			SetWindowWidgetLoweredState(w, 28, !_fullscreen);
-			ToggleFullScreen(!_fullscreen); // toggle full-screen on/off
-			SetWindowDirty(w);
-			return;
-		case 30: case 31: /* Setup screenshot format dropdown */
-			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, 31, 0, 0);
-			return;
-		}
-		break;
-
-	case WE_DROPDOWN_SELECT:
-		switch (e->we.dropdown.button) {
-		case 20: /* Vehicle design names */
-			if (e->we.dropdown.index == 0) {
-				DeleteCustomEngineNames();
-				MarkWholeScreenDirty();
-			} else if (!(_vehicle_design_names & 1)) {
-				LoadCustomEngineNames();
-				MarkWholeScreenDirty();
-			}
-			break;
-		case 5: /* Currency */
-			if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
-			_opt_ptr->currency = e->we.dropdown.index;
-			MarkWholeScreenDirty();
-			break;
-		case 8: /* Measuring units */
-			_opt_ptr->units = e->we.dropdown.index;
-			MarkWholeScreenDirty();
-			break;
-		case 11: /* Road side */
-			if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
-				DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
-				MarkWholeScreenDirty();
-			}
-			break;
-		case 14: /* Town names */
-			if (_game_mode == GM_MENU) {
-				_opt_ptr->town_name = e->we.dropdown.index;
-				InvalidateWindow(WC_GAME_OPTIONS, 0);
-			}
-			break;
-		case 17: /* Autosave options */
-			_opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
-			SetWindowDirty(w);
-			break;
-		case 24: /* Change interface language */
-			ReadLanguagePack(e->we.dropdown.index);
-			MarkWholeScreenDirty();
-			break;
-		case 27: /* Change resolution */
-			if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0],_resolutions[e->we.dropdown.index][1]))
-				SetWindowDirty(w);
-			break;
-		case 31: /* Change screenshot format */
-			SetScreenshotFormat(e->we.dropdown.index);
-			SetWindowDirty(w);
-			break;
-		}
-		break;
-
-	case WE_DESTROY:
-		DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
-		break;
-	}
-
-}
-
-/** Change the side of the road vehicles drive on (server only).
- * @param tile unused
- * @param p1 the side of the road; 0 = left side and 1 = right side
- * @param p2 unused
- */
-int32 CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	/* Check boundaries and you can only change this if NO vehicles have been built yet,
-	 * except in the intro-menu where of course it's always possible to do so. */
-	if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		_opt_ptr->road_side = p1;
-		InvalidateWindow(WC_GAME_OPTIONS,0);
-	}
-	return 0;
-}
-
-static const Widget _game_options_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   369,     0,    13, STR_00B1_GAME_OPTIONS,             STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   369,    14,   238, 0x0,                               STR_NULL},
-{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    20,    55, STR_02E0_CURRENCY_UNITS,           STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    34,    45, STR_02E1,                          STR_02E2_CURRENCY_UNITS_SELECTION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    35,    44, STR_0225,                          STR_02E2_CURRENCY_UNITS_SELECTION},
-{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    20,    55, STR_MEASURING_UNITS,               STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    34,    45, STR_02E4,                          STR_MEASURING_UNITS_SELECTION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    35,    44, STR_0225,                          STR_MEASURING_UNITS_SELECTION},
-{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    62,    97, STR_02E6_ROAD_VEHICLES,            STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    76,    87, STR_02E7,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    77,    86, STR_0225,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
-{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    62,    97, STR_02EB_TOWN_NAMES,               STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    76,    87, STR_02EC,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    77,    86, STR_0225,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
-{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   104,   139, STR_02F4_AUTOSAVE,                 STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   118,   129, STR_02F5,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   119,   128, STR_0225,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
-
-{      WWT_FRAME,   RESIZE_NONE,    14,    10,   359,   194,   228, STR_02BC_VEHICLE_DESIGN_NAMES,     STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,    20,   119,   207,   218, STR_02BD,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   108,   118,   208,   217, STR_0225,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   349,   207,   218, STR_02C0_SAVE_CUSTOM_NAMES,        STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
-
-{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   104,   139, STR_OPTIONS_LANG,                  STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   118,   129, STR_OPTIONS_LANG_CBO,              STR_OPTIONS_LANG_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   119,   128, STR_0225,                          STR_OPTIONS_LANG_TIP},
-
-{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   146,   190, STR_OPTIONS_RES,                   STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   160,   171, STR_OPTIONS_RES_CBO,               STR_OPTIONS_RES_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   161,   170, STR_0225,                          STR_OPTIONS_RES_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   149,   169,   176,   184, STR_EMPTY,                         STR_OPTIONS_FULLSCREEN_TIP},
-
-{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   146,   190, STR_OPTIONS_SCREENSHOT_FORMAT,     STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   160,   171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   161,   170, STR_0225,                          STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
-
-{   WIDGETS_END},
-};
-
-static const WindowDesc _game_options_desc = {
-	WDP_CENTER, WDP_CENTER, 370, 239,
-	WC_GAME_OPTIONS,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_game_options_widgets,
-	GameOptionsWndProc
-};
-
-
-void ShowGameOptions(void)
-{
-	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	AllocateWindowDesc(&_game_options_desc);
-}
-
-typedef struct {
-	int16 min;
-	int16 max;
-	int16 step;
-	StringID str;
-} GameSettingData;
-
-static const GameSettingData _game_setting_info[] = {
-	{  0,   7,  1, STR_NULL},
-	{  0,   3,  1, STR_6830_IMMEDIATE},
-	{  0,   2,  1, STR_6816_LOW},
-	{  0,   3,  1, STR_26816_NONE},
-	{100, 500, 50, STR_NULL},
-	{  2,   4,  1, STR_NULL},
-	{  0,   2,  1, STR_6820_LOW},
-	{  0,   4,  1, STR_681B_VERY_SLOW},
-	{  0,   2,  1, STR_6820_LOW},
-	{  0,   2,  1, STR_6823_NONE},
-	{  0,   3,  1, STR_6826_X1_5},
-	{  0,   2,  1, STR_6820_LOW},
-	{  0,   3,  1, STR_682A_VERY_FLAT},
-	{  0,   3,  1, STR_VERY_LOW},
-	{  0,   1,  1, STR_682E_STEADY},
-	{  0,   1,  1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS},
-	{  0,   1,  1, STR_6836_OFF},
-	{  0,   2,  1, STR_6839_PERMISSIVE},
-};
-
-static inline bool GetBitAndShift(uint32 *b)
-{
-	uint32 x = *b;
-	*b >>= 1;
-	return HASBIT(x, 0);
-}
-
-/*
- * A: competitors
- * B: start time in months / 3
- * C: town count (2 = high, 0 = low)
- * D: industry count (3 = high, 0 = none)
- * E: inital loan / 1000 (in GBP)
- * F: interest rate
- * G: running costs (0 = low, 2 = high)
- * H: construction speed of competitors (0 = very slow, 4 = very fast)
- * I: intelligence (0-2)
- * J: breakdowns (0 = off, 2 = normal)
- * K: subsidy multiplier (0 = 1.5, 3 = 4.0)
- * L: construction cost (0-2)
- * M: terrain type (0 = very flat, 3 = mountainous)
- * N: amount of water (0 = very low, 3 = high)
- * O: economy (0 = steady, 1 = fluctuating)
- * P: Train reversing (0 = end of line + stations, 1 = end of line)
- * Q: disasters
- * R: area restructuring (0 = permissive, 2 = hostile)
- */
-static const int16 _default_game_diff[3][GAME_DIFFICULTY_NUM] = { /*
-	 A, B, C, D,   E, F, G, H, I, J, K, L, M, N, O, P, Q, R*/
-	{2, 2, 1, 3, 300, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0}, //easy
-	{4, 1, 1, 2, 150, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1}, //medium
-	{7, 0, 2, 2, 100, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2}, //hard
-};
-
-void SetDifficultyLevel(int mode, GameOptions *gm_opt)
-{
-	int i;
-	assert(mode <= 3);
-
-	gm_opt->diff_level = mode;
-	if (mode != 3) { // not custom
-		for (i = 0; i != GAME_DIFFICULTY_NUM; i++)
-			((int*)&gm_opt->diff)[i] = _default_game_diff[mode][i];
-	}
-}
-
-extern void StartupEconomy(void);
-
-enum {
-	GAMEDIFF_WND_TOP_OFFSET = 45,
-	GAMEDIFF_WND_ROWSIZE    = 9
-};
-
-// Temporary holding place of values in the difficulty window until 'Save' is clicked
-static GameOptions _opt_mod_temp;
-// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
-#define DIFF_INGAME_DISABLED_BUTTONS 0x383E
-
-static void GameDifficultyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: // Setup disabled buttons when creating window
-		/* disable all other difficulty buttons during gameplay except for 'custom' */
-		SetWindowWidgetDisabledState(w,  3, _game_mode == GM_NORMAL);
-		SetWindowWidgetDisabledState(w,  4, _game_mode == GM_NORMAL);
-		SetWindowWidgetDisabledState(w,  5, _game_mode == GM_NORMAL);
-		SetWindowWidgetDisabledState(w,  6, _game_mode == GM_NORMAL);
-		SetWindowWidgetDisabledState(w,  7, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
-		SetWindowWidgetDisabledState(w, 10, _networking && !_network_server); // Save-button in multiplayer (and if client)
-
-		break;
-	case WE_PAINT: {
-		uint32 click_a, click_b, disabled;
-		int i;
-		int y, value;
-
-		DrawWindowWidgets(w);
-
-		click_a = _difficulty_click_a;
-		click_b = _difficulty_click_b;
-
-		/* XXX - Disabled buttons in normal gameplay. Bitshifted for each button to see if
-		 * that bit is set. If it is set, the button is disabled */
-		disabled = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
-
-		y = GAMEDIFF_WND_TOP_OFFSET;
-		for (i = 0; i != GAME_DIFFICULTY_NUM; i++) {
-			DrawFrameRect( 5, y,  5 + 8, y + 8, 3, GetBitAndShift(&click_a) ? FR_LOWERED : 0);
-			DrawFrameRect(15, y, 15 + 8, y + 8, 3, GetBitAndShift(&click_b) ? FR_LOWERED : 0);
-			if (GetBitAndShift(&disabled) || (_networking && !_network_server)) {
-				int color = PALETTE_MODIFIER_GREYOUT | _colour_gradient[COLOUR_YELLOW][2];
-				GfxFillRect( 6, y + 1,  6 + 8, y + 8, color);
-				GfxFillRect(16, y + 1, 16 + 8, y + 8, color);
-			}
-
-			DrawStringCentered(10, y, STR_6819, 0);
-			DrawStringCentered(20, y, STR_681A, 0);
-
-
-			value = _game_setting_info[i].str + ((int*)&_opt_mod_temp.diff)[i];
-			if (i == 4) value *= 1000; // XXX - handle currency option
-			SetDParam(0, value);
-			DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, 0);
-
-			y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
-		}
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 8: { /* Difficulty settings widget, decode click */
-			const GameSettingData *info;
-			int x, y;
-			uint btn, dis;
-			int val;
-
-			// Don't allow clients to make any changes
-			if  (_networking && !_network_server)
-				return;
-
-			x = e->we.click.pt.x - 5;
-			if (!IS_INT_INSIDE(x, 0, 21)) // Button area
-				return;
-
-			y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
-			if (y < 0)
-				return;
-
-			// Get button from Y coord.
-			btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
-			if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
-				return;
-
-			// Clicked disabled button?
-			dis = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
-
-			if (HASBIT(dis, btn))
-				return;
-
-			_difficulty_timeout = 5;
-
-			val = ((int*)&_opt_mod_temp.diff)[btn];
-
-			info = &_game_setting_info[btn]; // get information about the difficulty setting
-			if (x >= 10) {
-				// Increase button clicked
-				val = min(val + info->step, info->max);
-				SETBIT(_difficulty_click_b, btn);
-			} else {
-				// Decrease button clicked
-				val = max(val - info->step, info->min);
-				SETBIT(_difficulty_click_a, btn);
-			}
-
-			// save value in temporary variable
-			((int*)&_opt_mod_temp.diff)[btn] = val;
-			SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
-			SetWindowDirty(w);
-		}	break;
-		case 3: case 4: case 5: case 6: /* Easy / Medium / Hard / Custom */
-			// temporarily change difficulty level
-			RaiseWindowWidget(w, _opt_mod_temp.diff_level + 3);
-			SetDifficultyLevel(e->we.click.widget - 3, &_opt_mod_temp);
-			LowerWindowWidget(w, _opt_mod_temp.diff_level + 3);
-			SetWindowDirty(w);
-			break;
-		case 7: /* Highscore Table */
-			ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
-			break;
-		case 10: { /* Save button - save changes */
-			int btn, val;
-			for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
-				val = ((int*)&_opt_mod_temp.diff)[btn];
-				// if setting has changed, change it
-				if (val != ((int*)&_opt_ptr->diff)[btn])
-					DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-			}
-			DoCommandP(0, -1, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-			DeleteWindow(w);
-			// If we are in the editor, we should reload the economy.
-			//  This way when you load a game, the max loan and interest rate
-			//  are loaded correctly.
-			if (_game_mode == GM_EDITOR)
-				StartupEconomy();
-			break;
-		}
-		case 11: /* Cancel button - close window, abandon changes */
-			DeleteWindow(w);
-			break;
-	} break;
-
-	case WE_MOUSELOOP: /* Handle the visual 'clicking' of the buttons */
-		if (_difficulty_timeout != 0 && !--_difficulty_timeout) {
-			_difficulty_click_a = 0;
-			_difficulty_click_b = 0;
-			SetWindowDirty(w);
-		}
-		break;
-	}
-}
-
-#undef DIFF_INGAME_DISABLED_BUTTONS
-
-static const Widget _game_difficulty_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_6800_DIFFICULTY_LEVEL,    STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    29, 0x0,                          STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_6801_EASY,                STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_6802_MEDIUM,              STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_6803_HARD,                STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_6804_CUSTOM,              STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    10,     0,   369,    30,    41, STR_6838_SHOW_HI_SCORE_CHART, STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   262, 0x0,                          STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,   263,   278, 0x0,                          STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   105,   185,   265,   276, STR_OPTIONS_SAVE_CHANGES,     STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   186,   266,   265,   276, STR_012E_CANCEL,              STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _game_difficulty_desc = {
-	WDP_CENTER, WDP_CENTER, 370, 279,
-	WC_GAME_OPTIONS,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_game_difficulty_widgets,
-	GameDifficultyWndProc
-};
-
-void ShowGameDifficulty(void)
-{
-	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	/* Copy current settings (ingame or in intro) to temporary holding place
-	 * change that when setting stuff, copy back on clicking 'OK' */
-	_opt_mod_temp = *_opt_ptr;
-	AllocateWindowDesc(&_game_difficulty_desc);
-}
-
-static const char *_patches_ui[] = {
-	"vehicle_speed",
-	"status_long_date",
-	"show_finances",
-	"autoscroll",
-	"reverse_scroll",
-	"errmsg_duration",
-	"toolbar_pos",
-	"measure_tooltip",
-	"window_snap_radius",
-	"invisible_trees",
-	"population_in_label",
-	"link_terraform_toolbar",
-	"liveries",
-	"prefer_teamchat",
-};
-
-static const char *_patches_construction[] = {
-	"build_on_slopes",
-	"extra_dynamite",
-	"longbridges",
-	"signal_side",
-	"always_small_airport",
-	"drag_signals_density",
-	"oil_refinery_limit",
-};
-
-static const char *_patches_stations[] = {
-	"join_stations",
-	"full_load_any",
-	"improved_load",
-	"selectgoods",
-	"new_nonstop",
-	"nonuniform_stations",
-	"station_spread",
-	"serviceathelipad",
-	"modified_catchment",
-	"gradual_loading",
-};
-
-static const char *_patches_economy[] = {
-	"inflation",
-	"build_rawmaterial_ind",
-	"multiple_industry_per_town",
-	"same_industry_close",
-	"bribe",
-	"colored_news_year",
-	"ending_year",
-	"smooth_economy",
-	"allow_shares",
-};
-
-static const char *_patches_ai[] = {
-	"ainew_active",
-	"ai_in_multiplayer",
-	"ai_disable_veh_train",
-	"ai_disable_veh_roadveh",
-	"ai_disable_veh_aircraft",
-	"ai_disable_veh_ship",
-};
-
-static const char *_patches_vehicles[] = {
-	"realistic_acceleration",
-	"forbid_90_deg",
-	"mammoth_trains",
-	"gotodepot",
-	"roadveh_queue",
-	"new_pathfinding_all",
-	"yapf.ship_use_yapf",
-	"yapf.road_use_yapf",
-	"yapf.rail_use_yapf",
-	"train_income_warn",
-	"order_review_system",
-	"never_expire_vehicles",
-	"lost_train_warn",
-	"autorenew",
-	"autorenew_months",
-	"autorenew_money",
-	"max_trains",
-	"max_roadveh",
-	"max_aircraft",
-	"max_ships",
-	"servint_ispercent",
-	"servint_trains",
-	"servint_roadveh",
-	"servint_ships",
-	"servint_aircraft",
-	"no_servicing_if_no_breakdowns",
-	"wagon_speed_limits",
-	"disable_elrails",
-	"freight_trains",
-};
-
-typedef struct PatchEntry {
-	const SettingDesc *setting;
-	uint index;
-} PatchEntry;
-
-typedef struct PatchPage {
-	const char **names;
-	PatchEntry *entries;
-	byte num;
-} PatchPage;
-
-/* PatchPage holds the categories, the number of elements in each category
- * and (in NULL) a dynamic array of settings based on the string-representations
- * of the settings. This way there is no worry about indeces, and such */
-static PatchPage _patches_page[] = {
-	{_patches_ui,           NULL, lengthof(_patches_ui)},
-	{_patches_construction, NULL, lengthof(_patches_construction)},
-	{_patches_vehicles,     NULL, lengthof(_patches_vehicles)},
-	{_patches_stations,     NULL, lengthof(_patches_stations)},
-	{_patches_economy,      NULL, lengthof(_patches_economy)},
-	{_patches_ai,           NULL, lengthof(_patches_ai)},
-};
-
-/** The main patches window. Shows a number of categories on top and
- * a selection of patches in that category.
- * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
-static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
-{
-	static Patches *patches_ptr;
-
-	switch (e->event) {
-	case WE_CREATE: {
-		static bool first_time = true;
-
-		patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-
-		/* Build up the dynamic settings-array only once per OpenTTD session */
-		if (first_time) {
-			PatchPage *page;
-			for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
-				uint i;
-
-				page->entries = malloc(page->num * sizeof(*page->entries));
-				for (i = 0; i != page->num; i++) {
-					uint index;
-					const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
-					assert(sd != NULL);
-
-					page->entries[i].setting = sd;
-					page->entries[i].index = index;
-				}
-			}
-			first_time = false;
-		}
-		LowerWindowWidget(w, 4);
-	} break;
-
-	case WE_PAINT: {
-		int x, y;
-		const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
-		uint i;
-
-		/* Set up selected category */
-		DrawWindowWidgets(w);
-
-		x = 5;
-		y = 47;
-		for (i = 0; i != page->num; i++) {
-			const SettingDesc *sd = page->entries[i].setting;
-			const SettingDescBase *sdb = &sd->desc;
-			const void *var = GetVariableAddress(patches_ptr, &sd->save);
-			bool editable = true;
-			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 ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
-
-			if (sdb->cmd == SDT_BOOLX) {
-				static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
-				/* Draw checkbox for boolean-value either on/off */
-				bool on = (*(bool*)var);
-
-				DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : 0);
-				SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
-			} else {
-				int32 value;
-
-				value = (int32)ReadValue(var, sd->save.conv);
-
-				/* Draw [<][>] boxes for settings of an integer-type */
-				DrawArrowButtons(x, y, 3, WP(w,def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
-
-				disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
-				if (disabled) {
-					SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
-				} else {
-					if (sdb->flags & SGF_CURRENCY) {
-						SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
-					} else if (sdb->flags & SGF_MULTISTRING) {
-						SetDParam(0, sdb->str + value + 1);
-					} else {
-						SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
-					}
-					SetDParam(1, value);
-				}
-			}
-			DrawString(30, y, (sdb->str) + disabled, 0);
-			y += 11;
-		}
-		break;
-	}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: {
-			const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
-			const SettingDesc *sd;
-			void *var;
-			int32 value;
-			int x, y;
-			byte btn;
-
-			y = e->we.click.pt.y - 46 - 1;
-			if (y < 0) return;
-
-			x = e->we.click.pt.x - 5;
-			if (x < 0) return;
-
-			btn = y / 11;
-			if (y % 11 > 9) return;
-			if (btn >= page->num) return;
-
-			sd = page->entries[btn].setting;
-
-			/* return if action is only active in network, or only settable by server */
-			if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
-			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
-
-			var = GetVariableAddress(patches_ptr, &sd->save);
-			value = (int32)ReadValue(var, sd->save.conv);
-
-			/* clicked on the icon on the left side. Either scroller or bool on/off */
-			if (x < 21) {
-				const SettingDescBase *sdb = &sd->desc;
-				int32 oldvalue = value;
-
-				switch (sdb->cmd) {
-				case SDT_BOOLX: value ^= 1; break;
-				case SDT_NUMX: {
-					/* Add a dynamic step-size to the scroller. In a maximum of
-					 * 50-steps you should be able to get from min to max,
-					 * unless specified otherwise in the 'interval' variable
-					 * of the current patch. */
-					uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
-					if (step == 0) step = 1;
-
-					// don't allow too fast scrolling
-					if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
-						_left_button_clicked = false;
-						return;
-					}
-
-					/* Increase or decrease the value and clamp it to extremes */
-					if (x >= 10) {
-						value += step;
-						if (value > sdb->max) value = sdb->max;
-					} else {
-						value -= step;
-						if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
-					}
-
-					/* Set up scroller timeout */
-					if (value != oldvalue) {
-						WP(w,def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
-						w->flags4 |= 5 << WF_TIMEOUT_SHL;
-						_left_button_clicked = false;
-					}
-				} break;
-				default: NOT_REACHED();
-				}
-
-				if (value != oldvalue) {
-					SetPatchValue(page->entries[btn].index, patches_ptr, value);
-					SetWindowDirty(w);
-				}
-			} else {
-				/* only open editbox for types that its sensible for */
-				if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
-					/* Show the correct currency-translated value */
-					if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
-
-					WP(w,def_d).data_3 = btn;
-					SetDParam(0, value);
-					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
-				}
-			}
-
-			break;
-		}
-		case 4: case 5: case 6: case 7: case 8: case 9:
-			RaiseWindowWidget(w, WP(w, def_d).data_1 + 4);
-			WP(w, def_d).data_1 = e->we.click.widget - 4;
-			LowerWindowWidget(w, WP(w, def_d).data_1 + 4);
-			DeleteWindowById(WC_QUERY_STRING, 0);
-			SetWindowDirty(w);
-			break;
-		}
-		break;
-
-	case WE_TIMEOUT:
-		WP(w,def_d).data_2 = 0;
-		SetWindowDirty(w);
-		break;
-
-	case WE_ON_EDIT_TEXT: {
-		if (e->we.edittext.str != NULL) {
-			const PatchEntry *pe = &_patches_page[WP(w,def_d).data_1].entries[WP(w,def_d).data_3];
-			const SettingDesc *sd = pe->setting;
-			int32 value = atoi(e->we.edittext.str);
-
-			/* Save the correct currency-translated value */
-			if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
-
-			SetPatchValue(pe->index, patches_ptr, value);
-			SetWindowDirty(w);
-		}
-		break;
-	}
-
-	case WE_DESTROY:
-		DeleteWindowById(WC_QUERY_STRING, 0);
-		break;
-	}
-}
-
-static const Widget _patches_selection_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_CONFIG_PATCHES_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    41, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   370, 0x0,                             STR_NULL},
-
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_CONFIG_PATCHES_GUI,          STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_CONFIG_PATCHES_VEHICLES,     STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_CONFIG_PATCHES_STATIONS,     STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,    10,    96,    28,    39, STR_CONFIG_PATCHES_ECONOMY,      STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,     3,    97,   183,    28,    39, STR_CONFIG_PATCHES_AI,           STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _patches_selection_desc = {
-	WDP_CENTER, WDP_CENTER, 370, 371,
-	WC_GAME_OPTIONS,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_patches_selection_widgets,
-	PatchesSelectionWndProc,
-};
-
-void ShowPatchesSelection(void)
-{
-	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	AllocateWindowDesc(&_patches_selection_desc);
-}
-
-
-/**
- * Draw [<][>] boxes.
- * @param x the x position to draw
- * @param y the y position to draw
- * @param ctab the color of the buttons
- * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked
- * @param clickable_left is the left button clickable?
- * @param clickable_right is the right button clickable?
- */
-void DrawArrowButtons(int x, int y, int ctab, byte state, bool clickable_left, bool clickable_right)
-{
-	int color = PALETTE_MODIFIER_GREYOUT | _colour_gradient[COLOUR_YELLOW][2];
-
-	DrawFrameRect(x,      y + 1, x +  9, y + 9, ctab, (state == 1) ? FR_LOWERED : 0);
-	DrawFrameRect(x + 10, y + 1, x + 19, y + 9, ctab, (state == 2) ? FR_LOWERED : 0);
-	DrawStringCentered(x +  5, y + 1, STR_6819, 0); // [<]
-	DrawStringCentered(x + 15, y + 1, STR_681A, 0); // [>]
-
-	/* Grey out the buttons that aren't clickable */
-	if (!clickable_left)
-		GfxFillRect(x +  1, y + 1, x +  1 + 8, y + 8, color);
-	if (!clickable_right)
-		GfxFillRect(x + 11, y + 1, x + 11 + 8, y + 8, color);
-}
-
-static char _str_separator[2];
-
-static void CustCurrencyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			int x;
-			int y = 20;
-			int clk = WP(w,def_d).data_1;
-			DrawWindowWidgets(w);
-
-			// exchange rate
-			DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
-			SetDParam(0, 1);
-			SetDParam(1, 1);
-			DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, 0);
-			y += 12;
-
-			// separator
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : 0);
-			x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, 0);
-			DoDrawString(_str_separator, x + 4, y + 1, 6);
-			y += 12;
-
-			// prefix
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : 0);
-			x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, 0);
-			DoDrawString(_custom_currency.prefix, x + 4, y + 1, 6);
-			y += 12;
-
-			// suffix
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : 0);
-			x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, 0);
-			DoDrawString(_custom_currency.suffix, x + 4, y + 1, 6);
-			y += 12;
-
-			// switch to euro
-			DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
-			SetDParam(0, _custom_currency.to_euro);
-			DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, 0);
-			y += 12;
-
-			// Preview
-			y += 12;
-			SetDParam(0, 10000);
-			DrawString(35, y + 1, STR_CURRENCY_PREVIEW, 0);
-			break;
-		}
-
-		case WE_CLICK: {
-			int line = (e->we.click.pt.y - 20) / 12;
-			int len = 0;
-			int x = e->we.click.pt.x;
-			StringID str = 0;
-			CharSetFilter afilter = CS_ALPHANUMERAL;
-
-			switch (line) {
-				case 0: // rate
-					if (IS_INT_INSIDE(x, 10, 30)) { // clicked buttons
-						if (x < 20) {
-							if (_custom_currency.rate > 1) _custom_currency.rate--;
-							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
-						} else {
-							if (_custom_currency.rate < 5000) _custom_currency.rate++;
-							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
-						}
-					} else { // enter text
-						SetDParam(0, _custom_currency.rate);
-						str = STR_CONFIG_PATCHES_INT32;
-						len = 4;
-						afilter = CS_NUMERAL;
-					}
-					break;
-
-				case 1: // separator
-					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
-						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
-					}
-					str = BindCString(_str_separator);
-					len = 1;
-					break;
-
-				case 2: // prefix
-					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
-						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
-					}
-					str = BindCString(_custom_currency.prefix);
-					len = 12;
-					break;
-
-				case 3: // suffix
-					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
-						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
-					}
-					str = BindCString(_custom_currency.suffix);
-					len = 12;
-					break;
-
-				case 4: // to euro
-					if (IS_INT_INSIDE(x, 10, 30)) { // clicked buttons
-						if (x < 20) {
-							_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
-								CF_NOEURO : _custom_currency.to_euro - 1;
-							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
-						} else {
-							_custom_currency.to_euro =
-								clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
-							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
-						}
-					} else { // enter text
-						SetDParam(0, _custom_currency.to_euro);
-						str = STR_CONFIG_PATCHES_INT32;
-						len = 4;
-						afilter = CS_NUMERAL;
-					}
-					break;
-			}
-
-			if (len != 0) {
-				WP(w, def_d).data_2 = line;
-				ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
-			}
-
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-			SetWindowDirty(w);
-			break;
-		}
-
-		case WE_ON_EDIT_TEXT: {
-				const char *b = e->we.edittext.str;
-
-				switch (WP(w,def_d).data_2) {
-					case 0: /* Exchange rate */
-						_custom_currency.rate = clamp(atoi(b), 1, 5000);
-						break;
-
-					case 1: /* Thousands seperator */
-						_custom_currency.separator = (b[0] == '\0') ? ' ' : b[0];
-						ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
-						break;
-
-					case 2: /* Currency prefix */
-						ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
-						break;
-
-					case 3: /* Currency suffix */
-						ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
-						break;
-
-					case 4: { /* Year to switch to euro */
-						int val = atoi(b);
-
-						_custom_currency.to_euro =
-							(val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
-						break;
-					}
-				}
-			MarkWholeScreenDirty();
-			break;
-		}
-
-		case WE_TIMEOUT:
-			WP(w,def_d).data_1 = 0;
-			SetWindowDirty(w);
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_QUERY_STRING, 0);
-			MarkWholeScreenDirty();
-			break;
-	}
-}
-
-static const Widget _cust_currency_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   229,     0,    13, STR_CURRENCY_WINDOW, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   229,    14,   119, 0x0,                 STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _cust_currency_desc = {
-	WDP_CENTER, WDP_CENTER, 230, 120,
-	WC_CUSTOM_CURRENCY, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_cust_currency_widgets,
-	CustCurrencyWndProc,
-};
-
-static void ShowCustCurrency(void)
-{
-	_str_separator[0] = _custom_currency.separator;
-	_str_separator[1] = '\0';
-
-	DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
-	AllocateWindowDesc(&_cust_currency_desc);
-}
new file mode 100644
--- /dev/null
+++ b/src/settings_gui.cpp
@@ -0,0 +1,1140 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "functions.h"
+#include "string.h"
+#include "strings.h" // XXX GetCurrentCurrencyRate()
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "command.h"
+#include "engine.h"
+#include "screenshot.h"
+#include "newgrf.h"
+#include "network/network.h"
+#include "town.h"
+#include "variables.h"
+#include "settings.h"
+#include "vehicle.h"
+#include "date.h"
+
+static uint32 _difficulty_click_a;
+static uint32 _difficulty_click_b;
+static byte _difficulty_timeout;
+
+static const StringID _units_dropdown[] = {
+	STR_UNITS_IMPERIAL,
+	STR_UNITS_METRIC,
+	STR_UNITS_SI,
+	INVALID_STRING_ID
+};
+
+static const StringID _driveside_dropdown[] = {
+	STR_02E9_DRIVE_ON_LEFT,
+	STR_02EA_DRIVE_ON_RIGHT,
+	INVALID_STRING_ID
+};
+
+static const StringID _autosave_dropdown[] = {
+	STR_02F7_OFF,
+	STR_AUTOSAVE_1_MONTH,
+	STR_02F8_EVERY_3_MONTHS,
+	STR_02F9_EVERY_6_MONTHS,
+	STR_02FA_EVERY_12_MONTHS,
+	INVALID_STRING_ID,
+};
+
+static const StringID _designnames_dropdown[] = {
+	STR_02BE_DEFAULT,
+	STR_02BF_CUSTOM,
+	INVALID_STRING_ID
+};
+
+static StringID *BuildDynamicDropdown(StringID base, int num)
+{
+	static StringID buf[32 + 1];
+	StringID *p = buf;
+	while (--num>=0) *p++ = base++;
+	*p = INVALID_STRING_ID;
+	return buf;
+}
+
+static int GetCurRes(void)
+{
+	int i;
+
+	for (i = 0; i != _num_resolutions; i++) {
+		if (_resolutions[i][0] == _screen.width &&
+				_resolutions[i][1] == _screen.height) {
+			break;
+		}
+	}
+	return i;
+}
+
+static inline bool RoadVehiclesAreBuilt(void)
+{
+	const Vehicle* v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Road) return true;
+	}
+	return false;
+}
+
+
+static void ShowCustCurrency(void);
+
+static void GameOptionsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		int i;
+		StringID str = STR_02BE_DEFAULT;
+
+		SetWindowWidgetDisabledState(w, 21, !(_vehicle_design_names & 1));
+		if (!IsWindowWidgetDisabled(w, 21)) str = STR_02BF_CUSTOM;
+		SetDParam(0, str);
+		SetDParam(1, _currency_specs[_opt_ptr->currency].name);
+		SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
+		SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
+		SetDParam(4, STR_TOWNNAME_ORIGINAL_ENGLISH + _opt_ptr->town_name);
+		SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
+		SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
+		i = GetCurRes();
+		SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
+		SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
+		SetWindowWidgetLoweredState(w, 28, _fullscreen);
+
+		DrawWindowWidgets(w);
+		DrawString(20, 175, STR_OPTIONS_FULLSCREEN, 0); // fullscreen
+	}	break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 4: case 5: /* Setup currencies dropdown */
+			ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, 5, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);;
+			return;
+		case 7: case 8: /* Setup distance unit dropdown */
+			ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, 8, 0, 0);
+			return;
+		case 10: case 11: { /* Setup road-side dropdown */
+			int i = 0;
+
+			/* You can only change the drive side if you are in the menu or ingame with
+			 * no vehicles present. In a networking game only the server can change it */
+			if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
+				i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
+
+			ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, 11, i, 0);
+		} return;
+		case 13: case 14: { /* Setup townname dropdown */
+			int i = _opt_ptr->town_name;
+			ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, 14, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0);
+			return;
+		}
+		case 16: case 17: /* Setup autosave dropdown */
+			ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, 17, 0, 0);
+			return;
+		case 19: case 20: /* Setup customized vehicle-names dropdown */
+			ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, 20, (_vehicle_design_names & 2) ? 0 : 2, 0);
+			return;
+		case 21: /* Save customized vehicle-names to disk */
+			return;
+		case 23: case 24: /* Setup interface language dropdown */
+			ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, 24, 0, 0);
+			return;
+		case 26: case 27: /* Setup resolution dropdown */
+			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), 27, 0, 0);
+			return;
+		case 28: /* Click fullscreen on/off */
+			SetWindowWidgetLoweredState(w, 28, !_fullscreen);
+			ToggleFullScreen(!_fullscreen); // toggle full-screen on/off
+			SetWindowDirty(w);
+			return;
+		case 30: case 31: /* Setup screenshot format dropdown */
+			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, 31, 0, 0);
+			return;
+		}
+		break;
+
+	case WE_DROPDOWN_SELECT:
+		switch (e->we.dropdown.button) {
+		case 20: /* Vehicle design names */
+			if (e->we.dropdown.index == 0) {
+				DeleteCustomEngineNames();
+				MarkWholeScreenDirty();
+			} else if (!(_vehicle_design_names & 1)) {
+				LoadCustomEngineNames();
+				MarkWholeScreenDirty();
+			}
+			break;
+		case 5: /* Currency */
+			if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
+			_opt_ptr->currency = e->we.dropdown.index;
+			MarkWholeScreenDirty();
+			break;
+		case 8: /* Measuring units */
+			_opt_ptr->units = e->we.dropdown.index;
+			MarkWholeScreenDirty();
+			break;
+		case 11: /* Road side */
+			if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
+				DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+				MarkWholeScreenDirty();
+			}
+			break;
+		case 14: /* Town names */
+			if (_game_mode == GM_MENU) {
+				_opt_ptr->town_name = e->we.dropdown.index;
+				InvalidateWindow(WC_GAME_OPTIONS, 0);
+			}
+			break;
+		case 17: /* Autosave options */
+			_opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
+			SetWindowDirty(w);
+			break;
+		case 24: /* Change interface language */
+			ReadLanguagePack(e->we.dropdown.index);
+			MarkWholeScreenDirty();
+			break;
+		case 27: /* Change resolution */
+			if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0],_resolutions[e->we.dropdown.index][1]))
+				SetWindowDirty(w);
+			break;
+		case 31: /* Change screenshot format */
+			SetScreenshotFormat(e->we.dropdown.index);
+			SetWindowDirty(w);
+			break;
+		}
+		break;
+
+	case WE_DESTROY:
+		DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
+		break;
+	}
+
+}
+
+/** Change the side of the road vehicles drive on (server only).
+ * @param tile unused
+ * @param p1 the side of the road; 0 = left side and 1 = right side
+ * @param p2 unused
+ */
+int32 CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	/* Check boundaries and you can only change this if NO vehicles have been built yet,
+	 * except in the intro-menu where of course it's always possible to do so. */
+	if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		_opt_ptr->road_side = p1;
+		InvalidateWindow(WC_GAME_OPTIONS,0);
+	}
+	return 0;
+}
+
+static const Widget _game_options_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   369,     0,    13, STR_00B1_GAME_OPTIONS,             STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   369,    14,   238, 0x0,                               STR_NULL},
+{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    20,    55, STR_02E0_CURRENCY_UNITS,           STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    34,    45, STR_02E1,                          STR_02E2_CURRENCY_UNITS_SELECTION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    35,    44, STR_0225,                          STR_02E2_CURRENCY_UNITS_SELECTION},
+{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    20,    55, STR_MEASURING_UNITS,               STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    34,    45, STR_02E4,                          STR_MEASURING_UNITS_SELECTION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    35,    44, STR_0225,                          STR_MEASURING_UNITS_SELECTION},
+{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    62,    97, STR_02E6_ROAD_VEHICLES,            STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    76,    87, STR_02E7,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    77,    86, STR_0225,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
+{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    62,    97, STR_02EB_TOWN_NAMES,               STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    76,    87, STR_02EC,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    77,    86, STR_0225,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
+{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   104,   139, STR_02F4_AUTOSAVE,                 STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   118,   129, STR_02F5,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   119,   128, STR_0225,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
+
+{      WWT_FRAME,   RESIZE_NONE,    14,    10,   359,   194,   228, STR_02BC_VEHICLE_DESIGN_NAMES,     STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,    20,   119,   207,   218, STR_02BD,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   108,   118,   208,   217, STR_0225,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   349,   207,   218, STR_02C0_SAVE_CUSTOM_NAMES,        STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
+
+{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   104,   139, STR_OPTIONS_LANG,                  STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   118,   129, STR_OPTIONS_LANG_CBO,              STR_OPTIONS_LANG_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   119,   128, STR_0225,                          STR_OPTIONS_LANG_TIP},
+
+{      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   146,   190, STR_OPTIONS_RES,                   STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   160,   171, STR_OPTIONS_RES_CBO,               STR_OPTIONS_RES_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   161,   170, STR_0225,                          STR_OPTIONS_RES_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   149,   169,   176,   184, STR_EMPTY,                         STR_OPTIONS_FULLSCREEN_TIP},
+
+{      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   146,   190, STR_OPTIONS_SCREENSHOT_FORMAT,     STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   160,   171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   161,   170, STR_0225,                          STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
+
+{   WIDGETS_END},
+};
+
+static const WindowDesc _game_options_desc = {
+	WDP_CENTER, WDP_CENTER, 370, 239,
+	WC_GAME_OPTIONS,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_game_options_widgets,
+	GameOptionsWndProc
+};
+
+
+void ShowGameOptions(void)
+{
+	DeleteWindowById(WC_GAME_OPTIONS, 0);
+	AllocateWindowDesc(&_game_options_desc);
+}
+
+typedef struct {
+	int16 min;
+	int16 max;
+	int16 step;
+	StringID str;
+} GameSettingData;
+
+static const GameSettingData _game_setting_info[] = {
+	{  0,   7,  1, STR_NULL},
+	{  0,   3,  1, STR_6830_IMMEDIATE},
+	{  0,   2,  1, STR_6816_LOW},
+	{  0,   3,  1, STR_26816_NONE},
+	{100, 500, 50, STR_NULL},
+	{  2,   4,  1, STR_NULL},
+	{  0,   2,  1, STR_6820_LOW},
+	{  0,   4,  1, STR_681B_VERY_SLOW},
+	{  0,   2,  1, STR_6820_LOW},
+	{  0,   2,  1, STR_6823_NONE},
+	{  0,   3,  1, STR_6826_X1_5},
+	{  0,   2,  1, STR_6820_LOW},
+	{  0,   3,  1, STR_682A_VERY_FLAT},
+	{  0,   3,  1, STR_VERY_LOW},
+	{  0,   1,  1, STR_682E_STEADY},
+	{  0,   1,  1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS},
+	{  0,   1,  1, STR_6836_OFF},
+	{  0,   2,  1, STR_6839_PERMISSIVE},
+};
+
+static inline bool GetBitAndShift(uint32 *b)
+{
+	uint32 x = *b;
+	*b >>= 1;
+	return HASBIT(x, 0);
+}
+
+/*
+ * A: competitors
+ * B: start time in months / 3
+ * C: town count (2 = high, 0 = low)
+ * D: industry count (3 = high, 0 = none)
+ * E: inital loan / 1000 (in GBP)
+ * F: interest rate
+ * G: running costs (0 = low, 2 = high)
+ * H: construction speed of competitors (0 = very slow, 4 = very fast)
+ * I: intelligence (0-2)
+ * J: breakdowns (0 = off, 2 = normal)
+ * K: subsidy multiplier (0 = 1.5, 3 = 4.0)
+ * L: construction cost (0-2)
+ * M: terrain type (0 = very flat, 3 = mountainous)
+ * N: amount of water (0 = very low, 3 = high)
+ * O: economy (0 = steady, 1 = fluctuating)
+ * P: Train reversing (0 = end of line + stations, 1 = end of line)
+ * Q: disasters
+ * R: area restructuring (0 = permissive, 2 = hostile)
+ */
+static const int16 _default_game_diff[3][GAME_DIFFICULTY_NUM] = { /*
+	 A, B, C, D,   E, F, G, H, I, J, K, L, M, N, O, P, Q, R*/
+	{2, 2, 1, 3, 300, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0}, //easy
+	{4, 1, 1, 2, 150, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1}, //medium
+	{7, 0, 2, 2, 100, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2}, //hard
+};
+
+void SetDifficultyLevel(int mode, GameOptions *gm_opt)
+{
+	int i;
+	assert(mode <= 3);
+
+	gm_opt->diff_level = mode;
+	if (mode != 3) { // not custom
+		for (i = 0; i != GAME_DIFFICULTY_NUM; i++)
+			((int*)&gm_opt->diff)[i] = _default_game_diff[mode][i];
+	}
+}
+
+extern void StartupEconomy(void);
+
+enum {
+	GAMEDIFF_WND_TOP_OFFSET = 45,
+	GAMEDIFF_WND_ROWSIZE    = 9
+};
+
+// Temporary holding place of values in the difficulty window until 'Save' is clicked
+static GameOptions _opt_mod_temp;
+// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
+#define DIFF_INGAME_DISABLED_BUTTONS 0x383E
+
+static void GameDifficultyWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: // Setup disabled buttons when creating window
+		/* disable all other difficulty buttons during gameplay except for 'custom' */
+		SetWindowWidgetDisabledState(w,  3, _game_mode == GM_NORMAL);
+		SetWindowWidgetDisabledState(w,  4, _game_mode == GM_NORMAL);
+		SetWindowWidgetDisabledState(w,  5, _game_mode == GM_NORMAL);
+		SetWindowWidgetDisabledState(w,  6, _game_mode == GM_NORMAL);
+		SetWindowWidgetDisabledState(w,  7, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
+		SetWindowWidgetDisabledState(w, 10, _networking && !_network_server); // Save-button in multiplayer (and if client)
+
+		break;
+	case WE_PAINT: {
+		uint32 click_a, click_b, disabled;
+		int i;
+		int y, value;
+
+		DrawWindowWidgets(w);
+
+		click_a = _difficulty_click_a;
+		click_b = _difficulty_click_b;
+
+		/* XXX - Disabled buttons in normal gameplay. Bitshifted for each button to see if
+		 * that bit is set. If it is set, the button is disabled */
+		disabled = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
+
+		y = GAMEDIFF_WND_TOP_OFFSET;
+		for (i = 0; i != GAME_DIFFICULTY_NUM; i++) {
+			DrawFrameRect( 5, y,  5 + 8, y + 8, 3, GetBitAndShift(&click_a) ? FR_LOWERED : 0);
+			DrawFrameRect(15, y, 15 + 8, y + 8, 3, GetBitAndShift(&click_b) ? FR_LOWERED : 0);
+			if (GetBitAndShift(&disabled) || (_networking && !_network_server)) {
+				int color = PALETTE_MODIFIER_GREYOUT | _colour_gradient[COLOUR_YELLOW][2];
+				GfxFillRect( 6, y + 1,  6 + 8, y + 8, color);
+				GfxFillRect(16, y + 1, 16 + 8, y + 8, color);
+			}
+
+			DrawStringCentered(10, y, STR_6819, 0);
+			DrawStringCentered(20, y, STR_681A, 0);
+
+
+			value = _game_setting_info[i].str + ((int*)&_opt_mod_temp.diff)[i];
+			if (i == 4) value *= 1000; // XXX - handle currency option
+			SetDParam(0, value);
+			DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, 0);
+
+			y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
+		}
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 8: { /* Difficulty settings widget, decode click */
+			const GameSettingData *info;
+			int x, y;
+			uint btn, dis;
+			int val;
+
+			// Don't allow clients to make any changes
+			if  (_networking && !_network_server)
+				return;
+
+			x = e->we.click.pt.x - 5;
+			if (!IS_INT_INSIDE(x, 0, 21)) // Button area
+				return;
+
+			y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
+			if (y < 0)
+				return;
+
+			// Get button from Y coord.
+			btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
+			if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
+				return;
+
+			// Clicked disabled button?
+			dis = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
+
+			if (HASBIT(dis, btn))
+				return;
+
+			_difficulty_timeout = 5;
+
+			val = ((int*)&_opt_mod_temp.diff)[btn];
+
+			info = &_game_setting_info[btn]; // get information about the difficulty setting
+			if (x >= 10) {
+				// Increase button clicked
+				val = min(val + info->step, info->max);
+				SETBIT(_difficulty_click_b, btn);
+			} else {
+				// Decrease button clicked
+				val = max(val - info->step, info->min);
+				SETBIT(_difficulty_click_a, btn);
+			}
+
+			// save value in temporary variable
+			((int*)&_opt_mod_temp.diff)[btn] = val;
+			SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
+			SetWindowDirty(w);
+		}	break;
+		case 3: case 4: case 5: case 6: /* Easy / Medium / Hard / Custom */
+			// temporarily change difficulty level
+			RaiseWindowWidget(w, _opt_mod_temp.diff_level + 3);
+			SetDifficultyLevel(e->we.click.widget - 3, &_opt_mod_temp);
+			LowerWindowWidget(w, _opt_mod_temp.diff_level + 3);
+			SetWindowDirty(w);
+			break;
+		case 7: /* Highscore Table */
+			ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
+			break;
+		case 10: { /* Save button - save changes */
+			int btn, val;
+			for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
+				val = ((int*)&_opt_mod_temp.diff)[btn];
+				// if setting has changed, change it
+				if (val != ((int*)&_opt_ptr->diff)[btn])
+					DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+			}
+			DoCommandP(0, -1, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+			DeleteWindow(w);
+			// If we are in the editor, we should reload the economy.
+			//  This way when you load a game, the max loan and interest rate
+			//  are loaded correctly.
+			if (_game_mode == GM_EDITOR)
+				StartupEconomy();
+			break;
+		}
+		case 11: /* Cancel button - close window, abandon changes */
+			DeleteWindow(w);
+			break;
+	} break;
+
+	case WE_MOUSELOOP: /* Handle the visual 'clicking' of the buttons */
+		if (_difficulty_timeout != 0 && !--_difficulty_timeout) {
+			_difficulty_click_a = 0;
+			_difficulty_click_b = 0;
+			SetWindowDirty(w);
+		}
+		break;
+	}
+}
+
+#undef DIFF_INGAME_DISABLED_BUTTONS
+
+static const Widget _game_difficulty_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_6800_DIFFICULTY_LEVEL,    STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    29, 0x0,                          STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_6801_EASY,                STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_6802_MEDIUM,              STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_6803_HARD,                STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_6804_CUSTOM,              STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    10,     0,   369,    30,    41, STR_6838_SHOW_HI_SCORE_CHART, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   262, 0x0,                          STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,   263,   278, 0x0,                          STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   105,   185,   265,   276, STR_OPTIONS_SAVE_CHANGES,     STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   186,   266,   265,   276, STR_012E_CANCEL,              STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _game_difficulty_desc = {
+	WDP_CENTER, WDP_CENTER, 370, 279,
+	WC_GAME_OPTIONS,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_game_difficulty_widgets,
+	GameDifficultyWndProc
+};
+
+void ShowGameDifficulty(void)
+{
+	DeleteWindowById(WC_GAME_OPTIONS, 0);
+	/* Copy current settings (ingame or in intro) to temporary holding place
+	 * change that when setting stuff, copy back on clicking 'OK' */
+	_opt_mod_temp = *_opt_ptr;
+	AllocateWindowDesc(&_game_difficulty_desc);
+}
+
+static const char *_patches_ui[] = {
+	"vehicle_speed",
+	"status_long_date",
+	"show_finances",
+	"autoscroll",
+	"reverse_scroll",
+	"errmsg_duration",
+	"toolbar_pos",
+	"measure_tooltip",
+	"window_snap_radius",
+	"invisible_trees",
+	"population_in_label",
+	"link_terraform_toolbar",
+	"liveries",
+	"prefer_teamchat",
+};
+
+static const char *_patches_construction[] = {
+	"build_on_slopes",
+	"extra_dynamite",
+	"longbridges",
+	"signal_side",
+	"always_small_airport",
+	"drag_signals_density",
+	"oil_refinery_limit",
+};
+
+static const char *_patches_stations[] = {
+	"join_stations",
+	"full_load_any",
+	"improved_load",
+	"selectgoods",
+	"new_nonstop",
+	"nonuniform_stations",
+	"station_spread",
+	"serviceathelipad",
+	"modified_catchment",
+	"gradual_loading",
+};
+
+static const char *_patches_economy[] = {
+	"inflation",
+	"build_rawmaterial_ind",
+	"multiple_industry_per_town",
+	"same_industry_close",
+	"bribe",
+	"colored_news_year",
+	"ending_year",
+	"smooth_economy",
+	"allow_shares",
+};
+
+static const char *_patches_ai[] = {
+	"ainew_active",
+	"ai_in_multiplayer",
+	"ai_disable_veh_train",
+	"ai_disable_veh_roadveh",
+	"ai_disable_veh_aircraft",
+	"ai_disable_veh_ship",
+};
+
+static const char *_patches_vehicles[] = {
+	"realistic_acceleration",
+	"forbid_90_deg",
+	"mammoth_trains",
+	"gotodepot",
+	"roadveh_queue",
+	"new_pathfinding_all",
+	"yapf.ship_use_yapf",
+	"yapf.road_use_yapf",
+	"yapf.rail_use_yapf",
+	"train_income_warn",
+	"order_review_system",
+	"never_expire_vehicles",
+	"lost_train_warn",
+	"autorenew",
+	"autorenew_months",
+	"autorenew_money",
+	"max_trains",
+	"max_roadveh",
+	"max_aircraft",
+	"max_ships",
+	"servint_ispercent",
+	"servint_trains",
+	"servint_roadveh",
+	"servint_ships",
+	"servint_aircraft",
+	"no_servicing_if_no_breakdowns",
+	"wagon_speed_limits",
+	"disable_elrails",
+	"freight_trains",
+};
+
+typedef struct PatchEntry {
+	const SettingDesc *setting;
+	uint index;
+} PatchEntry;
+
+typedef struct PatchPage {
+	const char **names;
+	PatchEntry *entries;
+	byte num;
+} PatchPage;
+
+/* PatchPage holds the categories, the number of elements in each category
+ * and (in NULL) a dynamic array of settings based on the string-representations
+ * of the settings. This way there is no worry about indeces, and such */
+static PatchPage _patches_page[] = {
+	{_patches_ui,           NULL, lengthof(_patches_ui)},
+	{_patches_construction, NULL, lengthof(_patches_construction)},
+	{_patches_vehicles,     NULL, lengthof(_patches_vehicles)},
+	{_patches_stations,     NULL, lengthof(_patches_stations)},
+	{_patches_economy,      NULL, lengthof(_patches_economy)},
+	{_patches_ai,           NULL, lengthof(_patches_ai)},
+};
+
+/** The main patches window. Shows a number of categories on top and
+ * a selection of patches in that category.
+ * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
+static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
+{
+	static Patches *patches_ptr;
+
+	switch (e->event) {
+	case WE_CREATE: {
+		static bool first_time = true;
+
+		patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
+
+		/* Build up the dynamic settings-array only once per OpenTTD session */
+		if (first_time) {
+			PatchPage *page;
+			for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
+				uint i;
+
+				page->entries = malloc(page->num * sizeof(*page->entries));
+				for (i = 0; i != page->num; i++) {
+					uint index;
+					const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
+					assert(sd != NULL);
+
+					page->entries[i].setting = sd;
+					page->entries[i].index = index;
+				}
+			}
+			first_time = false;
+		}
+		LowerWindowWidget(w, 4);
+	} break;
+
+	case WE_PAINT: {
+		int x, y;
+		const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
+		uint i;
+
+		/* Set up selected category */
+		DrawWindowWidgets(w);
+
+		x = 5;
+		y = 47;
+		for (i = 0; i != page->num; i++) {
+			const SettingDesc *sd = page->entries[i].setting;
+			const SettingDescBase *sdb = &sd->desc;
+			const void *var = GetVariableAddress(patches_ptr, &sd->save);
+			bool editable = true;
+			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 ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
+
+			if (sdb->cmd == SDT_BOOLX) {
+				static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
+				/* Draw checkbox for boolean-value either on/off */
+				bool on = (*(bool*)var);
+
+				DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : 0);
+				SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+			} else {
+				int32 value;
+
+				value = (int32)ReadValue(var, sd->save.conv);
+
+				/* Draw [<][>] boxes for settings of an integer-type */
+				DrawArrowButtons(x, y, 3, WP(w,def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
+
+				disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
+				if (disabled) {
+					SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
+				} else {
+					if (sdb->flags & SGF_CURRENCY) {
+						SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
+					} else if (sdb->flags & SGF_MULTISTRING) {
+						SetDParam(0, sdb->str + value + 1);
+					} else {
+						SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
+					}
+					SetDParam(1, value);
+				}
+			}
+			DrawString(30, y, (sdb->str) + disabled, 0);
+			y += 11;
+		}
+		break;
+	}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: {
+			const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
+			const SettingDesc *sd;
+			void *var;
+			int32 value;
+			int x, y;
+			byte btn;
+
+			y = e->we.click.pt.y - 46 - 1;
+			if (y < 0) return;
+
+			x = e->we.click.pt.x - 5;
+			if (x < 0) return;
+
+			btn = y / 11;
+			if (y % 11 > 9) return;
+			if (btn >= page->num) return;
+
+			sd = page->entries[btn].setting;
+
+			/* return if action is only active in network, or only settable by server */
+			if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
+			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
+
+			var = GetVariableAddress(patches_ptr, &sd->save);
+			value = (int32)ReadValue(var, sd->save.conv);
+
+			/* clicked on the icon on the left side. Either scroller or bool on/off */
+			if (x < 21) {
+				const SettingDescBase *sdb = &sd->desc;
+				int32 oldvalue = value;
+
+				switch (sdb->cmd) {
+				case SDT_BOOLX: value ^= 1; break;
+				case SDT_NUMX: {
+					/* Add a dynamic step-size to the scroller. In a maximum of
+					 * 50-steps you should be able to get from min to max,
+					 * unless specified otherwise in the 'interval' variable
+					 * of the current patch. */
+					uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
+					if (step == 0) step = 1;
+
+					// don't allow too fast scrolling
+					if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
+						_left_button_clicked = false;
+						return;
+					}
+
+					/* Increase or decrease the value and clamp it to extremes */
+					if (x >= 10) {
+						value += step;
+						if (value > sdb->max) value = sdb->max;
+					} else {
+						value -= step;
+						if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
+					}
+
+					/* Set up scroller timeout */
+					if (value != oldvalue) {
+						WP(w,def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
+						w->flags4 |= 5 << WF_TIMEOUT_SHL;
+						_left_button_clicked = false;
+					}
+				} break;
+				default: NOT_REACHED();
+				}
+
+				if (value != oldvalue) {
+					SetPatchValue(page->entries[btn].index, patches_ptr, value);
+					SetWindowDirty(w);
+				}
+			} else {
+				/* only open editbox for types that its sensible for */
+				if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
+					/* Show the correct currency-translated value */
+					if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
+
+					WP(w,def_d).data_3 = btn;
+					SetDParam(0, value);
+					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
+				}
+			}
+
+			break;
+		}
+		case 4: case 5: case 6: case 7: case 8: case 9:
+			RaiseWindowWidget(w, WP(w, def_d).data_1 + 4);
+			WP(w, def_d).data_1 = e->we.click.widget - 4;
+			LowerWindowWidget(w, WP(w, def_d).data_1 + 4);
+			DeleteWindowById(WC_QUERY_STRING, 0);
+			SetWindowDirty(w);
+			break;
+		}
+		break;
+
+	case WE_TIMEOUT:
+		WP(w,def_d).data_2 = 0;
+		SetWindowDirty(w);
+		break;
+
+	case WE_ON_EDIT_TEXT: {
+		if (e->we.edittext.str != NULL) {
+			const PatchEntry *pe = &_patches_page[WP(w,def_d).data_1].entries[WP(w,def_d).data_3];
+			const SettingDesc *sd = pe->setting;
+			int32 value = atoi(e->we.edittext.str);
+
+			/* Save the correct currency-translated value */
+			if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
+
+			SetPatchValue(pe->index, patches_ptr, value);
+			SetWindowDirty(w);
+		}
+		break;
+	}
+
+	case WE_DESTROY:
+		DeleteWindowById(WC_QUERY_STRING, 0);
+		break;
+	}
+}
+
+static const Widget _patches_selection_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_CONFIG_PATCHES_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    41, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   370, 0x0,                             STR_NULL},
+
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_CONFIG_PATCHES_GUI,          STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_CONFIG_PATCHES_VEHICLES,     STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_CONFIG_PATCHES_STATIONS,     STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,    10,    96,    28,    39, STR_CONFIG_PATCHES_ECONOMY,      STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,     3,    97,   183,    28,    39, STR_CONFIG_PATCHES_AI,           STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _patches_selection_desc = {
+	WDP_CENTER, WDP_CENTER, 370, 371,
+	WC_GAME_OPTIONS,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_patches_selection_widgets,
+	PatchesSelectionWndProc,
+};
+
+void ShowPatchesSelection(void)
+{
+	DeleteWindowById(WC_GAME_OPTIONS, 0);
+	AllocateWindowDesc(&_patches_selection_desc);
+}
+
+
+/**
+ * Draw [<][>] boxes.
+ * @param x the x position to draw
+ * @param y the y position to draw
+ * @param ctab the color of the buttons
+ * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked
+ * @param clickable_left is the left button clickable?
+ * @param clickable_right is the right button clickable?
+ */
+void DrawArrowButtons(int x, int y, int ctab, byte state, bool clickable_left, bool clickable_right)
+{
+	int color = PALETTE_MODIFIER_GREYOUT | _colour_gradient[COLOUR_YELLOW][2];
+
+	DrawFrameRect(x,      y + 1, x +  9, y + 9, ctab, (state == 1) ? FR_LOWERED : 0);
+	DrawFrameRect(x + 10, y + 1, x + 19, y + 9, ctab, (state == 2) ? FR_LOWERED : 0);
+	DrawStringCentered(x +  5, y + 1, STR_6819, 0); // [<]
+	DrawStringCentered(x + 15, y + 1, STR_681A, 0); // [>]
+
+	/* Grey out the buttons that aren't clickable */
+	if (!clickable_left)
+		GfxFillRect(x +  1, y + 1, x +  1 + 8, y + 8, color);
+	if (!clickable_right)
+		GfxFillRect(x + 11, y + 1, x + 11 + 8, y + 8, color);
+}
+
+static char _str_separator[2];
+
+static void CustCurrencyWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			int x;
+			int y = 20;
+			int clk = WP(w,def_d).data_1;
+			DrawWindowWidgets(w);
+
+			// exchange rate
+			DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
+			SetDParam(0, 1);
+			SetDParam(1, 1);
+			DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, 0);
+			y += 12;
+
+			// separator
+			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : 0);
+			x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, 0);
+			DoDrawString(_str_separator, x + 4, y + 1, 6);
+			y += 12;
+
+			// prefix
+			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : 0);
+			x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, 0);
+			DoDrawString(_custom_currency.prefix, x + 4, y + 1, 6);
+			y += 12;
+
+			// suffix
+			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : 0);
+			x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, 0);
+			DoDrawString(_custom_currency.suffix, x + 4, y + 1, 6);
+			y += 12;
+
+			// switch to euro
+			DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
+			SetDParam(0, _custom_currency.to_euro);
+			DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, 0);
+			y += 12;
+
+			// Preview
+			y += 12;
+			SetDParam(0, 10000);
+			DrawString(35, y + 1, STR_CURRENCY_PREVIEW, 0);
+			break;
+		}
+
+		case WE_CLICK: {
+			int line = (e->we.click.pt.y - 20) / 12;
+			int len = 0;
+			int x = e->we.click.pt.x;
+			StringID str = 0;
+			CharSetFilter afilter = CS_ALPHANUMERAL;
+
+			switch (line) {
+				case 0: // rate
+					if (IS_INT_INSIDE(x, 10, 30)) { // clicked buttons
+						if (x < 20) {
+							if (_custom_currency.rate > 1) _custom_currency.rate--;
+							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
+						} else {
+							if (_custom_currency.rate < 5000) _custom_currency.rate++;
+							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
+						}
+					} else { // enter text
+						SetDParam(0, _custom_currency.rate);
+						str = STR_CONFIG_PATCHES_INT32;
+						len = 4;
+						afilter = CS_NUMERAL;
+					}
+					break;
+
+				case 1: // separator
+					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
+						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
+					}
+					str = BindCString(_str_separator);
+					len = 1;
+					break;
+
+				case 2: // prefix
+					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
+						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
+					}
+					str = BindCString(_custom_currency.prefix);
+					len = 12;
+					break;
+
+				case 3: // suffix
+					if (IS_INT_INSIDE(x, 10, 30)) { // clicked button
+						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
+					}
+					str = BindCString(_custom_currency.suffix);
+					len = 12;
+					break;
+
+				case 4: // to euro
+					if (IS_INT_INSIDE(x, 10, 30)) { // clicked buttons
+						if (x < 20) {
+							_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
+								CF_NOEURO : _custom_currency.to_euro - 1;
+							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
+						} else {
+							_custom_currency.to_euro =
+								clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
+							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
+						}
+					} else { // enter text
+						SetDParam(0, _custom_currency.to_euro);
+						str = STR_CONFIG_PATCHES_INT32;
+						len = 4;
+						afilter = CS_NUMERAL;
+					}
+					break;
+			}
+
+			if (len != 0) {
+				WP(w, def_d).data_2 = line;
+				ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
+			}
+
+			w->flags4 |= 5 << WF_TIMEOUT_SHL;
+			SetWindowDirty(w);
+			break;
+		}
+
+		case WE_ON_EDIT_TEXT: {
+				const char *b = e->we.edittext.str;
+
+				switch (WP(w,def_d).data_2) {
+					case 0: /* Exchange rate */
+						_custom_currency.rate = clamp(atoi(b), 1, 5000);
+						break;
+
+					case 1: /* Thousands seperator */
+						_custom_currency.separator = (b[0] == '\0') ? ' ' : b[0];
+						ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
+						break;
+
+					case 2: /* Currency prefix */
+						ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
+						break;
+
+					case 3: /* Currency suffix */
+						ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
+						break;
+
+					case 4: { /* Year to switch to euro */
+						int val = atoi(b);
+
+						_custom_currency.to_euro =
+							(val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
+						break;
+					}
+				}
+			MarkWholeScreenDirty();
+			break;
+		}
+
+		case WE_TIMEOUT:
+			WP(w,def_d).data_1 = 0;
+			SetWindowDirty(w);
+			break;
+
+		case WE_DESTROY:
+			DeleteWindowById(WC_QUERY_STRING, 0);
+			MarkWholeScreenDirty();
+			break;
+	}
+}
+
+static const Widget _cust_currency_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   229,     0,    13, STR_CURRENCY_WINDOW, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   229,    14,   119, 0x0,                 STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _cust_currency_desc = {
+	WDP_CENTER, WDP_CENTER, 230, 120,
+	WC_CUSTOM_CURRENCY, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_cust_currency_widgets,
+	CustCurrencyWndProc,
+};
+
+static void ShowCustCurrency(void)
+{
+	_str_separator[0] = _custom_currency.separator;
+	_str_separator[1] = '\0';
+
+	DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
+	AllocateWindowDesc(&_cust_currency_desc);
+}
deleted file mode 100644
--- a/src/ship_cmd.c
+++ /dev/null
@@ -1,1110 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "ship.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
-#include "command.h"
-#include "pathfind.h"
-#include "station_map.h"
-#include "station.h"
-#include "news.h"
-#include "engine.h"
-#include "player.h"
-#include "sound.h"
-#include "npf.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "newgrf_engine.h"
-#include "water_map.h"
-#include "yapf/yapf.h"
-#include "debug.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_text.h"
-#include "newgrf_sound.h"
-#include "date.h"
-
-static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D};
-static const byte _ship_sometracks[4] = {0x19, 0x16, 0x25, 0x2A};
-
-static byte GetTileShipTrackStatus(TileIndex tile)
-{
-	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
-	return r | r >> 8;
-}
-
-void DrawShipEngine(int x, int y, EngineID engine, uint32 image_ormod)
-{
-	int spritenum = ShipVehInfo(engine)->image_index;
-
-	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleIcon(engine, DIR_W);
-
-		if (sprite != 0) {
-			DrawSprite(sprite | image_ormod, x, y);
-			return;
-		}
-		spritenum = orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index;
-	}
-	DrawSprite((6 + _ship_sprites[spritenum]) | image_ormod, x, y);
-}
-
-int GetShipImage(const Vehicle* v, Direction direction)
-{
-	int spritenum = v->spritenum;
-
-	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleSprite(v, direction);
-
-		if (sprite != 0) return sprite;
-		spritenum = orig_ship_vehicle_info[v->engine_type - SHIP_ENGINES_INDEX].image_index;
-	}
-	return _ship_sprites[spritenum] + direction;
-}
-
-static const Depot* FindClosestShipDepot(const Vehicle* v)
-{
-	const Depot* depot;
-	const Depot* best_depot = NULL;
-	uint dist;
-	uint best_dist = (uint)-1;
-	TileIndex tile;
-	TileIndex tile2 = v->tile;
-
-	if (_patches.new_pathfinding_all) {
-		NPFFoundTargetData ftd;
-		byte trackdir = GetVehicleTrackdir(v);
-		ftd = NPFRouteToDepotTrialError(v->tile, trackdir, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
-		if (ftd.best_bird_dist == 0) {
-			best_depot = GetDepotByTile(ftd.node.tile); /* Found target */
-		} else {
-			best_depot = NULL; /* Did not find target */
-		}
-	} else {
-		FOR_ALL_DEPOTS(depot) {
-			tile = depot->xy;
-			if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) {
-				dist = DistanceManhattan(tile, tile2);
-				if (dist < best_dist) {
-					best_dist = dist;
-					best_depot = depot;
-				}
-			}
-		}
-	}
-	return best_depot;
-}
-
-static void CheckIfShipNeedsService(Vehicle *v)
-{
-	const Depot* depot;
-
-	if (_patches.servint_ships == 0) return;
-	if (!VehicleNeedsService(v))     return;
-	if (v->vehstatus & VS_STOPPED)   return;
-
-	if (v->current_order.type == OT_GOTO_DEPOT &&
-			v->current_order.flags & OF_HALT_IN_DEPOT)
-		return;
-
-	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
-
-	if (IsShipInDepot(v)) {
-		VehicleServiceInDepot(v);
-		return;
-	}
-
-	depot = FindClosestShipDepot(v);
-
-	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
-		if (v->current_order.type == OT_GOTO_DEPOT) {
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return;
-	}
-
-	v->current_order.type = OT_GOTO_DEPOT;
-	v->current_order.flags = OF_NON_STOP;
-	v->current_order.dest = depot->index;
-	v->dest_tile = depot->xy;
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-}
-
-void OnNewDay_Ship(Vehicle *v)
-{
-	int32 cost;
-
-	if ((++v->day_counter & 7) == 0)
-		DecreaseVehicleValue(v);
-
-	CheckVehicleBreakdown(v);
-	AgeVehicle(v);
-	CheckIfShipNeedsService(v);
-
-	CheckOrders(v);
-
-	if (v->vehstatus & VS_STOPPED) return;
-
-	cost = ShipVehInfo(v->engine_type)->running_cost * _price.ship_running / 364;
-	v->profit_this_year -= cost >> 8;
-
-	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
-	SubtractMoneyFromPlayerFract(v->owner, cost);
-
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-	//we need this for the profit
-	InvalidateWindowClasses(WC_SHIPS_LIST);
-}
-
-static void HandleBrokenShip(Vehicle *v)
-{
-	if (v->breakdown_ctr != 1) {
-		v->breakdown_ctr = 1;
-		v->cur_speed = 0;
-
-		if (v->breakdowns_since_last_service != 255)
-			v->breakdowns_since_last_service++;
-
-		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
-			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
-				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
-		}
-
-		if (!(v->vehstatus & VS_HIDDEN)) {
-			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
-		}
-	}
-
-	if (!(v->tick_counter & 1)) {
-		if (!--v->breakdown_delay) {
-			v->breakdown_ctr = 0;
-			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		}
-	}
-}
-
-static void MarkShipDirty(Vehicle *v)
-{
-	v->cur_image = GetShipImage(v, v->direction);
-	MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
-}
-
-static void PlayShipSound(Vehicle *v)
-{
-	if (!PlayVehicleSound(v, VSE_START)) {
-		SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v);
-	}
-}
-
-static void ProcessShipOrder(Vehicle *v)
-{
-	const Order *order;
-
-	switch (v->current_order.type) {
-		case OT_GOTO_DEPOT:
-			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return;
-			if (v->current_order.flags & OF_SERVICE_IF_NEEDED &&
-					!VehicleNeedsService(v)) {
-				v->cur_order_index++;
-			}
-			break;
-
-		case OT_LOADING:
-		case OT_LEAVESTATION:
-			return;
-
-		default: break;
-	}
-
-	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
-
-	order = GetVehicleOrder(v, v->cur_order_index);
-
-	if (order == NULL) {
-		v->current_order.type  = OT_NOTHING;
-		v->current_order.flags = 0;
-		v->dest_tile = 0;
-		return;
-	}
-
-	if (order->type  == v->current_order.type &&
-			order->flags == v->current_order.flags &&
-			order->dest  == v->current_order.dest)
-		return;
-
-	v->current_order = *order;
-
-	if (order->type == OT_GOTO_STATION) {
-		const Station *st;
-
-		if (order->dest == v->last_station_visited)
-			v->last_station_visited = INVALID_STATION;
-
-		st = GetStation(order->dest);
-		if (st->dock_tile != 0) {
-			v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
-		}
-	} else if (order->type == OT_GOTO_DEPOT) {
-		v->dest_tile = GetDepot(order->dest)->xy;
-	} else {
-		v->dest_tile = 0;
-	}
-
-	InvalidateVehicleOrder(v);
-
-	InvalidateWindowClasses(WC_SHIPS_LIST);
-}
-
-static void HandleShipLoading(Vehicle *v)
-{
-	if (v->current_order.type == OT_NOTHING) return;
-
-	if (v->current_order.type != OT_DUMMY) {
-		if (v->current_order.type != OT_LOADING) return;
-		if (--v->load_unload_time_rem) return;
-
-		if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
-				(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
-			SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
-			if (LoadUnloadVehicle(v, false)) {
-				InvalidateWindow(WC_SHIPS_LIST, v->owner);
-				MarkShipDirty(v);
-			}
-			return;
-		}
-		PlayShipSound(v);
-
-		{
-			Order b = v->current_order;
-			v->current_order.type = OT_LEAVESTATION;
-			v->current_order.flags = 0;
-			if (!(b.flags & OF_NON_STOP)) return;
-		}
-	}
-
-	v->cur_order_index++;
-	InvalidateVehicleOrder(v);
-}
-
-static void UpdateShipDeltaXY(Vehicle *v, int dir)
-{
-#define MKIT(d,c,b,a) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
-	static const uint32 _delta_xy_table[8] = {
-		MKIT( -3,  -3,  6,  6),
-		MKIT(-16,  -3, 32,  6),
-		MKIT( -3,  -3,  6,  6),
-		MKIT( -3, -16,  6, 32),
-		MKIT( -3,  -3,  6,  6),
-		MKIT(-16,  -3, 32,  6),
-		MKIT( -3,  -3,  6,  6),
-		MKIT( -3, -16,  6, 32),
-	};
-#undef MKIT
-	uint32 x = _delta_xy_table[dir];
-	v->x_offs        = GB(x,  0, 8);
-	v->y_offs        = GB(x,  8, 8);
-	v->sprite_width  = GB(x, 16, 8);
-	v->sprite_height = GB(x, 24, 8);
-}
-
-void RecalcShipStuff(Vehicle *v)
-{
-	UpdateShipDeltaXY(v, v->direction);
-	v->cur_image = GetShipImage(v, v->direction);
-	MarkShipDirty(v);
-	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-}
-
-static const TileIndexDiffC _ship_leave_depot_offs[] = {
-	{-1,  0},
-	{ 0, -1}
-};
-
-static void CheckShipLeaveDepot(Vehicle *v)
-{
-	TileIndex tile;
-	Axis axis;
-	uint m;
-
-	if (!IsShipInDepot(v)) return;
-
-	tile = v->tile;
-	axis = GetShipDepotAxis(tile);
-
-	// Check first side
-	if (_ship_sometracks[axis] & GetTileShipTrackStatus(TILE_ADD(tile, ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
-		m = (axis == AXIS_X) ? 0x101 : 0x207;
-	// Check second side
-	} else if (_ship_sometracks[axis + 2] & GetTileShipTrackStatus(TILE_ADD(tile, -2 * ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
-		m = (axis == AXIS_X) ? 0x105 : 0x203;
-	} else {
-		return;
-	}
-	v->direction    = GB(m, 0, 8);
-	v->u.ship.state = GB(m, 8, 8);
-	v->vehstatus &= ~VS_HIDDEN;
-
-	v->cur_speed = 0;
-	RecalcShipStuff(v);
-
-	PlayShipSound(v);
-	VehicleServiceInDepot(v);
-	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-	InvalidateWindowClasses(WC_SHIPS_LIST);
-}
-
-static bool ShipAccelerate(Vehicle *v)
-{
-	uint spd;
-	byte t;
-
-	spd = min(v->cur_speed + 1, v->max_speed);
-
-	//updates statusbar only if speed have changed to save CPU time
-	if (spd != v->cur_speed) {
-		v->cur_speed = spd;
-		if (_patches.vehicle_speed)
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-
-	// Decrease somewhat when turning
-	if (!(v->direction & 1)) spd = spd * 3 / 4;
-
-	if (spd == 0) return false;
-	if ((byte)++spd == 0) return true;
-
-	v->progress = (t = v->progress) - (byte)spd;
-
-	return (t < v->progress);
-}
-
-static int32 EstimateShipCost(EngineID engine_type)
-{
-	return ShipVehInfo(engine_type)->base_cost * (_price.ship_base>>3)>>5;
-}
-
-static void ShipArrivesAt(const Vehicle* v, Station* st)
-{
-	/* Check if station was ever visited before */
-	if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
-		uint32 flags;
-
-		st->had_vehicle_of_type |= HVOT_SHIP;
-
-		SetDParam(0, st->index);
-		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
-		AddNewsItem(
-			STR_9833_CITIZENS_CELEBRATE_FIRST,
-			flags,
-			v->index,
-			0);
-	}
-}
-
-typedef struct {
-	TileIndex skiptile;
-	TileIndex dest_coords;
-	uint best_bird_dist;
-	uint best_length;
-} PathFindShip;
-
-static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length, byte *state)
-{
-	// Found dest?
-	if (tile == pfs->dest_coords) {
-		pfs->best_bird_dist = 0;
-
-		pfs->best_length = minu(pfs->best_length, length);
-		return true;
-	}
-
-	// Skip this tile in the calculation
-	if (tile != pfs->skiptile) {
-		pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
-	}
-
-	return false;
-}
-
-static const byte _ship_search_directions[6][4] = {
-	{ 0, 9, 2, 9 },
-	{ 9, 1, 9, 3 },
-	{ 9, 0, 3, 9 },
-	{ 1, 9, 9, 2 },
-	{ 3, 2, 9, 9 },
-	{ 9, 9, 1, 0 },
-};
-
-static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0};
-
-static uint FindShipTrack(Vehicle *v, TileIndex tile, int dir, uint bits, TileIndex skiptile, int *track)
-{
-	PathFindShip pfs;
-	int i, best_track;
-	uint best_bird_dist = 0;
-	uint best_length    = 0;
-	uint r;
-	byte ship_dir = v->direction & 3;
-
-	pfs.dest_coords = v->dest_tile;
-	pfs.skiptile = skiptile;
-
-	best_track = -1;
-
-	do {
-		i = FIND_FIRST_BIT(bits);
-		bits = KILL_FIRST_BIT(bits);
-
-		pfs.best_bird_dist = (uint)-1;
-		pfs.best_length = (uint)-1;
-
-		FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs);
-
-		if (best_track >= 0) {
-			if (pfs.best_bird_dist != 0) {
-				/* neither reached the destination, pick the one with the smallest bird dist */
-				if (pfs.best_bird_dist > best_bird_dist) goto bad;
-				if (pfs.best_bird_dist < best_bird_dist) goto good;
-			} else {
-				if (pfs.best_length > best_length) goto bad;
-				if (pfs.best_length < best_length) goto good;
-			}
-
-			/* if we reach this position, there's two paths of equal value so far.
-			 * pick one randomly. */
-			r = GB(Random(), 0, 8);
-			if (_pick_shiptrack_table[i] == ship_dir) r += 80;
-			if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
-			if (r <= 127) goto bad;
-		}
-good:;
-		best_track = i;
-		best_bird_dist = pfs.best_bird_dist;
-		best_length = pfs.best_length;
-bad:;
-
-	} while (bits != 0);
-
-	*track = best_track;
-	return best_bird_dist;
-}
-
-static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
-{
-
-	void* perf = NpfBeginInterval();
-	NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, owner, railtypes);
-	int t = NpfEndInterval(perf);
-	DEBUG(yapf, 4, "[NPFW] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
-	return ret;
-}
-
-/* returns the track to choose on the next tile, or -1 when it's better to
- * reverse. The tile given is the tile we are about to enter, enterdir is the
- * direction in which we are entering the tile */
-static int ChooseShipTrack(Vehicle *v, TileIndex tile, int enterdir, uint tracks)
-{
-	assert(enterdir>=0 && enterdir<=3);
-
-	if (_patches.yapf.ship_use_yapf) {
-		Trackdir trackdir = YapfChooseShipTrack(v, tile, enterdir, tracks);
-		return (trackdir != INVALID_TRACKDIR) ? (int)TrackdirToTrack(trackdir) : -1;
-	} else if (_patches.new_pathfinding_all) {
-		NPFFindStationOrTileData fstd;
-		NPFFoundTargetData ftd;
-		TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
-		byte trackdir = GetVehicleTrackdir(v);
-		assert (trackdir != 0xFF); /* Check that we are not in a depot */
-
-		NPFFillWithOrderData(&fstd, v);
-
-		ftd = PerfNPFRouteToStationOrTile(src_tile, trackdir, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
-
-		if (ftd.best_trackdir != 0xff) {
-			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
-			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
-			we did not find our target, but ftd.best_trackdir contains the direction leading
-			to the tile closest to our target. */
-			return ftd.best_trackdir & 7; /* TODO: Wrapper function? */
-		} else {
-			return -1; /* Already at target, reverse? */
-		}
-	} else {
-		uint b;
-		uint tot_dist, dist;
-		int track;
-		TileIndex tile2;
-
-		tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
-		tot_dist = (uint)-1;
-
-		/* Let's find out how far it would be if we would reverse first */
-		b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagDir(enterdir)] & v->u.ship.state;
-		if (b != 0) {
-			dist = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
-			if (dist != (uint)-1)
-				tot_dist = dist + 1;
-		}
-		/* And if we would not reverse? */
-		dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
-		if (dist > tot_dist)
-			/* We could better reverse */
-			return -1;
-		return track;
-	}
-}
-
-static const Direction _new_vehicle_direction_table[] = {
-	DIR_N , DIR_NW, DIR_W , 0,
-	DIR_NE, DIR_N , DIR_SW, 0,
-	DIR_E , DIR_SE, DIR_S
-};
-
-static int ShipGetNewDirectionFromTiles(TileIndex new_tile, TileIndex old_tile)
-{
-	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
-							TileX(new_tile) - TileX(old_tile) + 1;
-	assert(offs < 11 && offs != 3 && offs != 7);
-	return _new_vehicle_direction_table[offs];
-}
-
-static int ShipGetNewDirection(Vehicle *v, int x, int y)
-{
-	uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1);
-	assert(offs < 11 && offs != 3 && offs != 7);
-	return _new_vehicle_direction_table[offs];
-}
-
-static int GetAvailShipTracks(TileIndex tile, int dir)
-{
-	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
-	return (byte) ((r | r >> 8)) & _ship_sometracks[dir];
-}
-
-static const byte _ship_subcoord[4][6][3] = {
-	{
-		{15, 8, 1},
-		{ 0, 0, 0},
-		{ 0, 0, 0},
-		{15, 8, 2},
-		{15, 7, 0},
-		{ 0, 0, 0},
-	},
-	{
-		{ 0, 0, 0},
-		{ 8, 0, 3},
-		{ 7, 0, 2},
-		{ 0, 0, 0},
-		{ 8, 0, 4},
-		{ 0, 0, 0},
-	},
-	{
-		{ 0, 8, 5},
-		{ 0, 0, 0},
-		{ 0, 7, 6},
-		{ 0, 0, 0},
-		{ 0, 0, 0},
-		{ 0, 8, 4},
-	},
-	{
-		{ 0, 0, 0},
-		{ 8,15, 7},
-		{ 0, 0, 0},
-		{ 8,15, 6},
-		{ 0, 0, 0},
-		{ 7,15, 0},
-	}
-};
-
-static void ShipController(Vehicle *v)
-{
-	GetNewVehiclePosResult gp;
-	uint32 r;
-	const byte *b;
-	Direction dir;
-	int track;
-	int tracks;
-
-	v->tick_counter++;
-
-	if (v->breakdown_ctr != 0) {
-		if (v->breakdown_ctr <= 2) {
-			HandleBrokenShip(v);
-			return;
-		}
-		v->breakdown_ctr--;
-	}
-
-	if (v->vehstatus & VS_STOPPED) return;
-
-	ProcessShipOrder(v);
-	HandleShipLoading(v);
-
-	if (v->current_order.type == OT_LOADING) return;
-
-	CheckShipLeaveDepot(v);
-
-	if (!ShipAccelerate(v)) return;
-
-	BeginVehicleMove(v);
-
-	if (GetNewVehiclePos(v, &gp)) {
-		// staying in tile
-		if (IsShipInDepot(v)) {
-			gp.x = v->x_pos;
-			gp.y = v->y_pos;
-		} else {
-			/* isnot inside depot */
-			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-			if (r & 0x8) goto reverse_direction;
-
-			/* A leave station order only needs one tick to get processed, so we can
-			 * always skip ahead. */
-			if (v->current_order.type == OT_LEAVESTATION) {
-				v->current_order.type = OT_NOTHING;
-				v->current_order.flags = 0;
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-			} else if (v->dest_tile != 0) {
-				/* We have a target, let's see if we reached it... */
-				if (v->current_order.type == OT_GOTO_STATION &&
-						IsBuoyTile(v->dest_tile) &&
-						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
-					/* We got within 3 tiles of our target buoy, so let's skip to our
-					 * next order */
-					v->cur_order_index++;
-					v->current_order.type = OT_DUMMY;
-					InvalidateVehicleOrder(v);
-				} else {
-					/* Non-buoy orders really need to reach the tile */
-					if (v->dest_tile == gp.new_tile) {
-						if (v->current_order.type == OT_GOTO_DEPOT) {
-							if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
-								VehicleEnterDepot(v);
-								return;
-							}
-						} else if (v->current_order.type == OT_GOTO_STATION) {
-							Station *st;
-
-							v->last_station_visited = v->current_order.dest;
-
-							/* Process station in the orderlist. */
-							st = GetStation(v->current_order.dest);
-							if (st->facilities & FACIL_DOCK) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
-								v->current_order.type = OT_LOADING;
-								v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
-								v->current_order.flags |= OF_NON_STOP;
-								ShipArrivesAt(v, st);
-
-								SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
-								if (LoadUnloadVehicle(v, true)) {
-									InvalidateWindow(WC_SHIPS_LIST, v->owner);
-									MarkShipDirty(v);
-								}
-								InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-							} else { /* leave stations without docks right aways */
-								v->current_order.type = OT_LEAVESTATION;
-								v->current_order.flags = 0;
-								v->cur_order_index++;
-								InvalidateVehicleOrder(v);
-							}
-						}
-					}
-				}
-			}
-		}
-	} else {
-		DiagDirection diagdir;
-		// new tile
-		if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY())
-			goto reverse_direction;
-
-		dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
-		assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
-		diagdir = DirToDiagDir(dir);
-		tracks = GetAvailShipTracks(gp.new_tile, diagdir);
-		if (tracks == 0)
-			goto reverse_direction;
-
-		// Choose a direction, and continue if we find one
-		track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
-		if (track < 0)
-			goto reverse_direction;
-
-		b = _ship_subcoord[diagdir][track];
-
-		gp.x = (gp.x&~0xF) | b[0];
-		gp.y = (gp.y&~0xF) | b[1];
-
-		/* Call the landscape function and tell it that the vehicle entered the tile */
-		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-		if (r&0x8) goto reverse_direction;
-
-		if (!(r&0x4)) {
-			v->tile = gp.new_tile;
-			v->u.ship.state = 1 << track;
-		}
-
-		v->direction = b[2];
-	}
-
-	/* update image of ship, as well as delta XY */
-	dir = ShipGetNewDirection(v, gp.x, gp.y);
-	v->x_pos = gp.x;
-	v->y_pos = gp.y;
-	v->z_pos = GetSlopeZ(gp.x, gp.y);
-
-getout:
-	UpdateShipDeltaXY(v, dir);
-	v->cur_image = GetShipImage(v, dir);
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-	return;
-
-reverse_direction:
-	dir = ReverseDir(v->direction);
-	v->direction = dir;
-	goto getout;
-}
-
-static void AgeShipCargo(Vehicle *v)
-{
-	if (_age_cargo_skip_counter != 0) return;
-	if (v->cargo_days != 255) v->cargo_days++;
-}
-
-void Ship_Tick(Vehicle *v)
-{
-	AgeShipCargo(v);
-	ShipController(v);
-}
-
-
-void ShipsYearlyLoop(void)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Ship) {
-			v->profit_last_year = v->profit_this_year;
-			v->profit_this_year = 0;
-			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		}
-	}
-}
-
-/** Build a ship.
- * @param tile tile of depot where ship is built
- * @param p1 ship type being built (engine)
- * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number
- */
-int32 CmdBuildShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 value;
-	Vehicle *v;
-	UnitID unit_num;
-	Engine *e;
-
-	if (!IsEngineBuildable(p1, VEH_Ship, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	value = EstimateShipCost(p1);
-	if (flags & DC_QUERY_COST) return value;
-
-	/* The ai_new queries the vehicle cost before building the route,
-	 * so we must check against cheaters no sooner than now. --pasky */
-	if (!IsTileDepotType(tile, TRANSPORT_WATER)) return CMD_ERROR;
-	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
-
-	v = AllocateVehicle();
-	unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Ship);
-
-	if (v == NULL || IsOrderPoolFull() || unit_num > _patches.max_ships)
-		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-	if (flags & DC_EXEC) {
-		int x;
-		int y;
-
-		const ShipVehicleInfo *svi = ShipVehInfo(p1);
-
-		v->unitnumber = unit_num;
-
-		v->owner = _current_player;
-		v->tile = tile;
-		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
-		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
-		v->x_pos = x;
-		v->y_pos = y;
-		v->z_pos = GetSlopeZ(x,y);
-
-		v->z_height = 6;
-		v->sprite_width = 6;
-		v->sprite_height = 6;
-		v->x_offs = -3;
-		v->y_offs = -3;
-		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
-
-		v->spritenum = svi->image_index;
-		v->cargo_type = svi->cargo_type;
-		v->cargo_subtype = 0;
-		v->cargo_cap = svi->capacity;
-		v->value = value;
-
-		v->last_station_visited = INVALID_STATION;
-		v->max_speed = svi->max_speed;
-		v->engine_type = p1;
-
-		e = GetEngine(p1);
-		v->reliability = e->reliability;
-		v->reliability_spd_dec = e->reliability_spd_dec;
-		v->max_age = e->lifelength * 366;
-		_new_vehicle_id = v->index;
-
-		v->string_id = STR_SV_SHIP_NAME;
-		v->u.ship.state = 0x80;
-
-		v->service_interval = _patches.servint_ships;
-		v->date_of_last_service = _date;
-		v->build_year = _cur_year;
-		v->cur_image = 0x0E5E;
-		v->type = VEH_Ship;
-		v->random_bits = VehicleRandomBits();
-
-		VehiclePositionChanged(v);
-		GetPlayer(_current_player)->num_engines[p1]++;
-
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-		InvalidateWindow(WC_COMPANY, v->owner);
-		if (IsLocalPlayer())
-			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
-	}
-
-	return value;
-}
-
-/** Sell a ship.
- * @param tile unused
- * @param p1 vehicle ID to be sold
- * @param p2 unused
- */
-int32 CmdSellShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	if (!IsShipInDepotStopped(v)) {
-		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
-	}
-
-	if (flags & DC_EXEC) {
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-		InvalidateWindow(WC_COMPANY, v->owner);
-		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-		DeleteDepotHighlightOfVehicle(v);
-		DeleteVehicle(v);
-		if (IsLocalPlayer())
-			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
-	}
-
-	return -(int32)v->value;
-}
-
-/** Start/Stop a ship.
- * @param tile unused
- * @param p1 ship ID to start/stop
- * @param p2 unused
- */
-int32 CmdStartStopShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	uint16 callback;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* Check if this ship can be started/stopped. The callback will fail or
-	 * return 0xFF if it can. */
-	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
-		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
-		return_cmd_error(error);
-	}
-
-	if (flags & DC_EXEC) {
-		if (IsShipInDepotStopped(v)) {
-			DeleteVehicleNews(p1, STR_981C_SHIP_IS_WAITING_IN_DEPOT);
-		}
-
-		v->vehstatus ^= VS_STOPPED;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		InvalidateWindowClasses(WC_SHIPS_LIST);
-	}
-
-	return 0;
-}
-
-/** Send a ship to the depot.
- * @param tile unused
- * @param p1 vehicle ID to send to the depot
- * @param p2 various bitmasked elements
- * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
- * - p2 bit 8-10 - VLW flag (for mass goto depot)
- */
-int32 CmdSendShipToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	const Depot *dep;
-
-	if (p2 & DEPOT_MASS_SEND) {
-		/* Mass goto depot requested */
-		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
-		return SendAllVehiclesToDepot(VEH_Ship, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
-	}
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
-
-	if (IsShipInDepot(v)) return CMD_ERROR;
-
-	/* If the current orders are already goto-depot */
-	if (v->current_order.type == OT_GOTO_DEPOT) {
-		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
-			/* We called with a different DEPOT_SERVICE setting.
-			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
-			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
-			if (flags & DC_EXEC) {
-				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-			}
-			return 0;
-		}
-
-		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
-		if (flags & DC_EXEC) {
-			/* If the orders to 'goto depot' are in the orders list (forced servicing),
-			 * then skip to the next order; effectively cancelling this forced service */
-			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS))
-				v->cur_order_index++;
-
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return 0;
-	}
-
-	dep = FindClosestShipDepot(v);
-	if (dep == NULL) return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT);
-
-	if (flags & DC_EXEC) {
-		v->dest_tile = dep->xy;
-		v->current_order.type = OT_GOTO_DEPOT;
-		v->current_order.flags = OF_NON_STOP;
-		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-		v->current_order.refit_cargo = CT_INVALID;
-		v->current_order.dest = dep->index;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-
-	return 0;
-}
-
-
-/** Refits a ship to the specified cargo type.
- * @param tile unused
- * @param p1 vehicle ID of the ship to refit
- * @param p2 various bitstuffed elements
- * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
- * - p2 = (bit 8-15) - the new cargo subtype to refit to
- */
-int32 CmdRefitShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	int32 cost;
-	CargoID new_cid = GB(p2, 0, 8); //gets the cargo number
-	byte new_subtype = GB(p2, 8, 8);
-	uint16 capacity = CALLBACK_FAILED;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (!IsShipInDepotStopped(v)) {
-		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
-	}
-
-	/* Check cargo */
-	if (!ShipVehInfo(v->engine_type)->refittable) return CMD_ERROR;
-	if (new_cid > NUM_CARGO || !CanRefitTo(v->engine_type, new_cid)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
-
-	/* Check the refit capacity callback */
-	if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
-		/* Back up the existing cargo type */
-		CargoID temp_cid = v->cargo_type;
-		byte temp_subtype = v->cargo_subtype;
-		v->cargo_type = new_cid;
-		v->cargo_subtype = new_subtype;
-
-		capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
-
-		/* Restore the cargo type */
-		v->cargo_type = temp_cid;
-		v->cargo_subtype = temp_subtype;
-	}
-
-	if (capacity == CALLBACK_FAILED) {
-		capacity = ShipVehInfo(v->engine_type)->capacity;
-	}
-	_returned_refit_capacity = capacity;
-
-	cost = 0;
-	if (IsHumanPlayer(v->owner) && new_cid != v->cargo_type) {
-		cost = GetRefitCost(v->engine_type);
-	}
-
-	if (flags & DC_EXEC) {
-		v->cargo_cap = capacity;
-		v->cargo_count = (v->cargo_type == new_cid) ? min(v->cargo_cap, v->cargo_count) : 0;
-		v->cargo_type = new_cid;
-		v->cargo_subtype = new_subtype;
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
-	}
-
-	return cost;
-
-}
new file mode 100644
--- /dev/null
+++ b/src/ship_cmd.cpp
@@ -0,0 +1,1110 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "ship.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "vehicle.h"
+#include "command.h"
+#include "pathfind.h"
+#include "station_map.h"
+#include "station.h"
+#include "news.h"
+#include "engine.h"
+#include "player.h"
+#include "sound.h"
+#include "npf.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "newgrf_engine.h"
+#include "water_map.h"
+#include "yapf/yapf.h"
+#include "debug.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_text.h"
+#include "newgrf_sound.h"
+#include "date.h"
+
+static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D};
+static const byte _ship_sometracks[4] = {0x19, 0x16, 0x25, 0x2A};
+
+static byte GetTileShipTrackStatus(TileIndex tile)
+{
+	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
+	return r | r >> 8;
+}
+
+void DrawShipEngine(int x, int y, EngineID engine, uint32 image_ormod)
+{
+	int spritenum = ShipVehInfo(engine)->image_index;
+
+	if (is_custom_sprite(spritenum)) {
+		int sprite = GetCustomVehicleIcon(engine, DIR_W);
+
+		if (sprite != 0) {
+			DrawSprite(sprite | image_ormod, x, y);
+			return;
+		}
+		spritenum = orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index;
+	}
+	DrawSprite((6 + _ship_sprites[spritenum]) | image_ormod, x, y);
+}
+
+int GetShipImage(const Vehicle* v, Direction direction)
+{
+	int spritenum = v->spritenum;
+
+	if (is_custom_sprite(spritenum)) {
+		int sprite = GetCustomVehicleSprite(v, direction);
+
+		if (sprite != 0) return sprite;
+		spritenum = orig_ship_vehicle_info[v->engine_type - SHIP_ENGINES_INDEX].image_index;
+	}
+	return _ship_sprites[spritenum] + direction;
+}
+
+static const Depot* FindClosestShipDepot(const Vehicle* v)
+{
+	const Depot* depot;
+	const Depot* best_depot = NULL;
+	uint dist;
+	uint best_dist = (uint)-1;
+	TileIndex tile;
+	TileIndex tile2 = v->tile;
+
+	if (_patches.new_pathfinding_all) {
+		NPFFoundTargetData ftd;
+		byte trackdir = GetVehicleTrackdir(v);
+		ftd = NPFRouteToDepotTrialError(v->tile, trackdir, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
+		if (ftd.best_bird_dist == 0) {
+			best_depot = GetDepotByTile(ftd.node.tile); /* Found target */
+		} else {
+			best_depot = NULL; /* Did not find target */
+		}
+	} else {
+		FOR_ALL_DEPOTS(depot) {
+			tile = depot->xy;
+			if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) {
+				dist = DistanceManhattan(tile, tile2);
+				if (dist < best_dist) {
+					best_dist = dist;
+					best_depot = depot;
+				}
+			}
+		}
+	}
+	return best_depot;
+}
+
+static void CheckIfShipNeedsService(Vehicle *v)
+{
+	const Depot* depot;
+
+	if (_patches.servint_ships == 0) return;
+	if (!VehicleNeedsService(v))     return;
+	if (v->vehstatus & VS_STOPPED)   return;
+
+	if (v->current_order.type == OT_GOTO_DEPOT &&
+			v->current_order.flags & OF_HALT_IN_DEPOT)
+		return;
+
+	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
+
+	if (IsShipInDepot(v)) {
+		VehicleServiceInDepot(v);
+		return;
+	}
+
+	depot = FindClosestShipDepot(v);
+
+	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
+		if (v->current_order.type == OT_GOTO_DEPOT) {
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return;
+	}
+
+	v->current_order.type = OT_GOTO_DEPOT;
+	v->current_order.flags = OF_NON_STOP;
+	v->current_order.dest = depot->index;
+	v->dest_tile = depot->xy;
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+}
+
+void OnNewDay_Ship(Vehicle *v)
+{
+	int32 cost;
+
+	if ((++v->day_counter & 7) == 0)
+		DecreaseVehicleValue(v);
+
+	CheckVehicleBreakdown(v);
+	AgeVehicle(v);
+	CheckIfShipNeedsService(v);
+
+	CheckOrders(v);
+
+	if (v->vehstatus & VS_STOPPED) return;
+
+	cost = ShipVehInfo(v->engine_type)->running_cost * _price.ship_running / 364;
+	v->profit_this_year -= cost >> 8;
+
+	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
+	SubtractMoneyFromPlayerFract(v->owner, cost);
+
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+	//we need this for the profit
+	InvalidateWindowClasses(WC_SHIPS_LIST);
+}
+
+static void HandleBrokenShip(Vehicle *v)
+{
+	if (v->breakdown_ctr != 1) {
+		v->breakdown_ctr = 1;
+		v->cur_speed = 0;
+
+		if (v->breakdowns_since_last_service != 255)
+			v->breakdowns_since_last_service++;
+
+		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+		}
+
+		if (!(v->vehstatus & VS_HIDDEN)) {
+			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
+			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
+		}
+	}
+
+	if (!(v->tick_counter & 1)) {
+		if (!--v->breakdown_delay) {
+			v->breakdown_ctr = 0;
+			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		}
+	}
+}
+
+static void MarkShipDirty(Vehicle *v)
+{
+	v->cur_image = GetShipImage(v, v->direction);
+	MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
+}
+
+static void PlayShipSound(Vehicle *v)
+{
+	if (!PlayVehicleSound(v, VSE_START)) {
+		SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v);
+	}
+}
+
+static void ProcessShipOrder(Vehicle *v)
+{
+	const Order *order;
+
+	switch (v->current_order.type) {
+		case OT_GOTO_DEPOT:
+			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return;
+			if (v->current_order.flags & OF_SERVICE_IF_NEEDED &&
+					!VehicleNeedsService(v)) {
+				v->cur_order_index++;
+			}
+			break;
+
+		case OT_LOADING:
+		case OT_LEAVESTATION:
+			return;
+
+		default: break;
+	}
+
+	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
+
+	order = GetVehicleOrder(v, v->cur_order_index);
+
+	if (order == NULL) {
+		v->current_order.type  = OT_NOTHING;
+		v->current_order.flags = 0;
+		v->dest_tile = 0;
+		return;
+	}
+
+	if (order->type  == v->current_order.type &&
+			order->flags == v->current_order.flags &&
+			order->dest  == v->current_order.dest)
+		return;
+
+	v->current_order = *order;
+
+	if (order->type == OT_GOTO_STATION) {
+		const Station *st;
+
+		if (order->dest == v->last_station_visited)
+			v->last_station_visited = INVALID_STATION;
+
+		st = GetStation(order->dest);
+		if (st->dock_tile != 0) {
+			v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
+		}
+	} else if (order->type == OT_GOTO_DEPOT) {
+		v->dest_tile = GetDepot(order->dest)->xy;
+	} else {
+		v->dest_tile = 0;
+	}
+
+	InvalidateVehicleOrder(v);
+
+	InvalidateWindowClasses(WC_SHIPS_LIST);
+}
+
+static void HandleShipLoading(Vehicle *v)
+{
+	if (v->current_order.type == OT_NOTHING) return;
+
+	if (v->current_order.type != OT_DUMMY) {
+		if (v->current_order.type != OT_LOADING) return;
+		if (--v->load_unload_time_rem) return;
+
+		if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
+				(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
+			SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
+			if (LoadUnloadVehicle(v, false)) {
+				InvalidateWindow(WC_SHIPS_LIST, v->owner);
+				MarkShipDirty(v);
+			}
+			return;
+		}
+		PlayShipSound(v);
+
+		{
+			Order b = v->current_order;
+			v->current_order.type = OT_LEAVESTATION;
+			v->current_order.flags = 0;
+			if (!(b.flags & OF_NON_STOP)) return;
+		}
+	}
+
+	v->cur_order_index++;
+	InvalidateVehicleOrder(v);
+}
+
+static void UpdateShipDeltaXY(Vehicle *v, int dir)
+{
+#define MKIT(d,c,b,a) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
+	static const uint32 _delta_xy_table[8] = {
+		MKIT( -3,  -3,  6,  6),
+		MKIT(-16,  -3, 32,  6),
+		MKIT( -3,  -3,  6,  6),
+		MKIT( -3, -16,  6, 32),
+		MKIT( -3,  -3,  6,  6),
+		MKIT(-16,  -3, 32,  6),
+		MKIT( -3,  -3,  6,  6),
+		MKIT( -3, -16,  6, 32),
+	};
+#undef MKIT
+	uint32 x = _delta_xy_table[dir];
+	v->x_offs        = GB(x,  0, 8);
+	v->y_offs        = GB(x,  8, 8);
+	v->sprite_width  = GB(x, 16, 8);
+	v->sprite_height = GB(x, 24, 8);
+}
+
+void RecalcShipStuff(Vehicle *v)
+{
+	UpdateShipDeltaXY(v, v->direction);
+	v->cur_image = GetShipImage(v, v->direction);
+	MarkShipDirty(v);
+	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+}
+
+static const TileIndexDiffC _ship_leave_depot_offs[] = {
+	{-1,  0},
+	{ 0, -1}
+};
+
+static void CheckShipLeaveDepot(Vehicle *v)
+{
+	TileIndex tile;
+	Axis axis;
+	uint m;
+
+	if (!IsShipInDepot(v)) return;
+
+	tile = v->tile;
+	axis = GetShipDepotAxis(tile);
+
+	// Check first side
+	if (_ship_sometracks[axis] & GetTileShipTrackStatus(TILE_ADD(tile, ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
+		m = (axis == AXIS_X) ? 0x101 : 0x207;
+	// Check second side
+	} else if (_ship_sometracks[axis + 2] & GetTileShipTrackStatus(TILE_ADD(tile, -2 * ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
+		m = (axis == AXIS_X) ? 0x105 : 0x203;
+	} else {
+		return;
+	}
+	v->direction    = GB(m, 0, 8);
+	v->u.ship.state = GB(m, 8, 8);
+	v->vehstatus &= ~VS_HIDDEN;
+
+	v->cur_speed = 0;
+	RecalcShipStuff(v);
+
+	PlayShipSound(v);
+	VehicleServiceInDepot(v);
+	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	InvalidateWindowClasses(WC_SHIPS_LIST);
+}
+
+static bool ShipAccelerate(Vehicle *v)
+{
+	uint spd;
+	byte t;
+
+	spd = min(v->cur_speed + 1, v->max_speed);
+
+	//updates statusbar only if speed have changed to save CPU time
+	if (spd != v->cur_speed) {
+		v->cur_speed = spd;
+		if (_patches.vehicle_speed)
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+
+	// Decrease somewhat when turning
+	if (!(v->direction & 1)) spd = spd * 3 / 4;
+
+	if (spd == 0) return false;
+	if ((byte)++spd == 0) return true;
+
+	v->progress = (t = v->progress) - (byte)spd;
+
+	return (t < v->progress);
+}
+
+static int32 EstimateShipCost(EngineID engine_type)
+{
+	return ShipVehInfo(engine_type)->base_cost * (_price.ship_base>>3)>>5;
+}
+
+static void ShipArrivesAt(const Vehicle* v, Station* st)
+{
+	/* Check if station was ever visited before */
+	if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
+		uint32 flags;
+
+		st->had_vehicle_of_type |= HVOT_SHIP;
+
+		SetDParam(0, st->index);
+		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
+		AddNewsItem(
+			STR_9833_CITIZENS_CELEBRATE_FIRST,
+			flags,
+			v->index,
+			0);
+	}
+}
+
+typedef struct {
+	TileIndex skiptile;
+	TileIndex dest_coords;
+	uint best_bird_dist;
+	uint best_length;
+} PathFindShip;
+
+static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length, byte *state)
+{
+	// Found dest?
+	if (tile == pfs->dest_coords) {
+		pfs->best_bird_dist = 0;
+
+		pfs->best_length = minu(pfs->best_length, length);
+		return true;
+	}
+
+	// Skip this tile in the calculation
+	if (tile != pfs->skiptile) {
+		pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
+	}
+
+	return false;
+}
+
+static const byte _ship_search_directions[6][4] = {
+	{ 0, 9, 2, 9 },
+	{ 9, 1, 9, 3 },
+	{ 9, 0, 3, 9 },
+	{ 1, 9, 9, 2 },
+	{ 3, 2, 9, 9 },
+	{ 9, 9, 1, 0 },
+};
+
+static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0};
+
+static uint FindShipTrack(Vehicle *v, TileIndex tile, int dir, uint bits, TileIndex skiptile, int *track)
+{
+	PathFindShip pfs;
+	int i, best_track;
+	uint best_bird_dist = 0;
+	uint best_length    = 0;
+	uint r;
+	byte ship_dir = v->direction & 3;
+
+	pfs.dest_coords = v->dest_tile;
+	pfs.skiptile = skiptile;
+
+	best_track = -1;
+
+	do {
+		i = FIND_FIRST_BIT(bits);
+		bits = KILL_FIRST_BIT(bits);
+
+		pfs.best_bird_dist = (uint)-1;
+		pfs.best_length = (uint)-1;
+
+		FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs);
+
+		if (best_track >= 0) {
+			if (pfs.best_bird_dist != 0) {
+				/* neither reached the destination, pick the one with the smallest bird dist */
+				if (pfs.best_bird_dist > best_bird_dist) goto bad;
+				if (pfs.best_bird_dist < best_bird_dist) goto good;
+			} else {
+				if (pfs.best_length > best_length) goto bad;
+				if (pfs.best_length < best_length) goto good;
+			}
+
+			/* if we reach this position, there's two paths of equal value so far.
+			 * pick one randomly. */
+			r = GB(Random(), 0, 8);
+			if (_pick_shiptrack_table[i] == ship_dir) r += 80;
+			if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
+			if (r <= 127) goto bad;
+		}
+good:;
+		best_track = i;
+		best_bird_dist = pfs.best_bird_dist;
+		best_length = pfs.best_length;
+bad:;
+
+	} while (bits != 0);
+
+	*track = best_track;
+	return best_bird_dist;
+}
+
+static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailTypeMask railtypes)
+{
+
+	void* perf = NpfBeginInterval();
+	NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, owner, railtypes);
+	int t = NpfEndInterval(perf);
+	DEBUG(yapf, 4, "[NPFW] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
+	return ret;
+}
+
+/* returns the track to choose on the next tile, or -1 when it's better to
+ * reverse. The tile given is the tile we are about to enter, enterdir is the
+ * direction in which we are entering the tile */
+static int ChooseShipTrack(Vehicle *v, TileIndex tile, int enterdir, uint tracks)
+{
+	assert(enterdir>=0 && enterdir<=3);
+
+	if (_patches.yapf.ship_use_yapf) {
+		Trackdir trackdir = YapfChooseShipTrack(v, tile, enterdir, tracks);
+		return (trackdir != INVALID_TRACKDIR) ? (int)TrackdirToTrack(trackdir) : -1;
+	} else if (_patches.new_pathfinding_all) {
+		NPFFindStationOrTileData fstd;
+		NPFFoundTargetData ftd;
+		TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
+		byte trackdir = GetVehicleTrackdir(v);
+		assert (trackdir != 0xFF); /* Check that we are not in a depot */
+
+		NPFFillWithOrderData(&fstd, v);
+
+		ftd = PerfNPFRouteToStationOrTile(src_tile, trackdir, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE);
+
+		if (ftd.best_trackdir != 0xff) {
+			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
+			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
+			we did not find our target, but ftd.best_trackdir contains the direction leading
+			to the tile closest to our target. */
+			return ftd.best_trackdir & 7; /* TODO: Wrapper function? */
+		} else {
+			return -1; /* Already at target, reverse? */
+		}
+	} else {
+		uint b;
+		uint tot_dist, dist;
+		int track;
+		TileIndex tile2;
+
+		tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
+		tot_dist = (uint)-1;
+
+		/* Let's find out how far it would be if we would reverse first */
+		b = GetTileShipTrackStatus(tile2) & _ship_sometracks[ReverseDiagDir(enterdir)] & v->u.ship.state;
+		if (b != 0) {
+			dist = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
+			if (dist != (uint)-1)
+				tot_dist = dist + 1;
+		}
+		/* And if we would not reverse? */
+		dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
+		if (dist > tot_dist)
+			/* We could better reverse */
+			return -1;
+		return track;
+	}
+}
+
+static const Direction _new_vehicle_direction_table[] = {
+	DIR_N , DIR_NW, DIR_W , 0,
+	DIR_NE, DIR_N , DIR_SW, 0,
+	DIR_E , DIR_SE, DIR_S
+};
+
+static int ShipGetNewDirectionFromTiles(TileIndex new_tile, TileIndex old_tile)
+{
+	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
+							TileX(new_tile) - TileX(old_tile) + 1;
+	assert(offs < 11 && offs != 3 && offs != 7);
+	return _new_vehicle_direction_table[offs];
+}
+
+static int ShipGetNewDirection(Vehicle *v, int x, int y)
+{
+	uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1);
+	assert(offs < 11 && offs != 3 && offs != 7);
+	return _new_vehicle_direction_table[offs];
+}
+
+static int GetAvailShipTracks(TileIndex tile, int dir)
+{
+	uint32 r = GetTileTrackStatus(tile, TRANSPORT_WATER);
+	return (byte) ((r | r >> 8)) & _ship_sometracks[dir];
+}
+
+static const byte _ship_subcoord[4][6][3] = {
+	{
+		{15, 8, 1},
+		{ 0, 0, 0},
+		{ 0, 0, 0},
+		{15, 8, 2},
+		{15, 7, 0},
+		{ 0, 0, 0},
+	},
+	{
+		{ 0, 0, 0},
+		{ 8, 0, 3},
+		{ 7, 0, 2},
+		{ 0, 0, 0},
+		{ 8, 0, 4},
+		{ 0, 0, 0},
+	},
+	{
+		{ 0, 8, 5},
+		{ 0, 0, 0},
+		{ 0, 7, 6},
+		{ 0, 0, 0},
+		{ 0, 0, 0},
+		{ 0, 8, 4},
+	},
+	{
+		{ 0, 0, 0},
+		{ 8,15, 7},
+		{ 0, 0, 0},
+		{ 8,15, 6},
+		{ 0, 0, 0},
+		{ 7,15, 0},
+	}
+};
+
+static void ShipController(Vehicle *v)
+{
+	GetNewVehiclePosResult gp;
+	uint32 r;
+	const byte *b;
+	Direction dir;
+	int track;
+	int tracks;
+
+	v->tick_counter++;
+
+	if (v->breakdown_ctr != 0) {
+		if (v->breakdown_ctr <= 2) {
+			HandleBrokenShip(v);
+			return;
+		}
+		v->breakdown_ctr--;
+	}
+
+	if (v->vehstatus & VS_STOPPED) return;
+
+	ProcessShipOrder(v);
+	HandleShipLoading(v);
+
+	if (v->current_order.type == OT_LOADING) return;
+
+	CheckShipLeaveDepot(v);
+
+	if (!ShipAccelerate(v)) return;
+
+	BeginVehicleMove(v);
+
+	if (GetNewVehiclePos(v, &gp)) {
+		// staying in tile
+		if (IsShipInDepot(v)) {
+			gp.x = v->x_pos;
+			gp.y = v->y_pos;
+		} else {
+			/* isnot inside depot */
+			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+			if (r & 0x8) goto reverse_direction;
+
+			/* A leave station order only needs one tick to get processed, so we can
+			 * always skip ahead. */
+			if (v->current_order.type == OT_LEAVESTATION) {
+				v->current_order.type = OT_NOTHING;
+				v->current_order.flags = 0;
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			} else if (v->dest_tile != 0) {
+				/* We have a target, let's see if we reached it... */
+				if (v->current_order.type == OT_GOTO_STATION &&
+						IsBuoyTile(v->dest_tile) &&
+						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
+					/* We got within 3 tiles of our target buoy, so let's skip to our
+					 * next order */
+					v->cur_order_index++;
+					v->current_order.type = OT_DUMMY;
+					InvalidateVehicleOrder(v);
+				} else {
+					/* Non-buoy orders really need to reach the tile */
+					if (v->dest_tile == gp.new_tile) {
+						if (v->current_order.type == OT_GOTO_DEPOT) {
+							if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
+								VehicleEnterDepot(v);
+								return;
+							}
+						} else if (v->current_order.type == OT_GOTO_STATION) {
+							Station *st;
+
+							v->last_station_visited = v->current_order.dest;
+
+							/* Process station in the orderlist. */
+							st = GetStation(v->current_order.dest);
+							if (st->facilities & FACIL_DOCK) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
+								v->current_order.type = OT_LOADING;
+								v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
+								v->current_order.flags |= OF_NON_STOP;
+								ShipArrivesAt(v, st);
+
+								SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
+								if (LoadUnloadVehicle(v, true)) {
+									InvalidateWindow(WC_SHIPS_LIST, v->owner);
+									MarkShipDirty(v);
+								}
+								InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+							} else { /* leave stations without docks right aways */
+								v->current_order.type = OT_LEAVESTATION;
+								v->current_order.flags = 0;
+								v->cur_order_index++;
+								InvalidateVehicleOrder(v);
+							}
+						}
+					}
+				}
+			}
+		}
+	} else {
+		DiagDirection diagdir;
+		// new tile
+		if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY())
+			goto reverse_direction;
+
+		dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
+		assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
+		diagdir = DirToDiagDir(dir);
+		tracks = GetAvailShipTracks(gp.new_tile, diagdir);
+		if (tracks == 0)
+			goto reverse_direction;
+
+		// Choose a direction, and continue if we find one
+		track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
+		if (track < 0)
+			goto reverse_direction;
+
+		b = _ship_subcoord[diagdir][track];
+
+		gp.x = (gp.x&~0xF) | b[0];
+		gp.y = (gp.y&~0xF) | b[1];
+
+		/* Call the landscape function and tell it that the vehicle entered the tile */
+		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+		if (r&0x8) goto reverse_direction;
+
+		if (!(r&0x4)) {
+			v->tile = gp.new_tile;
+			v->u.ship.state = 1 << track;
+		}
+
+		v->direction = b[2];
+	}
+
+	/* update image of ship, as well as delta XY */
+	dir = ShipGetNewDirection(v, gp.x, gp.y);
+	v->x_pos = gp.x;
+	v->y_pos = gp.y;
+	v->z_pos = GetSlopeZ(gp.x, gp.y);
+
+getout:
+	UpdateShipDeltaXY(v, dir);
+	v->cur_image = GetShipImage(v, dir);
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+	return;
+
+reverse_direction:
+	dir = ReverseDir(v->direction);
+	v->direction = dir;
+	goto getout;
+}
+
+static void AgeShipCargo(Vehicle *v)
+{
+	if (_age_cargo_skip_counter != 0) return;
+	if (v->cargo_days != 255) v->cargo_days++;
+}
+
+void Ship_Tick(Vehicle *v)
+{
+	AgeShipCargo(v);
+	ShipController(v);
+}
+
+
+void ShipsYearlyLoop(void)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Ship) {
+			v->profit_last_year = v->profit_this_year;
+			v->profit_this_year = 0;
+			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		}
+	}
+}
+
+/** Build a ship.
+ * @param tile tile of depot where ship is built
+ * @param p1 ship type being built (engine)
+ * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number
+ */
+int32 CmdBuildShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 value;
+	Vehicle *v;
+	UnitID unit_num;
+	Engine *e;
+
+	if (!IsEngineBuildable(p1, VEH_Ship, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	value = EstimateShipCost(p1);
+	if (flags & DC_QUERY_COST) return value;
+
+	/* The ai_new queries the vehicle cost before building the route,
+	 * so we must check against cheaters no sooner than now. --pasky */
+	if (!IsTileDepotType(tile, TRANSPORT_WATER)) return CMD_ERROR;
+	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
+
+	v = AllocateVehicle();
+	unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Ship);
+
+	if (v == NULL || IsOrderPoolFull() || unit_num > _patches.max_ships)
+		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+	if (flags & DC_EXEC) {
+		int x;
+		int y;
+
+		const ShipVehicleInfo *svi = ShipVehInfo(p1);
+
+		v->unitnumber = unit_num;
+
+		v->owner = _current_player;
+		v->tile = tile;
+		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
+		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
+		v->x_pos = x;
+		v->y_pos = y;
+		v->z_pos = GetSlopeZ(x,y);
+
+		v->z_height = 6;
+		v->sprite_width = 6;
+		v->sprite_height = 6;
+		v->x_offs = -3;
+		v->y_offs = -3;
+		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
+
+		v->spritenum = svi->image_index;
+		v->cargo_type = svi->cargo_type;
+		v->cargo_subtype = 0;
+		v->cargo_cap = svi->capacity;
+		v->value = value;
+
+		v->last_station_visited = INVALID_STATION;
+		v->max_speed = svi->max_speed;
+		v->engine_type = p1;
+
+		e = GetEngine(p1);
+		v->reliability = e->reliability;
+		v->reliability_spd_dec = e->reliability_spd_dec;
+		v->max_age = e->lifelength * 366;
+		_new_vehicle_id = v->index;
+
+		v->string_id = STR_SV_SHIP_NAME;
+		v->u.ship.state = 0x80;
+
+		v->service_interval = _patches.servint_ships;
+		v->date_of_last_service = _date;
+		v->build_year = _cur_year;
+		v->cur_image = 0x0E5E;
+		v->type = VEH_Ship;
+		v->random_bits = VehicleRandomBits();
+
+		VehiclePositionChanged(v);
+		GetPlayer(_current_player)->num_engines[p1]++;
+
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+		InvalidateWindow(WC_COMPANY, v->owner);
+		if (IsLocalPlayer())
+			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
+	}
+
+	return value;
+}
+
+/** Sell a ship.
+ * @param tile unused
+ * @param p1 vehicle ID to be sold
+ * @param p2 unused
+ */
+int32 CmdSellShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	if (!IsShipInDepotStopped(v)) {
+		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
+	}
+
+	if (flags & DC_EXEC) {
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+		InvalidateWindow(WC_COMPANY, v->owner);
+		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
+		DeleteDepotHighlightOfVehicle(v);
+		DeleteVehicle(v);
+		if (IsLocalPlayer())
+			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Ship); // updates the replace Ship window
+	}
+
+	return -(int32)v->value;
+}
+
+/** Start/Stop a ship.
+ * @param tile unused
+ * @param p1 ship ID to start/stop
+ * @param p2 unused
+ */
+int32 CmdStartStopShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	uint16 callback;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* Check if this ship can be started/stopped. The callback will fail or
+	 * return 0xFF if it can. */
+	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
+	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
+		return_cmd_error(error);
+	}
+
+	if (flags & DC_EXEC) {
+		if (IsShipInDepotStopped(v)) {
+			DeleteVehicleNews(p1, STR_981C_SHIP_IS_WAITING_IN_DEPOT);
+		}
+
+		v->vehstatus ^= VS_STOPPED;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		InvalidateWindowClasses(WC_SHIPS_LIST);
+	}
+
+	return 0;
+}
+
+/** Send a ship to the depot.
+ * @param tile unused
+ * @param p1 vehicle ID to send to the depot
+ * @param p2 various bitmasked elements
+ * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
+ * - p2 bit 8-10 - VLW flag (for mass goto depot)
+ */
+int32 CmdSendShipToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	const Depot *dep;
+
+	if (p2 & DEPOT_MASS_SEND) {
+		/* Mass goto depot requested */
+		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
+		return SendAllVehiclesToDepot(VEH_Ship, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
+	}
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
+
+	if (IsShipInDepot(v)) return CMD_ERROR;
+
+	/* If the current orders are already goto-depot */
+	if (v->current_order.type == OT_GOTO_DEPOT) {
+		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
+			/* We called with a different DEPOT_SERVICE setting.
+			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
+			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
+			if (flags & DC_EXEC) {
+				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			}
+			return 0;
+		}
+
+		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
+		if (flags & DC_EXEC) {
+			/* If the orders to 'goto depot' are in the orders list (forced servicing),
+			 * then skip to the next order; effectively cancelling this forced service */
+			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS))
+				v->cur_order_index++;
+
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return 0;
+	}
+
+	dep = FindClosestShipDepot(v);
+	if (dep == NULL) return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT);
+
+	if (flags & DC_EXEC) {
+		v->dest_tile = dep->xy;
+		v->current_order.type = OT_GOTO_DEPOT;
+		v->current_order.flags = OF_NON_STOP;
+		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+		v->current_order.refit_cargo = CT_INVALID;
+		v->current_order.dest = dep->index;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+
+	return 0;
+}
+
+
+/** Refits a ship to the specified cargo type.
+ * @param tile unused
+ * @param p1 vehicle ID of the ship to refit
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
+ * - p2 = (bit 8-15) - the new cargo subtype to refit to
+ */
+int32 CmdRefitShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	int32 cost;
+	CargoID new_cid = GB(p2, 0, 8); //gets the cargo number
+	byte new_subtype = GB(p2, 8, 8);
+	uint16 capacity = CALLBACK_FAILED;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (!IsShipInDepotStopped(v)) {
+		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
+	}
+
+	/* Check cargo */
+	if (!ShipVehInfo(v->engine_type)->refittable) return CMD_ERROR;
+	if (new_cid > NUM_CARGO || !CanRefitTo(v->engine_type, new_cid)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
+
+	/* Check the refit capacity callback */
+	if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
+		/* Back up the existing cargo type */
+		CargoID temp_cid = v->cargo_type;
+		byte temp_subtype = v->cargo_subtype;
+		v->cargo_type = new_cid;
+		v->cargo_subtype = new_subtype;
+
+		capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
+
+		/* Restore the cargo type */
+		v->cargo_type = temp_cid;
+		v->cargo_subtype = temp_subtype;
+	}
+
+	if (capacity == CALLBACK_FAILED) {
+		capacity = ShipVehInfo(v->engine_type)->capacity;
+	}
+	_returned_refit_capacity = capacity;
+
+	cost = 0;
+	if (IsHumanPlayer(v->owner) && new_cid != v->cargo_type) {
+		cost = GetRefitCost(v->engine_type);
+	}
+
+	if (flags & DC_EXEC) {
+		v->cargo_cap = capacity;
+		v->cargo_count = (v->cargo_type == new_cid) ? min(v->cargo_cap, v->cargo_count) : 0;
+		v->cargo_type = new_cid;
+		v->cargo_subtype = new_subtype;
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		RebuildVehicleLists();
+	}
+
+	return cost;
+
+}
deleted file mode 100644
--- a/src/ship_gui.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "ship.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "station.h"
-#include "command.h"
-#include "player.h"
-#include "engine.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "newgrf_engine.h"
-#include "date.h"
-
-/**
- * Draw the purchase info details of a ship at a given location.
- * @param x,y location where to draw the info
- * @param engine_number the engine of which to draw the info of
- */
-void DrawShipPurchaseInfo(int x, int y, uint w, EngineID engine_number)
-{
-	YearMonthDay ymd;
-	const ShipVehicleInfo *svi = ShipVehInfo(engine_number);
-	const Engine *e;
-
-	/* Purchase cost - Max speed */
-	SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5);
-	SetDParam(1, svi->max_speed / 2);
-	DrawString(x,y, STR_PURCHASE_INFO_COST_SPEED, 0);
-	y += 10;
-
-	/* Cargo type + capacity */
-	SetDParam(0, svi->cargo_type);
-	SetDParam(1, svi->capacity);
-	SetDParam(2, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY);
-	DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0);
-	y += 10;
-
-	/* Running cost */
-	SetDParam(0, svi->running_cost * _price.ship_running >> 8);
-	DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
-	y += 10;
-
-	/* Design date - Life length */
-	e = GetEngine(engine_number);
-	ConvertDateToYMD(e->intro_date, &ymd);
-	SetDParam(0, ymd.year);
-	SetDParam(1, e->lifelength);
-	DrawString(x,y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
-	y += 10;
-
-	/* Reliability */
-	SetDParam(0, e->reliability * 100 >> 16);
-	DrawString(x,y, STR_PURCHASE_INFO_RELIABILITY, 0);
-	y += 10;
-
-	/* Additional text from NewGRF */
-	y += ShowAdditionalText(x, y, w, engine_number);
-	if (svi->refittable) y += ShowRefitOptionsList(x, y, w, engine_number);
-}
-
-void DrawShipImage(const Vehicle *v, int x, int y, VehicleID selection)
-{
-	DrawSprite(GetShipImage(v, DIR_W) | GetVehiclePalette(v), x + 32, y + 10);
-
-	if (v->index == selection) {
-		DrawFrameRect(x - 5, y - 1, x + 67, y + 21, 15, FR_BORDERONLY);
-	}
-}
-
-static void ShipDetailsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		StringID str;
-
-		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
-		// disable service-scroller when interval is set to disabled
-		SetWindowWidgetDisabledState(w, 5, !_patches.servint_ships);
-		SetWindowWidgetDisabledState(w, 6, !_patches.servint_ships);
-
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		/* Draw running cost */
-		{
-			int year = v->age / 366;
-
-			SetDParam(1, year);
-
-			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
-			SetDParam(2, v->max_age / 366);
-			SetDParam(3, ShipVehInfo(v->engine_type)->running_cost * _price.ship_running >> 8);
-			DrawString(2, 15, STR_9812_AGE_RUNNING_COST_YR, 0);
-		}
-
-		/* Draw max speed */
-		{
-			SetDParam(0, v->max_speed / 2);
-			DrawString(2, 25, STR_9813_MAX_SPEED, 0);
-		}
-
-		/* Draw profit */
-		{
-			SetDParam(0, v->profit_this_year);
-			SetDParam(1, v->profit_last_year);
-			DrawString(2, 35, STR_9814_PROFIT_THIS_YEAR_LAST_YEAR, 0);
-		}
-
-		/* Draw breakdown & reliability */
-		{
-			SetDParam(0, v->reliability * 100 >> 16);
-			SetDParam(1, v->breakdowns_since_last_service);
-			DrawString(2, 45, STR_9815_RELIABILITY_BREAKDOWNS, 0);
-		}
-
-		/* Draw service interval text */
-		{
-			SetDParam(0, v->service_interval);
-			SetDParam(1, v->date_of_last_service);
-			DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
-		}
-
-		DrawShipImage(v, 3, 57, INVALID_VEHICLE);
-
-		SetDParam(1, v->build_year);
-		SetDParam(0, GetCustomEngineName(v->engine_type));
-		SetDParam(2, v->value);
-		DrawString(74, 57, STR_9816_BUILT_VALUE, 0);
-
-		SetDParam(0, v->cargo_type);
-		SetDParam(1, v->cargo_cap);
-		DrawString(74, 67, STR_9817_CAPACITY, 0);
-
-		str = STR_8812_EMPTY;
-		if (v->cargo_count != 0) {
-			SetDParam(0, v->cargo_type);
-			SetDParam(1, v->cargo_count);
-			SetDParam(2, v->cargo_source);
-			str = STR_8813_FROM;
-		}
-		DrawString(74, 78, str, 0);
-	} break;
-
-	case WE_CLICK: {
-		int mod;
-		const Vehicle *v;
-		switch (e->we.click.widget) {
-		case 2: /* rename */
-			v = GetVehicle(w->window_number);
-			SetDParam(0, v->unitnumber);
-			ShowQueryString(v->string_id, STR_9831_NAME_SHIP, 31, 150, w, CS_ALPHANUMERAL);
-			break;
-		case 5: /* increase int */
-			mod = _ctrl_pressed? 5 : 10;
-			goto do_change_service_int;
-		case 6: /* decrease int */
-			mod = _ctrl_pressed?- 5 : -10;
-do_change_service_int:
-			v = GetVehicle(w->window_number);
-
-			mod = GetServiceIntervalClamped(mod + v->service_interval);
-			if (mod == v->service_interval) return;
-
-			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
-			break;
-		}
-	} break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_NAME_VEHICLE | CMD_MSG(STR_9832_CAN_T_NAME_SHIP));
-		}
-		break;
-	}
-}
-
-
-static const Widget _ship_details_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   364,     0,    13, STR_9811_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   365,   404,     0,    13, STR_01AA_NAME,    STR_982F_NAME_SHIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   404,    14,    55, 0x0,              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   404,    56,    88, 0x0,              STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    89,    94, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    95,   100, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    11,   404,    89,   100, 0x0,              STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _ship_details_desc = {
-	WDP_AUTO, WDP_AUTO, 405, 101,
-	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_ship_details_widgets,
-	ShipDetailsWndProc
-};
-
-static void ShowShipDetailsWindow(const Vehicle *v)
-{
-	Window *w;
-	VehicleID veh = v->index;
-
-	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
-	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
-	w = AllocateWindowDescFront(&_ship_details_desc, veh);
-	w->caption_color = v->owner;
-}
-
-void CcBuildShip(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	const Vehicle *v;
-	if (!success) return;
-
-	v = GetVehicle(_new_vehicle_id);
-	if (v->tile == _backup_orders_tile) {
-		_backup_orders_tile = 0;
-		RestoreVehicleOrders(v, _backup_orders_data);
-	}
-	ShowShipViewWindow(v);
-}
-
-void CcCloneShip(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) ShowShipViewWindow(GetVehicle(_new_vehicle_id));
-}
-
-static void NewShipWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			EngineID selected_id;
-			EngineID eid;
-			int count;
-			int pos;
-			int sel;
-			int y;
-
-			SetWindowWidgetDisabledState(w, 5, w->window_number == 0);
-
-			count = 0;
-			for (eid = SHIP_ENGINES_INDEX; eid < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; eid++) {
-				if (HASBIT(GetEngine(eid)->player_avail, _local_player)) count++;
-			}
-			SetVScrollCount(w, count);
-
-			DrawWindowWidgets(w);
-
-			y = 15;
-			sel = WP(w,buildvehicle_d).sel_index;
-			pos = w->vscroll.pos;
-			selected_id = INVALID_ENGINE;
-			for (eid = SHIP_ENGINES_INDEX; eid < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; eid++) {
-				if (!HASBIT(GetEngine(eid)->player_avail, _local_player)) continue;
-				if (sel == 0) selected_id = eid;
-				if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
-					DrawString(77, y + 7, GetCustomEngineName(eid), sel == 0 ? 0xC : 0x10);
-					DrawShipEngine(37, y + 10, eid, GetEnginePalette(eid, _local_player));
-					y += 24;
-				}
-				sel--;
-			}
-
-			WP(w,buildvehicle_d).sel_engine = selected_id;
-
-			if (selected_id != INVALID_ENGINE) {
-				const Widget *wi = &w->widget[4];
-				DrawShipPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
-			}
-			break;
-		}
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: { /* listbox */
-			uint i = (e->we.click.pt.y - 14) / 24;
-			if (i < w->vscroll.cap) {
-				WP(w,buildvehicle_d).sel_index = i + w->vscroll.pos;
-				SetWindowDirty(w);
-			}
-		} break;
-		case 5: { /* build */
-			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
-			if (sel_eng != INVALID_ENGINE)
-				DoCommandP(w->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
-		} break;
-
-		case 6: { /* rename */
-			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				WP(w, buildvehicle_d).rename_engine = sel_eng;
-				ShowQueryString(GetCustomEngineName(sel_eng), STR_9838_RENAME_SHIP_TYPE, 31, 160, w, CS_ALPHANUMERAL);
-			}
-		}	break;
-		}
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, WP(w, buildvehicle_d).rename_engine, 0, NULL,
-				CMD_RENAME_ENGINE | CMD_MSG(STR_9839_CAN_T_RENAME_SHIP_TYPE));
-		}
-		break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 24;
-		w->widget[2].data = (w->vscroll.cap << 8) + 1;
-		break;
-
-	}
-}
-
-static const Widget _new_ship_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   254,     0,    13, STR_9808_NEW_SHIPS,  STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   242,    14,   109, 0x401,               STR_9825_SHIP_SELECTION_LIST_CLICK},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   243,   254,    14,   109, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    14,     0,   254,   110,   201, 0x0,                 STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   121,   202,   213, STR_9809_BUILD_SHIP, STR_9826_BUILD_THE_HIGHLIGHTED_SHIP},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   122,   242,   202,   213, STR_9836_RENAME,     STR_9837_RENAME_SHIP_TYPE},
-{  WWT_RESIZEBOX,     RESIZE_TB,    14,   243,   254,   202,   213, 0x0,                 STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _new_ship_desc = {
-	WDP_AUTO, WDP_AUTO, 255, 214,
-	WC_BUILD_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_new_ship_widgets,
-	NewShipWndProc
-};
-
-
-void ShowBuildShipWindow(TileIndex tile)
-{
-	Window *w;
-
-	DeleteWindowById(WC_BUILD_VEHICLE, tile);
-
-	w = AllocateWindowDescFront(&_new_ship_desc, tile);
-	w->vscroll.cap = 4;
-	w->widget[2].data = (w->vscroll.cap << 8) + 1;
-
-	w->resize.step_height = 24;
-
-	if (tile != 0) {
-		w->caption_color = GetTileOwner(tile);
-	} else {
-		w->caption_color = _local_player;
-	}
-
-}
-
-
-static void ShipViewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			Vehicle *v = GetVehicle(w->window_number);
-			StringID str;
-			bool refitable_and_stopped_in_depot = ShipVehInfo(v->engine_type)->refittable && IsShipInDepotStopped(v);
-			bool is_localplayer = v->owner == _local_player;
-
-			SetWindowWidgetDisabledState(w,  7, !is_localplayer);
-			SetWindowWidgetDisabledState(w,  8,
-			                             !is_localplayer ||      // Disable if owner is not local player
-			                             !refitable_and_stopped_in_depot); // Disable if the ship is not refitable or stopped in a depot
-			SetWindowWidgetDisabledState(w, 11, !is_localplayer);
-
-			/* draw widgets & caption */
-			SetDParam(0, v->string_id);
-			SetDParam(1, v->unitnumber);
-			DrawWindowWidgets(w);
-
-			if (v->breakdown_ctr == 1) {
-				str = STR_885C_BROKEN_DOWN;
-			} else if (v->vehstatus & VS_STOPPED) {
-				str = STR_8861_STOPPED;
-			} else {
-				switch (v->current_order.type) {
-					case OT_GOTO_STATION: {
-						SetDParam(0, v->current_order.dest);
-						SetDParam(1, v->cur_speed / 2);
-						str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
-					} break;
-
-					case OT_GOTO_DEPOT: {
-						Depot *depot = GetDepot(v->current_order.dest);
-						SetDParam(0, depot->town_index);
-						SetDParam(1, v->cur_speed / 2);
-						if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-							str = STR_HEADING_FOR_SHIP_DEPOT + _patches.vehicle_speed;
-						} else {
-							str = STR_HEADING_FOR_SHIP_DEPOT_SERVICE + _patches.vehicle_speed;
-						}
-					} break;
-
-					case OT_LOADING:
-					case OT_LEAVESTATION:
-						str = STR_882F_LOADING_UNLOADING;
-						break;
-
-					default:
-						if (v->num_orders == 0) {
-							str = STR_NO_ORDERS + _patches.vehicle_speed;
-							SetDParam(0, v->cur_speed / 2);
-						} else {
-							str = STR_EMPTY;
-						}
-						break;
-				}
-			}
-
-		/* draw the flag plus orders */
-		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
-		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
-		DrawWindowViewport(w);
-	} break;
-
-		case WE_CLICK: {
-			const Vehicle *v = GetVehicle(w->window_number);
-
-			switch (e->we.click.widget) {
-				case 5: /* start stop */
-					DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP));
-					break;
-				case 6: /* center main view */
-					ScrollMainWindowTo(v->x_pos, v->y_pos);
-					break;
-				case 7: /* goto hangar */
-					DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_SHIP_TO_DEPOT | CMD_MSG(STR_9819_CAN_T_SEND_SHIP_TO_DEPOT));
-					break;
-				case 8: /* refit */
-					ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
-					break;
-				case 9: /* show orders */
-					ShowOrdersWindow(v);
-					break;
-				case 10: /* show details */
-					ShowShipDetailsWindow(v);
-					break;
-				case 11: {
-					/* clone vehicle */
-					DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneShip, CMD_CLONE_VEHICLE | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
-				} break;
-			}
-		} break;
-
-		case WE_RESIZE:
-			w->viewport->width          += e->we.sizing.diff.x;
-			w->viewport->height         += e->we.sizing.diff.y;
-			w->viewport->virtual_width  += e->we.sizing.diff.x;
-			w->viewport->virtual_height += e->we.sizing.diff.y;
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
-			DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
-			DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
-			break;
-
-		case WE_MOUSELOOP: {
-			const Vehicle *v = GetVehicle(w->window_number);
-			bool ship_stopped = IsShipInDepotStopped(v);
-
-			/* Widget 7 (send to depot) must be hidden if the ship is already stopped in depot.
-			 * Widget 11 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
-			 * This sytem allows to have two buttons, on top of each otherother*/
-			if (ship_stopped != IsWindowWidgetHidden(w, 7) || ship_stopped == IsWindowWidgetHidden(w, 11)) {
-				SetWindowWidgetHiddenState(w,  7, ship_stopped);  // send to depot
-				SetWindowWidgetHiddenState(w, 11, !ship_stopped); // clone
-				SetWindowDirty(w);
-			}
-		}
-	}
-}
-
-static const Widget _ship_view_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_980F,                STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX, RESIZE_LR,    14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON},
-{      WWT_PANEL, RESIZE_RB,    14,   0, 231,  14, 103, 0x0,                     STR_NULL},
-{      WWT_INSET, RESIZE_RB,    14,   2, 229,  16, 101, 0x0,                     STR_NULL},
-{    WWT_PUSHBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,                     STR_9827_CURRENT_SHIP_ACTION_CLICK},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_9829_CENTER_MAIN_VIEW_ON_SHIP},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_SEND_SHIP_TODEPOT,   STR_982A_SEND_SHIP_TO_DEPOT},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,       STR_983A_REFIT_CARGO_SHIP_TO_CARRY},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, SPR_SHOW_ORDERS,         STR_9828_SHOW_SHIP_S_ORDERS},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS,STR_982B_SHOW_SHIP_DETAILS},
-{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_SHIP,          STR_CLONE_SHIP_INFO},
-{      WWT_PANEL, RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,                     STR_NULL },
-{  WWT_RESIZEBOX, RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                     STR_NULL },
-{ WIDGETS_END }
-};
-
-static const WindowDesc _ship_view_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 116,
-	WC_VEHICLE_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_ship_view_widgets,
-	ShipViewWndProc
-};
-
-void ShowShipViewWindow(const Vehicle *v)
-{
-	Window *w = AllocateWindowDescFront(&_ship_view_desc, v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/ship_gui.cpp
@@ -0,0 +1,527 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "ship.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "station.h"
+#include "command.h"
+#include "player.h"
+#include "engine.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "newgrf_engine.h"
+#include "date.h"
+
+/**
+ * Draw the purchase info details of a ship at a given location.
+ * @param x,y location where to draw the info
+ * @param engine_number the engine of which to draw the info of
+ */
+void DrawShipPurchaseInfo(int x, int y, uint w, EngineID engine_number)
+{
+	YearMonthDay ymd;
+	const ShipVehicleInfo *svi = ShipVehInfo(engine_number);
+	const Engine *e;
+
+	/* Purchase cost - Max speed */
+	SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5);
+	SetDParam(1, svi->max_speed / 2);
+	DrawString(x,y, STR_PURCHASE_INFO_COST_SPEED, 0);
+	y += 10;
+
+	/* Cargo type + capacity */
+	SetDParam(0, svi->cargo_type);
+	SetDParam(1, svi->capacity);
+	SetDParam(2, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY);
+	DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0);
+	y += 10;
+
+	/* Running cost */
+	SetDParam(0, svi->running_cost * _price.ship_running >> 8);
+	DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
+	y += 10;
+
+	/* Design date - Life length */
+	e = GetEngine(engine_number);
+	ConvertDateToYMD(e->intro_date, &ymd);
+	SetDParam(0, ymd.year);
+	SetDParam(1, e->lifelength);
+	DrawString(x,y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
+	y += 10;
+
+	/* Reliability */
+	SetDParam(0, e->reliability * 100 >> 16);
+	DrawString(x,y, STR_PURCHASE_INFO_RELIABILITY, 0);
+	y += 10;
+
+	/* Additional text from NewGRF */
+	y += ShowAdditionalText(x, y, w, engine_number);
+	if (svi->refittable) y += ShowRefitOptionsList(x, y, w, engine_number);
+}
+
+void DrawShipImage(const Vehicle *v, int x, int y, VehicleID selection)
+{
+	DrawSprite(GetShipImage(v, DIR_W) | GetVehiclePalette(v), x + 32, y + 10);
+
+	if (v->index == selection) {
+		DrawFrameRect(x - 5, y - 1, x + 67, y + 21, 15, FR_BORDERONLY);
+	}
+}
+
+static void ShipDetailsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		StringID str;
+
+		SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
+		// disable service-scroller when interval is set to disabled
+		SetWindowWidgetDisabledState(w, 5, !_patches.servint_ships);
+		SetWindowWidgetDisabledState(w, 6, !_patches.servint_ships);
+
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		/* Draw running cost */
+		{
+			int year = v->age / 366;
+
+			SetDParam(1, year);
+
+			SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+			SetDParam(2, v->max_age / 366);
+			SetDParam(3, ShipVehInfo(v->engine_type)->running_cost * _price.ship_running >> 8);
+			DrawString(2, 15, STR_9812_AGE_RUNNING_COST_YR, 0);
+		}
+
+		/* Draw max speed */
+		{
+			SetDParam(0, v->max_speed / 2);
+			DrawString(2, 25, STR_9813_MAX_SPEED, 0);
+		}
+
+		/* Draw profit */
+		{
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(2, 35, STR_9814_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+		}
+
+		/* Draw breakdown & reliability */
+		{
+			SetDParam(0, v->reliability * 100 >> 16);
+			SetDParam(1, v->breakdowns_since_last_service);
+			DrawString(2, 45, STR_9815_RELIABILITY_BREAKDOWNS, 0);
+		}
+
+		/* Draw service interval text */
+		{
+			SetDParam(0, v->service_interval);
+			SetDParam(1, v->date_of_last_service);
+			DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
+		}
+
+		DrawShipImage(v, 3, 57, INVALID_VEHICLE);
+
+		SetDParam(1, v->build_year);
+		SetDParam(0, GetCustomEngineName(v->engine_type));
+		SetDParam(2, v->value);
+		DrawString(74, 57, STR_9816_BUILT_VALUE, 0);
+
+		SetDParam(0, v->cargo_type);
+		SetDParam(1, v->cargo_cap);
+		DrawString(74, 67, STR_9817_CAPACITY, 0);
+
+		str = STR_8812_EMPTY;
+		if (v->cargo_count != 0) {
+			SetDParam(0, v->cargo_type);
+			SetDParam(1, v->cargo_count);
+			SetDParam(2, v->cargo_source);
+			str = STR_8813_FROM;
+		}
+		DrawString(74, 78, str, 0);
+	} break;
+
+	case WE_CLICK: {
+		int mod;
+		const Vehicle *v;
+		switch (e->we.click.widget) {
+		case 2: /* rename */
+			v = GetVehicle(w->window_number);
+			SetDParam(0, v->unitnumber);
+			ShowQueryString(v->string_id, STR_9831_NAME_SHIP, 31, 150, w, CS_ALPHANUMERAL);
+			break;
+		case 5: /* increase int */
+			mod = _ctrl_pressed? 5 : 10;
+			goto do_change_service_int;
+		case 6: /* decrease int */
+			mod = _ctrl_pressed?- 5 : -10;
+do_change_service_int:
+			v = GetVehicle(w->window_number);
+
+			mod = GetServiceIntervalClamped(mod + v->service_interval);
+			if (mod == v->service_interval) return;
+
+			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+			break;
+		}
+	} break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_NAME_VEHICLE | CMD_MSG(STR_9832_CAN_T_NAME_SHIP));
+		}
+		break;
+	}
+}
+
+
+static const Widget _ship_details_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   364,     0,    13, STR_9811_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   365,   404,     0,    13, STR_01AA_NAME,    STR_982F_NAME_SHIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   404,    14,    55, 0x0,              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   404,    56,    88, 0x0,              STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    89,    94, STR_0188,         STR_884D_INCREASE_SERVICING_INTERVAL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    10,    95,   100, STR_0189,         STR_884E_DECREASE_SERVICING_INTERVAL},
+{      WWT_PANEL,   RESIZE_NONE,    14,    11,   404,    89,   100, 0x0,              STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _ship_details_desc = {
+	WDP_AUTO, WDP_AUTO, 405, 101,
+	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_ship_details_widgets,
+	ShipDetailsWndProc
+};
+
+static void ShowShipDetailsWindow(const Vehicle *v)
+{
+	Window *w;
+	VehicleID veh = v->index;
+
+	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
+	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
+	w = AllocateWindowDescFront(&_ship_details_desc, veh);
+	w->caption_color = v->owner;
+}
+
+void CcBuildShip(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	const Vehicle *v;
+	if (!success) return;
+
+	v = GetVehicle(_new_vehicle_id);
+	if (v->tile == _backup_orders_tile) {
+		_backup_orders_tile = 0;
+		RestoreVehicleOrders(v, _backup_orders_data);
+	}
+	ShowShipViewWindow(v);
+}
+
+void CcCloneShip(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) ShowShipViewWindow(GetVehicle(_new_vehicle_id));
+}
+
+static void NewShipWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			EngineID selected_id;
+			EngineID eid;
+			int count;
+			int pos;
+			int sel;
+			int y;
+
+			SetWindowWidgetDisabledState(w, 5, w->window_number == 0);
+
+			count = 0;
+			for (eid = SHIP_ENGINES_INDEX; eid < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; eid++) {
+				if (HASBIT(GetEngine(eid)->player_avail, _local_player)) count++;
+			}
+			SetVScrollCount(w, count);
+
+			DrawWindowWidgets(w);
+
+			y = 15;
+			sel = WP(w,buildvehicle_d).sel_index;
+			pos = w->vscroll.pos;
+			selected_id = INVALID_ENGINE;
+			for (eid = SHIP_ENGINES_INDEX; eid < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; eid++) {
+				if (!HASBIT(GetEngine(eid)->player_avail, _local_player)) continue;
+				if (sel == 0) selected_id = eid;
+				if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
+					DrawString(77, y + 7, GetCustomEngineName(eid), sel == 0 ? 0xC : 0x10);
+					DrawShipEngine(37, y + 10, eid, GetEnginePalette(eid, _local_player));
+					y += 24;
+				}
+				sel--;
+			}
+
+			WP(w,buildvehicle_d).sel_engine = selected_id;
+
+			if (selected_id != INVALID_ENGINE) {
+				const Widget *wi = &w->widget[4];
+				DrawShipPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
+			}
+			break;
+		}
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 2: { /* listbox */
+			uint i = (e->we.click.pt.y - 14) / 24;
+			if (i < w->vscroll.cap) {
+				WP(w,buildvehicle_d).sel_index = i + w->vscroll.pos;
+				SetWindowDirty(w);
+			}
+		} break;
+		case 5: { /* build */
+			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
+			if (sel_eng != INVALID_ENGINE)
+				DoCommandP(w->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
+		} break;
+
+		case 6: { /* rename */
+			EngineID sel_eng = WP(w,buildvehicle_d).sel_engine;
+			if (sel_eng != INVALID_ENGINE) {
+				WP(w, buildvehicle_d).rename_engine = sel_eng;
+				ShowQueryString(GetCustomEngineName(sel_eng), STR_9838_RENAME_SHIP_TYPE, 31, 160, w, CS_ALPHANUMERAL);
+			}
+		}	break;
+		}
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, WP(w, buildvehicle_d).rename_engine, 0, NULL,
+				CMD_RENAME_ENGINE | CMD_MSG(STR_9839_CAN_T_RENAME_SHIP_TYPE));
+		}
+		break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 24;
+		w->widget[2].data = (w->vscroll.cap << 8) + 1;
+		break;
+
+	}
+}
+
+static const Widget _new_ship_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   254,     0,    13, STR_9808_NEW_SHIPS,  STR_018C_WINDOW_TITLE_DRAG_THIS},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   242,    14,   109, 0x401,               STR_9825_SHIP_SELECTION_LIST_CLICK},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   243,   254,    14,   109, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    14,     0,   254,   110,   201, 0x0,                 STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   121,   202,   213, STR_9809_BUILD_SHIP, STR_9826_BUILD_THE_HIGHLIGHTED_SHIP},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   122,   242,   202,   213, STR_9836_RENAME,     STR_9837_RENAME_SHIP_TYPE},
+{  WWT_RESIZEBOX,     RESIZE_TB,    14,   243,   254,   202,   213, 0x0,                 STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _new_ship_desc = {
+	WDP_AUTO, WDP_AUTO, 255, 214,
+	WC_BUILD_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_new_ship_widgets,
+	NewShipWndProc
+};
+
+
+void ShowBuildShipWindow(TileIndex tile)
+{
+	Window *w;
+
+	DeleteWindowById(WC_BUILD_VEHICLE, tile);
+
+	w = AllocateWindowDescFront(&_new_ship_desc, tile);
+	w->vscroll.cap = 4;
+	w->widget[2].data = (w->vscroll.cap << 8) + 1;
+
+	w->resize.step_height = 24;
+
+	if (tile != 0) {
+		w->caption_color = GetTileOwner(tile);
+	} else {
+		w->caption_color = _local_player;
+	}
+
+}
+
+
+static void ShipViewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			Vehicle *v = GetVehicle(w->window_number);
+			StringID str;
+			bool refitable_and_stopped_in_depot = ShipVehInfo(v->engine_type)->refittable && IsShipInDepotStopped(v);
+			bool is_localplayer = v->owner == _local_player;
+
+			SetWindowWidgetDisabledState(w,  7, !is_localplayer);
+			SetWindowWidgetDisabledState(w,  8,
+			                             !is_localplayer ||      // Disable if owner is not local player
+			                             !refitable_and_stopped_in_depot); // Disable if the ship is not refitable or stopped in a depot
+			SetWindowWidgetDisabledState(w, 11, !is_localplayer);
+
+			/* draw widgets & caption */
+			SetDParam(0, v->string_id);
+			SetDParam(1, v->unitnumber);
+			DrawWindowWidgets(w);
+
+			if (v->breakdown_ctr == 1) {
+				str = STR_885C_BROKEN_DOWN;
+			} else if (v->vehstatus & VS_STOPPED) {
+				str = STR_8861_STOPPED;
+			} else {
+				switch (v->current_order.type) {
+					case OT_GOTO_STATION: {
+						SetDParam(0, v->current_order.dest);
+						SetDParam(1, v->cur_speed / 2);
+						str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+					} break;
+
+					case OT_GOTO_DEPOT: {
+						Depot *depot = GetDepot(v->current_order.dest);
+						SetDParam(0, depot->town_index);
+						SetDParam(1, v->cur_speed / 2);
+						if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
+							str = STR_HEADING_FOR_SHIP_DEPOT + _patches.vehicle_speed;
+						} else {
+							str = STR_HEADING_FOR_SHIP_DEPOT_SERVICE + _patches.vehicle_speed;
+						}
+					} break;
+
+					case OT_LOADING:
+					case OT_LEAVESTATION:
+						str = STR_882F_LOADING_UNLOADING;
+						break;
+
+					default:
+						if (v->num_orders == 0) {
+							str = STR_NO_ORDERS + _patches.vehicle_speed;
+							SetDParam(0, v->cur_speed / 2);
+						} else {
+							str = STR_EMPTY;
+						}
+						break;
+				}
+			}
+
+		/* draw the flag plus orders */
+		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
+		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
+		DrawWindowViewport(w);
+	} break;
+
+		case WE_CLICK: {
+			const Vehicle *v = GetVehicle(w->window_number);
+
+			switch (e->we.click.widget) {
+				case 5: /* start stop */
+					DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP));
+					break;
+				case 6: /* center main view */
+					ScrollMainWindowTo(v->x_pos, v->y_pos);
+					break;
+				case 7: /* goto hangar */
+					DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_SHIP_TO_DEPOT | CMD_MSG(STR_9819_CAN_T_SEND_SHIP_TO_DEPOT));
+					break;
+				case 8: /* refit */
+					ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+					break;
+				case 9: /* show orders */
+					ShowOrdersWindow(v);
+					break;
+				case 10: /* show details */
+					ShowShipDetailsWindow(v);
+					break;
+				case 11: {
+					/* clone vehicle */
+					DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneShip, CMD_CLONE_VEHICLE | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
+				} break;
+			}
+		} break;
+
+		case WE_RESIZE:
+			w->viewport->width          += e->we.sizing.diff.x;
+			w->viewport->height         += e->we.sizing.diff.y;
+			w->viewport->virtual_width  += e->we.sizing.diff.x;
+			w->viewport->virtual_height += e->we.sizing.diff.y;
+			break;
+
+		case WE_DESTROY:
+			DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
+			DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
+			DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
+			break;
+
+		case WE_MOUSELOOP: {
+			const Vehicle *v = GetVehicle(w->window_number);
+			bool ship_stopped = IsShipInDepotStopped(v);
+
+			/* Widget 7 (send to depot) must be hidden if the ship is already stopped in depot.
+			 * Widget 11 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
+			 * This sytem allows to have two buttons, on top of each otherother*/
+			if (ship_stopped != IsWindowWidgetHidden(w, 7) || ship_stopped == IsWindowWidgetHidden(w, 11)) {
+				SetWindowWidgetHiddenState(w,  7, ship_stopped);  // send to depot
+				SetWindowWidgetHiddenState(w, 11, !ship_stopped); // clone
+				SetWindowDirty(w);
+			}
+		}
+	}
+}
+
+static const Widget _ship_view_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_980F,                STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX, RESIZE_LR,    14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON},
+{      WWT_PANEL, RESIZE_RB,    14,   0, 231,  14, 103, 0x0,                     STR_NULL},
+{      WWT_INSET, RESIZE_RB,    14,   2, 229,  16, 101, 0x0,                     STR_NULL},
+{    WWT_PUSHBTN, RESIZE_RTB,   14,   0, 237, 104, 115, 0x0,                     STR_9827_CURRENT_SHIP_ACTION_CLICK},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_9829_CENTER_MAIN_VIEW_ON_SHIP},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_SEND_SHIP_TODEPOT,   STR_982A_SEND_SHIP_TO_DEPOT},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  50,  67, SPR_REFIT_VEHICLE,       STR_983A_REFIT_CARGO_SHIP_TO_CARRY},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  68,  85, SPR_SHOW_ORDERS,         STR_9828_SHOW_SHIP_S_ORDERS},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  86, 103, SPR_SHOW_VEHICLE_DETAILS,STR_982B_SHOW_SHIP_DETAILS},
+{ WWT_PUSHIMGBTN, RESIZE_LR,    14, 232, 249,  32,  49, SPR_CLONE_SHIP,          STR_CLONE_SHIP_INFO},
+{      WWT_PANEL, RESIZE_LRB,   14, 232, 249, 104, 103, 0x0,                     STR_NULL },
+{  WWT_RESIZEBOX, RESIZE_LRTB,  14, 238, 249, 104, 115, 0x0,                     STR_NULL },
+{ WIDGETS_END }
+};
+
+static const WindowDesc _ship_view_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 116,
+	WC_VEHICLE_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_ship_view_widgets,
+	ShipViewWndProc
+};
+
+void ShowShipViewWindow(const Vehicle *v)
+{
+	Window *w = AllocateWindowDescFront(&_ship_view_desc, v->index);
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
+	}
+}
deleted file mode 100644
--- a/src/signs.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "player.h"
-#include "signs.h"
-#include "saveload.h"
-#include "command.h"
-#include "variables.h"
-
-static Sign *_new_sign;
-
-/**
- * Called if a new block is added to the sign-pool
- */
-static void SignPoolNewBlock(uint start_item)
-{
-	Sign *si;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (si = GetSign(start_item); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) si->index = start_item++;
-}
-
-/* Initialize the sign-pool */
-DEFINE_OLD_POOL(Sign, Sign, SignPoolNewBlock, NULL)
-
-/**
- *
- * Update the coordinate of one sign
- *
- */
-static void UpdateSignVirtCoords(Sign *si)
-{
-	Point pt = RemapCoords(si->x, si->y, si->z);
-	SetDParam(0, si->str);
-	UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806);
-}
-
-/**
- *
- * Update the coordinates of all signs
- *
- */
-void UpdateAllSignVirtCoords(void)
-{
-	Sign *si;
-
-	FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si);
-
-}
-
-/**
- *
- * Marks the region of a sign as dirty
- *
- * @param si Pointer to the Sign
- */
-static void MarkSignDirty(Sign *si)
-{
-	MarkAllViewportsDirty(
-		si->sign.left - 6,
-		si->sign.top  - 3,
-		si->sign.left + si->sign.width_1 * 4 + 12,
-		si->sign.top  + 45);
-}
-
-/**
- *
- * Allocates a new sign
- *
- * @return The pointer to the new sign, or NULL if there is no more free space
- */
-static Sign *AllocateSign(void)
-{
-	Sign *si;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (si = GetSign(0); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) {
-		if (!IsValidSign(si)) {
-			uint index = si->index;
-
-			memset(si, 0, sizeof(Sign));
-			si->index = index;
-
-			return si;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Sign_pool))
-		return AllocateSign();
-
-	return NULL;
-}
-
-void DestroySign(Sign *si)
-{
-	DeleteName(si->str);
-}
-
-/**
- * Place a sign at the given coordinates. Ownership of sign has
- * no effect whatsoever except for the colour the sign gets for easy recognition,
- * but everybody is able to rename/remove it.
- * @param tile tile to place sign at
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdPlaceSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Sign *si;
-
-	/* Try to locate a new sign */
-	si = AllocateSign();
-	if (si == NULL) return_cmd_error(STR_2808_TOO_MANY_SIGNS);
-
-	/* When we execute, really make the sign */
-	if (flags & DC_EXEC) {
-		int x = TileX(tile) * TILE_SIZE;
-		int y = TileY(tile) * TILE_SIZE;
-
-		si->str = STR_280A_SIGN;
-		si->x = x;
-		si->y = y;
-		si->owner = _current_player; // owner of the sign; just eyecandy
-		si->z = GetSlopeZ(x,y);
-		UpdateSignVirtCoords(si);
-		MarkSignDirty(si);
-		InvalidateWindow(WC_SIGN_LIST, 0);
-		_sign_sort_dirty = true;
-		_new_sign = si;
-	}
-
-	return 0;
-}
-
-/** Rename a sign. If the new name of the sign is empty, we assume
- * the user wanted to delete it. So delete it. Ownership of signs
- * has no meaning/effect whatsoever except for eyecandy
- * @param tile unused
- * @param p1 index of the sign to be renamed/removed
- * @param p2 unused
- */
-int32 CmdRenameSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	if (!IsValidSignID(p1)) return CMD_ERROR;
-
-	/* If _cmd_text 0 means the new text for the sign is non-empty.
-	 * So rename the sign. If it is empty, it has no name, so delete it */
-	if (_cmd_text[0] != '\0') {
-		/* Create the name */
-		StringID str = AllocateName(_cmd_text, 0);
-		if (str == 0) return CMD_ERROR;
-
-		if (flags & DC_EXEC) {
-			Sign *si = GetSign(p1);
-
-			/* Delete the old name */
-			DeleteName(si->str);
-			/* Assign the new one */
-			si->str = str;
-			si->owner = _current_player;
-
-			/* Update; mark sign dirty twice, because it can either becom longer, or shorter */
-			MarkSignDirty(si);
-			UpdateSignVirtCoords(si);
-			MarkSignDirty(si);
-			InvalidateWindow(WC_SIGN_LIST, 0);
-			_sign_sort_dirty = true;
-		} else {
-			/* Free the name, because we did not assign it yet */
-			DeleteName(str);
-		}
-	} else { /* Delete sign */
-		if (flags & DC_EXEC) {
-			Sign *si = GetSign(p1);
-
-			MarkSignDirty(si);
-			DeleteSign(si);
-
-			InvalidateWindow(WC_SIGN_LIST, 0);
-			_sign_sort_dirty = true;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *
- * Callback function that is called after a sign is placed
- *
- */
-void CcPlaceSign(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		ShowRenameSignWindow(_new_sign);
-		ResetObjectToPlace();
-	}
-}
-
-/**
- *
- * PlaceProc function, called when someone pressed the button if the
- *  sign-tool is selected
- *
- */
-void PlaceProc_Sign(TileIndex tile)
-{
-	DoCommandP(tile, 0, 0, CcPlaceSign, CMD_PLACE_SIGN | CMD_MSG(STR_2809_CAN_T_PLACE_SIGN_HERE));
-}
-
-/**
- *
- * Initialize the signs
- *
- */
-void InitializeSigns(void)
-{
-	CleanPool(&_Sign_pool);
-	AddBlockToPool(&_Sign_pool);
-}
-
-static const SaveLoad _sign_desc[] = {
-      SLE_VAR(Sign, str,   SLE_UINT16),
-  SLE_CONDVAR(Sign, x,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
-  SLE_CONDVAR(Sign, y,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
-  SLE_CONDVAR(Sign, x,     SLE_INT32,                  5, SL_MAX_VERSION),
-  SLE_CONDVAR(Sign, y,     SLE_INT32,                  5, SL_MAX_VERSION),
-  SLE_CONDVAR(Sign, owner, SLE_UINT8,                  6, SL_MAX_VERSION),
-      SLE_VAR(Sign, z,     SLE_UINT8),
-	SLE_END()
-};
-
-/**
- *
- * Save all signs
- *
- */
-static void Save_SIGN(void)
-{
-	Sign *si;
-
-	FOR_ALL_SIGNS(si) {
-		SlSetArrayIndex(si->index);
-		SlObject(si, _sign_desc);
-	}
-}
-
-/**
- *
- * Load all signs
- *
- */
-static void Load_SIGN(void)
-{
-	int index;
-	while ((index = SlIterateArray()) != -1) {
-		Sign *si;
-
-		if (!AddBlockIfNeeded(&_Sign_pool, index))
-			error("Signs: failed loading savegame: too many signs");
-
-		si = GetSign(index);
-		SlObject(si, _sign_desc);
-	}
-
-	_sign_sort_dirty = true;
-}
-
-const ChunkHandler _sign_chunk_handlers[] = {
-	{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/signs.cpp
@@ -0,0 +1,277 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "player.h"
+#include "signs.h"
+#include "saveload.h"
+#include "command.h"
+#include "variables.h"
+
+static Sign *_new_sign;
+
+/**
+ * Called if a new block is added to the sign-pool
+ */
+static void SignPoolNewBlock(uint start_item)
+{
+	Sign *si;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (si = GetSign(start_item); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) si->index = start_item++;
+}
+
+/* Initialize the sign-pool */
+DEFINE_OLD_POOL(Sign, Sign, SignPoolNewBlock, NULL)
+
+/**
+ *
+ * Update the coordinate of one sign
+ *
+ */
+static void UpdateSignVirtCoords(Sign *si)
+{
+	Point pt = RemapCoords(si->x, si->y, si->z);
+	SetDParam(0, si->str);
+	UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806);
+}
+
+/**
+ *
+ * Update the coordinates of all signs
+ *
+ */
+void UpdateAllSignVirtCoords(void)
+{
+	Sign *si;
+
+	FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si);
+
+}
+
+/**
+ *
+ * Marks the region of a sign as dirty
+ *
+ * @param si Pointer to the Sign
+ */
+static void MarkSignDirty(Sign *si)
+{
+	MarkAllViewportsDirty(
+		si->sign.left - 6,
+		si->sign.top  - 3,
+		si->sign.left + si->sign.width_1 * 4 + 12,
+		si->sign.top  + 45);
+}
+
+/**
+ *
+ * Allocates a new sign
+ *
+ * @return The pointer to the new sign, or NULL if there is no more free space
+ */
+static Sign *AllocateSign(void)
+{
+	Sign *si;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (si = GetSign(0); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) {
+		if (!IsValidSign(si)) {
+			uint index = si->index;
+
+			memset(si, 0, sizeof(Sign));
+			si->index = index;
+
+			return si;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Sign_pool))
+		return AllocateSign();
+
+	return NULL;
+}
+
+void DestroySign(Sign *si)
+{
+	DeleteName(si->str);
+}
+
+/**
+ * Place a sign at the given coordinates. Ownership of sign has
+ * no effect whatsoever except for the colour the sign gets for easy recognition,
+ * but everybody is able to rename/remove it.
+ * @param tile tile to place sign at
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdPlaceSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Sign *si;
+
+	/* Try to locate a new sign */
+	si = AllocateSign();
+	if (si == NULL) return_cmd_error(STR_2808_TOO_MANY_SIGNS);
+
+	/* When we execute, really make the sign */
+	if (flags & DC_EXEC) {
+		int x = TileX(tile) * TILE_SIZE;
+		int y = TileY(tile) * TILE_SIZE;
+
+		si->str = STR_280A_SIGN;
+		si->x = x;
+		si->y = y;
+		si->owner = _current_player; // owner of the sign; just eyecandy
+		si->z = GetSlopeZ(x,y);
+		UpdateSignVirtCoords(si);
+		MarkSignDirty(si);
+		InvalidateWindow(WC_SIGN_LIST, 0);
+		_sign_sort_dirty = true;
+		_new_sign = si;
+	}
+
+	return 0;
+}
+
+/** Rename a sign. If the new name of the sign is empty, we assume
+ * the user wanted to delete it. So delete it. Ownership of signs
+ * has no meaning/effect whatsoever except for eyecandy
+ * @param tile unused
+ * @param p1 index of the sign to be renamed/removed
+ * @param p2 unused
+ */
+int32 CmdRenameSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	if (!IsValidSignID(p1)) return CMD_ERROR;
+
+	/* If _cmd_text 0 means the new text for the sign is non-empty.
+	 * So rename the sign. If it is empty, it has no name, so delete it */
+	if (_cmd_text[0] != '\0') {
+		/* Create the name */
+		StringID str = AllocateName(_cmd_text, 0);
+		if (str == 0) return CMD_ERROR;
+
+		if (flags & DC_EXEC) {
+			Sign *si = GetSign(p1);
+
+			/* Delete the old name */
+			DeleteName(si->str);
+			/* Assign the new one */
+			si->str = str;
+			si->owner = _current_player;
+
+			/* Update; mark sign dirty twice, because it can either becom longer, or shorter */
+			MarkSignDirty(si);
+			UpdateSignVirtCoords(si);
+			MarkSignDirty(si);
+			InvalidateWindow(WC_SIGN_LIST, 0);
+			_sign_sort_dirty = true;
+		} else {
+			/* Free the name, because we did not assign it yet */
+			DeleteName(str);
+		}
+	} else { /* Delete sign */
+		if (flags & DC_EXEC) {
+			Sign *si = GetSign(p1);
+
+			MarkSignDirty(si);
+			DeleteSign(si);
+
+			InvalidateWindow(WC_SIGN_LIST, 0);
+			_sign_sort_dirty = true;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *
+ * Callback function that is called after a sign is placed
+ *
+ */
+void CcPlaceSign(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		ShowRenameSignWindow(_new_sign);
+		ResetObjectToPlace();
+	}
+}
+
+/**
+ *
+ * PlaceProc function, called when someone pressed the button if the
+ *  sign-tool is selected
+ *
+ */
+void PlaceProc_Sign(TileIndex tile)
+{
+	DoCommandP(tile, 0, 0, CcPlaceSign, CMD_PLACE_SIGN | CMD_MSG(STR_2809_CAN_T_PLACE_SIGN_HERE));
+}
+
+/**
+ *
+ * Initialize the signs
+ *
+ */
+void InitializeSigns(void)
+{
+	CleanPool(&_Sign_pool);
+	AddBlockToPool(&_Sign_pool);
+}
+
+static const SaveLoad _sign_desc[] = {
+      SLE_VAR(Sign, str,   SLE_UINT16),
+  SLE_CONDVAR(Sign, x,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
+  SLE_CONDVAR(Sign, y,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
+  SLE_CONDVAR(Sign, x,     SLE_INT32,                  5, SL_MAX_VERSION),
+  SLE_CONDVAR(Sign, y,     SLE_INT32,                  5, SL_MAX_VERSION),
+  SLE_CONDVAR(Sign, owner, SLE_UINT8,                  6, SL_MAX_VERSION),
+      SLE_VAR(Sign, z,     SLE_UINT8),
+	SLE_END()
+};
+
+/**
+ *
+ * Save all signs
+ *
+ */
+static void Save_SIGN(void)
+{
+	Sign *si;
+
+	FOR_ALL_SIGNS(si) {
+		SlSetArrayIndex(si->index);
+		SlObject(si, _sign_desc);
+	}
+}
+
+/**
+ *
+ * Load all signs
+ *
+ */
+static void Load_SIGN(void)
+{
+	int index;
+	while ((index = SlIterateArray()) != -1) {
+		Sign *si;
+
+		if (!AddBlockIfNeeded(&_Sign_pool, index))
+			error("Signs: failed loading savegame: too many signs");
+
+		si = GetSign(index);
+		SlObject(si, _sign_desc);
+	}
+
+	_sign_sort_dirty = true;
+}
+
+const ChunkHandler _sign_chunk_handlers[] = {
+	{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/smallmap_gui.c
+++ /dev/null
@@ -1,1114 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "bridge_map.h"
-#include "clear_map.h"
-#include "industry_map.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "tile.h"
-#include "gui.h"
-#include "tree_map.h"
-#include "tunnel_map.h"
-#include "window.h"
-#include "gfx.h"
-#include "viewport.h"
-#include "player.h"
-#include "vehicle.h"
-#include "town.h"
-#include "sound.h"
-#include "variables.h"
-
-static const Widget _smallmap_widgets[] = {
-{  WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{   WWT_CAPTION,  RESIZE_RIGHT,    13,    11,   433,     0,    13, STR_00B0_MAP,            STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_STICKYBOX,     RESIZE_LR,    13,   434,   445,     0,    13, 0x0,                     STR_STICKY_BUTTON},
-{     WWT_PANEL,     RESIZE_RB,    13,     0,   445,    14,   257, 0x0,                     STR_NULL},
-{     WWT_INSET,     RESIZE_RB,    13,     2,   443,    16,   255, 0x0,                     STR_NULL},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   380,   401,   258,   279, SPR_IMG_SHOW_COUNTOURS,  STR_0191_SHOW_LAND_CONTOURS_ON_MAP},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   402,   423,   258,   279, SPR_IMG_SHOW_VEHICLES,   STR_0192_SHOW_VEHICLES_ON_MAP},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   424,   445,   258,   279, SPR_IMG_INDUSTRY,        STR_0193_SHOW_INDUSTRIES_ON_MAP},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   380,   401,   280,   301, SPR_IMG_SHOW_ROUTES,     STR_0194_SHOW_TRANSPORT_ROUTES_ON},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   402,   423,   280,   301, SPR_IMG_PLANTTREES,      STR_0195_SHOW_VEGETATION_ON_MAP},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   424,   445,   280,   301, SPR_IMG_COMPANY_GENERAL, STR_0196_SHOW_LAND_OWNERS_ON_MAP},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   358,   379,   258,   279, SPR_IMG_SMALLMAP,        STR_SMALLMAP_CENTER},
-{    WWT_IMGBTN,   RESIZE_LRTB,    13,   358,   379,   280,   301, SPR_IMG_TOWN,            STR_0197_TOGGLE_TOWN_NAMES_ON_OFF},
-{     WWT_PANEL,    RESIZE_RTB,    13,     0,   357,   258,   301, 0x0,                     STR_NULL},
-{     WWT_PANEL,    RESIZE_RTB,    13,     0,   433,   302,   313, 0x0,                     STR_NULL},
-{ WWT_RESIZEBOX,   RESIZE_LRTB,    13,   434,   445,   302,   313, 0x0,                     STR_RESIZE_BUTTON},
-{  WIDGETS_END},
-};
-
-static int _smallmap_type;
-static bool _smallmap_show_towns = true;
-
-#define MK(a,b) a, b
-#define MKEND() 0xFFFF
-#define MS(a,b) (a | 0x100), b
-
-/* Legend text giving the colours to look for on the minimap */
-static const uint16 _legend_land_contours[] = {
-	MK(0x5A, STR_00F0_100M),
-	MK(0x5C, STR_00F1_200M),
-	MK(0x5E, STR_00F2_300M),
-	MK(0x1F, STR_00F3_400M),
-	MK(0x27, STR_00F4_500M),
-
-	MS(0xD7, STR_00EB_ROADS),
-	MK(0x0A, STR_00EC_RAILROADS),
-	MK(0x98, STR_00ED_STATIONS_AIRPORTS_DOCKS),
-	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
-	MK(0x0F, STR_00EF_VEHICLES),
-	MKEND()
-};
-
-static const uint16 _legend_vehicles[] = {
-	MK(0xB8, STR_00F5_TRAINS),
-	MK(0xBF, STR_00F6_ROAD_VEHICLES),
-	MK(0x98, STR_00F7_SHIPS),
-	MK(0x0F, STR_00F8_AIRCRAFT),
-	MS(0xD7, STR_00F9_TRANSPORT_ROUTES),
-	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
-	MKEND()
-};
-
-static const uint16 _legend_industries_normal[] = {
-	MK(0xD7, STR_00FA_COAL_MINE),
-	MK(0xB8, STR_00FB_POWER_STATION),
-	MK(0x56, STR_00FC_FOREST),
-	MK(0xC2, STR_00FD_SAWMILL),
-	MK(0xBF, STR_00FE_OIL_REFINERY),
-	MK(0x0F, STR_0105_BANK),
-
-	MS(0x30, STR_00FF_FARM),
-	MK(0xAE, STR_0100_FACTORY),
-	MK(0x98, STR_0102_OIL_WELLS),
-	MK(0x37, STR_0103_IRON_ORE_MINE),
-	MK(0x0A, STR_0104_STEEL_MILL),
-	MKEND()
-};
-
-static const uint16 _legend_industries_hilly[] = {
-	MK(0xD7, STR_00FA_COAL_MINE),
-	MK(0xB8, STR_00FB_POWER_STATION),
-	MK(0x56, STR_00FC_FOREST),
-	MK(0x0A, STR_0106_PAPER_MILL),
-	MK(0xBF, STR_00FE_OIL_REFINERY),
-	MK(0x37, STR_0108_FOOD_PROCESSING_PLANT),
-	MS(0x30, STR_00FF_FARM),
-
-	MK(0xAE, STR_0101_PRINTING_WORKS),
-	MK(0x98, STR_0102_OIL_WELLS),
-	MK(0xC2, STR_0107_GOLD_MINE),
-	MK(0x0F, STR_0105_BANK),
-	MKEND()
-};
-
-static const uint16 _legend_industries_desert[] = {
-	MK(0xBF, STR_00FE_OIL_REFINERY),
-	MK(0x98, STR_0102_OIL_WELLS),
-	MK(0x0F, STR_0105_BANK),
-	MK(0xB8, STR_0109_DIAMOND_MINE),
-	MK(0x37, STR_0108_FOOD_PROCESSING_PLANT),
-	MK(0x0A, STR_010A_COPPER_ORE_MINE),
-	MK(0x30, STR_00FF_FARM),
-	MS(0x56, STR_010B_FRUIT_PLANTATION),
-
-	MK(0x27, STR_010C_RUBBER_PLANTATION),
-	MK(0x25, STR_010D_WATER_SUPPLY),
-	MK(0xD0, STR_010E_WATER_TOWER),
-	MK(0xAE, STR_0100_FACTORY),
-	MK(0xC2, STR_010F_LUMBER_MILL),
-	MKEND()
-};
-
-static const uint16 _legend_industries_candy[] = {
-	MK(0x30, STR_0110_COTTON_CANDY_FOREST),
-	MK(0xAE, STR_0111_CANDY_FACTORY),
-	MK(0x27, STR_0112_BATTERY_FARM),
-	MK(0x37, STR_0113_COLA_WELLS),
-	MK(0xD0, STR_0114_TOY_SHOP),
-	MK(0x0A, STR_0115_TOY_FACTORY),
-	MS(0x25, STR_0116_PLASTIC_FOUNTAINS),
-
-	MK(0xB8, STR_0117_FIZZY_DRINK_FACTORY),
-	MK(0x98, STR_0118_BUBBLE_GENERATOR),
-	MK(0xC2, STR_0119_TOFFEE_QUARRY),
-	MK(0x0F, STR_011A_SUGAR_MINE),
-	MKEND()
-};
-
-static const uint16 _legend_routes[] = {
-	MK(0xD7, STR_00EB_ROADS),
-	MK(0x0A, STR_00EC_RAILROADS),
-	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
-	MS(0x56, STR_011B_RAILROAD_STATION),
-
-	MK(0xC2, STR_011C_TRUCK_LOADING_BAY),
-	MK(0xBF, STR_011D_BUS_STATION),
-	MK(0xB8, STR_011E_AIRPORT_HELIPORT),
-	MK(0x98, STR_011F_DOCK),
-	MKEND()
-};
-
-static const uint16 _legend_vegetation[] = {
-	MK(0x52, STR_0120_ROUGH_LAND),
-	MK(0x54, STR_0121_GRASS_LAND),
-	MK(0x37, STR_0122_BARE_LAND),
-	MK(0x25, STR_0123_FIELDS),
-	MK(0x57, STR_0124_TREES),
-	MK(0xD0, STR_00FC_FOREST),
-	MS(0x0A, STR_0125_ROCKS),
-
-	MK(0xC2, STR_012A_DESERT),
-	MK(0x98, STR_012B_SNOW),
-	MK(0xD7, STR_00F9_TRANSPORT_ROUTES),
-	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
-	MKEND()
-};
-
-static const uint16 _legend_land_owners[] = {
-	MK(0xCA, STR_0126_WATER),
-	MK(0x54, STR_0127_NO_OWNER),
-	MK(0xB4, STR_0128_TOWNS),
-	MK(0x20, STR_0129_INDUSTRIES),
-	MKEND()
-};
-#undef MK
-#undef MS
-#undef MKEND
-
-
-enum { IND_OFFS = 6 };
-static const uint16 * const _legend_table[] = {
-	_legend_land_contours,
-	_legend_vehicles,
-	NULL,
-	_legend_routes,
-	_legend_vegetation,
-	_legend_land_owners,
-
-	_legend_industries_normal,
-	_legend_industries_hilly,
-	_legend_industries_desert,
-	_legend_industries_candy,
-};
-
-#if defined(OTTD_ALIGNMENT)
-	static inline void WRITE_PIXELS(Pixel* d, uint32 val)
-	{
-#	if defined(TTD_BIG_ENDIAN)
-		d[0] = GB(val, 24, 8);
-		d[1] = GB(val, 16, 8);
-		d[2] = GB(val,  8, 8);
-		d[3] = GB(val,  0, 8);
-#	elif defined(TTD_LITTLE_ENDIAN)
-		d[0] = GB(val,  0, 8);
-		d[1] = GB(val,  8, 8);
-		d[2] = GB(val, 16, 8);
-		d[3] = GB(val, 24, 8);
-#	endif
-	}
-
-/* need to use OR, otherwise we will overwrite the wrong pixels at the edges :( */
-	static inline void WRITE_PIXELS_OR(Pixel *d, uint32 val)
-	{
-#	if defined(TTD_BIG_ENDIAN)
-		d[0] |= GB(val, 24, 8);
-		d[1] |= GB(val, 16, 8);
-		d[2] |= GB(val,  8, 8);
-		d[3] |= GB(val,  0, 8);
-#	elif defined(TTD_LITTLE_ENDIAN)
-		d[0] |= GB(val,  0, 8);
-		d[1] |= GB(val,  8, 8);
-		d[2] |= GB(val, 16, 8);
-		d[3] |= GB(val, 24, 8);
-#	endif
-	}
-#else
-#	define WRITE_PIXELS(dst, val)   *(uint32*)(dst) = (val);
-#	define WRITE_PIXELS_OR(dst,val) *(uint32*)(dst) |= (val);
-#endif
-
-#define MKCOLOR(x) TO_LE32X(x)
-
-/* Height encodings; 16 levels XXX - needs updating for more/finer heights! */
-static const uint32 _map_height_bits[16] = {
-	MKCOLOR(0x5A5A5A5A),
-	MKCOLOR(0x5A5B5A5B),
-	MKCOLOR(0x5B5B5B5B),
-	MKCOLOR(0x5B5C5B5C),
-	MKCOLOR(0x5C5C5C5C),
-	MKCOLOR(0x5C5D5C5D),
-	MKCOLOR(0x5D5D5D5D),
-	MKCOLOR(0x5D5E5D5E),
-	MKCOLOR(0x5E5E5E5E),
-	MKCOLOR(0x5E5F5E5F),
-	MKCOLOR(0x5F5F5F5F),
-	MKCOLOR(0x5F1F5F1F),
-	MKCOLOR(0x1F1F1F1F),
-	MKCOLOR(0x1F271F27),
-	MKCOLOR(0x27272727),
-	MKCOLOR(0x27272727),
-};
-
-typedef struct AndOr {
-	uint32 mor;
-	uint32 mand;
-} AndOr;
-
-static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
-{
-	return (colour & mask->mand) | mask->mor;
-}
-
-
-static const AndOr _smallmap_contours_andor[] = {
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x000A0A00), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x98989898), MKCOLOR(0x00000000)},
-	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x000A0A00), MKCOLOR(0xFF0000FF)},
-};
-
-static const AndOr _smallmap_vehicles_andor[] = {
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-};
-
-static const AndOr _smallmap_vegetation_andor[] = {
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00575700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
-	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
-	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
-	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
-};
-
-typedef uint32 GetSmallMapPixels(TileIndex tile); // typedef callthrough function
-
-/**
- * Draws one column of the small map in a certain mode onto the screen buffer. This
- * function looks exactly the same for all types
- *
- * @param dst Pointer to a part of the screen buffer to write to.
- * @param xc The X coordinate of the first tile in the column.
- * @param yc The Y coordinate of the first tile in the column
- * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written.
- * @param reps Number of lines to draw
- * @param mask ?
- * @param proc Pointer to the colour function
- * @see GetSmallMapPixels(TileIndex)
- */
-static void DrawSmallMapStuff(Pixel *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc)
-{
-	Pixel *dst_ptr_end = _screen.dst_ptr + _screen.width * _screen.height - _screen.width;
-
-	do {
-		// check if the tile (xc,yc) is within the map range
-		if (xc < MapMaxX() && yc < MapMaxY()) {
-			// check if the dst pointer points to a pixel inside the screen buffer
-			if (dst > _screen.dst_ptr && dst < dst_ptr_end)
-				WRITE_PIXELS_OR(dst, proc(TileXY(xc, yc)) & mask);
-		}
-	// switch to next tile in the column
-	} while (xc++, yc++, dst += pitch, --reps != 0);
-}
-
-
-static inline TileType GetEffectiveTileType(TileIndex tile)
-{
-	TileType t = GetTileType(tile);
-
-	if (t == MP_TUNNELBRIDGE) {
-		TransportType tt;
-
-		if (IsTunnel(tile)) {
-			tt = GetTunnelTransportType(tile);
-		} else {
-			tt = GetBridgeTransportType(tile);
-		}
-		switch (tt) {
-			case TRANSPORT_RAIL: t = MP_RAILWAY; break;
-			case TRANSPORT_ROAD: t = MP_STREET;  break;
-			default:             t = MP_WATER;   break;
-		}
-	}
-	return t;
-}
-
-/**
- * Return the color a tile would be displayed with in the small map in mode "Contour".
- * @param tile The tile of which we would like to get the color.
- * @return The color of tile in the small map in mode "Contour"
- */
-static inline uint32 GetSmallMapContoursPixels(TileIndex tile)
-{
-	TileType t = GetEffectiveTileType(tile);
-
-	return
-		ApplyMask(_map_height_bits[TileHeight(tile)], &_smallmap_contours_andor[t]);
-}
-
-/**
- * Return the color a tile would be displayed with in the small map in mode "Vehicles".
- *
- * @param t The tile of which we would like to get the color.
- * @return The color of tile in the small map in mode "Vehicles"
- */
-static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile)
-{
-	TileType t = GetEffectiveTileType(tile);
-
-	return ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
-}
-
-/* Industry colours... a total of 175 gfx - XXX - increase if more industries */
-static const byte _industry_smallmap_colors[175] = {
-	215, 215, 215, 215, 215, 215, 215, 184,
-	184, 184, 184, 194, 194, 194, 194, 194,
-	 86,  86, 191, 191, 191, 191, 191, 191,
-	152, 152, 152, 152, 152, 152, 152, 152,
-	152,  48,  48,  48,  48,  48,  48, 174,
-	174, 174, 174, 174, 174, 174, 174,  10,
-	 10,  10,  10,  10,  10,  10,  10,  10,
-	 10,  10,  15,  15,  55,  55,  55,  55,
-	 10,  10,  10,  10,  10,  10,  10,  10,
-	194, 194, 194, 194, 194, 194, 194, 194,
-	194, 194, 194, 194, 194, 194, 194, 194,
-	194,  15,  15, 184, 184, 184, 184, 184,
-	184, 184, 184, 184,  55,  55,  55,  55,
-	 55,  55,  55,  55,  55,  55,  55,  55,
-	 55,  55,  55,  55,  86,  39,  37,  37,
-	208, 174, 174, 174, 174, 194, 194, 194,
-	194,  48,  48, 174, 174, 174, 174,  39,
-	 39,  55, 208, 208, 208, 208,  10,  10,
-	 10,  10,  10,  10,  37,  37,  37,  37,
-	 37,  37,  37,  37, 184, 184, 184, 184,
-	152, 152, 152, 152, 194, 194, 194,  15,
-	 15,  15,  15,  15,  15,  15,  15,
-};
-
-/**
- * Return the color a tile would be displayed with in the small map in mode "Industries".
- *
- * @param tile The tile of which we would like to get the color.
- * @return The color of tile in the small map in mode "Industries"
- */
-static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile)
-{
-	TileType t = GetEffectiveTileType(tile);
-
-	if (t == MP_INDUSTRY) {
-		return _industry_smallmap_colors[GetIndustryGfx(tile)] * 0x01010101;
-	}
-
-	return ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
-}
-
-/**
- * Return the color a tile would be displayed with in the small map in mode "Routes".
- *
- * @param t The tile of which we would like to get the color.
- * @return The color of tile  in the small map in mode "Routes"
- */
-static inline uint32 GetSmallMapRoutesPixels(TileIndex tile)
-{
-	TileType t = GetEffectiveTileType(tile);
-	uint32 bits;
-
-	if (t == MP_STATION) {
-		switch (GetStationType(tile)) {
-			case STATION_RAIL:    bits = MKCOLOR(0x56565656); break;
-			case STATION_AIRPORT: bits = MKCOLOR(0xB8B8B8B8); break;
-			case STATION_TRUCK:   bits = MKCOLOR(0xC2C2C2C2); break;
-			case STATION_BUS:     bits = MKCOLOR(0xBFBFBFBF); break;
-			case STATION_DOCK:    bits = MKCOLOR(0x98989898); break;
-			default:              bits = MKCOLOR(0xFFFFFFFF); break;
-		}
-	} else {
-		// ground color
-		bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_contours_andor[t]);
-	}
-	return bits;
-}
-
-
-static const uint32 _vegetation_clear_bits[] = {
-	MKCOLOR(0x54545454), ///< full grass
-	MKCOLOR(0x52525252), ///< rough land
-	MKCOLOR(0x0A0A0A0A), ///< rocks
-	MKCOLOR(0x25252525), ///< fields
-	MKCOLOR(0x98989898), ///< snow
-	MKCOLOR(0xC2C2C2C2), ///< desert
-	MKCOLOR(0x54545454), ///< unused
-	MKCOLOR(0x54545454), ///< unused
-};
-
-static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
-{
-	TileType t = GetEffectiveTileType(tile);
-	uint32 bits;
-
-	switch (t) {
-		case MP_CLEAR:
-			if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) {
-				bits = MKCOLOR(0x37373737);
-			} else {
-				bits = _vegetation_clear_bits[GetClearGround(tile)];
-			}
-			break;
-
-		case MP_INDUSTRY:
-			bits = GetIndustryType(tile) == IT_FOREST ? MKCOLOR(0xD0D0D0D0) : MKCOLOR(0xB5B5B5B5);
-			break;
-
-		case MP_TREES:
-			if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT) {
-				bits = (_opt.landscape == LT_HILLY) ? MKCOLOR(0x98575798) : MKCOLOR(0xC25757C2);
-			} else {
-				bits = MKCOLOR(0x54575754);
-			}
-			break;
-
-		default:
-			bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
-			break;
-	}
-
-	return bits;
-}
-
-
-static uint32 _owner_colors[OWNER_END + 1];
-
-/**
- * Return the color a tile would be displayed with in the small map in mode "Owner".
- *
- * @param t The tile of which we would like to get the color.
- * @return The color of tile in the small map in mode "Owner"
- */
-static inline uint32 GetSmallMapOwnerPixels(TileIndex tile)
-{
-	Owner o;
-
-	switch (GetTileType(tile)) {
-		case MP_INDUSTRY: o = OWNER_END;          break;
-		case MP_HOUSE:    o = OWNER_TOWN;         break;
-		default:          o = GetTileOwner(tile); break;
-	}
-
-	return _owner_colors[o];
-}
-
-
-static const uint32 _smallmap_mask_left[3] = {
-	MKCOLOR(0xFF000000),
-	MKCOLOR(0xFFFF0000),
-	MKCOLOR(0xFFFFFF00),
-};
-
-static const uint32 _smallmap_mask_right[] = {
-	MKCOLOR(0x000000FF),
-	MKCOLOR(0x0000FFFF),
-	MKCOLOR(0x00FFFFFF),
-};
-
-/* each tile has 4 x pixels and 1 y pixel */
-
-static GetSmallMapPixels *_smallmap_draw_procs[] = {
-	GetSmallMapContoursPixels,
-	GetSmallMapVehiclesPixels,
-	GetSmallMapIndustriesPixels,
-	GetSmallMapRoutesPixels,
-	GetSmallMapVegetationPixels,
-	GetSmallMapOwnerPixels,
-};
-
-static const byte _vehicle_type_colors[6] = {
-	184, 191, 152, 15, 215, 184
-};
-
-
-static void DrawVertMapIndicator(int x, int y, int x2, int y2)
-{
-	GfxFillRect(x, y,      x2, y + 3, 69);
-	GfxFillRect(x, y2 - 3, x2, y2,    69);
-}
-
-static void DrawHorizMapIndicator(int x, int y, int x2, int y2)
-{
-	GfxFillRect(x,      y, x + 3, y2, 69);
-	GfxFillRect(x2 - 3, y, x2,    y2, 69);
-}
-
-/**
- * Draws the small map.
- *
- * Basically, the small map is draw column of pixels by column of pixels. The pixels
- * are drawn directly into the screen buffer. The final map is drawn in multiple passes.
- * The passes are:
- * <ol><li>The colors of tiles in the different modes.</li>
- * <li>Town names (optional)</li>
- *
- * @param dpi pointer to pixel to write onto
- * @param w pointer to Window struct
- * @param type type of map requested (vegetation, owners, routes, etc)
- * @param show_towns true if the town names should be displayed, false if not.
- */
-static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_towns)
-{
-	DrawPixelInfo *old_dpi;
-	int dx,dy, x, y, x2, y2;
-	Pixel *ptr;
-	int tile_x;
-	int tile_y;
-	ViewPort *vp;
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = dpi;
-
-	/* clear it */
-	GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
-
-	/* setup owner table */
-	if (type == 5) {
-		const Player *p;
-
-		/* fill with some special colors */
-		_owner_colors[OWNER_TOWN] = MKCOLOR(0xB4B4B4B4);
-		_owner_colors[OWNER_NONE] = MKCOLOR(0x54545454);
-		_owner_colors[OWNER_WATER] = MKCOLOR(0xCACACACA);
-		_owner_colors[OWNER_END]   = MKCOLOR(0x20202020); /* industry */
-
-		/* now fill with the player colors */
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active) {
-				_owner_colors[p->index] =
-					_colour_gradient[p->player_color][5] * 0x01010101;
-			}
-		}
-	}
-
-	tile_x = WP(w,smallmap_d).scroll_x / TILE_SIZE;
-	tile_y = WP(w,smallmap_d).scroll_y / TILE_SIZE;
-
-	dx = dpi->left + WP(w,smallmap_d).subscroll;
-	tile_x -= dx / 4;
-	tile_y += dx / 4;
-	dx &= 3;
-
-	dy = dpi->top;
-	tile_x += dy / 2;
-	tile_y += dy / 2;
-
-	if (dy & 1) {
-		tile_x++;
-		dx += 2;
-		if (dx > 3) {
-			dx -= 4;
-			tile_x--;
-			tile_y++;
-		}
-	}
-
-	ptr = dpi->dst_ptr - dx - 4;
-	x = - dx - 4;
-	y = 0;
-
-	for (;;) {
-		uint32 mask = 0xFFFFFFFF;
-		int reps;
-		int t;
-
-		/* distance from left edge */
-		if (x < 0) {
-			if (x < -3) goto skip_column;
-			/* mask to use at the left edge */
-			mask = _smallmap_mask_left[x + 3];
-		}
-
-		/* distance from right edge */
-		t = dpi->width - x;
-		if (t < 4) {
-			if (t <= 0) break; /* exit loop */
-			/* mask to use at the right edge */
-			mask &= _smallmap_mask_right[t - 1];
-		}
-
-		/* number of lines */
-		reps = (dpi->height - y + 1) / 2;
-		if (reps > 0) {
-//			assert(ptr >= dpi->dst_ptr);
-			DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, _smallmap_draw_procs[type]);
-		}
-
-skip_column:
-		if (y == 0) {
-			tile_y++;
-			y++;
-			ptr += dpi->pitch;
-		} else {
-			tile_x--;
-			y--;
-			ptr -= dpi->pitch;
-		}
-		ptr += 2;
-		x += 2;
-	}
-
-	/* draw vehicles? */
-	if (type == 0 || type == 1) {
-		Vehicle *v;
-		bool skip;
-		byte color;
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_Special &&
-					(v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) {
-				// Remap into flat coordinates.
-				Point pt = RemapCoords(
-					v->x_pos / TILE_SIZE - WP(w,smallmap_d).scroll_x / TILE_SIZE, // divide each one separately because (a-b)/c != a/c-b/c in integer world
-					v->y_pos / TILE_SIZE - WP(w,smallmap_d).scroll_y / TILE_SIZE, //    dtto
-					0);
-				x = pt.x;
-				y = pt.y;
-
-				// Check if y is out of bounds?
-				y -= dpi->top;
-				if (!IS_INT_INSIDE(y, 0, dpi->height)) continue;
-
-				// Default is to draw both pixels.
-				skip = false;
-
-				// Offset X coordinate
-				x -= WP(w,smallmap_d).subscroll + 3 + dpi->left;
-
-				if (x < 0) {
-					// if x+1 is 0, that means we're on the very left edge,
-					//  and should thus only draw a single pixel
-					if (++x != 0) continue;
-					skip = true;
-				} else if (x >= dpi->width - 1) {
-					// Check if we're at the very right edge, and if so draw only a single pixel
-					if (x != dpi->width - 1) continue;
-					skip = true;
-				}
-
-				// Calculate pointer to pixel and the color
-				ptr = dpi->dst_ptr + y * dpi->pitch + x;
-				color = (type == 1) ? _vehicle_type_colors[v->type-0x10] : 0xF;
-
-				// And draw either one or two pixels depending on clipping
-				ptr[0] = color;
-				if (!skip) ptr[1] = color;
-			}
-		}
-	}
-
-	if (show_towns) {
-		const Town *t;
-
-		FOR_ALL_TOWNS(t) {
-			// Remap the town coordinate
-			Point pt = RemapCoords(
-				(int)(TileX(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_x) / TILE_SIZE,
-				(int)(TileY(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_y) / TILE_SIZE,
-				0);
-			x = pt.x - WP(w,smallmap_d).subscroll + 3 - (t->sign.width_2 >> 1);
-			y = pt.y;
-
-			// Check if the town sign is within bounds
-			if (x + t->sign.width_2 > dpi->left &&
-					x < dpi->left + dpi->width &&
-					y + 6 > dpi->top &&
-					y < dpi->top + dpi->height) {
-				// And draw it.
-				SetDParam(0, t->index);
-				DrawString(x, y, STR_2056, 12);
-			}
-		}
-	}
-
-	// Draw map indicators
-	{
-		Point pt;
-
-		// Find main viewport.
-		vp = FindWindowById(WC_MAIN_WINDOW,0)->viewport;
-
-		pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w, smallmap_d).scroll_y, 0);
-
-		x = vp->virtual_left - pt.x;
-		y = vp->virtual_top - pt.y;
-		x2 = (x + vp->virtual_width) / TILE_SIZE;
-		y2 = (y + vp->virtual_height) / TILE_SIZE;
-		x /= TILE_SIZE;
-		y /= TILE_SIZE;
-
-		x -= WP(w,smallmap_d).subscroll;
-		x2 -= WP(w,smallmap_d).subscroll;
-
-		DrawVertMapIndicator(x, y, x, y2);
-		DrawVertMapIndicator(x2, y, x2, y2);
-
-		DrawHorizMapIndicator(x, y, x2, y);
-		DrawHorizMapIndicator(x, y2, x2, y2);
-	}
-	_cur_dpi = old_dpi;
-}
-
-void SmallMapCenterOnCurrentPos(Window *w)
-{
-	int x, y;
-	ViewPort *vp;
-	vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
-
-	x  = ((vp->virtual_width  - (w->widget[4].right  - w->widget[4].left) * TILE_SIZE) / 2 + vp->virtual_left) / 4;
-	y  = ((vp->virtual_height - (w->widget[4].bottom - w->widget[4].top ) * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2;
-	WP(w, smallmap_d).scroll_x = (y - x) & ~0xF;
-	WP(w, smallmap_d).scroll_y = (x + y) & ~0xF;
-	SetWindowDirty(w);
-}
-
-static void SmallMapWindowProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const uint16 *tbl;
-			int x, y, y_org;
-			DrawPixelInfo new_dpi;
-
-			/* draw the window */
-			SetDParam(0, STR_00E5_CONTOURS + _smallmap_type);
-			DrawWindowWidgets(w);
-
-			/* draw the legend */
-			tbl = _legend_table[(_smallmap_type != 2) ? _smallmap_type : (_opt.landscape + IND_OFFS)];
-			x = 4;
-			y_org = w->height - 44 - 11;
-			y = y_org;
-			for (;;) {
-				GfxFillRect(x,     y + 1, x + 8, y + 5, 0);
-				GfxFillRect(x + 1, y + 2, x + 7, y + 4, (byte)tbl[0]);
-				DrawString(x + 11, y, tbl[1], 0);
-
-				tbl += 2;
-				y += 6;
-
-				if (tbl[0] == 0xFFFF) {
-					break;
-				} else if (tbl[0] & 0x100) {
-					x += 123;
-					y = y_org;
-				}
-			}
-
-			if (!FillDrawPixelInfo(&new_dpi, 3, 17, w->width - 28 + 22, w->height - 64 - 11))
-				return;
-
-			DrawSmallMap(&new_dpi, w, _smallmap_type, _smallmap_show_towns);
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 4: { // Map window
-					Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
-					Point pt;
-
-					/*
-					 * XXX: scrolling with the left mouse button is done by subsequently
-					 * clicking with the left mouse button; clicking once centers the
-					 * large map at the selected point. So by unclicking the left mouse
-					 * button here, it gets reclicked during the next inputloop, which
-					 * would make it look like the mouse is being dragged, while it is
-					 * actually being (virtually) clicked every inputloop.
-					 */
-					_left_button_clicked = false;
-
-					pt = RemapCoords(WP(w,smallmap_d).scroll_x, WP(w,smallmap_d).scroll_y, 0);
-					WP(w2, vp_d).scrollpos_x = pt.x + ((_cursor.pos.x - w->left + 2) << 4) - (w2->viewport->virtual_width >> 1);
-					WP(w2, vp_d).scrollpos_y = pt.y + ((_cursor.pos.y - w->top - 16) << 4) - (w2->viewport->virtual_height >> 1);
-
-					SetWindowDirty(w);
-				} break;
-
-				case 5:  // Show land contours
-				case 6:  // Show vehicles
-				case 7:  // Show industries
-				case 8:  // Show transport routes
-				case 9:  // Show vegetation
-				case 10: // Show land owners
-					RaiseWindowWidget(w, _smallmap_type + 5);
-					_smallmap_type = e->we.click.widget - 5;
-					LowerWindowWidget(w, _smallmap_type + 5);
-
-					SetWindowDirty(w);
-					SndPlayFx(SND_15_BEEP);
-					break;
-
-				case 11: // Center the smallmap again
-					SmallMapCenterOnCurrentPos(w);
-
-					SetWindowDirty(w);
-					SndPlayFx(SND_15_BEEP);
-					break;
-
-				case 12: // Toggle town names
-					ToggleWidgetLoweredState(w, 12);
-					_smallmap_show_towns = IsWindowWidgetLowered(w, 12);
-
-					SetWindowDirty(w);
-					SndPlayFx(SND_15_BEEP);
-					break;
-				}
-			break;
-
-		case WE_RCLICK:
-			if (e->we.click.widget == 4) {
-				if (_scrolling_viewport) return;
-				_scrolling_viewport = true;
-				_cursor.delta.x = 0;
-				_cursor.delta.y = 0;
-			}
-			break;
-
-		case WE_MOUSELOOP:
-			/* update the window every now and then */
-			if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w);
-			break;
-
-		case WE_SCROLL: {
-			int x;
-			int y;
-			int sub;
-			int hx;
-			int hy;
-			int hvx;
-			int hvy;
-
-			_cursor.fix_at = true;
-
-			x = WP(w, smallmap_d).scroll_x;
-			y = WP(w, smallmap_d).scroll_y;
-
-			sub = WP(w, smallmap_d).subscroll + e->we.scroll.delta.x;
-
-			x -= (sub >> 2) << 4;
-			y += (sub >> 2) << 4;
-			sub &= 3;
-
-			x += (e->we.scroll.delta.y >> 1) << 4;
-			y += (e->we.scroll.delta.y >> 1) << 4;
-
-			if (e->we.scroll.delta.y & 1) {
-				x += TILE_SIZE;
-				sub += 2;
-				if (sub > 3) {
-					sub -= 4;
-					x -= TILE_SIZE;
-					y += TILE_SIZE;
-				}
-			}
-
-			hx = (w->widget[4].right  - w->widget[4].left) / 2;
-			hy = (w->widget[4].bottom - w->widget[4].top ) / 2;
-			hvx = hx * -4 + hy * 8;
-			hvy = hx *  4 + hy * 8;
-			if (x < -hvx) {
-				x = -hvx;
-				sub = 0;
-			}
-			if (x > (int)MapMaxX() * TILE_SIZE - hvx) {
-				x = MapMaxX() * TILE_SIZE - hvx;
-				sub = 0;
-			}
-			if (y < -hvy) {
-				y = -hvy;
-				sub = 0;
-			}
-			if (y > (int)MapMaxY() * TILE_SIZE - hvy) {
-				y = MapMaxY() * TILE_SIZE - hvy;
-				sub = 0;
-			}
-
-			WP(w, smallmap_d).scroll_x = x;
-			WP(w, smallmap_d).scroll_y = y;
-			WP(w, smallmap_d).subscroll = sub;
-
-			SetWindowDirty(w);
-		} break;
-	}
-}
-
-static const WindowDesc _smallmap_desc = {
-	WDP_AUTO, WDP_AUTO, 446, 314,
-	WC_SMALLMAP,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_smallmap_widgets,
-	SmallMapWindowProc
-};
-
-void ShowSmallMap(void)
-{
-	Window *w;
-
-	w = AllocateWindowDescFront(&_smallmap_desc, 0);
-	if (w == NULL) return;
-
-	LowerWindowWidget(w, _smallmap_type + 5);
-	SetWindowWidgetLoweredState(w, 12, _smallmap_show_towns);
-	w->resize.width = 350;
-	w->resize.height = 250;
-
-	SmallMapCenterOnCurrentPos(w);
-}
-
-/* Extra ViewPort Window Stuff */
-static const Widget _extra_view_port_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   287,     0,    13, STR_EXTRA_VIEW_PORT_TITLE,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,     RESIZE_LR,    14,   288,   299,     0,    13, 0x0,                              STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_RB,    14,     0,   299,    14,   233, 0x0,                              STR_NULL},
-{      WWT_INSET,     RESIZE_RB,    14,     2,   297,    16,   231, 0x0,                              STR_NULL},
-{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,     0,    21,   234,   255, SPR_IMG_ZOOMIN,                   STR_017F_ZOOM_THE_VIEW_IN},
-{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,    22,    43,   234,   255, SPR_IMG_ZOOMOUT,                  STR_0180_ZOOM_THE_VIEW_OUT},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,    44,   171,   234,   255, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   172,   298,   234,   255, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT},
-{      WWT_PANEL,    RESIZE_RTB,    14,   299,   299,   234,   255, 0x0,                              STR_NULL},
-{      WWT_PANEL,    RESIZE_RTB,    14,     0,   287,   256,   267, 0x0,                              STR_NULL},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   288,   299,   256,   267, 0x0,                              STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: /* Disable zoom in button */
-		DisableWindowWidget(w, 5);
-		break;
-
-	case WE_PAINT:
-		// set the number in the title bar
-		SetDParam(0, w->window_number + 1);
-
-		DrawWindowWidgets(w);
-		DrawWindowViewport(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 5: DoZoomInOutWindow(ZOOM_IN,  w); break;
-			case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
-
-		case 7: { /* location button (move main view to same spot as this view) 'Paste Location' */
-			Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
-			int x = WP(w, vp_d).scrollpos_x; // Where is the main looking at
-			int y = WP(w, vp_d).scrollpos_y;
-
-			// set this view to same location. Based on the center, adjusting for zoom
-			WP(w2, vp_d).scrollpos_x =  x - (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
-			WP(w2, vp_d).scrollpos_y =  y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
-		} break;
-
-		case 8: { /* inverse location button (move this view to same spot as main view) 'Copy Location' */
-			const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
-			int x = WP(w2, const vp_d).scrollpos_x;
-			int y = WP(w2, const vp_d).scrollpos_y;
-
-			WP(w, vp_d).scrollpos_x =  x + (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
-			WP(w, vp_d).scrollpos_y =  y + (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
-		} break;
-		}
-		break;
-
-	case WE_RESIZE:
-		w->viewport->width          += e->we.sizing.diff.x;
-		w->viewport->height         += e->we.sizing.diff.y;
-		w->viewport->virtual_width  += e->we.sizing.diff.x;
-		w->viewport->virtual_height += e->we.sizing.diff.y;
-		break;
-
-		case WE_SCROLL: {
-			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
-
-			if (vp == NULL) {
-				_cursor.fix_at = false;
-				_scrolling_viewport = false;
-			}
-
-			WP(w, vp_d).scrollpos_x += e->we.scroll.delta.x << vp->zoom;
-			WP(w, vp_d).scrollpos_y += e->we.scroll.delta.y << vp->zoom;
-		} break;
-
-		case WE_MOUSEWHEEL:
-			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
-			break;
-
-
-		case WE_MESSAGE:
-			/* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
-			if (e->we.message.wparam != w->window_number) break;
-			HandleZoomMessage(w, w->viewport, 5, 6);
-			break;
-	}
-}
-
-static const WindowDesc _extra_view_port_desc = {
-	WDP_AUTO, WDP_AUTO, 300, 268,
-	WC_EXTRA_VIEW_PORT,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_extra_view_port_widgets,
-	ExtraViewPortWndProc
-};
-
-void ShowExtraViewPortWindow(void)
-{
-	Window *w, *v;
-	int i = 0;
-
-	// find next free window number for extra viewport
-	while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++;
-
-	w = AllocateWindowDescFront(&_extra_view_port_desc, i);
-	if (w != NULL) {
-		int x, y;
-		// the main window with the main view
-		v = FindWindowById(WC_MAIN_WINDOW, 0);
-		// New viewport start ats (zero,zero)
-		AssignWindowViewport(w, 3, 17, 294, 214, 0 , 0);
-
-		// center on same place as main window (zoom is maximum, no adjustment needed)
-		x = WP(v, vp_d).scrollpos_x;
-		y = WP(v, vp_d).scrollpos_y;
-		WP(w, vp_d).scrollpos_x = x + (v->viewport->virtual_width  - (294)) / 2;
-		WP(w, vp_d).scrollpos_y = y + (v->viewport->virtual_height - (214)) / 2;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/smallmap_gui.cpp
@@ -0,0 +1,1114 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "bridge_map.h"
+#include "clear_map.h"
+#include "industry_map.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "tile.h"
+#include "gui.h"
+#include "tree_map.h"
+#include "tunnel_map.h"
+#include "window.h"
+#include "gfx.h"
+#include "viewport.h"
+#include "player.h"
+#include "vehicle.h"
+#include "town.h"
+#include "sound.h"
+#include "variables.h"
+
+static const Widget _smallmap_widgets[] = {
+{  WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{   WWT_CAPTION,  RESIZE_RIGHT,    13,    11,   433,     0,    13, STR_00B0_MAP,            STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_STICKYBOX,     RESIZE_LR,    13,   434,   445,     0,    13, 0x0,                     STR_STICKY_BUTTON},
+{     WWT_PANEL,     RESIZE_RB,    13,     0,   445,    14,   257, 0x0,                     STR_NULL},
+{     WWT_INSET,     RESIZE_RB,    13,     2,   443,    16,   255, 0x0,                     STR_NULL},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   380,   401,   258,   279, SPR_IMG_SHOW_COUNTOURS,  STR_0191_SHOW_LAND_CONTOURS_ON_MAP},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   402,   423,   258,   279, SPR_IMG_SHOW_VEHICLES,   STR_0192_SHOW_VEHICLES_ON_MAP},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   424,   445,   258,   279, SPR_IMG_INDUSTRY,        STR_0193_SHOW_INDUSTRIES_ON_MAP},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   380,   401,   280,   301, SPR_IMG_SHOW_ROUTES,     STR_0194_SHOW_TRANSPORT_ROUTES_ON},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   402,   423,   280,   301, SPR_IMG_PLANTTREES,      STR_0195_SHOW_VEGETATION_ON_MAP},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   424,   445,   280,   301, SPR_IMG_COMPANY_GENERAL, STR_0196_SHOW_LAND_OWNERS_ON_MAP},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   358,   379,   258,   279, SPR_IMG_SMALLMAP,        STR_SMALLMAP_CENTER},
+{    WWT_IMGBTN,   RESIZE_LRTB,    13,   358,   379,   280,   301, SPR_IMG_TOWN,            STR_0197_TOGGLE_TOWN_NAMES_ON_OFF},
+{     WWT_PANEL,    RESIZE_RTB,    13,     0,   357,   258,   301, 0x0,                     STR_NULL},
+{     WWT_PANEL,    RESIZE_RTB,    13,     0,   433,   302,   313, 0x0,                     STR_NULL},
+{ WWT_RESIZEBOX,   RESIZE_LRTB,    13,   434,   445,   302,   313, 0x0,                     STR_RESIZE_BUTTON},
+{  WIDGETS_END},
+};
+
+static int _smallmap_type;
+static bool _smallmap_show_towns = true;
+
+#define MK(a,b) a, b
+#define MKEND() 0xFFFF
+#define MS(a,b) (a | 0x100), b
+
+/* Legend text giving the colours to look for on the minimap */
+static const uint16 _legend_land_contours[] = {
+	MK(0x5A, STR_00F0_100M),
+	MK(0x5C, STR_00F1_200M),
+	MK(0x5E, STR_00F2_300M),
+	MK(0x1F, STR_00F3_400M),
+	MK(0x27, STR_00F4_500M),
+
+	MS(0xD7, STR_00EB_ROADS),
+	MK(0x0A, STR_00EC_RAILROADS),
+	MK(0x98, STR_00ED_STATIONS_AIRPORTS_DOCKS),
+	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
+	MK(0x0F, STR_00EF_VEHICLES),
+	MKEND()
+};
+
+static const uint16 _legend_vehicles[] = {
+	MK(0xB8, STR_00F5_TRAINS),
+	MK(0xBF, STR_00F6_ROAD_VEHICLES),
+	MK(0x98, STR_00F7_SHIPS),
+	MK(0x0F, STR_00F8_AIRCRAFT),
+	MS(0xD7, STR_00F9_TRANSPORT_ROUTES),
+	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
+	MKEND()
+};
+
+static const uint16 _legend_industries_normal[] = {
+	MK(0xD7, STR_00FA_COAL_MINE),
+	MK(0xB8, STR_00FB_POWER_STATION),
+	MK(0x56, STR_00FC_FOREST),
+	MK(0xC2, STR_00FD_SAWMILL),
+	MK(0xBF, STR_00FE_OIL_REFINERY),
+	MK(0x0F, STR_0105_BANK),
+
+	MS(0x30, STR_00FF_FARM),
+	MK(0xAE, STR_0100_FACTORY),
+	MK(0x98, STR_0102_OIL_WELLS),
+	MK(0x37, STR_0103_IRON_ORE_MINE),
+	MK(0x0A, STR_0104_STEEL_MILL),
+	MKEND()
+};
+
+static const uint16 _legend_industries_hilly[] = {
+	MK(0xD7, STR_00FA_COAL_MINE),
+	MK(0xB8, STR_00FB_POWER_STATION),
+	MK(0x56, STR_00FC_FOREST),
+	MK(0x0A, STR_0106_PAPER_MILL),
+	MK(0xBF, STR_00FE_OIL_REFINERY),
+	MK(0x37, STR_0108_FOOD_PROCESSING_PLANT),
+	MS(0x30, STR_00FF_FARM),
+
+	MK(0xAE, STR_0101_PRINTING_WORKS),
+	MK(0x98, STR_0102_OIL_WELLS),
+	MK(0xC2, STR_0107_GOLD_MINE),
+	MK(0x0F, STR_0105_BANK),
+	MKEND()
+};
+
+static const uint16 _legend_industries_desert[] = {
+	MK(0xBF, STR_00FE_OIL_REFINERY),
+	MK(0x98, STR_0102_OIL_WELLS),
+	MK(0x0F, STR_0105_BANK),
+	MK(0xB8, STR_0109_DIAMOND_MINE),
+	MK(0x37, STR_0108_FOOD_PROCESSING_PLANT),
+	MK(0x0A, STR_010A_COPPER_ORE_MINE),
+	MK(0x30, STR_00FF_FARM),
+	MS(0x56, STR_010B_FRUIT_PLANTATION),
+
+	MK(0x27, STR_010C_RUBBER_PLANTATION),
+	MK(0x25, STR_010D_WATER_SUPPLY),
+	MK(0xD0, STR_010E_WATER_TOWER),
+	MK(0xAE, STR_0100_FACTORY),
+	MK(0xC2, STR_010F_LUMBER_MILL),
+	MKEND()
+};
+
+static const uint16 _legend_industries_candy[] = {
+	MK(0x30, STR_0110_COTTON_CANDY_FOREST),
+	MK(0xAE, STR_0111_CANDY_FACTORY),
+	MK(0x27, STR_0112_BATTERY_FARM),
+	MK(0x37, STR_0113_COLA_WELLS),
+	MK(0xD0, STR_0114_TOY_SHOP),
+	MK(0x0A, STR_0115_TOY_FACTORY),
+	MS(0x25, STR_0116_PLASTIC_FOUNTAINS),
+
+	MK(0xB8, STR_0117_FIZZY_DRINK_FACTORY),
+	MK(0x98, STR_0118_BUBBLE_GENERATOR),
+	MK(0xC2, STR_0119_TOFFEE_QUARRY),
+	MK(0x0F, STR_011A_SUGAR_MINE),
+	MKEND()
+};
+
+static const uint16 _legend_routes[] = {
+	MK(0xD7, STR_00EB_ROADS),
+	MK(0x0A, STR_00EC_RAILROADS),
+	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
+	MS(0x56, STR_011B_RAILROAD_STATION),
+
+	MK(0xC2, STR_011C_TRUCK_LOADING_BAY),
+	MK(0xBF, STR_011D_BUS_STATION),
+	MK(0xB8, STR_011E_AIRPORT_HELIPORT),
+	MK(0x98, STR_011F_DOCK),
+	MKEND()
+};
+
+static const uint16 _legend_vegetation[] = {
+	MK(0x52, STR_0120_ROUGH_LAND),
+	MK(0x54, STR_0121_GRASS_LAND),
+	MK(0x37, STR_0122_BARE_LAND),
+	MK(0x25, STR_0123_FIELDS),
+	MK(0x57, STR_0124_TREES),
+	MK(0xD0, STR_00FC_FOREST),
+	MS(0x0A, STR_0125_ROCKS),
+
+	MK(0xC2, STR_012A_DESERT),
+	MK(0x98, STR_012B_SNOW),
+	MK(0xD7, STR_00F9_TRANSPORT_ROUTES),
+	MK(0xB5, STR_00EE_BUILDINGS_INDUSTRIES),
+	MKEND()
+};
+
+static const uint16 _legend_land_owners[] = {
+	MK(0xCA, STR_0126_WATER),
+	MK(0x54, STR_0127_NO_OWNER),
+	MK(0xB4, STR_0128_TOWNS),
+	MK(0x20, STR_0129_INDUSTRIES),
+	MKEND()
+};
+#undef MK
+#undef MS
+#undef MKEND
+
+
+enum { IND_OFFS = 6 };
+static const uint16 * const _legend_table[] = {
+	_legend_land_contours,
+	_legend_vehicles,
+	NULL,
+	_legend_routes,
+	_legend_vegetation,
+	_legend_land_owners,
+
+	_legend_industries_normal,
+	_legend_industries_hilly,
+	_legend_industries_desert,
+	_legend_industries_candy,
+};
+
+#if defined(OTTD_ALIGNMENT)
+	static inline void WRITE_PIXELS(Pixel* d, uint32 val)
+	{
+#	if defined(TTD_BIG_ENDIAN)
+		d[0] = GB(val, 24, 8);
+		d[1] = GB(val, 16, 8);
+		d[2] = GB(val,  8, 8);
+		d[3] = GB(val,  0, 8);
+#	elif defined(TTD_LITTLE_ENDIAN)
+		d[0] = GB(val,  0, 8);
+		d[1] = GB(val,  8, 8);
+		d[2] = GB(val, 16, 8);
+		d[3] = GB(val, 24, 8);
+#	endif
+	}
+
+/* need to use OR, otherwise we will overwrite the wrong pixels at the edges :( */
+	static inline void WRITE_PIXELS_OR(Pixel *d, uint32 val)
+	{
+#	if defined(TTD_BIG_ENDIAN)
+		d[0] |= GB(val, 24, 8);
+		d[1] |= GB(val, 16, 8);
+		d[2] |= GB(val,  8, 8);
+		d[3] |= GB(val,  0, 8);
+#	elif defined(TTD_LITTLE_ENDIAN)
+		d[0] |= GB(val,  0, 8);
+		d[1] |= GB(val,  8, 8);
+		d[2] |= GB(val, 16, 8);
+		d[3] |= GB(val, 24, 8);
+#	endif
+	}
+#else
+#	define WRITE_PIXELS(dst, val)   *(uint32*)(dst) = (val);
+#	define WRITE_PIXELS_OR(dst,val) *(uint32*)(dst) |= (val);
+#endif
+
+#define MKCOLOR(x) TO_LE32X(x)
+
+/* Height encodings; 16 levels XXX - needs updating for more/finer heights! */
+static const uint32 _map_height_bits[16] = {
+	MKCOLOR(0x5A5A5A5A),
+	MKCOLOR(0x5A5B5A5B),
+	MKCOLOR(0x5B5B5B5B),
+	MKCOLOR(0x5B5C5B5C),
+	MKCOLOR(0x5C5C5C5C),
+	MKCOLOR(0x5C5D5C5D),
+	MKCOLOR(0x5D5D5D5D),
+	MKCOLOR(0x5D5E5D5E),
+	MKCOLOR(0x5E5E5E5E),
+	MKCOLOR(0x5E5F5E5F),
+	MKCOLOR(0x5F5F5F5F),
+	MKCOLOR(0x5F1F5F1F),
+	MKCOLOR(0x1F1F1F1F),
+	MKCOLOR(0x1F271F27),
+	MKCOLOR(0x27272727),
+	MKCOLOR(0x27272727),
+};
+
+typedef struct AndOr {
+	uint32 mor;
+	uint32 mand;
+} AndOr;
+
+static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
+{
+	return (colour & mask->mand) | mask->mor;
+}
+
+
+static const AndOr _smallmap_contours_andor[] = {
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x000A0A00), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x98989898), MKCOLOR(0x00000000)},
+	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x000A0A00), MKCOLOR(0xFF0000FF)},
+};
+
+static const AndOr _smallmap_vehicles_andor[] = {
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+};
+
+static const AndOr _smallmap_vegetation_andor[] = {
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00575700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0xCACACACA), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0xB5B5B5B5), MKCOLOR(0x00000000)},
+	{MKCOLOR(0x00000000), MKCOLOR(0xFFFFFFFF)},
+	{MKCOLOR(0x00B5B500), MKCOLOR(0xFF0000FF)},
+	{MKCOLOR(0x00D7D700), MKCOLOR(0xFF0000FF)},
+};
+
+typedef uint32 GetSmallMapPixels(TileIndex tile); // typedef callthrough function
+
+/**
+ * Draws one column of the small map in a certain mode onto the screen buffer. This
+ * function looks exactly the same for all types
+ *
+ * @param dst Pointer to a part of the screen buffer to write to.
+ * @param xc The X coordinate of the first tile in the column.
+ * @param yc The Y coordinate of the first tile in the column
+ * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written.
+ * @param reps Number of lines to draw
+ * @param mask ?
+ * @param proc Pointer to the colour function
+ * @see GetSmallMapPixels(TileIndex)
+ */
+static void DrawSmallMapStuff(Pixel *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc)
+{
+	Pixel *dst_ptr_end = _screen.dst_ptr + _screen.width * _screen.height - _screen.width;
+
+	do {
+		// check if the tile (xc,yc) is within the map range
+		if (xc < MapMaxX() && yc < MapMaxY()) {
+			// check if the dst pointer points to a pixel inside the screen buffer
+			if (dst > _screen.dst_ptr && dst < dst_ptr_end)
+				WRITE_PIXELS_OR(dst, proc(TileXY(xc, yc)) & mask);
+		}
+	// switch to next tile in the column
+	} while (xc++, yc++, dst += pitch, --reps != 0);
+}
+
+
+static inline TileType GetEffectiveTileType(TileIndex tile)
+{
+	TileType t = GetTileType(tile);
+
+	if (t == MP_TUNNELBRIDGE) {
+		TransportType tt;
+
+		if (IsTunnel(tile)) {
+			tt = GetTunnelTransportType(tile);
+		} else {
+			tt = GetBridgeTransportType(tile);
+		}
+		switch (tt) {
+			case TRANSPORT_RAIL: t = MP_RAILWAY; break;
+			case TRANSPORT_ROAD: t = MP_STREET;  break;
+			default:             t = MP_WATER;   break;
+		}
+	}
+	return t;
+}
+
+/**
+ * Return the color a tile would be displayed with in the small map in mode "Contour".
+ * @param tile The tile of which we would like to get the color.
+ * @return The color of tile in the small map in mode "Contour"
+ */
+static inline uint32 GetSmallMapContoursPixels(TileIndex tile)
+{
+	TileType t = GetEffectiveTileType(tile);
+
+	return
+		ApplyMask(_map_height_bits[TileHeight(tile)], &_smallmap_contours_andor[t]);
+}
+
+/**
+ * Return the color a tile would be displayed with in the small map in mode "Vehicles".
+ *
+ * @param t The tile of which we would like to get the color.
+ * @return The color of tile in the small map in mode "Vehicles"
+ */
+static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile)
+{
+	TileType t = GetEffectiveTileType(tile);
+
+	return ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
+}
+
+/* Industry colours... a total of 175 gfx - XXX - increase if more industries */
+static const byte _industry_smallmap_colors[175] = {
+	215, 215, 215, 215, 215, 215, 215, 184,
+	184, 184, 184, 194, 194, 194, 194, 194,
+	 86,  86, 191, 191, 191, 191, 191, 191,
+	152, 152, 152, 152, 152, 152, 152, 152,
+	152,  48,  48,  48,  48,  48,  48, 174,
+	174, 174, 174, 174, 174, 174, 174,  10,
+	 10,  10,  10,  10,  10,  10,  10,  10,
+	 10,  10,  15,  15,  55,  55,  55,  55,
+	 10,  10,  10,  10,  10,  10,  10,  10,
+	194, 194, 194, 194, 194, 194, 194, 194,
+	194, 194, 194, 194, 194, 194, 194, 194,
+	194,  15,  15, 184, 184, 184, 184, 184,
+	184, 184, 184, 184,  55,  55,  55,  55,
+	 55,  55,  55,  55,  55,  55,  55,  55,
+	 55,  55,  55,  55,  86,  39,  37,  37,
+	208, 174, 174, 174, 174, 194, 194, 194,
+	194,  48,  48, 174, 174, 174, 174,  39,
+	 39,  55, 208, 208, 208, 208,  10,  10,
+	 10,  10,  10,  10,  37,  37,  37,  37,
+	 37,  37,  37,  37, 184, 184, 184, 184,
+	152, 152, 152, 152, 194, 194, 194,  15,
+	 15,  15,  15,  15,  15,  15,  15,
+};
+
+/**
+ * Return the color a tile would be displayed with in the small map in mode "Industries".
+ *
+ * @param tile The tile of which we would like to get the color.
+ * @return The color of tile in the small map in mode "Industries"
+ */
+static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile)
+{
+	TileType t = GetEffectiveTileType(tile);
+
+	if (t == MP_INDUSTRY) {
+		return _industry_smallmap_colors[GetIndustryGfx(tile)] * 0x01010101;
+	}
+
+	return ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
+}
+
+/**
+ * Return the color a tile would be displayed with in the small map in mode "Routes".
+ *
+ * @param t The tile of which we would like to get the color.
+ * @return The color of tile  in the small map in mode "Routes"
+ */
+static inline uint32 GetSmallMapRoutesPixels(TileIndex tile)
+{
+	TileType t = GetEffectiveTileType(tile);
+	uint32 bits;
+
+	if (t == MP_STATION) {
+		switch (GetStationType(tile)) {
+			case STATION_RAIL:    bits = MKCOLOR(0x56565656); break;
+			case STATION_AIRPORT: bits = MKCOLOR(0xB8B8B8B8); break;
+			case STATION_TRUCK:   bits = MKCOLOR(0xC2C2C2C2); break;
+			case STATION_BUS:     bits = MKCOLOR(0xBFBFBFBF); break;
+			case STATION_DOCK:    bits = MKCOLOR(0x98989898); break;
+			default:              bits = MKCOLOR(0xFFFFFFFF); break;
+		}
+	} else {
+		// ground color
+		bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_contours_andor[t]);
+	}
+	return bits;
+}
+
+
+static const uint32 _vegetation_clear_bits[] = {
+	MKCOLOR(0x54545454), ///< full grass
+	MKCOLOR(0x52525252), ///< rough land
+	MKCOLOR(0x0A0A0A0A), ///< rocks
+	MKCOLOR(0x25252525), ///< fields
+	MKCOLOR(0x98989898), ///< snow
+	MKCOLOR(0xC2C2C2C2), ///< desert
+	MKCOLOR(0x54545454), ///< unused
+	MKCOLOR(0x54545454), ///< unused
+};
+
+static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
+{
+	TileType t = GetEffectiveTileType(tile);
+	uint32 bits;
+
+	switch (t) {
+		case MP_CLEAR:
+			if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) {
+				bits = MKCOLOR(0x37373737);
+			} else {
+				bits = _vegetation_clear_bits[GetClearGround(tile)];
+			}
+			break;
+
+		case MP_INDUSTRY:
+			bits = GetIndustryType(tile) == IT_FOREST ? MKCOLOR(0xD0D0D0D0) : MKCOLOR(0xB5B5B5B5);
+			break;
+
+		case MP_TREES:
+			if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT) {
+				bits = (_opt.landscape == LT_HILLY) ? MKCOLOR(0x98575798) : MKCOLOR(0xC25757C2);
+			} else {
+				bits = MKCOLOR(0x54575754);
+			}
+			break;
+
+		default:
+			bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
+			break;
+	}
+
+	return bits;
+}
+
+
+static uint32 _owner_colors[OWNER_END + 1];
+
+/**
+ * Return the color a tile would be displayed with in the small map in mode "Owner".
+ *
+ * @param t The tile of which we would like to get the color.
+ * @return The color of tile in the small map in mode "Owner"
+ */
+static inline uint32 GetSmallMapOwnerPixels(TileIndex tile)
+{
+	Owner o;
+
+	switch (GetTileType(tile)) {
+		case MP_INDUSTRY: o = OWNER_END;          break;
+		case MP_HOUSE:    o = OWNER_TOWN;         break;
+		default:          o = GetTileOwner(tile); break;
+	}
+
+	return _owner_colors[o];
+}
+
+
+static const uint32 _smallmap_mask_left[3] = {
+	MKCOLOR(0xFF000000),
+	MKCOLOR(0xFFFF0000),
+	MKCOLOR(0xFFFFFF00),
+};
+
+static const uint32 _smallmap_mask_right[] = {
+	MKCOLOR(0x000000FF),
+	MKCOLOR(0x0000FFFF),
+	MKCOLOR(0x00FFFFFF),
+};
+
+/* each tile has 4 x pixels and 1 y pixel */
+
+static GetSmallMapPixels *_smallmap_draw_procs[] = {
+	GetSmallMapContoursPixels,
+	GetSmallMapVehiclesPixels,
+	GetSmallMapIndustriesPixels,
+	GetSmallMapRoutesPixels,
+	GetSmallMapVegetationPixels,
+	GetSmallMapOwnerPixels,
+};
+
+static const byte _vehicle_type_colors[6] = {
+	184, 191, 152, 15, 215, 184
+};
+
+
+static void DrawVertMapIndicator(int x, int y, int x2, int y2)
+{
+	GfxFillRect(x, y,      x2, y + 3, 69);
+	GfxFillRect(x, y2 - 3, x2, y2,    69);
+}
+
+static void DrawHorizMapIndicator(int x, int y, int x2, int y2)
+{
+	GfxFillRect(x,      y, x + 3, y2, 69);
+	GfxFillRect(x2 - 3, y, x2,    y2, 69);
+}
+
+/**
+ * Draws the small map.
+ *
+ * Basically, the small map is draw column of pixels by column of pixels. The pixels
+ * are drawn directly into the screen buffer. The final map is drawn in multiple passes.
+ * The passes are:
+ * <ol><li>The colors of tiles in the different modes.</li>
+ * <li>Town names (optional)</li>
+ *
+ * @param dpi pointer to pixel to write onto
+ * @param w pointer to Window struct
+ * @param type type of map requested (vegetation, owners, routes, etc)
+ * @param show_towns true if the town names should be displayed, false if not.
+ */
+static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_towns)
+{
+	DrawPixelInfo *old_dpi;
+	int dx,dy, x, y, x2, y2;
+	Pixel *ptr;
+	int tile_x;
+	int tile_y;
+	ViewPort *vp;
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = dpi;
+
+	/* clear it */
+	GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
+
+	/* setup owner table */
+	if (type == 5) {
+		const Player *p;
+
+		/* fill with some special colors */
+		_owner_colors[OWNER_TOWN] = MKCOLOR(0xB4B4B4B4);
+		_owner_colors[OWNER_NONE] = MKCOLOR(0x54545454);
+		_owner_colors[OWNER_WATER] = MKCOLOR(0xCACACACA);
+		_owner_colors[OWNER_END]   = MKCOLOR(0x20202020); /* industry */
+
+		/* now fill with the player colors */
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				_owner_colors[p->index] =
+					_colour_gradient[p->player_color][5] * 0x01010101;
+			}
+		}
+	}
+
+	tile_x = WP(w,smallmap_d).scroll_x / TILE_SIZE;
+	tile_y = WP(w,smallmap_d).scroll_y / TILE_SIZE;
+
+	dx = dpi->left + WP(w,smallmap_d).subscroll;
+	tile_x -= dx / 4;
+	tile_y += dx / 4;
+	dx &= 3;
+
+	dy = dpi->top;
+	tile_x += dy / 2;
+	tile_y += dy / 2;
+
+	if (dy & 1) {
+		tile_x++;
+		dx += 2;
+		if (dx > 3) {
+			dx -= 4;
+			tile_x--;
+			tile_y++;
+		}
+	}
+
+	ptr = dpi->dst_ptr - dx - 4;
+	x = - dx - 4;
+	y = 0;
+
+	for (;;) {
+		uint32 mask = 0xFFFFFFFF;
+		int reps;
+		int t;
+
+		/* distance from left edge */
+		if (x < 0) {
+			if (x < -3) goto skip_column;
+			/* mask to use at the left edge */
+			mask = _smallmap_mask_left[x + 3];
+		}
+
+		/* distance from right edge */
+		t = dpi->width - x;
+		if (t < 4) {
+			if (t <= 0) break; /* exit loop */
+			/* mask to use at the right edge */
+			mask &= _smallmap_mask_right[t - 1];
+		}
+
+		/* number of lines */
+		reps = (dpi->height - y + 1) / 2;
+		if (reps > 0) {
+//			assert(ptr >= dpi->dst_ptr);
+			DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, _smallmap_draw_procs[type]);
+		}
+
+skip_column:
+		if (y == 0) {
+			tile_y++;
+			y++;
+			ptr += dpi->pitch;
+		} else {
+			tile_x--;
+			y--;
+			ptr -= dpi->pitch;
+		}
+		ptr += 2;
+		x += 2;
+	}
+
+	/* draw vehicles? */
+	if (type == 0 || type == 1) {
+		Vehicle *v;
+		bool skip;
+		byte color;
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->type != VEH_Special &&
+					(v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) {
+				// Remap into flat coordinates.
+				Point pt = RemapCoords(
+					v->x_pos / TILE_SIZE - WP(w,smallmap_d).scroll_x / TILE_SIZE, // divide each one separately because (a-b)/c != a/c-b/c in integer world
+					v->y_pos / TILE_SIZE - WP(w,smallmap_d).scroll_y / TILE_SIZE, //    dtto
+					0);
+				x = pt.x;
+				y = pt.y;
+
+				// Check if y is out of bounds?
+				y -= dpi->top;
+				if (!IS_INT_INSIDE(y, 0, dpi->height)) continue;
+
+				// Default is to draw both pixels.
+				skip = false;
+
+				// Offset X coordinate
+				x -= WP(w,smallmap_d).subscroll + 3 + dpi->left;
+
+				if (x < 0) {
+					// if x+1 is 0, that means we're on the very left edge,
+					//  and should thus only draw a single pixel
+					if (++x != 0) continue;
+					skip = true;
+				} else if (x >= dpi->width - 1) {
+					// Check if we're at the very right edge, and if so draw only a single pixel
+					if (x != dpi->width - 1) continue;
+					skip = true;
+				}
+
+				// Calculate pointer to pixel and the color
+				ptr = dpi->dst_ptr + y * dpi->pitch + x;
+				color = (type == 1) ? _vehicle_type_colors[v->type-0x10] : 0xF;
+
+				// And draw either one or two pixels depending on clipping
+				ptr[0] = color;
+				if (!skip) ptr[1] = color;
+			}
+		}
+	}
+
+	if (show_towns) {
+		const Town *t;
+
+		FOR_ALL_TOWNS(t) {
+			// Remap the town coordinate
+			Point pt = RemapCoords(
+				(int)(TileX(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_x) / TILE_SIZE,
+				(int)(TileY(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_y) / TILE_SIZE,
+				0);
+			x = pt.x - WP(w,smallmap_d).subscroll + 3 - (t->sign.width_2 >> 1);
+			y = pt.y;
+
+			// Check if the town sign is within bounds
+			if (x + t->sign.width_2 > dpi->left &&
+					x < dpi->left + dpi->width &&
+					y + 6 > dpi->top &&
+					y < dpi->top + dpi->height) {
+				// And draw it.
+				SetDParam(0, t->index);
+				DrawString(x, y, STR_2056, 12);
+			}
+		}
+	}
+
+	// Draw map indicators
+	{
+		Point pt;
+
+		// Find main viewport.
+		vp = FindWindowById(WC_MAIN_WINDOW,0)->viewport;
+
+		pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w, smallmap_d).scroll_y, 0);
+
+		x = vp->virtual_left - pt.x;
+		y = vp->virtual_top - pt.y;
+		x2 = (x + vp->virtual_width) / TILE_SIZE;
+		y2 = (y + vp->virtual_height) / TILE_SIZE;
+		x /= TILE_SIZE;
+		y /= TILE_SIZE;
+
+		x -= WP(w,smallmap_d).subscroll;
+		x2 -= WP(w,smallmap_d).subscroll;
+
+		DrawVertMapIndicator(x, y, x, y2);
+		DrawVertMapIndicator(x2, y, x2, y2);
+
+		DrawHorizMapIndicator(x, y, x2, y);
+		DrawHorizMapIndicator(x, y2, x2, y2);
+	}
+	_cur_dpi = old_dpi;
+}
+
+void SmallMapCenterOnCurrentPos(Window *w)
+{
+	int x, y;
+	ViewPort *vp;
+	vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
+
+	x  = ((vp->virtual_width  - (w->widget[4].right  - w->widget[4].left) * TILE_SIZE) / 2 + vp->virtual_left) / 4;
+	y  = ((vp->virtual_height - (w->widget[4].bottom - w->widget[4].top ) * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2;
+	WP(w, smallmap_d).scroll_x = (y - x) & ~0xF;
+	WP(w, smallmap_d).scroll_y = (x + y) & ~0xF;
+	SetWindowDirty(w);
+}
+
+static void SmallMapWindowProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			const uint16 *tbl;
+			int x, y, y_org;
+			DrawPixelInfo new_dpi;
+
+			/* draw the window */
+			SetDParam(0, STR_00E5_CONTOURS + _smallmap_type);
+			DrawWindowWidgets(w);
+
+			/* draw the legend */
+			tbl = _legend_table[(_smallmap_type != 2) ? _smallmap_type : (_opt.landscape + IND_OFFS)];
+			x = 4;
+			y_org = w->height - 44 - 11;
+			y = y_org;
+			for (;;) {
+				GfxFillRect(x,     y + 1, x + 8, y + 5, 0);
+				GfxFillRect(x + 1, y + 2, x + 7, y + 4, (byte)tbl[0]);
+				DrawString(x + 11, y, tbl[1], 0);
+
+				tbl += 2;
+				y += 6;
+
+				if (tbl[0] == 0xFFFF) {
+					break;
+				} else if (tbl[0] & 0x100) {
+					x += 123;
+					y = y_org;
+				}
+			}
+
+			if (!FillDrawPixelInfo(&new_dpi, 3, 17, w->width - 28 + 22, w->height - 64 - 11))
+				return;
+
+			DrawSmallMap(&new_dpi, w, _smallmap_type, _smallmap_show_towns);
+		} break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case 4: { // Map window
+					Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
+					Point pt;
+
+					/*
+					 * XXX: scrolling with the left mouse button is done by subsequently
+					 * clicking with the left mouse button; clicking once centers the
+					 * large map at the selected point. So by unclicking the left mouse
+					 * button here, it gets reclicked during the next inputloop, which
+					 * would make it look like the mouse is being dragged, while it is
+					 * actually being (virtually) clicked every inputloop.
+					 */
+					_left_button_clicked = false;
+
+					pt = RemapCoords(WP(w,smallmap_d).scroll_x, WP(w,smallmap_d).scroll_y, 0);
+					WP(w2, vp_d).scrollpos_x = pt.x + ((_cursor.pos.x - w->left + 2) << 4) - (w2->viewport->virtual_width >> 1);
+					WP(w2, vp_d).scrollpos_y = pt.y + ((_cursor.pos.y - w->top - 16) << 4) - (w2->viewport->virtual_height >> 1);
+
+					SetWindowDirty(w);
+				} break;
+
+				case 5:  // Show land contours
+				case 6:  // Show vehicles
+				case 7:  // Show industries
+				case 8:  // Show transport routes
+				case 9:  // Show vegetation
+				case 10: // Show land owners
+					RaiseWindowWidget(w, _smallmap_type + 5);
+					_smallmap_type = e->we.click.widget - 5;
+					LowerWindowWidget(w, _smallmap_type + 5);
+
+					SetWindowDirty(w);
+					SndPlayFx(SND_15_BEEP);
+					break;
+
+				case 11: // Center the smallmap again
+					SmallMapCenterOnCurrentPos(w);
+
+					SetWindowDirty(w);
+					SndPlayFx(SND_15_BEEP);
+					break;
+
+				case 12: // Toggle town names
+					ToggleWidgetLoweredState(w, 12);
+					_smallmap_show_towns = IsWindowWidgetLowered(w, 12);
+
+					SetWindowDirty(w);
+					SndPlayFx(SND_15_BEEP);
+					break;
+				}
+			break;
+
+		case WE_RCLICK:
+			if (e->we.click.widget == 4) {
+				if (_scrolling_viewport) return;
+				_scrolling_viewport = true;
+				_cursor.delta.x = 0;
+				_cursor.delta.y = 0;
+			}
+			break;
+
+		case WE_MOUSELOOP:
+			/* update the window every now and then */
+			if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w);
+			break;
+
+		case WE_SCROLL: {
+			int x;
+			int y;
+			int sub;
+			int hx;
+			int hy;
+			int hvx;
+			int hvy;
+
+			_cursor.fix_at = true;
+
+			x = WP(w, smallmap_d).scroll_x;
+			y = WP(w, smallmap_d).scroll_y;
+
+			sub = WP(w, smallmap_d).subscroll + e->we.scroll.delta.x;
+
+			x -= (sub >> 2) << 4;
+			y += (sub >> 2) << 4;
+			sub &= 3;
+
+			x += (e->we.scroll.delta.y >> 1) << 4;
+			y += (e->we.scroll.delta.y >> 1) << 4;
+
+			if (e->we.scroll.delta.y & 1) {
+				x += TILE_SIZE;
+				sub += 2;
+				if (sub > 3) {
+					sub -= 4;
+					x -= TILE_SIZE;
+					y += TILE_SIZE;
+				}
+			}
+
+			hx = (w->widget[4].right  - w->widget[4].left) / 2;
+			hy = (w->widget[4].bottom - w->widget[4].top ) / 2;
+			hvx = hx * -4 + hy * 8;
+			hvy = hx *  4 + hy * 8;
+			if (x < -hvx) {
+				x = -hvx;
+				sub = 0;
+			}
+			if (x > (int)MapMaxX() * TILE_SIZE - hvx) {
+				x = MapMaxX() * TILE_SIZE - hvx;
+				sub = 0;
+			}
+			if (y < -hvy) {
+				y = -hvy;
+				sub = 0;
+			}
+			if (y > (int)MapMaxY() * TILE_SIZE - hvy) {
+				y = MapMaxY() * TILE_SIZE - hvy;
+				sub = 0;
+			}
+
+			WP(w, smallmap_d).scroll_x = x;
+			WP(w, smallmap_d).scroll_y = y;
+			WP(w, smallmap_d).subscroll = sub;
+
+			SetWindowDirty(w);
+		} break;
+	}
+}
+
+static const WindowDesc _smallmap_desc = {
+	WDP_AUTO, WDP_AUTO, 446, 314,
+	WC_SMALLMAP,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_smallmap_widgets,
+	SmallMapWindowProc
+};
+
+void ShowSmallMap(void)
+{
+	Window *w;
+
+	w = AllocateWindowDescFront(&_smallmap_desc, 0);
+	if (w == NULL) return;
+
+	LowerWindowWidget(w, _smallmap_type + 5);
+	SetWindowWidgetLoweredState(w, 12, _smallmap_show_towns);
+	w->resize.width = 350;
+	w->resize.height = 250;
+
+	SmallMapCenterOnCurrentPos(w);
+}
+
+/* Extra ViewPort Window Stuff */
+static const Widget _extra_view_port_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   287,     0,    13, STR_EXTRA_VIEW_PORT_TITLE,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,     RESIZE_LR,    14,   288,   299,     0,    13, 0x0,                              STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_RB,    14,     0,   299,    14,   233, 0x0,                              STR_NULL},
+{      WWT_INSET,     RESIZE_RB,    14,     2,   297,    16,   231, 0x0,                              STR_NULL},
+{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,     0,    21,   234,   255, SPR_IMG_ZOOMIN,                   STR_017F_ZOOM_THE_VIEW_IN},
+{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,    22,    43,   234,   255, SPR_IMG_ZOOMOUT,                  STR_0180_ZOOM_THE_VIEW_OUT},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,    44,   171,   234,   255, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   172,   298,   234,   255, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT},
+{      WWT_PANEL,    RESIZE_RTB,    14,   299,   299,   234,   255, 0x0,                              STR_NULL},
+{      WWT_PANEL,    RESIZE_RTB,    14,     0,   287,   256,   267, 0x0,                              STR_NULL},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   288,   299,   256,   267, 0x0,                              STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_CREATE: /* Disable zoom in button */
+		DisableWindowWidget(w, 5);
+		break;
+
+	case WE_PAINT:
+		// set the number in the title bar
+		SetDParam(0, w->window_number + 1);
+
+		DrawWindowWidgets(w);
+		DrawWindowViewport(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 5: DoZoomInOutWindow(ZOOM_IN,  w); break;
+			case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
+
+		case 7: { /* location button (move main view to same spot as this view) 'Paste Location' */
+			Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
+			int x = WP(w, vp_d).scrollpos_x; // Where is the main looking at
+			int y = WP(w, vp_d).scrollpos_y;
+
+			// set this view to same location. Based on the center, adjusting for zoom
+			WP(w2, vp_d).scrollpos_x =  x - (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
+			WP(w2, vp_d).scrollpos_y =  y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
+		} break;
+
+		case 8: { /* inverse location button (move this view to same spot as main view) 'Copy Location' */
+			const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
+			int x = WP(w2, const vp_d).scrollpos_x;
+			int y = WP(w2, const vp_d).scrollpos_y;
+
+			WP(w, vp_d).scrollpos_x =  x + (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
+			WP(w, vp_d).scrollpos_y =  y + (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
+		} break;
+		}
+		break;
+
+	case WE_RESIZE:
+		w->viewport->width          += e->we.sizing.diff.x;
+		w->viewport->height         += e->we.sizing.diff.y;
+		w->viewport->virtual_width  += e->we.sizing.diff.x;
+		w->viewport->virtual_height += e->we.sizing.diff.y;
+		break;
+
+		case WE_SCROLL: {
+			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
+
+			if (vp == NULL) {
+				_cursor.fix_at = false;
+				_scrolling_viewport = false;
+			}
+
+			WP(w, vp_d).scrollpos_x += e->we.scroll.delta.x << vp->zoom;
+			WP(w, vp_d).scrollpos_y += e->we.scroll.delta.y << vp->zoom;
+		} break;
+
+		case WE_MOUSEWHEEL:
+			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
+			break;
+
+
+		case WE_MESSAGE:
+			/* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
+			if (e->we.message.wparam != w->window_number) break;
+			HandleZoomMessage(w, w->viewport, 5, 6);
+			break;
+	}
+}
+
+static const WindowDesc _extra_view_port_desc = {
+	WDP_AUTO, WDP_AUTO, 300, 268,
+	WC_EXTRA_VIEW_PORT,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_extra_view_port_widgets,
+	ExtraViewPortWndProc
+};
+
+void ShowExtraViewPortWindow(void)
+{
+	Window *w, *v;
+	int i = 0;
+
+	// find next free window number for extra viewport
+	while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++;
+
+	w = AllocateWindowDescFront(&_extra_view_port_desc, i);
+	if (w != NULL) {
+		int x, y;
+		// the main window with the main view
+		v = FindWindowById(WC_MAIN_WINDOW, 0);
+		// New viewport start ats (zero,zero)
+		AssignWindowViewport(w, 3, 17, 294, 214, 0 , 0);
+
+		// center on same place as main window (zoom is maximum, no adjustment needed)
+		x = WP(v, vp_d).scrollpos_x;
+		y = WP(v, vp_d).scrollpos_y;
+		WP(w, vp_d).scrollpos_x = x + (v->viewport->virtual_width  - (294)) / 2;
+		WP(w, vp_d).scrollpos_y = y + (v->viewport->virtual_height - (214)) / 2;
+	}
+}
deleted file mode 100644
--- a/src/sound.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "map.h"
-#include "mixer.h"
-#include "sound.h"
-#include "vehicle.h"
-#include "window.h"
-#include "viewport.h"
-#include "fileio.h"
-#include "newgrf_sound.h"
-
-static uint _file_count;
-static FileEntry *_files;
-
-#define SOUND_SLOT 63
-// Number of levels of panning per side
-#define PANNING_LEVELS 16
-
-
-static void OpenBankFile(const char *filename)
-{
-	FileEntry *fe;
-	uint count;
-	uint i;
-
-	FioOpenFile(SOUND_SLOT, filename);
-	count = FioReadDword() / 8;
-	fe = calloc(count, sizeof(*fe));
-
-	if (fe == NULL) {
-		_file_count = 0;
-		_files = NULL;
-		return;
-	}
-
-	_file_count = count;
-	_files = fe;
-
-	FioSeekTo(0, SEEK_SET);
-
-	for (i = 0; i != count; i++) {
-		fe[i].file_offset = FioReadDword();
-		fe[i].file_size = FioReadDword();
-	}
-
-	for (i = 0; i != count; i++, fe++) {
-		char name[255];
-
-		FioSeekTo(fe->file_offset, SEEK_SET);
-
-		// Check for special case, see else case
-		FioReadBlock(name, FioReadByte()); // Read the name of the sound
-		if (strcmp(name, "Corrupt sound") != 0) {
-			FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
-
-			// Read riff tags
-			for (;;) {
-				uint32 tag = FioReadDword();
-				uint32 size = FioReadDword();
-
-				if (tag == ' tmf') {
-					FioReadWord(); // wFormatTag
-					fe->channels = FioReadWord(); // wChannels
-					FioReadDword();   // samples per second
-					fe->rate = 11025; // seems like all samples should be played at this rate.
-					FioReadDword();   // avg bytes per second
-					FioReadWord();    // alignment
-					fe->bits_per_sample = FioReadByte(); // bits per sample
-					FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
-				} else if (tag == 'atad') {
-					fe->file_size = size;
-					fe->file_offset = FioGetPos() | (SOUND_SLOT << 24);
-					break;
-				} else {
-					fe->file_size = 0;
-					break;
-				}
-			}
-		} else {
-			/*
-			 * Special case for the jackhammer sound
-			 * (name in sample.cat is "Corrupt sound")
-			 * It's no RIFF file, but raw PCM data
-			 */
-			fe->channels = 1;
-			fe->rate = 11025;
-			fe->bits_per_sample = 8;
-			fe->file_offset = FioGetPos() | (SOUND_SLOT << 24);
-		}
-	}
-}
-
-uint GetNumOriginalSounds(void)
-{
-	return _file_count;
-}
-
-static bool SetBankSource(MixerChannel *mc, uint bank)
-{
-	const FileEntry *fe;
-	int8 *mem;
-	uint i;
-
-	if (bank >= GetNumSounds()) return false;
-	fe = GetSound(bank);
-
-	if (fe->file_size == 0) return false;
-
-	mem = malloc(fe->file_size);
-	if (mem == NULL) return false;
-
-	FioSeekToFile(fe->file_offset);
-	FioReadBlock(mem, fe->file_size);
-
-	for (i = 0; i != fe->file_size; i++)
-		mem[i] += -128; // Convert unsigned sound data to signed
-
-	assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
-
-	MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
-
-	return true;
-}
-
-bool SoundInitialize(const char *filename)
-{
-	OpenBankFile(filename);
-	return true;
-}
-
-// Low level sound player
-static void StartSound(uint sound, int panning, uint volume)
-{
-	MixerChannel *mc;
-	uint left_vol, right_vol;
-
-	if (volume == 0) return;
-	mc = MxAllocateChannel();
-	if (mc == NULL) return;
-	if (!SetBankSource(mc, sound)) return;
-
-	panning = clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
-	left_vol = (volume * PANNING_LEVELS) - (volume * panning);
-	right_vol = (volume * PANNING_LEVELS) + (volume * panning);
-	MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
-	MxActivateChannel(mc);
-}
-
-
-static const byte _vol_factor_by_zoom[] = {255, 190, 134};
-
-static const byte _sound_base_vol[] = {
-	128,  90, 128, 128, 128, 128, 128, 128,
-	128,  90,  90, 128, 128, 128, 128, 128,
-	128, 128, 128,  80, 128, 128, 128, 128,
-	128, 128, 128, 128, 128, 128, 128, 128,
-	128, 128,  90,  90,  90, 128,  90, 128,
-	128,  90, 128, 128, 128,  90, 128, 128,
-	128, 128, 128, 128,  90, 128, 128, 128,
-	128,  90, 128, 128, 128, 128, 128, 128,
-	128, 128,  90,  90,  90, 128, 128, 128,
-	 90,
-};
-
-static const byte _sound_idx[] = {
-	 2,  3,  4,  5,  6,  7,  8,  9,
-	10, 11, 12, 13, 14, 15, 16, 17,
-	18, 19, 20, 21, 22, 23, 24, 25,
-	26, 27, 28, 29, 30, 31, 32, 33,
-	34, 35, 36, 37, 38, 39, 40,  0,
-	 1, 41, 42, 43, 44, 45, 46, 47,
-	48, 49, 50, 51, 52, 53, 54, 55,
-	56, 57, 58, 59, 60, 61, 62, 63,
-	64, 65, 66, 67, 68, 69, 70, 71,
-	72,
-};
-
-void SndCopyToPool(void)
-{
-	uint i;
-
-	for (i = 0; i < _file_count; i++) {
-		FileEntry *orig = &_files[_sound_idx[i]];
-		FileEntry *fe = AllocateFileEntry();
-
-		*fe = *orig;
-		fe->volume = _sound_base_vol[i];
-		fe->priority = 0;
-	}
-}
-
-static void SndPlayScreenCoordFx(SoundFx sound, int x, int y)
-{
-	Window* const *wz;
-
-	if (msf.effect_vol == 0) return;
-
-	FOR_ALL_WINDOWS(wz) {
-		const ViewPort *vp = (*wz)->viewport;
-
-		if (vp != NULL &&
-				IS_INSIDE_1D(x, vp->virtual_left, vp->virtual_width) &&
-				IS_INSIDE_1D(y, vp->virtual_top, vp->virtual_height)) {
-			int left = (x - vp->virtual_left);
-
-			StartSound(
-				sound,
-				left / (vp->virtual_width / ((PANNING_LEVELS << 1) + 1)) - PANNING_LEVELS,
-				(GetSound(sound)->volume * msf.effect_vol * _vol_factor_by_zoom[vp->zoom]) >> 15
-			);
-			return;
-		}
-	}
-
-}
-
-void SndPlayTileFx(SoundFx sound, TileIndex tile)
-{
-	/* emits sound from center of the tile */
-	int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
-	int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
-	Point pt = RemapCoords(x, y, GetSlopeZ(x, y));
-	SndPlayScreenCoordFx(sound, pt.x, pt.y);
-}
-
-void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
-{
-	SndPlayScreenCoordFx(sound,
-		(v->left_coord + v->right_coord) / 2,
-		(v->top_coord + v->bottom_coord) / 2
-	);
-}
-
-void SndPlayFx(SoundFx sound)
-{
-	StartSound(
-		sound,
-		0,
-		(GetSound(sound)->volume * msf.effect_vol) >> 7
-	);
-}
new file mode 100644
--- /dev/null
+++ b/src/sound.cpp
@@ -0,0 +1,244 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "map.h"
+#include "mixer.h"
+#include "sound.h"
+#include "vehicle.h"
+#include "window.h"
+#include "viewport.h"
+#include "fileio.h"
+#include "newgrf_sound.h"
+
+static uint _file_count;
+static FileEntry *_files;
+
+#define SOUND_SLOT 63
+// Number of levels of panning per side
+#define PANNING_LEVELS 16
+
+
+static void OpenBankFile(const char *filename)
+{
+	FileEntry *fe;
+	uint count;
+	uint i;
+
+	FioOpenFile(SOUND_SLOT, filename);
+	count = FioReadDword() / 8;
+	fe = calloc(count, sizeof(*fe));
+
+	if (fe == NULL) {
+		_file_count = 0;
+		_files = NULL;
+		return;
+	}
+
+	_file_count = count;
+	_files = fe;
+
+	FioSeekTo(0, SEEK_SET);
+
+	for (i = 0; i != count; i++) {
+		fe[i].file_offset = FioReadDword();
+		fe[i].file_size = FioReadDword();
+	}
+
+	for (i = 0; i != count; i++, fe++) {
+		char name[255];
+
+		FioSeekTo(fe->file_offset, SEEK_SET);
+
+		// Check for special case, see else case
+		FioReadBlock(name, FioReadByte()); // Read the name of the sound
+		if (strcmp(name, "Corrupt sound") != 0) {
+			FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
+
+			// Read riff tags
+			for (;;) {
+				uint32 tag = FioReadDword();
+				uint32 size = FioReadDword();
+
+				if (tag == ' tmf') {
+					FioReadWord(); // wFormatTag
+					fe->channels = FioReadWord(); // wChannels
+					FioReadDword();   // samples per second
+					fe->rate = 11025; // seems like all samples should be played at this rate.
+					FioReadDword();   // avg bytes per second
+					FioReadWord();    // alignment
+					fe->bits_per_sample = FioReadByte(); // bits per sample
+					FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
+				} else if (tag == 'atad') {
+					fe->file_size = size;
+					fe->file_offset = FioGetPos() | (SOUND_SLOT << 24);
+					break;
+				} else {
+					fe->file_size = 0;
+					break;
+				}
+			}
+		} else {
+			/*
+			 * Special case for the jackhammer sound
+			 * (name in sample.cat is "Corrupt sound")
+			 * It's no RIFF file, but raw PCM data
+			 */
+			fe->channels = 1;
+			fe->rate = 11025;
+			fe->bits_per_sample = 8;
+			fe->file_offset = FioGetPos() | (SOUND_SLOT << 24);
+		}
+	}
+}
+
+uint GetNumOriginalSounds(void)
+{
+	return _file_count;
+}
+
+static bool SetBankSource(MixerChannel *mc, uint bank)
+{
+	const FileEntry *fe;
+	int8 *mem;
+	uint i;
+
+	if (bank >= GetNumSounds()) return false;
+	fe = GetSound(bank);
+
+	if (fe->file_size == 0) return false;
+
+	mem = malloc(fe->file_size);
+	if (mem == NULL) return false;
+
+	FioSeekToFile(fe->file_offset);
+	FioReadBlock(mem, fe->file_size);
+
+	for (i = 0; i != fe->file_size; i++)
+		mem[i] += -128; // Convert unsigned sound data to signed
+
+	assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
+
+	MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
+
+	return true;
+}
+
+bool SoundInitialize(const char *filename)
+{
+	OpenBankFile(filename);
+	return true;
+}
+
+// Low level sound player
+static void StartSound(uint sound, int panning, uint volume)
+{
+	MixerChannel *mc;
+	uint left_vol, right_vol;
+
+	if (volume == 0) return;
+	mc = MxAllocateChannel();
+	if (mc == NULL) return;
+	if (!SetBankSource(mc, sound)) return;
+
+	panning = clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
+	left_vol = (volume * PANNING_LEVELS) - (volume * panning);
+	right_vol = (volume * PANNING_LEVELS) + (volume * panning);
+	MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
+	MxActivateChannel(mc);
+}
+
+
+static const byte _vol_factor_by_zoom[] = {255, 190, 134};
+
+static const byte _sound_base_vol[] = {
+	128,  90, 128, 128, 128, 128, 128, 128,
+	128,  90,  90, 128, 128, 128, 128, 128,
+	128, 128, 128,  80, 128, 128, 128, 128,
+	128, 128, 128, 128, 128, 128, 128, 128,
+	128, 128,  90,  90,  90, 128,  90, 128,
+	128,  90, 128, 128, 128,  90, 128, 128,
+	128, 128, 128, 128,  90, 128, 128, 128,
+	128,  90, 128, 128, 128, 128, 128, 128,
+	128, 128,  90,  90,  90, 128, 128, 128,
+	 90,
+};
+
+static const byte _sound_idx[] = {
+	 2,  3,  4,  5,  6,  7,  8,  9,
+	10, 11, 12, 13, 14, 15, 16, 17,
+	18, 19, 20, 21, 22, 23, 24, 25,
+	26, 27, 28, 29, 30, 31, 32, 33,
+	34, 35, 36, 37, 38, 39, 40,  0,
+	 1, 41, 42, 43, 44, 45, 46, 47,
+	48, 49, 50, 51, 52, 53, 54, 55,
+	56, 57, 58, 59, 60, 61, 62, 63,
+	64, 65, 66, 67, 68, 69, 70, 71,
+	72,
+};
+
+void SndCopyToPool(void)
+{
+	uint i;
+
+	for (i = 0; i < _file_count; i++) {
+		FileEntry *orig = &_files[_sound_idx[i]];
+		FileEntry *fe = AllocateFileEntry();
+
+		*fe = *orig;
+		fe->volume = _sound_base_vol[i];
+		fe->priority = 0;
+	}
+}
+
+static void SndPlayScreenCoordFx(SoundFx sound, int x, int y)
+{
+	Window* const *wz;
+
+	if (msf.effect_vol == 0) return;
+
+	FOR_ALL_WINDOWS(wz) {
+		const ViewPort *vp = (*wz)->viewport;
+
+		if (vp != NULL &&
+				IS_INSIDE_1D(x, vp->virtual_left, vp->virtual_width) &&
+				IS_INSIDE_1D(y, vp->virtual_top, vp->virtual_height)) {
+			int left = (x - vp->virtual_left);
+
+			StartSound(
+				sound,
+				left / (vp->virtual_width / ((PANNING_LEVELS << 1) + 1)) - PANNING_LEVELS,
+				(GetSound(sound)->volume * msf.effect_vol * _vol_factor_by_zoom[vp->zoom]) >> 15
+			);
+			return;
+		}
+	}
+
+}
+
+void SndPlayTileFx(SoundFx sound, TileIndex tile)
+{
+	/* emits sound from center of the tile */
+	int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
+	int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
+	Point pt = RemapCoords(x, y, GetSlopeZ(x, y));
+	SndPlayScreenCoordFx(sound, pt.x, pt.y);
+}
+
+void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
+{
+	SndPlayScreenCoordFx(sound,
+		(v->left_coord + v->right_coord) / 2,
+		(v->top_coord + v->bottom_coord) / 2
+	);
+}
+
+void SndPlayFx(SoundFx sound)
+{
+	StartSound(
+		sound,
+		0,
+		(GetSound(sound)->volume * msf.effect_vol) >> 7
+	);
+}
deleted file mode 100644
--- a/src/sound/cocoa_s.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* $Id$ */
-
-/*****************************************************************************
- *                             Cocoa sound driver                            *
- * Known things left to do:                                                  *
- * - Might need to do endian checking for it to work on both ppc and x86     *
- *****************************************************************************/
-
-#ifdef WITH_COCOA
-
-#include <AudioUnit/AudioUnit.h>
-
-/* Name conflict */
-#define Rect        OTTDRect
-#define Point       OTTDPoint
-#define WindowClass OTTDWindowClass
-/* Defined in stdbool.h */
-#ifndef __cplusplus
-# ifndef __BEOS__
-#  undef bool
-#  undef false
-#  undef true
-# endif
-#endif
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../debug.h"
-#include "../driver.h"
-#include "../mixer.h"
-#include "../sdl.h"
-
-#include "cocoa_s.h"
-
-#undef WindowClass
-#undef Point
-#undef Rect
-
-
-static AudioUnit _outputAudioUnit;
-
-/* The CoreAudio callback */
-static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
-{
-	MxMixSamples(ioData->mData, ioData->mDataByteSize / 4);
-
-	return noErr;
-}
-
-
-static const char *CocoaSoundStart(const char * const *parm)
-{
-	Component comp;
-	ComponentDescription desc;
-	struct AudioUnitInputCallback callback;
-	AudioStreamBasicDescription requestedDesc;
-
-	/* Setup a AudioStreamBasicDescription with the requested format */
-	requestedDesc.mFormatID = kAudioFormatLinearPCM;
-	requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
-	requestedDesc.mChannelsPerFrame = 2;
-	requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025);
-
-	requestedDesc.mBitsPerChannel = 16;
-	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
-
-#ifdef TTD_BIG_ENDIAN
-	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-#endif
-
-	requestedDesc.mFramesPerPacket = 1;
-	requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
-	requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
-
-
-	/* Locate the default output audio unit */
-	desc.componentType = kAudioUnitComponentType;
-	desc.componentSubType = kAudioUnitSubType_Output;
-	desc.componentManufacturer = kAudioUnitID_DefaultOutput;
-	desc.componentFlags = 0;
-	desc.componentFlagsMask = 0;
-
-	comp = FindNextComponent (NULL, &desc);
-	if (comp == NULL) {
-		return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
-	}
-
-	/* Open & initialize the default output audio unit */
-	if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
-		return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
-	}
-
-	if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
-		return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
-	}
-
-	/* Set the input format of the audio unit. */
-	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
-		return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
-	}
-
-	/* Set the audio callback */
-	callback.inputProc = audioCallback;
-	callback.inputProcRefCon = NULL;
-	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
-		return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)";
-	}
-
-	/* Finally, start processing of the audio unit */
-	if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
-		return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
-	}
-
-	/* We're running! */
-	return NULL;
-}
-
-
-static void CocoaSoundStop(void)
-{
-	struct AudioUnitInputCallback callback;
-
-	/* stop processing the audio unit */
-	if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
-		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
-		return;
-	}
-
-	/* Remove the input callback */
-	callback.inputProc = 0;
-	callback.inputProcRefCon = 0;
-	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
-		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback) failed");
-		return;
-	}
-
-	if (CloseComponent(_outputAudioUnit) != noErr) {
-		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
-		return;
-	}
-}
-
-
-const HalSoundDriver _cocoa_sound_driver = {
-	CocoaSoundStart,
-	CocoaSoundStop,
-};
-
-#endif /* WITH_COCOA */
new file mode 100644
--- /dev/null
+++ b/src/sound/cocoa_s.cpp
@@ -0,0 +1,149 @@
+/* $Id$ */
+
+/*****************************************************************************
+ *                             Cocoa sound driver                            *
+ * Known things left to do:                                                  *
+ * - Might need to do endian checking for it to work on both ppc and x86     *
+ *****************************************************************************/
+
+#ifdef WITH_COCOA
+
+#include <AudioUnit/AudioUnit.h>
+
+/* Name conflict */
+#define Rect        OTTDRect
+#define Point       OTTDPoint
+#define WindowClass OTTDWindowClass
+/* Defined in stdbool.h */
+#ifndef __cplusplus
+# ifndef __BEOS__
+#  undef bool
+#  undef false
+#  undef true
+# endif
+#endif
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../debug.h"
+#include "../driver.h"
+#include "../mixer.h"
+#include "../sdl.h"
+
+#include "cocoa_s.h"
+
+#undef WindowClass
+#undef Point
+#undef Rect
+
+
+static AudioUnit _outputAudioUnit;
+
+/* The CoreAudio callback */
+static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
+{
+	MxMixSamples(ioData->mData, ioData->mDataByteSize / 4);
+
+	return noErr;
+}
+
+
+static const char *CocoaSoundStart(const char * const *parm)
+{
+	Component comp;
+	ComponentDescription desc;
+	struct AudioUnitInputCallback callback;
+	AudioStreamBasicDescription requestedDesc;
+
+	/* Setup a AudioStreamBasicDescription with the requested format */
+	requestedDesc.mFormatID = kAudioFormatLinearPCM;
+	requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
+	requestedDesc.mChannelsPerFrame = 2;
+	requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 11025);
+
+	requestedDesc.mBitsPerChannel = 16;
+	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+
+#ifdef TTD_BIG_ENDIAN
+	requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
+#endif
+
+	requestedDesc.mFramesPerPacket = 1;
+	requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
+	requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
+
+
+	/* Locate the default output audio unit */
+	desc.componentType = kAudioUnitComponentType;
+	desc.componentSubType = kAudioUnitSubType_Output;
+	desc.componentManufacturer = kAudioUnitID_DefaultOutput;
+	desc.componentFlags = 0;
+	desc.componentFlagsMask = 0;
+
+	comp = FindNextComponent (NULL, &desc);
+	if (comp == NULL) {
+		return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
+	}
+
+	/* Open & initialize the default output audio unit */
+	if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
+		return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
+	}
+
+	if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
+		return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
+	}
+
+	/* Set the input format of the audio unit. */
+	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
+		return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
+	}
+
+	/* Set the audio callback */
+	callback.inputProc = audioCallback;
+	callback.inputProcRefCon = NULL;
+	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
+		return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)";
+	}
+
+	/* Finally, start processing of the audio unit */
+	if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
+		return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
+	}
+
+	/* We're running! */
+	return NULL;
+}
+
+
+static void CocoaSoundStop(void)
+{
+	struct AudioUnitInputCallback callback;
+
+	/* stop processing the audio unit */
+	if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
+		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
+		return;
+	}
+
+	/* Remove the input callback */
+	callback.inputProc = 0;
+	callback.inputProcRefCon = 0;
+	if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
+		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback) failed");
+		return;
+	}
+
+	if (CloseComponent(_outputAudioUnit) != noErr) {
+		DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
+		return;
+	}
+}
+
+
+const HalSoundDriver _cocoa_sound_driver = {
+	CocoaSoundStart,
+	CocoaSoundStop,
+};
+
+#endif /* WITH_COCOA */
deleted file mode 100644
--- a/src/sound/null_s.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "null_s.h"
-
-static const char *NullSoundStart(const char * const *parm) { return NULL; }
-static void NullSoundStop(void) {}
-
-const HalSoundDriver _null_sound_driver = {
-	NullSoundStart,
-	NullSoundStop,
-};
new file mode 100644
--- /dev/null
+++ b/src/sound/null_s.cpp
@@ -0,0 +1,13 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "null_s.h"
+
+static const char *NullSoundStart(const char * const *parm) { return NULL; }
+static void NullSoundStop(void) {}
+
+const HalSoundDriver _null_sound_driver = {
+	NullSoundStart,
+	NullSoundStop,
+};
deleted file mode 100644
--- a/src/sound/sdl_s.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-
-#ifdef WITH_SDL
-
-#include "../openttd.h"
-#include "../driver.h"
-#include "../mixer.h"
-#include "../sdl.h"
-#include "sdl_s.h"
-#include <SDL.h>
-
-static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len)
-{
-	MxMixSamples(stream, len / 4);
-}
-
-static const char *SdlSoundStart(const char * const *parm)
-{
-	SDL_AudioSpec spec;
-
-	const char *s = SdlOpen(SDL_INIT_AUDIO);
-	if (s != NULL) return s;
-
-	spec.freq = GetDriverParamInt(parm, "hz", 11025);
-	spec.format = AUDIO_S16SYS;
-	spec.channels = 2;
-	spec.samples = 512;
-	spec.callback = fill_sound_buffer;
-	SDL_CALL SDL_OpenAudio(&spec, &spec);
-	SDL_CALL SDL_PauseAudio(0);
-	return NULL;
-}
-
-static void SdlSoundStop(void)
-{
-	SDL_CALL SDL_CloseAudio();
-	SdlClose(SDL_INIT_AUDIO);
-}
-
-const HalSoundDriver _sdl_sound_driver = {
-	SdlSoundStart,
-	SdlSoundStop,
-};
-
-#endif
new file mode 100644
--- /dev/null
+++ b/src/sound/sdl_s.cpp
@@ -0,0 +1,47 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+
+#ifdef WITH_SDL
+
+#include "../openttd.h"
+#include "../driver.h"
+#include "../mixer.h"
+#include "../sdl.h"
+#include "sdl_s.h"
+#include <SDL.h>
+
+static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len)
+{
+	MxMixSamples(stream, len / 4);
+}
+
+static const char *SdlSoundStart(const char * const *parm)
+{
+	SDL_AudioSpec spec;
+
+	const char *s = SdlOpen(SDL_INIT_AUDIO);
+	if (s != NULL) return s;
+
+	spec.freq = GetDriverParamInt(parm, "hz", 11025);
+	spec.format = AUDIO_S16SYS;
+	spec.channels = 2;
+	spec.samples = 512;
+	spec.callback = fill_sound_buffer;
+	SDL_CALL SDL_OpenAudio(&spec, &spec);
+	SDL_CALL SDL_PauseAudio(0);
+	return NULL;
+}
+
+static void SdlSoundStop(void)
+{
+	SDL_CALL SDL_CloseAudio();
+	SdlClose(SDL_INIT_AUDIO);
+}
+
+const HalSoundDriver _sdl_sound_driver = {
+	SdlSoundStart,
+	SdlSoundStop,
+};
+
+#endif
deleted file mode 100644
--- a/src/sound/win32_s.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../driver.h"
-#include "../functions.h"
-#include "../mixer.h"
-#include "win32_s.h"
-#include <windows.h>
-#include <mmsystem.h>
-
-static HWAVEOUT _waveout;
-static WAVEHDR _wave_hdr[2];
-static int _bufsize;
-
-static void PrepareHeader(WAVEHDR *hdr)
-{
-	hdr->dwBufferLength = _bufsize * 4;
-	hdr->dwFlags = 0;
-	hdr->lpData = malloc(_bufsize * 4);
-	if (hdr->lpData == NULL ||
-			waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
-		error("waveOutPrepareHeader failed");
-}
-
-static void FillHeaders(void)
-{
-	WAVEHDR *hdr;
-
-	for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
-		if (!(hdr->dwFlags & WHDR_INQUEUE)) {
-			MxMixSamples(hdr->lpData, hdr->dwBufferLength / 4);
-			if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
-				error("waveOutWrite failed");
-		}
-	}
-}
-
-static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
-	DWORD dwParam1, DWORD dwParam2)
-{
-	switch (uMsg) {
-		case WOM_DONE:
-			if (_waveout) FillHeaders();
-			break;
-
-		default:
-			break;
-	}
-}
-
-static const char *Win32SoundStart(const char* const* parm)
-{
-	WAVEFORMATEX wfex;
-	int hz;
-
-	_bufsize = GetDriverParamInt(parm, "bufsize", 1024);
-	hz = GetDriverParamInt(parm, "hz", 11025);
-	wfex.wFormatTag = WAVE_FORMAT_PCM;
-	wfex.nChannels = 2;
-	wfex.nSamplesPerSec = hz;
-	wfex.nAvgBytesPerSec = hz * 2 * 2;
-	wfex.nBlockAlign = 4;
-	wfex.wBitsPerSample = 16;
-	if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD_PTR)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
-		return "waveOutOpen failed";
-	PrepareHeader(&_wave_hdr[0]);
-	PrepareHeader(&_wave_hdr[1]);
-	FillHeaders();
-	return NULL;
-}
-
-static void Win32SoundStop(void)
-{
-	HWAVEOUT waveout = _waveout;
-
-	_waveout = NULL;
-	waveOutReset(waveout);
-	waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR));
-	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
-	waveOutClose(waveout);
-}
-
-const HalSoundDriver _win32_sound_driver = {
-	Win32SoundStart,
-	Win32SoundStop,
-};
new file mode 100644
--- /dev/null
+++ b/src/sound/win32_s.cpp
@@ -0,0 +1,87 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../driver.h"
+#include "../functions.h"
+#include "../mixer.h"
+#include "win32_s.h"
+#include <windows.h>
+#include <mmsystem.h>
+
+static HWAVEOUT _waveout;
+static WAVEHDR _wave_hdr[2];
+static int _bufsize;
+
+static void PrepareHeader(WAVEHDR *hdr)
+{
+	hdr->dwBufferLength = _bufsize * 4;
+	hdr->dwFlags = 0;
+	hdr->lpData = malloc(_bufsize * 4);
+	if (hdr->lpData == NULL ||
+			waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
+		error("waveOutPrepareHeader failed");
+}
+
+static void FillHeaders(void)
+{
+	WAVEHDR *hdr;
+
+	for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
+		if (!(hdr->dwFlags & WHDR_INQUEUE)) {
+			MxMixSamples(hdr->lpData, hdr->dwBufferLength / 4);
+			if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
+				error("waveOutWrite failed");
+		}
+	}
+}
+
+static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+	DWORD dwParam1, DWORD dwParam2)
+{
+	switch (uMsg) {
+		case WOM_DONE:
+			if (_waveout) FillHeaders();
+			break;
+
+		default:
+			break;
+	}
+}
+
+static const char *Win32SoundStart(const char* const* parm)
+{
+	WAVEFORMATEX wfex;
+	int hz;
+
+	_bufsize = GetDriverParamInt(parm, "bufsize", 1024);
+	hz = GetDriverParamInt(parm, "hz", 11025);
+	wfex.wFormatTag = WAVE_FORMAT_PCM;
+	wfex.nChannels = 2;
+	wfex.nSamplesPerSec = hz;
+	wfex.nAvgBytesPerSec = hz * 2 * 2;
+	wfex.nBlockAlign = 4;
+	wfex.wBitsPerSample = 16;
+	if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD_PTR)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
+		return "waveOutOpen failed";
+	PrepareHeader(&_wave_hdr[0]);
+	PrepareHeader(&_wave_hdr[1]);
+	FillHeaders();
+	return NULL;
+}
+
+static void Win32SoundStop(void)
+{
+	HWAVEOUT waveout = _waveout;
+
+	_waveout = NULL;
+	waveOutReset(waveout);
+	waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR));
+	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
+	waveOutClose(waveout);
+}
+
+const HalSoundDriver _win32_sound_driver = {
+	Win32SoundStart,
+	Win32SoundStop,
+};
deleted file mode 100644
--- a/src/spritecache.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "macros.h"
-#include "spritecache.h"
-#include "table/sprites.h"
-#include "fileio.h"
-
-#define SPRITE_CACHE_SIZE 1024*1024
-
-
-typedef struct SpriteCache {
-	void *ptr;
-	uint32 file_pos;
-	int16 lru;
-} SpriteCache;
-
-
-static uint _spritecache_items = 0;
-static SpriteCache *_spritecache = NULL;
-
-
-static inline SpriteCache *GetSpriteCache(uint index)
-{
-	return &_spritecache[index];
-}
-
-
-static SpriteCache *AllocateSpriteCache(uint index)
-{
-	if (index >= _spritecache_items) {
-		/* Add another 1024 items to the 'pool' */
-		uint items = ALIGN(index + 1, 1024);
-
-		DEBUG(sprite, 4, "Increasing sprite cache to %d items (%d bytes)", items, items * sizeof(*_spritecache));
-
-		_spritecache = realloc(_spritecache, items * sizeof(*_spritecache));
-
-		if (_spritecache == NULL) {
-			error("Unable to allocate sprite cache of %d items (%d bytes)", items, items * sizeof(*_spritecache));
-		}
-
-		/* Reset the new items and update the count */
-		memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) * sizeof(*_spritecache));
-		_spritecache_items = items;
-	}
-
-	return GetSpriteCache(index);
-}
-
-
-typedef struct MemBlock {
-	uint32 size;
-	byte data[VARARRAY_SIZE];
-} MemBlock;
-
-static uint _sprite_lru_counter;
-static MemBlock *_spritecache_ptr;
-static int _compact_cache_counter;
-
-static void CompactSpriteCache(void);
-
-static bool ReadSpriteHeaderSkipData(void)
-{
-	uint16 num = FioReadWord();
-	byte type;
-
-	if (num == 0) return false;
-
-	type = FioReadByte();
-	if (type == 0xFF) {
-		FioSkipBytes(num);
-		/* Some NewGRF files have "empty" pseudo-sprites which are 1
-		 * byte long. Catch these so the sprites won't be displayed. */
-		return num != 1;
-	}
-
-	FioSkipBytes(7);
-	num -= 8;
-	if (num == 0) return true;
-
-	if (type & 2) {
-		FioSkipBytes(num);
-	} else {
-		while (num > 0) {
-			int8 i = FioReadByte();
-			if (i >= 0) {
-				num -= i;
-				FioSkipBytes(i);
-			} else {
-				i = -(i >> 3);
-				num -= i;
-				FioReadByte();
-			}
-		}
-	}
-
-	return true;
-}
-
-/* Check if the given Sprite ID exists */
-bool SpriteExists(SpriteID id)
-{
-	/* Special case for Sprite ID zero -- its position is also 0... */
-	if (id == 0) return true;
-
-	return GetSpriteCache(id)->file_pos != 0;
-}
-
-static void* AllocSprite(size_t);
-
-static void* ReadSprite(SpriteCache *sc, SpriteID id)
-{
-	uint num;
-	byte type;
-
-	DEBUG(sprite, 9, "Load sprite %d", id);
-
-	if (!SpriteExists(id)) {
-		error(
-			"Tried to load non-existing sprite #%d.\n"
-			"Probable cause: Wrong/missing NewGRFs",
-			id
-		);
-	}
-
-	FioSeekToFile(sc->file_pos);
-
-	num  = FioReadWord();
-	type = FioReadByte();
-	if (type == 0xFF) {
-		byte* dest = AllocSprite(num);
-
-		sc->ptr = dest;
-		FioReadBlock(dest, num);
-
-		return dest;
-	} else {
-		uint height = FioReadByte();
-		uint width  = FioReadWord();
-		Sprite* sprite;
-		byte* dest;
-
-		num = (type & 0x02) ? width * height : num - 8;
-		sprite = AllocSprite(sizeof(*sprite) + num);
-		sc->ptr = sprite;
-		sprite->info   = type;
-		sprite->height = (id != 142) ? height : 10; // Compensate for a TTD bug
-		sprite->width  = width;
-		sprite->x_offs = FioReadWord();
-		sprite->y_offs = FioReadWord();
-
-		dest = sprite->data;
-		while (num > 0) {
-			int8 i = FioReadByte();
-
-			if (i >= 0) {
-				num -= i;
-				for (; i > 0; --i) *dest++ = FioReadByte();
-			} else {
-				const byte* rel = dest - (((i & 7) << 8) | FioReadByte());
-
-				i = -(i >> 3);
-				num -= i;
-
-				for (; i > 0; --i) *dest++ = *rel++;
-			}
-		}
-
-		return sprite;
-	}
-}
-
-
-bool LoadNextSprite(int load_index, byte file_index)
-{
-	SpriteCache *sc;
-	uint32 file_pos = FioGetPos() | (file_index << 24);
-
-	if (!ReadSpriteHeaderSkipData()) return false;
-
-	if (load_index >= MAX_SPRITES) {
-		error("Tried to load too many sprites (#%d; max %d)", load_index, MAX_SPRITES);
-	}
-
-	sc = AllocateSpriteCache(load_index);
-	sc->file_pos = file_pos;
-	sc->ptr = NULL;
-	sc->lru = 0;
-
-	return true;
-}
-
-
-void DupSprite(SpriteID old, SpriteID new)
-{
-	SpriteCache *scold = GetSpriteCache(old);
-	SpriteCache *scnew = AllocateSpriteCache(new);
-
-	scnew->file_pos = scold->file_pos;
-	scnew->ptr = NULL;
-}
-
-
-void SkipSprites(uint count)
-{
-	for (; count > 0; --count) {
-		if (!ReadSpriteHeaderSkipData()) return;
-	}
-}
-
-
-#define S_FREE_MASK 1
-
-static inline MemBlock* NextBlock(MemBlock* block)
-{
-	return (MemBlock*)((byte*)block + (block->size & ~S_FREE_MASK));
-}
-
-static uint32 GetSpriteCacheUsage(void)
-{
-	uint32 tot_size = 0;
-	MemBlock* s;
-
-	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s))
-		if (!(s->size & S_FREE_MASK)) tot_size += s->size;
-
-	return tot_size;
-}
-
-
-void IncreaseSpriteLRU(void)
-{
-	// Increase all LRU values
-	if (_sprite_lru_counter > 16384) {
-		SpriteID i;
-
-		DEBUG(sprite, 3, "Fixing lru %d, inuse=%d", _sprite_lru_counter, GetSpriteCacheUsage());
-
-		for (i = 0; i != _spritecache_items; i++) {
-			SpriteCache *sc = GetSpriteCache(i);
-			if (sc->ptr != NULL) {
-				if (sc->lru >= 0) {
-					sc->lru = -1;
-				} else if (sc->lru != -32768) {
-					sc->lru--;
-				}
-			}
-		}
-		_sprite_lru_counter = 0;
-	}
-
-	// Compact sprite cache every now and then.
-	if (++_compact_cache_counter >= 740) {
-		CompactSpriteCache();
-		_compact_cache_counter = 0;
-	}
-}
-
-// Called when holes in the sprite cache should be removed.
-// That is accomplished by moving the cached data.
-static void CompactSpriteCache(void)
-{
-	MemBlock *s;
-
-	DEBUG(sprite, 3, "Compacting sprite cache, inuse=%d", GetSpriteCacheUsage());
-
-	for (s = _spritecache_ptr; s->size != 0;) {
-		if (s->size & S_FREE_MASK) {
-			MemBlock* next = NextBlock(s);
-			MemBlock temp;
-			SpriteID i;
-
-			// Since free blocks are automatically coalesced, this should hold true.
-			assert(!(next->size & S_FREE_MASK));
-
-			// If the next block is the sentinel block, we can safely return
-			if (next->size == 0)
-				break;
-
-			// Locate the sprite belonging to the next pointer.
-			for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
-				assert(i != _spritecache_items);
-			}
-
-			GetSpriteCache(i)->ptr = s->data; // Adjust sprite array entry
-			// Swap this and the next block
-			temp = *s;
-			memmove(s, next, next->size);
-			s = NextBlock(s);
-			*s = temp;
-
-			// Coalesce free blocks
-			while (NextBlock(s)->size & S_FREE_MASK) {
-				s->size += NextBlock(s)->size & ~S_FREE_MASK;
-			}
-		} else {
-			s = NextBlock(s);
-		}
-	}
-}
-
-static void DeleteEntryFromSpriteCache(void)
-{
-	SpriteID i;
-	uint best = -1;
-	MemBlock* s;
-	int cur_lru;
-
-	DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=%d", GetSpriteCacheUsage());
-
-	cur_lru = 0xffff;
-	for (i = 0; i != _spritecache_items; i++) {
-		SpriteCache *sc = GetSpriteCache(i);
-		if (sc->ptr != NULL && sc->lru < cur_lru) {
-			cur_lru = sc->lru;
-			best = i;
-		}
-	}
-
-	// Display an error message and die, in case we found no sprite at all.
-	// This shouldn't really happen, unless all sprites are locked.
-	if (best == (uint)-1)
-		error("Out of sprite memory");
-
-	// Mark the block as free (the block must be in use)
-	s = (MemBlock*)GetSpriteCache(best)->ptr - 1;
-	assert(!(s->size & S_FREE_MASK));
-	s->size |= S_FREE_MASK;
-	GetSpriteCache(best)->ptr = NULL;
-
-	// And coalesce adjacent free blocks
-	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
-		if (s->size & S_FREE_MASK) {
-			while (NextBlock(s)->size & S_FREE_MASK) {
-				s->size += NextBlock(s)->size & ~S_FREE_MASK;
-			}
-		}
-	}
-}
-
-static void* AllocSprite(size_t mem_req)
-{
-	mem_req += sizeof(MemBlock);
-
-	/* Align this to an uint32 boundary. This also makes sure that the 2 least
-	 * bits are not used, so we could use those for other things. */
-	mem_req = ALIGN(mem_req, sizeof(uint32));
-
-	for (;;) {
-		MemBlock* s;
-
-		for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
-			if (s->size & S_FREE_MASK) {
-				size_t cur_size = s->size & ~S_FREE_MASK;
-
-				/* Is the block exactly the size we need or
-				 * big enough for an additional free block? */
-				if (cur_size == mem_req ||
-						cur_size >= mem_req + sizeof(MemBlock)) {
-					// Set size and in use
-					s->size = mem_req;
-
-					// Do we need to inject a free block too?
-					if (cur_size != mem_req) {
-						NextBlock(s)->size = (cur_size - mem_req) | S_FREE_MASK;
-					}
-
-					return s->data;
-				}
-			}
-		}
-
-		// Reached sentinel, but no block found yet. Delete some old entry.
-		DeleteEntryFromSpriteCache();
-	}
-}
-
-
-const void *GetRawSprite(SpriteID sprite)
-{
-	SpriteCache *sc;
-	void* p;
-
-	assert(sprite < MAX_SPRITES);
-
-	sc = GetSpriteCache(sprite);
-
-	// Update LRU
-	sc->lru = ++_sprite_lru_counter;
-
-	p = sc->ptr;
-
-	// Load the sprite, if it is not loaded, yet
-	if (p == NULL) p = ReadSprite(sc, sprite);
-	return p;
-}
-
-
-void GfxInitSpriteMem(void)
-{
-	// initialize sprite cache heap
-	if (_spritecache_ptr == NULL) _spritecache_ptr = malloc(SPRITE_CACHE_SIZE);
-
-	// A big free block
-	_spritecache_ptr->size = (SPRITE_CACHE_SIZE - sizeof(MemBlock)) | S_FREE_MASK;
-	// Sentinel block (identified by size == 0)
-	NextBlock(_spritecache_ptr)->size = 0;
-
-	/* Reset the spritecache 'pool' */
-	free(_spritecache);
-	_spritecache_items = 0;
-	_spritecache = NULL;
-
-	_compact_cache_counter = 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/spritecache.cpp
@@ -0,0 +1,419 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "macros.h"
+#include "spritecache.h"
+#include "table/sprites.h"
+#include "fileio.h"
+
+#define SPRITE_CACHE_SIZE 1024*1024
+
+
+typedef struct SpriteCache {
+	void *ptr;
+	uint32 file_pos;
+	int16 lru;
+} SpriteCache;
+
+
+static uint _spritecache_items = 0;
+static SpriteCache *_spritecache = NULL;
+
+
+static inline SpriteCache *GetSpriteCache(uint index)
+{
+	return &_spritecache[index];
+}
+
+
+static SpriteCache *AllocateSpriteCache(uint index)
+{
+	if (index >= _spritecache_items) {
+		/* Add another 1024 items to the 'pool' */
+		uint items = ALIGN(index + 1, 1024);
+
+		DEBUG(sprite, 4, "Increasing sprite cache to %d items (%d bytes)", items, items * sizeof(*_spritecache));
+
+		_spritecache = realloc(_spritecache, items * sizeof(*_spritecache));
+
+		if (_spritecache == NULL) {
+			error("Unable to allocate sprite cache of %d items (%d bytes)", items, items * sizeof(*_spritecache));
+		}
+
+		/* Reset the new items and update the count */
+		memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) * sizeof(*_spritecache));
+		_spritecache_items = items;
+	}
+
+	return GetSpriteCache(index);
+}
+
+
+typedef struct MemBlock {
+	uint32 size;
+	byte data[VARARRAY_SIZE];
+} MemBlock;
+
+static uint _sprite_lru_counter;
+static MemBlock *_spritecache_ptr;
+static int _compact_cache_counter;
+
+static void CompactSpriteCache(void);
+
+static bool ReadSpriteHeaderSkipData(void)
+{
+	uint16 num = FioReadWord();
+	byte type;
+
+	if (num == 0) return false;
+
+	type = FioReadByte();
+	if (type == 0xFF) {
+		FioSkipBytes(num);
+		/* Some NewGRF files have "empty" pseudo-sprites which are 1
+		 * byte long. Catch these so the sprites won't be displayed. */
+		return num != 1;
+	}
+
+	FioSkipBytes(7);
+	num -= 8;
+	if (num == 0) return true;
+
+	if (type & 2) {
+		FioSkipBytes(num);
+	} else {
+		while (num > 0) {
+			int8 i = FioReadByte();
+			if (i >= 0) {
+				num -= i;
+				FioSkipBytes(i);
+			} else {
+				i = -(i >> 3);
+				num -= i;
+				FioReadByte();
+			}
+		}
+	}
+
+	return true;
+}
+
+/* Check if the given Sprite ID exists */
+bool SpriteExists(SpriteID id)
+{
+	/* Special case for Sprite ID zero -- its position is also 0... */
+	if (id == 0) return true;
+
+	return GetSpriteCache(id)->file_pos != 0;
+}
+
+static void* AllocSprite(size_t);
+
+static void* ReadSprite(SpriteCache *sc, SpriteID id)
+{
+	uint num;
+	byte type;
+
+	DEBUG(sprite, 9, "Load sprite %d", id);
+
+	if (!SpriteExists(id)) {
+		error(
+			"Tried to load non-existing sprite #%d.\n"
+			"Probable cause: Wrong/missing NewGRFs",
+			id
+		);
+	}
+
+	FioSeekToFile(sc->file_pos);
+
+	num  = FioReadWord();
+	type = FioReadByte();
+	if (type == 0xFF) {
+		byte* dest = AllocSprite(num);
+
+		sc->ptr = dest;
+		FioReadBlock(dest, num);
+
+		return dest;
+	} else {
+		uint height = FioReadByte();
+		uint width  = FioReadWord();
+		Sprite* sprite;
+		byte* dest;
+
+		num = (type & 0x02) ? width * height : num - 8;
+		sprite = AllocSprite(sizeof(*sprite) + num);
+		sc->ptr = sprite;
+		sprite->info   = type;
+		sprite->height = (id != 142) ? height : 10; // Compensate for a TTD bug
+		sprite->width  = width;
+		sprite->x_offs = FioReadWord();
+		sprite->y_offs = FioReadWord();
+
+		dest = sprite->data;
+		while (num > 0) {
+			int8 i = FioReadByte();
+
+			if (i >= 0) {
+				num -= i;
+				for (; i > 0; --i) *dest++ = FioReadByte();
+			} else {
+				const byte* rel = dest - (((i & 7) << 8) | FioReadByte());
+
+				i = -(i >> 3);
+				num -= i;
+
+				for (; i > 0; --i) *dest++ = *rel++;
+			}
+		}
+
+		return sprite;
+	}
+}
+
+
+bool LoadNextSprite(int load_index, byte file_index)
+{
+	SpriteCache *sc;
+	uint32 file_pos = FioGetPos() | (file_index << 24);
+
+	if (!ReadSpriteHeaderSkipData()) return false;
+
+	if (load_index >= MAX_SPRITES) {
+		error("Tried to load too many sprites (#%d; max %d)", load_index, MAX_SPRITES);
+	}
+
+	sc = AllocateSpriteCache(load_index);
+	sc->file_pos = file_pos;
+	sc->ptr = NULL;
+	sc->lru = 0;
+
+	return true;
+}
+
+
+void DupSprite(SpriteID old, SpriteID new)
+{
+	SpriteCache *scold = GetSpriteCache(old);
+	SpriteCache *scnew = AllocateSpriteCache(new);
+
+	scnew->file_pos = scold->file_pos;
+	scnew->ptr = NULL;
+}
+
+
+void SkipSprites(uint count)
+{
+	for (; count > 0; --count) {
+		if (!ReadSpriteHeaderSkipData()) return;
+	}
+}
+
+
+#define S_FREE_MASK 1
+
+static inline MemBlock* NextBlock(MemBlock* block)
+{
+	return (MemBlock*)((byte*)block + (block->size & ~S_FREE_MASK));
+}
+
+static uint32 GetSpriteCacheUsage(void)
+{
+	uint32 tot_size = 0;
+	MemBlock* s;
+
+	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s))
+		if (!(s->size & S_FREE_MASK)) tot_size += s->size;
+
+	return tot_size;
+}
+
+
+void IncreaseSpriteLRU(void)
+{
+	// Increase all LRU values
+	if (_sprite_lru_counter > 16384) {
+		SpriteID i;
+
+		DEBUG(sprite, 3, "Fixing lru %d, inuse=%d", _sprite_lru_counter, GetSpriteCacheUsage());
+
+		for (i = 0; i != _spritecache_items; i++) {
+			SpriteCache *sc = GetSpriteCache(i);
+			if (sc->ptr != NULL) {
+				if (sc->lru >= 0) {
+					sc->lru = -1;
+				} else if (sc->lru != -32768) {
+					sc->lru--;
+				}
+			}
+		}
+		_sprite_lru_counter = 0;
+	}
+
+	// Compact sprite cache every now and then.
+	if (++_compact_cache_counter >= 740) {
+		CompactSpriteCache();
+		_compact_cache_counter = 0;
+	}
+}
+
+// Called when holes in the sprite cache should be removed.
+// That is accomplished by moving the cached data.
+static void CompactSpriteCache(void)
+{
+	MemBlock *s;
+
+	DEBUG(sprite, 3, "Compacting sprite cache, inuse=%d", GetSpriteCacheUsage());
+
+	for (s = _spritecache_ptr; s->size != 0;) {
+		if (s->size & S_FREE_MASK) {
+			MemBlock* next = NextBlock(s);
+			MemBlock temp;
+			SpriteID i;
+
+			// Since free blocks are automatically coalesced, this should hold true.
+			assert(!(next->size & S_FREE_MASK));
+
+			// If the next block is the sentinel block, we can safely return
+			if (next->size == 0)
+				break;
+
+			// Locate the sprite belonging to the next pointer.
+			for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
+				assert(i != _spritecache_items);
+			}
+
+			GetSpriteCache(i)->ptr = s->data; // Adjust sprite array entry
+			// Swap this and the next block
+			temp = *s;
+			memmove(s, next, next->size);
+			s = NextBlock(s);
+			*s = temp;
+
+			// Coalesce free blocks
+			while (NextBlock(s)->size & S_FREE_MASK) {
+				s->size += NextBlock(s)->size & ~S_FREE_MASK;
+			}
+		} else {
+			s = NextBlock(s);
+		}
+	}
+}
+
+static void DeleteEntryFromSpriteCache(void)
+{
+	SpriteID i;
+	uint best = -1;
+	MemBlock* s;
+	int cur_lru;
+
+	DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=%d", GetSpriteCacheUsage());
+
+	cur_lru = 0xffff;
+	for (i = 0; i != _spritecache_items; i++) {
+		SpriteCache *sc = GetSpriteCache(i);
+		if (sc->ptr != NULL && sc->lru < cur_lru) {
+			cur_lru = sc->lru;
+			best = i;
+		}
+	}
+
+	// Display an error message and die, in case we found no sprite at all.
+	// This shouldn't really happen, unless all sprites are locked.
+	if (best == (uint)-1)
+		error("Out of sprite memory");
+
+	// Mark the block as free (the block must be in use)
+	s = (MemBlock*)GetSpriteCache(best)->ptr - 1;
+	assert(!(s->size & S_FREE_MASK));
+	s->size |= S_FREE_MASK;
+	GetSpriteCache(best)->ptr = NULL;
+
+	// And coalesce adjacent free blocks
+	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
+		if (s->size & S_FREE_MASK) {
+			while (NextBlock(s)->size & S_FREE_MASK) {
+				s->size += NextBlock(s)->size & ~S_FREE_MASK;
+			}
+		}
+	}
+}
+
+static void* AllocSprite(size_t mem_req)
+{
+	mem_req += sizeof(MemBlock);
+
+	/* Align this to an uint32 boundary. This also makes sure that the 2 least
+	 * bits are not used, so we could use those for other things. */
+	mem_req = ALIGN(mem_req, sizeof(uint32));
+
+	for (;;) {
+		MemBlock* s;
+
+		for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
+			if (s->size & S_FREE_MASK) {
+				size_t cur_size = s->size & ~S_FREE_MASK;
+
+				/* Is the block exactly the size we need or
+				 * big enough for an additional free block? */
+				if (cur_size == mem_req ||
+						cur_size >= mem_req + sizeof(MemBlock)) {
+					// Set size and in use
+					s->size = mem_req;
+
+					// Do we need to inject a free block too?
+					if (cur_size != mem_req) {
+						NextBlock(s)->size = (cur_size - mem_req) | S_FREE_MASK;
+					}
+
+					return s->data;
+				}
+			}
+		}
+
+		// Reached sentinel, but no block found yet. Delete some old entry.
+		DeleteEntryFromSpriteCache();
+	}
+}
+
+
+const void *GetRawSprite(SpriteID sprite)
+{
+	SpriteCache *sc;
+	void* p;
+
+	assert(sprite < MAX_SPRITES);
+
+	sc = GetSpriteCache(sprite);
+
+	// Update LRU
+	sc->lru = ++_sprite_lru_counter;
+
+	p = sc->ptr;
+
+	// Load the sprite, if it is not loaded, yet
+	if (p == NULL) p = ReadSprite(sc, sprite);
+	return p;
+}
+
+
+void GfxInitSpriteMem(void)
+{
+	// initialize sprite cache heap
+	if (_spritecache_ptr == NULL) _spritecache_ptr = malloc(SPRITE_CACHE_SIZE);
+
+	// A big free block
+	_spritecache_ptr->size = (SPRITE_CACHE_SIZE - sizeof(MemBlock)) | S_FREE_MASK;
+	// Sentinel block (identified by size == 0)
+	NextBlock(_spritecache_ptr)->size = 0;
+
+	/* Reset the spritecache 'pool' */
+	free(_spritecache);
+	_spritecache_items = 0;
+	_spritecache = NULL;
+
+	_compact_cache_counter = 0;
+}
deleted file mode 100644
--- a/src/station_cmd.c
+++ /dev/null
@@ -1,3285 +0,0 @@
-/* $Id$ */
-
-/** @file station_cmd.c */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "debug.h"
-#include "functions.h"
-#include "station_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "station.h"
-#include "gfx.h"
-#include "window.h"
-#include "viewport.h"
-#include "command.h"
-#include "town.h"
-#include "vehicle.h"
-#include "news.h"
-#include "saveload.h"
-#include "economy.h"
-#include "player.h"
-#include "airport.h"
-#include "sprite.h"
-#include "depot.h"
-#include "train.h"
-#include "water_map.h"
-#include "industry_map.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_station.h"
-#include "yapf/yapf.h"
-#include "date.h"
-
-typedef enum StationRectModes
-{
-	RECT_MODE_TEST = 0,
-	RECT_MODE_TRY,
-	RECT_MODE_FORCE
-} StationRectMode;
-
-static void StationRect_Init(Station *st);
-static bool StationRect_IsEmpty(Station *st);
-static bool StationRect_BeforeAddTile(Station *st, TileIndex tile, StationRectMode mode);
-static bool StationRect_BeforeAddRect(Station *st, TileIndex tile, int w, int h, StationRectMode mode);
-static bool StationRect_AfterRemoveTile(Station *st, TileIndex tile);
-static bool StationRect_AfterRemoveRect(Station *st, TileIndex tile, int w, int h);
-
-
-/**
- * Called if a new block is added to the station-pool
- */
-static void StationPoolNewBlock(uint start_item)
-{
-	Station *st;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 *  TODO - This is just a temporary stage, this will be removed. */
-	for (st = GetStation(start_item); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) st->index = start_item++;
-}
-
-static void StationPoolCleanBlock(uint start_item, uint end_item)
-{
-	uint i;
-
-	for (i = start_item; i <= end_item; i++) {
-		Station *st = GetStation(i);
-		free(st->speclist);
-		st->speclist = NULL;
-	}
-}
-
-/**
- * Called if a new block is added to the roadstop-pool
- */
-static void RoadStopPoolNewBlock(uint start_item)
-{
-	RoadStop *rs;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (rs = GetRoadStop(start_item); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) rs->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Station, Station, StationPoolNewBlock, StationPoolCleanBlock)
-DEFINE_OLD_POOL(RoadStop, RoadStop, RoadStopPoolNewBlock, NULL)
-
-
-extern void UpdateAirplanesOnNewStation(Station *st);
-
-static bool TileBelongsToRailStation(const Station *st, TileIndex tile)
-{
-	return IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile);
-}
-
-void MarkStationTilesDirty(const Station *st)
-{
-	TileIndex tile = st->train_tile;
-	int w, h;
-
-	// XXX No station is recorded as 0, not INVALID_TILE...
-	if (tile == 0) return;
-
-	for (h = 0; h < st->trainst_h; h++) {
-		for (w = 0; w < st->trainst_w; w++) {
-			if (TileBelongsToRailStation(st, tile)) {
-				MarkTileDirtyByTile(tile);
-			}
-			tile += TileDiffXY(1, 0);
-		}
-		tile += TileDiffXY(-w, 1);
-	}
-}
-
-static void MarkStationDirty(const Station* st)
-{
-	if (st->sign.width_1 != 0) {
-		InvalidateWindowWidget(WC_STATION_VIEW, st->index, 1);
-
-		MarkAllViewportsDirty(
-			st->sign.left - 6,
-			st->sign.top,
-			st->sign.left + (st->sign.width_1 << 2) + 12,
-			st->sign.top + 48);
-	}
-}
-
-static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index)
-{
-	road_stop->xy = tile;
-	road_stop->used = true;
-	road_stop->status = 3; //stop is free
-	road_stop->next = NULL;
-	road_stop->prev = previous;
-	road_stop->station = index;
-	road_stop->num_vehicles = 0;
-}
-
-RoadStop* GetPrimaryRoadStop(const Station* st, RoadStopType type)
-{
-	switch (type) {
-		case RS_BUS:   return st->bus_stops;
-		case RS_TRUCK: return st->truck_stops;
-		default: NOT_REACHED();
-	}
-
-	return NULL;
-}
-
-RoadStop* GetRoadStopByTile(TileIndex tile, RoadStopType type)
-{
-	const Station* st = GetStationByTile(tile);
-	RoadStop* rs;
-
-	for (rs = GetPrimaryRoadStop(st, type); rs->xy != tile; rs = rs->next) {
-		assert(rs->next != NULL);
-	}
-
-	return rs;
-}
-
-uint GetNumRoadStopsInStation(const Station* st, RoadStopType type)
-{
-	uint num = 0;
-	const RoadStop *rs;
-
-	assert(st != NULL);
-	for (rs = GetPrimaryRoadStop(st, type); rs != NULL; rs = rs->next) num++;
-
-	return num;
-}
-
-RoadStop *AllocateRoadStop(void)
-{
-	RoadStop *rs;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (rs = GetRoadStop(0); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) {
-		if (!IsValidRoadStop(rs)) {
-			RoadStopID index = rs->index;
-
-			memset(rs, 0, sizeof(*rs));
-			rs->index = index;
-
-			return rs;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_RoadStop_pool)) return AllocateRoadStop();
-
-	return NULL;
-}
-
-/* Calculate the radius of the station. Basicly it is the biggest
- *  radius that is available within the station */
-static uint FindCatchmentRadius(const Station* st)
-{
-	uint ret = 0;
-
-	if (st->bus_stops != NULL)   ret = max(ret, CA_BUS);
-	if (st->truck_stops != NULL) ret = max(ret, CA_TRUCK);
-	if (st->train_tile) ret = max(ret, CA_TRAIN);
-	if (st->dock_tile)  ret = max(ret, CA_DOCK);
-
-	if (st->airport_tile) {
-		switch (st->airport_type) {
-			case AT_OILRIG:        ret = max(ret, CA_AIR_OILPAD);   break;
-			case AT_SMALL:         ret = max(ret, CA_AIR_SMALL);    break;
-			case AT_HELIPORT:      ret = max(ret, CA_AIR_HELIPORT); break;
-			case AT_LARGE:         ret = max(ret, CA_AIR_LARGE);    break;
-			case AT_METROPOLITAN:  ret = max(ret, CA_AIR_METRO);    break;
-			case AT_INTERNATIONAL: ret = max(ret, CA_AIR_INTER);    break;
-			case AT_COMMUTER:      ret = max(ret, CA_AIR_COMMUTER); break;
-			case AT_HELIDEPOT:     ret = max(ret, CA_AIR_HELIDEPOT); break;
-			case AT_INTERCON:      ret = max(ret, CA_AIR_INTERCON); break;
-			case AT_HELISTATION:   ret = max(ret, CA_AIR_HELISTATION); break;
-		}
-	}
-
-	return ret;
-}
-
-#define CHECK_STATIONS_ERR ((Station*)-1)
-
-static Station* GetStationAround(TileIndex tile, int w, int h, StationID closest_station)
-{
-	// check around to see if there's any stations there
-	BEGIN_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1))
-		if (IsTileType(tile_cur, MP_STATION)) {
-			StationID t = GetStationIndex(tile_cur);
-			{
-				Station *st = GetStation(t);
-				// you cannot take control of an oilrig!!
-				if (st->airport_type == AT_OILRIG && st->facilities == (FACIL_AIRPORT|FACIL_DOCK))
-					continue;
-			}
-
-			if (closest_station == INVALID_STATION) {
-				closest_station = t;
-			} else if (closest_station != t) {
-				_error_message = STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING;
-				return CHECK_STATIONS_ERR;
-			}
-		}
-	END_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1))
-	return (closest_station == INVALID_STATION) ? NULL : GetStation(closest_station);
-}
-
-static Station *AllocateStation(void)
-{
-	Station *st = NULL;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (st = GetStation(0); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) {
-		if (!IsValidStation(st)) {
-			StationID index = st->index;
-
-			memset(st, 0, sizeof(Station));
-			st->index = index;
-
-			return st;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Station_pool)) return AllocateStation();
-
-	_error_message = STR_3008_TOO_MANY_STATIONS_LOADING;
-	return NULL;
-}
-
-
-/**
- * Counts the numbers of tiles matching a specific type in the area around
- * @param tile the center tile of the 'count area'
- * @param type the type of tile searched for
- * @param industry when type == MP_INDUSTRY, the type of the industry,
- *                 in all other cases this parameter is ignored
- * @result the noumber of matching tiles around
- */
-static int CountMapSquareAround(TileIndex tile, TileType type, IndustryType industry)
-{
-	TileIndex cur_tile;
-	int dx, dy;
-	int num = 0;
-
-	for (dx = -3; dx <= 3; dx++) {
-		for (dy = -3; dy <= 3; dy++) {
-			cur_tile = TILE_MASK(tile + TileDiffXY(dx, dy));
-
-			if (IsTileType(cur_tile, type)) {
-				switch (type) {
-					case MP_INDUSTRY:
-						if (GetIndustryType(cur_tile) == industry)
-							num++;
-						break;
-
-					case MP_WATER:
-						if (!IsWater(cur_tile))
-							break;
-						/* FALL THROUGH WHEN WATER TILE */
-					case MP_TREES:
-						num++;
-						break;
-
-					default:
-						break;
-				}
-			}
-		}
-	}
-
-	return num;
-}
-
-#define M(x) ((x) - STR_SV_STNAME)
-
-static bool GenerateStationName(Station *st, TileIndex tile, int flag)
-{
-	static const uint32 _gen_station_name_bits[] = {
-		0,                                      /* 0 */
-		1 << M(STR_SV_STNAME_AIRPORT),          /* 1 */
-		1 << M(STR_SV_STNAME_OILFIELD),         /* 2 */
-		1 << M(STR_SV_STNAME_DOCKS),            /* 3 */
-		0x1FF << M(STR_SV_STNAME_BUOY_1),       /* 4 */
-		1 << M(STR_SV_STNAME_HELIPORT),         /* 5 */
-	};
-
-	Town *t = st->town;
-	uint32 free_names = (uint32)-1;
-	int found;
-	uint z,z2;
-	unsigned long tmp;
-
-	{
-		Station *s;
-
-		FOR_ALL_STATIONS(s) {
-			if (s != st && s->town==t) {
-				uint str = M(s->string_id);
-				if (str <= 0x20) {
-					if (str == M(STR_SV_STNAME_FOREST))
-						str = M(STR_SV_STNAME_WOODS);
-					CLRBIT(free_names, str);
-				}
-			}
-		}
-	}
-
-	/* check default names */
-	tmp = free_names & _gen_station_name_bits[flag];
-	if (tmp != 0) {
-		found = FindFirstBit(tmp);
-		goto done;
-	}
-
-	/* check mine? */
-	if (HASBIT(free_names, M(STR_SV_STNAME_MINES))) {
-		if (CountMapSquareAround(tile, MP_INDUSTRY, IT_COAL_MINE) >= 2 ||
-				CountMapSquareAround(tile, MP_INDUSTRY, IT_IRON_MINE) >= 2 ||
-				CountMapSquareAround(tile, MP_INDUSTRY, IT_COPPER_MINE) >= 2 ||
-				CountMapSquareAround(tile, MP_INDUSTRY, IT_GOLD_MINE) >= 2 ||
-				CountMapSquareAround(tile, MP_INDUSTRY, IT_DIAMOND_MINE) >= 2) {
-			found = M(STR_SV_STNAME_MINES);
-			goto done;
-		}
-	}
-
-	/* check close enough to town to get central as name? */
-	if (DistanceMax(tile,t->xy) < 8) {
-		found = M(STR_SV_STNAME);
-		if (HASBIT(free_names, M(STR_SV_STNAME))) goto done;
-
-		found = M(STR_SV_STNAME_CENTRAL);
-		if (HASBIT(free_names, M(STR_SV_STNAME_CENTRAL))) goto done;
-	}
-
-	/* Check lakeside */
-	if (HASBIT(free_names, M(STR_SV_STNAME_LAKESIDE)) &&
-			DistanceFromEdge(tile) < 20 &&
-			CountMapSquareAround(tile, MP_WATER, 0) >= 5) {
-		found = M(STR_SV_STNAME_LAKESIDE);
-		goto done;
-	}
-
-	/* Check woods */
-	if (HASBIT(free_names, M(STR_SV_STNAME_WOODS)) && (
-				CountMapSquareAround(tile, MP_TREES, 0) >= 8 ||
-				CountMapSquareAround(tile, MP_INDUSTRY, IT_FOREST) >= 2)
-			) {
-		found = _opt.landscape == LT_DESERT ?
-			M(STR_SV_STNAME_FOREST) : M(STR_SV_STNAME_WOODS);
-		goto done;
-	}
-
-	/* check elevation compared to town */
-	z = GetTileZ(tile);
-	z2 = GetTileZ(t->xy);
-	if (z < z2) {
-		found = M(STR_SV_STNAME_VALLEY);
-		if (HASBIT(free_names, M(STR_SV_STNAME_VALLEY))) goto done;
-	} else if (z > z2) {
-		found = M(STR_SV_STNAME_HEIGHTS);
-		if (HASBIT(free_names, M(STR_SV_STNAME_HEIGHTS))) goto done;
-	}
-
-	/* check direction compared to town */
-	{
-		static const int8 _direction_and_table[] = {
-			~( (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_EAST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
-			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
-			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_EAST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
-			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_EAST)) ),
-		};
-
-		free_names &= _direction_and_table[
-			(TileX(tile) < TileX(t->xy)) +
-			(TileY(tile) < TileY(t->xy)) * 2];
-	}
-
-	tmp = free_names & ((1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<6)|(1<<7)|(1<<12)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30));
-	if (tmp == 0) {
-		_error_message = STR_3007_TOO_MANY_STATIONS_LOADING;
-		return false;
-	}
-	found = FindFirstBit(tmp);
-
-done:
-	st->string_id = found + STR_SV_STNAME;
-	return true;
-}
-#undef M
-
-static Station* GetClosestStationFromTile(TileIndex tile, uint threshold, PlayerID owner)
-{
-	Station* best_station = NULL;
-	Station* st;
-
-	FOR_ALL_STATIONS(st) {
-		if ((owner == PLAYER_SPECTATOR || st->owner == owner)) {
-			uint cur_dist = DistanceManhattan(tile, st->xy);
-
-			if (cur_dist < threshold) {
-				threshold = cur_dist;
-				best_station = st;
-			}
-		}
-	}
-
-	return best_station;
-}
-
-static void StationInitialize(Station *st, TileIndex tile)
-{
-	GoodsEntry *ge;
-
-	st->xy = tile;
-	st->airport_tile = st->dock_tile = st->train_tile = 0;
-	st->bus_stops = st->truck_stops = NULL;
-	st->had_vehicle_of_type = 0;
-	st->time_since_load = 255;
-	st->time_since_unload = 255;
-	st->delete_ctr = 0;
-	st->facilities = 0;
-
-	st->last_vehicle_type = VEH_Invalid;
-
-	for (ge = st->goods; ge != endof(st->goods); ge++) {
-		ge->waiting_acceptance = 0;
-		ge->days_since_pickup = 0;
-		ge->enroute_from = INVALID_STATION;
-		ge->rating = 175;
-		ge->last_speed = 0;
-		ge->last_age = 0xFF;
-		ge->feeder_profit = 0;
-	}
-
-	st->random_bits = Random();
-	st->waiting_triggers = 0;
-
-	StationRect_Init(st);
-}
-
-// Update the virtual coords needed to draw the station sign.
-// st = Station to update for.
-static void UpdateStationVirtCoord(Station *st)
-{
-	Point pt = RemapCoords2(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE);
-
-	pt.y -= 32;
-	if (st->facilities & FACIL_AIRPORT && st->airport_type == AT_OILRIG) pt.y -= 16;
-
-	SetDParam(0, st->index);
-	SetDParam(1, st->facilities);
-	UpdateViewportSignPos(&st->sign, pt.x, pt.y, STR_305C_0);
-}
-
-// Update the virtual coords needed to draw the station sign for all stations.
-void UpdateAllStationVirtCoord(void)
-{
-	Station* st;
-
-	FOR_ALL_STATIONS(st) {
-		UpdateStationVirtCoord(st);
-	}
-}
-
-// Update the station virt coords while making the modified parts dirty.
-static void UpdateStationVirtCoordDirty(Station *st)
-{
-	MarkStationDirty(st);
-	UpdateStationVirtCoord(st);
-	MarkStationDirty(st);
-}
-
-// Get a mask of the cargo types that the station accepts.
-static uint GetAcceptanceMask(const Station *st)
-{
-	uint mask = 0;
-	uint i;
-
-	for (i = 0; i != NUM_CARGO; i++) {
-		if (st->goods[i].waiting_acceptance & 0x8000) mask |= 1 << i;
-	}
-	return mask;
-}
-
-// Items contains the two cargo names that are to be accepted or rejected.
-// msg is the string id of the message to display.
-static void ShowRejectOrAcceptNews(const Station *st, uint32 items, StringID msg)
-{
-	if (items) {
-		SetDParam(2, GB(items, 16, 16));
-		SetDParam(1, GB(items,  0, 16));
-		SetDParam(0, st->index);
-		AddNewsItem(msg + (GB(items, 16, 16) ? 1 : 0), NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_TILE, NT_ACCEPTANCE, 0), st->xy, 0);
-	}
-}
-
-// Get a list of the cargo types being produced around the tile.
-void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile,
-	int w, int h, int rad)
-{
-	int x,y;
-	int x1,y1,x2,y2;
-	int xc,yc;
-
-	memset(produced, 0, sizeof(AcceptedCargo));
-
-	x = TileX(tile);
-	y = TileY(tile);
-
-	// expand the region by rad tiles on each side
-	// while making sure that we remain inside the board.
-	x2 = min(x + w + rad, MapSizeX());
-	x1 = max(x - rad, 0);
-
-	y2 = min(y + h + rad, MapSizeY());
-	y1 = max(y - rad, 0);
-
-	assert(x1 < x2);
-	assert(y1 < y2);
-	assert(w > 0);
-	assert(h > 0);
-
-	for (yc = y1; yc != y2; yc++) {
-		for (xc = x1; xc != x2; xc++) {
-			if (!(IS_INSIDE_1D(xc, x, w) && IS_INSIDE_1D(yc, y, h))) {
-				GetProducedCargoProc *gpc;
-				TileIndex tile = TileXY(xc, yc);
-
-				gpc = _tile_type_procs[GetTileType(tile)]->get_produced_cargo_proc;
-				if (gpc != NULL) {
-					CargoID cargos[2] = { CT_INVALID, CT_INVALID };
-
-					gpc(tile, cargos);
-					if (cargos[0] != CT_INVALID) {
-						produced[cargos[0]]++;
-						if (cargos[1] != CT_INVALID) {
-							produced[cargos[1]]++;
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
-// Get a list of the cargo types that are accepted around the tile.
-void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile,
-	int w, int h, int rad)
-{
-	int x,y;
-	int x1,y1,x2,y2;
-	int xc,yc;
-
-	memset(accepts, 0, sizeof(AcceptedCargo));
-
-	x = TileX(tile);
-	y = TileY(tile);
-
-	// expand the region by rad tiles on each side
-	// while making sure that we remain inside the board.
-	x2 = min(x + w + rad, MapSizeX());
-	y2 = min(y + h + rad, MapSizeY());
-	x1 = max(x - rad, 0);
-	y1 = max(y - rad, 0);
-
-	assert(x1 < x2);
-	assert(y1 < y2);
-	assert(w > 0);
-	assert(h > 0);
-
-	for (yc = y1; yc != y2; yc++) {
-		for (xc = x1; xc != x2; xc++) {
-			TileIndex tile = TileXY(xc, yc);
-
-			if (!IsTileType(tile, MP_STATION)) {
-				AcceptedCargo ac;
-				uint i;
-
-				GetAcceptedCargo(tile, ac);
-				for (i = 0; i < lengthof(ac); ++i) accepts[i] += ac[i];
-			}
-		}
-	}
-}
-
-typedef struct ottd_Rectangle {
-	uint min_x;
-	uint min_y;
-	uint max_x;
-	uint max_y;
-} ottd_Rectangle;
-
-static inline void MergePoint(ottd_Rectangle* rect, TileIndex tile)
-{
-	uint x = TileX(tile);
-	uint y = TileY(tile);
-
-	if (rect->min_x > x) rect->min_x = x;
-	if (rect->min_y > y) rect->min_y = y;
-	if (rect->max_x < x) rect->max_x = x;
-	if (rect->max_y < y) rect->max_y = y;
-}
-
-// Update the acceptance for a station.
-// show_msg controls whether to display a message that acceptance was changed.
-static void UpdateStationAcceptance(Station *st, bool show_msg)
-{
-	uint old_acc, new_acc;
-	const RoadStop *cur_rs;
-	int i;
-	ottd_Rectangle rect;
-	int rad;
-	AcceptedCargo accepts;
-
-	rect.min_x = MapSizeX();
-	rect.min_y = MapSizeY();
-	rect.max_x = rect.max_y = 0;
-	// Don't update acceptance for a buoy
-	if (IsBuoy(st)) return;
-
-	/* old accepted goods types */
-	old_acc = GetAcceptanceMask(st);
-
-	// Put all the tiles that span an area in the table.
-	if (st->train_tile != 0) {
-		MergePoint(&rect, st->train_tile);
-		MergePoint(&rect,
-			st->train_tile + TileDiffXY(st->trainst_w - 1, st->trainst_h - 1)
-		);
-	}
-
-	if (st->airport_tile != 0) {
-		const AirportFTAClass* afc = GetAirport(st->airport_type);
-
-		MergePoint(&rect, st->airport_tile);
-		MergePoint(&rect,
-			st->airport_tile + TileDiffXY(afc->size_x - 1, afc->size_y - 1)
-		);
-	}
-
-	if (st->dock_tile != 0) MergePoint(&rect, st->dock_tile);
-
-	for (cur_rs = st->bus_stops; cur_rs != NULL; cur_rs = cur_rs->next) {
-		MergePoint(&rect, cur_rs->xy);
-	}
-
-	for (cur_rs = st->truck_stops; cur_rs != NULL; cur_rs = cur_rs->next) {
-		MergePoint(&rect, cur_rs->xy);
-	}
-
-	rad = (_patches.modified_catchment) ? FindCatchmentRadius(st) : 4;
-
-	// And retrieve the acceptance.
-	if (rect.max_x >= rect.min_x) {
-		GetAcceptanceAroundTiles(
-			accepts,
-			TileXY(rect.min_x, rect.min_y),
-			rect.max_x - rect.min_x + 1,
-			rect.max_y - rect.min_y + 1,
-			rad
-		);
-	} else {
-		memset(accepts, 0, sizeof(accepts));
-	}
-
-	// Adjust in case our station only accepts fewer kinds of goods
-	for (i = 0; i != NUM_CARGO; i++) {
-		uint amt = min(accepts[i], 15);
-
-		// Make sure the station can accept the goods type.
-		if ((i != CT_PASSENGERS && !(st->facilities & (byte)~FACIL_BUS_STOP)) ||
-				(i == CT_PASSENGERS && !(st->facilities & (byte)~FACIL_TRUCK_STOP)))
-			amt = 0;
-
-		SB(st->goods[i].waiting_acceptance, 12, 4, amt);
-	}
-
-	// Only show a message in case the acceptance was actually changed.
-	new_acc = GetAcceptanceMask(st);
-	if (old_acc == new_acc)
-		return;
-
-	// show a message to report that the acceptance was changed?
-	if (show_msg && st->owner == _local_player && st->facilities) {
-		uint32 accept=0, reject=0; /* these contain two string ids each */
-		const StringID *str = _cargoc.names_s;
-
-		do {
-			if (new_acc & 1) {
-				if (!(old_acc & 1)) accept = (accept << 16) | *str;
-			} else {
-				if (old_acc & 1) reject = (reject << 16) | *str;
-			}
-		} while (str++,(new_acc>>=1) != (old_acc>>=1));
-
-		ShowRejectOrAcceptNews(st, accept, STR_3040_NOW_ACCEPTS);
-		ShowRejectOrAcceptNews(st, reject, STR_303E_NO_LONGER_ACCEPTS);
-	}
-
-	// redraw the station view since acceptance changed
-	InvalidateWindowWidget(WC_STATION_VIEW, st->index, 4);
-}
-
-static void UpdateStationSignCoord(Station *st)
-{
-	Rect *r = &st->rect;
-
-	if (StationRect_IsEmpty(st)) return; // no tiles belong to this station
-
-	// clamp sign coord to be inside the station rect
-	st->xy = TileXY(clampu(TileX(st->xy), r->left, r->right), clampu(TileY(st->xy), r->top, r->bottom));
-	UpdateStationVirtCoordDirty(st);
-}
-
-// This is called right after a station was deleted.
-// It checks if the whole station is free of substations, and if so, the station will be
-// deleted after a little while.
-static void DeleteStationIfEmpty(Station* st)
-{
-	if (st->facilities == 0) {
-		st->delete_ctr = 0;
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-	/* station remains but it probably lost some parts - station sign should stay in the station boundaries */
-	UpdateStationSignCoord(st);
-}
-
-static int32 ClearTile_Station(TileIndex tile, byte flags);
-
-// Tries to clear the given area. Returns the cost in case of success.
-// Or an error code if it failed.
-int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station)
-{
-	int32 cost = 0, ret;
-
-	Slope tileh;
-	uint z;
-	int allowed_z = -1;
-	int flat_z;
-
-	BEGIN_TILE_LOOP(tile_cur, w, h, tile)
-		if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) {
-			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-		}
-
-		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
-
-		tileh = GetTileSlope(tile_cur, &z);
-
-		/* Prohibit building if
-		 *   1) The tile is "steep" (i.e. stretches two height levels)
-		 * -OR-
-		 *   2) The tile is non-flat if
-		 *     a) the player building is an "old-school" AI
-		 *   -OR-
-		 *     b) the build_on_slopes switch is disabled
-		 */
-		if (IsSteepSlope(tileh) ||
-				((_is_old_ai_player || !_patches.build_on_slopes) && tileh != SLOPE_FLAT)) {
-			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-		}
-
-		flat_z = z;
-		if (tileh != SLOPE_FLAT) {
-			// need to check so the entrance to the station is not pointing at a slope.
-			if ((invalid_dirs&1 && !(tileh & SLOPE_NE) && (uint)w_cur == w) ||
-					(invalid_dirs&2 && !(tileh & SLOPE_SE) && h_cur == 1) ||
-					(invalid_dirs&4 && !(tileh & SLOPE_SW) && w_cur == 1) ||
-					(invalid_dirs&8 && !(tileh & SLOPE_NW) && (uint)h_cur == h)) {
-				return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-			}
-			cost += _price.terraform;
-			flat_z += TILE_HEIGHT;
-		}
-
-		// get corresponding flat level and make sure that all parts of the station have the same level.
-		if (allowed_z == -1) {
-			// first tile
-			allowed_z = flat_z;
-		} else if (allowed_z != flat_z) {
-			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-		}
-
-		// if station is set, then we have special handling to allow building on top of already existing stations.
-		// so station points to INVALID_STATION if we can build on any station. or it points to a station if we're only allowed to build
-		// on exactly that station.
-		if (station != NULL && IsTileType(tile_cur, MP_STATION)) {
-			if (!IsRailwayStation(tile_cur)) {
-				return ClearTile_Station(tile_cur, DC_AUTO); // get error message
-			} else {
-				StationID st = GetStationIndex(tile_cur);
-				if (*station == INVALID_STATION) {
-					*station = st;
-				} else if (*station != st) {
-					return_cmd_error(STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING);
-				}
-			}
-		} else {
-			ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-		}
-	END_TILE_LOOP(tile_cur, w, h, tile)
-
-	return cost;
-}
-
-static bool CanExpandRailroadStation(Station* st, uint* fin, Axis axis)
-{
-	uint curw = st->trainst_w, curh = st->trainst_h;
-	TileIndex tile = fin[0];
-	uint w = fin[1];
-	uint h = fin[2];
-
-	if (_patches.nonuniform_stations) {
-		// determine new size of train station region..
-		int x = min(TileX(st->train_tile), TileX(tile));
-		int y = min(TileY(st->train_tile), TileY(tile));
-		curw = max(TileX(st->train_tile) + curw, TileX(tile) + w) - x;
-		curh = max(TileY(st->train_tile) + curh, TileY(tile) + h) - y;
-		tile = TileXY(x, y);
-	} else {
-		// check so the orientation is the same
-		if (GetRailStationAxis(st->train_tile) != axis) {
-			_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED;
-			return false;
-		}
-
-		// check if the new station adjoins the old station in either direction
-		if (curw == w && st->train_tile == tile + TileDiffXY(0, h)) {
-			// above
-			curh += h;
-		} else if (curw == w && st->train_tile == tile - TileDiffXY(0, curh)) {
-			// below
-			tile -= TileDiffXY(0, curh);
-			curh += h;
-		} else if (curh == h && st->train_tile == tile + TileDiffXY(w, 0)) {
-			// to the left
-			curw += w;
-		} else if (curh == h && st->train_tile == tile - TileDiffXY(curw, 0)) {
-			// to the right
-			tile -= TileDiffXY(curw, 0);
-			curw += w;
-		} else {
-			_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED;
-			return false;
-		}
-	}
-	// make sure the final size is not too big.
-	if (curw > _patches.station_spread || curh > _patches.station_spread) {
-		_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
-		return false;
-	}
-
-	// now tile contains the new value for st->train_tile
-	// curw, curh contain the new value for width and height
-	fin[0] = tile;
-	fin[1] = curw;
-	fin[2] = curh;
-	return true;
-}
-
-static inline byte *CreateSingle(byte *layout, int n)
-{
-	int i = n;
-	do *layout++ = 0; while (--i);
-	layout[((n-1) >> 1)-n] = 2;
-	return layout;
-}
-
-static inline byte *CreateMulti(byte *layout, int n, byte b)
-{
-	int i = n;
-	do *layout++ = b; while (--i);
-	if (n > 4) {
-		layout[0-n] = 0;
-		layout[n-1-n] = 0;
-	}
-	return layout;
-}
-
-static void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
-{
-	if (statspec != NULL && statspec->lengths >= plat_len &&
-			statspec->platforms[plat_len - 1] >= numtracks &&
-			statspec->layouts[plat_len - 1][numtracks - 1]) {
-		/* Custom layout defined, follow it. */
-		memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
-			plat_len * numtracks);
-		return;
-	}
-
-	if (plat_len == 1) {
-		CreateSingle(layout, numtracks);
-	} else {
-		if (numtracks & 1) layout = CreateSingle(layout, plat_len);
-		numtracks >>= 1;
-
-		while (--numtracks >= 0) {
-			layout = CreateMulti(layout, plat_len, 4);
-			layout = CreateMulti(layout, plat_len, 6);
-		}
-	}
-}
-
-/** Build railroad station
- * @param tile_org starting position of station dragging/placement
- * @param p1 various bitstuffed elements
- * - p1 = (bit  0)    - orientation (p1 & 1)
- * - p1 = (bit  8-15) - number of tracks
- * - p1 = (bit 16-23) - platform length
- * @param p2 various bitstuffed elements
- * - p2 = (bit  0- 3) - railtype (p2 & 0xF)
- * - p2 = (bit  8-15) - custom station class
- * - p2 = (bit 16-23) - custom station id
- */
-int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint32 p2)
-{
-	Station *st;
-	int w_org, h_org;
-	int32 cost, ret;
-	StationID est;
-	int plat_len, numtracks;
-	Axis axis;
-	uint finalvalues[3];
-	const StationSpec *statspec;
-	int specindex;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* Does the authority allow this? */
-	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile_org)) return CMD_ERROR;
-	if (!ValParamRailtype(p2 & 0xF)) return CMD_ERROR;
-
-	/* unpack parameters */
-	axis = p1 & 1;
-	numtracks = GB(p1,  8, 8);
-	plat_len  = GB(p1, 16, 8);
-	/* w = length, h = num_tracks */
-	if (axis == AXIS_X) {
-		w_org = plat_len;
-		h_org = numtracks;
-	} else {
-		h_org = plat_len;
-		w_org = numtracks;
-	}
-
-	if (h_org > _patches.station_spread || w_org > _patches.station_spread) return CMD_ERROR;
-
-	// these values are those that will be stored in train_tile and station_platforms
-	finalvalues[0] = tile_org;
-	finalvalues[1] = w_org;
-	finalvalues[2] = h_org;
-
-	// Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station)
-	est = INVALID_STATION;
-	// If DC_EXEC is in flag, do not want to pass it to CheckFlatLandBelow, because of a nice bug
-	//  for detail info, see: https://sourceforge.net/tracker/index.php?func=detail&aid=1029064&group_id=103924&atid=636365
-	ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags & ~DC_EXEC, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
-	if (CmdFailed(ret)) return ret;
-	cost = ret + (numtracks * _price.train_station_track + _price.train_station_length) * plat_len;
-
-	// Make sure there are no similar stations around us.
-	st = GetStationAround(tile_org, w_org, h_org, est);
-	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
-
-	// See if there is a deleted station close to us.
-	if (st == NULL) {
-		st = GetClosestStationFromTile(tile_org, 8, _current_player);
-		if (st != NULL && st->facilities) st = NULL;
-	}
-
-	if (st != NULL) {
-		// Reuse an existing station.
-		if (st->owner != OWNER_NONE && st->owner != _current_player)
-			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
-
-		if (st->train_tile != 0) {
-			// check if we want to expanding an already existing station?
-			if (_is_old_ai_player || !_patches.join_stations)
-				return_cmd_error(STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD);
-			if (!CanExpandRailroadStation(st, finalvalues, axis))
-				return CMD_ERROR;
-		}
-
-		//XXX can't we pack this in the "else" part of the if above?
-		if (!StationRect_BeforeAddRect(st, tile_org, w_org, h_org, RECT_MODE_TEST)) return CMD_ERROR;
-	} else {
-		// Create a new station
-		st = AllocateStation();
-		if (st == NULL) return CMD_ERROR;
-
-		st->town = ClosestTownFromTile(tile_org, (uint)-1);
-		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
-			SETBIT(st->town->have_ratings, _current_player);
-
-		if (!GenerateStationName(st, tile_org, 0)) return CMD_ERROR;
-
-		if (flags & DC_EXEC) StationInitialize(st, tile_org);
-	}
-
-	/* Check if the given station class is valid */
-	if (GB(p2, 8, 8) >= STAT_CLASS_MAX) return CMD_ERROR;
-
-	/* Check if we can allocate a custom stationspec to this station */
-	statspec = GetCustomStationSpec(GB(p2, 8, 8), GB(p2, 16, 8));
-	specindex = AllocateSpecToStation(statspec, st, flags & DC_EXEC);
-	if (specindex == -1) return CMD_ERROR;
-
-	if (statspec != NULL) {
-		/* Perform NewStation checks */
-
-		/* Check if the station size is permitted */
-		if (HASBIT(statspec->disallowed_platforms, numtracks - 1) || HASBIT(statspec->disallowed_lengths, plat_len - 1)) {
-			return CMD_ERROR;
-		}
-
-		/* Check if the station is buildable */
-		if (HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
-			return CMD_ERROR;
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		TileIndexDiff tile_delta;
-		byte *layout_ptr;
-		byte numtracks_orig;
-		Track track;
-
-		// Now really clear the land below the station
-		// It should never return CMD_ERROR.. but you never know ;)
-		//  (a bit strange function name for it, but it really does clear the land, when DC_EXEC is in flags)
-		ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
-		if (CmdFailed(ret)) return ret;
-
-		st->train_tile = finalvalues[0];
-		if (!st->facilities) st->xy = finalvalues[0];
-		st->facilities |= FACIL_TRAIN;
-		st->owner = _current_player;
-
-		st->trainst_w = finalvalues[1];
-		st->trainst_h = finalvalues[2];
-
-		st->build_date = _date;
-
-		StationRect_BeforeAddRect(st, tile_org, w_org, h_org, RECT_MODE_TRY);
-
-		tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
-		track = AxisToTrack(axis);
-
-		layout_ptr = alloca(numtracks * plat_len);
-		GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
-
-		numtracks_orig = numtracks;
-
-		do {
-			TileIndex tile = tile_org;
-			int w = plat_len;
-			do {
-				byte layout = *layout_ptr++;
-				MakeRailStation(tile, st->owner, st->index, axis, layout, GB(p2, 0, 4));
-				SetCustomStationSpecIndex(tile, specindex);
-				SetStationTileRandomBits(tile, GB(Random(), 0, 4));
-
-				if (statspec != NULL) {
-					/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
-					uint32 platinfo = GetPlatformInfo(AXIS_X, 0, plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
-					uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, st, tile);
-					if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, callback + axis);
-				}
-
-				tile += tile_delta;
-			} while (--w);
-			SetSignalsOnBothDir(tile_org, track);
-			YapfNotifyTrackLayoutChange(tile_org, track);
-			tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
-		} while (--numtracks);
-
-		MarkStationTilesDirty(st);
-		UpdateStationVirtCoordDirty(st);
-		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-
-	return cost;
-}
-
-static void MakeRailwayStationAreaSmaller(Station *st)
-{
-	uint w = st->trainst_w;
-	uint h = st->trainst_h;
-	TileIndex tile = st->train_tile;
-	uint i;
-
-restart:
-
-	// too small?
-	if (w != 0 && h != 0) {
-		// check the left side, x = constant, y changes
-		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(0, i));) {
-			// the left side is unused?
-			if (++i == h) {
-				tile += TileDiffXY(1, 0);
-				w--;
-				goto restart;
-			}
-		}
-
-		// check the right side, x = constant, y changes
-		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(w - 1, i));) {
-			// the right side is unused?
-			if (++i == h) {
-				w--;
-				goto restart;
-			}
-		}
-
-		// check the upper side, y = constant, x changes
-		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(i, 0));) {
-			// the left side is unused?
-			if (++i == w) {
-				tile += TileDiffXY(0, 1);
-				h--;
-				goto restart;
-			}
-		}
-
-		// check the lower side, y = constant, x changes
-		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(i, h - 1));) {
-			// the left side is unused?
-			if (++i == w) {
-				h--;
-				goto restart;
-			}
-		}
-	} else {
-		tile = 0;
-	}
-
-	st->trainst_w = w;
-	st->trainst_h = h;
-	st->train_tile = tile;
-}
-
-/** Remove a single tile from a railroad station.
- * This allows for custom-built station with holes and weird layouts
- * @param tile tile of station piece to remove
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdRemoveFromRailroadStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Station *st;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	// make sure the specified tile belongs to the current player, and that it is a railroad station.
-	if (!IsTileType(tile, MP_STATION) || !IsRailwayStation(tile) || !_patches.nonuniform_stations) return CMD_ERROR;
-	st = GetStationByTile(tile);
-	if (_current_player != OWNER_WATER && (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile))) return CMD_ERROR;
-
-	// if we reached here, it means we can actually delete it. do that.
-	if (flags & DC_EXEC) {
-		uint specindex = GetCustomStationSpecIndex(tile);
-		Track track = GetRailStationTrack(tile);
-		DoClearSquare(tile);
-		StationRect_AfterRemoveTile(st, tile);
-		SetSignalsOnBothDir(tile, track);
-		YapfNotifyTrackLayoutChange(tile, track);
-
-		DeallocateSpecFromStation(st, specindex);
-
-		// now we need to make the "spanned" area of the railway station smaller if we deleted something at the edges.
-		// we also need to adjust train_tile.
-		MakeRailwayStationAreaSmaller(st);
-		MarkStationTilesDirty(st);
-		UpdateStationSignCoord(st);
-
-		// if we deleted the whole station, delete the train facility.
-		if (st->train_tile == 0) {
-			st->facilities &= ~FACIL_TRAIN;
-			UpdateStationVirtCoordDirty(st);
-			DeleteStationIfEmpty(st);
-		}
-	}
-	return _price.remove_rail_station;
-}
-
-// determine the number of platforms for the station
-uint GetStationPlatforms(const Station *st, TileIndex tile)
-{
-	TileIndex t;
-	TileIndexDiff delta;
-	Axis axis;
-	uint len;
-	assert(TileBelongsToRailStation(st, tile));
-
-	len = 0;
-	axis = GetRailStationAxis(tile);
-	delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
-
-	// find starting tile..
-	t = tile;
-	do {
-		t -= delta;
-		len++;
-	} while (TileBelongsToRailStation(st, t) && GetRailStationAxis(t) == axis);
-
-	// find ending tile
-	t = tile;
-	do {
-		t += delta;
-		len++;
-	} while (TileBelongsToRailStation(st, t) && GetRailStationAxis(t) == axis);
-
-	return len - 1;
-}
-
-/** Determines the REMAINING length of a platform, starting at (and including)
- * the given tile.
- * @param tile the tile from which to start searching. Must be a railway station tile
- * @param dir The direction in which to search.
- * @return The platform length
- */
-uint GetPlatformLength(TileIndex tile, DiagDirection dir)
-{
-	TileIndex start_tile = tile;
-	uint length = 0;
-	assert(IsRailwayStationTile(tile));
-	assert(dir < DIAGDIR_END);
-
-	do {
-		length ++;
-		tile += TileOffsByDiagDir(dir);
-	} while (IsCompatibleTrainStationTile(tile, start_tile));
-
-	return length;
-}
-
-
-static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
-{
-	int w,h;
-	int32 cost = 0;
-
-	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
-	if (_current_player == OWNER_WATER && _patches.nonuniform_stations)
-		return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAILROAD_STATION);
-
-	/* Current player owns the station? */
-	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
-		return CMD_ERROR;
-
-	/* determine width and height of platforms */
-	tile = st->train_tile;
-	w = st->trainst_w;
-	h = st->trainst_h;
-
-	assert(w != 0 && h != 0);
-
-	/* clear all areas of the station */
-	do {
-		int w_bak = w;
-		do {
-			// for nonuniform stations, only remove tiles that are actually train station tiles
-			if (TileBelongsToRailStation(st, tile)) {
-				if (!EnsureNoVehicle(tile))
-					return CMD_ERROR;
-				cost += _price.remove_rail_station;
-				if (flags & DC_EXEC) {
-					Track track = GetRailStationTrack(tile);
-					DoClearSquare(tile);
-					SetSignalsOnBothDir(tile, track);
-					YapfNotifyTrackLayoutChange(tile, track);
-				}
-			}
-			tile += TileDiffXY(1, 0);
-		} while (--w);
-		w = w_bak;
-		tile += TileDiffXY(-w, 1);
-	} while (--h);
-
-	if (flags & DC_EXEC) {
-		StationRect_AfterRemoveRect(st, st->train_tile, st->trainst_w, st->trainst_h);
-
-		st->train_tile = 0;
-		st->trainst_w = st->trainst_h = 0;
-		st->facilities &= ~FACIL_TRAIN;
-
-		free(st->speclist);
-		st->num_specs = 0;
-		st->speclist  = NULL;
-
-		UpdateStationVirtCoordDirty(st);
-		DeleteStationIfEmpty(st);
-	}
-
-	return cost;
-}
-
-int32 DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
-{
-	const Station* st = GetStationByTile(tile);
-
-	if (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	// tile is not a railroad station?
-	if (!IsRailwayStation(tile)) return CMD_ERROR;
-
-	if (GetRailType(tile) == totype) return CMD_ERROR;
-
-	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
-	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
-
-	if (exec) {
-		SetRailType(tile, totype);
-		MarkTileDirtyByTile(tile);
-		YapfNotifyTrackLayoutChange(tile, GetRailStationTrack(tile));
-	}
-
-	return _price.build_rail >> 1;
-}
-
-/** Heavy wizardry used to add a roadstop to a station.
- * To understand the function, lets first look at what is passed around,
- * especially the last two parameters. CmdBuildRoadStop allocates a road
- * stop and needs to put that stop into the linked list of road stops.
- * It (CmdBuildRoadStop) has a **currstop pointer which points to element
- * in the linked list of stops (each element in this list being a pointer
- * in itself, hence the double pointer). We (FindRoadStopSpot) need to
- * modify this pointer (**currstop) thus we need to pass by reference,
- * obtaining a triple pointer (***currstop). When finished, **currstop
- * in CmdBuildRoadStop will contain the address of the pointer which will
- * then point into the global roadstop array. *prev (in CmdBuildRoadStop)
- * is the pointer tino the global roadstop array which has *currstop in
- * its ->next element.
- * @param[in] truck_station Determines whether a stop is RS_BUS or RS_TRUCK
- * @param[in] station The station to do the whole procedure for
- * @param[out] currstop See the detailed function description
- * @param prev See the detailed function description
- */
-static void FindRoadStopSpot(bool truck_station, Station* st, RoadStop*** currstop, RoadStop** prev)
-{
-	RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
-	assert(*prev == NULL);
-
-	if (*primary_stop == NULL) {
-		//we have no roadstop of the type yet, so write a "primary stop"
-		*currstop = primary_stop;
-	} else {
-		//there are stops already, so append to the end of the list
-		*prev = *primary_stop;
-		*currstop = &(*primary_stop)->next;
-		while (**currstop != NULL) {
-			*prev = (*prev)->next;
-			*currstop = &(**currstop)->next;
-		}
-	}
-}
-
-/** Build a bus or truck stop
- * @param tile tile to build the stop at
- * @param p1 entrance direction (DiagDirection)
- * @param p2 0 for Bus stops, 1 for truck stops
- */
-int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Station *st;
-	RoadStop *road_stop;
-	RoadStop **currstop;
-	RoadStop *prev = NULL;
-	int32 cost;
-	int32 ret;
-	bool type = !!p2;
-
-	/* Saveguard the parameters */
-	if (!IsValidDiagDirection(p1)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
-		return CMD_ERROR;
-
-	ret = CheckFlatLandBelow(tile, 1, 1, flags, 1 << p1, NULL);
-	if (CmdFailed(ret)) return ret;
-	cost = ret;
-
-	st = GetStationAround(tile, 1, 1, -1);
-	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
-
-	/* Find a station close to us */
-	if (st == NULL) {
-		st = GetClosestStationFromTile(tile, 8, _current_player);
-		if (st != NULL && st->facilities != 0) st = NULL;
-	}
-
-	//give us a road stop in the list, and check if something went wrong
-	road_stop = AllocateRoadStop();
-	if (road_stop == NULL) {
-		return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
-	}
-
-	if (st != NULL &&
-			GetNumRoadStopsInStation(st, RS_BUS) + GetNumRoadStopsInStation(st, RS_TRUCK) >= ROAD_STOP_LIMIT) {
-		return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
-	}
-
-	if (st != NULL) {
-		if (st->owner != OWNER_NONE && st->owner != _current_player) {
-			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
-		}
-
-		if (!StationRect_BeforeAddTile(st, tile, RECT_MODE_TEST)) return CMD_ERROR;
-
-		FindRoadStopSpot(type, st, &currstop, &prev);
-	} else {
-		Town *t;
-
-		st = AllocateStation();
-		if (st == NULL) return CMD_ERROR;
-
-		st->town = t = ClosestTownFromTile(tile, (uint)-1);
-
-		FindRoadStopSpot(type, st, &currstop, &prev);
-
-		if (IsValidPlayer(_current_player) && (flags & DC_EXEC)) {
-			SETBIT(t->have_ratings, _current_player);
-		}
-
-		st->sign.width_1 = 0;
-
-		if (!GenerateStationName(st, tile, 0)) return CMD_ERROR;
-
-		if (flags & DC_EXEC) StationInitialize(st, tile);
-	}
-
-	cost += (type) ? _price.build_truck_station : _price.build_bus_station;
-
-	if (flags & DC_EXEC) {
-		//point to the correct item in the _busstops or _truckstops array
-		*currstop = road_stop;
-
-		//initialize an empty station
-		InitializeRoadStop(road_stop, prev, tile, st->index);
-		if (!st->facilities) st->xy = tile;
-		st->facilities |= (type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP;
-		st->owner = _current_player;
-
-		st->build_date = _date;
-
-		StationRect_BeforeAddTile(st, tile, RECT_MODE_TRY);
-
-		MakeRoadStop(tile, st->owner, st->index, type, p1);
-
-		UpdateStationVirtCoordDirty(st);
-		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-	return cost;
-}
-
-// Remove a bus station
-static int32 RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
-{
-	RoadStop **primary_stop;
-	RoadStop *cur_stop;
-	bool is_truck = IsTruckStop(tile);
-
-	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner)) {
-		return CMD_ERROR;
-	}
-
-	if (is_truck) { // truck stop
-		primary_stop = &st->truck_stops;
-		cur_stop = GetRoadStopByTile(tile, RS_TRUCK);
-	} else {
-		primary_stop = &st->bus_stops;
-		cur_stop = GetRoadStopByTile(tile, RS_BUS);
-	}
-
-	assert(cur_stop != NULL);
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		//we only had one stop left
-		if (cur_stop->next == NULL && cur_stop->prev == NULL) {
-			//so we remove ALL stops
-			*primary_stop = NULL;
-			st->facilities &= (is_truck) ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP;
-		} else if (cur_stop == *primary_stop) {
-			//removed the first stop in the list
-			//need to set the primary element to the next stop
-			*primary_stop = (*primary_stop)->next;
-		}
-
-		DeleteRoadStop(cur_stop);
-		DoClearSquare(tile);
-		StationRect_AfterRemoveTile(st, tile);
-
-		UpdateStationVirtCoordDirty(st);
-		DeleteStationIfEmpty(st);
-	}
-
-	return (is_truck) ? _price.remove_truck_station : _price.remove_bus_station;
-}
-
-
-
-// FIXME -- need to move to its corresponding Airport variable
-// Country Airfield (small)
-static const byte _airport_sections_country[] = {
-	54, 53, 52, 65,
-	58, 57, 56, 55,
-	64, 63, 63, 62
-};
-
-// City Airport (large)
-static const byte _airport_sections_town[] = {
-	31,  9, 33,  9,  9, 32,
-	27, 36, 29, 34,  8, 10,
-	30, 11, 35, 13, 20, 21,
-	51, 12, 14, 17, 19, 28,
-	38, 13, 15, 16, 18, 39,
-	26, 22, 23, 24, 25, 26
-};
-
-// Metropolitain Airport (large) - 2 runways
-static const byte _airport_sections_metropolitan[] = {
-	 31,  9, 33,  9,  9, 32,
-	 27, 36, 29, 34,  8, 10,
-	 30, 11, 35, 13, 20, 21,
-	102,  8,  8,  8,  8, 28,
-	 83, 84, 84, 84, 84, 83,
-	 26, 23, 23, 23, 23, 26
-};
-
-// International Airport (large) - 2 runways
-static const byte _airport_sections_international[] = {
-	88, 89, 89, 89, 89, 89,  88,
-	51,  8,  8,  8,  8,  8,  32,
-	30,  8, 11, 27, 11,  8,  10,
-	32,  8, 11, 27, 11,  8, 114,
-	87,  8, 11, 85, 11,  8, 114,
-	87,  8,  8,  8,  8,  8,  90,
-	26, 23, 23, 23, 23, 23,  26
-};
-
-// Intercontinental Airport (vlarge) - 4 runways
-static const byte _airport_sections_intercontinental[] = {
-	102, 120,  89,  89,  89,  89,  89,  89, 118,
-	120,  22,  22,  22,  22,  22,  22, 119, 117,
-	 87,  54,  87,   8,   8,   8,   8,  51, 117,
-	 87, 162,  87,  85, 116, 116,   8,   9,  10,
-	 87,   8,   8,  11,  31,  11,   8, 160,  32,
-	 32, 160,   8,  11,  27,  11,   8,   8,  10,
-	 87,   8,   8,  11,  30,  11,   8,   8,  10,
-	 87, 142,   8,  11,  29,  11,  10, 163,  10,
-	 87, 164,  87,   8,   8,   8,  10,  37, 117,
-	 87, 120,  89,  89,  89,  89,  89,  89, 119,
-	121,  22,  22,  22,  22,  22,  22, 119,  37
-};
-
-
-// Commuter Airfield (small)
-static const byte _airport_sections_commuter[] = {
-	85, 30, 115, 115, 32,
-	87, 8,    8,   8, 10,
-	87, 11,  11,  11, 10,
-	26, 23,  23,  23, 26
-};
-
-// Heliport
-static const byte _airport_sections_heliport[] = {
-	66,
-};
-
-// Helidepot
-static const byte _airport_sections_helidepot[] = {
-	124, 32,
-	122, 123
-};
-
-// Helistation
-static const byte _airport_sections_helistation[] = {
-	 32, 134, 159, 158,
-	161, 142, 142, 157
-};
-
-static const byte * const _airport_sections[] = {
-	_airport_sections_country,           // Country Airfield (small)
-	_airport_sections_town,              // City Airport (large)
-	_airport_sections_heliport,          // Heliport
-	_airport_sections_metropolitan,      // Metropolitain Airport (large)
-	_airport_sections_international,     // International Airport (xlarge)
-	_airport_sections_commuter,          // Commuter Airport (small)
-	_airport_sections_helidepot,         // Helidepot
-	_airport_sections_intercontinental,  // Intercontinental Airport (xxlarge)
-	_airport_sections_helistation        // Helistation
-};
-
-/** Place an Airport.
- * @param tile tile where airport will be built
- * @param p1 airport type, @see airport.h
- * @param p2 unused
- */
-int32 CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Town *t;
-	Station *st;
-	int32 cost;
-	int32 ret;
-	int w, h;
-	bool airport_upgrade = true;
-	const AirportFTAClass* afc;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* Check if a valid, buildable airport was chosen for construction */
-	if (p1 > lengthof(_airport_sections) || !HASBIT(GetValidAirports(), p1)) return CMD_ERROR;
-
-	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
-		return CMD_ERROR;
-
-	t = ClosestTownFromTile(tile, (uint)-1);
-
-	/* Check if local auth refuses a new airport */
-	{
-		uint num = 0;
-		FOR_ALL_STATIONS(st) {
-			if (st->town == t && st->facilities&FACIL_AIRPORT && st->airport_type != AT_OILRIG)
-				num++;
-		}
-		if (num >= 2) {
-			SetDParam(0, t->index);
-			return_cmd_error(STR_2035_LOCAL_AUTHORITY_REFUSES);
-		}
-	}
-
-	afc = GetAirport(p1);
-	w = afc->size_x;
-	h = afc->size_y;
-
-	ret = CheckFlatLandBelow(tile, w, h, flags, 0, NULL);
-	if (CmdFailed(ret)) return ret;
-	cost = ret;
-
-	st = GetStationAround(tile, w, h, -1);
-	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
-
-	/* Find a station close to us */
-	if (st == NULL) {
-		st = GetClosestStationFromTile(tile, 8, _current_player);
-		if (st != NULL && st->facilities) st = NULL;
-	}
-
-	if (w > _patches.station_spread || h > _patches.station_spread) {
-		_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
-		return CMD_ERROR;
-	}
-
-	if (st != NULL) {
-		if (st->owner != OWNER_NONE && st->owner != _current_player)
-			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
-
-		if (!StationRect_BeforeAddRect(st, tile, w, h, RECT_MODE_TEST)) return CMD_ERROR;
-
-		if (st->airport_tile != 0)
-			return_cmd_error(STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT);
-	} else {
-		airport_upgrade = false;
-
-		st = AllocateStation();
-		if (st == NULL) return CMD_ERROR;
-
-		st->town = t;
-
-		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
-			SETBIT(t->have_ratings, _current_player);
-
-		st->sign.width_1 = 0;
-
-		// if airport type equals Heliport then generate
-		// type 5 name, which is heliport, otherwise airport names (1)
-		if (!GenerateStationName(st, tile, (p1 == AT_HELIPORT)||(p1 == AT_HELIDEPOT)||(p1 == AT_HELISTATION) ? 5 : 1))
-			return CMD_ERROR;
-
-		if (flags & DC_EXEC) StationInitialize(st, tile);
-	}
-
-	cost += _price.build_airport * w * h;
-
-	if (flags & DC_EXEC) {
-		st->owner = _current_player;
-		st->airport_tile = tile;
-		if (!st->facilities) st->xy = tile;
-		st->facilities |= FACIL_AIRPORT;
-		st->airport_type = (byte)p1;
-		st->airport_flags = 0;
-
-		st->build_date = _date;
-
-		StationRect_BeforeAddRect(st, tile, w, h, RECT_MODE_TRY);
-
-		/* if airport was demolished while planes were en-route to it, the
-		 * positions can no longer be the same (v->u.air.pos), since different
-		 * airports have different indexes. So update all planes en-route to this
-		 * airport. Only update if
-		 * 1. airport is upgraded
-		 * 2. airport is added to existing station (unfortunately unavoideable)
-		 */
-		if (airport_upgrade) UpdateAirplanesOnNewStation(st);
-
-		{
-			const byte *b = _airport_sections[p1];
-
-			BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
-				MakeAirport(tile_cur, st->owner, st->index, *b++);
-			} END_TILE_LOOP(tile_cur, w, h, tile)
-		}
-
-		UpdateStationVirtCoordDirty(st);
-		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-
-	return cost;
-}
-
-static int32 RemoveAirport(Station *st, uint32 flags)
-{
-	TileIndex tile;
-	int w,h;
-	int32 cost;
-	const AirportFTAClass* afc;
-
-	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
-		return CMD_ERROR;
-
-	tile = st->airport_tile;
-
-	afc = GetAirport(st->airport_type);
-	w = afc->size_x;
-	h = afc->size_y;
-
-	cost = w * h * _price.remove_airport;
-
-	BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
-		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
-
-		if (flags & DC_EXEC) {
-			DeleteAnimatedTile(tile_cur);
-			DoClearSquare(tile_cur);
-		}
-	} END_TILE_LOOP(tile_cur, w,h,tile)
-
-	if (flags & DC_EXEC) {
-		uint i;
-
-		for (i = 0; i < afc->nof_depots; ++i) {
-			DeleteWindowById(
-				WC_VEHICLE_DEPOT, tile + ToTileIndexDiff(afc->airport_depots[i])
-			);
-		}
-
-		StationRect_AfterRemoveRect(st, tile, w, h);
-
-		st->airport_tile = 0;
-		st->facilities &= ~FACIL_AIRPORT;
-
-		UpdateStationVirtCoordDirty(st);
-		DeleteStationIfEmpty(st);
-	}
-
-	return cost;
-}
-
-/** Build a buoy.
- * @param tile tile where to place the bouy
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdBuildBuoy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Station *st;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!IsClearWaterTile(tile) || tile == 0) return_cmd_error(STR_304B_SITE_UNSUITABLE);
-
-	st = AllocateStation();
-	if (st == NULL) return CMD_ERROR;
-
-	st->town = ClosestTownFromTile(tile, (uint)-1);
-	st->sign.width_1 = 0;
-
-	if (!GenerateStationName(st, tile, 4)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		StationInitialize(st, tile);
-		st->dock_tile = tile;
-		st->facilities |= FACIL_DOCK;
-		/* Buoys are marked in the Station struct by this flag. Yes, it is this
-		 * braindead.. */
-		st->had_vehicle_of_type |= HVOT_BUOY;
-		st->owner = OWNER_NONE;
-
-		st->build_date = _date;
-
-		MakeBuoy(tile, st->index);
-
-		UpdateStationVirtCoordDirty(st);
-		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-
-	return _price.build_dock;
-}
-
-/* Checks if any ship is servicing the buoy specified. Returns yes or no */
-static bool CheckShipsOnBuoy(Station *st)
-{
-	const Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Ship) {
-			const Order *order;
-			FOR_VEHICLE_ORDERS(v, order) {
-				if (order->type == OT_GOTO_STATION && order->dest == st->index) {
-					return true;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-static int32 RemoveBuoy(Station *st, uint32 flags)
-{
-	TileIndex tile;
-
-	/* XXX: strange stuff */
-	if (!IsValidPlayer(_current_player))  return_cmd_error(INVALID_STRING_ID);
-
-	tile = st->dock_tile;
-
-	if (CheckShipsOnBuoy(st))   return_cmd_error(STR_BUOY_IS_IN_USE);
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		st->dock_tile = 0;
-		/* Buoys are marked in the Station struct by this flag. Yes, it is this
-		 * braindead.. */
-		st->facilities &= ~FACIL_DOCK;
-		st->had_vehicle_of_type &= ~HVOT_BUOY;
-
-		MakeWater(tile);
-		MarkTileDirtyByTile(tile);
-
-		UpdateStationVirtCoordDirty(st);
-		DeleteStationIfEmpty(st);
-	}
-
-	return _price.remove_truck_station;
-}
-
-static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
-	{-1,  0},
-	{ 0,  0},
-	{ 0,  0},
-	{ 0, -1}
-};
-static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
-static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
-
-/** Build a dock/haven.
- * @param tile tile where dock will be built
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdBuildDock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TileIndex tile_cur;
-	DiagDirection direction;
-	int32 cost;
-	Station *st;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	switch (GetTileSlope(tile, NULL)) {
-		case SLOPE_SW: direction = DIAGDIR_NE; break;
-		case SLOPE_SE: direction = DIAGDIR_NW; break;
-		case SLOPE_NW: direction = DIAGDIR_SE; break;
-		case SLOPE_NE: direction = DIAGDIR_SW; break;
-		default: return_cmd_error(STR_304B_SITE_UNSUITABLE);
-	}
-
-	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(cost)) return CMD_ERROR;
-
-	tile_cur = tile + TileOffsByDiagDir(direction);
-
-	if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
-
-	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
-		return_cmd_error(STR_304B_SITE_UNSUITABLE);
-	}
-
-	cost = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(cost)) return CMD_ERROR;
-
-	tile_cur += TileOffsByDiagDir(direction);
-	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
-		return_cmd_error(STR_304B_SITE_UNSUITABLE);
-	}
-
-	/* middle */
-	st = GetStationAround(
-		tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
-		_dock_w_chk[direction], _dock_h_chk[direction], -1);
-	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
-
-	/* Find a station close to us */
-	if (st == NULL) {
-		st = GetClosestStationFromTile(tile, 8, _current_player);
-		if (st!=NULL && st->facilities) st = NULL;
-	}
-
-	if (st != NULL) {
-		if (st->owner != OWNER_NONE && st->owner != _current_player)
-			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
-
-		if (!StationRect_BeforeAddRect(st, tile, _dock_w_chk[direction], _dock_h_chk[direction], RECT_MODE_TEST)) return CMD_ERROR;
-
-		if (st->dock_tile != 0) return_cmd_error(STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK);
-	} else {
-		Town *t;
-
-		st = AllocateStation();
-		if (st == NULL) return CMD_ERROR;
-
-		st->town = t = ClosestTownFromTile(tile, (uint)-1);
-
-		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
-			SETBIT(t->have_ratings, _current_player);
-
-		st->sign.width_1 = 0;
-
-		if (!GenerateStationName(st, tile, 3)) return CMD_ERROR;
-
-		if (flags & DC_EXEC) StationInitialize(st, tile);
-	}
-
-	if (flags & DC_EXEC) {
-		st->dock_tile = tile;
-		if (!st->facilities) st->xy = tile;
-		st->facilities |= FACIL_DOCK;
-		st->owner = _current_player;
-
-		st->build_date = _date;
-
-		StationRect_BeforeAddRect(st, tile, _dock_w_chk[direction], _dock_h_chk[direction], RECT_MODE_TRY);
-
-		MakeDock(tile, st->owner, st->index, direction);
-
-		UpdateStationVirtCoordDirty(st);
-		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
-	}
-	return _price.build_dock;
-}
-
-static int32 RemoveDock(Station *st, uint32 flags)
-{
-	TileIndex tile1;
-	TileIndex tile2;
-
-	if (!CheckOwnership(st->owner)) return CMD_ERROR;
-
-	tile1 = st->dock_tile;
-	tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
-
-	if (!EnsureNoVehicle(tile1)) return CMD_ERROR;
-	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		DoClearSquare(tile1);
-		MakeWater(tile2);
-
-		StationRect_AfterRemoveTile(st, tile1);
-		StationRect_AfterRemoveTile(st, tile2);
-
-		MarkTileDirtyByTile(tile2);
-
-		st->dock_tile = 0;
-		st->facilities &= ~FACIL_DOCK;
-
-		UpdateStationVirtCoordDirty(st);
-		DeleteStationIfEmpty(st);
-	}
-
-	return _price.remove_dock;
-}
-
-#include "table/station_land.h"
-
-const DrawTileSprites *GetStationTileLayout(byte gfx)
-{
-	return &_station_display_datas[gfx];
-}
-
-static void DrawTile_Station(TileInfo *ti)
-{
-	uint32 image;
-	const DrawTileSeqStruct *dtss;
-	const DrawTileSprites *t = NULL;
-	RailType railtype = GetRailType(ti->tile);
-	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
-	uint32 relocation = 0;
-	const Station *st = NULL;
-	const StationSpec *statspec = NULL;
-	PlayerID owner = GetTileOwner(ti->tile);
-	uint32 palette;
-
-	if (IsValidPlayer(owner)) {
-		palette = PLAYER_SPRITE_COLOR(owner);
-	} else {
-		// Some stations are not owner by a player, namely oil rigs
-		palette = PALETTE_TO_GREY;
-	}
-
-	// don't show foundation for docks
-	if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile))
-		DrawFoundation(ti, ti->tileh);
-
-	if (IsCustomStationSpecIndex(ti->tile)) {
-		// look for customization
-		st = GetStationByTile(ti->tile);
-		statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
-
-		//debug("Cust-o-mized %p", statspec);
-
-		if (statspec != NULL) {
-			uint tile = GetStationGfx(ti->tile);
-
-			relocation = GetCustomStationRelocation(statspec, st, ti->tile);
-
-			if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
-				uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
-				if (callback != CALLBACK_FAILED) tile = (callback & ~1) + GetRailStationAxis(ti->tile);
-			}
-
-			/* Ensure the chosen tile layout is valid for this custom station */
-			if (statspec->renderdata != NULL) {
-				t = &statspec->renderdata[tile < statspec->tiles ? tile : GetRailStationAxis(ti->tile)];
-			}
-		}
-	}
-
-	if (t == NULL || t->seq == NULL) t = &_station_display_datas[GetStationGfx(ti->tile)];
-
-	image = t->ground_sprite;
-	if (HASBIT(image, 31)) {
-		CLRBIT(image, 31);
-		image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
-		image += rti->custom_ground_offset;
-	} else {
-		image += rti->total_offset;
-	}
-	if (image & PALETTE_MODIFIER_COLOR) image |= palette;
-
-	// station_land array has been increased from 82 elements to 114
-	// but this is something else. If AI builds station with 114 it looks all weird
-	DrawGroundSprite(image);
-
-	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti);
-
-	foreach_draw_tile_seq(dtss, t->seq) {
-		image = dtss->image;
-		if (HASBIT(image, 30)) {
-			CLRBIT(image, 30);
-			image += rti->total_offset;
-		} else {
-			image += relocation;
-		}
-
-		if (_display_opt & DO_TRANS_BUILDINGS) {
-			MAKE_TRANSPARENT(image);
-		} else if (image & PALETTE_MODIFIER_COLOR) {
-			image |= palette;
-		}
-
-		if ((byte)dtss->delta_z != 0x80) {
-			AddSortableSpriteToDraw(
-				image,
-				ti->x + dtss->delta_x, ti->y + dtss->delta_y,
-				dtss->size_x, dtss->size_y,
-				dtss->size_z, ti->z + dtss->delta_z
-			);
-		} else {
-			AddChildSpriteScreen(image, dtss->delta_x, dtss->delta_y);
-		}
-	}
-}
-
-void StationPickerDrawSprite(int x, int y, RailType railtype, int image)
-{
-	uint32 ormod, img;
-	const DrawTileSeqStruct *dtss;
-	const DrawTileSprites *t;
-	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
-
-	ormod = PLAYER_SPRITE_COLOR(_local_player);
-
-	t = &_station_display_datas[image];
-
-	img = t->ground_sprite;
-	if (img & PALETTE_MODIFIER_COLOR) img |= ormod;
-	DrawSprite(img + rti->total_offset, x, y);
-
-	foreach_draw_tile_seq(dtss, t->seq) {
-		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
-		DrawSprite((dtss->image | ormod) + rti->total_offset, x + pt.x, y + pt.y);
-	}
-}
-
-static uint GetSlopeZ_Station(TileIndex tile, uint x, uint y)
-{
-	return GetTileMaxZ(tile);
-}
-
-static Slope GetSlopeTileh_Station(TileIndex tile, Slope tileh)
-{
-	return SLOPE_FLAT;
-}
-
-static void GetAcceptedCargo_Station(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
-{
-	StringID str;
-
-	td->owner = GetTileOwner(tile);
-	td->build_date = GetStationByTile(tile)->build_date;
-
-	switch (GetStationType(tile)) {
-		default: NOT_REACHED();
-		case STATION_RAIL:    str = STR_305E_RAILROAD_STATION; break;
-		case STATION_AIRPORT:
-			str = (IsHangar(tile) ? STR_305F_AIRCRAFT_HANGAR : STR_3060_AIRPORT);
-			break;
-		case STATION_TRUCK:   str = STR_3061_TRUCK_LOADING_AREA; break;
-		case STATION_BUS:     str = STR_3062_BUS_STATION; break;
-		case STATION_OILRIG:  str = STR_4807_OIL_RIG; break;
-		case STATION_DOCK:    str = STR_3063_SHIP_DOCK; break;
-		case STATION_BUOY:    str = STR_3069_BUOY; break;
-	}
-	td->str = str;
-}
-
-
-static uint32 GetTileTrackStatus_Station(TileIndex tile, TransportType mode)
-{
-	switch (mode) {
-		case TRANSPORT_RAIL:
-			if (IsRailwayStation(tile) && !IsStationTileBlocked(tile)) {
-				return TrackToTrackBits(GetRailStationTrack(tile)) * 0x101;
-			}
-			break;
-
-		case TRANSPORT_WATER:
-			// buoy is coded as a station, it is always on open water
-			if (IsBuoy_(tile)) return TRACK_BIT_ALL * 0x101;
-			break;
-
-		case TRANSPORT_ROAD:
-			if (IsRoadStopTile(tile)) {
-				return AxisToTrackBits(DiagDirToAxis(GetRoadStopDir(tile))) * 0x101;
-			}
-			break;
-
-		default:
-			break;
-	}
-
-	return 0;
-}
-
-
-static void TileLoop_Station(TileIndex tile)
-{
-	// FIXME -- GetTileTrackStatus_Station -> animated stationtiles
-	// hardcoded.....not good
-	switch (GetStationGfx(tile)) {
-		case GFX_RADAR_LARGE_FIRST:
-		case GFX_WINDSACK_FIRST : // for small airport
-		case GFX_RADAR_INTERNATIONAL_FIRST:
-		case GFX_RADAR_METROPOLITAN_FIRST:
-		case GFX_RADAR_DISTRICTWE_FIRST: // radar district W-E airport
-		case GFX_WINDSACK_INTERCON_FIRST : // for intercontinental airport
-			AddAnimatedTile(tile);
-			break;
-
-		case GFX_OILRIG_BASE: //(station part)
-		case GFX_BUOY_BASE:
-			TileLoop_Water(tile);
-			break;
-
-		default: break;
-	}
-}
-
-
-static void AnimateTile_Station(TileIndex tile)
-{
-	typedef struct AnimData {
-		StationGfx from; // first sprite
-		StationGfx to;   // last sprite
-		byte delay;
-	} AnimData;
-
-	static const AnimData data[] = {
-		{ GFX_RADAR_LARGE_FIRST,         GFX_RADAR_LARGE_LAST,         3 },
-		{ GFX_WINDSACK_FIRST,            GFX_WINDSACK_LAST,            1 },
-		{ GFX_RADAR_INTERNATIONAL_FIRST, GFX_RADAR_INTERNATIONAL_LAST, 3 },
-		{ GFX_RADAR_METROPOLITAN_FIRST,  GFX_RADAR_METROPOLITAN_LAST,  3 },
-		{ GFX_RADAR_DISTRICTWE_FIRST,    GFX_RADAR_DISTRICTWE_LAST,    3 },
-		{ GFX_WINDSACK_INTERCON_FIRST,   GFX_WINDSACK_INTERCON_LAST,   1 }
-	};
-
-	StationGfx gfx = GetStationGfx(tile);
-	const AnimData* i;
-
-	for (i = data; i != endof(data); i++) {
-		if (i->from <= gfx && gfx <= i->to) {
-			if ((_tick_counter & i->delay) == 0) {
-				SetStationGfx(tile, gfx < i->to ? gfx + 1 : i->from);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-		}
-	}
-}
-
-
-static void ClickTile_Station(TileIndex tile)
-{
-	if (IsHangar(tile)) {
-		ShowDepotWindow(tile, VEH_Aircraft);
-	} else {
-		ShowStationViewWindow(GetStationIndex(tile));
-	}
-}
-
-static const byte _enter_station_speedtable[12] = {
-	215, 195, 175, 155, 135, 115, 95, 75, 55, 35, 15, 0
-};
-
-static uint32 VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
-{
-	if (v->type == VEH_Train) {
-		if (IsRailwayStation(tile) && IsFrontEngine(v) &&
-				!IsCompatibleTrainStationTile(tile + TileOffsByDiagDir(DirToDiagDir(v->direction)), tile)) {
-			StationID station_id = GetStationIndex(tile);
-
-			if ((!(v->current_order.flags & OF_NON_STOP) && !_patches.new_nonstop) ||
-					(v->current_order.type == OT_GOTO_STATION && v->current_order.dest == station_id)) {
-				if (!(_patches.new_nonstop && v->current_order.flags & OF_NON_STOP) &&
-						v->current_order.type != OT_LEAVESTATION &&
-						v->last_station_visited != station_id) {
-					DiagDirection dir = DirToDiagDir(v->direction);
-
-					x &= 0xF;
-					y &= 0xF;
-
-					if (DiagDirToAxis(dir) != AXIS_X) intswap(x, y);
-					if (y == TILE_SIZE / 2) {
-						if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
-						if (x == 12) return 2 | (station_id << 8); /* enter station */
-						if (x < 12) {
-							uint16 spd;
-
-							v->vehstatus |= VS_TRAIN_SLOWING;
-							spd = _enter_station_speedtable[x];
-							if (spd < v->cur_speed) v->cur_speed = spd;
-						}
-					}
-				}
-			}
-		}
-	} else if (v->type == VEH_Road) {
-		if (v->u.road.state < 16 && !HASBIT(v->u.road.state, 2) && v->u.road.frame == 0) {
-			if (IsRoadStop(tile)) {
-				/* Attempt to allocate a parking bay in a road stop */
-				RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile));
-
-				/* rs->status bits 0 and 1 describe current the two parking spots.
-				 * 0 means occupied, 1 means free. */
-
-				// Check if station is busy or if there are no free bays.
-				if (HASBIT(rs->status, 7) || GB(rs->status, 0, 2) == 0)
-					return 8;
-
-				v->u.road.state += 32;
-
-				// if the first bay is free, allocate that, else the second bay must be free.
-				if (HASBIT(rs->status, 0)) {
-					CLRBIT(rs->status, 0);
-				} else {
-					CLRBIT(rs->status, 1);
-					v->u.road.state += 2;
-				}
-
-				// mark the station as busy
-				SETBIT(rs->status, 7);
-			}
-		}
-	}
-
-	return 0;
-}
-
-/**
- * Cleanup a RoadStop. Make sure no vehicles try to go to this roadstop.
- */
-void DestroyRoadStop(RoadStop* rs)
-{
-	Vehicle *v;
-
-	/* Clear the slot assignment of all vehicles heading for this road stop */
-	if (rs->num_vehicles != 0) {
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_Road && v->u.road.slot == rs) {
-				ClearSlot(v);
-			}
-		}
-	}
-	assert(rs->num_vehicles == 0);
-
-	if (rs->prev != NULL) rs->prev->next = rs->next;
-	if (rs->next != NULL) rs->next->prev = rs->prev;
-}
-
-/**
- * Clean up a station by clearing vehicle orders and invalidating windows.
- * Aircraft-Hangar orders need special treatment here, as the hangars are
- * actually part of a station (tiletype is STATION), but the order type
- * is OT_GOTO_DEPOT.
- * @param st Station to be deleted
- */
-void DestroyStation(Station *st)
-{
-	StationID index;
-
-	index = st->index;
-
-	DeleteName(st->string_id);
-	MarkStationDirty(st);
-	RebuildStationLists();
-	InvalidateWindowClasses(WC_STATION_LIST);
-
-	DeleteWindowById(WC_STATION_VIEW, index);
-
-	/* Now delete all orders that go to the station */
-	RemoveOrderFromAllVehicles(OT_GOTO_STATION, index);
-
-	//Subsidies need removal as well
-	DeleteSubsidyWithStation(index);
-
-	free(st->speclist);
-}
-
-void DeleteAllPlayerStations(void)
-{
-	Station *st;
-
-	FOR_ALL_STATIONS(st) {
-		if (IsValidPlayer(st->owner)) DeleteStation(st);
-	}
-}
-
-/* this function is called for one station each tick */
-static void StationHandleBigTick(Station *st)
-{
-	UpdateStationAcceptance(st, true);
-
-	if (st->facilities == 0 && ++st->delete_ctr >= 8) DeleteStation(st);
-
-}
-
-static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; }
-
-static void UpdateStationRating(Station *st)
-{
-	GoodsEntry *ge;
-	int rating;
-	StationID index;
-	int waiting;
-	bool waiting_changed = false;
-
-	byte_inc_sat(&st->time_since_load);
-	byte_inc_sat(&st->time_since_unload);
-
-	ge = st->goods;
-	do {
-		if (ge->enroute_from != INVALID_STATION) {
-			byte_inc_sat(&ge->enroute_time);
-			byte_inc_sat(&ge->days_since_pickup);
-
-			rating = 0;
-
-			{
-				int b = ge->last_speed;
-				if ((b-=85) >= 0)
-					rating += b >> 2;
-			}
-
-			{
-				byte age = ge->last_age;
-				(age >= 3) ||
-				(rating += 10, age >= 2) ||
-				(rating += 10, age >= 1) ||
-				(rating += 13, true);
-			}
-
-			if (IsValidPlayer(st->owner) && HASBIT(st->town->statues, st->owner)) rating += 26;
-
-			{
-				byte days = ge->days_since_pickup;
-				if (st->last_vehicle_type == VEH_Ship)
-							days >>= 2;
-				(days > 21) ||
-				(rating += 25, days > 12) ||
-				(rating += 25, days > 6) ||
-				(rating += 45, days > 3) ||
-				(rating += 35, true);
-			}
-
-			{
-				waiting = GB(ge->waiting_acceptance, 0, 12);
-				(rating -= 90, waiting > 1500) ||
-				(rating += 55, waiting > 1000) ||
-				(rating += 35, waiting > 600) ||
-				(rating += 10, waiting > 300) ||
-				(rating += 20, waiting > 100) ||
-				(rating += 10, true);
-			}
-
-			{
-				int or = ge->rating; // old rating
-
-				// only modify rating in steps of -2, -1, 0, 1 or 2
-				ge->rating = rating = or + clamp(clamp(rating, 0, 255) - or, -2, 2);
-
-				// if rating is <= 64 and more than 200 items waiting, remove some random amount of goods from the station
-				if (rating <= 64 && waiting >= 200) {
-					int dec = Random() & 0x1F;
-					if (waiting < 400) dec &= 7;
-					waiting -= dec + 1;
-					waiting_changed = true;
-				}
-
-				// if rating is <= 127 and there are any items waiting, maybe remove some goods.
-				if (rating <= 127 && waiting != 0) {
-					uint32 r = Random();
-					if ( (uint)rating <= (r & 0x7F) ) {
-						waiting = max(waiting - ((r >> 8)&3) - 1, 0);
-						waiting_changed = true;
-					}
-				}
-
-				if (waiting_changed) SB(ge->waiting_acceptance, 0, 12, waiting);
-			}
-		}
-	} while (++ge != endof(st->goods));
-
-	index = st->index;
-
-	if (waiting_changed) {
-		InvalidateWindow(WC_STATION_VIEW, index);
-	} else {
-		InvalidateWindowWidget(WC_STATION_VIEW, index, 5);
-	}
-}
-
-/* called for every station each tick */
-static void StationHandleSmallTick(Station *st)
-{
-	byte b;
-
-	if (st->facilities == 0) return;
-
-	b = st->delete_ctr + 1;
-	if (b >= 185) b = 0;
-	st->delete_ctr = b;
-
-	if (b == 0) UpdateStationRating(st);
-}
-
-void OnTick_Station(void)
-{
-	uint i;
-	Station *st;
-
-	if (_game_mode == GM_EDITOR) return;
-
-	i = _station_tick_ctr;
-	if (++_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
-
-	if (IsValidStationID(i)) StationHandleBigTick(GetStation(i));
-
-	FOR_ALL_STATIONS(st) {
-		StationHandleSmallTick(st);
-	}
-}
-
-void StationMonthlyLoop(void)
-{
-}
-
-
-void ModifyStationRatingAround(TileIndex tile, PlayerID owner, int amount, uint radius)
-{
-	Station *st;
-
-	FOR_ALL_STATIONS(st) {
-		if (st->owner == owner &&
-				DistanceManhattan(tile, st->xy) <= radius) {
-			uint i;
-
-			for (i = 0; i != NUM_CARGO; i++) {
-				GoodsEntry* ge = &st->goods[i];
-
-				if (ge->enroute_from != INVALID_STATION) {
-					ge->rating = clamp(ge->rating + amount, 0, 255);
-				}
-			}
-		}
-	}
-}
-
-static void UpdateStationWaiting(Station *st, int type, uint amount)
-{
-	SB(st->goods[type].waiting_acceptance, 0, 12,
-		min(0xFFF, GB(st->goods[type].waiting_acceptance, 0, 12) + amount)
-	);
-
-	st->goods[type].enroute_time = 0;
-	st->goods[type].enroute_from = st->index;
-	InvalidateWindow(WC_STATION_VIEW, st->index);
-	MarkStationTilesDirty(st);
-}
-
-/** Rename a station
- * @param tile unused
- * @param p1 station ID that is to be renamed
- * @param p2 unused
- */
-int32 CmdRenameStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID str;
-	Station *st;
-
-	if (!IsValidStationID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
-	st = GetStation(p1);
-
-	if (!CheckOwnership(st->owner)) return CMD_ERROR;
-
-	str = AllocateNameUnique(_cmd_text, 6);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		StringID old_str = st->string_id;
-
-		st->string_id = str;
-		UpdateStationVirtCoord(st);
-		DeleteName(old_str);
-		ResortStationLists();
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-
-	return 0;
-}
-
-
-uint MoveGoodsToStation(TileIndex tile, int w, int h, int type, uint amount)
-{
-	Station* around[8];
-	uint i;
-	uint moved;
-	uint best_rating, best_rating2;
-	Station *st1, *st2;
-	uint t;
-	int rad = 0;
-	int w_prod; //width and height of the "producer" of the cargo
-	int h_prod;
-	int max_rad;
-
-	for (i = 0; i < lengthof(around); i++) around[i] = NULL;
-
-	if (_patches.modified_catchment) {
-		w_prod = w;
-		h_prod = h;
-		w += 16;
-		h += 16;
-		max_rad = 8;
-	} else {
-		w_prod = 0;
-		h_prod = 0;
-		w += 8;
-		h += 8;
-		max_rad = 4;
-	}
-
-	BEGIN_TILE_LOOP(cur_tile, w, h, tile - TileDiffXY(max_rad, max_rad))
-		Station* st;
-
-		cur_tile = TILE_MASK(cur_tile);
-		if (!IsTileType(cur_tile, MP_STATION)) continue;
-
-		st = GetStationByTile(cur_tile);
-
-		for (i = 0; i != lengthof(around); i++) {
-			if (around[i] == NULL) {
-				if (!IsBuoy(st) &&
-						(st->town->exclusive_counter == 0 || st->town->exclusivity == st->owner) && // check exclusive transport rights
-						st->goods[type].rating != 0 &&
-						(!_patches.selectgoods || st->goods[type].last_speed > 0) && // if last_speed is 0, no vehicle has been there.
-						((st->facilities & ~FACIL_BUS_STOP)   != 0 || type == CT_PASSENGERS) && // if we have other fac. than a bus stop, or the cargo is passengers
-						((st->facilities & ~FACIL_TRUCK_STOP) != 0 || type != CT_PASSENGERS)) { // if we have other fac. than a cargo bay or the cargo is not passengers
-					int x_dist;
-					int y_dist;
-
-					if (_patches.modified_catchment) {
-						// min and max coordinates of the producer relative
-						const int x_min_prod = 9;
-						const int x_max_prod = 8 + w_prod;
-						const int y_min_prod = 9;
-						const int y_max_prod = 8 + h_prod;
-
-						rad = FindCatchmentRadius(st);
-
-						x_dist = min(w_cur - x_min_prod, x_max_prod - w_cur);
-						if (w_cur < x_min_prod) {
-							x_dist = x_min_prod - w_cur;
-						} else if (w_cur > x_max_prod) {
-							x_dist = w_cur - x_max_prod;
-						}
-
-						y_dist = min(h_cur - y_min_prod, y_max_prod - h_cur);
-						if (h_cur < y_min_prod) {
-							y_dist = y_min_prod - h_cur;
-						} else if (h_cur > y_max_prod) {
-							y_dist = h_cur - y_max_prod;
-						}
-					} else {
-						x_dist = 0;
-						y_dist = 0;
-					}
-
-					if (x_dist <= rad && y_dist <= rad) around[i] = st;
-				}
-				break;
-			} else if (around[i] == st) {
-				break;
-			}
-		}
-	END_TILE_LOOP(cur_tile, w, h, tile - TileDiffXY(max_rad, max_rad))
-
-	/* no stations around at all? */
-	if (around[0] == NULL) return 0;
-
-	if (around[1] == NULL) {
-		/* only one station around */
-		moved = (amount * around[0]->goods[type].rating >> 8) + 1;
-		UpdateStationWaiting(around[0], type, moved);
-		return moved;
-	}
-
-	/* several stations around, find the two with the highest rating */
-	st2 = st1 = NULL;
-	best_rating = best_rating2 = 0;
-
-	for (i = 0; i != lengthof(around) && around[i] != NULL; i++) {
-		if (around[i]->goods[type].rating >= best_rating) {
-			best_rating2 = best_rating;
-			st2 = st1;
-
-			best_rating = around[i]->goods[type].rating;
-			st1 = around[i];
-		} else if (around[i]->goods[type].rating >= best_rating2) {
-			best_rating2 = around[i]->goods[type].rating;
-			st2 = around[i];
-		}
-	}
-
-	assert(st1 != NULL);
-	assert(st2 != NULL);
-	assert(best_rating != 0 || best_rating2 != 0);
-
-	/* the 2nd highest one gets a penalty */
-	best_rating2 >>= 1;
-
-	/* amount given to station 1 */
-	t = (best_rating * (amount + 1)) / (best_rating + best_rating2);
-
-	moved = 0;
-	if (t != 0) {
-		moved = t * best_rating / 256 + 1;
-		amount -= t;
-		UpdateStationWaiting(st1, type, moved);
-	}
-
-	if (amount != 0) {
-		amount = amount * best_rating2 / 256 + 1;
-		moved += amount;
-		UpdateStationWaiting(st2, type, amount);
-	}
-
-	return moved;
-}
-
-void BuildOilRig(TileIndex tile)
-{
-	uint j;
-	Station *st = AllocateStation();
-
-	if (st == NULL) {
-		DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
-		return;
-	}
-	if (!GenerateStationName(st, tile, 2)) {
-		DEBUG(misc, 0, "Can't allocate station-name for oilrig at 0x%X, reverting to oilrig only", tile);
-		return;
-	}
-
-	st->town = ClosestTownFromTile(tile, (uint)-1);
-	st->sign.width_1 = 0;
-
-	MakeOilrig(tile, st->index);
-
-	st->owner = OWNER_NONE;
-	st->airport_flags = 0;
-	st->airport_type = AT_OILRIG;
-	st->xy = tile;
-	st->bus_stops = NULL;
-	st->truck_stops = NULL;
-	st->airport_tile = tile;
-	st->dock_tile = tile;
-	st->train_tile = 0;
-	st->had_vehicle_of_type = 0;
-	st->time_since_load = 255;
-	st->time_since_unload = 255;
-	st->delete_ctr = 0;
-	st->last_vehicle_type = VEH_Invalid;
-	st->facilities = FACIL_AIRPORT | FACIL_DOCK;
-	st->build_date = _date;
-
-	for (j = 0; j != NUM_CARGO; j++) {
-		st->goods[j].waiting_acceptance = 0;
-		st->goods[j].days_since_pickup = 0;
-		st->goods[j].enroute_from = INVALID_STATION;
-		st->goods[j].rating = 175;
-		st->goods[j].last_speed = 0;
-		st->goods[j].last_age = 255;
-	}
-
-	UpdateStationVirtCoordDirty(st);
-	UpdateStationAcceptance(st, false);
-}
-
-void DeleteOilRig(TileIndex tile)
-{
-	Station* st = GetStationByTile(tile);
-
-	DoClearSquare(tile);
-
-	st->dock_tile = 0;
-	st->airport_tile = 0;
-	st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
-	st->airport_flags = 0;
-	UpdateStationVirtCoordDirty(st);
-	DeleteStation(st);
-}
-
-static void ChangeTileOwner_Station(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (new_player != PLAYER_SPECTATOR) {
-		Station* st = GetStationByTile(tile);
-
-		SetTileOwner(tile, new_player);
-		st->owner = new_player;
-		RebuildStationLists();
-		InvalidateWindowClasses(WC_STATION_LIST);
-	} else {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-	}
-}
-
-static int32 ClearTile_Station(TileIndex tile, byte flags)
-{
-	Station *st;
-
-	if (flags & DC_AUTO) {
-		switch (GetStationType(tile)) {
-			case STATION_RAIL:    return_cmd_error(STR_300B_MUST_DEMOLISH_RAILROAD);
-			case STATION_AIRPORT: return_cmd_error(STR_300E_MUST_DEMOLISH_AIRPORT_FIRST);
-			case STATION_TRUCK:   return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION);
-			case STATION_BUS:     return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION);
-			case STATION_BUOY:    return_cmd_error(STR_306A_BUOY_IN_THE_WAY);
-			case STATION_DOCK:    return_cmd_error(STR_304D_MUST_DEMOLISH_DOCK_FIRST);
-			case STATION_OILRIG:
-				SetDParam(0, STR_4807_OIL_RIG);
-				return_cmd_error(STR_4800_IN_THE_WAY);
-		}
-	}
-
-	st = GetStationByTile(tile);
-
-	switch (GetStationType(tile)) {
-		case STATION_RAIL:    return RemoveRailroadStation(st, tile, flags);
-		case STATION_AIRPORT: return RemoveAirport(st, flags);
-		case STATION_TRUCK:
-		case STATION_BUS:     return RemoveRoadStop(st, flags, tile);
-		case STATION_BUOY:    return RemoveBuoy(st, flags);
-		case STATION_DOCK:    return RemoveDock(st, flags);
-		default: break;
-	}
-
-	return CMD_ERROR;
-}
-
-void InitializeStations(void)
-{
-	/* Clean the station pool and create 1 block in it */
-	CleanPool(&_Station_pool);
-	AddBlockToPool(&_Station_pool);
-
-	/* Clean the roadstop pool and create 1 block in it */
-	CleanPool(&_RoadStop_pool);
-	AddBlockToPool(&_RoadStop_pool);
-
-	_station_tick_ctr = 0;
-
-}
-
-
-void AfterLoadStations(void)
-{
-	Station *st;
-	uint i;
-	TileIndex tile;
-
-	/* Update the speclists of all stations to point to the currently loaded custom stations. */
-	FOR_ALL_STATIONS(st) {
-		for (i = 0; i < st->num_specs; i++) {
-			if (st->speclist[i].grfid == 0) continue;
-
-			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
-		}
-	}
-
-	for (tile = 0; tile < MapSize(); tile++) {
-		if (GetTileType(tile) != MP_STATION) continue;
-		st = GetStationByTile(tile);
-		StationRect_BeforeAddTile(st, tile, RECT_MODE_FORCE);
-	}
-}
-
-
-const TileTypeProcs _tile_type_station_procs = {
-	DrawTile_Station,           /* draw_tile_proc */
-	GetSlopeZ_Station,          /* get_slope_z_proc */
-	ClearTile_Station,          /* clear_tile_proc */
-	GetAcceptedCargo_Station,   /* get_accepted_cargo_proc */
-	GetTileDesc_Station,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Station, /* get_tile_track_status_proc */
-	ClickTile_Station,          /* click_tile_proc */
-	AnimateTile_Station,        /* animate_tile_proc */
-	TileLoop_Station,           /* tile_loop_clear */
-	ChangeTileOwner_Station,    /* change_tile_owner_clear */
-	NULL,                       /* get_produced_cargo_proc */
-	VehicleEnter_Station,       /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Station,      /* get_slope_tileh_proc */
-};
-
-static const SaveLoad _roadstop_desc[] = {
-	SLE_VAR(RoadStop,xy,           SLE_UINT32),
-	SLE_VAR(RoadStop,used,         SLE_BOOL),
-	SLE_VAR(RoadStop,status,       SLE_UINT8),
-	/* Index was saved in some versions, but this is not needed */
-	SLE_CONDNULL(4, 0, 8),
-	SLE_VAR(RoadStop,station,      SLE_UINT16),
-	SLE_CONDNULL(1, 0, 25),
-
-	SLE_REF(RoadStop,next,         REF_ROADSTOPS),
-	SLE_REF(RoadStop,prev,         REF_ROADSTOPS),
-
-	SLE_CONDNULL(4, 0, 24),
-	SLE_CONDNULL(1, 25, 25),
-
-	SLE_END()
-};
-
-static const SaveLoad _station_desc[] = {
-	SLE_CONDVAR(Station, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Station, bus_tile_obsolete,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, lorry_tile_obsolete,        SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, train_tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, train_tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Station, airport_tile,               SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, airport_tile,               SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Station, dock_tile,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Station, dock_tile,                  SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLE_REF(Station, town,                       REF_TOWN),
-	    SLE_VAR(Station, trainst_w,                  SLE_UINT8),
-	SLE_CONDVAR(Station, trainst_h,                  SLE_UINT8,                   2, SL_MAX_VERSION),
-
-	// alpha_order was stored here in savegame format 0 - 3
-	SLE_CONDNULL(1, 0, 3),
-
-	    SLE_VAR(Station, string_id,                  SLE_STRINGID),
-	    SLE_VAR(Station, had_vehicle_of_type,        SLE_UINT16),
-
-	    SLE_VAR(Station, time_since_load,            SLE_UINT8),
-	    SLE_VAR(Station, time_since_unload,          SLE_UINT8),
-	    SLE_VAR(Station, delete_ctr,                 SLE_UINT8),
-	    SLE_VAR(Station, owner,                      SLE_UINT8),
-	    SLE_VAR(Station, facilities,                 SLE_UINT8),
-	    SLE_VAR(Station, airport_type,               SLE_UINT8),
-
-	// truck/bus_stop_status was stored here in savegame format 0 - 6
-	SLE_CONDVAR(Station, truck_stop_status_obsolete, SLE_UINT8, 0, 5),
-	SLE_CONDVAR(Station, bus_stop_status_obsolete,   SLE_UINT8, 0, 5),
-
-	// blocked_months was stored here in savegame format 0 - 4.0
-	SLE_CONDVAR(Station, blocked_months_obsolete,    SLE_UINT8, 0, 4),
-
-	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U32 | SLE_FILE_U16,  0,  2),
-	SLE_CONDVAR(Station, airport_flags,              SLE_UINT32,                  3, SL_MAX_VERSION),
-
-	SLE_CONDNULL(2, 0, 25), /* Ex last-vehicle */
-	SLE_CONDVAR(Station, last_vehicle_type,          SLE_UINT8,                  26, SL_MAX_VERSION),
-
-	// Was custom station class and id
-	SLE_CONDNULL(2, 3, 25),
-	SLE_CONDVAR(Station, build_date,                 SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
-	SLE_CONDVAR(Station, build_date,                 SLE_INT32,                  31, SL_MAX_VERSION),
-
-	SLE_CONDREF(Station, bus_stops,                  REF_ROADSTOPS,               6, SL_MAX_VERSION),
-	SLE_CONDREF(Station, truck_stops,                REF_ROADSTOPS,               6, SL_MAX_VERSION),
-
-	/* Used by newstations for graphic variations */
-	SLE_CONDVAR(Station, random_bits,                SLE_UINT16,                 27, SL_MAX_VERSION),
-	SLE_CONDVAR(Station, waiting_triggers,           SLE_UINT8,                  27, SL_MAX_VERSION),
-	SLE_CONDVAR(Station, num_specs,                  SLE_UINT8,                  27, SL_MAX_VERSION),
-
-	// reserve extra space in savegame here. (currently 32 bytes)
-	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _goods_desc[] = {
-	    SLE_VAR(GoodsEntry, waiting_acceptance, SLE_UINT16),
-	    SLE_VAR(GoodsEntry, days_since_pickup,  SLE_UINT8),
-	    SLE_VAR(GoodsEntry, rating,             SLE_UINT8),
-	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_FILE_U8 | SLE_VAR_U16,  0, 6),
-	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_UINT16,                 7, SL_MAX_VERSION),
-	    SLE_VAR(GoodsEntry, enroute_time,       SLE_UINT8),
-	    SLE_VAR(GoodsEntry, last_speed,         SLE_UINT8),
-	    SLE_VAR(GoodsEntry, last_age,           SLE_UINT8),
-	SLE_CONDVAR(GoodsEntry, feeder_profit,      SLE_INT32,                 14, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _station_speclist_desc[] = {
-	SLE_CONDVAR(StationSpecList, grfid,    SLE_UINT32, 27, SL_MAX_VERSION),
-	SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8,  27, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-
-static void SaveLoad_STNS(Station *st)
-{
-	uint i;
-
-	SlObject(st, _station_desc);
-	for (i = 0; i != NUM_CARGO; i++) {
-		SlObject(&st->goods[i], _goods_desc);
-
-		/* In older versions, enroute_from had 0xFF as INVALID_STATION, is now 0xFFFF */
-		if (CheckSavegameVersion(7) && st->goods[i].enroute_from == 0xFF) {
-			st->goods[i].enroute_from = INVALID_STATION;
-		}
-	}
-
-	if (st->num_specs != 0) {
-		/* Allocate speclist memory when loading a game */
-		if (st->speclist == NULL) st->speclist = calloc(st->num_specs, sizeof(*st->speclist));
-		for (i = 0; i < st->num_specs; i++) SlObject(&st->speclist[i], _station_speclist_desc);
-	}
-}
-
-static void Save_STNS(void)
-{
-	Station *st;
-	// Write the stations
-	FOR_ALL_STATIONS(st) {
-		SlSetArrayIndex(st->index);
-		SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
-	}
-}
-
-static void Load_STNS(void)
-{
-	int index;
-	while ((index = SlIterateArray()) != -1) {
-		Station *st;
-
-		if (!AddBlockIfNeeded(&_Station_pool, index))
-			error("Stations: failed loading savegame: too many stations");
-
-		st = GetStation(index);
-		SaveLoad_STNS(st);
-
-		// this means it's an oldstyle savegame without support for nonuniform stations
-		if (st->train_tile != 0 && st->trainst_h == 0) {
-			uint w = GB(st->trainst_w, 4, 4);
-			uint h = GB(st->trainst_w, 0, 4);
-
-			if (GetRailStationAxis(st->train_tile) == AXIS_Y) uintswap(w, h);
-			st->trainst_w = w;
-			st->trainst_h = h;
-		}
-
-		/* In older versions, we had just 1 tile for a bus/lorry, now we have more..
-		 *  convert, if needed */
-		if (CheckSavegameVersion(6)) {
-			if (st->bus_tile_obsolete != 0) {
-				st->bus_stops = AllocateRoadStop();
-				if (st->bus_stops == NULL)
-					error("Station: too many busstations in savegame");
-
-				InitializeRoadStop(st->bus_stops, NULL, st->bus_tile_obsolete, st->index);
-			}
-			if (st->lorry_tile_obsolete != 0) {
-				st->truck_stops = AllocateRoadStop();
-				if (st->truck_stops == NULL)
-					error("Station: too many truckstations in savegame");
-
-				InitializeRoadStop(st->truck_stops, NULL, st->lorry_tile_obsolete, st->index);
-			}
-		}
-	}
-
-	/* This is to ensure all pointers are within the limits of _stations_size */
-	if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
-}
-
-static void Save_ROADSTOP(void)
-{
-	RoadStop *rs;
-
-	FOR_ALL_ROADSTOPS(rs) {
-		SlSetArrayIndex(rs->index);
-		SlObject(rs, _roadstop_desc);
-	}
-}
-
-static void Load_ROADSTOP(void)
-{
-	int index;
-	Vehicle *v;
-
-	while ((index = SlIterateArray()) != -1) {
-		RoadStop *rs;
-
-		if (!AddBlockIfNeeded(&_RoadStop_pool, index))
-			error("RoadStops: failed loading savegame: too many RoadStops");
-
-		rs = GetRoadStop(index);
-		SlObject(rs, _roadstop_desc);
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Road && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++;
-	}
-}
-
-const ChunkHandler _station_chunk_handlers[] = {
-	{ 'STNS', Save_STNS,      Load_STNS,      CH_ARRAY },
-	{ 'ROAD', Save_ROADSTOP,  Load_ROADSTOP,  CH_ARRAY | CH_LAST},
-};
-
-
-static inline bool PtInRectXY(Rect *r, int x, int y)
-{
-	return (r->left <= x && x <= r->right && r->top <= y && y <= r->bottom);
-}
-
-static void StationRect_Init(Station *st)
-{
-	Rect *r = &st->rect;
-	r->left = r->top = r->right = r->bottom = 0;
-}
-
-static bool StationRect_IsEmpty(Station *st)
-{
-	return (st->rect.left == 0 || st->rect.left > st->rect.right || st->rect.top > st->rect.bottom);
-}
-
-static bool StationRect_BeforeAddTile(Station *st, TileIndex tile, StationRectMode mode)
-{
-	Rect *r = &st->rect;
-	int x = TileX(tile);
-	int y = TileY(tile);
-	if (StationRect_IsEmpty(st)) {
-		// we are adding the first station tile
-		r->left = r->right = x;
-		r->top = r->bottom = y;
-	} else if (!PtInRectXY(r, x, y)) {
-		// current rect is not empty and new point is outside this rect
-		// make new spread-out rectangle
-		Rect new_rect = {min(x, r->left), min(y, r->top), max(x, r->right), max(y, r->bottom)};
-		// check new rect dimensions against preset max
-		int w = new_rect.right - new_rect.left + 1;
-		int h = new_rect.bottom - new_rect.top + 1;
-		if (mode != RECT_MODE_FORCE && (w > _patches.station_spread || h > _patches.station_spread)) {
-			assert(mode != RECT_MODE_TRY);
-			_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
-			return false;
-		}
-		// spread-out ok, return true
-		if (mode != RECT_MODE_TEST) {
-			// we should update the station rect
-			*r = new_rect;
-		}
-	} else {
-		; // new point is inside the rect, we don't need to do anything
-	}
-	return true;
-}
-
-static bool StationRect_BeforeAddRect(Station *st, TileIndex tile, int w, int h, StationRectMode mode)
-{
-	return StationRect_BeforeAddTile(st, tile, mode) && StationRect_BeforeAddTile(st, TILE_ADDXY(tile, w - 1, h - 1), mode);
-}
-
-static inline bool ScanRectForStationTiles(StationID st_id, int left, int top, int right, int bottom)
-{
-	TileIndex top_left = TileXY(left, top);
-	int width = right - left + 1;
-	int height = bottom - top + 1;
-	BEGIN_TILE_LOOP(tile, width, height, top_left)
-		if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
-	END_TILE_LOOP(tile, width, height, top_left);
-	return false;
-}
-
-static bool StationRect_AfterRemoveTile(Station *st, TileIndex tile)
-{
-	Rect *r = &st->rect;
-	int x = TileX(tile);
-	int y = TileY(tile);
-	bool reduce_x, reduce_y;
-
-	// look if removed tile was on the bounding rect edge
-	// and try to reduce the rect by this edge
-	// do it until we have empty rect or nothing to do
-	for (;;) {
-		// check if removed tile is on rect edge
-		bool left_edge = (x == r->left);
-		bool right_edge = (x == r->right);
-		bool top_edge = (y == r->top);
-		bool bottom_edge = (y == r->bottom);
-		// can we reduce the rect in either direction?
-		reduce_x = ((left_edge || right_edge) && !ScanRectForStationTiles(st->index, x, r->top, x, r->bottom));
-		reduce_y = ((top_edge || bottom_edge) && !ScanRectForStationTiles(st->index, r->left, y, r->right, y));
-		if (!(reduce_x || reduce_y)) break; // nothing to do (can't reduce)
-		if (reduce_x) {
-			// reduce horizontally
-			if (left_edge) {
-				// move left edge right
-				r->left = x = x + 1;
-			} else {
-				// move right edge left
-				r->right = x = x - 1;
-			}
-		}
-		if (reduce_y) {
-			// reduce vertically
-			if (top_edge) {
-				// move top edge down
-				r->top = y = y + 1;
-			} else {
-				// move bottom edge up
-				r->bottom = y = y - 1;
-			}
-		}
-		if (r->left > r->right || r->top > r->bottom) {
-		// can't continue, if the remaining rectangle is empty
-			StationRect_Init(st);
-			return true; // empty remaining rect
-		}
-	}
-	return false; // non-empty remaining rect
-}
-
-static bool StationRect_AfterRemoveRect(Station *st, TileIndex tile, int w, int h)
-{
-	bool empty;
-	assert(PtInRectXY(&st->rect, TileX(tile), TileY(tile)));
-	assert(PtInRectXY(&st->rect, TileX(tile) + w - 1, TileY(tile) + h - 1));
-	empty = StationRect_AfterRemoveTile(st, tile);
-	if (w != 1 || h != 1) empty = empty || StationRect_AfterRemoveTile(st, TILE_ADDXY(tile, w - 1, h - 1));
-	return empty;
-}
new file mode 100644
--- /dev/null
+++ b/src/station_cmd.cpp
@@ -0,0 +1,3285 @@
+/* $Id$ */
+
+/** @file station_cmd.c */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "debug.h"
+#include "functions.h"
+#include "station_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "station.h"
+#include "gfx.h"
+#include "window.h"
+#include "viewport.h"
+#include "command.h"
+#include "town.h"
+#include "vehicle.h"
+#include "news.h"
+#include "saveload.h"
+#include "economy.h"
+#include "player.h"
+#include "airport.h"
+#include "sprite.h"
+#include "depot.h"
+#include "train.h"
+#include "water_map.h"
+#include "industry_map.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_station.h"
+#include "yapf/yapf.h"
+#include "date.h"
+
+typedef enum StationRectModes
+{
+	RECT_MODE_TEST = 0,
+	RECT_MODE_TRY,
+	RECT_MODE_FORCE
+} StationRectMode;
+
+static void StationRect_Init(Station *st);
+static bool StationRect_IsEmpty(Station *st);
+static bool StationRect_BeforeAddTile(Station *st, TileIndex tile, StationRectMode mode);
+static bool StationRect_BeforeAddRect(Station *st, TileIndex tile, int w, int h, StationRectMode mode);
+static bool StationRect_AfterRemoveTile(Station *st, TileIndex tile);
+static bool StationRect_AfterRemoveRect(Station *st, TileIndex tile, int w, int h);
+
+
+/**
+ * Called if a new block is added to the station-pool
+ */
+static void StationPoolNewBlock(uint start_item)
+{
+	Station *st;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 *  TODO - This is just a temporary stage, this will be removed. */
+	for (st = GetStation(start_item); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) st->index = start_item++;
+}
+
+static void StationPoolCleanBlock(uint start_item, uint end_item)
+{
+	uint i;
+
+	for (i = start_item; i <= end_item; i++) {
+		Station *st = GetStation(i);
+		free(st->speclist);
+		st->speclist = NULL;
+	}
+}
+
+/**
+ * Called if a new block is added to the roadstop-pool
+ */
+static void RoadStopPoolNewBlock(uint start_item)
+{
+	RoadStop *rs;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (rs = GetRoadStop(start_item); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) rs->index = start_item++;
+}
+
+DEFINE_OLD_POOL(Station, Station, StationPoolNewBlock, StationPoolCleanBlock)
+DEFINE_OLD_POOL(RoadStop, RoadStop, RoadStopPoolNewBlock, NULL)
+
+
+extern void UpdateAirplanesOnNewStation(Station *st);
+
+static bool TileBelongsToRailStation(const Station *st, TileIndex tile)
+{
+	return IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile);
+}
+
+void MarkStationTilesDirty(const Station *st)
+{
+	TileIndex tile = st->train_tile;
+	int w, h;
+
+	// XXX No station is recorded as 0, not INVALID_TILE...
+	if (tile == 0) return;
+
+	for (h = 0; h < st->trainst_h; h++) {
+		for (w = 0; w < st->trainst_w; w++) {
+			if (TileBelongsToRailStation(st, tile)) {
+				MarkTileDirtyByTile(tile);
+			}
+			tile += TileDiffXY(1, 0);
+		}
+		tile += TileDiffXY(-w, 1);
+	}
+}
+
+static void MarkStationDirty(const Station* st)
+{
+	if (st->sign.width_1 != 0) {
+		InvalidateWindowWidget(WC_STATION_VIEW, st->index, 1);
+
+		MarkAllViewportsDirty(
+			st->sign.left - 6,
+			st->sign.top,
+			st->sign.left + (st->sign.width_1 << 2) + 12,
+			st->sign.top + 48);
+	}
+}
+
+static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index)
+{
+	road_stop->xy = tile;
+	road_stop->used = true;
+	road_stop->status = 3; //stop is free
+	road_stop->next = NULL;
+	road_stop->prev = previous;
+	road_stop->station = index;
+	road_stop->num_vehicles = 0;
+}
+
+RoadStop* GetPrimaryRoadStop(const Station* st, RoadStopType type)
+{
+	switch (type) {
+		case RS_BUS:   return st->bus_stops;
+		case RS_TRUCK: return st->truck_stops;
+		default: NOT_REACHED();
+	}
+
+	return NULL;
+}
+
+RoadStop* GetRoadStopByTile(TileIndex tile, RoadStopType type)
+{
+	const Station* st = GetStationByTile(tile);
+	RoadStop* rs;
+
+	for (rs = GetPrimaryRoadStop(st, type); rs->xy != tile; rs = rs->next) {
+		assert(rs->next != NULL);
+	}
+
+	return rs;
+}
+
+uint GetNumRoadStopsInStation(const Station* st, RoadStopType type)
+{
+	uint num = 0;
+	const RoadStop *rs;
+
+	assert(st != NULL);
+	for (rs = GetPrimaryRoadStop(st, type); rs != NULL; rs = rs->next) num++;
+
+	return num;
+}
+
+RoadStop *AllocateRoadStop(void)
+{
+	RoadStop *rs;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (rs = GetRoadStop(0); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) {
+		if (!IsValidRoadStop(rs)) {
+			RoadStopID index = rs->index;
+
+			memset(rs, 0, sizeof(*rs));
+			rs->index = index;
+
+			return rs;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_RoadStop_pool)) return AllocateRoadStop();
+
+	return NULL;
+}
+
+/* Calculate the radius of the station. Basicly it is the biggest
+ *  radius that is available within the station */
+static uint FindCatchmentRadius(const Station* st)
+{
+	uint ret = 0;
+
+	if (st->bus_stops != NULL)   ret = max(ret, CA_BUS);
+	if (st->truck_stops != NULL) ret = max(ret, CA_TRUCK);
+	if (st->train_tile) ret = max(ret, CA_TRAIN);
+	if (st->dock_tile)  ret = max(ret, CA_DOCK);
+
+	if (st->airport_tile) {
+		switch (st->airport_type) {
+			case AT_OILRIG:        ret = max(ret, CA_AIR_OILPAD);   break;
+			case AT_SMALL:         ret = max(ret, CA_AIR_SMALL);    break;
+			case AT_HELIPORT:      ret = max(ret, CA_AIR_HELIPORT); break;
+			case AT_LARGE:         ret = max(ret, CA_AIR_LARGE);    break;
+			case AT_METROPOLITAN:  ret = max(ret, CA_AIR_METRO);    break;
+			case AT_INTERNATIONAL: ret = max(ret, CA_AIR_INTER);    break;
+			case AT_COMMUTER:      ret = max(ret, CA_AIR_COMMUTER); break;
+			case AT_HELIDEPOT:     ret = max(ret, CA_AIR_HELIDEPOT); break;
+			case AT_INTERCON:      ret = max(ret, CA_AIR_INTERCON); break;
+			case AT_HELISTATION:   ret = max(ret, CA_AIR_HELISTATION); break;
+		}
+	}
+
+	return ret;
+}
+
+#define CHECK_STATIONS_ERR ((Station*)-1)
+
+static Station* GetStationAround(TileIndex tile, int w, int h, StationID closest_station)
+{
+	// check around to see if there's any stations there
+	BEGIN_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1))
+		if (IsTileType(tile_cur, MP_STATION)) {
+			StationID t = GetStationIndex(tile_cur);
+			{
+				Station *st = GetStation(t);
+				// you cannot take control of an oilrig!!
+				if (st->airport_type == AT_OILRIG && st->facilities == (FACIL_AIRPORT|FACIL_DOCK))
+					continue;
+			}
+
+			if (closest_station == INVALID_STATION) {
+				closest_station = t;
+			} else if (closest_station != t) {
+				_error_message = STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING;
+				return CHECK_STATIONS_ERR;
+			}
+		}
+	END_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1))
+	return (closest_station == INVALID_STATION) ? NULL : GetStation(closest_station);
+}
+
+static Station *AllocateStation(void)
+{
+	Station *st = NULL;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (st = GetStation(0); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) {
+		if (!IsValidStation(st)) {
+			StationID index = st->index;
+
+			memset(st, 0, sizeof(Station));
+			st->index = index;
+
+			return st;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Station_pool)) return AllocateStation();
+
+	_error_message = STR_3008_TOO_MANY_STATIONS_LOADING;
+	return NULL;
+}
+
+
+/**
+ * Counts the numbers of tiles matching a specific type in the area around
+ * @param tile the center tile of the 'count area'
+ * @param type the type of tile searched for
+ * @param industry when type == MP_INDUSTRY, the type of the industry,
+ *                 in all other cases this parameter is ignored
+ * @result the noumber of matching tiles around
+ */
+static int CountMapSquareAround(TileIndex tile, TileType type, IndustryType industry)
+{
+	TileIndex cur_tile;
+	int dx, dy;
+	int num = 0;
+
+	for (dx = -3; dx <= 3; dx++) {
+		for (dy = -3; dy <= 3; dy++) {
+			cur_tile = TILE_MASK(tile + TileDiffXY(dx, dy));
+
+			if (IsTileType(cur_tile, type)) {
+				switch (type) {
+					case MP_INDUSTRY:
+						if (GetIndustryType(cur_tile) == industry)
+							num++;
+						break;
+
+					case MP_WATER:
+						if (!IsWater(cur_tile))
+							break;
+						/* FALL THROUGH WHEN WATER TILE */
+					case MP_TREES:
+						num++;
+						break;
+
+					default:
+						break;
+				}
+			}
+		}
+	}
+
+	return num;
+}
+
+#define M(x) ((x) - STR_SV_STNAME)
+
+static bool GenerateStationName(Station *st, TileIndex tile, int flag)
+{
+	static const uint32 _gen_station_name_bits[] = {
+		0,                                      /* 0 */
+		1 << M(STR_SV_STNAME_AIRPORT),          /* 1 */
+		1 << M(STR_SV_STNAME_OILFIELD),         /* 2 */
+		1 << M(STR_SV_STNAME_DOCKS),            /* 3 */
+		0x1FF << M(STR_SV_STNAME_BUOY_1),       /* 4 */
+		1 << M(STR_SV_STNAME_HELIPORT),         /* 5 */
+	};
+
+	Town *t = st->town;
+	uint32 free_names = (uint32)-1;
+	int found;
+	uint z,z2;
+	unsigned long tmp;
+
+	{
+		Station *s;
+
+		FOR_ALL_STATIONS(s) {
+			if (s != st && s->town==t) {
+				uint str = M(s->string_id);
+				if (str <= 0x20) {
+					if (str == M(STR_SV_STNAME_FOREST))
+						str = M(STR_SV_STNAME_WOODS);
+					CLRBIT(free_names, str);
+				}
+			}
+		}
+	}
+
+	/* check default names */
+	tmp = free_names & _gen_station_name_bits[flag];
+	if (tmp != 0) {
+		found = FindFirstBit(tmp);
+		goto done;
+	}
+
+	/* check mine? */
+	if (HASBIT(free_names, M(STR_SV_STNAME_MINES))) {
+		if (CountMapSquareAround(tile, MP_INDUSTRY, IT_COAL_MINE) >= 2 ||
+				CountMapSquareAround(tile, MP_INDUSTRY, IT_IRON_MINE) >= 2 ||
+				CountMapSquareAround(tile, MP_INDUSTRY, IT_COPPER_MINE) >= 2 ||
+				CountMapSquareAround(tile, MP_INDUSTRY, IT_GOLD_MINE) >= 2 ||
+				CountMapSquareAround(tile, MP_INDUSTRY, IT_DIAMOND_MINE) >= 2) {
+			found = M(STR_SV_STNAME_MINES);
+			goto done;
+		}
+	}
+
+	/* check close enough to town to get central as name? */
+	if (DistanceMax(tile,t->xy) < 8) {
+		found = M(STR_SV_STNAME);
+		if (HASBIT(free_names, M(STR_SV_STNAME))) goto done;
+
+		found = M(STR_SV_STNAME_CENTRAL);
+		if (HASBIT(free_names, M(STR_SV_STNAME_CENTRAL))) goto done;
+	}
+
+	/* Check lakeside */
+	if (HASBIT(free_names, M(STR_SV_STNAME_LAKESIDE)) &&
+			DistanceFromEdge(tile) < 20 &&
+			CountMapSquareAround(tile, MP_WATER, 0) >= 5) {
+		found = M(STR_SV_STNAME_LAKESIDE);
+		goto done;
+	}
+
+	/* Check woods */
+	if (HASBIT(free_names, M(STR_SV_STNAME_WOODS)) && (
+				CountMapSquareAround(tile, MP_TREES, 0) >= 8 ||
+				CountMapSquareAround(tile, MP_INDUSTRY, IT_FOREST) >= 2)
+			) {
+		found = _opt.landscape == LT_DESERT ?
+			M(STR_SV_STNAME_FOREST) : M(STR_SV_STNAME_WOODS);
+		goto done;
+	}
+
+	/* check elevation compared to town */
+	z = GetTileZ(tile);
+	z2 = GetTileZ(t->xy);
+	if (z < z2) {
+		found = M(STR_SV_STNAME_VALLEY);
+		if (HASBIT(free_names, M(STR_SV_STNAME_VALLEY))) goto done;
+	} else if (z > z2) {
+		found = M(STR_SV_STNAME_HEIGHTS);
+		if (HASBIT(free_names, M(STR_SV_STNAME_HEIGHTS))) goto done;
+	}
+
+	/* check direction compared to town */
+	{
+		static const int8 _direction_and_table[] = {
+			~( (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_EAST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
+			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
+			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_EAST)) | (1<<M(STR_SV_STNAME_NORTH)) ),
+			~( (1<<M(STR_SV_STNAME_SOUTH)) | (1<<M(STR_SV_STNAME_WEST)) | (1<<M(STR_SV_STNAME_EAST)) ),
+		};
+
+		free_names &= _direction_and_table[
+			(TileX(tile) < TileX(t->xy)) +
+			(TileY(tile) < TileY(t->xy)) * 2];
+	}
+
+	tmp = free_names & ((1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<6)|(1<<7)|(1<<12)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30));
+	if (tmp == 0) {
+		_error_message = STR_3007_TOO_MANY_STATIONS_LOADING;
+		return false;
+	}
+	found = FindFirstBit(tmp);
+
+done:
+	st->string_id = found + STR_SV_STNAME;
+	return true;
+}
+#undef M
+
+static Station* GetClosestStationFromTile(TileIndex tile, uint threshold, PlayerID owner)
+{
+	Station* best_station = NULL;
+	Station* st;
+
+	FOR_ALL_STATIONS(st) {
+		if ((owner == PLAYER_SPECTATOR || st->owner == owner)) {
+			uint cur_dist = DistanceManhattan(tile, st->xy);
+
+			if (cur_dist < threshold) {
+				threshold = cur_dist;
+				best_station = st;
+			}
+		}
+	}
+
+	return best_station;
+}
+
+static void StationInitialize(Station *st, TileIndex tile)
+{
+	GoodsEntry *ge;
+
+	st->xy = tile;
+	st->airport_tile = st->dock_tile = st->train_tile = 0;
+	st->bus_stops = st->truck_stops = NULL;
+	st->had_vehicle_of_type = 0;
+	st->time_since_load = 255;
+	st->time_since_unload = 255;
+	st->delete_ctr = 0;
+	st->facilities = 0;
+
+	st->last_vehicle_type = VEH_Invalid;
+
+	for (ge = st->goods; ge != endof(st->goods); ge++) {
+		ge->waiting_acceptance = 0;
+		ge->days_since_pickup = 0;
+		ge->enroute_from = INVALID_STATION;
+		ge->rating = 175;
+		ge->last_speed = 0;
+		ge->last_age = 0xFF;
+		ge->feeder_profit = 0;
+	}
+
+	st->random_bits = Random();
+	st->waiting_triggers = 0;
+
+	StationRect_Init(st);
+}
+
+// Update the virtual coords needed to draw the station sign.
+// st = Station to update for.
+static void UpdateStationVirtCoord(Station *st)
+{
+	Point pt = RemapCoords2(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE);
+
+	pt.y -= 32;
+	if (st->facilities & FACIL_AIRPORT && st->airport_type == AT_OILRIG) pt.y -= 16;
+
+	SetDParam(0, st->index);
+	SetDParam(1, st->facilities);
+	UpdateViewportSignPos(&st->sign, pt.x, pt.y, STR_305C_0);
+}
+
+// Update the virtual coords needed to draw the station sign for all stations.
+void UpdateAllStationVirtCoord(void)
+{
+	Station* st;
+
+	FOR_ALL_STATIONS(st) {
+		UpdateStationVirtCoord(st);
+	}
+}
+
+// Update the station virt coords while making the modified parts dirty.
+static void UpdateStationVirtCoordDirty(Station *st)
+{
+	MarkStationDirty(st);
+	UpdateStationVirtCoord(st);
+	MarkStationDirty(st);
+}
+
+// Get a mask of the cargo types that the station accepts.
+static uint GetAcceptanceMask(const Station *st)
+{
+	uint mask = 0;
+	uint i;
+
+	for (i = 0; i != NUM_CARGO; i++) {
+		if (st->goods[i].waiting_acceptance & 0x8000) mask |= 1 << i;
+	}
+	return mask;
+}
+
+// Items contains the two cargo names that are to be accepted or rejected.
+// msg is the string id of the message to display.
+static void ShowRejectOrAcceptNews(const Station *st, uint32 items, StringID msg)
+{
+	if (items) {
+		SetDParam(2, GB(items, 16, 16));
+		SetDParam(1, GB(items,  0, 16));
+		SetDParam(0, st->index);
+		AddNewsItem(msg + (GB(items, 16, 16) ? 1 : 0), NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_TILE, NT_ACCEPTANCE, 0), st->xy, 0);
+	}
+}
+
+// Get a list of the cargo types being produced around the tile.
+void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile,
+	int w, int h, int rad)
+{
+	int x,y;
+	int x1,y1,x2,y2;
+	int xc,yc;
+
+	memset(produced, 0, sizeof(AcceptedCargo));
+
+	x = TileX(tile);
+	y = TileY(tile);
+
+	// expand the region by rad tiles on each side
+	// while making sure that we remain inside the board.
+	x2 = min(x + w + rad, MapSizeX());
+	x1 = max(x - rad, 0);
+
+	y2 = min(y + h + rad, MapSizeY());
+	y1 = max(y - rad, 0);
+
+	assert(x1 < x2);
+	assert(y1 < y2);
+	assert(w > 0);
+	assert(h > 0);
+
+	for (yc = y1; yc != y2; yc++) {
+		for (xc = x1; xc != x2; xc++) {
+			if (!(IS_INSIDE_1D(xc, x, w) && IS_INSIDE_1D(yc, y, h))) {
+				GetProducedCargoProc *gpc;
+				TileIndex tile = TileXY(xc, yc);
+
+				gpc = _tile_type_procs[GetTileType(tile)]->get_produced_cargo_proc;
+				if (gpc != NULL) {
+					CargoID cargos[2] = { CT_INVALID, CT_INVALID };
+
+					gpc(tile, cargos);
+					if (cargos[0] != CT_INVALID) {
+						produced[cargos[0]]++;
+						if (cargos[1] != CT_INVALID) {
+							produced[cargos[1]]++;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+// Get a list of the cargo types that are accepted around the tile.
+void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile,
+	int w, int h, int rad)
+{
+	int x,y;
+	int x1,y1,x2,y2;
+	int xc,yc;
+
+	memset(accepts, 0, sizeof(AcceptedCargo));
+
+	x = TileX(tile);
+	y = TileY(tile);
+
+	// expand the region by rad tiles on each side
+	// while making sure that we remain inside the board.
+	x2 = min(x + w + rad, MapSizeX());
+	y2 = min(y + h + rad, MapSizeY());
+	x1 = max(x - rad, 0);
+	y1 = max(y - rad, 0);
+
+	assert(x1 < x2);
+	assert(y1 < y2);
+	assert(w > 0);
+	assert(h > 0);
+
+	for (yc = y1; yc != y2; yc++) {
+		for (xc = x1; xc != x2; xc++) {
+			TileIndex tile = TileXY(xc, yc);
+
+			if (!IsTileType(tile, MP_STATION)) {
+				AcceptedCargo ac;
+				uint i;
+
+				GetAcceptedCargo(tile, ac);
+				for (i = 0; i < lengthof(ac); ++i) accepts[i] += ac[i];
+			}
+		}
+	}
+}
+
+typedef struct ottd_Rectangle {
+	uint min_x;
+	uint min_y;
+	uint max_x;
+	uint max_y;
+} ottd_Rectangle;
+
+static inline void MergePoint(ottd_Rectangle* rect, TileIndex tile)
+{
+	uint x = TileX(tile);
+	uint y = TileY(tile);
+
+	if (rect->min_x > x) rect->min_x = x;
+	if (rect->min_y > y) rect->min_y = y;
+	if (rect->max_x < x) rect->max_x = x;
+	if (rect->max_y < y) rect->max_y = y;
+}
+
+// Update the acceptance for a station.
+// show_msg controls whether to display a message that acceptance was changed.
+static void UpdateStationAcceptance(Station *st, bool show_msg)
+{
+	uint old_acc, new_acc;
+	const RoadStop *cur_rs;
+	int i;
+	ottd_Rectangle rect;
+	int rad;
+	AcceptedCargo accepts;
+
+	rect.min_x = MapSizeX();
+	rect.min_y = MapSizeY();
+	rect.max_x = rect.max_y = 0;
+	// Don't update acceptance for a buoy
+	if (IsBuoy(st)) return;
+
+	/* old accepted goods types */
+	old_acc = GetAcceptanceMask(st);
+
+	// Put all the tiles that span an area in the table.
+	if (st->train_tile != 0) {
+		MergePoint(&rect, st->train_tile);
+		MergePoint(&rect,
+			st->train_tile + TileDiffXY(st->trainst_w - 1, st->trainst_h - 1)
+		);
+	}
+
+	if (st->airport_tile != 0) {
+		const AirportFTAClass* afc = GetAirport(st->airport_type);
+
+		MergePoint(&rect, st->airport_tile);
+		MergePoint(&rect,
+			st->airport_tile + TileDiffXY(afc->size_x - 1, afc->size_y - 1)
+		);
+	}
+
+	if (st->dock_tile != 0) MergePoint(&rect, st->dock_tile);
+
+	for (cur_rs = st->bus_stops; cur_rs != NULL; cur_rs = cur_rs->next) {
+		MergePoint(&rect, cur_rs->xy);
+	}
+
+	for (cur_rs = st->truck_stops; cur_rs != NULL; cur_rs = cur_rs->next) {
+		MergePoint(&rect, cur_rs->xy);
+	}
+
+	rad = (_patches.modified_catchment) ? FindCatchmentRadius(st) : 4;
+
+	// And retrieve the acceptance.
+	if (rect.max_x >= rect.min_x) {
+		GetAcceptanceAroundTiles(
+			accepts,
+			TileXY(rect.min_x, rect.min_y),
+			rect.max_x - rect.min_x + 1,
+			rect.max_y - rect.min_y + 1,
+			rad
+		);
+	} else {
+		memset(accepts, 0, sizeof(accepts));
+	}
+
+	// Adjust in case our station only accepts fewer kinds of goods
+	for (i = 0; i != NUM_CARGO; i++) {
+		uint amt = min(accepts[i], 15);
+
+		// Make sure the station can accept the goods type.
+		if ((i != CT_PASSENGERS && !(st->facilities & (byte)~FACIL_BUS_STOP)) ||
+				(i == CT_PASSENGERS && !(st->facilities & (byte)~FACIL_TRUCK_STOP)))
+			amt = 0;
+
+		SB(st->goods[i].waiting_acceptance, 12, 4, amt);
+	}
+
+	// Only show a message in case the acceptance was actually changed.
+	new_acc = GetAcceptanceMask(st);
+	if (old_acc == new_acc)
+		return;
+
+	// show a message to report that the acceptance was changed?
+	if (show_msg && st->owner == _local_player && st->facilities) {
+		uint32 accept=0, reject=0; /* these contain two string ids each */
+		const StringID *str = _cargoc.names_s;
+
+		do {
+			if (new_acc & 1) {
+				if (!(old_acc & 1)) accept = (accept << 16) | *str;
+			} else {
+				if (old_acc & 1) reject = (reject << 16) | *str;
+			}
+		} while (str++,(new_acc>>=1) != (old_acc>>=1));
+
+		ShowRejectOrAcceptNews(st, accept, STR_3040_NOW_ACCEPTS);
+		ShowRejectOrAcceptNews(st, reject, STR_303E_NO_LONGER_ACCEPTS);
+	}
+
+	// redraw the station view since acceptance changed
+	InvalidateWindowWidget(WC_STATION_VIEW, st->index, 4);
+}
+
+static void UpdateStationSignCoord(Station *st)
+{
+	Rect *r = &st->rect;
+
+	if (StationRect_IsEmpty(st)) return; // no tiles belong to this station
+
+	// clamp sign coord to be inside the station rect
+	st->xy = TileXY(clampu(TileX(st->xy), r->left, r->right), clampu(TileY(st->xy), r->top, r->bottom));
+	UpdateStationVirtCoordDirty(st);
+}
+
+// This is called right after a station was deleted.
+// It checks if the whole station is free of substations, and if so, the station will be
+// deleted after a little while.
+static void DeleteStationIfEmpty(Station* st)
+{
+	if (st->facilities == 0) {
+		st->delete_ctr = 0;
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+	/* station remains but it probably lost some parts - station sign should stay in the station boundaries */
+	UpdateStationSignCoord(st);
+}
+
+static int32 ClearTile_Station(TileIndex tile, byte flags);
+
+// Tries to clear the given area. Returns the cost in case of success.
+// Or an error code if it failed.
+int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station)
+{
+	int32 cost = 0, ret;
+
+	Slope tileh;
+	uint z;
+	int allowed_z = -1;
+	int flat_z;
+
+	BEGIN_TILE_LOOP(tile_cur, w, h, tile)
+		if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) {
+			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+		}
+
+		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
+
+		tileh = GetTileSlope(tile_cur, &z);
+
+		/* Prohibit building if
+		 *   1) The tile is "steep" (i.e. stretches two height levels)
+		 * -OR-
+		 *   2) The tile is non-flat if
+		 *     a) the player building is an "old-school" AI
+		 *   -OR-
+		 *     b) the build_on_slopes switch is disabled
+		 */
+		if (IsSteepSlope(tileh) ||
+				((_is_old_ai_player || !_patches.build_on_slopes) && tileh != SLOPE_FLAT)) {
+			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+		}
+
+		flat_z = z;
+		if (tileh != SLOPE_FLAT) {
+			// need to check so the entrance to the station is not pointing at a slope.
+			if ((invalid_dirs&1 && !(tileh & SLOPE_NE) && (uint)w_cur == w) ||
+					(invalid_dirs&2 && !(tileh & SLOPE_SE) && h_cur == 1) ||
+					(invalid_dirs&4 && !(tileh & SLOPE_SW) && w_cur == 1) ||
+					(invalid_dirs&8 && !(tileh & SLOPE_NW) && (uint)h_cur == h)) {
+				return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+			}
+			cost += _price.terraform;
+			flat_z += TILE_HEIGHT;
+		}
+
+		// get corresponding flat level and make sure that all parts of the station have the same level.
+		if (allowed_z == -1) {
+			// first tile
+			allowed_z = flat_z;
+		} else if (allowed_z != flat_z) {
+			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+		}
+
+		// if station is set, then we have special handling to allow building on top of already existing stations.
+		// so station points to INVALID_STATION if we can build on any station. or it points to a station if we're only allowed to build
+		// on exactly that station.
+		if (station != NULL && IsTileType(tile_cur, MP_STATION)) {
+			if (!IsRailwayStation(tile_cur)) {
+				return ClearTile_Station(tile_cur, DC_AUTO); // get error message
+			} else {
+				StationID st = GetStationIndex(tile_cur);
+				if (*station == INVALID_STATION) {
+					*station = st;
+				} else if (*station != st) {
+					return_cmd_error(STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING);
+				}
+			}
+		} else {
+			ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			if (CmdFailed(ret)) return ret;
+			cost += ret;
+		}
+	END_TILE_LOOP(tile_cur, w, h, tile)
+
+	return cost;
+}
+
+static bool CanExpandRailroadStation(Station* st, uint* fin, Axis axis)
+{
+	uint curw = st->trainst_w, curh = st->trainst_h;
+	TileIndex tile = fin[0];
+	uint w = fin[1];
+	uint h = fin[2];
+
+	if (_patches.nonuniform_stations) {
+		// determine new size of train station region..
+		int x = min(TileX(st->train_tile), TileX(tile));
+		int y = min(TileY(st->train_tile), TileY(tile));
+		curw = max(TileX(st->train_tile) + curw, TileX(tile) + w) - x;
+		curh = max(TileY(st->train_tile) + curh, TileY(tile) + h) - y;
+		tile = TileXY(x, y);
+	} else {
+		// check so the orientation is the same
+		if (GetRailStationAxis(st->train_tile) != axis) {
+			_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED;
+			return false;
+		}
+
+		// check if the new station adjoins the old station in either direction
+		if (curw == w && st->train_tile == tile + TileDiffXY(0, h)) {
+			// above
+			curh += h;
+		} else if (curw == w && st->train_tile == tile - TileDiffXY(0, curh)) {
+			// below
+			tile -= TileDiffXY(0, curh);
+			curh += h;
+		} else if (curh == h && st->train_tile == tile + TileDiffXY(w, 0)) {
+			// to the left
+			curw += w;
+		} else if (curh == h && st->train_tile == tile - TileDiffXY(curw, 0)) {
+			// to the right
+			tile -= TileDiffXY(curw, 0);
+			curw += w;
+		} else {
+			_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED;
+			return false;
+		}
+	}
+	// make sure the final size is not too big.
+	if (curw > _patches.station_spread || curh > _patches.station_spread) {
+		_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
+		return false;
+	}
+
+	// now tile contains the new value for st->train_tile
+	// curw, curh contain the new value for width and height
+	fin[0] = tile;
+	fin[1] = curw;
+	fin[2] = curh;
+	return true;
+}
+
+static inline byte *CreateSingle(byte *layout, int n)
+{
+	int i = n;
+	do *layout++ = 0; while (--i);
+	layout[((n-1) >> 1)-n] = 2;
+	return layout;
+}
+
+static inline byte *CreateMulti(byte *layout, int n, byte b)
+{
+	int i = n;
+	do *layout++ = b; while (--i);
+	if (n > 4) {
+		layout[0-n] = 0;
+		layout[n-1-n] = 0;
+	}
+	return layout;
+}
+
+static void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
+{
+	if (statspec != NULL && statspec->lengths >= plat_len &&
+			statspec->platforms[plat_len - 1] >= numtracks &&
+			statspec->layouts[plat_len - 1][numtracks - 1]) {
+		/* Custom layout defined, follow it. */
+		memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
+			plat_len * numtracks);
+		return;
+	}
+
+	if (plat_len == 1) {
+		CreateSingle(layout, numtracks);
+	} else {
+		if (numtracks & 1) layout = CreateSingle(layout, plat_len);
+		numtracks >>= 1;
+
+		while (--numtracks >= 0) {
+			layout = CreateMulti(layout, plat_len, 4);
+			layout = CreateMulti(layout, plat_len, 6);
+		}
+	}
+}
+
+/** Build railroad station
+ * @param tile_org starting position of station dragging/placement
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit  0)    - orientation (p1 & 1)
+ * - p1 = (bit  8-15) - number of tracks
+ * - p1 = (bit 16-23) - platform length
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit  0- 3) - railtype (p2 & 0xF)
+ * - p2 = (bit  8-15) - custom station class
+ * - p2 = (bit 16-23) - custom station id
+ */
+int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint32 p2)
+{
+	Station *st;
+	int w_org, h_org;
+	int32 cost, ret;
+	StationID est;
+	int plat_len, numtracks;
+	Axis axis;
+	uint finalvalues[3];
+	const StationSpec *statspec;
+	int specindex;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* Does the authority allow this? */
+	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile_org)) return CMD_ERROR;
+	if (!ValParamRailtype(p2 & 0xF)) return CMD_ERROR;
+
+	/* unpack parameters */
+	axis = p1 & 1;
+	numtracks = GB(p1,  8, 8);
+	plat_len  = GB(p1, 16, 8);
+	/* w = length, h = num_tracks */
+	if (axis == AXIS_X) {
+		w_org = plat_len;
+		h_org = numtracks;
+	} else {
+		h_org = plat_len;
+		w_org = numtracks;
+	}
+
+	if (h_org > _patches.station_spread || w_org > _patches.station_spread) return CMD_ERROR;
+
+	// these values are those that will be stored in train_tile and station_platforms
+	finalvalues[0] = tile_org;
+	finalvalues[1] = w_org;
+	finalvalues[2] = h_org;
+
+	// Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station)
+	est = INVALID_STATION;
+	// If DC_EXEC is in flag, do not want to pass it to CheckFlatLandBelow, because of a nice bug
+	//  for detail info, see: https://sourceforge.net/tracker/index.php?func=detail&aid=1029064&group_id=103924&atid=636365
+	ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags & ~DC_EXEC, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
+	if (CmdFailed(ret)) return ret;
+	cost = ret + (numtracks * _price.train_station_track + _price.train_station_length) * plat_len;
+
+	// Make sure there are no similar stations around us.
+	st = GetStationAround(tile_org, w_org, h_org, est);
+	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
+
+	// See if there is a deleted station close to us.
+	if (st == NULL) {
+		st = GetClosestStationFromTile(tile_org, 8, _current_player);
+		if (st != NULL && st->facilities) st = NULL;
+	}
+
+	if (st != NULL) {
+		// Reuse an existing station.
+		if (st->owner != OWNER_NONE && st->owner != _current_player)
+			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
+
+		if (st->train_tile != 0) {
+			// check if we want to expanding an already existing station?
+			if (_is_old_ai_player || !_patches.join_stations)
+				return_cmd_error(STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD);
+			if (!CanExpandRailroadStation(st, finalvalues, axis))
+				return CMD_ERROR;
+		}
+
+		//XXX can't we pack this in the "else" part of the if above?
+		if (!StationRect_BeforeAddRect(st, tile_org, w_org, h_org, RECT_MODE_TEST)) return CMD_ERROR;
+	} else {
+		// Create a new station
+		st = AllocateStation();
+		if (st == NULL) return CMD_ERROR;
+
+		st->town = ClosestTownFromTile(tile_org, (uint)-1);
+		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
+			SETBIT(st->town->have_ratings, _current_player);
+
+		if (!GenerateStationName(st, tile_org, 0)) return CMD_ERROR;
+
+		if (flags & DC_EXEC) StationInitialize(st, tile_org);
+	}
+
+	/* Check if the given station class is valid */
+	if (GB(p2, 8, 8) >= STAT_CLASS_MAX) return CMD_ERROR;
+
+	/* Check if we can allocate a custom stationspec to this station */
+	statspec = GetCustomStationSpec(GB(p2, 8, 8), GB(p2, 16, 8));
+	specindex = AllocateSpecToStation(statspec, st, flags & DC_EXEC);
+	if (specindex == -1) return CMD_ERROR;
+
+	if (statspec != NULL) {
+		/* Perform NewStation checks */
+
+		/* Check if the station size is permitted */
+		if (HASBIT(statspec->disallowed_platforms, numtracks - 1) || HASBIT(statspec->disallowed_lengths, plat_len - 1)) {
+			return CMD_ERROR;
+		}
+
+		/* Check if the station is buildable */
+		if (HASBIT(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+			return CMD_ERROR;
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		TileIndexDiff tile_delta;
+		byte *layout_ptr;
+		byte numtracks_orig;
+		Track track;
+
+		// Now really clear the land below the station
+		// It should never return CMD_ERROR.. but you never know ;)
+		//  (a bit strange function name for it, but it really does clear the land, when DC_EXEC is in flags)
+		ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
+		if (CmdFailed(ret)) return ret;
+
+		st->train_tile = finalvalues[0];
+		if (!st->facilities) st->xy = finalvalues[0];
+		st->facilities |= FACIL_TRAIN;
+		st->owner = _current_player;
+
+		st->trainst_w = finalvalues[1];
+		st->trainst_h = finalvalues[2];
+
+		st->build_date = _date;
+
+		StationRect_BeforeAddRect(st, tile_org, w_org, h_org, RECT_MODE_TRY);
+
+		tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
+		track = AxisToTrack(axis);
+
+		layout_ptr = alloca(numtracks * plat_len);
+		GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
+
+		numtracks_orig = numtracks;
+
+		do {
+			TileIndex tile = tile_org;
+			int w = plat_len;
+			do {
+				byte layout = *layout_ptr++;
+				MakeRailStation(tile, st->owner, st->index, axis, layout, GB(p2, 0, 4));
+				SetCustomStationSpecIndex(tile, specindex);
+				SetStationTileRandomBits(tile, GB(Random(), 0, 4));
+
+				if (statspec != NULL) {
+					/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
+					uint32 platinfo = GetPlatformInfo(AXIS_X, 0, plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
+					uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, st, tile);
+					if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, callback + axis);
+				}
+
+				tile += tile_delta;
+			} while (--w);
+			SetSignalsOnBothDir(tile_org, track);
+			YapfNotifyTrackLayoutChange(tile_org, track);
+			tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
+		} while (--numtracks);
+
+		MarkStationTilesDirty(st);
+		UpdateStationVirtCoordDirty(st);
+		UpdateStationAcceptance(st, false);
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+
+	return cost;
+}
+
+static void MakeRailwayStationAreaSmaller(Station *st)
+{
+	uint w = st->trainst_w;
+	uint h = st->trainst_h;
+	TileIndex tile = st->train_tile;
+	uint i;
+
+restart:
+
+	// too small?
+	if (w != 0 && h != 0) {
+		// check the left side, x = constant, y changes
+		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(0, i));) {
+			// the left side is unused?
+			if (++i == h) {
+				tile += TileDiffXY(1, 0);
+				w--;
+				goto restart;
+			}
+		}
+
+		// check the right side, x = constant, y changes
+		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(w - 1, i));) {
+			// the right side is unused?
+			if (++i == h) {
+				w--;
+				goto restart;
+			}
+		}
+
+		// check the upper side, y = constant, x changes
+		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(i, 0));) {
+			// the left side is unused?
+			if (++i == w) {
+				tile += TileDiffXY(0, 1);
+				h--;
+				goto restart;
+			}
+		}
+
+		// check the lower side, y = constant, x changes
+		for (i = 0; !TileBelongsToRailStation(st, tile + TileDiffXY(i, h - 1));) {
+			// the left side is unused?
+			if (++i == w) {
+				h--;
+				goto restart;
+			}
+		}
+	} else {
+		tile = 0;
+	}
+
+	st->trainst_w = w;
+	st->trainst_h = h;
+	st->train_tile = tile;
+}
+
+/** Remove a single tile from a railroad station.
+ * This allows for custom-built station with holes and weird layouts
+ * @param tile tile of station piece to remove
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdRemoveFromRailroadStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Station *st;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	// make sure the specified tile belongs to the current player, and that it is a railroad station.
+	if (!IsTileType(tile, MP_STATION) || !IsRailwayStation(tile) || !_patches.nonuniform_stations) return CMD_ERROR;
+	st = GetStationByTile(tile);
+	if (_current_player != OWNER_WATER && (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile))) return CMD_ERROR;
+
+	// if we reached here, it means we can actually delete it. do that.
+	if (flags & DC_EXEC) {
+		uint specindex = GetCustomStationSpecIndex(tile);
+		Track track = GetRailStationTrack(tile);
+		DoClearSquare(tile);
+		StationRect_AfterRemoveTile(st, tile);
+		SetSignalsOnBothDir(tile, track);
+		YapfNotifyTrackLayoutChange(tile, track);
+
+		DeallocateSpecFromStation(st, specindex);
+
+		// now we need to make the "spanned" area of the railway station smaller if we deleted something at the edges.
+		// we also need to adjust train_tile.
+		MakeRailwayStationAreaSmaller(st);
+		MarkStationTilesDirty(st);
+		UpdateStationSignCoord(st);
+
+		// if we deleted the whole station, delete the train facility.
+		if (st->train_tile == 0) {
+			st->facilities &= ~FACIL_TRAIN;
+			UpdateStationVirtCoordDirty(st);
+			DeleteStationIfEmpty(st);
+		}
+	}
+	return _price.remove_rail_station;
+}
+
+// determine the number of platforms for the station
+uint GetStationPlatforms(const Station *st, TileIndex tile)
+{
+	TileIndex t;
+	TileIndexDiff delta;
+	Axis axis;
+	uint len;
+	assert(TileBelongsToRailStation(st, tile));
+
+	len = 0;
+	axis = GetRailStationAxis(tile);
+	delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
+
+	// find starting tile..
+	t = tile;
+	do {
+		t -= delta;
+		len++;
+	} while (TileBelongsToRailStation(st, t) && GetRailStationAxis(t) == axis);
+
+	// find ending tile
+	t = tile;
+	do {
+		t += delta;
+		len++;
+	} while (TileBelongsToRailStation(st, t) && GetRailStationAxis(t) == axis);
+
+	return len - 1;
+}
+
+/** Determines the REMAINING length of a platform, starting at (and including)
+ * the given tile.
+ * @param tile the tile from which to start searching. Must be a railway station tile
+ * @param dir The direction in which to search.
+ * @return The platform length
+ */
+uint GetPlatformLength(TileIndex tile, DiagDirection dir)
+{
+	TileIndex start_tile = tile;
+	uint length = 0;
+	assert(IsRailwayStationTile(tile));
+	assert(dir < DIAGDIR_END);
+
+	do {
+		length ++;
+		tile += TileOffsByDiagDir(dir);
+	} while (IsCompatibleTrainStationTile(tile, start_tile));
+
+	return length;
+}
+
+
+static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
+{
+	int w,h;
+	int32 cost = 0;
+
+	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
+	if (_current_player == OWNER_WATER && _patches.nonuniform_stations)
+		return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAILROAD_STATION);
+
+	/* Current player owns the station? */
+	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
+		return CMD_ERROR;
+
+	/* determine width and height of platforms */
+	tile = st->train_tile;
+	w = st->trainst_w;
+	h = st->trainst_h;
+
+	assert(w != 0 && h != 0);
+
+	/* clear all areas of the station */
+	do {
+		int w_bak = w;
+		do {
+			// for nonuniform stations, only remove tiles that are actually train station tiles
+			if (TileBelongsToRailStation(st, tile)) {
+				if (!EnsureNoVehicle(tile))
+					return CMD_ERROR;
+				cost += _price.remove_rail_station;
+				if (flags & DC_EXEC) {
+					Track track = GetRailStationTrack(tile);
+					DoClearSquare(tile);
+					SetSignalsOnBothDir(tile, track);
+					YapfNotifyTrackLayoutChange(tile, track);
+				}
+			}
+			tile += TileDiffXY(1, 0);
+		} while (--w);
+		w = w_bak;
+		tile += TileDiffXY(-w, 1);
+	} while (--h);
+
+	if (flags & DC_EXEC) {
+		StationRect_AfterRemoveRect(st, st->train_tile, st->trainst_w, st->trainst_h);
+
+		st->train_tile = 0;
+		st->trainst_w = st->trainst_h = 0;
+		st->facilities &= ~FACIL_TRAIN;
+
+		free(st->speclist);
+		st->num_specs = 0;
+		st->speclist  = NULL;
+
+		UpdateStationVirtCoordDirty(st);
+		DeleteStationIfEmpty(st);
+	}
+
+	return cost;
+}
+
+int32 DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
+{
+	const Station* st = GetStationByTile(tile);
+
+	if (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	// tile is not a railroad station?
+	if (!IsRailwayStation(tile)) return CMD_ERROR;
+
+	if (GetRailType(tile) == totype) return CMD_ERROR;
+
+	// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
+	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
+
+	if (exec) {
+		SetRailType(tile, totype);
+		MarkTileDirtyByTile(tile);
+		YapfNotifyTrackLayoutChange(tile, GetRailStationTrack(tile));
+	}
+
+	return _price.build_rail >> 1;
+}
+
+/** Heavy wizardry used to add a roadstop to a station.
+ * To understand the function, lets first look at what is passed around,
+ * especially the last two parameters. CmdBuildRoadStop allocates a road
+ * stop and needs to put that stop into the linked list of road stops.
+ * It (CmdBuildRoadStop) has a **currstop pointer which points to element
+ * in the linked list of stops (each element in this list being a pointer
+ * in itself, hence the double pointer). We (FindRoadStopSpot) need to
+ * modify this pointer (**currstop) thus we need to pass by reference,
+ * obtaining a triple pointer (***currstop). When finished, **currstop
+ * in CmdBuildRoadStop will contain the address of the pointer which will
+ * then point into the global roadstop array. *prev (in CmdBuildRoadStop)
+ * is the pointer tino the global roadstop array which has *currstop in
+ * its ->next element.
+ * @param[in] truck_station Determines whether a stop is RS_BUS or RS_TRUCK
+ * @param[in] station The station to do the whole procedure for
+ * @param[out] currstop See the detailed function description
+ * @param prev See the detailed function description
+ */
+static void FindRoadStopSpot(bool truck_station, Station* st, RoadStop*** currstop, RoadStop** prev)
+{
+	RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
+	assert(*prev == NULL);
+
+	if (*primary_stop == NULL) {
+		//we have no roadstop of the type yet, so write a "primary stop"
+		*currstop = primary_stop;
+	} else {
+		//there are stops already, so append to the end of the list
+		*prev = *primary_stop;
+		*currstop = &(*primary_stop)->next;
+		while (**currstop != NULL) {
+			*prev = (*prev)->next;
+			*currstop = &(**currstop)->next;
+		}
+	}
+}
+
+/** Build a bus or truck stop
+ * @param tile tile to build the stop at
+ * @param p1 entrance direction (DiagDirection)
+ * @param p2 0 for Bus stops, 1 for truck stops
+ */
+int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Station *st;
+	RoadStop *road_stop;
+	RoadStop **currstop;
+	RoadStop *prev = NULL;
+	int32 cost;
+	int32 ret;
+	bool type = !!p2;
+
+	/* Saveguard the parameters */
+	if (!IsValidDiagDirection(p1)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
+		return CMD_ERROR;
+
+	ret = CheckFlatLandBelow(tile, 1, 1, flags, 1 << p1, NULL);
+	if (CmdFailed(ret)) return ret;
+	cost = ret;
+
+	st = GetStationAround(tile, 1, 1, -1);
+	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
+
+	/* Find a station close to us */
+	if (st == NULL) {
+		st = GetClosestStationFromTile(tile, 8, _current_player);
+		if (st != NULL && st->facilities != 0) st = NULL;
+	}
+
+	//give us a road stop in the list, and check if something went wrong
+	road_stop = AllocateRoadStop();
+	if (road_stop == NULL) {
+		return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
+	}
+
+	if (st != NULL &&
+			GetNumRoadStopsInStation(st, RS_BUS) + GetNumRoadStopsInStation(st, RS_TRUCK) >= ROAD_STOP_LIMIT) {
+		return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
+	}
+
+	if (st != NULL) {
+		if (st->owner != OWNER_NONE && st->owner != _current_player) {
+			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
+		}
+
+		if (!StationRect_BeforeAddTile(st, tile, RECT_MODE_TEST)) return CMD_ERROR;
+
+		FindRoadStopSpot(type, st, &currstop, &prev);
+	} else {
+		Town *t;
+
+		st = AllocateStation();
+		if (st == NULL) return CMD_ERROR;
+
+		st->town = t = ClosestTownFromTile(tile, (uint)-1);
+
+		FindRoadStopSpot(type, st, &currstop, &prev);
+
+		if (IsValidPlayer(_current_player) && (flags & DC_EXEC)) {
+			SETBIT(t->have_ratings, _current_player);
+		}
+
+		st->sign.width_1 = 0;
+
+		if (!GenerateStationName(st, tile, 0)) return CMD_ERROR;
+
+		if (flags & DC_EXEC) StationInitialize(st, tile);
+	}
+
+	cost += (type) ? _price.build_truck_station : _price.build_bus_station;
+
+	if (flags & DC_EXEC) {
+		//point to the correct item in the _busstops or _truckstops array
+		*currstop = road_stop;
+
+		//initialize an empty station
+		InitializeRoadStop(road_stop, prev, tile, st->index);
+		if (!st->facilities) st->xy = tile;
+		st->facilities |= (type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP;
+		st->owner = _current_player;
+
+		st->build_date = _date;
+
+		StationRect_BeforeAddTile(st, tile, RECT_MODE_TRY);
+
+		MakeRoadStop(tile, st->owner, st->index, type, p1);
+
+		UpdateStationVirtCoordDirty(st);
+		UpdateStationAcceptance(st, false);
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+	return cost;
+}
+
+// Remove a bus station
+static int32 RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
+{
+	RoadStop **primary_stop;
+	RoadStop *cur_stop;
+	bool is_truck = IsTruckStop(tile);
+
+	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner)) {
+		return CMD_ERROR;
+	}
+
+	if (is_truck) { // truck stop
+		primary_stop = &st->truck_stops;
+		cur_stop = GetRoadStopByTile(tile, RS_TRUCK);
+	} else {
+		primary_stop = &st->bus_stops;
+		cur_stop = GetRoadStopByTile(tile, RS_BUS);
+	}
+
+	assert(cur_stop != NULL);
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		//we only had one stop left
+		if (cur_stop->next == NULL && cur_stop->prev == NULL) {
+			//so we remove ALL stops
+			*primary_stop = NULL;
+			st->facilities &= (is_truck) ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP;
+		} else if (cur_stop == *primary_stop) {
+			//removed the first stop in the list
+			//need to set the primary element to the next stop
+			*primary_stop = (*primary_stop)->next;
+		}
+
+		DeleteRoadStop(cur_stop);
+		DoClearSquare(tile);
+		StationRect_AfterRemoveTile(st, tile);
+
+		UpdateStationVirtCoordDirty(st);
+		DeleteStationIfEmpty(st);
+	}
+
+	return (is_truck) ? _price.remove_truck_station : _price.remove_bus_station;
+}
+
+
+
+// FIXME -- need to move to its corresponding Airport variable
+// Country Airfield (small)
+static const byte _airport_sections_country[] = {
+	54, 53, 52, 65,
+	58, 57, 56, 55,
+	64, 63, 63, 62
+};
+
+// City Airport (large)
+static const byte _airport_sections_town[] = {
+	31,  9, 33,  9,  9, 32,
+	27, 36, 29, 34,  8, 10,
+	30, 11, 35, 13, 20, 21,
+	51, 12, 14, 17, 19, 28,
+	38, 13, 15, 16, 18, 39,
+	26, 22, 23, 24, 25, 26
+};
+
+// Metropolitain Airport (large) - 2 runways
+static const byte _airport_sections_metropolitan[] = {
+	 31,  9, 33,  9,  9, 32,
+	 27, 36, 29, 34,  8, 10,
+	 30, 11, 35, 13, 20, 21,
+	102,  8,  8,  8,  8, 28,
+	 83, 84, 84, 84, 84, 83,
+	 26, 23, 23, 23, 23, 26
+};
+
+// International Airport (large) - 2 runways
+static const byte _airport_sections_international[] = {
+	88, 89, 89, 89, 89, 89,  88,
+	51,  8,  8,  8,  8,  8,  32,
+	30,  8, 11, 27, 11,  8,  10,
+	32,  8, 11, 27, 11,  8, 114,
+	87,  8, 11, 85, 11,  8, 114,
+	87,  8,  8,  8,  8,  8,  90,
+	26, 23, 23, 23, 23, 23,  26
+};
+
+// Intercontinental Airport (vlarge) - 4 runways
+static const byte _airport_sections_intercontinental[] = {
+	102, 120,  89,  89,  89,  89,  89,  89, 118,
+	120,  22,  22,  22,  22,  22,  22, 119, 117,
+	 87,  54,  87,   8,   8,   8,   8,  51, 117,
+	 87, 162,  87,  85, 116, 116,   8,   9,  10,
+	 87,   8,   8,  11,  31,  11,   8, 160,  32,
+	 32, 160,   8,  11,  27,  11,   8,   8,  10,
+	 87,   8,   8,  11,  30,  11,   8,   8,  10,
+	 87, 142,   8,  11,  29,  11,  10, 163,  10,
+	 87, 164,  87,   8,   8,   8,  10,  37, 117,
+	 87, 120,  89,  89,  89,  89,  89,  89, 119,
+	121,  22,  22,  22,  22,  22,  22, 119,  37
+};
+
+
+// Commuter Airfield (small)
+static const byte _airport_sections_commuter[] = {
+	85, 30, 115, 115, 32,
+	87, 8,    8,   8, 10,
+	87, 11,  11,  11, 10,
+	26, 23,  23,  23, 26
+};
+
+// Heliport
+static const byte _airport_sections_heliport[] = {
+	66,
+};
+
+// Helidepot
+static const byte _airport_sections_helidepot[] = {
+	124, 32,
+	122, 123
+};
+
+// Helistation
+static const byte _airport_sections_helistation[] = {
+	 32, 134, 159, 158,
+	161, 142, 142, 157
+};
+
+static const byte * const _airport_sections[] = {
+	_airport_sections_country,           // Country Airfield (small)
+	_airport_sections_town,              // City Airport (large)
+	_airport_sections_heliport,          // Heliport
+	_airport_sections_metropolitan,      // Metropolitain Airport (large)
+	_airport_sections_international,     // International Airport (xlarge)
+	_airport_sections_commuter,          // Commuter Airport (small)
+	_airport_sections_helidepot,         // Helidepot
+	_airport_sections_intercontinental,  // Intercontinental Airport (xxlarge)
+	_airport_sections_helistation        // Helistation
+};
+
+/** Place an Airport.
+ * @param tile tile where airport will be built
+ * @param p1 airport type, @see airport.h
+ * @param p2 unused
+ */
+int32 CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Town *t;
+	Station *st;
+	int32 cost;
+	int32 ret;
+	int w, h;
+	bool airport_upgrade = true;
+	const AirportFTAClass* afc;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* Check if a valid, buildable airport was chosen for construction */
+	if (p1 > lengthof(_airport_sections) || !HASBIT(GetValidAirports(), p1)) return CMD_ERROR;
+
+	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile))
+		return CMD_ERROR;
+
+	t = ClosestTownFromTile(tile, (uint)-1);
+
+	/* Check if local auth refuses a new airport */
+	{
+		uint num = 0;
+		FOR_ALL_STATIONS(st) {
+			if (st->town == t && st->facilities&FACIL_AIRPORT && st->airport_type != AT_OILRIG)
+				num++;
+		}
+		if (num >= 2) {
+			SetDParam(0, t->index);
+			return_cmd_error(STR_2035_LOCAL_AUTHORITY_REFUSES);
+		}
+	}
+
+	afc = GetAirport(p1);
+	w = afc->size_x;
+	h = afc->size_y;
+
+	ret = CheckFlatLandBelow(tile, w, h, flags, 0, NULL);
+	if (CmdFailed(ret)) return ret;
+	cost = ret;
+
+	st = GetStationAround(tile, w, h, -1);
+	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
+
+	/* Find a station close to us */
+	if (st == NULL) {
+		st = GetClosestStationFromTile(tile, 8, _current_player);
+		if (st != NULL && st->facilities) st = NULL;
+	}
+
+	if (w > _patches.station_spread || h > _patches.station_spread) {
+		_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
+		return CMD_ERROR;
+	}
+
+	if (st != NULL) {
+		if (st->owner != OWNER_NONE && st->owner != _current_player)
+			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
+
+		if (!StationRect_BeforeAddRect(st, tile, w, h, RECT_MODE_TEST)) return CMD_ERROR;
+
+		if (st->airport_tile != 0)
+			return_cmd_error(STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT);
+	} else {
+		airport_upgrade = false;
+
+		st = AllocateStation();
+		if (st == NULL) return CMD_ERROR;
+
+		st->town = t;
+
+		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
+			SETBIT(t->have_ratings, _current_player);
+
+		st->sign.width_1 = 0;
+
+		// if airport type equals Heliport then generate
+		// type 5 name, which is heliport, otherwise airport names (1)
+		if (!GenerateStationName(st, tile, (p1 == AT_HELIPORT)||(p1 == AT_HELIDEPOT)||(p1 == AT_HELISTATION) ? 5 : 1))
+			return CMD_ERROR;
+
+		if (flags & DC_EXEC) StationInitialize(st, tile);
+	}
+
+	cost += _price.build_airport * w * h;
+
+	if (flags & DC_EXEC) {
+		st->owner = _current_player;
+		st->airport_tile = tile;
+		if (!st->facilities) st->xy = tile;
+		st->facilities |= FACIL_AIRPORT;
+		st->airport_type = (byte)p1;
+		st->airport_flags = 0;
+
+		st->build_date = _date;
+
+		StationRect_BeforeAddRect(st, tile, w, h, RECT_MODE_TRY);
+
+		/* if airport was demolished while planes were en-route to it, the
+		 * positions can no longer be the same (v->u.air.pos), since different
+		 * airports have different indexes. So update all planes en-route to this
+		 * airport. Only update if
+		 * 1. airport is upgraded
+		 * 2. airport is added to existing station (unfortunately unavoideable)
+		 */
+		if (airport_upgrade) UpdateAirplanesOnNewStation(st);
+
+		{
+			const byte *b = _airport_sections[p1];
+
+			BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
+				MakeAirport(tile_cur, st->owner, st->index, *b++);
+			} END_TILE_LOOP(tile_cur, w, h, tile)
+		}
+
+		UpdateStationVirtCoordDirty(st);
+		UpdateStationAcceptance(st, false);
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+
+	return cost;
+}
+
+static int32 RemoveAirport(Station *st, uint32 flags)
+{
+	TileIndex tile;
+	int w,h;
+	int32 cost;
+	const AirportFTAClass* afc;
+
+	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
+		return CMD_ERROR;
+
+	tile = st->airport_tile;
+
+	afc = GetAirport(st->airport_type);
+	w = afc->size_x;
+	h = afc->size_y;
+
+	cost = w * h * _price.remove_airport;
+
+	BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
+		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
+
+		if (flags & DC_EXEC) {
+			DeleteAnimatedTile(tile_cur);
+			DoClearSquare(tile_cur);
+		}
+	} END_TILE_LOOP(tile_cur, w,h,tile)
+
+	if (flags & DC_EXEC) {
+		uint i;
+
+		for (i = 0; i < afc->nof_depots; ++i) {
+			DeleteWindowById(
+				WC_VEHICLE_DEPOT, tile + ToTileIndexDiff(afc->airport_depots[i])
+			);
+		}
+
+		StationRect_AfterRemoveRect(st, tile, w, h);
+
+		st->airport_tile = 0;
+		st->facilities &= ~FACIL_AIRPORT;
+
+		UpdateStationVirtCoordDirty(st);
+		DeleteStationIfEmpty(st);
+	}
+
+	return cost;
+}
+
+/** Build a buoy.
+ * @param tile tile where to place the bouy
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdBuildBuoy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Station *st;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!IsClearWaterTile(tile) || tile == 0) return_cmd_error(STR_304B_SITE_UNSUITABLE);
+
+	st = AllocateStation();
+	if (st == NULL) return CMD_ERROR;
+
+	st->town = ClosestTownFromTile(tile, (uint)-1);
+	st->sign.width_1 = 0;
+
+	if (!GenerateStationName(st, tile, 4)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		StationInitialize(st, tile);
+		st->dock_tile = tile;
+		st->facilities |= FACIL_DOCK;
+		/* Buoys are marked in the Station struct by this flag. Yes, it is this
+		 * braindead.. */
+		st->had_vehicle_of_type |= HVOT_BUOY;
+		st->owner = OWNER_NONE;
+
+		st->build_date = _date;
+
+		MakeBuoy(tile, st->index);
+
+		UpdateStationVirtCoordDirty(st);
+		UpdateStationAcceptance(st, false);
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+
+	return _price.build_dock;
+}
+
+/* Checks if any ship is servicing the buoy specified. Returns yes or no */
+static bool CheckShipsOnBuoy(Station *st)
+{
+	const Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Ship) {
+			const Order *order;
+			FOR_VEHICLE_ORDERS(v, order) {
+				if (order->type == OT_GOTO_STATION && order->dest == st->index) {
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+static int32 RemoveBuoy(Station *st, uint32 flags)
+{
+	TileIndex tile;
+
+	/* XXX: strange stuff */
+	if (!IsValidPlayer(_current_player))  return_cmd_error(INVALID_STRING_ID);
+
+	tile = st->dock_tile;
+
+	if (CheckShipsOnBuoy(st))   return_cmd_error(STR_BUOY_IS_IN_USE);
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		st->dock_tile = 0;
+		/* Buoys are marked in the Station struct by this flag. Yes, it is this
+		 * braindead.. */
+		st->facilities &= ~FACIL_DOCK;
+		st->had_vehicle_of_type &= ~HVOT_BUOY;
+
+		MakeWater(tile);
+		MarkTileDirtyByTile(tile);
+
+		UpdateStationVirtCoordDirty(st);
+		DeleteStationIfEmpty(st);
+	}
+
+	return _price.remove_truck_station;
+}
+
+static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
+	{-1,  0},
+	{ 0,  0},
+	{ 0,  0},
+	{ 0, -1}
+};
+static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
+static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
+
+/** Build a dock/haven.
+ * @param tile tile where dock will be built
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdBuildDock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TileIndex tile_cur;
+	DiagDirection direction;
+	int32 cost;
+	Station *st;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	switch (GetTileSlope(tile, NULL)) {
+		case SLOPE_SW: direction = DIAGDIR_NE; break;
+		case SLOPE_SE: direction = DIAGDIR_NW; break;
+		case SLOPE_NW: direction = DIAGDIR_SE; break;
+		case SLOPE_NE: direction = DIAGDIR_SW; break;
+		default: return_cmd_error(STR_304B_SITE_UNSUITABLE);
+	}
+
+	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(cost)) return CMD_ERROR;
+
+	tile_cur = tile + TileOffsByDiagDir(direction);
+
+	if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
+
+	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
+		return_cmd_error(STR_304B_SITE_UNSUITABLE);
+	}
+
+	cost = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(cost)) return CMD_ERROR;
+
+	tile_cur += TileOffsByDiagDir(direction);
+	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
+		return_cmd_error(STR_304B_SITE_UNSUITABLE);
+	}
+
+	/* middle */
+	st = GetStationAround(
+		tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
+		_dock_w_chk[direction], _dock_h_chk[direction], -1);
+	if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
+
+	/* Find a station close to us */
+	if (st == NULL) {
+		st = GetClosestStationFromTile(tile, 8, _current_player);
+		if (st!=NULL && st->facilities) st = NULL;
+	}
+
+	if (st != NULL) {
+		if (st->owner != OWNER_NONE && st->owner != _current_player)
+			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
+
+		if (!StationRect_BeforeAddRect(st, tile, _dock_w_chk[direction], _dock_h_chk[direction], RECT_MODE_TEST)) return CMD_ERROR;
+
+		if (st->dock_tile != 0) return_cmd_error(STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK);
+	} else {
+		Town *t;
+
+		st = AllocateStation();
+		if (st == NULL) return CMD_ERROR;
+
+		st->town = t = ClosestTownFromTile(tile, (uint)-1);
+
+		if (IsValidPlayer(_current_player) && (flags & DC_EXEC))
+			SETBIT(t->have_ratings, _current_player);
+
+		st->sign.width_1 = 0;
+
+		if (!GenerateStationName(st, tile, 3)) return CMD_ERROR;
+
+		if (flags & DC_EXEC) StationInitialize(st, tile);
+	}
+
+	if (flags & DC_EXEC) {
+		st->dock_tile = tile;
+		if (!st->facilities) st->xy = tile;
+		st->facilities |= FACIL_DOCK;
+		st->owner = _current_player;
+
+		st->build_date = _date;
+
+		StationRect_BeforeAddRect(st, tile, _dock_w_chk[direction], _dock_h_chk[direction], RECT_MODE_TRY);
+
+		MakeDock(tile, st->owner, st->index, direction);
+
+		UpdateStationVirtCoordDirty(st);
+		UpdateStationAcceptance(st, false);
+		RebuildStationLists();
+		InvalidateWindow(WC_STATION_LIST, st->owner);
+	}
+	return _price.build_dock;
+}
+
+static int32 RemoveDock(Station *st, uint32 flags)
+{
+	TileIndex tile1;
+	TileIndex tile2;
+
+	if (!CheckOwnership(st->owner)) return CMD_ERROR;
+
+	tile1 = st->dock_tile;
+	tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
+
+	if (!EnsureNoVehicle(tile1)) return CMD_ERROR;
+	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		DoClearSquare(tile1);
+		MakeWater(tile2);
+
+		StationRect_AfterRemoveTile(st, tile1);
+		StationRect_AfterRemoveTile(st, tile2);
+
+		MarkTileDirtyByTile(tile2);
+
+		st->dock_tile = 0;
+		st->facilities &= ~FACIL_DOCK;
+
+		UpdateStationVirtCoordDirty(st);
+		DeleteStationIfEmpty(st);
+	}
+
+	return _price.remove_dock;
+}
+
+#include "table/station_land.h"
+
+const DrawTileSprites *GetStationTileLayout(byte gfx)
+{
+	return &_station_display_datas[gfx];
+}
+
+static void DrawTile_Station(TileInfo *ti)
+{
+	uint32 image;
+	const DrawTileSeqStruct *dtss;
+	const DrawTileSprites *t = NULL;
+	RailType railtype = GetRailType(ti->tile);
+	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
+	uint32 relocation = 0;
+	const Station *st = NULL;
+	const StationSpec *statspec = NULL;
+	PlayerID owner = GetTileOwner(ti->tile);
+	uint32 palette;
+
+	if (IsValidPlayer(owner)) {
+		palette = PLAYER_SPRITE_COLOR(owner);
+	} else {
+		// Some stations are not owner by a player, namely oil rigs
+		palette = PALETTE_TO_GREY;
+	}
+
+	// don't show foundation for docks
+	if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile))
+		DrawFoundation(ti, ti->tileh);
+
+	if (IsCustomStationSpecIndex(ti->tile)) {
+		// look for customization
+		st = GetStationByTile(ti->tile);
+		statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
+
+		//debug("Cust-o-mized %p", statspec);
+
+		if (statspec != NULL) {
+			uint tile = GetStationGfx(ti->tile);
+
+			relocation = GetCustomStationRelocation(statspec, st, ti->tile);
+
+			if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
+				uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
+				if (callback != CALLBACK_FAILED) tile = (callback & ~1) + GetRailStationAxis(ti->tile);
+			}
+
+			/* Ensure the chosen tile layout is valid for this custom station */
+			if (statspec->renderdata != NULL) {
+				t = &statspec->renderdata[tile < statspec->tiles ? tile : GetRailStationAxis(ti->tile)];
+			}
+		}
+	}
+
+	if (t == NULL || t->seq == NULL) t = &_station_display_datas[GetStationGfx(ti->tile)];
+
+	image = t->ground_sprite;
+	if (HASBIT(image, 31)) {
+		CLRBIT(image, 31);
+		image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
+		image += rti->custom_ground_offset;
+	} else {
+		image += rti->total_offset;
+	}
+	if (image & PALETTE_MODIFIER_COLOR) image |= palette;
+
+	// station_land array has been increased from 82 elements to 114
+	// but this is something else. If AI builds station with 114 it looks all weird
+	DrawGroundSprite(image);
+
+	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti);
+
+	foreach_draw_tile_seq(dtss, t->seq) {
+		image = dtss->image;
+		if (HASBIT(image, 30)) {
+			CLRBIT(image, 30);
+			image += rti->total_offset;
+		} else {
+			image += relocation;
+		}
+
+		if (_display_opt & DO_TRANS_BUILDINGS) {
+			MAKE_TRANSPARENT(image);
+		} else if (image & PALETTE_MODIFIER_COLOR) {
+			image |= palette;
+		}
+
+		if ((byte)dtss->delta_z != 0x80) {
+			AddSortableSpriteToDraw(
+				image,
+				ti->x + dtss->delta_x, ti->y + dtss->delta_y,
+				dtss->size_x, dtss->size_y,
+				dtss->size_z, ti->z + dtss->delta_z
+			);
+		} else {
+			AddChildSpriteScreen(image, dtss->delta_x, dtss->delta_y);
+		}
+	}
+}
+
+void StationPickerDrawSprite(int x, int y, RailType railtype, int image)
+{
+	uint32 ormod, img;
+	const DrawTileSeqStruct *dtss;
+	const DrawTileSprites *t;
+	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
+
+	ormod = PLAYER_SPRITE_COLOR(_local_player);
+
+	t = &_station_display_datas[image];
+
+	img = t->ground_sprite;
+	if (img & PALETTE_MODIFIER_COLOR) img |= ormod;
+	DrawSprite(img + rti->total_offset, x, y);
+
+	foreach_draw_tile_seq(dtss, t->seq) {
+		Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
+		DrawSprite((dtss->image | ormod) + rti->total_offset, x + pt.x, y + pt.y);
+	}
+}
+
+static uint GetSlopeZ_Station(TileIndex tile, uint x, uint y)
+{
+	return GetTileMaxZ(tile);
+}
+
+static Slope GetSlopeTileh_Station(TileIndex tile, Slope tileh)
+{
+	return SLOPE_FLAT;
+}
+
+static void GetAcceptedCargo_Station(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
+{
+	StringID str;
+
+	td->owner = GetTileOwner(tile);
+	td->build_date = GetStationByTile(tile)->build_date;
+
+	switch (GetStationType(tile)) {
+		default: NOT_REACHED();
+		case STATION_RAIL:    str = STR_305E_RAILROAD_STATION; break;
+		case STATION_AIRPORT:
+			str = (IsHangar(tile) ? STR_305F_AIRCRAFT_HANGAR : STR_3060_AIRPORT);
+			break;
+		case STATION_TRUCK:   str = STR_3061_TRUCK_LOADING_AREA; break;
+		case STATION_BUS:     str = STR_3062_BUS_STATION; break;
+		case STATION_OILRIG:  str = STR_4807_OIL_RIG; break;
+		case STATION_DOCK:    str = STR_3063_SHIP_DOCK; break;
+		case STATION_BUOY:    str = STR_3069_BUOY; break;
+	}
+	td->str = str;
+}
+
+
+static uint32 GetTileTrackStatus_Station(TileIndex tile, TransportType mode)
+{
+	switch (mode) {
+		case TRANSPORT_RAIL:
+			if (IsRailwayStation(tile) && !IsStationTileBlocked(tile)) {
+				return TrackToTrackBits(GetRailStationTrack(tile)) * 0x101;
+			}
+			break;
+
+		case TRANSPORT_WATER:
+			// buoy is coded as a station, it is always on open water
+			if (IsBuoy_(tile)) return TRACK_BIT_ALL * 0x101;
+			break;
+
+		case TRANSPORT_ROAD:
+			if (IsRoadStopTile(tile)) {
+				return AxisToTrackBits(DiagDirToAxis(GetRoadStopDir(tile))) * 0x101;
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	return 0;
+}
+
+
+static void TileLoop_Station(TileIndex tile)
+{
+	// FIXME -- GetTileTrackStatus_Station -> animated stationtiles
+	// hardcoded.....not good
+	switch (GetStationGfx(tile)) {
+		case GFX_RADAR_LARGE_FIRST:
+		case GFX_WINDSACK_FIRST : // for small airport
+		case GFX_RADAR_INTERNATIONAL_FIRST:
+		case GFX_RADAR_METROPOLITAN_FIRST:
+		case GFX_RADAR_DISTRICTWE_FIRST: // radar district W-E airport
+		case GFX_WINDSACK_INTERCON_FIRST : // for intercontinental airport
+			AddAnimatedTile(tile);
+			break;
+
+		case GFX_OILRIG_BASE: //(station part)
+		case GFX_BUOY_BASE:
+			TileLoop_Water(tile);
+			break;
+
+		default: break;
+	}
+}
+
+
+static void AnimateTile_Station(TileIndex tile)
+{
+	typedef struct AnimData {
+		StationGfx from; // first sprite
+		StationGfx to;   // last sprite
+		byte delay;
+	} AnimData;
+
+	static const AnimData data[] = {
+		{ GFX_RADAR_LARGE_FIRST,         GFX_RADAR_LARGE_LAST,         3 },
+		{ GFX_WINDSACK_FIRST,            GFX_WINDSACK_LAST,            1 },
+		{ GFX_RADAR_INTERNATIONAL_FIRST, GFX_RADAR_INTERNATIONAL_LAST, 3 },
+		{ GFX_RADAR_METROPOLITAN_FIRST,  GFX_RADAR_METROPOLITAN_LAST,  3 },
+		{ GFX_RADAR_DISTRICTWE_FIRST,    GFX_RADAR_DISTRICTWE_LAST,    3 },
+		{ GFX_WINDSACK_INTERCON_FIRST,   GFX_WINDSACK_INTERCON_LAST,   1 }
+	};
+
+	StationGfx gfx = GetStationGfx(tile);
+	const AnimData* i;
+
+	for (i = data; i != endof(data); i++) {
+		if (i->from <= gfx && gfx <= i->to) {
+			if ((_tick_counter & i->delay) == 0) {
+				SetStationGfx(tile, gfx < i->to ? gfx + 1 : i->from);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+		}
+	}
+}
+
+
+static void ClickTile_Station(TileIndex tile)
+{
+	if (IsHangar(tile)) {
+		ShowDepotWindow(tile, VEH_Aircraft);
+	} else {
+		ShowStationViewWindow(GetStationIndex(tile));
+	}
+}
+
+static const byte _enter_station_speedtable[12] = {
+	215, 195, 175, 155, 135, 115, 95, 75, 55, 35, 15, 0
+};
+
+static uint32 VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
+{
+	if (v->type == VEH_Train) {
+		if (IsRailwayStation(tile) && IsFrontEngine(v) &&
+				!IsCompatibleTrainStationTile(tile + TileOffsByDiagDir(DirToDiagDir(v->direction)), tile)) {
+			StationID station_id = GetStationIndex(tile);
+
+			if ((!(v->current_order.flags & OF_NON_STOP) && !_patches.new_nonstop) ||
+					(v->current_order.type == OT_GOTO_STATION && v->current_order.dest == station_id)) {
+				if (!(_patches.new_nonstop && v->current_order.flags & OF_NON_STOP) &&
+						v->current_order.type != OT_LEAVESTATION &&
+						v->last_station_visited != station_id) {
+					DiagDirection dir = DirToDiagDir(v->direction);
+
+					x &= 0xF;
+					y &= 0xF;
+
+					if (DiagDirToAxis(dir) != AXIS_X) intswap(x, y);
+					if (y == TILE_SIZE / 2) {
+						if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
+						if (x == 12) return 2 | (station_id << 8); /* enter station */
+						if (x < 12) {
+							uint16 spd;
+
+							v->vehstatus |= VS_TRAIN_SLOWING;
+							spd = _enter_station_speedtable[x];
+							if (spd < v->cur_speed) v->cur_speed = spd;
+						}
+					}
+				}
+			}
+		}
+	} else if (v->type == VEH_Road) {
+		if (v->u.road.state < 16 && !HASBIT(v->u.road.state, 2) && v->u.road.frame == 0) {
+			if (IsRoadStop(tile)) {
+				/* Attempt to allocate a parking bay in a road stop */
+				RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile));
+
+				/* rs->status bits 0 and 1 describe current the two parking spots.
+				 * 0 means occupied, 1 means free. */
+
+				// Check if station is busy or if there are no free bays.
+				if (HASBIT(rs->status, 7) || GB(rs->status, 0, 2) == 0)
+					return 8;
+
+				v->u.road.state += 32;
+
+				// if the first bay is free, allocate that, else the second bay must be free.
+				if (HASBIT(rs->status, 0)) {
+					CLRBIT(rs->status, 0);
+				} else {
+					CLRBIT(rs->status, 1);
+					v->u.road.state += 2;
+				}
+
+				// mark the station as busy
+				SETBIT(rs->status, 7);
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Cleanup a RoadStop. Make sure no vehicles try to go to this roadstop.
+ */
+void DestroyRoadStop(RoadStop* rs)
+{
+	Vehicle *v;
+
+	/* Clear the slot assignment of all vehicles heading for this road stop */
+	if (rs->num_vehicles != 0) {
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Road && v->u.road.slot == rs) {
+				ClearSlot(v);
+			}
+		}
+	}
+	assert(rs->num_vehicles == 0);
+
+	if (rs->prev != NULL) rs->prev->next = rs->next;
+	if (rs->next != NULL) rs->next->prev = rs->prev;
+}
+
+/**
+ * Clean up a station by clearing vehicle orders and invalidating windows.
+ * Aircraft-Hangar orders need special treatment here, as the hangars are
+ * actually part of a station (tiletype is STATION), but the order type
+ * is OT_GOTO_DEPOT.
+ * @param st Station to be deleted
+ */
+void DestroyStation(Station *st)
+{
+	StationID index;
+
+	index = st->index;
+
+	DeleteName(st->string_id);
+	MarkStationDirty(st);
+	RebuildStationLists();
+	InvalidateWindowClasses(WC_STATION_LIST);
+
+	DeleteWindowById(WC_STATION_VIEW, index);
+
+	/* Now delete all orders that go to the station */
+	RemoveOrderFromAllVehicles(OT_GOTO_STATION, index);
+
+	//Subsidies need removal as well
+	DeleteSubsidyWithStation(index);
+
+	free(st->speclist);
+}
+
+void DeleteAllPlayerStations(void)
+{
+	Station *st;
+
+	FOR_ALL_STATIONS(st) {
+		if (IsValidPlayer(st->owner)) DeleteStation(st);
+	}
+}
+
+/* this function is called for one station each tick */
+static void StationHandleBigTick(Station *st)
+{
+	UpdateStationAcceptance(st, true);
+
+	if (st->facilities == 0 && ++st->delete_ctr >= 8) DeleteStation(st);
+
+}
+
+static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; }
+
+static void UpdateStationRating(Station *st)
+{
+	GoodsEntry *ge;
+	int rating;
+	StationID index;
+	int waiting;
+	bool waiting_changed = false;
+
+	byte_inc_sat(&st->time_since_load);
+	byte_inc_sat(&st->time_since_unload);
+
+	ge = st->goods;
+	do {
+		if (ge->enroute_from != INVALID_STATION) {
+			byte_inc_sat(&ge->enroute_time);
+			byte_inc_sat(&ge->days_since_pickup);
+
+			rating = 0;
+
+			{
+				int b = ge->last_speed;
+				if ((b-=85) >= 0)
+					rating += b >> 2;
+			}
+
+			{
+				byte age = ge->last_age;
+				(age >= 3) ||
+				(rating += 10, age >= 2) ||
+				(rating += 10, age >= 1) ||
+				(rating += 13, true);
+			}
+
+			if (IsValidPlayer(st->owner) && HASBIT(st->town->statues, st->owner)) rating += 26;
+
+			{
+				byte days = ge->days_since_pickup;
+				if (st->last_vehicle_type == VEH_Ship)
+							days >>= 2;
+				(days > 21) ||
+				(rating += 25, days > 12) ||
+				(rating += 25, days > 6) ||
+				(rating += 45, days > 3) ||
+				(rating += 35, true);
+			}
+
+			{
+				waiting = GB(ge->waiting_acceptance, 0, 12);
+				(rating -= 90, waiting > 1500) ||
+				(rating += 55, waiting > 1000) ||
+				(rating += 35, waiting > 600) ||
+				(rating += 10, waiting > 300) ||
+				(rating += 20, waiting > 100) ||
+				(rating += 10, true);
+			}
+
+			{
+				int or = ge->rating; // old rating
+
+				// only modify rating in steps of -2, -1, 0, 1 or 2
+				ge->rating = rating = or + clamp(clamp(rating, 0, 255) - or, -2, 2);
+
+				// if rating is <= 64 and more than 200 items waiting, remove some random amount of goods from the station
+				if (rating <= 64 && waiting >= 200) {
+					int dec = Random() & 0x1F;
+					if (waiting < 400) dec &= 7;
+					waiting -= dec + 1;
+					waiting_changed = true;
+				}
+
+				// if rating is <= 127 and there are any items waiting, maybe remove some goods.
+				if (rating <= 127 && waiting != 0) {
+					uint32 r = Random();
+					if ( (uint)rating <= (r & 0x7F) ) {
+						waiting = max(waiting - ((r >> 8)&3) - 1, 0);
+						waiting_changed = true;
+					}
+				}
+
+				if (waiting_changed) SB(ge->waiting_acceptance, 0, 12, waiting);
+			}
+		}
+	} while (++ge != endof(st->goods));
+
+	index = st->index;
+
+	if (waiting_changed) {
+		InvalidateWindow(WC_STATION_VIEW, index);
+	} else {
+		InvalidateWindowWidget(WC_STATION_VIEW, index, 5);
+	}
+}
+
+/* called for every station each tick */
+static void StationHandleSmallTick(Station *st)
+{
+	byte b;
+
+	if (st->facilities == 0) return;
+
+	b = st->delete_ctr + 1;
+	if (b >= 185) b = 0;
+	st->delete_ctr = b;
+
+	if (b == 0) UpdateStationRating(st);
+}
+
+void OnTick_Station(void)
+{
+	uint i;
+	Station *st;
+
+	if (_game_mode == GM_EDITOR) return;
+
+	i = _station_tick_ctr;
+	if (++_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
+
+	if (IsValidStationID(i)) StationHandleBigTick(GetStation(i));
+
+	FOR_ALL_STATIONS(st) {
+		StationHandleSmallTick(st);
+	}
+}
+
+void StationMonthlyLoop(void)
+{
+}
+
+
+void ModifyStationRatingAround(TileIndex tile, PlayerID owner, int amount, uint radius)
+{
+	Station *st;
+
+	FOR_ALL_STATIONS(st) {
+		if (st->owner == owner &&
+				DistanceManhattan(tile, st->xy) <= radius) {
+			uint i;
+
+			for (i = 0; i != NUM_CARGO; i++) {
+				GoodsEntry* ge = &st->goods[i];
+
+				if (ge->enroute_from != INVALID_STATION) {
+					ge->rating = clamp(ge->rating + amount, 0, 255);
+				}
+			}
+		}
+	}
+}
+
+static void UpdateStationWaiting(Station *st, int type, uint amount)
+{
+	SB(st->goods[type].waiting_acceptance, 0, 12,
+		min(0xFFF, GB(st->goods[type].waiting_acceptance, 0, 12) + amount)
+	);
+
+	st->goods[type].enroute_time = 0;
+	st->goods[type].enroute_from = st->index;
+	InvalidateWindow(WC_STATION_VIEW, st->index);
+	MarkStationTilesDirty(st);
+}
+
+/** Rename a station
+ * @param tile unused
+ * @param p1 station ID that is to be renamed
+ * @param p2 unused
+ */
+int32 CmdRenameStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID str;
+	Station *st;
+
+	if (!IsValidStationID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+	st = GetStation(p1);
+
+	if (!CheckOwnership(st->owner)) return CMD_ERROR;
+
+	str = AllocateNameUnique(_cmd_text, 6);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		StringID old_str = st->string_id;
+
+		st->string_id = str;
+		UpdateStationVirtCoord(st);
+		DeleteName(old_str);
+		ResortStationLists();
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+
+	return 0;
+}
+
+
+uint MoveGoodsToStation(TileIndex tile, int w, int h, int type, uint amount)
+{
+	Station* around[8];
+	uint i;
+	uint moved;
+	uint best_rating, best_rating2;
+	Station *st1, *st2;
+	uint t;
+	int rad = 0;
+	int w_prod; //width and height of the "producer" of the cargo
+	int h_prod;
+	int max_rad;
+
+	for (i = 0; i < lengthof(around); i++) around[i] = NULL;
+
+	if (_patches.modified_catchment) {
+		w_prod = w;
+		h_prod = h;
+		w += 16;
+		h += 16;
+		max_rad = 8;
+	} else {
+		w_prod = 0;
+		h_prod = 0;
+		w += 8;
+		h += 8;
+		max_rad = 4;
+	}
+
+	BEGIN_TILE_LOOP(cur_tile, w, h, tile - TileDiffXY(max_rad, max_rad))
+		Station* st;
+
+		cur_tile = TILE_MASK(cur_tile);
+		if (!IsTileType(cur_tile, MP_STATION)) continue;
+
+		st = GetStationByTile(cur_tile);
+
+		for (i = 0; i != lengthof(around); i++) {
+			if (around[i] == NULL) {
+				if (!IsBuoy(st) &&
+						(st->town->exclusive_counter == 0 || st->town->exclusivity == st->owner) && // check exclusive transport rights
+						st->goods[type].rating != 0 &&
+						(!_patches.selectgoods || st->goods[type].last_speed > 0) && // if last_speed is 0, no vehicle has been there.
+						((st->facilities & ~FACIL_BUS_STOP)   != 0 || type == CT_PASSENGERS) && // if we have other fac. than a bus stop, or the cargo is passengers
+						((st->facilities & ~FACIL_TRUCK_STOP) != 0 || type != CT_PASSENGERS)) { // if we have other fac. than a cargo bay or the cargo is not passengers
+					int x_dist;
+					int y_dist;
+
+					if (_patches.modified_catchment) {
+						// min and max coordinates of the producer relative
+						const int x_min_prod = 9;
+						const int x_max_prod = 8 + w_prod;
+						const int y_min_prod = 9;
+						const int y_max_prod = 8 + h_prod;
+
+						rad = FindCatchmentRadius(st);
+
+						x_dist = min(w_cur - x_min_prod, x_max_prod - w_cur);
+						if (w_cur < x_min_prod) {
+							x_dist = x_min_prod - w_cur;
+						} else if (w_cur > x_max_prod) {
+							x_dist = w_cur - x_max_prod;
+						}
+
+						y_dist = min(h_cur - y_min_prod, y_max_prod - h_cur);
+						if (h_cur < y_min_prod) {
+							y_dist = y_min_prod - h_cur;
+						} else if (h_cur > y_max_prod) {
+							y_dist = h_cur - y_max_prod;
+						}
+					} else {
+						x_dist = 0;
+						y_dist = 0;
+					}
+
+					if (x_dist <= rad && y_dist <= rad) around[i] = st;
+				}
+				break;
+			} else if (around[i] == st) {
+				break;
+			}
+		}
+	END_TILE_LOOP(cur_tile, w, h, tile - TileDiffXY(max_rad, max_rad))
+
+	/* no stations around at all? */
+	if (around[0] == NULL) return 0;
+
+	if (around[1] == NULL) {
+		/* only one station around */
+		moved = (amount * around[0]->goods[type].rating >> 8) + 1;
+		UpdateStationWaiting(around[0], type, moved);
+		return moved;
+	}
+
+	/* several stations around, find the two with the highest rating */
+	st2 = st1 = NULL;
+	best_rating = best_rating2 = 0;
+
+	for (i = 0; i != lengthof(around) && around[i] != NULL; i++) {
+		if (around[i]->goods[type].rating >= best_rating) {
+			best_rating2 = best_rating;
+			st2 = st1;
+
+			best_rating = around[i]->goods[type].rating;
+			st1 = around[i];
+		} else if (around[i]->goods[type].rating >= best_rating2) {
+			best_rating2 = around[i]->goods[type].rating;
+			st2 = around[i];
+		}
+	}
+
+	assert(st1 != NULL);
+	assert(st2 != NULL);
+	assert(best_rating != 0 || best_rating2 != 0);
+
+	/* the 2nd highest one gets a penalty */
+	best_rating2 >>= 1;
+
+	/* amount given to station 1 */
+	t = (best_rating * (amount + 1)) / (best_rating + best_rating2);
+
+	moved = 0;
+	if (t != 0) {
+		moved = t * best_rating / 256 + 1;
+		amount -= t;
+		UpdateStationWaiting(st1, type, moved);
+	}
+
+	if (amount != 0) {
+		amount = amount * best_rating2 / 256 + 1;
+		moved += amount;
+		UpdateStationWaiting(st2, type, amount);
+	}
+
+	return moved;
+}
+
+void BuildOilRig(TileIndex tile)
+{
+	uint j;
+	Station *st = AllocateStation();
+
+	if (st == NULL) {
+		DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
+		return;
+	}
+	if (!GenerateStationName(st, tile, 2)) {
+		DEBUG(misc, 0, "Can't allocate station-name for oilrig at 0x%X, reverting to oilrig only", tile);
+		return;
+	}
+
+	st->town = ClosestTownFromTile(tile, (uint)-1);
+	st->sign.width_1 = 0;
+
+	MakeOilrig(tile, st->index);
+
+	st->owner = OWNER_NONE;
+	st->airport_flags = 0;
+	st->airport_type = AT_OILRIG;
+	st->xy = tile;
+	st->bus_stops = NULL;
+	st->truck_stops = NULL;
+	st->airport_tile = tile;
+	st->dock_tile = tile;
+	st->train_tile = 0;
+	st->had_vehicle_of_type = 0;
+	st->time_since_load = 255;
+	st->time_since_unload = 255;
+	st->delete_ctr = 0;
+	st->last_vehicle_type = VEH_Invalid;
+	st->facilities = FACIL_AIRPORT | FACIL_DOCK;
+	st->build_date = _date;
+
+	for (j = 0; j != NUM_CARGO; j++) {
+		st->goods[j].waiting_acceptance = 0;
+		st->goods[j].days_since_pickup = 0;
+		st->goods[j].enroute_from = INVALID_STATION;
+		st->goods[j].rating = 175;
+		st->goods[j].last_speed = 0;
+		st->goods[j].last_age = 255;
+	}
+
+	UpdateStationVirtCoordDirty(st);
+	UpdateStationAcceptance(st, false);
+}
+
+void DeleteOilRig(TileIndex tile)
+{
+	Station* st = GetStationByTile(tile);
+
+	DoClearSquare(tile);
+
+	st->dock_tile = 0;
+	st->airport_tile = 0;
+	st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
+	st->airport_flags = 0;
+	UpdateStationVirtCoordDirty(st);
+	DeleteStation(st);
+}
+
+static void ChangeTileOwner_Station(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (new_player != PLAYER_SPECTATOR) {
+		Station* st = GetStationByTile(tile);
+
+		SetTileOwner(tile, new_player);
+		st->owner = new_player;
+		RebuildStationLists();
+		InvalidateWindowClasses(WC_STATION_LIST);
+	} else {
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	}
+}
+
+static int32 ClearTile_Station(TileIndex tile, byte flags)
+{
+	Station *st;
+
+	if (flags & DC_AUTO) {
+		switch (GetStationType(tile)) {
+			case STATION_RAIL:    return_cmd_error(STR_300B_MUST_DEMOLISH_RAILROAD);
+			case STATION_AIRPORT: return_cmd_error(STR_300E_MUST_DEMOLISH_AIRPORT_FIRST);
+			case STATION_TRUCK:   return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION);
+			case STATION_BUS:     return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION);
+			case STATION_BUOY:    return_cmd_error(STR_306A_BUOY_IN_THE_WAY);
+			case STATION_DOCK:    return_cmd_error(STR_304D_MUST_DEMOLISH_DOCK_FIRST);
+			case STATION_OILRIG:
+				SetDParam(0, STR_4807_OIL_RIG);
+				return_cmd_error(STR_4800_IN_THE_WAY);
+		}
+	}
+
+	st = GetStationByTile(tile);
+
+	switch (GetStationType(tile)) {
+		case STATION_RAIL:    return RemoveRailroadStation(st, tile, flags);
+		case STATION_AIRPORT: return RemoveAirport(st, flags);
+		case STATION_TRUCK:
+		case STATION_BUS:     return RemoveRoadStop(st, flags, tile);
+		case STATION_BUOY:    return RemoveBuoy(st, flags);
+		case STATION_DOCK:    return RemoveDock(st, flags);
+		default: break;
+	}
+
+	return CMD_ERROR;
+}
+
+void InitializeStations(void)
+{
+	/* Clean the station pool and create 1 block in it */
+	CleanPool(&_Station_pool);
+	AddBlockToPool(&_Station_pool);
+
+	/* Clean the roadstop pool and create 1 block in it */
+	CleanPool(&_RoadStop_pool);
+	AddBlockToPool(&_RoadStop_pool);
+
+	_station_tick_ctr = 0;
+
+}
+
+
+void AfterLoadStations(void)
+{
+	Station *st;
+	uint i;
+	TileIndex tile;
+
+	/* Update the speclists of all stations to point to the currently loaded custom stations. */
+	FOR_ALL_STATIONS(st) {
+		for (i = 0; i < st->num_specs; i++) {
+			if (st->speclist[i].grfid == 0) continue;
+
+			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
+		}
+	}
+
+	for (tile = 0; tile < MapSize(); tile++) {
+		if (GetTileType(tile) != MP_STATION) continue;
+		st = GetStationByTile(tile);
+		StationRect_BeforeAddTile(st, tile, RECT_MODE_FORCE);
+	}
+}
+
+
+const TileTypeProcs _tile_type_station_procs = {
+	DrawTile_Station,           /* draw_tile_proc */
+	GetSlopeZ_Station,          /* get_slope_z_proc */
+	ClearTile_Station,          /* clear_tile_proc */
+	GetAcceptedCargo_Station,   /* get_accepted_cargo_proc */
+	GetTileDesc_Station,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Station, /* get_tile_track_status_proc */
+	ClickTile_Station,          /* click_tile_proc */
+	AnimateTile_Station,        /* animate_tile_proc */
+	TileLoop_Station,           /* tile_loop_clear */
+	ChangeTileOwner_Station,    /* change_tile_owner_clear */
+	NULL,                       /* get_produced_cargo_proc */
+	VehicleEnter_Station,       /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Station,      /* get_slope_tileh_proc */
+};
+
+static const SaveLoad _roadstop_desc[] = {
+	SLE_VAR(RoadStop,xy,           SLE_UINT32),
+	SLE_VAR(RoadStop,used,         SLE_BOOL),
+	SLE_VAR(RoadStop,status,       SLE_UINT8),
+	/* Index was saved in some versions, but this is not needed */
+	SLE_CONDNULL(4, 0, 8),
+	SLE_VAR(RoadStop,station,      SLE_UINT16),
+	SLE_CONDNULL(1, 0, 25),
+
+	SLE_REF(RoadStop,next,         REF_ROADSTOPS),
+	SLE_REF(RoadStop,prev,         REF_ROADSTOPS),
+
+	SLE_CONDNULL(4, 0, 24),
+	SLE_CONDNULL(1, 25, 25),
+
+	SLE_END()
+};
+
+static const SaveLoad _station_desc[] = {
+	SLE_CONDVAR(Station, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Station, bus_tile_obsolete,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, lorry_tile_obsolete,        SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, train_tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, train_tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Station, airport_tile,               SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, airport_tile,               SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Station, dock_tile,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Station, dock_tile,                  SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLE_REF(Station, town,                       REF_TOWN),
+	    SLE_VAR(Station, trainst_w,                  SLE_UINT8),
+	SLE_CONDVAR(Station, trainst_h,                  SLE_UINT8,                   2, SL_MAX_VERSION),
+
+	// alpha_order was stored here in savegame format 0 - 3
+	SLE_CONDNULL(1, 0, 3),
+
+	    SLE_VAR(Station, string_id,                  SLE_STRINGID),
+	    SLE_VAR(Station, had_vehicle_of_type,        SLE_UINT16),
+
+	    SLE_VAR(Station, time_since_load,            SLE_UINT8),
+	    SLE_VAR(Station, time_since_unload,          SLE_UINT8),
+	    SLE_VAR(Station, delete_ctr,                 SLE_UINT8),
+	    SLE_VAR(Station, owner,                      SLE_UINT8),
+	    SLE_VAR(Station, facilities,                 SLE_UINT8),
+	    SLE_VAR(Station, airport_type,               SLE_UINT8),
+
+	// truck/bus_stop_status was stored here in savegame format 0 - 6
+	SLE_CONDVAR(Station, truck_stop_status_obsolete, SLE_UINT8, 0, 5),
+	SLE_CONDVAR(Station, bus_stop_status_obsolete,   SLE_UINT8, 0, 5),
+
+	// blocked_months was stored here in savegame format 0 - 4.0
+	SLE_CONDVAR(Station, blocked_months_obsolete,    SLE_UINT8, 0, 4),
+
+	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U32 | SLE_FILE_U16,  0,  2),
+	SLE_CONDVAR(Station, airport_flags,              SLE_UINT32,                  3, SL_MAX_VERSION),
+
+	SLE_CONDNULL(2, 0, 25), /* Ex last-vehicle */
+	SLE_CONDVAR(Station, last_vehicle_type,          SLE_UINT8,                  26, SL_MAX_VERSION),
+
+	// Was custom station class and id
+	SLE_CONDNULL(2, 3, 25),
+	SLE_CONDVAR(Station, build_date,                 SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
+	SLE_CONDVAR(Station, build_date,                 SLE_INT32,                  31, SL_MAX_VERSION),
+
+	SLE_CONDREF(Station, bus_stops,                  REF_ROADSTOPS,               6, SL_MAX_VERSION),
+	SLE_CONDREF(Station, truck_stops,                REF_ROADSTOPS,               6, SL_MAX_VERSION),
+
+	/* Used by newstations for graphic variations */
+	SLE_CONDVAR(Station, random_bits,                SLE_UINT16,                 27, SL_MAX_VERSION),
+	SLE_CONDVAR(Station, waiting_triggers,           SLE_UINT8,                  27, SL_MAX_VERSION),
+	SLE_CONDVAR(Station, num_specs,                  SLE_UINT8,                  27, SL_MAX_VERSION),
+
+	// reserve extra space in savegame here. (currently 32 bytes)
+	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _goods_desc[] = {
+	    SLE_VAR(GoodsEntry, waiting_acceptance, SLE_UINT16),
+	    SLE_VAR(GoodsEntry, days_since_pickup,  SLE_UINT8),
+	    SLE_VAR(GoodsEntry, rating,             SLE_UINT8),
+	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_FILE_U8 | SLE_VAR_U16,  0, 6),
+	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_UINT16,                 7, SL_MAX_VERSION),
+	    SLE_VAR(GoodsEntry, enroute_time,       SLE_UINT8),
+	    SLE_VAR(GoodsEntry, last_speed,         SLE_UINT8),
+	    SLE_VAR(GoodsEntry, last_age,           SLE_UINT8),
+	SLE_CONDVAR(GoodsEntry, feeder_profit,      SLE_INT32,                 14, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _station_speclist_desc[] = {
+	SLE_CONDVAR(StationSpecList, grfid,    SLE_UINT32, 27, SL_MAX_VERSION),
+	SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8,  27, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+
+static void SaveLoad_STNS(Station *st)
+{
+	uint i;
+
+	SlObject(st, _station_desc);
+	for (i = 0; i != NUM_CARGO; i++) {
+		SlObject(&st->goods[i], _goods_desc);
+
+		/* In older versions, enroute_from had 0xFF as INVALID_STATION, is now 0xFFFF */
+		if (CheckSavegameVersion(7) && st->goods[i].enroute_from == 0xFF) {
+			st->goods[i].enroute_from = INVALID_STATION;
+		}
+	}
+
+	if (st->num_specs != 0) {
+		/* Allocate speclist memory when loading a game */
+		if (st->speclist == NULL) st->speclist = calloc(st->num_specs, sizeof(*st->speclist));
+		for (i = 0; i < st->num_specs; i++) SlObject(&st->speclist[i], _station_speclist_desc);
+	}
+}
+
+static void Save_STNS(void)
+{
+	Station *st;
+	// Write the stations
+	FOR_ALL_STATIONS(st) {
+		SlSetArrayIndex(st->index);
+		SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
+	}
+}
+
+static void Load_STNS(void)
+{
+	int index;
+	while ((index = SlIterateArray()) != -1) {
+		Station *st;
+
+		if (!AddBlockIfNeeded(&_Station_pool, index))
+			error("Stations: failed loading savegame: too many stations");
+
+		st = GetStation(index);
+		SaveLoad_STNS(st);
+
+		// this means it's an oldstyle savegame without support for nonuniform stations
+		if (st->train_tile != 0 && st->trainst_h == 0) {
+			uint w = GB(st->trainst_w, 4, 4);
+			uint h = GB(st->trainst_w, 0, 4);
+
+			if (GetRailStationAxis(st->train_tile) == AXIS_Y) uintswap(w, h);
+			st->trainst_w = w;
+			st->trainst_h = h;
+		}
+
+		/* In older versions, we had just 1 tile for a bus/lorry, now we have more..
+		 *  convert, if needed */
+		if (CheckSavegameVersion(6)) {
+			if (st->bus_tile_obsolete != 0) {
+				st->bus_stops = AllocateRoadStop();
+				if (st->bus_stops == NULL)
+					error("Station: too many busstations in savegame");
+
+				InitializeRoadStop(st->bus_stops, NULL, st->bus_tile_obsolete, st->index);
+			}
+			if (st->lorry_tile_obsolete != 0) {
+				st->truck_stops = AllocateRoadStop();
+				if (st->truck_stops == NULL)
+					error("Station: too many truckstations in savegame");
+
+				InitializeRoadStop(st->truck_stops, NULL, st->lorry_tile_obsolete, st->index);
+			}
+		}
+	}
+
+	/* This is to ensure all pointers are within the limits of _stations_size */
+	if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
+}
+
+static void Save_ROADSTOP(void)
+{
+	RoadStop *rs;
+
+	FOR_ALL_ROADSTOPS(rs) {
+		SlSetArrayIndex(rs->index);
+		SlObject(rs, _roadstop_desc);
+	}
+}
+
+static void Load_ROADSTOP(void)
+{
+	int index;
+	Vehicle *v;
+
+	while ((index = SlIterateArray()) != -1) {
+		RoadStop *rs;
+
+		if (!AddBlockIfNeeded(&_RoadStop_pool, index))
+			error("RoadStops: failed loading savegame: too many RoadStops");
+
+		rs = GetRoadStop(index);
+		SlObject(rs, _roadstop_desc);
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Road && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++;
+	}
+}
+
+const ChunkHandler _station_chunk_handlers[] = {
+	{ 'STNS', Save_STNS,      Load_STNS,      CH_ARRAY },
+	{ 'ROAD', Save_ROADSTOP,  Load_ROADSTOP,  CH_ARRAY | CH_LAST},
+};
+
+
+static inline bool PtInRectXY(Rect *r, int x, int y)
+{
+	return (r->left <= x && x <= r->right && r->top <= y && y <= r->bottom);
+}
+
+static void StationRect_Init(Station *st)
+{
+	Rect *r = &st->rect;
+	r->left = r->top = r->right = r->bottom = 0;
+}
+
+static bool StationRect_IsEmpty(Station *st)
+{
+	return (st->rect.left == 0 || st->rect.left > st->rect.right || st->rect.top > st->rect.bottom);
+}
+
+static bool StationRect_BeforeAddTile(Station *st, TileIndex tile, StationRectMode mode)
+{
+	Rect *r = &st->rect;
+	int x = TileX(tile);
+	int y = TileY(tile);
+	if (StationRect_IsEmpty(st)) {
+		// we are adding the first station tile
+		r->left = r->right = x;
+		r->top = r->bottom = y;
+	} else if (!PtInRectXY(r, x, y)) {
+		// current rect is not empty and new point is outside this rect
+		// make new spread-out rectangle
+		Rect new_rect = {min(x, r->left), min(y, r->top), max(x, r->right), max(y, r->bottom)};
+		// check new rect dimensions against preset max
+		int w = new_rect.right - new_rect.left + 1;
+		int h = new_rect.bottom - new_rect.top + 1;
+		if (mode != RECT_MODE_FORCE && (w > _patches.station_spread || h > _patches.station_spread)) {
+			assert(mode != RECT_MODE_TRY);
+			_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
+			return false;
+		}
+		// spread-out ok, return true
+		if (mode != RECT_MODE_TEST) {
+			// we should update the station rect
+			*r = new_rect;
+		}
+	} else {
+		; // new point is inside the rect, we don't need to do anything
+	}
+	return true;
+}
+
+static bool StationRect_BeforeAddRect(Station *st, TileIndex tile, int w, int h, StationRectMode mode)
+{
+	return StationRect_BeforeAddTile(st, tile, mode) && StationRect_BeforeAddTile(st, TILE_ADDXY(tile, w - 1, h - 1), mode);
+}
+
+static inline bool ScanRectForStationTiles(StationID st_id, int left, int top, int right, int bottom)
+{
+	TileIndex top_left = TileXY(left, top);
+	int width = right - left + 1;
+	int height = bottom - top + 1;
+	BEGIN_TILE_LOOP(tile, width, height, top_left)
+		if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
+	END_TILE_LOOP(tile, width, height, top_left);
+	return false;
+}
+
+static bool StationRect_AfterRemoveTile(Station *st, TileIndex tile)
+{
+	Rect *r = &st->rect;
+	int x = TileX(tile);
+	int y = TileY(tile);
+	bool reduce_x, reduce_y;
+
+	// look if removed tile was on the bounding rect edge
+	// and try to reduce the rect by this edge
+	// do it until we have empty rect or nothing to do
+	for (;;) {
+		// check if removed tile is on rect edge
+		bool left_edge = (x == r->left);
+		bool right_edge = (x == r->right);
+		bool top_edge = (y == r->top);
+		bool bottom_edge = (y == r->bottom);
+		// can we reduce the rect in either direction?
+		reduce_x = ((left_edge || right_edge) && !ScanRectForStationTiles(st->index, x, r->top, x, r->bottom));
+		reduce_y = ((top_edge || bottom_edge) && !ScanRectForStationTiles(st->index, r->left, y, r->right, y));
+		if (!(reduce_x || reduce_y)) break; // nothing to do (can't reduce)
+		if (reduce_x) {
+			// reduce horizontally
+			if (left_edge) {
+				// move left edge right
+				r->left = x = x + 1;
+			} else {
+				// move right edge left
+				r->right = x = x - 1;
+			}
+		}
+		if (reduce_y) {
+			// reduce vertically
+			if (top_edge) {
+				// move top edge down
+				r->top = y = y + 1;
+			} else {
+				// move bottom edge up
+				r->bottom = y = y - 1;
+			}
+		}
+		if (r->left > r->right || r->top > r->bottom) {
+		// can't continue, if the remaining rectangle is empty
+			StationRect_Init(st);
+			return true; // empty remaining rect
+		}
+	}
+	return false; // non-empty remaining rect
+}
+
+static bool StationRect_AfterRemoveRect(Station *st, TileIndex tile, int w, int h)
+{
+	bool empty;
+	assert(PtInRectXY(&st->rect, TileX(tile), TileY(tile)));
+	assert(PtInRectXY(&st->rect, TileX(tile) + w - 1, TileY(tile) + h - 1));
+	empty = StationRect_AfterRemoveTile(st, tile);
+	if (w != 1 || h != 1) empty = empty || StationRect_AfterRemoveTile(st, TILE_ADDXY(tile, w - 1, h - 1));
+	return empty;
+}
deleted file mode 100644
--- a/src/station_gui.c
+++ /dev/null
@@ -1,825 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "strings.h"
-#include "table/strings.h"
-#include "window.h"
-#include "gui.h"
-#include "station.h"
-#include "gfx.h"
-#include "player.h"
-#include "economy.h"
-#include "town.h"
-#include "command.h"
-#include "variables.h"
-#include "vehicle_gui.h"
-#include "date.h"
-#include "vehicle.h"
-
-enum StationListWidgets {
-	STATIONLIST_WIDGET_CLOSEBOX = 0,
-	STATIONLIST_WIDGET_LIST = 3,
-	STATIONLIST_WIDGET_TRAIN =6,
-	STATIONLIST_WIDGET_TRUCK,
-	STATIONLIST_WIDGET_BUS,
-	STATIONLIST_WIDGET_AIRPLANE,
-	STATIONLIST_WIDGET_SHIP,
-	STATIONLIST_WIDGET_CARGOSTART = 12,
-	STATIONLIST_WIDGET_NOCARGOWAITING = 24,
-	STATIONLIST_WIDGET_FACILALL = 26,
-	STATIONLIST_WIDGET_CARGOALL,
-	STATIONLIST_WIDGET_SORTBY,
-	STATIONLIST_WIDGET_SORTCRITERIA,
-	STATIONLIST_WIDGET_SORTDROPBTN,
-	CARGO_ALL_SELECTED = 0x1FFF,
-};
-
-typedef int CDECL StationSortListingTypeFunction(const void*, const void*);
-
-static StationSortListingTypeFunction StationNameSorter;
-static StationSortListingTypeFunction StationTypeSorter;
-static StationSortListingTypeFunction StationWaitingSorter;
-static StationSortListingTypeFunction StationRatingMaxSorter;
-
-/** Draw small boxes of cargo amount and ratings data at the given
- * coordinates. If amount exceeds 576 units, it is shown 'full', same
- * goes for the rating: at above 90% orso (224) it is also 'full'
- * Each cargo-bar is 16 pixels wide and 6 pixels high
- * Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar
- * @param x,y X/Y coordinate to draw the box at
- * @param type Cargo type
- * @param amount Cargo amount
- * @param rating ratings data for that particular cargo */
-static void StationsWndShowStationRating(int x, int y, CargoID type, uint amount, byte rating)
-{
-	int colour = _cargo_colours[type];
-	uint w = (minu(amount, 576) + 5) / 36;
-
-	/* Draw total cargo (limited) on station (fits into 16 pixels) */
-	if (w != 0) GfxFillRect(x, y, x + w - 1, y + 6, colour);
-
-	/* Draw a one pixel-wide bar of additional cargo meter, useful
-	 * for stations with only a small amount (<=30) */
-	if (w == 0) {
-		uint rest = amount / 5;
-		if (rest != 0) {
-			w += x;
-			GfxFillRect(w, y + 6 - rest, w, y + 6, colour);
-		}
-	}
-
-	DrawString(x + 1, y, _cargoc.names_short[type], 0x10);
-
-	/* Draw green/red ratings bar (fits into 14 pixels) */
-	y += 8;
-	GfxFillRect(x + 1, y, x + 14, y, 0xB8);
-	rating = minu(rating,  224) / 16;
-	if (rating != 0) GfxFillRect(x + 1, y, x + rating, y, 0xD0);
-}
-
-const StringID _station_sort_listing[] = {
-	STR_SORT_BY_DROPDOWN_NAME,
-	STR_SORT_BY_FACILITY,
-	STR_SORT_BY_WAITING,
-	STR_SORT_BY_RATING_MAX,
-	INVALID_STRING_ID
-};
-
-static char _bufcache[64];
-static const Station* _last_station;
-static int _internal_sort_order;
-
-static int CDECL StationNameSorter(const void *a, const void *b)
-{
-	const Station* st1 = *(const Station**)a;
-	const Station* st2 = *(const Station**)b;
-	char buf1[64];
-	int r;
-
-	SetDParam(0, st1->index);
-	GetString(buf1, STR_STATION, lastof(buf1));
-
-	if (st2 != _last_station) {
-		_last_station = st2;
-		SetDParam(0, st2->index);
-		GetString(_bufcache, STR_STATION, lastof(_bufcache));
-	}
-
-	r =  strcmp(buf1, _bufcache); // sort by name
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL StationTypeSorter(const void *a, const void *b)
-{
-	const Station* st1 = *(const Station**)a;
-	const Station* st2 = *(const Station**)b;
-	return (_internal_sort_order & 1) ? st2->facilities - st1->facilities : st1->facilities - st2->facilities;
-}
-
-static int CDECL StationWaitingSorter(const void *a, const void *b)
-{
-	const Station* st1 = *(const Station**)a;
-	const Station* st2 = *(const Station**)b;
-	int sum1 = 0, sum2 = 0;
-	int j;
-
-	for (j = 0; j < NUM_CARGO; j++) {
-		if (st1->goods[j].waiting_acceptance & 0xfff) sum1 += GetTransportedGoodsIncome(st1->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
-		if (st2->goods[j].waiting_acceptance & 0xfff) sum2 += GetTransportedGoodsIncome(st2->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
-	}
-
-	return (_internal_sort_order & 1) ? sum2 - sum1 : sum1 - sum2;
-}
-
-static int CDECL StationRatingMaxSorter(const void *a, const void *b)
-{
-	const Station* st1 = *(const Station**)a;
-	const Station* st2 = *(const Station**)b;
-	byte maxr1 = 0;
-	byte maxr2 = 0;
-	int j;
-
-	for (j = 0; j < NUM_CARGO; j++) {
-		if (st1->goods[j].waiting_acceptance & 0xfff) maxr1 = max(maxr1, st1->goods[j].rating);
-		if (st2->goods[j].waiting_acceptance & 0xfff) maxr2 = max(maxr2, st2->goods[j].rating);
-	}
-
-	return (_internal_sort_order & 1) ? maxr2 - maxr1 : maxr1 - maxr2;
-}
-
-typedef enum StationListFlags {
-	SL_ORDER   = 0x01,
-	SL_RESORT  = 0x02,
-	SL_REBUILD = 0x04,
-} StationListFlags;
-
-typedef struct plstations_d {
-	const Station** sort_list;
-	uint16 list_length;
-	byte sort_type;
-	StationListFlags flags;
-	uint16 resort_timer;  //was byte refresh_counter;
-} plstations_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(plstations_d));
-
-void RebuildStationLists(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == WC_STATION_LIST) {
-			WP(w, plstations_d).flags |= SL_REBUILD;
-			SetWindowDirty(w);
-		}
-	}
-}
-
-void ResortStationLists(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == WC_STATION_LIST) {
-			WP(w, plstations_d).flags |= SL_RESORT;
-			SetWindowDirty(w);
-		}
-	}
-}
-
-static void BuildStationsList(plstations_d* sl, PlayerID owner, byte facilities, uint16 cargo_filter)
-{
-	uint n = 0;
-	uint i, j;
-	const Station** station_sort;
-	const Station *st;
-
-	if (!(sl->flags & SL_REBUILD)) return;
-
-	/* Create array for sorting */
-	station_sort = malloc((GetMaxStationIndex() + 1) * sizeof(station_sort[0]));
-	if (station_sort == NULL) error("Could not allocate memory for the station-sorting-list");
-
-	DEBUG(misc, 3, "Building station list for player %d", owner);
-
-	FOR_ALL_STATIONS(st) {
-		if (st->owner == owner) {
-			if (facilities & st->facilities) { //only stations with selected facilities
-				int num_waiting_cargo = 0;
-				for (j = 0; j < NUM_CARGO; j++) {
-					if (st->goods[j].waiting_acceptance & 0xFFF) {
-						num_waiting_cargo++; //count number of waiting cargo
-						if (HASBIT(cargo_filter, j)) {
-							station_sort[n++] = st;
-							break;
-						}
-					}
-				}
-				//stations without waiting cargo
-				if (num_waiting_cargo == 0 && HASBIT(cargo_filter, NUM_CARGO)) {
-					station_sort[n++] = st;
-				}
-			}
-		}
-	}
-
-	free((void*)sl->sort_list);
-	sl->sort_list = malloc(n * sizeof(sl->sort_list[0]));
-	if (n != 0 && sl->sort_list == NULL) error("Could not allocate memory for the station-sorting-list");
-	sl->list_length = n;
-
-	for (i = 0; i < n; ++i) sl->sort_list[i] = station_sort[i];
-
-	sl->flags &= ~SL_REBUILD;
-	sl->flags |= SL_RESORT;
-	free((void*)station_sort);
-}
-
-static void SortStationsList(plstations_d *sl)
-{
-	static StationSortListingTypeFunction* const _station_sorter[] = {
-		&StationNameSorter,
-		&StationTypeSorter,
-		&StationWaitingSorter,
-		&StationRatingMaxSorter
-	};
-
-	if (!(sl->flags & SL_RESORT)) return;
-
-	_internal_sort_order = sl->flags & SL_ORDER;
-	_last_station = NULL; // used for "cache" in namesorting
-	qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), _station_sorter[sl->sort_type]);
-
-	sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
-	sl->flags &= ~SL_RESORT;
-}
-
-static void PlayerStationsWndProc(Window *w, WindowEvent *e)
-{
-	const PlayerID owner = w->window_number;
-	static byte facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
-	static uint16 cargo_filter = CARGO_ALL_SELECTED;
-	plstations_d *sl = &WP(w, plstations_d);
-
-	switch (e->event) {
-	case WE_CREATE: { /* set up resort timer */
-		int i;
-		for (i = 0; i < 5; i++) {
-			if (HASBIT(facilities, i)) LowerWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
-		}
-		for (i = 0; i < NUM_CARGO; i++) {
-			if (HASBIT(cargo_filter, i)) LowerWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
-		}
-		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_FACILALL, facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
-		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_CARGOALL, cargo_filter == CARGO_ALL_SELECTED);
-		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_NOCARGOWAITING, HASBIT(cargo_filter, STATIONLIST_WIDGET_NOCARGOWAITING - NUM_CARGO));
-
-		sl->sort_list = NULL;
-		sl->flags = SL_REBUILD;
-		sl->sort_type = 0;
-		sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
-		break;
-	}
-
-	case WE_PAINT: {
-		BuildStationsList(sl, owner, facilities, cargo_filter);
-		SortStationsList(sl);
-
-		SetVScrollCount(w, sl->list_length);
-
-		/* draw widgets, with player's name in the caption */
-		{
-			const Player* p = GetPlayer(owner);
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
-			DrawWindowWidgets(w);
-		}
-
-		{
-			int max;
-			int i, cg_ofst;
-			int x = 0, y = 0, xb = 2; // offset from top of widget
-
-			/* draw sorting criteria string */
-			DrawString(85, 26, _station_sort_listing[sl->sort_type], 0x10);
-			/* draw arrow pointing up/down for ascending/descending sorting */
-			DoDrawString(sl->flags & SL_ORDER ? DOWNARROW : UPARROW, 69, 26, 0x10);
-
-
-			x = 89;
-			y = 14;
-
-			for (i = 0; i < NUM_CARGO; i++) {
-				cg_ofst = IsWindowWidgetLowered(w, i + STATIONLIST_WIDGET_CARGOSTART) ? 2 : 1;
-
-				GfxFillRect(x + cg_ofst, y + cg_ofst, x + cg_ofst + 10 , y + cg_ofst + 7, _cargo_colours[i]);
-				DrawStringCentered(x + 6 + cg_ofst, y + cg_ofst, _cargoc.names_short[i], 0x10);
-				x += 14;
-			}
-
-			x += 6;
-			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_NOCARGOWAITING) ? 2 : 1;
-			DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_NONE, 16);
-			x += 14;
-			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_CARGOALL) ? 2 : 1;
-			DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, 16);
-
-			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_FACILALL) ? 2 : 1;
-			DrawString(71 + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, 16);
-
-			if (w->vscroll.count == 0) { // player has no stations
-				DrawString(xb, 40, STR_304A_NONE, 0);
-				return;
-			}
-
-			max = min(w->vscroll.pos + w->vscroll.cap, sl->list_length);
-			y = 40; // start of the list-widget
-
-			for (i = w->vscroll.pos; i < max; ++i) { // do until max number of stations of owner
-				const Station *st = sl->sort_list[i];
-				CargoID j;
-				int x;
-
-				assert(st->xy != 0);
-				assert(st->owner == owner);
-
-				SetDParam(0, st->index);
-				SetDParam(1, st->facilities);
-				x = DrawString(xb, y, STR_3049_0, 0) + 5;
-
-				// show cargo waiting and station ratings
-				for (j = 0; j != NUM_CARGO; j++) {
-					uint amount = GB(st->goods[j].waiting_acceptance, 0, 12);
-
-					if (amount != 0) {
-						StationsWndShowStationRating(x, y, j, amount, st->goods[j].rating);
-						x += 20;
-					}
-				}
-				y += 10;
-			}
-		}
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case STATIONLIST_WIDGET_LIST: {
-			const Station* st;
-
-			uint32 id_v = (e->we.click.pt.y - 41) / 10;
-
-			if (id_v >= w->vscroll.cap) return; // click out of bounds
-
-			id_v += w->vscroll.pos;
-
-			if (id_v >= sl->list_length) return; // click out of list bound
-
-			st = sl->sort_list[id_v];
-			assert(st->owner == owner);
-			ScrollMainWindowToTile(st->xy);
-			break;
-		}
-
-		case STATIONLIST_WIDGET_TRAIN:
-		case STATIONLIST_WIDGET_TRUCK:
-		case STATIONLIST_WIDGET_BUS:
-		case STATIONLIST_WIDGET_AIRPLANE:
-		case STATIONLIST_WIDGET_SHIP:
-			if (_ctrl_pressed) {
-				TOGGLEBIT(facilities, e->we.click.widget - STATIONLIST_WIDGET_TRAIN);
-				ToggleWidgetLoweredState(w, e->we.click.widget);
-			} else {
-				int i;
-				for (i = 0; facilities != 0; i++, facilities >>= 1) {
-					if (HASBIT(facilities, 0)) RaiseWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
-				}
-				SETBIT(facilities, e->we.click.widget - STATIONLIST_WIDGET_TRAIN);
-				LowerWindowWidget(w, e->we.click.widget);
-			}
-			SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_FACILALL, facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
-			sl->flags |= SL_REBUILD;
-			SetWindowDirty(w);
-		break;
-
-		case STATIONLIST_WIDGET_FACILALL: {
-			int i;
-			for (i = 0; i < 5; i++) {
-				LowerWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
-			}
-			LowerWindowWidget(w, STATIONLIST_WIDGET_FACILALL);
-
-			facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
-			sl->flags |= SL_REBUILD;
-			SetWindowDirty(w);
-			break;
-		}
-		case STATIONLIST_WIDGET_CARGOALL: {
-			int i;
-			for (i = 0; i < NUM_CARGO; i++) {
-				LowerWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
-			}
-			LowerWindowWidget(w, STATIONLIST_WIDGET_NOCARGOWAITING);
-			LowerWindowWidget(w, STATIONLIST_WIDGET_CARGOALL);
-
-			cargo_filter = CARGO_ALL_SELECTED;
-			sl->flags |= SL_REBUILD;
-			SetWindowDirty(w);
-			break;
-		}
-		case STATIONLIST_WIDGET_SORTBY: /*flip sorting method asc/desc*/
-			TOGGLEBIT(sl->flags, 0); //DESC-flag
-			sl->flags |= SL_RESORT;
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-			LowerWindowWidget(w, STATIONLIST_WIDGET_SORTBY);
-			SetWindowDirty(w);
-		break;
-
-		case STATIONLIST_WIDGET_SORTCRITERIA:
-		case STATIONLIST_WIDGET_SORTDROPBTN: /* select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _station_sort_listing, sl->sort_type, STATIONLIST_WIDGET_SORTDROPBTN, 0, 0);
-		break;
-
-		default:
-			if (e->we.click.widget >= STATIONLIST_WIDGET_CARGOSTART && e->we.click.widget <= STATIONLIST_WIDGET_NOCARGOWAITING) { //change cargo_filter
-				if (_ctrl_pressed) {
-					TOGGLEBIT(cargo_filter, e->we.click.widget - STATIONLIST_WIDGET_CARGOSTART);
-					ToggleWidgetLoweredState(w, e->we.click.widget);
-				} else {
-					int i;
-					for (i = 0; cargo_filter != 0; i++, cargo_filter >>= 1) {
-						if (HASBIT(cargo_filter, 0)) RaiseWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
-					}
-					SETBIT(cargo_filter, e->we.click.widget - STATIONLIST_WIDGET_CARGOSTART);
-					LowerWindowWidget(w, e->we.click.widget);
-				}
-				sl->flags |= SL_REBUILD;
-				SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_CARGOALL, cargo_filter == CARGO_ALL_SELECTED);
-				SetWindowDirty(w);
-			}
-		}
-	} break;
-
-	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		if (sl->sort_type != e->we.dropdown.index) {
-			// value has changed -> resort
-			sl->sort_type = e->we.dropdown.index;
-			sl->flags |= SL_RESORT;
-		}
-		SetWindowDirty(w);
-		break;
-
-	case WE_TICK:
-		if (--sl->resort_timer == 0) {
-			DEBUG(misc, 3, "Periodic rebuild station list player %d", owner);
-			sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
-			sl->flags |= VL_REBUILD;
-			SetWindowDirty(w);
-		}
-		break;
-
-	case WE_TIMEOUT:
-		RaiseWindowWidget(w, STATIONLIST_WIDGET_SORTBY);
-		SetWindowDirty(w);
-		break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 10;
-		break;
-	}
-}
-
-static const Widget _player_stations_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_3048_STATIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,               STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    37,   161, 0x0,               STR_3057_STATION_NAMES_CLICK_ON},
-{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    37,   149, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   150,   161, 0x0,               STR_RESIZE_BUTTON},
-//Index 6
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,    13,    14,    24, STR_TRAIN,         STR_USE_CTRL_TO_SELECT_MORE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    27,    14,    24, STR_LORRY,         STR_USE_CTRL_TO_SELECT_MORE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    28,    41,    14,    24, STR_BUS,           STR_USE_CTRL_TO_SELECT_MORE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    42,    55,    14,    24, STR_PLANE,         STR_USE_CTRL_TO_SELECT_MORE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    56,    69,    14,    24, STR_SHIP,          STR_USE_CTRL_TO_SELECT_MORE},
-//Index 11
-{      WWT_PANEL,   RESIZE_NONE,    14,    83,    88,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,    89,   102,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   103,   116,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   117,   130,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   131,   144,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   145,   158,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   159,   172,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   173,   186,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   187,   200,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   201,   214,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   215,   228,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   229,   242,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   243,   256,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
-{      WWT_PANEL,   RESIZE_NONE,    14,   257,   270,    14,    24, 0x0,               STR_NO_WAITING_CARGO},
-{      WWT_PANEL,  RESIZE_RIGHT,    14,   285,   357,    14,    24, 0x0,               STR_NULL},
-
-//26
-{      WWT_PANEL,   RESIZE_NONE,    14,    70,    83,    14,    24, 0x0,               STR_SELECT_ALL_FACILITIES},
-{      WWT_PANEL,   RESIZE_NONE,    14,   271,   284,    14,    24, 0x0,               STR_SELECT_ALL_TYPES},
-
-//28
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,    80,    25,    36, STR_SORT_BY,       STR_SORT_ORDER_TIP},
-{      WWT_PANEL,   RESIZE_NONE,    14,    81,   232,    25,    36, 0x0,               STR_SORT_CRITERIA_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,   233,   243,    25,    36, STR_0225,          STR_SORT_CRITERIA_TIP},
-{      WWT_PANEL,  RESIZE_RIGHT,    14,   244,   357,    25,    36, 0x0,               STR_NULL},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _player_stations_desc = {
-	WDP_AUTO, WDP_AUTO, 358, 162,
-	WC_STATION_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_player_stations_widgets,
-	PlayerStationsWndProc
-};
-
-
-void ShowPlayerStations(PlayerID player)
-{
-	Window *w;
-
-	if (!IsValidPlayer(player)) return;
-
-	w = AllocateWindowDescFront(&_player_stations_desc, player);
-	if (w != NULL) {
-		w->caption_color = (byte)w->window_number;
-		w->vscroll.cap = 12;
-		w->resize.step_height = 10;
-		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
-	}
-}
-
-static const Widget _station_view_expanded_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   236,     0,    13, STR_300A_0,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   237,   248,     0,    13, 0x0,               STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   236,    14,    65, 0x0,               STR_NULL},
-{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   237,   248,    14,    65, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   248,    66,   197, 0x0,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    63,   198,   209, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    64,   128,   198,   209, STR_3033_ACCEPTS,  STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   129,   192,   198,   209, STR_0130_RENAME,   STR_3055_CHANGE_NAME_OF_STATION},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   193,   206,   198,   209, STR_TRAIN,         STR_SCHEDULED_TRAINS_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   207,   220,   198,   209, STR_LORRY,         STR_SCHEDULED_ROAD_VEHICLES_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   221,   234,   198,   209, STR_PLANE,         STR_SCHEDULED_AIRCRAFT_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   235,   248,   198,   209, STR_SHIP,          STR_SCHEDULED_SHIPS_TIP },
-{   WIDGETS_END},
-};
-
-static const Widget _station_view_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   236,     0,    13, STR_300A_0,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   237,   248,     0,    13, 0x0,               STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   236,    14,    65, 0x0,               STR_NULL},
-{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   237,   248,    14,    65, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   248,    66,    97, 0x0,               STR_NULL},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    63,    98,   109, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    64,   128,    98,   109, STR_3032_RATINGS,  STR_3054_SHOW_STATION_RATINGS},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   129,   192,    98,   109, STR_0130_RENAME,   STR_3055_CHANGE_NAME_OF_STATION},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   193,   206,    98,   109, STR_TRAIN,         STR_SCHEDULED_TRAINS_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   207,   220,    98,   109, STR_LORRY,         STR_SCHEDULED_ROAD_VEHICLES_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   221,   234,    98,   109, STR_PLANE,         STR_SCHEDULED_AIRCRAFT_TIP },
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   235,   248,    98,   109, STR_SHIP,          STR_SCHEDULED_SHIPS_TIP },
-{   WIDGETS_END},
-};
-
-static void DrawStationViewWindow(Window *w)
-{
-	StationID station_id = w->window_number;
-	const Station* st = GetStation(station_id);
-	uint i;
-	uint num;
-	int x,y;
-	int pos;
-	StringID str;
-
-	num = 1;
-	for (i = 0; i != NUM_CARGO; i++) {
-		if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) {
-			num++;
-			if (st->goods[i].enroute_from != station_id) num++;
-		}
-	}
-	SetVScrollCount(w, num);
-
-	SetWindowWidgetDisabledState(w,  9, st->owner != _local_player);
-	SetWindowWidgetDisabledState(w, 10, !(st->facilities & FACIL_TRAIN));
-	SetWindowWidgetDisabledState(w, 11, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
-	SetWindowWidgetDisabledState(w, 12, !(st->facilities & FACIL_AIRPORT));
-	SetWindowWidgetDisabledState(w, 13, !(st->facilities & FACIL_DOCK));
-
-	SetDParam(0, st->index);
-	SetDParam(1, st->facilities);
-	DrawWindowWidgets(w);
-
-	x = 2;
-	y = 15;
-	pos = w->vscroll.pos;
-
-	if (--pos < 0) {
-		str = STR_00D0_NOTHING;
-		for (i = 0; i != NUM_CARGO; i++) {
-			if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) str = STR_EMPTY;
-		}
-		SetDParam(0, str);
-		DrawString(x, y, STR_0008_WAITING, 0);
-		y += 10;
-	}
-
-	i = 0;
-	do {
-		uint waiting = GB(st->goods[i].waiting_acceptance, 0, 12);
-		if (waiting == 0) continue;
-
-		num = (waiting + 5) / 10;
-		if (num != 0) {
-			int cur_x = x;
-			num = min(num, 23);
-			do {
-				DrawSprite(_cargoc.sprites[i], cur_x, y);
-				cur_x += 10;
-			} while (--num);
-		}
-
-		if ( st->goods[i].enroute_from == station_id) {
-			if (--pos < 0) {
-				SetDParam(1, waiting);
-				SetDParam(0, i);
-				DrawStringRightAligned(x + 234, y, STR_0009, 0);
-				y += 10;
-			}
-		} else {
-			/* enroute */
-			if (--pos < 0) {
-				SetDParam(1, waiting);
-				SetDParam(0, i);
-				DrawStringRightAligned(x + 234, y, STR_000A_EN_ROUTE_FROM, 0);
-				y += 10;
-			}
-
-			if (pos > -5 && --pos < 0) {
-				SetDParam(0, st->goods[i].enroute_from);
-				DrawStringRightAligned(x + 234, y, STR_000B, 0);
-				y += 10;
-			}
-		}
-	} while (pos > -5 && ++i != NUM_CARGO);
-
-	if (IsWindowOfPrototype(w, _station_view_widgets)) {
-		char *b = _userstring;
-		bool first = true;
-
-		b = InlineString(b, STR_000C_ACCEPTS);
-
-		for (i = 0; i != NUM_CARGO; i++) {
-			if (b >= endof(_userstring) - 5 - 1) break;
-			if (st->goods[i].waiting_acceptance & 0x8000) {
-				if (first) {
-					first = false;
-				} else {
-					/* Add a comma if this is not the first item */
-					*b++ = ',';
-					*b++ = ' ';
-				}
-				b = InlineString(b, _cargoc.names_s[i]);
-			}
-		}
-
-		/* If first is still true then no cargo is accepted */
-		if (first) b = InlineString(b, STR_00D0_NOTHING);
-
-		*b = '\0';
-		DrawStringMultiLine(2, 67, STR_SPEC_USERSTRING, 245);
-	} else {
-		DrawString(2, 67, STR_3034_LOCAL_RATING_OF_TRANSPORT, 0);
-
-		y = 77;
-		for (i = 0; i != NUM_CARGO; i++) {
-			if (st->goods[i].enroute_from != INVALID_STATION) {
-				SetDParam(0, _cargoc.names_s[i]);
-				SetDParam(2, st->goods[i].rating * 101 >> 8);
-				SetDParam(1, STR_3035_APPALLING + (st->goods[i].rating >> 5));
-				DrawString(8, y, STR_303D, 0);
-				y += 10;
-			}
-		}
-	}
-}
-
-
-static void StationViewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawStationViewWindow(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 7:
-			ScrollMainWindowToTile(GetStation(w->window_number)->xy);
-			break;
-
-		case 8:
-			SetWindowDirty(w);
-
-			/* toggle height/widget set */
-			if (IsWindowOfPrototype(w, _station_view_expanded_widgets)) {
-				AssignWidgetToWindow(w, _station_view_widgets);
-				w->height = 110;
-			} else {
-				AssignWidgetToWindow(w, _station_view_expanded_widgets);
-				w->height = 210;
-			}
-
-			SetWindowDirty(w);
-			break;
-
-		case 9: {
-			SetDParam(0, w->window_number);
-			ShowQueryString(STR_STATION, STR_3030_RENAME_STATION_LOADING, 31, 180, w, CS_ALPHANUMERAL);
-		} break;
-
-		case 10: { /* Show a list of scheduled trains to this station */
-			const Station *st = GetStation(w->window_number);
-			ShowVehicleListWindow(st->owner, w->window_number, VEH_Train);
-			break;
-		}
-
-		case 11: { /* Show a list of scheduled road-vehicles to this station */
-			const Station *st = GetStation(w->window_number);
-			ShowVehicleListWindow(st->owner, w->window_number, VEH_Road);
-			break;
-		}
-
-		case 12: { /* Show a list of scheduled aircraft to this station */
-			const Station *st = GetStation(w->window_number);
-			/* Since oilrigs have no owners, show the scheduled aircraft of current player */
-			PlayerID owner = (st->owner == OWNER_NONE) ? _current_player : st->owner;
-			ShowVehicleListWindow(owner, w->window_number, VEH_Aircraft);
-			break;
-		}
-
-		case 13: { /* Show a list of scheduled ships to this station */
-			const Station *st = GetStation(w->window_number);
-			/* Since oilrigs/bouys have no owners, show the scheduled ships of current player */
-			PlayerID owner = (st->owner == OWNER_NONE) ? _current_player : st->owner;
-			ShowVehicleListWindow(owner, w->window_number, VEH_Ship);
-			break;
-		}
-		}
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_RENAME_STATION | CMD_MSG(STR_3031_CAN_T_RENAME_STATION));
-		}
-		break;
-
-	case WE_DESTROY: {
-		WindowNumber wno =
-			(w->window_number << 16) | GetStation(w->window_number)->owner;
-
-		DeleteWindowById(WC_TRAINS_LIST, wno);
-		DeleteWindowById(WC_ROADVEH_LIST, wno);
-		DeleteWindowById(WC_SHIPS_LIST, wno);
-		DeleteWindowById(WC_AIRCRAFT_LIST, wno);
-		break;
-	}
-	}
-}
-
-
-static const WindowDesc _station_view_desc = {
-	WDP_AUTO, WDP_AUTO, 249, 110,
-	WC_STATION_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_station_view_widgets,
-	StationViewWndProc
-};
-
-void ShowStationViewWindow(StationID station)
-{
-	Window *w;
-
-	w = AllocateWindowDescFront(&_station_view_desc, station);
-	if (w != NULL) {
-		PlayerID owner = GetStation(w->window_number)->owner;
-		if (owner != OWNER_NONE) w->caption_color = owner;
-		w->vscroll.cap = 5;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/station_gui.cpp
@@ -0,0 +1,825 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "window.h"
+#include "gui.h"
+#include "station.h"
+#include "gfx.h"
+#include "player.h"
+#include "economy.h"
+#include "town.h"
+#include "command.h"
+#include "variables.h"
+#include "vehicle_gui.h"
+#include "date.h"
+#include "vehicle.h"
+
+enum StationListWidgets {
+	STATIONLIST_WIDGET_CLOSEBOX = 0,
+	STATIONLIST_WIDGET_LIST = 3,
+	STATIONLIST_WIDGET_TRAIN =6,
+	STATIONLIST_WIDGET_TRUCK,
+	STATIONLIST_WIDGET_BUS,
+	STATIONLIST_WIDGET_AIRPLANE,
+	STATIONLIST_WIDGET_SHIP,
+	STATIONLIST_WIDGET_CARGOSTART = 12,
+	STATIONLIST_WIDGET_NOCARGOWAITING = 24,
+	STATIONLIST_WIDGET_FACILALL = 26,
+	STATIONLIST_WIDGET_CARGOALL,
+	STATIONLIST_WIDGET_SORTBY,
+	STATIONLIST_WIDGET_SORTCRITERIA,
+	STATIONLIST_WIDGET_SORTDROPBTN,
+	CARGO_ALL_SELECTED = 0x1FFF,
+};
+
+typedef int CDECL StationSortListingTypeFunction(const void*, const void*);
+
+static StationSortListingTypeFunction StationNameSorter;
+static StationSortListingTypeFunction StationTypeSorter;
+static StationSortListingTypeFunction StationWaitingSorter;
+static StationSortListingTypeFunction StationRatingMaxSorter;
+
+/** Draw small boxes of cargo amount and ratings data at the given
+ * coordinates. If amount exceeds 576 units, it is shown 'full', same
+ * goes for the rating: at above 90% orso (224) it is also 'full'
+ * Each cargo-bar is 16 pixels wide and 6 pixels high
+ * Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar
+ * @param x,y X/Y coordinate to draw the box at
+ * @param type Cargo type
+ * @param amount Cargo amount
+ * @param rating ratings data for that particular cargo */
+static void StationsWndShowStationRating(int x, int y, CargoID type, uint amount, byte rating)
+{
+	int colour = _cargo_colours[type];
+	uint w = (minu(amount, 576) + 5) / 36;
+
+	/* Draw total cargo (limited) on station (fits into 16 pixels) */
+	if (w != 0) GfxFillRect(x, y, x + w - 1, y + 6, colour);
+
+	/* Draw a one pixel-wide bar of additional cargo meter, useful
+	 * for stations with only a small amount (<=30) */
+	if (w == 0) {
+		uint rest = amount / 5;
+		if (rest != 0) {
+			w += x;
+			GfxFillRect(w, y + 6 - rest, w, y + 6, colour);
+		}
+	}
+
+	DrawString(x + 1, y, _cargoc.names_short[type], 0x10);
+
+	/* Draw green/red ratings bar (fits into 14 pixels) */
+	y += 8;
+	GfxFillRect(x + 1, y, x + 14, y, 0xB8);
+	rating = minu(rating,  224) / 16;
+	if (rating != 0) GfxFillRect(x + 1, y, x + rating, y, 0xD0);
+}
+
+const StringID _station_sort_listing[] = {
+	STR_SORT_BY_DROPDOWN_NAME,
+	STR_SORT_BY_FACILITY,
+	STR_SORT_BY_WAITING,
+	STR_SORT_BY_RATING_MAX,
+	INVALID_STRING_ID
+};
+
+static char _bufcache[64];
+static const Station* _last_station;
+static int _internal_sort_order;
+
+static int CDECL StationNameSorter(const void *a, const void *b)
+{
+	const Station* st1 = *(const Station**)a;
+	const Station* st2 = *(const Station**)b;
+	char buf1[64];
+	int r;
+
+	SetDParam(0, st1->index);
+	GetString(buf1, STR_STATION, lastof(buf1));
+
+	if (st2 != _last_station) {
+		_last_station = st2;
+		SetDParam(0, st2->index);
+		GetString(_bufcache, STR_STATION, lastof(_bufcache));
+	}
+
+	r =  strcmp(buf1, _bufcache); // sort by name
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL StationTypeSorter(const void *a, const void *b)
+{
+	const Station* st1 = *(const Station**)a;
+	const Station* st2 = *(const Station**)b;
+	return (_internal_sort_order & 1) ? st2->facilities - st1->facilities : st1->facilities - st2->facilities;
+}
+
+static int CDECL StationWaitingSorter(const void *a, const void *b)
+{
+	const Station* st1 = *(const Station**)a;
+	const Station* st2 = *(const Station**)b;
+	int sum1 = 0, sum2 = 0;
+	int j;
+
+	for (j = 0; j < NUM_CARGO; j++) {
+		if (st1->goods[j].waiting_acceptance & 0xfff) sum1 += GetTransportedGoodsIncome(st1->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
+		if (st2->goods[j].waiting_acceptance & 0xfff) sum2 += GetTransportedGoodsIncome(st2->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
+	}
+
+	return (_internal_sort_order & 1) ? sum2 - sum1 : sum1 - sum2;
+}
+
+static int CDECL StationRatingMaxSorter(const void *a, const void *b)
+{
+	const Station* st1 = *(const Station**)a;
+	const Station* st2 = *(const Station**)b;
+	byte maxr1 = 0;
+	byte maxr2 = 0;
+	int j;
+
+	for (j = 0; j < NUM_CARGO; j++) {
+		if (st1->goods[j].waiting_acceptance & 0xfff) maxr1 = max(maxr1, st1->goods[j].rating);
+		if (st2->goods[j].waiting_acceptance & 0xfff) maxr2 = max(maxr2, st2->goods[j].rating);
+	}
+
+	return (_internal_sort_order & 1) ? maxr2 - maxr1 : maxr1 - maxr2;
+}
+
+typedef enum StationListFlags {
+	SL_ORDER   = 0x01,
+	SL_RESORT  = 0x02,
+	SL_REBUILD = 0x04,
+} StationListFlags;
+
+typedef struct plstations_d {
+	const Station** sort_list;
+	uint16 list_length;
+	byte sort_type;
+	StationListFlags flags;
+	uint16 resort_timer;  //was byte refresh_counter;
+} plstations_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(plstations_d));
+
+void RebuildStationLists(void)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class == WC_STATION_LIST) {
+			WP(w, plstations_d).flags |= SL_REBUILD;
+			SetWindowDirty(w);
+		}
+	}
+}
+
+void ResortStationLists(void)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class == WC_STATION_LIST) {
+			WP(w, plstations_d).flags |= SL_RESORT;
+			SetWindowDirty(w);
+		}
+	}
+}
+
+static void BuildStationsList(plstations_d* sl, PlayerID owner, byte facilities, uint16 cargo_filter)
+{
+	uint n = 0;
+	uint i, j;
+	const Station** station_sort;
+	const Station *st;
+
+	if (!(sl->flags & SL_REBUILD)) return;
+
+	/* Create array for sorting */
+	station_sort = malloc((GetMaxStationIndex() + 1) * sizeof(station_sort[0]));
+	if (station_sort == NULL) error("Could not allocate memory for the station-sorting-list");
+
+	DEBUG(misc, 3, "Building station list for player %d", owner);
+
+	FOR_ALL_STATIONS(st) {
+		if (st->owner == owner) {
+			if (facilities & st->facilities) { //only stations with selected facilities
+				int num_waiting_cargo = 0;
+				for (j = 0; j < NUM_CARGO; j++) {
+					if (st->goods[j].waiting_acceptance & 0xFFF) {
+						num_waiting_cargo++; //count number of waiting cargo
+						if (HASBIT(cargo_filter, j)) {
+							station_sort[n++] = st;
+							break;
+						}
+					}
+				}
+				//stations without waiting cargo
+				if (num_waiting_cargo == 0 && HASBIT(cargo_filter, NUM_CARGO)) {
+					station_sort[n++] = st;
+				}
+			}
+		}
+	}
+
+	free((void*)sl->sort_list);
+	sl->sort_list = malloc(n * sizeof(sl->sort_list[0]));
+	if (n != 0 && sl->sort_list == NULL) error("Could not allocate memory for the station-sorting-list");
+	sl->list_length = n;
+
+	for (i = 0; i < n; ++i) sl->sort_list[i] = station_sort[i];
+
+	sl->flags &= ~SL_REBUILD;
+	sl->flags |= SL_RESORT;
+	free((void*)station_sort);
+}
+
+static void SortStationsList(plstations_d *sl)
+{
+	static StationSortListingTypeFunction* const _station_sorter[] = {
+		&StationNameSorter,
+		&StationTypeSorter,
+		&StationWaitingSorter,
+		&StationRatingMaxSorter
+	};
+
+	if (!(sl->flags & SL_RESORT)) return;
+
+	_internal_sort_order = sl->flags & SL_ORDER;
+	_last_station = NULL; // used for "cache" in namesorting
+	qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), _station_sorter[sl->sort_type]);
+
+	sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+	sl->flags &= ~SL_RESORT;
+}
+
+static void PlayerStationsWndProc(Window *w, WindowEvent *e)
+{
+	const PlayerID owner = w->window_number;
+	static byte facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
+	static uint16 cargo_filter = CARGO_ALL_SELECTED;
+	plstations_d *sl = &WP(w, plstations_d);
+
+	switch (e->event) {
+	case WE_CREATE: { /* set up resort timer */
+		int i;
+		for (i = 0; i < 5; i++) {
+			if (HASBIT(facilities, i)) LowerWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
+		}
+		for (i = 0; i < NUM_CARGO; i++) {
+			if (HASBIT(cargo_filter, i)) LowerWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
+		}
+		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_FACILALL, facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
+		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_CARGOALL, cargo_filter == CARGO_ALL_SELECTED);
+		SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_NOCARGOWAITING, HASBIT(cargo_filter, STATIONLIST_WIDGET_NOCARGOWAITING - NUM_CARGO));
+
+		sl->sort_list = NULL;
+		sl->flags = SL_REBUILD;
+		sl->sort_type = 0;
+		sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+		break;
+	}
+
+	case WE_PAINT: {
+		BuildStationsList(sl, owner, facilities, cargo_filter);
+		SortStationsList(sl);
+
+		SetVScrollCount(w, sl->list_length);
+
+		/* draw widgets, with player's name in the caption */
+		{
+			const Player* p = GetPlayer(owner);
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			SetDParam(2, w->vscroll.count);
+			DrawWindowWidgets(w);
+		}
+
+		{
+			int max;
+			int i, cg_ofst;
+			int x = 0, y = 0, xb = 2; // offset from top of widget
+
+			/* draw sorting criteria string */
+			DrawString(85, 26, _station_sort_listing[sl->sort_type], 0x10);
+			/* draw arrow pointing up/down for ascending/descending sorting */
+			DoDrawString(sl->flags & SL_ORDER ? DOWNARROW : UPARROW, 69, 26, 0x10);
+
+
+			x = 89;
+			y = 14;
+
+			for (i = 0; i < NUM_CARGO; i++) {
+				cg_ofst = IsWindowWidgetLowered(w, i + STATIONLIST_WIDGET_CARGOSTART) ? 2 : 1;
+
+				GfxFillRect(x + cg_ofst, y + cg_ofst, x + cg_ofst + 10 , y + cg_ofst + 7, _cargo_colours[i]);
+				DrawStringCentered(x + 6 + cg_ofst, y + cg_ofst, _cargoc.names_short[i], 0x10);
+				x += 14;
+			}
+
+			x += 6;
+			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_NOCARGOWAITING) ? 2 : 1;
+			DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_NONE, 16);
+			x += 14;
+			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_CARGOALL) ? 2 : 1;
+			DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, 16);
+
+			cg_ofst = IsWindowWidgetLowered(w, STATIONLIST_WIDGET_FACILALL) ? 2 : 1;
+			DrawString(71 + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, 16);
+
+			if (w->vscroll.count == 0) { // player has no stations
+				DrawString(xb, 40, STR_304A_NONE, 0);
+				return;
+			}
+
+			max = min(w->vscroll.pos + w->vscroll.cap, sl->list_length);
+			y = 40; // start of the list-widget
+
+			for (i = w->vscroll.pos; i < max; ++i) { // do until max number of stations of owner
+				const Station *st = sl->sort_list[i];
+				CargoID j;
+				int x;
+
+				assert(st->xy != 0);
+				assert(st->owner == owner);
+
+				SetDParam(0, st->index);
+				SetDParam(1, st->facilities);
+				x = DrawString(xb, y, STR_3049_0, 0) + 5;
+
+				// show cargo waiting and station ratings
+				for (j = 0; j != NUM_CARGO; j++) {
+					uint amount = GB(st->goods[j].waiting_acceptance, 0, 12);
+
+					if (amount != 0) {
+						StationsWndShowStationRating(x, y, j, amount, st->goods[j].rating);
+						x += 20;
+					}
+				}
+				y += 10;
+			}
+		}
+	} break;
+
+	case WE_CLICK: {
+		switch (e->we.click.widget) {
+		case STATIONLIST_WIDGET_LIST: {
+			const Station* st;
+
+			uint32 id_v = (e->we.click.pt.y - 41) / 10;
+
+			if (id_v >= w->vscroll.cap) return; // click out of bounds
+
+			id_v += w->vscroll.pos;
+
+			if (id_v >= sl->list_length) return; // click out of list bound
+
+			st = sl->sort_list[id_v];
+			assert(st->owner == owner);
+			ScrollMainWindowToTile(st->xy);
+			break;
+		}
+
+		case STATIONLIST_WIDGET_TRAIN:
+		case STATIONLIST_WIDGET_TRUCK:
+		case STATIONLIST_WIDGET_BUS:
+		case STATIONLIST_WIDGET_AIRPLANE:
+		case STATIONLIST_WIDGET_SHIP:
+			if (_ctrl_pressed) {
+				TOGGLEBIT(facilities, e->we.click.widget - STATIONLIST_WIDGET_TRAIN);
+				ToggleWidgetLoweredState(w, e->we.click.widget);
+			} else {
+				int i;
+				for (i = 0; facilities != 0; i++, facilities >>= 1) {
+					if (HASBIT(facilities, 0)) RaiseWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
+				}
+				SETBIT(facilities, e->we.click.widget - STATIONLIST_WIDGET_TRAIN);
+				LowerWindowWidget(w, e->we.click.widget);
+			}
+			SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_FACILALL, facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
+			sl->flags |= SL_REBUILD;
+			SetWindowDirty(w);
+		break;
+
+		case STATIONLIST_WIDGET_FACILALL: {
+			int i;
+			for (i = 0; i < 5; i++) {
+				LowerWindowWidget(w, i + STATIONLIST_WIDGET_TRAIN);
+			}
+			LowerWindowWidget(w, STATIONLIST_WIDGET_FACILALL);
+
+			facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
+			sl->flags |= SL_REBUILD;
+			SetWindowDirty(w);
+			break;
+		}
+		case STATIONLIST_WIDGET_CARGOALL: {
+			int i;
+			for (i = 0; i < NUM_CARGO; i++) {
+				LowerWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
+			}
+			LowerWindowWidget(w, STATIONLIST_WIDGET_NOCARGOWAITING);
+			LowerWindowWidget(w, STATIONLIST_WIDGET_CARGOALL);
+
+			cargo_filter = CARGO_ALL_SELECTED;
+			sl->flags |= SL_REBUILD;
+			SetWindowDirty(w);
+			break;
+		}
+		case STATIONLIST_WIDGET_SORTBY: /*flip sorting method asc/desc*/
+			TOGGLEBIT(sl->flags, 0); //DESC-flag
+			sl->flags |= SL_RESORT;
+			w->flags4 |= 5 << WF_TIMEOUT_SHL;
+			LowerWindowWidget(w, STATIONLIST_WIDGET_SORTBY);
+			SetWindowDirty(w);
+		break;
+
+		case STATIONLIST_WIDGET_SORTCRITERIA:
+		case STATIONLIST_WIDGET_SORTDROPBTN: /* select sorting criteria dropdown menu */
+			ShowDropDownMenu(w, _station_sort_listing, sl->sort_type, STATIONLIST_WIDGET_SORTDROPBTN, 0, 0);
+		break;
+
+		default:
+			if (e->we.click.widget >= STATIONLIST_WIDGET_CARGOSTART && e->we.click.widget <= STATIONLIST_WIDGET_NOCARGOWAITING) { //change cargo_filter
+				if (_ctrl_pressed) {
+					TOGGLEBIT(cargo_filter, e->we.click.widget - STATIONLIST_WIDGET_CARGOSTART);
+					ToggleWidgetLoweredState(w, e->we.click.widget);
+				} else {
+					int i;
+					for (i = 0; cargo_filter != 0; i++, cargo_filter >>= 1) {
+						if (HASBIT(cargo_filter, 0)) RaiseWindowWidget(w, i + STATIONLIST_WIDGET_CARGOSTART);
+					}
+					SETBIT(cargo_filter, e->we.click.widget - STATIONLIST_WIDGET_CARGOSTART);
+					LowerWindowWidget(w, e->we.click.widget);
+				}
+				sl->flags |= SL_REBUILD;
+				SetWindowWidgetLoweredState(w, STATIONLIST_WIDGET_CARGOALL, cargo_filter == CARGO_ALL_SELECTED);
+				SetWindowDirty(w);
+			}
+		}
+	} break;
+
+	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+		if (sl->sort_type != e->we.dropdown.index) {
+			// value has changed -> resort
+			sl->sort_type = e->we.dropdown.index;
+			sl->flags |= SL_RESORT;
+		}
+		SetWindowDirty(w);
+		break;
+
+	case WE_TICK:
+		if (--sl->resort_timer == 0) {
+			DEBUG(misc, 3, "Periodic rebuild station list player %d", owner);
+			sl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+			sl->flags |= VL_REBUILD;
+			SetWindowDirty(w);
+		}
+		break;
+
+	case WE_TIMEOUT:
+		RaiseWindowWidget(w, STATIONLIST_WIDGET_SORTBY);
+		SetWindowDirty(w);
+		break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 10;
+		break;
+	}
+}
+
+static const Widget _player_stations_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_3048_STATIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,               STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    37,   161, 0x0,               STR_3057_STATION_NAMES_CLICK_ON},
+{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    37,   149, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   150,   161, 0x0,               STR_RESIZE_BUTTON},
+//Index 6
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,    13,    14,    24, STR_TRAIN,         STR_USE_CTRL_TO_SELECT_MORE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    27,    14,    24, STR_LORRY,         STR_USE_CTRL_TO_SELECT_MORE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    28,    41,    14,    24, STR_BUS,           STR_USE_CTRL_TO_SELECT_MORE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    42,    55,    14,    24, STR_PLANE,         STR_USE_CTRL_TO_SELECT_MORE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    56,    69,    14,    24, STR_SHIP,          STR_USE_CTRL_TO_SELECT_MORE},
+//Index 11
+{      WWT_PANEL,   RESIZE_NONE,    14,    83,    88,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,    89,   102,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   103,   116,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   117,   130,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   131,   144,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   145,   158,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   159,   172,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   173,   186,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   187,   200,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   201,   214,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   215,   228,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   229,   242,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   243,   256,    14,    24, 0x0,               STR_USE_CTRL_TO_SELECT_MORE},
+{      WWT_PANEL,   RESIZE_NONE,    14,   257,   270,    14,    24, 0x0,               STR_NO_WAITING_CARGO},
+{      WWT_PANEL,  RESIZE_RIGHT,    14,   285,   357,    14,    24, 0x0,               STR_NULL},
+
+//26
+{      WWT_PANEL,   RESIZE_NONE,    14,    70,    83,    14,    24, 0x0,               STR_SELECT_ALL_FACILITIES},
+{      WWT_PANEL,   RESIZE_NONE,    14,   271,   284,    14,    24, 0x0,               STR_SELECT_ALL_TYPES},
+
+//28
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,    80,    25,    36, STR_SORT_BY,       STR_SORT_ORDER_TIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,    81,   232,    25,    36, 0x0,               STR_SORT_CRITERIA_TIP},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,   233,   243,    25,    36, STR_0225,          STR_SORT_CRITERIA_TIP},
+{      WWT_PANEL,  RESIZE_RIGHT,    14,   244,   357,    25,    36, 0x0,               STR_NULL},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _player_stations_desc = {
+	WDP_AUTO, WDP_AUTO, 358, 162,
+	WC_STATION_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_player_stations_widgets,
+	PlayerStationsWndProc
+};
+
+
+void ShowPlayerStations(PlayerID player)
+{
+	Window *w;
+
+	if (!IsValidPlayer(player)) return;
+
+	w = AllocateWindowDescFront(&_player_stations_desc, player);
+	if (w != NULL) {
+		w->caption_color = (byte)w->window_number;
+		w->vscroll.cap = 12;
+		w->resize.step_height = 10;
+		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
+	}
+}
+
+static const Widget _station_view_expanded_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   236,     0,    13, STR_300A_0,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   237,   248,     0,    13, 0x0,               STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   236,    14,    65, 0x0,               STR_NULL},
+{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   237,   248,    14,    65, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   248,    66,   197, 0x0,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    63,   198,   209, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    64,   128,   198,   209, STR_3033_ACCEPTS,  STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   129,   192,   198,   209, STR_0130_RENAME,   STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   193,   206,   198,   209, STR_TRAIN,         STR_SCHEDULED_TRAINS_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   207,   220,   198,   209, STR_LORRY,         STR_SCHEDULED_ROAD_VEHICLES_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   221,   234,   198,   209, STR_PLANE,         STR_SCHEDULED_AIRCRAFT_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   235,   248,   198,   209, STR_SHIP,          STR_SCHEDULED_SHIPS_TIP },
+{   WIDGETS_END},
+};
+
+static const Widget _station_view_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   236,     0,    13, STR_300A_0,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   237,   248,     0,    13, 0x0,               STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   236,    14,    65, 0x0,               STR_NULL},
+{  WWT_SCROLLBAR,   RESIZE_NONE,    14,   237,   248,    14,    65, 0x0,               STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   248,    66,    97, 0x0,               STR_NULL},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    63,    98,   109, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,    64,   128,    98,   109, STR_3032_RATINGS,  STR_3054_SHOW_STATION_RATINGS},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   129,   192,    98,   109, STR_0130_RENAME,   STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   193,   206,    98,   109, STR_TRAIN,         STR_SCHEDULED_TRAINS_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   207,   220,    98,   109, STR_LORRY,         STR_SCHEDULED_ROAD_VEHICLES_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   221,   234,    98,   109, STR_PLANE,         STR_SCHEDULED_AIRCRAFT_TIP },
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   235,   248,    98,   109, STR_SHIP,          STR_SCHEDULED_SHIPS_TIP },
+{   WIDGETS_END},
+};
+
+static void DrawStationViewWindow(Window *w)
+{
+	StationID station_id = w->window_number;
+	const Station* st = GetStation(station_id);
+	uint i;
+	uint num;
+	int x,y;
+	int pos;
+	StringID str;
+
+	num = 1;
+	for (i = 0; i != NUM_CARGO; i++) {
+		if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) {
+			num++;
+			if (st->goods[i].enroute_from != station_id) num++;
+		}
+	}
+	SetVScrollCount(w, num);
+
+	SetWindowWidgetDisabledState(w,  9, st->owner != _local_player);
+	SetWindowWidgetDisabledState(w, 10, !(st->facilities & FACIL_TRAIN));
+	SetWindowWidgetDisabledState(w, 11, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
+	SetWindowWidgetDisabledState(w, 12, !(st->facilities & FACIL_AIRPORT));
+	SetWindowWidgetDisabledState(w, 13, !(st->facilities & FACIL_DOCK));
+
+	SetDParam(0, st->index);
+	SetDParam(1, st->facilities);
+	DrawWindowWidgets(w);
+
+	x = 2;
+	y = 15;
+	pos = w->vscroll.pos;
+
+	if (--pos < 0) {
+		str = STR_00D0_NOTHING;
+		for (i = 0; i != NUM_CARGO; i++) {
+			if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) str = STR_EMPTY;
+		}
+		SetDParam(0, str);
+		DrawString(x, y, STR_0008_WAITING, 0);
+		y += 10;
+	}
+
+	i = 0;
+	do {
+		uint waiting = GB(st->goods[i].waiting_acceptance, 0, 12);
+		if (waiting == 0) continue;
+
+		num = (waiting + 5) / 10;
+		if (num != 0) {
+			int cur_x = x;
+			num = min(num, 23);
+			do {
+				DrawSprite(_cargoc.sprites[i], cur_x, y);
+				cur_x += 10;
+			} while (--num);
+		}
+
+		if ( st->goods[i].enroute_from == station_id) {
+			if (--pos < 0) {
+				SetDParam(1, waiting);
+				SetDParam(0, i);
+				DrawStringRightAligned(x + 234, y, STR_0009, 0);
+				y += 10;
+			}
+		} else {
+			/* enroute */
+			if (--pos < 0) {
+				SetDParam(1, waiting);
+				SetDParam(0, i);
+				DrawStringRightAligned(x + 234, y, STR_000A_EN_ROUTE_FROM, 0);
+				y += 10;
+			}
+
+			if (pos > -5 && --pos < 0) {
+				SetDParam(0, st->goods[i].enroute_from);
+				DrawStringRightAligned(x + 234, y, STR_000B, 0);
+				y += 10;
+			}
+		}
+	} while (pos > -5 && ++i != NUM_CARGO);
+
+	if (IsWindowOfPrototype(w, _station_view_widgets)) {
+		char *b = _userstring;
+		bool first = true;
+
+		b = InlineString(b, STR_000C_ACCEPTS);
+
+		for (i = 0; i != NUM_CARGO; i++) {
+			if (b >= endof(_userstring) - 5 - 1) break;
+			if (st->goods[i].waiting_acceptance & 0x8000) {
+				if (first) {
+					first = false;
+				} else {
+					/* Add a comma if this is not the first item */
+					*b++ = ',';
+					*b++ = ' ';
+				}
+				b = InlineString(b, _cargoc.names_s[i]);
+			}
+		}
+
+		/* If first is still true then no cargo is accepted */
+		if (first) b = InlineString(b, STR_00D0_NOTHING);
+
+		*b = '\0';
+		DrawStringMultiLine(2, 67, STR_SPEC_USERSTRING, 245);
+	} else {
+		DrawString(2, 67, STR_3034_LOCAL_RATING_OF_TRANSPORT, 0);
+
+		y = 77;
+		for (i = 0; i != NUM_CARGO; i++) {
+			if (st->goods[i].enroute_from != INVALID_STATION) {
+				SetDParam(0, _cargoc.names_s[i]);
+				SetDParam(2, st->goods[i].rating * 101 >> 8);
+				SetDParam(1, STR_3035_APPALLING + (st->goods[i].rating >> 5));
+				DrawString(8, y, STR_303D, 0);
+				y += 10;
+			}
+		}
+	}
+}
+
+
+static void StationViewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawStationViewWindow(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 7:
+			ScrollMainWindowToTile(GetStation(w->window_number)->xy);
+			break;
+
+		case 8:
+			SetWindowDirty(w);
+
+			/* toggle height/widget set */
+			if (IsWindowOfPrototype(w, _station_view_expanded_widgets)) {
+				AssignWidgetToWindow(w, _station_view_widgets);
+				w->height = 110;
+			} else {
+				AssignWidgetToWindow(w, _station_view_expanded_widgets);
+				w->height = 210;
+			}
+
+			SetWindowDirty(w);
+			break;
+
+		case 9: {
+			SetDParam(0, w->window_number);
+			ShowQueryString(STR_STATION, STR_3030_RENAME_STATION_LOADING, 31, 180, w, CS_ALPHANUMERAL);
+		} break;
+
+		case 10: { /* Show a list of scheduled trains to this station */
+			const Station *st = GetStation(w->window_number);
+			ShowVehicleListWindow(st->owner, w->window_number, VEH_Train);
+			break;
+		}
+
+		case 11: { /* Show a list of scheduled road-vehicles to this station */
+			const Station *st = GetStation(w->window_number);
+			ShowVehicleListWindow(st->owner, w->window_number, VEH_Road);
+			break;
+		}
+
+		case 12: { /* Show a list of scheduled aircraft to this station */
+			const Station *st = GetStation(w->window_number);
+			/* Since oilrigs have no owners, show the scheduled aircraft of current player */
+			PlayerID owner = (st->owner == OWNER_NONE) ? _current_player : st->owner;
+			ShowVehicleListWindow(owner, w->window_number, VEH_Aircraft);
+			break;
+		}
+
+		case 13: { /* Show a list of scheduled ships to this station */
+			const Station *st = GetStation(w->window_number);
+			/* Since oilrigs/bouys have no owners, show the scheduled ships of current player */
+			PlayerID owner = (st->owner == OWNER_NONE) ? _current_player : st->owner;
+			ShowVehicleListWindow(owner, w->window_number, VEH_Ship);
+			break;
+		}
+		}
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_RENAME_STATION | CMD_MSG(STR_3031_CAN_T_RENAME_STATION));
+		}
+		break;
+
+	case WE_DESTROY: {
+		WindowNumber wno =
+			(w->window_number << 16) | GetStation(w->window_number)->owner;
+
+		DeleteWindowById(WC_TRAINS_LIST, wno);
+		DeleteWindowById(WC_ROADVEH_LIST, wno);
+		DeleteWindowById(WC_SHIPS_LIST, wno);
+		DeleteWindowById(WC_AIRCRAFT_LIST, wno);
+		break;
+	}
+	}
+}
+
+
+static const WindowDesc _station_view_desc = {
+	WDP_AUTO, WDP_AUTO, 249, 110,
+	WC_STATION_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_station_view_widgets,
+	StationViewWndProc
+};
+
+void ShowStationViewWindow(StationID station)
+{
+	Window *w;
+
+	w = AllocateWindowDescFront(&_station_view_desc, station);
+	if (w != NULL) {
+		PlayerID owner = GetStation(w->window_number)->owner;
+		if (owner != OWNER_NONE) w->caption_color = owner;
+		w->vscroll.cap = 5;
+	}
+}
deleted file mode 100644
--- a/src/station_map.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "station_map.h"
-
-
-StationType GetStationType(TileIndex t)
-{
-	assert(IsTileType(t, MP_STATION));
-	if (IsRailwayStation(t)) return STATION_RAIL;
-	if (IsAirport(t)) return STATION_AIRPORT;
-	if (IsTruckStop(t)) return STATION_TRUCK;
-	if (IsBusStop(t)) return STATION_BUS;
-	if (IsOilRig(t)) return STATION_OILRIG;
-	if (IsDock(t)) return STATION_DOCK;
-	assert(IsBuoy_(t));
-	return STATION_BUOY;
-}
new file mode 100644
--- /dev/null
+++ b/src/station_map.cpp
@@ -0,0 +1,19 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "station_map.h"
+
+
+StationType GetStationType(TileIndex t)
+{
+	assert(IsTileType(t, MP_STATION));
+	if (IsRailwayStation(t)) return STATION_RAIL;
+	if (IsAirport(t)) return STATION_AIRPORT;
+	if (IsTruckStop(t)) return STATION_TRUCK;
+	if (IsBusStop(t)) return STATION_BUS;
+	if (IsOilRig(t)) return STATION_OILRIG;
+	if (IsDock(t)) return STATION_DOCK;
+	assert(IsBuoy_(t));
+	return STATION_BUOY;
+}
deleted file mode 100644
--- a/src/strgen/strgen.c
+++ /dev/null
@@ -1,1399 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../macros.h"
-#include "../string.h"
-#include "../table/control_codes.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#if (!defined(WIN32) && !defined(WIN64)) || defined(__CYGWIN__)
-#include <unistd.h>
-#endif
-
-#if defined WIN32 || defined __WATCOMC__
-#include <direct.h>
-#endif /* WIN32 || __WATCOMC__ */
-
-#ifdef __MORPHOS__
-#ifdef stderr
-#undef stderr
-#endif
-#define stderr stdout
-#endif /* __MORPHOS__ */
-
-#ifdef __WATCOMC__
-	uint _map_log_x;     // an unpleasant hack required because Watcom is insisting on
-	uint _map_size_x;    // these variables being valid references in map.h
-	uint _map_size_y;
-	uint _map_tile_mask;
-	uint _map_size;
-#endif /* __WATCOMC__ */
-
-/* Compiles a list of strings into a compiled string list */
-
-typedef void (*ParseCmdProc)(char *buf, int value);
-
-typedef struct LanguagePackHeader {
-	uint32 ident;
-	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
-	char name[32];      // the international name of this language
-	char own_name[32];  // the localized name of this language
-	char isocode[16];   // the ISO code for the language (not country code)
-	uint16 offsets[32]; // the offsets
-	byte plural_form;   // plural form index
-	byte pad[3];        // pad header to be a multiple of 4
-} LanguagePackHeader;
-
-typedef struct CmdStruct {
-	const char *cmd;
-	ParseCmdProc proc;
-	long value;
-	int8 consumes;
-	byte flags;
-} CmdStruct;
-
-enum {
-	C_DONTCOUNT = 1,
-	C_CASE      = 2,
-};
-
-
-typedef struct Case {
-	int caseidx;
-	char *string;
-	struct Case *next;
-} Case;
-
-static bool _masterlang;
-static bool _translated;
-static const char* _file = "(unknown file)";
-static int _cur_line;
-static int _errors, _warnings;
-
-typedef struct LangString {
-	char *name;            // Name of the string
-	char *english;         // English text
-	char *translated;      // Translated text
-	uint16 hash_next;      // next hash entry
-	uint16 index;
-	int line;              // line of string in source-file
-	Case *english_case;    // cases for english
-	Case *translated_case; // cases for foreign
-} LangString;
-
-static LangString *_strings[65536];
-
-
-#define HASH_SIZE 32767
-static uint16 _hash_head[HASH_SIZE];
-
-static byte _put_buf[4096];
-static int _put_pos;
-static int _next_string_id;
-
-static uint32 _hash;
-static char _lang_name[32], _lang_ownname[32], _lang_isocode[16];
-static byte _lang_pluralform;
-#define MAX_NUM_GENDER 8
-static char _genders[MAX_NUM_GENDER][8];
-static int _numgenders;
-
-// contains the name of all cases.
-#define MAX_NUM_CASES 50
-static char _cases[MAX_NUM_CASES][16];
-static int _numcases;
-
-// for each plural value, this is the number of plural forms.
-static const byte _plural_form_counts[] = { 2, 1, 2, 3, 3, 3, 3, 3, 4 };
-
-static const char *_cur_ident;
-
-typedef struct CmdPair {
-	const CmdStruct *a;
-	char *v;
-} CmdPair;
-
-typedef struct ParsedCommandStruct {
-	int np;
-	CmdPair pairs[32];
-	const CmdStruct *cmd[32]; // ordered by param #
-} ParsedCommandStruct;
-
-// Used when generating some advanced commands.
-static ParsedCommandStruct _cur_pcs;
-static int _cur_argidx;
-
-static uint HashStr(const char *s)
-{
-	uint hash = 0;
-	for (; *s != '\0'; s++) hash = ROL(hash, 3) ^ *s;
-	return hash % HASH_SIZE;
-}
-
-static void HashAdd(const char *s, LangString *ls)
-{
-	uint hash = HashStr(s);
-	ls->hash_next = _hash_head[hash];
-	_hash_head[hash] = ls->index + 1;
-}
-
-static LangString *HashFind(const char *s)
-{
-	int idx = _hash_head[HashStr(s)];
-
-	while (--idx >= 0) {
-		LangString* ls = _strings[idx];
-
-		if (strcmp(ls->name, s) == 0) return ls;
-		idx = ls->hash_next;
-	}
-	return NULL;
-}
-
-#ifdef _MSC_VER
-# define LINE_NUM_FMT "(%d)"
-#else
-# define LINE_NUM_FMT ":%d"
-#endif
-
-static void CDECL warning(const char *s, ...)
-{
-	char buf[1024];
-	va_list va;
-	va_start(va, s);
-	vsnprintf(buf, lengthof(buf), s, va);
-	va_end(va);
-	fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf);
-	_warnings++;
-}
-
-void CDECL error(const char *s, ...)
-{
-	char buf[1024];
-	va_list va;
-	va_start(va, s);
-	vsnprintf(buf, lengthof(buf), s, va);
-	va_end(va);
-	fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf);
-	_errors++;
-}
-
-
-static void NORETURN CDECL fatal(const char *s, ...)
-{
-	char buf[1024];
-	va_list va;
-	va_start(va, s);
-	vsnprintf(buf, lengthof(buf), s, va);
-	va_end(va);
-	fprintf(stderr, "%s" LINE_NUM_FMT ": FATAL: %s\n", _file, _cur_line, buf);
-	exit(1);
-}
-
-static void PutByte(byte c)
-{
-	if (_put_pos == lengthof(_put_buf)) fatal("Put buffer too small");
-	_put_buf[_put_pos++] = c;
-}
-
-
-static void PutUtf8(uint32 value)
-{
-	if (value < 0x80) {
-		PutByte(value);
-	} else if (value < 0x800) {
-		PutByte(0xC0 + GB(value,  6, 5));
-		PutByte(0x80 + GB(value,  0, 6));
-	} else if (value < 0x10000) {
-		PutByte(0xE0 + GB(value, 12, 4));
-		PutByte(0x80 + GB(value,  6, 6));
-		PutByte(0x80 + GB(value,  0, 6));
-	} else if (value < 0x110000) {
-		PutByte(0xF0 + GB(value, 18, 3));
-		PutByte(0x80 + GB(value, 12, 6));
-		PutByte(0x80 + GB(value,  6, 6));
-		PutByte(0x80 + GB(value,  0, 6));
-	} else {
-		warning("Invalid unicode value U+0x%X", value);
-	}
-}
-
-
-size_t Utf8Validate(const char *s)
-{
-	uint32 c;
-
-	if (!HASBIT(s[0], 7)) {
-		/* 1 byte */
-		return 1;
-	} else if (GB(s[0], 5, 3) == 6 && IsUtf8Part(s[1])) {
-		/* 2 bytes */
-		c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
-		if (c >= 0x80) return 2;
-	} else if (GB(s[0], 4, 4) == 14 && IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
-		/* 3 bytes */
-		c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
-		if (c >= 0x800) return 3;
-	} else if (GB(s[0], 3, 5) == 30 && IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
-		/* 4 bytes */
-		c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
-		if (c >= 0x10000 && c <= 0x10FFFF) return 4;
-	}
-
-	return 0;
-}
-
-
-static void EmitSingleChar(char *buf, int value)
-{
-	if (*buf != '\0') warning("Ignoring trailing letters in command");
-	PutUtf8(value);
-}
-
-
-static void EmitSetX(char *buf, int value)
-{
-	char *err;
-	int x = strtol(buf, &err, 0);
-	if (*err != 0) fatal("SetX param invalid");
-	PutUtf8(SCC_SETX);
-	PutByte((byte)x);
-}
-
-
-static void EmitSetXY(char *buf, int value)
-{
-	char *err;
-	int x;
-	int y;
-
-	x = strtol(buf, &err, 0);
-	if (*err != ' ') fatal("SetXY param invalid");
-	y = strtol(err + 1, &err, 0);
-	if (*err != 0) fatal("SetXY param invalid");
-
-	PutUtf8(SCC_SETXY);
-	PutByte((byte)x);
-	PutByte((byte)y);
-}
-
-// The plural specifier looks like
-// {NUM} {PLURAL -1 passenger passengers} then it picks either passenger/passengers depending on the count in NUM
-
-// This is encoded like
-//  CommandByte <ARG#> <NUM> {Length of each string} {each string}
-
-bool ParseRelNum(char **buf, int *value)
-{
-	const char* s = *buf;
-	char* end;
-	bool rel = false;
-	int v;
-
-	while (*s == ' ' || *s == '\t') s++;
-	if (*s == '+') {
-		rel = true;
-		s++;
-	}
-	v = strtol(s, &end, 0);
-	if (end == s) return false;
-	if (rel || v < 0) {
-		*value += v;
-	} else {
-		*value = v;
-	}
-	*buf = end;
-	return true;
-}
-
-// Parse out the next word, or NULL
-char *ParseWord(char **buf)
-{
-	char *s = *buf, *r;
-
-	while (*s == ' ' || *s == '\t') s++;
-	if (*s == '\0') return NULL;
-
-	if (*s == '"') {
-		r = ++s;
-		// parse until next " or NUL
-		for (;;) {
-			if (*s == '\0') break;
-			if (*s == '"') {
-				*s++ = '\0';
-				break;
-			}
-			s++;
-		}
-	} else {
-		// proceed until whitespace or NUL
-		r = s;
-		for (;;) {
-			if (*s == '\0') break;
-			if (*s == ' ' || *s == '\t') {
-				*s++ = '\0';
-				break;
-			}
-			s++;
-		}
-	}
-	*buf = s;
-	return r;
-}
-
-// Forward declaration
-static int TranslateArgumentIdx(int arg);
-
-static void EmitWordList(const char* const* words, uint nw)
-{
-	uint i;
-	uint j;
-
-	PutByte(nw);
-	for (i = 0; i < nw; i++) PutByte(strlen(words[i]));
-	for (i = 0; i < nw; i++) {
-		for (j = 0; words[i][j] != '\0'; j++) PutByte(words[i][j]);
-	}
-}
-
-static void EmitPlural(char *buf, int value)
-{
-	int argidx = _cur_argidx;
-	const char* words[5];
-	int nw = 0;
-
-	// Parse out the number, if one exists. Otherwise default to prev arg.
-	if (!ParseRelNum(&buf, &argidx)) argidx--;
-
-	// Parse each string
-	for (nw = 0; nw < 5; nw++) {
-		words[nw] = ParseWord(&buf);
-		if (words[nw] == NULL) break;
-	}
-
-	if (nw == 0)
-		fatal("%s: No plural words", _cur_ident);
-
-	if (_plural_form_counts[_lang_pluralform] != nw) {
-		if (_translated) {
-			fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident,
-				_plural_form_counts[_lang_pluralform], nw);
-		} else {
-			warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
-			if (nw > _plural_form_counts[_lang_pluralform]) {
-				nw = _plural_form_counts[_lang_pluralform];
-			} else {
-				for (; nw < _plural_form_counts[_lang_pluralform]; nw++) {
-					words[nw] = words[nw - 1];
-				}
-			}
-		}
-	}
-
-	PutUtf8(SCC_PLURAL_LIST);
-	PutByte(TranslateArgumentIdx(argidx));
-	EmitWordList(words, nw);
-}
-
-
-static void EmitGender(char *buf, int value)
-{
-	int argidx = _cur_argidx;
-	uint nw;
-
-	if (buf[0] == '=') {
-		buf++;
-
-		// This is a {G=DER} command
-		for (nw = 0; ; nw++) {
-			if (nw >= 8) fatal("G argument '%s' invalid", buf);
-			if (strcmp(buf, _genders[nw]) == 0) break;
-		}
-		// now nw contains the gender index
-		PutUtf8(SCC_GENDER_INDEX);
-		PutByte(nw);
-	} else {
-		const char* words[8];
-
-		// This is a {G 0 foo bar two} command.
-		// If no relative number exists, default to +0
-		if (!ParseRelNum(&buf, &argidx)) {}
-
-		for (nw = 0; nw < 8; nw++) {
-			words[nw] = ParseWord(&buf);
-			if (words[nw] == NULL) break;
-		}
-		if (nw != _numgenders) fatal("Bad # of arguments for gender command");
-		PutUtf8(SCC_GENDER_LIST);
-		PutByte(TranslateArgumentIdx(argidx));
-		EmitWordList(words, nw);
-	}
-}
-
-
-static const CmdStruct _cmd_structs[] = {
-	// Update position
-	{"SETX",  EmitSetX,  SCC_SETX,  0, 0},
-	{"SETXY", EmitSetXY, SCC_SETXY, 0, 0},
-
-	// Font size
-	{"TINYFONT", EmitSingleChar, SCC_TINYFONT, 0, 0},
-	{"BIGFONT",  EmitSingleChar, SCC_BIGFONT,  0, 0},
-
-	// Colors
-	{"BLUE",    EmitSingleChar, SCC_BLUE,    0, 0},
-	{"SILVER",  EmitSingleChar, SCC_SILVER,  0, 0},
-	{"GOLD",    EmitSingleChar, SCC_GOLD,    0, 0},
-	{"RED",     EmitSingleChar, SCC_RED,     0, 0},
-	{"PURPLE",  EmitSingleChar, SCC_PURPLE,  0, 0},
-	{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, 0},
-	{"ORANGE",  EmitSingleChar, SCC_ORANGE,  0, 0},
-	{"GREEN",   EmitSingleChar, SCC_GREEN,   0, 0},
-	{"YELLOW",  EmitSingleChar, SCC_YELLOW,  0, 0},
-	{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, 0},
-	{"CREAM",   EmitSingleChar, SCC_CREAM,   0, 0},
-	{"BROWN",   EmitSingleChar, SCC_BROWN,   0, 0},
-	{"WHITE",   EmitSingleChar, SCC_WHITE,   0, 0},
-	{"LTBLUE",  EmitSingleChar, SCC_LTBLUE,  0, 0},
-	{"GRAY",    EmitSingleChar, SCC_GRAY,    0, 0},
-	{"DKBLUE",  EmitSingleChar, SCC_DKBLUE,  0, 0},
-	{"BLACK",   EmitSingleChar, SCC_BLACK,   0, 0},
-
-	{"CURRCOMPACT",   EmitSingleChar, SCC_CURRENCY_COMPACT,    1, 0}, // compact currency (32 bits)
-	{"REV",           EmitSingleChar, SCC_REVISION,            0, 0}, // openttd revision string
-	{"SHORTCARGO",    EmitSingleChar, SCC_CARGO_SHORT,         2, 0}, // short cargo description, only ### tons, or ### litres
-	{"CURRCOMPACT64", EmitSingleChar, SCC_CURRENCY_COMPACT_64, 2, 0}, // compact currency 64 bits
-
-	// These are special versions of {STRING1}
-	// The first string includes the second string.
-	{"COMPANY",    EmitSingleChar, SCC_STRING1, 1, 0},
-	{"PLAYERNAME", EmitSingleChar, SCC_STRING1, 1, 0},
-	{"VEHICLE",    EmitSingleChar, SCC_STRING1, 1, 0},
-
-	{"STRING1", EmitSingleChar, SCC_STRING1, 1, C_CASE}, // included string that consumes ONE argument
-	{"STRING2", EmitSingleChar, SCC_STRING2, 2, C_CASE}, // included string that consumes TWO arguments
-	{"STRING3", EmitSingleChar, SCC_STRING3, 3, C_CASE}, // included string that consumes THREE arguments
-	{"STRING4", EmitSingleChar, SCC_STRING4, 4, C_CASE}, // included string that consumes FOUR arguments
-	{"STRING5", EmitSingleChar, SCC_STRING5, 5, C_CASE}, // included string that consumes FIVE arguments
-
-	{"STATIONFEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, 0}, // station features string, icons of the features
-	{"INDUSTRY",        EmitSingleChar, SCC_INDUSTRY_NAME,    1, 0}, // industry, takes an industry #
-	{"CARGO",           EmitSingleChar, SCC_CARGO,            2, 0},
-	{"POWER",           EmitSingleChar, SCC_POWER,            1, 0},
-	{"VOLUME",          EmitSingleChar, SCC_VOLUME,           1, 0},
-	{"VOLUME_S",        EmitSingleChar, SCC_VOLUME_SHORT,     1, 0},
-	{"WEIGHT",          EmitSingleChar, SCC_WEIGHT,           1, 0},
-	{"WEIGHT_S",        EmitSingleChar, SCC_WEIGHT_SHORT,     1, 0},
-	{"FORCE",           EmitSingleChar, SCC_FORCE,            1, 0},
-	{"VELOCITY",        EmitSingleChar, SCC_VELOCITY,         1, 0},
-
-	{"P", EmitPlural, 0, 0, C_DONTCOUNT}, // plural specifier
-	{"G", EmitGender, 0, 0, C_DONTCOUNT}, // gender specifier
-
-	{"DATE_TINY",  EmitSingleChar, SCC_DATE_TINY, 1, 0},
-	{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, 0},
-	{"DATE_LONG",  EmitSingleChar, SCC_DATE_LONG, 1, 0},
-
-	{"SKIP", EmitSingleChar, SCC_SKIP, 1, 0},
-
-	{"STRING", EmitSingleChar, SCC_STRING, 1, C_CASE},
-
-	// Numbers
-	{"COMMA", EmitSingleChar, SCC_COMMA, 1, 0}, // Number with comma
-	{"NUM",   EmitSingleChar, SCC_NUM,   1, 0}, // Signed number
-
-	{"CURRENCY",   EmitSingleChar, SCC_CURRENCY,    1, 0},
-	{"CURRENCY64", EmitSingleChar, SCC_CURRENCY_64, 2, 0},
-
-	{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, 0}, // waypoint name
-	{"STATION",  EmitSingleChar, SCC_STATION_NAME,  1, 0},
-	{"TOWN",     EmitSingleChar, SCC_TOWN_NAME,     1, 0},
-
-	// 0x9D is used for the pseudo command SETCASE
-	// 0x9E is used for case switching
-
-	{"",               EmitSingleChar, '\n',               0, C_DONTCOUNT},
-	{"{",              EmitSingleChar, '{',                0, C_DONTCOUNT},
-	{"UPARROW",        EmitSingleChar, SCC_UPARROW,        0, 0},
-	{"SMALLUPARROW",   EmitSingleChar, SCC_SMALLUPARROW,   0, 0},
-	{"SMALLDOWNARROW", EmitSingleChar, SCC_SMALLDOWNARROW, 0, 0},
-	{"TRAIN",          EmitSingleChar, SCC_TRAIN,          0, 0},
-	{"LORRY",          EmitSingleChar, SCC_LORRY,          0, 0},
-	{"BUS",            EmitSingleChar, SCC_BUS,            0, 0},
-	{"PLANE",          EmitSingleChar, SCC_PLANE,          0, 0},
-	{"SHIP",           EmitSingleChar, SCC_SHIP,           0, 0},
-	{"NBSP",           EmitSingleChar, 0xA0,               0, C_DONTCOUNT},
-	{"CENT",           EmitSingleChar, 0xA2,               0, C_DONTCOUNT},
-	{"POUNDSIGN",      EmitSingleChar, 0xA3,               0, C_DONTCOUNT},
-	{"EURO",           EmitSingleChar, 0x20AC,             0, C_DONTCOUNT},
-	{"YENSIGN",        EmitSingleChar, 0xA5,               0, C_DONTCOUNT},
-	{"COPYRIGHT",      EmitSingleChar, 0xA9,               0, C_DONTCOUNT},
-	{"DOWNARROW",      EmitSingleChar, SCC_DOWNARROW,      0, C_DONTCOUNT},
-	{"CHECKMARK",      EmitSingleChar, SCC_CHECKMARK,      0, C_DONTCOUNT},
-	{"CROSS",          EmitSingleChar, SCC_CROSS,          0, C_DONTCOUNT},
-	{"REGISTERED",     EmitSingleChar, 0xAE,               0, C_DONTCOUNT},
-	{"RIGHTARROW",     EmitSingleChar, SCC_RIGHTARROW,     0, C_DONTCOUNT},
-	{"SMALLLEFTARROW", EmitSingleChar, SCC_LESSTHAN,       0, C_DONTCOUNT},
-	{"SMALLRIGHTARROW",EmitSingleChar, SCC_GREATERTHAN,    0, C_DONTCOUNT},
-};
-
-
-static const CmdStruct *FindCmd(const char *s, int len)
-{
-	const CmdStruct* cs;
-
-	for (cs = _cmd_structs; cs != endof(_cmd_structs); cs++) {
-		if (strncmp(cs->cmd, s, len) == 0 && cs->cmd[len] == '\0') return cs;
-	}
-	return NULL;
-}
-
-static uint ResolveCaseName(const char *str, uint len)
-{
-	uint i;
-
-	for (i = 0; i < MAX_NUM_CASES; i++) {
-		if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1;
-	}
-	fatal("Invalid case-name '%s'", str);
-}
-
-
-// returns NULL on eof
-// else returns command struct
-static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei)
-{
-	const char *s = *str, *start;
-	const CmdStruct *cmd;
-	byte c;
-
-	*argno = -1;
-	*casei = -1;
-
-	// Scan to the next command, exit if there's no next command.
-	for (; *s != '{'; s++) {
-		if (*s == '\0') return NULL;
-	}
-	s++; // Skip past the {
-
-	if (*s >= '0' && *s <= '9') {
-		char *end;
-
-		*argno = strtoul(s, &end, 0);
-		if (*end != ':') fatal("missing arg #");
-		s = end + 1;
-	}
-
-	// parse command name
-	start = s;
-	do {
-		c = *s++;
-	} while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0);
-
-	cmd = FindCmd(start, s - start - 1);
-	if (cmd == NULL) {
-		error("Undefined command '%.*s'", s - start - 1, start);
-		return NULL;
-	}
-
-	if (c == '.') {
-		const char *casep = s;
-
-		if (!(cmd->flags & C_CASE))
-			fatal("Command '%s' can't have a case", cmd->cmd);
-
-		do c = *s++; while (c != '}' && c != ' ' && c != '\0');
-		*casei = ResolveCaseName(casep, s - casep - 1);
-	}
-
-	if (c == '\0') {
-		error("Missing } from command '%s'", start);
-		return NULL;
-	}
-
-
-	if (c != '}') {
-		if (c == '=') s--;
-		// copy params
-		start = s;
-		for (;;) {
-			c = *s++;
-			if (c == '}') break;
-			if (c == '\0') {
-				error("Missing } from command '%s'", start);
-				return NULL;
-			}
-			if (s - start == 250) fatal("param command too long");
-			*param++ = c;
-		}
-	}
-	*param = '\0';
-
-	*str = s;
-
-	return cmd;
-}
-
-
-static void HandlePragma(char *str)
-{
-	if (!memcmp(str, "id ", 3)) {
-		_next_string_id = strtoul(str + 3, NULL, 0);
-	} else if (!memcmp(str, "name ", 5)) {
-		ttd_strlcpy(_lang_name, str + 5, sizeof(_lang_name));
-	} else if (!memcmp(str, "ownname ", 8)) {
-		ttd_strlcpy(_lang_ownname, str + 8, sizeof(_lang_ownname));
-	} else if (!memcmp(str, "isocode ", 8)) {
-		ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode));
-	} else if (!memcmp(str, "plural ", 7)) {
-		_lang_pluralform = atoi(str + 7);
-		if (_lang_pluralform >= lengthof(_plural_form_counts))
-			fatal("Invalid pluralform %d", _lang_pluralform);
-	} else if (!memcmp(str, "gender ", 7)) {
-		char* buf = str + 7;
-
-		for (;;) {
-			const char* s = ParseWord(&buf);
-
-			if (s == NULL) break;
-			if (_numgenders >= MAX_NUM_GENDER) fatal("Too many genders, max %d", MAX_NUM_GENDER);
-			ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders]));
-			_numgenders++;
-		}
-	} else if (!memcmp(str, "case ", 5)) {
-		char* buf = str + 5;
-
-		for (;;) {
-			const char* s = ParseWord(&buf);
-
-			if (s == NULL) break;
-			if (_numcases >= MAX_NUM_CASES) fatal("Too many cases, max %d", MAX_NUM_CASES);
-			ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases]));
-			_numcases++;
-		}
-	} else {
-		fatal("unknown pragma '%s'", str);
-	}
-}
-
-static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings)
-{
-	char param[100];
-	int argno;
-	int argidx = 0;
-	int casei;
-
-	memset(p, 0, sizeof(*p));
-
-	for (;;) {
-		// read until next command from a.
-		const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei);
-
-		if (ar == NULL) break;
-
-		// Sanity checking
-		if (argno != -1 && ar->consumes == 0) fatal("Non consumer param can't have a paramindex");
-
-		if (ar->consumes) {
-			if (argno != -1) argidx = argno;
-			if (argidx < 0 || argidx >= lengthof(p->cmd)) fatal("invalid param idx %d", argidx);
-			if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) fatal("duplicate param idx %d", argidx);
-
-			p->cmd[argidx++] = ar;
-		} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
-			if (p->np >= lengthof(p->pairs)) fatal("too many commands in string, max %d", lengthof(p->pairs));
-			p->pairs[p->np].a = ar;
-			p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : "";
-			p->np++;
-		}
-	}
-}
-
-
-static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a)
-{
-	if (a == NULL) return NULL;
-
-	if (strcmp(a->cmd, "STRING1") == 0 ||
-			strcmp(a->cmd, "STRING2") == 0 ||
-			strcmp(a->cmd, "STRING3") == 0 ||
-			strcmp(a->cmd, "STRING4") == 0 ||
-			strcmp(a->cmd, "STRING5") == 0) {
-		return FindCmd("STRING", 6);
-	}
-
-	if (strcmp(a->cmd, "SKIP") == 0) return NULL;
-
-	return a;
-}
-
-
-static bool CheckCommandsMatch(char *a, char *b, const char *name)
-{
-	ParsedCommandStruct templ;
-	ParsedCommandStruct lang;
-	int i,j;
-	bool result = true;
-
-	ExtractCommandString(&templ, b, true);
-	ExtractCommandString(&lang, a, true);
-
-	// For each string in templ, see if we find it in lang
-	if (templ.np != lang.np) {
-		warning("%s: template string and language string have a different # of commands", name);
-		result = false;
-	}
-
-	for (i = 0; i < templ.np; i++) {
-		// see if we find it in lang, and zero it out
-		bool found = false;
-		for (j = 0; j < lang.np; j++) {
-			if (templ.pairs[i].a == lang.pairs[j].a &&
-					strcmp(templ.pairs[i].v, lang.pairs[j].v) == 0) {
-				// it was found in both. zero it out from lang so we don't find it again
-				lang.pairs[j].a = NULL;
-				found = true;
-				break;
-			}
-		}
-
-		if (!found) {
-			warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
-			result = false;
-		}
-	}
-
-	// if we reach here, all non consumer commands match up.
-	// Check if the non consumer commands match up also.
-	for (i = 0; i < lengthof(templ.cmd); i++) {
-		if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) {
-			warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i,
-				lang.cmd[i]  == NULL ? "<empty>" : lang.cmd[i]->cmd,
-				templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd);
-			result = false;
-		}
-	}
-
-	return result;
-}
-
-static void HandleString(char *str, bool master)
-{
-	char *s,*t;
-	LangString *ent;
-	char *casep;
-
-	if (*str == '#') {
-		if (str[1] == '#' && str[2] != '#') HandlePragma(str + 2);
-		return;
-	}
-
-	// Ignore comments & blank lines
-	if (*str == ';' || *str == ' ' || *str == '\0') return;
-
-	s = strchr(str, ':');
-	if (s == NULL) {
-		error("Line has no ':' delimiter");
-		return;
-	}
-
-	// Trim spaces.
-	// After this str points to the command name, and s points to the command contents
-	for (t = s; t > str && (t[-1] == ' ' || t[-1] == '\t'); t--);
-	*t = 0;
-	s++;
-
-	/* Check string is valid UTF-8 */
-	{
-		const char *tmp;
-		for (tmp = s; *tmp != '\0';) {
-			size_t len = Utf8Validate(tmp);
-			if (len == 0) fatal("Invalid UTF-8 sequence in '%s'", s);
-			tmp += len;
-		}
-	}
-
-	// Check if the string has a case..
-	// The syntax for cases is IDENTNAME.case
-	casep = strchr(str, '.');
-	if (casep) *casep++ = 0;
-
-	// Check if this string already exists..
-	ent = HashFind(str);
-
-	if (master) {
-		if (ent != NULL && casep == NULL) {
-			error("String name '%s' is used multiple times", str);
-			return;
-		}
-
-		if (ent == NULL && casep != NULL) {
-			error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str);
-			return;
-		}
-
-		if (ent == NULL) {
-			if (_strings[_next_string_id]) {
-				error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name);
-				return;
-			}
-
-			// Allocate a new LangString
-			ent = calloc(1, sizeof(*ent));
-			_strings[_next_string_id] = ent;
-			ent->index = _next_string_id++;
-			ent->name = strdup(str);
-			ent->line = _cur_line;
-
-			HashAdd(str, ent);
-		}
-
-		if (casep != NULL) {
-			Case* c = malloc(sizeof(*c));
-
-			c->caseidx = ResolveCaseName(casep, strlen(casep));
-			c->string = strdup(s);
-			c->next = ent->english_case;
-			ent->english_case = c;
-		} else {
-			ent->english = strdup(s);
-		}
-
-	} else {
-		if (ent == NULL) {
-			warning("String name '%s' does not exist in master file", str);
-			return;
-		}
-
-		if (ent->translated && casep == NULL) {
-			error("String name '%s' is used multiple times", str);
-			return;
-		}
-
-		if (s[0] == ':' && s[1] == '\0' && casep == NULL) {
-			// Special syntax :: means we should just inherit the master string
-			ent->translated = strdup(ent->english);
-		} else {
-			// make sure that the commands match
-			if (!CheckCommandsMatch(s, ent->english, str)) return;
-
-			if (casep != NULL) {
-				Case* c = malloc(sizeof(*c));
-
-				c->caseidx = ResolveCaseName(casep, strlen(casep));
-				c->string = strdup(s);
-				c->next = ent->translated_case;
-				ent->translated_case = c;
-			} else {
-				ent->translated = strdup(s);
-			}
-		}
-	}
-}
-
-
-static void rstrip(char *buf)
-{
-	int i = strlen(buf);
-	while (i > 0 && (buf[i - 1] == '\r' || buf[i - 1] == '\n' || buf[i - 1] == ' ')) i--;
-	buf[i] = '\0';
-}
-
-
-static void ParseFile(const char *file, bool english)
-{
-	FILE *in;
-	char buf[2048];
-
-	_file = file;
-
-	// For each new file we parse, reset the genders.
-	_numgenders = 0;
-	// TODO:!! We can't reset the cases. In case the translated strings
-	// derive some strings from english....
-
-
-	in = fopen(file, "r");
-	if (in == NULL) fatal("Cannot open file");
-	_cur_line = 1;
-	while (fgets(buf, sizeof(buf),in) != NULL) {
-		rstrip(buf);
-		HandleString(buf, english);
-		_cur_line++;
-	}
-	fclose(in);
-}
-
-
-static uint32 MyHashStr(uint32 hash, const char *s)
-{
-	for (; *s != '\0'; s++) {
-		hash = ROL(hash, 3) ^ *s;
-		hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
-	}
-	return hash;
-}
-
-
-// make a hash of the file to get a unique "version number"
-static void MakeHashOfStrings(void)
-{
-	uint32 hash = 0;
-	uint i;
-
-	for (i = 0; i != lengthof(_strings); i++) {
-		const LangString* ls = _strings[i];
-
-		if (ls != NULL) {
-			const CmdStruct* cs;
-			const char* s;
-			char buf[256];
-			int argno;
-			int casei;
-
-			s = ls->name;
-			hash ^= i * 0x717239;
-			hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
-			hash = MyHashStr(hash, s + 1);
-
-			s = ls->english;
-			while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != NULL) {
-				if (cs->flags & C_DONTCOUNT) continue;
-
-				hash ^= (cs - _cmd_structs) * 0x1234567;
-				hash = (hash & 1 ? hash >> 1 ^ 0xF00BAA4 : hash >> 1);
-			}
-		}
-	}
-	_hash = hash;
-}
-
-
-static uint CountInUse(uint grp)
-{
-	int i;
-
-	for (i = 0x800; --i >= 0;) if (_strings[(grp << 11) + i] != NULL) break;
-	return i + 1;
-}
-
-
-bool CompareFiles(const char *n1, const char *n2)
-{
-	FILE *f1, *f2;
-	char b1[4096];
-	char b2[4096];
-	size_t l1, l2;
-
-	f2 = fopen(n2, "rb");
-	if (f2 == NULL) return false;
-
-	f1 = fopen(n1, "rb");
-	if (f1 == NULL) fatal("can't open %s", n1);
-
-	do {
-		l1 = fread(b1, 1, sizeof(b1), f1);
-		l2 = fread(b2, 1, sizeof(b2), f2);
-
-		if (l1 != l2 || memcmp(b1, b2, l1)) {
-			fclose(f2);
-			fclose(f1);
-			return false;
-		}
-	} while (l1);
-
-	fclose(f2);
-	fclose(f1);
-	return true;
-}
-
-
-static void WriteStringsH(const char *filename)
-{
-	FILE *out;
-	int i;
-	int next = -1;
-	int lastgrp;
-
-	out = fopen("tmp.xxx", "w");
-	if (out == NULL) fatal("can't open tmp.xxx");
-
-	fprintf(out, "enum {");
-
-	lastgrp = 0;
-
-	for (i = 0; i != lengthof(_strings); i++) {
-		if (_strings[i] != NULL) {
-			if (lastgrp != (i >> 11)) {
-				lastgrp = (i >> 11);
-				fprintf(out, "};\n\nenum {");
-			}
-
-			fprintf(out, next == i ? "\t%s,\n" : "\n\t%s = 0x%X,\n", _strings[i]->name, i);
-			next = i + 1;
-		}
-	}
-
-	fprintf(out, "};\n");
-
-	fprintf(out,
-		"\nenum {\n"
-		"\tLANGUAGE_PACK_IDENT = 0x474E414C, // Big Endian value for 'LANG' (LE is 0x 4C 41 4E 47)\n"
-		"\tLANGUAGE_PACK_VERSION = 0x%X,\n"
-		"};\n", (uint)_hash
-	);
-
-	fclose(out);
-
-	if (CompareFiles("tmp.xxx", filename)) {
-		// files are equal. tmp.xxx is not needed
-		unlink("tmp.xxx");
-	} else {
-		// else rename tmp.xxx into filename
-#if defined(WIN32) || defined(WIN64)
-		unlink(filename);
-#endif
-		if (rename("tmp.xxx", filename) == -1) fatal("rename() failed");
-	}
-}
-
-static int TranslateArgumentIdx(int argidx)
-{
-	int i, sum;
-
-	if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd))
-		fatal("invalid argidx %d", argidx);
-
-	for (i = sum = 0; i < argidx; i++) {
-		const CmdStruct *cs = _cur_pcs.cmd[i];
-		sum += (cs != NULL) ? cs->consumes : 1;
-	}
-
-	return sum;
-}
-
-static void PutArgidxCommand(void)
-{
-	PutUtf8(SCC_ARG_INDEX);
-	PutByte(TranslateArgumentIdx(_cur_argidx));
-}
-
-
-static void PutCommandString(const char *str)
-{
-	const CmdStruct *cs;
-	char param[256];
-	int argno;
-	int casei;
-
-	_cur_argidx = 0;
-
-	while (*str != '\0') {
-		// Process characters as they are until we encounter a {
-		if (*str != '{') {
-			PutByte(*str++);
-			continue;
-		}
-		cs = ParseCommandString(&str, param, &argno, &casei);
-		if (cs == NULL) break;
-
-		if (casei != -1) {
-			PutUtf8(SCC_SETCASE); // {SETCASE}
-			PutByte(casei);
-		}
-
-		// For params that consume values, we need to handle the argindex properly
-		if (cs->consumes > 0) {
-			// Check if we need to output a move-param command
-			if (argno != -1 && argno != _cur_argidx) {
-				_cur_argidx = argno;
-				PutArgidxCommand();
-			}
-
-			// Output the one from the master string... it's always accurate.
-			cs = _cur_pcs.cmd[_cur_argidx++];
-			if (cs == NULL) {
-				fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1);
-			}
-		}
-
-		cs->proc(param, cs->value);
-	}
-}
-
-static void WriteLength(FILE *f, uint length)
-{
-	if (length < 0xC0) {
-		fputc(length, f);
-	} else if (length < 0x4000) {
-		fputc((length >> 8) | 0xC0, f);
-		fputc(length & 0xFF, f);
-	} else {
-		fatal("string too long");
-	}
-}
-
-
-static void WriteLangfile(const char *filename, int show_todo)
-{
-	FILE *f;
-	uint in_use[32];
-	LanguagePackHeader hdr;
-	uint i;
-	uint j;
-
-	f = fopen(filename, "wb");
-	if (f == NULL) fatal("can't open %s", filename);
-
-	memset(&hdr, 0, sizeof(hdr));
-	for (i = 0; i != 32; i++) {
-		uint n = CountInUse(i);
-
-		in_use[i] = n;
-		hdr.offsets[i] = TO_LE16(n);
-	}
-
-	// see line 655: fprintf(..."\tLANGUAGE_PACK_IDENT = 0x474E414C,...)
-	hdr.ident = TO_LE32(0x474E414C); // Big Endian value for 'LANG'
-	hdr.version = TO_LE32(_hash);
-	hdr.plural_form = _lang_pluralform;
-	strcpy(hdr.name, _lang_name);
-	strcpy(hdr.own_name, _lang_ownname);
-	strcpy(hdr.isocode, _lang_isocode);
-
-	fwrite(&hdr, sizeof(hdr), 1, f);
-
-	for (i = 0; i != 32; i++) {
-		for (j = 0; j != in_use[i]; j++) {
-			const LangString* ls = _strings[(i << 11) + j];
-			const Case* casep;
-			const char* cmdp;
-
-			// For undefined strings, just set that it's an empty string
-			if (ls == NULL) {
-				WriteLength(f, 0);
-				continue;
-			}
-
-			_cur_ident = ls->name;
-			_cur_line = ls->line;
-
-			// Produce a message if a string doesn't have a translation.
-			if (show_todo > 0 && ls->translated == NULL) {
-				if (show_todo == 2) {
-					warning("'%s' is untranslated", ls->name);
-				} else {
-					const char *s = "<TODO> ";
-					while (*s != '\0') PutByte(*s++);
-				}
-			}
-
-			// Extract the strings and stuff from the english command string
-			ExtractCommandString(&_cur_pcs, ls->english, false);
-
-			if (ls->translated_case != NULL || ls->translated != NULL) {
-				casep = ls->translated_case;
-				cmdp = ls->translated;
-			} else {
-				casep = ls->english_case;
-				cmdp = ls->english;
-			}
-
-			_translated = _masterlang || (cmdp != ls->english);
-
-			if (casep != NULL) {
-				const Case* c;
-				uint num;
-
-				// Need to output a case-switch.
-				// It has this format
-				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
-				// Each LEN is printed using 2 bytes in big endian order.
-				PutUtf8(SCC_SWITCH_CASE);
-				// Count the number of cases
-				for (num = 0, c = casep; c; c = c->next) num++;
-				PutByte(num);
-
-				// Write each case
-				for (c = casep; c != NULL; c = c->next) {
-					int pos;
-
-					PutByte(c->caseidx);
-					// Make some space for the 16-bit length
-					pos = _put_pos;
-					PutByte(0);
-					PutByte(0);
-					// Write string
-					PutCommandString(c->string);
-					PutByte(0); // terminate with a zero
-					// Fill in the length
-					_put_buf[pos + 0] = GB(_put_pos - (pos + 2), 8, 8);
-					_put_buf[pos + 1] = GB(_put_pos - (pos + 2), 0, 8);
-				}
-			}
-
-			if (cmdp != NULL) PutCommandString(cmdp);
-
-			WriteLength(f, _put_pos);
-			fwrite(_put_buf, 1, _put_pos, f);
-			_put_pos = 0;
-		}
-	}
-
-	fputc(0, f);
-	fclose(f);
-}
-
-/** Multi-OS mkdirectory function */
-static inline void ottd_mkdir(const char *directory)
-{
-#if defined(WIN32) || defined(__WATCOMC__)
-		mkdir(directory);
-#else
-		mkdir(directory, 0755);
-#endif
-}
-
-/** Create a path consisting of an already existing path, a possible
- * path seperator and the filename. The seperator is only appended if the path
- * does not already end with a seperator */
-static inline char *mkpath(char *buf, size_t buflen, const char *path, const char *file)
-{
-	char *p;
-	ttd_strlcpy(buf, path, buflen); // copy directory into buffer
-
-	p = strchr(buf, '\0'); // add path seperator if necessary
-	if (p[-1] != PATHSEPCHAR && (size_t)(p - buf) + 1 < buflen) *p++ = PATHSEPCHAR;
-	ttd_strlcpy(p, file, buflen - (size_t)(p - buf)); // catenate filename at end of buffer
-	return buf;
-}
-
-#if defined(__MINGW32__)
-/**
- * On MingW, it is common that both / as \ are accepted in the
- * params. To go with those flow, we rewrite all incoming /
- * simply to \, so internally we can safely assume \.
- */
-static inline char *replace_pathsep(char *s)
-{
-	char *c;
-
-	for (c = s; *c != '\0'; c++) if (*c == '/') *c = '\\';
-	return s;
-}
-#else
-static inline char *replace_pathsep(char *s) { return s; }
-#endif
-
-int CDECL main(int argc, char* argv[])
-{
-	char pathbuf[256];
-	const char *src_dir = ".";
-	const char *dest_dir = NULL;
-
-	int show_todo = 0;
-
-	while (argc > 1 && *argv[1] == '-') {
-		if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) {
-			puts("$Revision$");
-			return 0;
-		}
-
-		if (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--todo") == 0) {
-			show_todo = 1;
-			argc--, argv++;
-			continue;
-		}
-
-		if (strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "--warning") == 0) {
-			show_todo = 2;
-			argc--, argv++;
-			continue;
-		}
-
-		if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
-			puts(
-				"strgen - $Revision$\n"
-				" -v | --version    print version information and exit\n"
-				" -t | --todo       replace any untranslated strings with '<TODO>'\n"
-				" -w | --warning    print a warning for any untranslated strings\n"
-				" -h | -? | --help  print this help message and exit\n"
-				" -s | --source_dir search for english.txt in the specified directory\n"
-				" -d | --dest_dir   put output file in the specified directory, create if needed\n"
-				" Run without parameters and strgen will search for english.txt and parse it,\n"
-				" creating strings.h. Passing an argument, strgen will translate that language\n"
-				" file using english.txt as a reference and output <language>.lng."
-			);
-			return 0;
-		}
-
-		if (argc > 2 && (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--source_dir") == 0)) {
-			src_dir = replace_pathsep(argv[2]);
-			argc -= 2, argv += 2;
-			continue;
-		}
-
-		if (argc > 2 && (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--dest_dir") == 0)) {
-			dest_dir = replace_pathsep(argv[2]);
-			argc -= 2, argv += 2;
-			continue;
-		}
-
-		fprintf(stderr, "Invalid arguments\n");
-		return 0;
-	}
-
-	if (dest_dir == NULL) dest_dir = src_dir; // if dest_dir is not specified, it equals src_dir
-
-	/* strgen has two modes of operation. If no (free) arguments are passed
-	 * strgen generates strings.h to the destination directory. If it is supplied
-	 * with a (free) parameter the program will translate that language to destination
-	 * directory. As input english.txt is parsed from the source directory */
-	if (argc == 1) {
-		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
-
-		/* parse master file */
-		_masterlang = true;
-		ParseFile(pathbuf, true);
-		MakeHashOfStrings();
-		if (_errors) return 1;
-
-		/* write strings.h */
-		ottd_mkdir(dest_dir);
-		mkpath(pathbuf, lengthof(pathbuf), dest_dir, "strings.h");
-		WriteStringsH(pathbuf);
-	} else if (argc == 2) {
-		char *r;
-
-		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
-
-		/* parse master file and check if target file is correct */
-		_masterlang = false;
-		ParseFile(pathbuf, true);
-		MakeHashOfStrings();
-		ParseFile(replace_pathsep(argv[1]), false); // target file
-		if (_errors) return 1;
-
-		/* get the targetfile, strip any directories and append to destination path */
-		r = strrchr(argv[1], PATHSEPCHAR);
-		mkpath(pathbuf, lengthof(pathbuf), dest_dir, (r != NULL) ? &r[1] : argv[1]);
-
-		/* rename the .txt (input-extension) to .lng */
-		r = strrchr(pathbuf, '.');
-		if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0');
-		ttd_strlcpy(r, ".lng", (size_t)(r - pathbuf));
-		WriteLangfile(pathbuf, show_todo);
-
-		/* if showing warnings, print a summary of the language */
-		if (show_todo == 2) {
-			fprintf(stdout, "%d warnings and %d errors for %s\n", _warnings, _errors, pathbuf);
-		}
-	} else {
-		fprintf(stderr, "Invalid arguments\n");
-	}
-
-	return 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/strgen/strgen.cpp
@@ -0,0 +1,1399 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../macros.h"
+#include "../string.h"
+#include "../table/control_codes.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if (!defined(WIN32) && !defined(WIN64)) || defined(__CYGWIN__)
+#include <unistd.h>
+#endif
+
+#if defined WIN32 || defined __WATCOMC__
+#include <direct.h>
+#endif /* WIN32 || __WATCOMC__ */
+
+#ifdef __MORPHOS__
+#ifdef stderr
+#undef stderr
+#endif
+#define stderr stdout
+#endif /* __MORPHOS__ */
+
+#ifdef __WATCOMC__
+	uint _map_log_x;     // an unpleasant hack required because Watcom is insisting on
+	uint _map_size_x;    // these variables being valid references in map.h
+	uint _map_size_y;
+	uint _map_tile_mask;
+	uint _map_size;
+#endif /* __WATCOMC__ */
+
+/* Compiles a list of strings into a compiled string list */
+
+typedef void (*ParseCmdProc)(char *buf, int value);
+
+typedef struct LanguagePackHeader {
+	uint32 ident;
+	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
+	char name[32];      // the international name of this language
+	char own_name[32];  // the localized name of this language
+	char isocode[16];   // the ISO code for the language (not country code)
+	uint16 offsets[32]; // the offsets
+	byte plural_form;   // plural form index
+	byte pad[3];        // pad header to be a multiple of 4
+} LanguagePackHeader;
+
+typedef struct CmdStruct {
+	const char *cmd;
+	ParseCmdProc proc;
+	long value;
+	int8 consumes;
+	byte flags;
+} CmdStruct;
+
+enum {
+	C_DONTCOUNT = 1,
+	C_CASE      = 2,
+};
+
+
+typedef struct Case {
+	int caseidx;
+	char *string;
+	struct Case *next;
+} Case;
+
+static bool _masterlang;
+static bool _translated;
+static const char* _file = "(unknown file)";
+static int _cur_line;
+static int _errors, _warnings;
+
+typedef struct LangString {
+	char *name;            // Name of the string
+	char *english;         // English text
+	char *translated;      // Translated text
+	uint16 hash_next;      // next hash entry
+	uint16 index;
+	int line;              // line of string in source-file
+	Case *english_case;    // cases for english
+	Case *translated_case; // cases for foreign
+} LangString;
+
+static LangString *_strings[65536];
+
+
+#define HASH_SIZE 32767
+static uint16 _hash_head[HASH_SIZE];
+
+static byte _put_buf[4096];
+static int _put_pos;
+static int _next_string_id;
+
+static uint32 _hash;
+static char _lang_name[32], _lang_ownname[32], _lang_isocode[16];
+static byte _lang_pluralform;
+#define MAX_NUM_GENDER 8
+static char _genders[MAX_NUM_GENDER][8];
+static int _numgenders;
+
+// contains the name of all cases.
+#define MAX_NUM_CASES 50
+static char _cases[MAX_NUM_CASES][16];
+static int _numcases;
+
+// for each plural value, this is the number of plural forms.
+static const byte _plural_form_counts[] = { 2, 1, 2, 3, 3, 3, 3, 3, 4 };
+
+static const char *_cur_ident;
+
+typedef struct CmdPair {
+	const CmdStruct *a;
+	char *v;
+} CmdPair;
+
+typedef struct ParsedCommandStruct {
+	int np;
+	CmdPair pairs[32];
+	const CmdStruct *cmd[32]; // ordered by param #
+} ParsedCommandStruct;
+
+// Used when generating some advanced commands.
+static ParsedCommandStruct _cur_pcs;
+static int _cur_argidx;
+
+static uint HashStr(const char *s)
+{
+	uint hash = 0;
+	for (; *s != '\0'; s++) hash = ROL(hash, 3) ^ *s;
+	return hash % HASH_SIZE;
+}
+
+static void HashAdd(const char *s, LangString *ls)
+{
+	uint hash = HashStr(s);
+	ls->hash_next = _hash_head[hash];
+	_hash_head[hash] = ls->index + 1;
+}
+
+static LangString *HashFind(const char *s)
+{
+	int idx = _hash_head[HashStr(s)];
+
+	while (--idx >= 0) {
+		LangString* ls = _strings[idx];
+
+		if (strcmp(ls->name, s) == 0) return ls;
+		idx = ls->hash_next;
+	}
+	return NULL;
+}
+
+#ifdef _MSC_VER
+# define LINE_NUM_FMT "(%d)"
+#else
+# define LINE_NUM_FMT ":%d"
+#endif
+
+static void CDECL warning(const char *s, ...)
+{
+	char buf[1024];
+	va_list va;
+	va_start(va, s);
+	vsnprintf(buf, lengthof(buf), s, va);
+	va_end(va);
+	fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf);
+	_warnings++;
+}
+
+void CDECL error(const char *s, ...)
+{
+	char buf[1024];
+	va_list va;
+	va_start(va, s);
+	vsnprintf(buf, lengthof(buf), s, va);
+	va_end(va);
+	fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf);
+	_errors++;
+}
+
+
+static void NORETURN CDECL fatal(const char *s, ...)
+{
+	char buf[1024];
+	va_list va;
+	va_start(va, s);
+	vsnprintf(buf, lengthof(buf), s, va);
+	va_end(va);
+	fprintf(stderr, "%s" LINE_NUM_FMT ": FATAL: %s\n", _file, _cur_line, buf);
+	exit(1);
+}
+
+static void PutByte(byte c)
+{
+	if (_put_pos == lengthof(_put_buf)) fatal("Put buffer too small");
+	_put_buf[_put_pos++] = c;
+}
+
+
+static void PutUtf8(uint32 value)
+{
+	if (value < 0x80) {
+		PutByte(value);
+	} else if (value < 0x800) {
+		PutByte(0xC0 + GB(value,  6, 5));
+		PutByte(0x80 + GB(value,  0, 6));
+	} else if (value < 0x10000) {
+		PutByte(0xE0 + GB(value, 12, 4));
+		PutByte(0x80 + GB(value,  6, 6));
+		PutByte(0x80 + GB(value,  0, 6));
+	} else if (value < 0x110000) {
+		PutByte(0xF0 + GB(value, 18, 3));
+		PutByte(0x80 + GB(value, 12, 6));
+		PutByte(0x80 + GB(value,  6, 6));
+		PutByte(0x80 + GB(value,  0, 6));
+	} else {
+		warning("Invalid unicode value U+0x%X", value);
+	}
+}
+
+
+size_t Utf8Validate(const char *s)
+{
+	uint32 c;
+
+	if (!HASBIT(s[0], 7)) {
+		/* 1 byte */
+		return 1;
+	} else if (GB(s[0], 5, 3) == 6 && IsUtf8Part(s[1])) {
+		/* 2 bytes */
+		c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
+		if (c >= 0x80) return 2;
+	} else if (GB(s[0], 4, 4) == 14 && IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
+		/* 3 bytes */
+		c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
+		if (c >= 0x800) return 3;
+	} else if (GB(s[0], 3, 5) == 30 && IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
+		/* 4 bytes */
+		c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
+		if (c >= 0x10000 && c <= 0x10FFFF) return 4;
+	}
+
+	return 0;
+}
+
+
+static void EmitSingleChar(char *buf, int value)
+{
+	if (*buf != '\0') warning("Ignoring trailing letters in command");
+	PutUtf8(value);
+}
+
+
+static void EmitSetX(char *buf, int value)
+{
+	char *err;
+	int x = strtol(buf, &err, 0);
+	if (*err != 0) fatal("SetX param invalid");
+	PutUtf8(SCC_SETX);
+	PutByte((byte)x);
+}
+
+
+static void EmitSetXY(char *buf, int value)
+{
+	char *err;
+	int x;
+	int y;
+
+	x = strtol(buf, &err, 0);
+	if (*err != ' ') fatal("SetXY param invalid");
+	y = strtol(err + 1, &err, 0);
+	if (*err != 0) fatal("SetXY param invalid");
+
+	PutUtf8(SCC_SETXY);
+	PutByte((byte)x);
+	PutByte((byte)y);
+}
+
+// The plural specifier looks like
+// {NUM} {PLURAL -1 passenger passengers} then it picks either passenger/passengers depending on the count in NUM
+
+// This is encoded like
+//  CommandByte <ARG#> <NUM> {Length of each string} {each string}
+
+bool ParseRelNum(char **buf, int *value)
+{
+	const char* s = *buf;
+	char* end;
+	bool rel = false;
+	int v;
+
+	while (*s == ' ' || *s == '\t') s++;
+	if (*s == '+') {
+		rel = true;
+		s++;
+	}
+	v = strtol(s, &end, 0);
+	if (end == s) return false;
+	if (rel || v < 0) {
+		*value += v;
+	} else {
+		*value = v;
+	}
+	*buf = end;
+	return true;
+}
+
+// Parse out the next word, or NULL
+char *ParseWord(char **buf)
+{
+	char *s = *buf, *r;
+
+	while (*s == ' ' || *s == '\t') s++;
+	if (*s == '\0') return NULL;
+
+	if (*s == '"') {
+		r = ++s;
+		// parse until next " or NUL
+		for (;;) {
+			if (*s == '\0') break;
+			if (*s == '"') {
+				*s++ = '\0';
+				break;
+			}
+			s++;
+		}
+	} else {
+		// proceed until whitespace or NUL
+		r = s;
+		for (;;) {
+			if (*s == '\0') break;
+			if (*s == ' ' || *s == '\t') {
+				*s++ = '\0';
+				break;
+			}
+			s++;
+		}
+	}
+	*buf = s;
+	return r;
+}
+
+// Forward declaration
+static int TranslateArgumentIdx(int arg);
+
+static void EmitWordList(const char* const* words, uint nw)
+{
+	uint i;
+	uint j;
+
+	PutByte(nw);
+	for (i = 0; i < nw; i++) PutByte(strlen(words[i]));
+	for (i = 0; i < nw; i++) {
+		for (j = 0; words[i][j] != '\0'; j++) PutByte(words[i][j]);
+	}
+}
+
+static void EmitPlural(char *buf, int value)
+{
+	int argidx = _cur_argidx;
+	const char* words[5];
+	int nw = 0;
+
+	// Parse out the number, if one exists. Otherwise default to prev arg.
+	if (!ParseRelNum(&buf, &argidx)) argidx--;
+
+	// Parse each string
+	for (nw = 0; nw < 5; nw++) {
+		words[nw] = ParseWord(&buf);
+		if (words[nw] == NULL) break;
+	}
+
+	if (nw == 0)
+		fatal("%s: No plural words", _cur_ident);
+
+	if (_plural_form_counts[_lang_pluralform] != nw) {
+		if (_translated) {
+			fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident,
+				_plural_form_counts[_lang_pluralform], nw);
+		} else {
+			warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
+			if (nw > _plural_form_counts[_lang_pluralform]) {
+				nw = _plural_form_counts[_lang_pluralform];
+			} else {
+				for (; nw < _plural_form_counts[_lang_pluralform]; nw++) {
+					words[nw] = words[nw - 1];
+				}
+			}
+		}
+	}
+
+	PutUtf8(SCC_PLURAL_LIST);
+	PutByte(TranslateArgumentIdx(argidx));
+	EmitWordList(words, nw);
+}
+
+
+static void EmitGender(char *buf, int value)
+{
+	int argidx = _cur_argidx;
+	uint nw;
+
+	if (buf[0] == '=') {
+		buf++;
+
+		// This is a {G=DER} command
+		for (nw = 0; ; nw++) {
+			if (nw >= 8) fatal("G argument '%s' invalid", buf);
+			if (strcmp(buf, _genders[nw]) == 0) break;
+		}
+		// now nw contains the gender index
+		PutUtf8(SCC_GENDER_INDEX);
+		PutByte(nw);
+	} else {
+		const char* words[8];
+
+		// This is a {G 0 foo bar two} command.
+		// If no relative number exists, default to +0
+		if (!ParseRelNum(&buf, &argidx)) {}
+
+		for (nw = 0; nw < 8; nw++) {
+			words[nw] = ParseWord(&buf);
+			if (words[nw] == NULL) break;
+		}
+		if (nw != _numgenders) fatal("Bad # of arguments for gender command");
+		PutUtf8(SCC_GENDER_LIST);
+		PutByte(TranslateArgumentIdx(argidx));
+		EmitWordList(words, nw);
+	}
+}
+
+
+static const CmdStruct _cmd_structs[] = {
+	// Update position
+	{"SETX",  EmitSetX,  SCC_SETX,  0, 0},
+	{"SETXY", EmitSetXY, SCC_SETXY, 0, 0},
+
+	// Font size
+	{"TINYFONT", EmitSingleChar, SCC_TINYFONT, 0, 0},
+	{"BIGFONT",  EmitSingleChar, SCC_BIGFONT,  0, 0},
+
+	// Colors
+	{"BLUE",    EmitSingleChar, SCC_BLUE,    0, 0},
+	{"SILVER",  EmitSingleChar, SCC_SILVER,  0, 0},
+	{"GOLD",    EmitSingleChar, SCC_GOLD,    0, 0},
+	{"RED",     EmitSingleChar, SCC_RED,     0, 0},
+	{"PURPLE",  EmitSingleChar, SCC_PURPLE,  0, 0},
+	{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, 0},
+	{"ORANGE",  EmitSingleChar, SCC_ORANGE,  0, 0},
+	{"GREEN",   EmitSingleChar, SCC_GREEN,   0, 0},
+	{"YELLOW",  EmitSingleChar, SCC_YELLOW,  0, 0},
+	{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, 0},
+	{"CREAM",   EmitSingleChar, SCC_CREAM,   0, 0},
+	{"BROWN",   EmitSingleChar, SCC_BROWN,   0, 0},
+	{"WHITE",   EmitSingleChar, SCC_WHITE,   0, 0},
+	{"LTBLUE",  EmitSingleChar, SCC_LTBLUE,  0, 0},
+	{"GRAY",    EmitSingleChar, SCC_GRAY,    0, 0},
+	{"DKBLUE",  EmitSingleChar, SCC_DKBLUE,  0, 0},
+	{"BLACK",   EmitSingleChar, SCC_BLACK,   0, 0},
+
+	{"CURRCOMPACT",   EmitSingleChar, SCC_CURRENCY_COMPACT,    1, 0}, // compact currency (32 bits)
+	{"REV",           EmitSingleChar, SCC_REVISION,            0, 0}, // openttd revision string
+	{"SHORTCARGO",    EmitSingleChar, SCC_CARGO_SHORT,         2, 0}, // short cargo description, only ### tons, or ### litres
+	{"CURRCOMPACT64", EmitSingleChar, SCC_CURRENCY_COMPACT_64, 2, 0}, // compact currency 64 bits
+
+	// These are special versions of {STRING1}
+	// The first string includes the second string.
+	{"COMPANY",    EmitSingleChar, SCC_STRING1, 1, 0},
+	{"PLAYERNAME", EmitSingleChar, SCC_STRING1, 1, 0},
+	{"VEHICLE",    EmitSingleChar, SCC_STRING1, 1, 0},
+
+	{"STRING1", EmitSingleChar, SCC_STRING1, 1, C_CASE}, // included string that consumes ONE argument
+	{"STRING2", EmitSingleChar, SCC_STRING2, 2, C_CASE}, // included string that consumes TWO arguments
+	{"STRING3", EmitSingleChar, SCC_STRING3, 3, C_CASE}, // included string that consumes THREE arguments
+	{"STRING4", EmitSingleChar, SCC_STRING4, 4, C_CASE}, // included string that consumes FOUR arguments
+	{"STRING5", EmitSingleChar, SCC_STRING5, 5, C_CASE}, // included string that consumes FIVE arguments
+
+	{"STATIONFEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, 0}, // station features string, icons of the features
+	{"INDUSTRY",        EmitSingleChar, SCC_INDUSTRY_NAME,    1, 0}, // industry, takes an industry #
+	{"CARGO",           EmitSingleChar, SCC_CARGO,            2, 0},
+	{"POWER",           EmitSingleChar, SCC_POWER,            1, 0},
+	{"VOLUME",          EmitSingleChar, SCC_VOLUME,           1, 0},
+	{"VOLUME_S",        EmitSingleChar, SCC_VOLUME_SHORT,     1, 0},
+	{"WEIGHT",          EmitSingleChar, SCC_WEIGHT,           1, 0},
+	{"WEIGHT_S",        EmitSingleChar, SCC_WEIGHT_SHORT,     1, 0},
+	{"FORCE",           EmitSingleChar, SCC_FORCE,            1, 0},
+	{"VELOCITY",        EmitSingleChar, SCC_VELOCITY,         1, 0},
+
+	{"P", EmitPlural, 0, 0, C_DONTCOUNT}, // plural specifier
+	{"G", EmitGender, 0, 0, C_DONTCOUNT}, // gender specifier
+
+	{"DATE_TINY",  EmitSingleChar, SCC_DATE_TINY, 1, 0},
+	{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, 0},
+	{"DATE_LONG",  EmitSingleChar, SCC_DATE_LONG, 1, 0},
+
+	{"SKIP", EmitSingleChar, SCC_SKIP, 1, 0},
+
+	{"STRING", EmitSingleChar, SCC_STRING, 1, C_CASE},
+
+	// Numbers
+	{"COMMA", EmitSingleChar, SCC_COMMA, 1, 0}, // Number with comma
+	{"NUM",   EmitSingleChar, SCC_NUM,   1, 0}, // Signed number
+
+	{"CURRENCY",   EmitSingleChar, SCC_CURRENCY,    1, 0},
+	{"CURRENCY64", EmitSingleChar, SCC_CURRENCY_64, 2, 0},
+
+	{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, 0}, // waypoint name
+	{"STATION",  EmitSingleChar, SCC_STATION_NAME,  1, 0},
+	{"TOWN",     EmitSingleChar, SCC_TOWN_NAME,     1, 0},
+
+	// 0x9D is used for the pseudo command SETCASE
+	// 0x9E is used for case switching
+
+	{"",               EmitSingleChar, '\n',               0, C_DONTCOUNT},
+	{"{",              EmitSingleChar, '{',                0, C_DONTCOUNT},
+	{"UPARROW",        EmitSingleChar, SCC_UPARROW,        0, 0},
+	{"SMALLUPARROW",   EmitSingleChar, SCC_SMALLUPARROW,   0, 0},
+	{"SMALLDOWNARROW", EmitSingleChar, SCC_SMALLDOWNARROW, 0, 0},
+	{"TRAIN",          EmitSingleChar, SCC_TRAIN,          0, 0},
+	{"LORRY",          EmitSingleChar, SCC_LORRY,          0, 0},
+	{"BUS",            EmitSingleChar, SCC_BUS,            0, 0},
+	{"PLANE",          EmitSingleChar, SCC_PLANE,          0, 0},
+	{"SHIP",           EmitSingleChar, SCC_SHIP,           0, 0},
+	{"NBSP",           EmitSingleChar, 0xA0,               0, C_DONTCOUNT},
+	{"CENT",           EmitSingleChar, 0xA2,               0, C_DONTCOUNT},
+	{"POUNDSIGN",      EmitSingleChar, 0xA3,               0, C_DONTCOUNT},
+	{"EURO",           EmitSingleChar, 0x20AC,             0, C_DONTCOUNT},
+	{"YENSIGN",        EmitSingleChar, 0xA5,               0, C_DONTCOUNT},
+	{"COPYRIGHT",      EmitSingleChar, 0xA9,               0, C_DONTCOUNT},
+	{"DOWNARROW",      EmitSingleChar, SCC_DOWNARROW,      0, C_DONTCOUNT},
+	{"CHECKMARK",      EmitSingleChar, SCC_CHECKMARK,      0, C_DONTCOUNT},
+	{"CROSS",          EmitSingleChar, SCC_CROSS,          0, C_DONTCOUNT},
+	{"REGISTERED",     EmitSingleChar, 0xAE,               0, C_DONTCOUNT},
+	{"RIGHTARROW",     EmitSingleChar, SCC_RIGHTARROW,     0, C_DONTCOUNT},
+	{"SMALLLEFTARROW", EmitSingleChar, SCC_LESSTHAN,       0, C_DONTCOUNT},
+	{"SMALLRIGHTARROW",EmitSingleChar, SCC_GREATERTHAN,    0, C_DONTCOUNT},
+};
+
+
+static const CmdStruct *FindCmd(const char *s, int len)
+{
+	const CmdStruct* cs;
+
+	for (cs = _cmd_structs; cs != endof(_cmd_structs); cs++) {
+		if (strncmp(cs->cmd, s, len) == 0 && cs->cmd[len] == '\0') return cs;
+	}
+	return NULL;
+}
+
+static uint ResolveCaseName(const char *str, uint len)
+{
+	uint i;
+
+	for (i = 0; i < MAX_NUM_CASES; i++) {
+		if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1;
+	}
+	fatal("Invalid case-name '%s'", str);
+}
+
+
+// returns NULL on eof
+// else returns command struct
+static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei)
+{
+	const char *s = *str, *start;
+	const CmdStruct *cmd;
+	byte c;
+
+	*argno = -1;
+	*casei = -1;
+
+	// Scan to the next command, exit if there's no next command.
+	for (; *s != '{'; s++) {
+		if (*s == '\0') return NULL;
+	}
+	s++; // Skip past the {
+
+	if (*s >= '0' && *s <= '9') {
+		char *end;
+
+		*argno = strtoul(s, &end, 0);
+		if (*end != ':') fatal("missing arg #");
+		s = end + 1;
+	}
+
+	// parse command name
+	start = s;
+	do {
+		c = *s++;
+	} while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0);
+
+	cmd = FindCmd(start, s - start - 1);
+	if (cmd == NULL) {
+		error("Undefined command '%.*s'", s - start - 1, start);
+		return NULL;
+	}
+
+	if (c == '.') {
+		const char *casep = s;
+
+		if (!(cmd->flags & C_CASE))
+			fatal("Command '%s' can't have a case", cmd->cmd);
+
+		do c = *s++; while (c != '}' && c != ' ' && c != '\0');
+		*casei = ResolveCaseName(casep, s - casep - 1);
+	}
+
+	if (c == '\0') {
+		error("Missing } from command '%s'", start);
+		return NULL;
+	}
+
+
+	if (c != '}') {
+		if (c == '=') s--;
+		// copy params
+		start = s;
+		for (;;) {
+			c = *s++;
+			if (c == '}') break;
+			if (c == '\0') {
+				error("Missing } from command '%s'", start);
+				return NULL;
+			}
+			if (s - start == 250) fatal("param command too long");
+			*param++ = c;
+		}
+	}
+	*param = '\0';
+
+	*str = s;
+
+	return cmd;
+}
+
+
+static void HandlePragma(char *str)
+{
+	if (!memcmp(str, "id ", 3)) {
+		_next_string_id = strtoul(str + 3, NULL, 0);
+	} else if (!memcmp(str, "name ", 5)) {
+		ttd_strlcpy(_lang_name, str + 5, sizeof(_lang_name));
+	} else if (!memcmp(str, "ownname ", 8)) {
+		ttd_strlcpy(_lang_ownname, str + 8, sizeof(_lang_ownname));
+	} else if (!memcmp(str, "isocode ", 8)) {
+		ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode));
+	} else if (!memcmp(str, "plural ", 7)) {
+		_lang_pluralform = atoi(str + 7);
+		if (_lang_pluralform >= lengthof(_plural_form_counts))
+			fatal("Invalid pluralform %d", _lang_pluralform);
+	} else if (!memcmp(str, "gender ", 7)) {
+		char* buf = str + 7;
+
+		for (;;) {
+			const char* s = ParseWord(&buf);
+
+			if (s == NULL) break;
+			if (_numgenders >= MAX_NUM_GENDER) fatal("Too many genders, max %d", MAX_NUM_GENDER);
+			ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders]));
+			_numgenders++;
+		}
+	} else if (!memcmp(str, "case ", 5)) {
+		char* buf = str + 5;
+
+		for (;;) {
+			const char* s = ParseWord(&buf);
+
+			if (s == NULL) break;
+			if (_numcases >= MAX_NUM_CASES) fatal("Too many cases, max %d", MAX_NUM_CASES);
+			ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases]));
+			_numcases++;
+		}
+	} else {
+		fatal("unknown pragma '%s'", str);
+	}
+}
+
+static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings)
+{
+	char param[100];
+	int argno;
+	int argidx = 0;
+	int casei;
+
+	memset(p, 0, sizeof(*p));
+
+	for (;;) {
+		// read until next command from a.
+		const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei);
+
+		if (ar == NULL) break;
+
+		// Sanity checking
+		if (argno != -1 && ar->consumes == 0) fatal("Non consumer param can't have a paramindex");
+
+		if (ar->consumes) {
+			if (argno != -1) argidx = argno;
+			if (argidx < 0 || argidx >= lengthof(p->cmd)) fatal("invalid param idx %d", argidx);
+			if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) fatal("duplicate param idx %d", argidx);
+
+			p->cmd[argidx++] = ar;
+		} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
+			if (p->np >= lengthof(p->pairs)) fatal("too many commands in string, max %d", lengthof(p->pairs));
+			p->pairs[p->np].a = ar;
+			p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : "";
+			p->np++;
+		}
+	}
+}
+
+
+static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a)
+{
+	if (a == NULL) return NULL;
+
+	if (strcmp(a->cmd, "STRING1") == 0 ||
+			strcmp(a->cmd, "STRING2") == 0 ||
+			strcmp(a->cmd, "STRING3") == 0 ||
+			strcmp(a->cmd, "STRING4") == 0 ||
+			strcmp(a->cmd, "STRING5") == 0) {
+		return FindCmd("STRING", 6);
+	}
+
+	if (strcmp(a->cmd, "SKIP") == 0) return NULL;
+
+	return a;
+}
+
+
+static bool CheckCommandsMatch(char *a, char *b, const char *name)
+{
+	ParsedCommandStruct templ;
+	ParsedCommandStruct lang;
+	int i,j;
+	bool result = true;
+
+	ExtractCommandString(&templ, b, true);
+	ExtractCommandString(&lang, a, true);
+
+	// For each string in templ, see if we find it in lang
+	if (templ.np != lang.np) {
+		warning("%s: template string and language string have a different # of commands", name);
+		result = false;
+	}
+
+	for (i = 0; i < templ.np; i++) {
+		// see if we find it in lang, and zero it out
+		bool found = false;
+		for (j = 0; j < lang.np; j++) {
+			if (templ.pairs[i].a == lang.pairs[j].a &&
+					strcmp(templ.pairs[i].v, lang.pairs[j].v) == 0) {
+				// it was found in both. zero it out from lang so we don't find it again
+				lang.pairs[j].a = NULL;
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
+			result = false;
+		}
+	}
+
+	// if we reach here, all non consumer commands match up.
+	// Check if the non consumer commands match up also.
+	for (i = 0; i < lengthof(templ.cmd); i++) {
+		if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) {
+			warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i,
+				lang.cmd[i]  == NULL ? "<empty>" : lang.cmd[i]->cmd,
+				templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd);
+			result = false;
+		}
+	}
+
+	return result;
+}
+
+static void HandleString(char *str, bool master)
+{
+	char *s,*t;
+	LangString *ent;
+	char *casep;
+
+	if (*str == '#') {
+		if (str[1] == '#' && str[2] != '#') HandlePragma(str + 2);
+		return;
+	}
+
+	// Ignore comments & blank lines
+	if (*str == ';' || *str == ' ' || *str == '\0') return;
+
+	s = strchr(str, ':');
+	if (s == NULL) {
+		error("Line has no ':' delimiter");
+		return;
+	}
+
+	// Trim spaces.
+	// After this str points to the command name, and s points to the command contents
+	for (t = s; t > str && (t[-1] == ' ' || t[-1] == '\t'); t--);
+	*t = 0;
+	s++;
+
+	/* Check string is valid UTF-8 */
+	{
+		const char *tmp;
+		for (tmp = s; *tmp != '\0';) {
+			size_t len = Utf8Validate(tmp);
+			if (len == 0) fatal("Invalid UTF-8 sequence in '%s'", s);
+			tmp += len;
+		}
+	}
+
+	// Check if the string has a case..
+	// The syntax for cases is IDENTNAME.case
+	casep = strchr(str, '.');
+	if (casep) *casep++ = 0;
+
+	// Check if this string already exists..
+	ent = HashFind(str);
+
+	if (master) {
+		if (ent != NULL && casep == NULL) {
+			error("String name '%s' is used multiple times", str);
+			return;
+		}
+
+		if (ent == NULL && casep != NULL) {
+			error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str);
+			return;
+		}
+
+		if (ent == NULL) {
+			if (_strings[_next_string_id]) {
+				error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name);
+				return;
+			}
+
+			// Allocate a new LangString
+			ent = calloc(1, sizeof(*ent));
+			_strings[_next_string_id] = ent;
+			ent->index = _next_string_id++;
+			ent->name = strdup(str);
+			ent->line = _cur_line;
+
+			HashAdd(str, ent);
+		}
+
+		if (casep != NULL) {
+			Case* c = malloc(sizeof(*c));
+
+			c->caseidx = ResolveCaseName(casep, strlen(casep));
+			c->string = strdup(s);
+			c->next = ent->english_case;
+			ent->english_case = c;
+		} else {
+			ent->english = strdup(s);
+		}
+
+	} else {
+		if (ent == NULL) {
+			warning("String name '%s' does not exist in master file", str);
+			return;
+		}
+
+		if (ent->translated && casep == NULL) {
+			error("String name '%s' is used multiple times", str);
+			return;
+		}
+
+		if (s[0] == ':' && s[1] == '\0' && casep == NULL) {
+			// Special syntax :: means we should just inherit the master string
+			ent->translated = strdup(ent->english);
+		} else {
+			// make sure that the commands match
+			if (!CheckCommandsMatch(s, ent->english, str)) return;
+
+			if (casep != NULL) {
+				Case* c = malloc(sizeof(*c));
+
+				c->caseidx = ResolveCaseName(casep, strlen(casep));
+				c->string = strdup(s);
+				c->next = ent->translated_case;
+				ent->translated_case = c;
+			} else {
+				ent->translated = strdup(s);
+			}
+		}
+	}
+}
+
+
+static void rstrip(char *buf)
+{
+	int i = strlen(buf);
+	while (i > 0 && (buf[i - 1] == '\r' || buf[i - 1] == '\n' || buf[i - 1] == ' ')) i--;
+	buf[i] = '\0';
+}
+
+
+static void ParseFile(const char *file, bool english)
+{
+	FILE *in;
+	char buf[2048];
+
+	_file = file;
+
+	// For each new file we parse, reset the genders.
+	_numgenders = 0;
+	// TODO:!! We can't reset the cases. In case the translated strings
+	// derive some strings from english....
+
+
+	in = fopen(file, "r");
+	if (in == NULL) fatal("Cannot open file");
+	_cur_line = 1;
+	while (fgets(buf, sizeof(buf),in) != NULL) {
+		rstrip(buf);
+		HandleString(buf, english);
+		_cur_line++;
+	}
+	fclose(in);
+}
+
+
+static uint32 MyHashStr(uint32 hash, const char *s)
+{
+	for (; *s != '\0'; s++) {
+		hash = ROL(hash, 3) ^ *s;
+		hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
+	}
+	return hash;
+}
+
+
+// make a hash of the file to get a unique "version number"
+static void MakeHashOfStrings(void)
+{
+	uint32 hash = 0;
+	uint i;
+
+	for (i = 0; i != lengthof(_strings); i++) {
+		const LangString* ls = _strings[i];
+
+		if (ls != NULL) {
+			const CmdStruct* cs;
+			const char* s;
+			char buf[256];
+			int argno;
+			int casei;
+
+			s = ls->name;
+			hash ^= i * 0x717239;
+			hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
+			hash = MyHashStr(hash, s + 1);
+
+			s = ls->english;
+			while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != NULL) {
+				if (cs->flags & C_DONTCOUNT) continue;
+
+				hash ^= (cs - _cmd_structs) * 0x1234567;
+				hash = (hash & 1 ? hash >> 1 ^ 0xF00BAA4 : hash >> 1);
+			}
+		}
+	}
+	_hash = hash;
+}
+
+
+static uint CountInUse(uint grp)
+{
+	int i;
+
+	for (i = 0x800; --i >= 0;) if (_strings[(grp << 11) + i] != NULL) break;
+	return i + 1;
+}
+
+
+bool CompareFiles(const char *n1, const char *n2)
+{
+	FILE *f1, *f2;
+	char b1[4096];
+	char b2[4096];
+	size_t l1, l2;
+
+	f2 = fopen(n2, "rb");
+	if (f2 == NULL) return false;
+
+	f1 = fopen(n1, "rb");
+	if (f1 == NULL) fatal("can't open %s", n1);
+
+	do {
+		l1 = fread(b1, 1, sizeof(b1), f1);
+		l2 = fread(b2, 1, sizeof(b2), f2);
+
+		if (l1 != l2 || memcmp(b1, b2, l1)) {
+			fclose(f2);
+			fclose(f1);
+			return false;
+		}
+	} while (l1);
+
+	fclose(f2);
+	fclose(f1);
+	return true;
+}
+
+
+static void WriteStringsH(const char *filename)
+{
+	FILE *out;
+	int i;
+	int next = -1;
+	int lastgrp;
+
+	out = fopen("tmp.xxx", "w");
+	if (out == NULL) fatal("can't open tmp.xxx");
+
+	fprintf(out, "enum {");
+
+	lastgrp = 0;
+
+	for (i = 0; i != lengthof(_strings); i++) {
+		if (_strings[i] != NULL) {
+			if (lastgrp != (i >> 11)) {
+				lastgrp = (i >> 11);
+				fprintf(out, "};\n\nenum {");
+			}
+
+			fprintf(out, next == i ? "\t%s,\n" : "\n\t%s = 0x%X,\n", _strings[i]->name, i);
+			next = i + 1;
+		}
+	}
+
+	fprintf(out, "};\n");
+
+	fprintf(out,
+		"\nenum {\n"
+		"\tLANGUAGE_PACK_IDENT = 0x474E414C, // Big Endian value for 'LANG' (LE is 0x 4C 41 4E 47)\n"
+		"\tLANGUAGE_PACK_VERSION = 0x%X,\n"
+		"};\n", (uint)_hash
+	);
+
+	fclose(out);
+
+	if (CompareFiles("tmp.xxx", filename)) {
+		// files are equal. tmp.xxx is not needed
+		unlink("tmp.xxx");
+	} else {
+		// else rename tmp.xxx into filename
+#if defined(WIN32) || defined(WIN64)
+		unlink(filename);
+#endif
+		if (rename("tmp.xxx", filename) == -1) fatal("rename() failed");
+	}
+}
+
+static int TranslateArgumentIdx(int argidx)
+{
+	int i, sum;
+
+	if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd))
+		fatal("invalid argidx %d", argidx);
+
+	for (i = sum = 0; i < argidx; i++) {
+		const CmdStruct *cs = _cur_pcs.cmd[i];
+		sum += (cs != NULL) ? cs->consumes : 1;
+	}
+
+	return sum;
+}
+
+static void PutArgidxCommand(void)
+{
+	PutUtf8(SCC_ARG_INDEX);
+	PutByte(TranslateArgumentIdx(_cur_argidx));
+}
+
+
+static void PutCommandString(const char *str)
+{
+	const CmdStruct *cs;
+	char param[256];
+	int argno;
+	int casei;
+
+	_cur_argidx = 0;
+
+	while (*str != '\0') {
+		// Process characters as they are until we encounter a {
+		if (*str != '{') {
+			PutByte(*str++);
+			continue;
+		}
+		cs = ParseCommandString(&str, param, &argno, &casei);
+		if (cs == NULL) break;
+
+		if (casei != -1) {
+			PutUtf8(SCC_SETCASE); // {SETCASE}
+			PutByte(casei);
+		}
+
+		// For params that consume values, we need to handle the argindex properly
+		if (cs->consumes > 0) {
+			// Check if we need to output a move-param command
+			if (argno != -1 && argno != _cur_argidx) {
+				_cur_argidx = argno;
+				PutArgidxCommand();
+			}
+
+			// Output the one from the master string... it's always accurate.
+			cs = _cur_pcs.cmd[_cur_argidx++];
+			if (cs == NULL) {
+				fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1);
+			}
+		}
+
+		cs->proc(param, cs->value);
+	}
+}
+
+static void WriteLength(FILE *f, uint length)
+{
+	if (length < 0xC0) {
+		fputc(length, f);
+	} else if (length < 0x4000) {
+		fputc((length >> 8) | 0xC0, f);
+		fputc(length & 0xFF, f);
+	} else {
+		fatal("string too long");
+	}
+}
+
+
+static void WriteLangfile(const char *filename, int show_todo)
+{
+	FILE *f;
+	uint in_use[32];
+	LanguagePackHeader hdr;
+	uint i;
+	uint j;
+
+	f = fopen(filename, "wb");
+	if (f == NULL) fatal("can't open %s", filename);
+
+	memset(&hdr, 0, sizeof(hdr));
+	for (i = 0; i != 32; i++) {
+		uint n = CountInUse(i);
+
+		in_use[i] = n;
+		hdr.offsets[i] = TO_LE16(n);
+	}
+
+	// see line 655: fprintf(..."\tLANGUAGE_PACK_IDENT = 0x474E414C,...)
+	hdr.ident = TO_LE32(0x474E414C); // Big Endian value for 'LANG'
+	hdr.version = TO_LE32(_hash);
+	hdr.plural_form = _lang_pluralform;
+	strcpy(hdr.name, _lang_name);
+	strcpy(hdr.own_name, _lang_ownname);
+	strcpy(hdr.isocode, _lang_isocode);
+
+	fwrite(&hdr, sizeof(hdr), 1, f);
+
+	for (i = 0; i != 32; i++) {
+		for (j = 0; j != in_use[i]; j++) {
+			const LangString* ls = _strings[(i << 11) + j];
+			const Case* casep;
+			const char* cmdp;
+
+			// For undefined strings, just set that it's an empty string
+			if (ls == NULL) {
+				WriteLength(f, 0);
+				continue;
+			}
+
+			_cur_ident = ls->name;
+			_cur_line = ls->line;
+
+			// Produce a message if a string doesn't have a translation.
+			if (show_todo > 0 && ls->translated == NULL) {
+				if (show_todo == 2) {
+					warning("'%s' is untranslated", ls->name);
+				} else {
+					const char *s = "<TODO> ";
+					while (*s != '\0') PutByte(*s++);
+				}
+			}
+
+			// Extract the strings and stuff from the english command string
+			ExtractCommandString(&_cur_pcs, ls->english, false);
+
+			if (ls->translated_case != NULL || ls->translated != NULL) {
+				casep = ls->translated_case;
+				cmdp = ls->translated;
+			} else {
+				casep = ls->english_case;
+				cmdp = ls->english;
+			}
+
+			_translated = _masterlang || (cmdp != ls->english);
+
+			if (casep != NULL) {
+				const Case* c;
+				uint num;
+
+				// Need to output a case-switch.
+				// It has this format
+				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
+				// Each LEN is printed using 2 bytes in big endian order.
+				PutUtf8(SCC_SWITCH_CASE);
+				// Count the number of cases
+				for (num = 0, c = casep; c; c = c->next) num++;
+				PutByte(num);
+
+				// Write each case
+				for (c = casep; c != NULL; c = c->next) {
+					int pos;
+
+					PutByte(c->caseidx);
+					// Make some space for the 16-bit length
+					pos = _put_pos;
+					PutByte(0);
+					PutByte(0);
+					// Write string
+					PutCommandString(c->string);
+					PutByte(0); // terminate with a zero
+					// Fill in the length
+					_put_buf[pos + 0] = GB(_put_pos - (pos + 2), 8, 8);
+					_put_buf[pos + 1] = GB(_put_pos - (pos + 2), 0, 8);
+				}
+			}
+
+			if (cmdp != NULL) PutCommandString(cmdp);
+
+			WriteLength(f, _put_pos);
+			fwrite(_put_buf, 1, _put_pos, f);
+			_put_pos = 0;
+		}
+	}
+
+	fputc(0, f);
+	fclose(f);
+}
+
+/** Multi-OS mkdirectory function */
+static inline void ottd_mkdir(const char *directory)
+{
+#if defined(WIN32) || defined(__WATCOMC__)
+		mkdir(directory);
+#else
+		mkdir(directory, 0755);
+#endif
+}
+
+/** Create a path consisting of an already existing path, a possible
+ * path seperator and the filename. The seperator is only appended if the path
+ * does not already end with a seperator */
+static inline char *mkpath(char *buf, size_t buflen, const char *path, const char *file)
+{
+	char *p;
+	ttd_strlcpy(buf, path, buflen); // copy directory into buffer
+
+	p = strchr(buf, '\0'); // add path seperator if necessary
+	if (p[-1] != PATHSEPCHAR && (size_t)(p - buf) + 1 < buflen) *p++ = PATHSEPCHAR;
+	ttd_strlcpy(p, file, buflen - (size_t)(p - buf)); // catenate filename at end of buffer
+	return buf;
+}
+
+#if defined(__MINGW32__)
+/**
+ * On MingW, it is common that both / as \ are accepted in the
+ * params. To go with those flow, we rewrite all incoming /
+ * simply to \, so internally we can safely assume \.
+ */
+static inline char *replace_pathsep(char *s)
+{
+	char *c;
+
+	for (c = s; *c != '\0'; c++) if (*c == '/') *c = '\\';
+	return s;
+}
+#else
+static inline char *replace_pathsep(char *s) { return s; }
+#endif
+
+int CDECL main(int argc, char* argv[])
+{
+	char pathbuf[256];
+	const char *src_dir = ".";
+	const char *dest_dir = NULL;
+
+	int show_todo = 0;
+
+	while (argc > 1 && *argv[1] == '-') {
+		if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) {
+			puts("$Revision$");
+			return 0;
+		}
+
+		if (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--todo") == 0) {
+			show_todo = 1;
+			argc--, argv++;
+			continue;
+		}
+
+		if (strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "--warning") == 0) {
+			show_todo = 2;
+			argc--, argv++;
+			continue;
+		}
+
+		if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
+			puts(
+				"strgen - $Revision$\n"
+				" -v | --version    print version information and exit\n"
+				" -t | --todo       replace any untranslated strings with '<TODO>'\n"
+				" -w | --warning    print a warning for any untranslated strings\n"
+				" -h | -? | --help  print this help message and exit\n"
+				" -s | --source_dir search for english.txt in the specified directory\n"
+				" -d | --dest_dir   put output file in the specified directory, create if needed\n"
+				" Run without parameters and strgen will search for english.txt and parse it,\n"
+				" creating strings.h. Passing an argument, strgen will translate that language\n"
+				" file using english.txt as a reference and output <language>.lng."
+			);
+			return 0;
+		}
+
+		if (argc > 2 && (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--source_dir") == 0)) {
+			src_dir = replace_pathsep(argv[2]);
+			argc -= 2, argv += 2;
+			continue;
+		}
+
+		if (argc > 2 && (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--dest_dir") == 0)) {
+			dest_dir = replace_pathsep(argv[2]);
+			argc -= 2, argv += 2;
+			continue;
+		}
+
+		fprintf(stderr, "Invalid arguments\n");
+		return 0;
+	}
+
+	if (dest_dir == NULL) dest_dir = src_dir; // if dest_dir is not specified, it equals src_dir
+
+	/* strgen has two modes of operation. If no (free) arguments are passed
+	 * strgen generates strings.h to the destination directory. If it is supplied
+	 * with a (free) parameter the program will translate that language to destination
+	 * directory. As input english.txt is parsed from the source directory */
+	if (argc == 1) {
+		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
+
+		/* parse master file */
+		_masterlang = true;
+		ParseFile(pathbuf, true);
+		MakeHashOfStrings();
+		if (_errors) return 1;
+
+		/* write strings.h */
+		ottd_mkdir(dest_dir);
+		mkpath(pathbuf, lengthof(pathbuf), dest_dir, "strings.h");
+		WriteStringsH(pathbuf);
+	} else if (argc == 2) {
+		char *r;
+
+		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
+
+		/* parse master file and check if target file is correct */
+		_masterlang = false;
+		ParseFile(pathbuf, true);
+		MakeHashOfStrings();
+		ParseFile(replace_pathsep(argv[1]), false); // target file
+		if (_errors) return 1;
+
+		/* get the targetfile, strip any directories and append to destination path */
+		r = strrchr(argv[1], PATHSEPCHAR);
+		mkpath(pathbuf, lengthof(pathbuf), dest_dir, (r != NULL) ? &r[1] : argv[1]);
+
+		/* rename the .txt (input-extension) to .lng */
+		r = strrchr(pathbuf, '.');
+		if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0');
+		ttd_strlcpy(r, ".lng", (size_t)(r - pathbuf));
+		WriteLangfile(pathbuf, show_todo);
+
+		/* if showing warnings, print a summary of the language */
+		if (show_todo == 2) {
+			fprintf(stdout, "%d warnings and %d errors for %s\n", _warnings, _errors, pathbuf);
+		}
+	} else {
+		fprintf(stderr, "Invalid arguments\n");
+	}
+
+	return 0;
+}
deleted file mode 100644
--- a/src/string.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "string.h"
-#include "macros.h"
-#include "table/control_codes.h"
-
-#include <stdarg.h>
-#include <ctype.h> // required for tolower()
-
-void ttd_strlcat(char *dst, const char *src, size_t size)
-{
-	assert(size > 0);
-	for (; size > 0 && *dst != '\0'; --size, ++dst) {}
-	assert(size > 0);
-	while (--size > 0 && *src != '\0') *dst++ = *src++;
-	*dst = '\0';
-}
-
-
-void ttd_strlcpy(char *dst, const char *src, size_t size)
-{
-	assert(size > 0);
-	while (--size > 0 && *src != '\0') *dst++ = *src++;
-	*dst = '\0';
-}
-
-
-char* strecat(char* dst, const char* src, const char* last)
-{
-	assert(dst <= last);
-	for (; *dst != '\0'; ++dst)
-		if (dst == last) return dst;
-	for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
-	*dst = '\0';
-	return strecpy(dst, src, last);
-}
-
-
-char* strecpy(char* dst, const char* src, const char* last)
-{
-	assert(dst <= last);
-	for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
-	*dst = '\0';
-#if 1
-	if (dst == last && *src != '\0') {
-		error("String too long for destination buffer");
-	}
-#endif
-	return dst;
-}
-
-
-char* CDECL str_fmt(const char* str, ...)
-{
-	char buf[4096];
-	va_list va;
-	int len;
-	char* p;
-
-	va_start(va, str);
-	len = vsnprintf(buf, lengthof(buf), str, va);
-	va_end(va);
-	p = malloc(len + 1);
-	if (p != NULL) memcpy(p, buf, len + 1);
-	return p;
-}
-
-
-void str_validate(char *str)
-{
-	char *dst = str;
-	WChar c;
-	size_t len;
-
-	for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
-		if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END ||
-			IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) {
-			/* Copy the character back. Even if dst is current the same as str
-			 * (i.e. no characters have been changed) this is quicker than
-			 * moving the pointers ahead by len */
-			do {
-				*dst++ = *str++;
-			} while (--len != 0);
-		} else {
-			/* Replace the undesirable character with a question mark */
-			str += len;
-			*dst++ = '?';
-		}
-	}
-
-	*dst = '\0';
-}
-
-
-void str_strip_colours(char *str)
-{
-	char *dst = str;
-	WChar c;
-	size_t len;
-
-	for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
-		if (c < SCC_BLUE || c > SCC_BLACK) {
-			/* Copy the character back. Even if dst is current the same as str
-			 * (i.e. no characters have been changed) this is quicker than
-			 * moving the pointers ahead by len */
-			do {
-				*dst++ = *str++;
-			} while (--len != 0);
-		} else {
-			/* Just skip (strip) the colour codes */
-			str += len;
-		}
-	}
-	*dst = '\0';
-}
-
-/** Convert a given ASCII string to lowercase.
- * NOTE: only support ASCII characters, no UTF8 fancy. As currently
- * the function is only used to lowercase data-filenames if they are
- * not found, this is sufficient. If more, or general functionality is
- * needed, look to r7271 where it was removed because it was broken when
- * using certain locales: eg in Turkish the uppercase 'I' was converted to
- * '?', so just revert to the old functionality */
-void strtolower(char *str)
-{
-	for (; *str != '\0'; str++) *str = tolower(*str);
-}
-
-/**
- * Only allow certain keys. You can define the filter to be used. This makes
- *  sure no invalid keys can get into an editbox, like BELL.
- * @param key character to be checked
- * @param afilter the filter to use
- * @return true or false depending if the character is printable/valid or not
- */
-bool IsValidChar(WChar key, CharSetFilter afilter)
-{
-	switch (afilter) {
-		case CS_ALPHANUMERAL: return IsPrintable(key);
-		case CS_NUMERAL:      return (key >= '0' && key <= '9');
-		case CS_ALPHA:        return IsPrintable(key) && !(key >= '0' && key <= '9');
-	}
-
-	return false;
-}
-
-#ifdef WIN32
-int CDECL snprintf(char *str, size_t size, const char *format, ...)
-{
-	va_list ap;
-	int ret;
-
-	va_start(ap, format);
-	ret = vsnprintf(str, size, format, ap);
-	va_end(ap);
-	return ret;
-}
-
-#ifdef _MSC_VER
-int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
-{
-	int ret;
-	ret = _vsnprintf(str, size, format, ap);
-	if (ret < 0) str[size - 1] = '\0';
-	return ret;
-}
-#endif /* _MSC_VER */
-
-#endif /* WIN32 */
-
-
-/* UTF-8 handling routines */
-
-
-/* Decode and consume the next UTF-8 encoded character
- * @param c Buffer to place decoded character.
- * @param s Character stream to retrieve character from.
- * @return Number of characters in the sequence.
- */
-size_t Utf8Decode(WChar *c, const char *s)
-{
-	assert(c != NULL);
-
-	if (!HASBIT(s[0], 7)) {
-		/* Single byte character: 0xxxxxxx */
-		*c = s[0];
-		return 1;
-	} else if (GB(s[0], 5, 3) == 6) {
-		if (IsUtf8Part(s[1])) {
-			/* Double byte character: 110xxxxx 10xxxxxx */
-			*c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
-			if (*c >= 0x80) return 2;
-		}
-	} else if (GB(s[0], 4, 4) == 14) {
-		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
-			/* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */
-			*c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
-			if (*c >= 0x800) return 3;
-		}
-	} else if (GB(s[0], 3, 5) == 30) {
-		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
-			/* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
-			*c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
-			if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
-		}
-	}
-
-	//DEBUG(misc, 1, "[utf8] invalid UTF-8 sequence");
-	*c = '?';
-	return 1;
-}
-
-
-/* Encode a unicode character and place it in the buffer
- * @param buf Buffer to place character.
- * @param c   Unicode character to encode.
- * @return Number of characters in the encoded sequence.
- */
-size_t Utf8Encode(char *buf, WChar c)
-{
-	if (c < 0x80) {
-		*buf = c;
-		return 1;
-	} else if (c < 0x800) {
-		*buf++ = 0xC0 + GB(c,  6, 5);
-		*buf   = 0x80 + GB(c,  0, 6);
-		return 2;
-	} else if (c < 0x10000) {
-		*buf++ = 0xE0 + GB(c, 12, 4);
-		*buf++ = 0x80 + GB(c,  6, 6);
-		*buf   = 0x80 + GB(c,  0, 6);
-		return 3;
-	} else if (c < 0x110000) {
-		*buf++ = 0xF0 + GB(c, 18, 3);
-		*buf++ = 0x80 + GB(c, 12, 6);
-		*buf++ = 0x80 + GB(c,  6, 6);
-		*buf   = 0x80 + GB(c,  0, 6);
-		return 4;
-	}
-
-	//DEBUG(misc, 1, "[utf8] can't UTF-8 encode value 0x%X", c);
-	*buf = '?';
-	return 1;
-}
new file mode 100644
--- /dev/null
+++ b/src/string.cpp
@@ -0,0 +1,247 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "string.h"
+#include "macros.h"
+#include "table/control_codes.h"
+
+#include <stdarg.h>
+#include <ctype.h> // required for tolower()
+
+void ttd_strlcat(char *dst, const char *src, size_t size)
+{
+	assert(size > 0);
+	for (; size > 0 && *dst != '\0'; --size, ++dst) {}
+	assert(size > 0);
+	while (--size > 0 && *src != '\0') *dst++ = *src++;
+	*dst = '\0';
+}
+
+
+void ttd_strlcpy(char *dst, const char *src, size_t size)
+{
+	assert(size > 0);
+	while (--size > 0 && *src != '\0') *dst++ = *src++;
+	*dst = '\0';
+}
+
+
+char* strecat(char* dst, const char* src, const char* last)
+{
+	assert(dst <= last);
+	for (; *dst != '\0'; ++dst)
+		if (dst == last) return dst;
+	for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
+	*dst = '\0';
+	return strecpy(dst, src, last);
+}
+
+
+char* strecpy(char* dst, const char* src, const char* last)
+{
+	assert(dst <= last);
+	for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
+	*dst = '\0';
+#if 1
+	if (dst == last && *src != '\0') {
+		error("String too long for destination buffer");
+	}
+#endif
+	return dst;
+}
+
+
+char* CDECL str_fmt(const char* str, ...)
+{
+	char buf[4096];
+	va_list va;
+	int len;
+	char* p;
+
+	va_start(va, str);
+	len = vsnprintf(buf, lengthof(buf), str, va);
+	va_end(va);
+	p = malloc(len + 1);
+	if (p != NULL) memcpy(p, buf, len + 1);
+	return p;
+}
+
+
+void str_validate(char *str)
+{
+	char *dst = str;
+	WChar c;
+	size_t len;
+
+	for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
+		if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END ||
+			IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) {
+			/* Copy the character back. Even if dst is current the same as str
+			 * (i.e. no characters have been changed) this is quicker than
+			 * moving the pointers ahead by len */
+			do {
+				*dst++ = *str++;
+			} while (--len != 0);
+		} else {
+			/* Replace the undesirable character with a question mark */
+			str += len;
+			*dst++ = '?';
+		}
+	}
+
+	*dst = '\0';
+}
+
+
+void str_strip_colours(char *str)
+{
+	char *dst = str;
+	WChar c;
+	size_t len;
+
+	for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) {
+		if (c < SCC_BLUE || c > SCC_BLACK) {
+			/* Copy the character back. Even if dst is current the same as str
+			 * (i.e. no characters have been changed) this is quicker than
+			 * moving the pointers ahead by len */
+			do {
+				*dst++ = *str++;
+			} while (--len != 0);
+		} else {
+			/* Just skip (strip) the colour codes */
+			str += len;
+		}
+	}
+	*dst = '\0';
+}
+
+/** Convert a given ASCII string to lowercase.
+ * NOTE: only support ASCII characters, no UTF8 fancy. As currently
+ * the function is only used to lowercase data-filenames if they are
+ * not found, this is sufficient. If more, or general functionality is
+ * needed, look to r7271 where it was removed because it was broken when
+ * using certain locales: eg in Turkish the uppercase 'I' was converted to
+ * '?', so just revert to the old functionality */
+void strtolower(char *str)
+{
+	for (; *str != '\0'; str++) *str = tolower(*str);
+}
+
+/**
+ * Only allow certain keys. You can define the filter to be used. This makes
+ *  sure no invalid keys can get into an editbox, like BELL.
+ * @param key character to be checked
+ * @param afilter the filter to use
+ * @return true or false depending if the character is printable/valid or not
+ */
+bool IsValidChar(WChar key, CharSetFilter afilter)
+{
+	switch (afilter) {
+		case CS_ALPHANUMERAL: return IsPrintable(key);
+		case CS_NUMERAL:      return (key >= '0' && key <= '9');
+		case CS_ALPHA:        return IsPrintable(key) && !(key >= '0' && key <= '9');
+	}
+
+	return false;
+}
+
+#ifdef WIN32
+int CDECL snprintf(char *str, size_t size, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, format);
+	ret = vsnprintf(str, size, format, ap);
+	va_end(ap);
+	return ret;
+}
+
+#ifdef _MSC_VER
+int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+	int ret;
+	ret = _vsnprintf(str, size, format, ap);
+	if (ret < 0) str[size - 1] = '\0';
+	return ret;
+}
+#endif /* _MSC_VER */
+
+#endif /* WIN32 */
+
+
+/* UTF-8 handling routines */
+
+
+/* Decode and consume the next UTF-8 encoded character
+ * @param c Buffer to place decoded character.
+ * @param s Character stream to retrieve character from.
+ * @return Number of characters in the sequence.
+ */
+size_t Utf8Decode(WChar *c, const char *s)
+{
+	assert(c != NULL);
+
+	if (!HASBIT(s[0], 7)) {
+		/* Single byte character: 0xxxxxxx */
+		*c = s[0];
+		return 1;
+	} else if (GB(s[0], 5, 3) == 6) {
+		if (IsUtf8Part(s[1])) {
+			/* Double byte character: 110xxxxx 10xxxxxx */
+			*c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
+			if (*c >= 0x80) return 2;
+		}
+	} else if (GB(s[0], 4, 4) == 14) {
+		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
+			/* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */
+			*c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
+			if (*c >= 0x800) return 3;
+		}
+	} else if (GB(s[0], 3, 5) == 30) {
+		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
+			/* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+			*c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
+			if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
+		}
+	}
+
+	//DEBUG(misc, 1, "[utf8] invalid UTF-8 sequence");
+	*c = '?';
+	return 1;
+}
+
+
+/* Encode a unicode character and place it in the buffer
+ * @param buf Buffer to place character.
+ * @param c   Unicode character to encode.
+ * @return Number of characters in the encoded sequence.
+ */
+size_t Utf8Encode(char *buf, WChar c)
+{
+	if (c < 0x80) {
+		*buf = c;
+		return 1;
+	} else if (c < 0x800) {
+		*buf++ = 0xC0 + GB(c,  6, 5);
+		*buf   = 0x80 + GB(c,  0, 6);
+		return 2;
+	} else if (c < 0x10000) {
+		*buf++ = 0xE0 + GB(c, 12, 4);
+		*buf++ = 0x80 + GB(c,  6, 6);
+		*buf   = 0x80 + GB(c,  0, 6);
+		return 3;
+	} else if (c < 0x110000) {
+		*buf++ = 0xF0 + GB(c, 18, 3);
+		*buf++ = 0x80 + GB(c, 12, 6);
+		*buf++ = 0x80 + GB(c,  6, 6);
+		*buf   = 0x80 + GB(c,  0, 6);
+		return 4;
+	}
+
+	//DEBUG(misc, 1, "[utf8] can't UTF-8 encode value 0x%X", c);
+	*buf = '?';
+	return 1;
+}
deleted file mode 100644
--- a/src/strings.c
+++ /dev/null
@@ -1,1311 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "currency.h"
-#include "functions.h"
-#include "string.h"
-#include "strings.h"
-#include "table/strings.h"
-#include "namegen.h"
-#include "station.h"
-#include "town.h"
-#include "vehicle.h"
-#include "news.h"
-#include "screenshot.h"
-#include "waypoint.h"
-#include "industry.h"
-#include "variables.h"
-#include "newgrf_text.h"
-#include "table/landscape_const.h"
-#include "table/control_codes.h"
-#include "music.h"
-#include "date.h"
-#include "industry.h"
-
-#ifdef WIN32
-/* for opendir/readdir/closedir */
-# include "fios.h"
-#else
-# include <sys/types.h>
-# include <dirent.h>
-#endif /* WIN32 */
-
-char _userstring[128];
-
-static char *StationGetSpecialString(char *buff, int x, const char* last);
-static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last);
-static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last);
-
-static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last);
-
-typedef struct LanguagePack {
-	uint32 ident;
-	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
-	char name[32];      // the international name of this language
-	char own_name[32];  // the localized name of this language
-	char isocode[16];   // the ISO code for the language (not country code)
-	uint16 offsets[32]; // the offsets
-	byte plural_form;   // how to compute plural forms
-	byte pad[3];        // pad header to be a multiple of 4
-	char data[VARARRAY_SIZE];
-} LanguagePack;
-
-static char **_langpack_offs;
-static LanguagePack *_langpack;
-static uint _langtab_num[32]; // Offset into langpack offs
-static uint _langtab_start[32]; // Offset into langpack offs
-
-static const StringID _cargo_string_list[NUM_LANDSCAPE][NUM_CARGO] = {
-	{ /* LT_NORMAL */
-		STR_PASSENGERS,
-		STR_TONS,
-		STR_BAGS,
-		STR_LITERS,
-		STR_ITEMS,
-		STR_CRATES,
-		STR_TONS,
-		STR_TONS,
-		STR_TONS,
-		STR_TONS,
-		STR_BAGS,
-		STR_RES_OTHER
-	},
-
-	{ /* LT_HILLY */
-		STR_PASSENGERS,
-		STR_TONS,
-		STR_BAGS,
-		STR_LITERS,
-		STR_ITEMS,
-		STR_CRATES,
-		STR_TONS,
-		STR_TONS,
-		STR_RES_OTHER,
-		STR_TONS,
-		STR_BAGS,
-		STR_TONS
-	},
-
-	{ /* LT_DESERT */
-		STR_PASSENGERS,
-		STR_LITERS,
-		STR_BAGS,
-		STR_LITERS,
-		STR_TONS,
-		STR_CRATES,
-		STR_TONS,
-		STR_TONS,
-		STR_TONS,
-		STR_LITERS,
-		STR_BAGS,
-		STR_TONS
-	},
-
-	{ /* LT_CANDY */
-		STR_PASSENGERS,
-		STR_TONS,
-		STR_BAGS,
-		STR_NOTHING,
-		STR_NOTHING,
-		STR_TONS,
-		STR_TONS,
-		STR_LITERS,
-		STR_TONS,
-		STR_NOTHING,
-		STR_LITERS,
-		STR_NOTHING
-	}
-};
-
-
-// Read an int64 from the argv array.
-static inline int64 GetInt64(const int32 **argv)
-{
-	int64 result;
-
-	assert(argv);
-	result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32);
-	(*argv)+=2;
-	return result;
-}
-
-// Read an int32 from the argv array.
-static inline int32 GetInt32(const int32 **argv)
-{
-	assert(argv);
-	return *(*argv)++;
-}
-
-// Read an array from the argv array.
-static inline const int32 *GetArgvPtr(const int32 **argv, int n)
-{
-	const int32 *result;
-	assert(*argv);
-	result = *argv;
-	(*argv) += n;
-	return result;
-}
-
-
-#define NUM_BOUND_STRINGS 8
-
-// Array to hold the bound strings.
-static const char *_bound_strings[NUM_BOUND_STRINGS];
-
-// This index is used to implement a "round-robin" allocating of
-// slots for BindCString. NUM_BOUND_STRINGS slots are reserved.
-// Which means that after NUM_BOUND_STRINGS calls to BindCString,
-// the indices will be reused.
-static int _bind_index;
-
-static const char *GetStringPtr(StringID string)
-{
-	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
-}
-
-// The highest 8 bits of string contain the "case index".
-// These 8 bits will only be set when FormatString wants to print
-// the string in a different case. No one else except FormatString
-// should set those bits, therefore string CANNOT be StringID, but uint32.
-static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last)
-{
-	uint index = GB(string,  0, 11);
-	uint tab   = GB(string, 11,  5);
-	char buff[512];
-
-	if (GB(string, 0, 16) == 0) error("!invalid string id 0 in GetString");
-
-	switch (tab) {
-		case 4:
-			if (index >= 0xC0)
-				return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
-			break;
-
-		case 14:
-			if (index >= 0xE4)
-				return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
-			break;
-
-		// User defined name
-		case 15:
-			return GetName(buffr, index, last);
-
-		case 26:
-			/* Include string within newgrf text (format code 81) */
-			if (HASBIT(index, 10)) {
-				StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
-				return GetStringWithArgs(buffr, string, argv, last);
-			}
-			break;
-
-		case 28:
-			GetGRFString(buff, index, lastof(buff));
-			return FormatString(buffr, buff, argv, 0, last);
-
-		case 29:
-			GetGRFString(buff, index + 0x800, lastof(buff));
-			return FormatString(buffr, buff, argv, 0, last);
-
-		case 30:
-			GetGRFString(buff, index + 0x1000, lastof(buff));
-			return FormatString(buffr, buff, argv, 0, last);
-
-		case 31:
-			// dynamic strings. These are NOT to be passed through the formatter,
-			// but passed through verbatim.
-			if (index < (STR_SPEC_USERSTRING & 0x7FF)) {
-				return strecpy(buffr, _bound_strings[index], last);
-			}
-
-			return FormatString(buffr, _userstring, NULL, 0, last);
-	}
-
-	if (index >= _langtab_num[tab]) {
-		error(
-			"!String 0x%X is invalid. "
-			"Probably because an old version of the .lng file.\n", string
-		);
-	}
-
-	return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last);
-}
-
-char *GetString(char *buffr, StringID string, const char* last)
-{
-	return GetStringWithArgs(buffr, string, (int32*)_decode_parameters, last);
-}
-
-
-char *InlineString(char *buf, StringID string)
-{
-	buf += Utf8Encode(buf, SCC_STRING_ID);
-	buf += Utf8Encode(buf, string);
-	return buf;
-}
-
-
-// This function takes a C-string and allocates a temporary string ID.
-// The duration of the bound string is valid only until the next GetString,
-// so be careful.
-StringID BindCString(const char *str)
-{
-	int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1);
-	_bound_strings[idx] = str;
-	return idx + STR_SPEC_DYNSTRING;
-}
-
-// This function is used to "bind" a C string to a OpenTTD dparam slot.
-void SetDParamStr(uint n, const char *str)
-{
-	SetDParam(n, BindCString(str));
-}
-
-void InjectDParam(int amount)
-{
-	memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint32));
-}
-
-static const uint32 _divisor_table[] = {
-	1000000000,
-	100000000,
-	10000000,
-	1000000,
-
-	100000,
-	10000,
-	1000,
-	100,
-	10,
-	1
-};
-
-// TODO
-static char *FormatCommaNumber(char *buff, int32 number, const char* last)
-{
-	uint32 quot,divisor;
-	int i;
-	uint32 tot;
-	uint32 num;
-
-	if (number < 0) {
-		*buff++ = '-';
-		number = -number;
-	}
-
-	num = number;
-
-	tot = 0;
-	for (i = 0; i != 10; i++) {
-		divisor = _divisor_table[i];
-		quot = 0;
-		if (num >= divisor) {
-			quot = num / _divisor_table[i];
-			num = num % _divisor_table[i];
-		}
-		if (tot |= quot || i == 9) {
-			*buff++ = '0' + quot;
-			if (i == 0 || i == 3 || i == 6) *buff++ = ',';
-		}
-	}
-
-	*buff = '\0';
-
-	return buff;
-}
-
-// TODO
-static char *FormatNoCommaNumber(char *buff, int32 number, const char* last)
-{
-	uint32 quot,divisor;
-	int i;
-	uint32 tot;
-	uint32 num;
-
-	if (number < 0) {
-		buff = strecpy(buff, "-", last);
-		number = -number;
-	}
-
-	num = number;
-
-	tot = 0;
-	for (i = 0; i != 10; i++) {
-		divisor = _divisor_table[i];
-		quot = 0;
-		if (num >= divisor) {
-			quot = num / _divisor_table[i];
-			num = num % _divisor_table[i];
-		}
-		if (tot |= quot || i == 9) {
-			*buff++ = '0' + quot;
-		}
-	}
-
-	*buff = '\0';
-
-	return buff;
-}
-
-
-static char *FormatYmdString(char *buff, Date date, const char* last)
-{
-	YearMonthDay ymd;
-
-	ConvertDateToYMD(date, &ymd);
-
-	buff = strecpy(buff, GetStringPtr(ymd.day + STR_01AC_1ST - 1), last);
-	buff = strecpy(buff, " ", last);
-	buff = strecpy(buff, GetStringPtr(STR_0162_JAN + ymd.month), last);
-	buff = strecpy(buff, " ", last);
-
-	return FormatNoCommaNumber(buff, ymd.year, last);
-}
-
-static char *FormatMonthAndYear(char *buff, Date date, const char* last)
-{
-	YearMonthDay ymd;
-
-	ConvertDateToYMD(date, &ymd);
-
-	buff = strecpy(buff, GetStringPtr(STR_MONTH_JAN + ymd.month), last);
-	buff = strecpy(buff, " ", last);
-
-	return FormatNoCommaNumber(buff, ymd.year, last);
-}
-
-static char *FormatTinyDate(char *buff, Date date, const char* last)
-{
-	YearMonthDay ymd;
-
-	ConvertDateToYMD(date, &ymd);
-	buff += snprintf(
-		buff, last - buff + 1,
-		" %02i-%02i-%04i", ymd.day, ymd.month + 1, ymd.year
-	);
-
-	return buff;
-}
-
-static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 number, bool compact, const char* last)
-{
-	const char* multiplier = "";
-	char buf[40];
-	char* p;
-	int j;
-
-	// multiply by exchange rate
-	number *= spec->rate;
-
-	// convert from negative
-	if (number < 0) {
-		buff = strecpy(buff, "-", last);
-		number = -number;
-	}
-
-	/* Add prefix part, folowing symbol_pos specification.
-	 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
-	 * The only remaining value is 1 (suffix), so everything that is not 1 */
-	if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
-
-	// for huge numbers, compact the number into k or M
-	if (compact) {
-		if (number >= 1000000000) {
-			number = (number + 500000) / 1000000;
-			multiplier = "M";
-		} else if (number >= 1000000) {
-			number = (number + 500) / 1000;
-			multiplier = "k";
-		}
-	}
-
-	// convert to ascii number and add commas
-	p = endof(buf);
-	*--p = '\0';
-	j = 4;
-	do {
-		if (--j == 0) {
-			*--p = spec->separator;
-			j = 3;
-		}
-		*--p = '0' + number % 10;
-	} while ((number /= 10) != 0);
-	buff = strecpy(buff, p, last);
-
-	buff = strecpy(buff, multiplier, last);
-
-	/* Add suffix part, folowing symbol_pos specification.
-	 * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
-	 * The only remaining value is 1 (prefix), so everything that is not 0 */
-	if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
-
-	return buff;
-}
-
-static int DeterminePluralForm(int32 n)
-{
-	// The absolute value determines plurality
-	if (n < 0) n = -n;
-
-	switch (_langpack->plural_form) {
-	// Two forms, singular used for one only
-	// Used in:
-	//   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
-	//   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto
-	case 0:
-	default:
-		return n != 1;
-
-	// Only one form
-	// Used in:
-	//   Hungarian, Japanese, Korean, Turkish
-	case 1:
-		return 0;
-
-	// Two forms, singular used for zero and one
-	// Used in:
-	//   French, Brazilian Portuguese
-	case 2:
-		return n > 1;
-
-	// Three forms, special case for zero
-	// Used in:
-	//   Latvian
-	case 3:
-		return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;
-
-	// Three forms, special case for one and two
-	// Used in:
-	//   Gaelige (Irish)
-	case 4:
-		return n==1 ? 0 : n==2 ? 1 : 2;
-
-	// Three forms, special case for numbers ending in 1[2-9]
-	// Used in:
-	//   Lithuanian
-	case 5:
-		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;
-
-	// Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
-	// Used in:
-	//   Croatian, Czech, Russian, Slovak, Ukrainian
-	case 6:
-		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
-
-	// Three forms, special case for one and some numbers ending in 2, 3, or 4
-	// Used in:
-	//   Polish
-	case 7:
-		return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
-
-	// Four forms, special case for one and all numbers ending in 02, 03, or 04
-	// Used in:
-	//   Slovenian
-	case 8:
-		return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
-	}
-}
-
-static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
-{
-	//<NUM> {Length of each string} {each string}
-	uint n = (byte)*b++;
-	uint pos,i, mylen=0,mypos=0;
-
-	for (i = pos = 0; i != n; i++) {
-		uint len = (byte)*b++;
-		if (i == form) {
-			mypos = pos;
-			mylen = len;
-		}
-		pos += len;
-	}
-	*dstlen = mylen;
-	memcpy(dst, b + mypos, mylen);
-	return b + pos;
-}
-
-typedef struct Units {
-	int s_m;           ///< Multiplier for velocity
-	int s_s;           ///< Shift for velocity
-	StringID velocity; ///< String for velocity
-	int p_m;           ///< Multiplier for power
-	int p_s;           ///< Shift for power
-	StringID power;    ///< String for velocity
-	int w_m;           ///< Multiplier for weight
-	int w_s;           ///< Shift for weight
-	StringID s_weight; ///< Short string for weight
-	StringID l_weight; ///< Long string for weight
-	int v_m;           ///< Multiplier for volume
-	int v_s;           ///< Shift for volume
-	StringID s_volume; ///< Short string for volume
-	StringID l_volume; ///< Long string for volume
-	int f_m;           ///< Multiplier for force
-	int f_s;           ///< Shift for force
-	StringID force;    ///< String for force
-} Units;
-
-/* Unit conversions */
-static const Units units[] = {
-	{ // Imperial (Original, mph, hp, metric ton, litre, kN)
-		  10,  4, STR_UNITS_VELOCITY_IMPERIAL,
-		   1,  0, STR_UNITS_POWER_IMPERIAL,
-		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
-		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
-		   1,  0, STR_UNITS_FORCE_SI,
-	},
-	{ // Metric (km/h, hp, metric ton, litre, kN)
-		   1,  0, STR_UNITS_VELOCITY_METRIC,
-		   1,  0, STR_UNITS_POWER_METRIC,
-		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
-		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
-		   1,  0, STR_UNITS_FORCE_SI,
-	},
-	{ // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
-		 284, 10, STR_UNITS_VELOCITY_SI,
-		 764, 10, STR_UNITS_POWER_SI,
-		1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
-		   1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
-		   1,  0, STR_UNITS_FORCE_SI,
-	},
-};
-
-static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last)
-{
-	extern const char _openttd_revision[];
-	WChar b;
-	const int32 *argv_orig = argv;
-	uint modifier = 0;
-
-	while ((b = Utf8Consume(&str)) != '\0') {
-		switch (b) {
-			case SCC_SETX: // {SETX}
-				if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
-					buff += Utf8Encode(buff, SCC_SETX);
-					*buff++ = *str++;
-				}
-				break;
-
-			case SCC_SETXY: // {SETXY}
-				if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
-					buff += Utf8Encode(buff, SCC_SETXY);
-					*buff++ = *str++;
-					*buff++ = *str++;
-				}
-				break;
-
-			case SCC_STRING_ID: // {STRINL}
-				buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
-				break;
-
-			case SCC_DATE_LONG: // {DATE_LONG}
-				buff = FormatYmdString(buff, GetInt32(&argv), last);
-				break;
-
-			case SCC_DATE_SHORT: // {DATE_SHORT}
-				buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
-				break;
-
-			case SCC_VELOCITY: {// {VELOCITY}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */
-				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
-				break;
-
-			case SCC_REVISION: /* {REV} */
-				buff = strecpy(buff, _openttd_revision, last);
-				break;
-
-			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
-				// Short description of cargotypes. Layout:
-				// 8-bit = cargo type
-				// 16-bit = cargo count
-				StringID cargo_str = _cargo_types_base_values[_opt_ptr->landscape].units_volume[GetInt32(&argv)];
-				switch (cargo_str) {
-					case STR_TONS: {
-						int32 args[1];
-						assert(_opt_ptr->units < lengthof(units));
-						args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
-						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
-						modifier = 0;
-						break;
-					}
-
-					case STR_LITERS: {
-						int32 args[1];
-						assert(_opt_ptr->units < lengthof(units));
-						args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
-						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
-						modifier = 0;
-						break;
-					}
-
-					default:
-						buff = FormatCommaNumber(buff, GetInt32(&argv), last);
-						buff = strecpy(buff, " ", last);
-						buff = strecpy(buff, GetStringPtr(cargo_str), last);
-						break;
-				}
-			} break;
-
-			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
-				// 64 bit compact currency-unit
-				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
-				break;
-			}
-
-			case SCC_STRING1: { /* {STRING1} */
-				// String that consumes ONE argument
-				uint str = modifier + GetInt32(&argv);
-				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_STRING2: { /* {STRING2} */
-				// String that consumes TWO arguments
-				uint str = modifier + GetInt32(&argv);
-				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_STRING3: { /* {STRING3} */
-				// String that consumes THREE arguments
-				uint str = modifier + GetInt32(&argv);
-				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_STRING4: { /* {STRING4} */
-				// String that consumes FOUR arguments
-				uint str = modifier + GetInt32(&argv);
-				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_STRING5: { /* {STRING5} */
-				// String that consumes FIVE arguments
-				uint str = modifier + GetInt32(&argv);
-				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */
-				buff = StationGetSpecialString(buff, GetInt32(&argv), last);
-				break;
-			}
-
-			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
-				const Industry* i = GetIndustry(GetInt32(&argv));
-				int32 args[2];
-
-				// industry not valid anymore?
-				if (!IsValidIndustry(i)) break;
-
-				// First print the town name and the industry type name
-				// The string STR_INDUSTRY_PATTERN controls the formatting
-				args[0] = i->town->index;
-				args[1] = GetIndustrySpec(i->type)->name;
-				buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_VOLUME: { // {VOLUME}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_GENDER_LIST: { // {G 0 Der Die Das}
-				const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
-				int len;
-				int gender = 0;
-				if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0];
-				str = ParseStringChoice(str, gender, buff, &len);
-				buff += len;
-				break;
-			}
-
-			case SCC_DATE_TINY: { // {DATE_TINY}
-				buff = FormatTinyDate(buff, GetInt32(&argv), last);
-				break;
-			}
-
-			case SCC_CARGO: { // {CARGO}
-				// Layout now is:
-				//   8bit   - cargo type
-				//   16-bit - cargo count
-				CargoID cargo = GetInt32(&argv);
-				StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : _cargoc.names_long[cargo];
-				buff = GetStringWithArgs(buff, cargo_str, argv++, last);
-				break;
-			}
-
-			case SCC_POWER: { // {POWER}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].power), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_VOLUME_SHORT: { // {VOLUME_S}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_volume), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_WEIGHT: { // {WEIGHT}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_weight), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_FORCE: { // {FORCE}
-				int32 args[1];
-				assert(_opt_ptr->units < lengthof(units));
-				args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s;
-				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].force), args, modifier >> 24, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_SKIP: // {SKIP}
-				argv++;
-				break;
-
-			// This sets up the gender for the string.
-			// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
-			case SCC_GENDER_INDEX: // {GENDER 0}
-				str++;
-				break;
-
-			case SCC_STRING: {// {STRING}
-				uint str = modifier + GetInt32(&argv);
-				// WARNING. It's prohibited for the included string to consume any arguments.
-				// For included strings that consume argument, you should use STRING1, STRING2 etc.
-				// To debug stuff you can set argv to NULL and it will tell you
-				buff = GetStringWithArgs(buff, str, argv, last);
-				modifier = 0;
-				break;
-			}
-
-			case SCC_COMMA: // {COMMA}
-				buff = FormatCommaNumber(buff, GetInt32(&argv), last);
-				break;
-
-			case SCC_ARG_INDEX: // Move argument pointer
-				argv = argv_orig + (byte)*str++;
-				break;
-
-			case SCC_PLURAL_LIST: { // {P}
-				int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
-				int len;
-				str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
-				buff += len;
-				break;
-			}
-
-			case SCC_NUM: // {NUM}
-				buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
-				break;
-
-			case SCC_CURRENCY: // {CURRENCY}
-				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
-				break;
-
-			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
-				int32 temp[2];
-				Waypoint *wp = GetWaypoint(GetInt32(&argv));
-				StringID str;
-				if (wp->string != STR_NULL) {
-					str = wp->string;
-				} else {
-					temp[0] = wp->town_index;
-					temp[1] = wp->town_cn + 1;
-					str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
-				}
-				buff = GetStringWithArgs(buff, str, temp, last);
-				break;
-			}
-
-			case SCC_STATION_NAME: { // {STATION}
-				const Station* st = GetStation(GetInt32(&argv));
-
-				if (!IsValidStation(st)) { // station doesn't exist anymore
-					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
-				} else {
-					int32 temp[2];
-					temp[0] = st->town->townnametype;
-					temp[1] = st->town->townnameparts;
-					buff = GetStringWithArgs(buff, st->string_id, temp, last);
-				}
-				break;
-			}
-
-			case SCC_TOWN_NAME: { // {TOWN}
-				const Town* t = GetTown(GetInt32(&argv));
-				int32 temp[1];
-
-				assert(IsValidTown(t));
-
-				temp[0] = t->townnameparts;
-				buff = GetStringWithArgs(buff, t->townnametype, temp, last);
-				break;
-			}
-
-			case SCC_CURRENCY_64: { // {CURRENCY64}
-				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
-				break;
-			}
-
-			case SCC_SETCASE: { // {SETCASE}
-				// This is a pseudo command, it's outputted when someone does {STRING.ack}
-				// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
-				modifier = (byte)*str++ << 24;
-				break;
-			}
-
-			case SCC_SWITCH_CASE: { // {Used to implement case switching}
-				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
-				// Each LEN is printed using 2 bytes in big endian order.
-				uint num = (byte)*str++;
-				while (num) {
-					if ((byte)str[0] == casei) {
-						// Found the case, adjust str pointer and continue
-						str += 3;
-						break;
-					}
-					// Otherwise skip to the next case
-					str += 3 + (str[1] << 8) + str[2];
-					num--;
-				}
-				break;
-			}
-
-			default:
-				if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
-				break;
-		}
-	}
-	*buff = '\0';
-	return buff;
-}
-
-
-static char *StationGetSpecialString(char *buff, int x, const char* last)
-{
-	if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
-	if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
-	if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
-	if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
-	if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
-	*buff = '\0';
-	return buff;
-}
-
-static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last)
-{
-	char name[512];
-
-	_town_name_generators[ind](name, seed, lastof(name));
-	return strecpy(buff, name, last);
-}
-
-static const char* const _silly_company_names[] = {
-	"Bloggs Brothers",
-	"Tiny Transport Ltd.",
-	"Express Travel",
-	"Comfy-Coach & Co.",
-	"Crush & Bump Ltd.",
-	"Broken & Late Ltd.",
-	"Sam Speedy & Son",
-	"Supersonic Travel",
-	"Mike's Motors",
-	"Lightning International",
-	"Pannik & Loozit Ltd.",
-	"Inter-City Transport",
-	"Getout & Pushit Ltd."
-};
-
-static const char* const _surname_list[] = {
-	"Adams",
-	"Allan",
-	"Baker",
-	"Bigwig",
-	"Black",
-	"Bloggs",
-	"Brown",
-	"Campbell",
-	"Gordon",
-	"Hamilton",
-	"Hawthorn",
-	"Higgins",
-	"Green",
-	"Gribble",
-	"Jones",
-	"McAlpine",
-	"MacDonald",
-	"McIntosh",
-	"Muir",
-	"Murphy",
-	"Nelson",
-	"O'Donnell",
-	"Parker",
-	"Phillips",
-	"Pilkington",
-	"Quigley",
-	"Sharkey",
-	"Thomson",
-	"Watkins"
-};
-
-static const char* const _silly_surname_list[] = {
-	"Grumpy",
-	"Dozy",
-	"Speedy",
-	"Nosey",
-	"Dribble",
-	"Mushroom",
-	"Cabbage",
-	"Sniffle",
-	"Fishy",
-	"Swindle",
-	"Sneaky",
-	"Nutkins"
-};
-
-static const char _initial_name_letters[] = {
-	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
-	'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
-};
-
-static char *GenAndCoName(char *buff, uint32 arg, const char* last)
-{
-	const char* const* base;
-	uint num;
-
-	if (_opt_ptr->landscape == LT_CANDY) {
-		base = _silly_surname_list;
-		num  = lengthof(_silly_surname_list);
-	} else {
-		base = _surname_list;
-		num  = lengthof(_surname_list);
-	}
-
-	buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
-	buff = strecpy(buff, " & Co.", last);
-
-	return buff;
-}
-
-static char *GenPresidentName(char *buff, uint32 x, const char* last)
-{
-	char initial[] = "?. ";
-	const char* const* base;
-	uint num;
-	uint i;
-
-	initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
-	buff = strecpy(buff, initial, last);
-
-	i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
-	if (i < sizeof(_initial_name_letters)) {
-		initial[0] = _initial_name_letters[i];
-		buff = strecpy(buff, initial, last);
-	}
-
-	if (_opt_ptr->landscape == LT_CANDY) {
-		base = _silly_surname_list;
-		num  = lengthof(_silly_surname_list);
-	} else {
-		base = _surname_list;
-		num  = lengthof(_surname_list);
-	}
-
-	buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
-
-	return buff;
-}
-
-static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last)
-{
-	switch (ind) {
-		case 1: // not used
-			return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
-
-		case 2: // used for Foobar & Co company names
-			return GenAndCoName(buff, GetInt32(&argv), last);
-
-		case 3: // President name
-			return GenPresidentName(buff, GetInt32(&argv), last);
-
-		case 4: // song names
-			return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
-	}
-
-	// town name?
-	if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
-		buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
-		return strecpy(buff, " Transport", last);
-	}
-
-	// language name?
-	if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
-		int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
-		return strecpy(buff,
-			i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
-	}
-
-	// resolution size?
-	if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
-		int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
-		buff += snprintf(
-			buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1]
-		);
-		return buff;
-	}
-
-	// screenshot format name?
-	if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
-		int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
-		return strecpy(buff, GetScreenshotFormatDesc(i), last);
-	}
-
-	assert(0);
-	return NULL;
-}
-
-// remap a string ID from the old format to the new format
-StringID RemapOldStringID(StringID s)
-{
-	switch (s) {
-		case 0x0006: return STR_SV_EMPTY;
-		case 0x7000: return STR_SV_UNNAMED;
-		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
-		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
-		case 0x8864: return STR_SV_TRAIN_NAME;
-		case 0x902B: return STR_SV_ROADVEH_NAME;
-		case 0x9830: return STR_SV_SHIP_NAME;
-		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
-
-		default:
-			if (IS_INT_INSIDE(s, 0x300F, 0x3030)) {
-				return s - 0x300F + STR_SV_STNAME;
-			} else {
-				return s;
-			}
-	}
-}
-
-bool ReadLanguagePack(int lang_index)
-{
-	int tot_count, i;
-	LanguagePack *lang_pack;
-	size_t len;
-	char **langpack_offs;
-	char *s;
-
-	{
-		char *lang = str_fmt("%s%s", _paths.lang_dir, _dynlang.ent[lang_index].file);
-		lang_pack = ReadFileToMem(lang, &len, 200000);
-		free(lang);
-	}
-	if (lang_pack == NULL) return false;
-	if (len < sizeof(LanguagePack) ||
-			lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
-			lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
-		free(lang_pack);
-		return false;
-	}
-
-#if defined(TTD_BIG_ENDIAN)
-	for (i = 0; i != 32; i++) {
-		lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
-	}
-#endif
-
-	tot_count = 0;
-	for (i = 0; i != 32; i++) {
-		uint num = lang_pack->offsets[i];
-		_langtab_start[i] = tot_count;
-		_langtab_num[i] = num;
-		tot_count += num;
-	}
-
-	// Allocate offsets
-	langpack_offs = malloc(tot_count * sizeof(*langpack_offs));
-
-	// Fill offsets
-	s = lang_pack->data;
-	for (i = 0; i != tot_count; i++) {
-		len = (byte)*s;
-		*s++ = '\0'; // zero terminate the string before.
-		if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
-		langpack_offs[i] = s;
-		s += len;
-	}
-
-	free(_langpack);
-	_langpack = lang_pack;
-
-	free(_langpack_offs);
-	_langpack_offs = langpack_offs;
-
-	ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, sizeof(_dynlang.curr_file));
-
-	_dynlang.curr = lang_index;
-	SetCurrentGrfLangID(_langpack->isocode);
-	return true;
-}
-
-/** Determine the current charset based on the environment
- * First check some default values, after this one we passed ourselves
- * and if none exist return the value for $LANG
- * @param environment variable to check conditionally if default ones are not
- *        set. Pass NULL if you don't want additional checks.
- * @return return string containing current charset, or NULL if not-determinable */
-const char *GetCurrentLocale(const char *param)
-{
-	const char *env;
-
-	env = getenv("LANGUAGE");
-	if (env != NULL) return env;
-
-	env = getenv("LC_ALL");
-	if (env != NULL) return env;
-
-	if (param != NULL) {
-		env = getenv(param);
-		if (env != NULL) return env;
-	}
-
-	return getenv("LANG");
-}
-
-static int CDECL LanguageCompareFunc(const void *a, const void *b)
-{
-	return strcmp(*(const char* const *)a, *(const char* const *)b);
-}
-
-static int GetLanguageList(char **languages, int max)
-{
-	DIR *dir;
-	struct dirent *dirent;
-	int num = 0;
-
-	dir = opendir(_paths.lang_dir);
-	if (dir != NULL) {
-		while ((dirent = readdir(dir)) != NULL) {
-			const char *d_name = FS2OTTD(dirent->d_name);
-			char *t = strrchr(d_name, '.');
-
-			if (t != NULL && strcmp(t, ".lng") == 0) {
-				languages[num++] = strdup(d_name);
-				if (num == max) break;
-			}
-		}
-		closedir(dir);
-	}
-
-	qsort(languages, num, sizeof(char*), LanguageCompareFunc);
-	return num;
-}
-
-// make a list of the available language packs. put the data in _dynlang struct.
-void InitializeLanguagePacks(void)
-{
-	DynamicLanguages *dl = &_dynlang;
-	int i;
-	int n;
-	int m;
-	int def;
-	int def2;
-	int fallback;
-	LanguagePack hdr;
-	FILE *in;
-	char *files[MAX_LANG];
-	const char* lang;
-
-	lang = GetCurrentLocale("LC_MESSAGES");
-	if (lang == NULL) lang = "en_GB";
-
-	n = GetLanguageList(files, lengthof(files));
-
-	def = -1;
-	def2 = -1;
-	fallback = 0;
-
-	// go through the language files and make sure that they are valid.
-	for (i = m = 0; i != n; i++) {
-		size_t j;
-
-		char *s = str_fmt("%s%s", _paths.lang_dir, files[i]);
-		in = fopen(s, "rb");
-		free(s);
-		if (in == NULL ||
-				(j = fread(&hdr, sizeof(hdr), 1, in), fclose(in), j) != 1 ||
-				hdr.ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
-				hdr.version != TO_LE32(LANGUAGE_PACK_VERSION)) {
-			free(files[i]);
-			continue;
-		}
-
-		dl->ent[m].file = files[i];
-		dl->ent[m].name = strdup(hdr.name);
-
-		if (strcmp(hdr.isocode, "en_GB")  == 0) fallback = m;
-		if (strncmp(hdr.isocode, lang, 2) == 0) def2 = m;
-		if (strncmp(hdr.isocode, lang, 5) == 0) def = m;
-
-		m++;
-	}
-	if (def == -1) def = (def2 != -1 ? def2 : fallback);
-
-	if (m == 0)
-		error(n == 0 ? "No available language packs" : "Invalid version of language packs");
-
-	dl->num = m;
-	for (i = 0; i != dl->num; i++) dl->dropdown[i] = SPECSTR_LANGUAGE_START + i;
-	dl->dropdown[i] = INVALID_STRING_ID;
-
-	for (i = 0; i != dl->num; i++)
-		if (strcmp(dl->ent[i].file, dl->curr_file) == 0) {
-			def = i;
-			break;
-		}
-
-	if (!ReadLanguagePack(def))
-		error("can't read language pack '%s'", dl->ent[def].file);
-}
new file mode 100644
--- /dev/null
+++ b/src/strings.cpp
@@ -0,0 +1,1311 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "currency.h"
+#include "functions.h"
+#include "string.h"
+#include "strings.h"
+#include "table/strings.h"
+#include "namegen.h"
+#include "station.h"
+#include "town.h"
+#include "vehicle.h"
+#include "news.h"
+#include "screenshot.h"
+#include "waypoint.h"
+#include "industry.h"
+#include "variables.h"
+#include "newgrf_text.h"
+#include "table/landscape_const.h"
+#include "table/control_codes.h"
+#include "music.h"
+#include "date.h"
+#include "industry.h"
+
+#ifdef WIN32
+/* for opendir/readdir/closedir */
+# include "fios.h"
+#else
+# include <sys/types.h>
+# include <dirent.h>
+#endif /* WIN32 */
+
+char _userstring[128];
+
+static char *StationGetSpecialString(char *buff, int x, const char* last);
+static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last);
+static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last);
+
+static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last);
+
+typedef struct LanguagePack {
+	uint32 ident;
+	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
+	char name[32];      // the international name of this language
+	char own_name[32];  // the localized name of this language
+	char isocode[16];   // the ISO code for the language (not country code)
+	uint16 offsets[32]; // the offsets
+	byte plural_form;   // how to compute plural forms
+	byte pad[3];        // pad header to be a multiple of 4
+	char data[VARARRAY_SIZE];
+} LanguagePack;
+
+static char **_langpack_offs;
+static LanguagePack *_langpack;
+static uint _langtab_num[32]; // Offset into langpack offs
+static uint _langtab_start[32]; // Offset into langpack offs
+
+static const StringID _cargo_string_list[NUM_LANDSCAPE][NUM_CARGO] = {
+	{ /* LT_NORMAL */
+		STR_PASSENGERS,
+		STR_TONS,
+		STR_BAGS,
+		STR_LITERS,
+		STR_ITEMS,
+		STR_CRATES,
+		STR_TONS,
+		STR_TONS,
+		STR_TONS,
+		STR_TONS,
+		STR_BAGS,
+		STR_RES_OTHER
+	},
+
+	{ /* LT_HILLY */
+		STR_PASSENGERS,
+		STR_TONS,
+		STR_BAGS,
+		STR_LITERS,
+		STR_ITEMS,
+		STR_CRATES,
+		STR_TONS,
+		STR_TONS,
+		STR_RES_OTHER,
+		STR_TONS,
+		STR_BAGS,
+		STR_TONS
+	},
+
+	{ /* LT_DESERT */
+		STR_PASSENGERS,
+		STR_LITERS,
+		STR_BAGS,
+		STR_LITERS,
+		STR_TONS,
+		STR_CRATES,
+		STR_TONS,
+		STR_TONS,
+		STR_TONS,
+		STR_LITERS,
+		STR_BAGS,
+		STR_TONS
+	},
+
+	{ /* LT_CANDY */
+		STR_PASSENGERS,
+		STR_TONS,
+		STR_BAGS,
+		STR_NOTHING,
+		STR_NOTHING,
+		STR_TONS,
+		STR_TONS,
+		STR_LITERS,
+		STR_TONS,
+		STR_NOTHING,
+		STR_LITERS,
+		STR_NOTHING
+	}
+};
+
+
+// Read an int64 from the argv array.
+static inline int64 GetInt64(const int32 **argv)
+{
+	int64 result;
+
+	assert(argv);
+	result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32);
+	(*argv)+=2;
+	return result;
+}
+
+// Read an int32 from the argv array.
+static inline int32 GetInt32(const int32 **argv)
+{
+	assert(argv);
+	return *(*argv)++;
+}
+
+// Read an array from the argv array.
+static inline const int32 *GetArgvPtr(const int32 **argv, int n)
+{
+	const int32 *result;
+	assert(*argv);
+	result = *argv;
+	(*argv) += n;
+	return result;
+}
+
+
+#define NUM_BOUND_STRINGS 8
+
+// Array to hold the bound strings.
+static const char *_bound_strings[NUM_BOUND_STRINGS];
+
+// This index is used to implement a "round-robin" allocating of
+// slots for BindCString. NUM_BOUND_STRINGS slots are reserved.
+// Which means that after NUM_BOUND_STRINGS calls to BindCString,
+// the indices will be reused.
+static int _bind_index;
+
+static const char *GetStringPtr(StringID string)
+{
+	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
+}
+
+// The highest 8 bits of string contain the "case index".
+// These 8 bits will only be set when FormatString wants to print
+// the string in a different case. No one else except FormatString
+// should set those bits, therefore string CANNOT be StringID, but uint32.
+static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last)
+{
+	uint index = GB(string,  0, 11);
+	uint tab   = GB(string, 11,  5);
+	char buff[512];
+
+	if (GB(string, 0, 16) == 0) error("!invalid string id 0 in GetString");
+
+	switch (tab) {
+		case 4:
+			if (index >= 0xC0)
+				return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
+			break;
+
+		case 14:
+			if (index >= 0xE4)
+				return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
+			break;
+
+		// User defined name
+		case 15:
+			return GetName(buffr, index, last);
+
+		case 26:
+			/* Include string within newgrf text (format code 81) */
+			if (HASBIT(index, 10)) {
+				StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
+				return GetStringWithArgs(buffr, string, argv, last);
+			}
+			break;
+
+		case 28:
+			GetGRFString(buff, index, lastof(buff));
+			return FormatString(buffr, buff, argv, 0, last);
+
+		case 29:
+			GetGRFString(buff, index + 0x800, lastof(buff));
+			return FormatString(buffr, buff, argv, 0, last);
+
+		case 30:
+			GetGRFString(buff, index + 0x1000, lastof(buff));
+			return FormatString(buffr, buff, argv, 0, last);
+
+		case 31:
+			// dynamic strings. These are NOT to be passed through the formatter,
+			// but passed through verbatim.
+			if (index < (STR_SPEC_USERSTRING & 0x7FF)) {
+				return strecpy(buffr, _bound_strings[index], last);
+			}
+
+			return FormatString(buffr, _userstring, NULL, 0, last);
+	}
+
+	if (index >= _langtab_num[tab]) {
+		error(
+			"!String 0x%X is invalid. "
+			"Probably because an old version of the .lng file.\n", string
+		);
+	}
+
+	return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last);
+}
+
+char *GetString(char *buffr, StringID string, const char* last)
+{
+	return GetStringWithArgs(buffr, string, (int32*)_decode_parameters, last);
+}
+
+
+char *InlineString(char *buf, StringID string)
+{
+	buf += Utf8Encode(buf, SCC_STRING_ID);
+	buf += Utf8Encode(buf, string);
+	return buf;
+}
+
+
+// This function takes a C-string and allocates a temporary string ID.
+// The duration of the bound string is valid only until the next GetString,
+// so be careful.
+StringID BindCString(const char *str)
+{
+	int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1);
+	_bound_strings[idx] = str;
+	return idx + STR_SPEC_DYNSTRING;
+}
+
+// This function is used to "bind" a C string to a OpenTTD dparam slot.
+void SetDParamStr(uint n, const char *str)
+{
+	SetDParam(n, BindCString(str));
+}
+
+void InjectDParam(int amount)
+{
+	memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint32));
+}
+
+static const uint32 _divisor_table[] = {
+	1000000000,
+	100000000,
+	10000000,
+	1000000,
+
+	100000,
+	10000,
+	1000,
+	100,
+	10,
+	1
+};
+
+// TODO
+static char *FormatCommaNumber(char *buff, int32 number, const char* last)
+{
+	uint32 quot,divisor;
+	int i;
+	uint32 tot;
+	uint32 num;
+
+	if (number < 0) {
+		*buff++ = '-';
+		number = -number;
+	}
+
+	num = number;
+
+	tot = 0;
+	for (i = 0; i != 10; i++) {
+		divisor = _divisor_table[i];
+		quot = 0;
+		if (num >= divisor) {
+			quot = num / _divisor_table[i];
+			num = num % _divisor_table[i];
+		}
+		if (tot |= quot || i == 9) {
+			*buff++ = '0' + quot;
+			if (i == 0 || i == 3 || i == 6) *buff++ = ',';
+		}
+	}
+
+	*buff = '\0';
+
+	return buff;
+}
+
+// TODO
+static char *FormatNoCommaNumber(char *buff, int32 number, const char* last)
+{
+	uint32 quot,divisor;
+	int i;
+	uint32 tot;
+	uint32 num;
+
+	if (number < 0) {
+		buff = strecpy(buff, "-", last);
+		number = -number;
+	}
+
+	num = number;
+
+	tot = 0;
+	for (i = 0; i != 10; i++) {
+		divisor = _divisor_table[i];
+		quot = 0;
+		if (num >= divisor) {
+			quot = num / _divisor_table[i];
+			num = num % _divisor_table[i];
+		}
+		if (tot |= quot || i == 9) {
+			*buff++ = '0' + quot;
+		}
+	}
+
+	*buff = '\0';
+
+	return buff;
+}
+
+
+static char *FormatYmdString(char *buff, Date date, const char* last)
+{
+	YearMonthDay ymd;
+
+	ConvertDateToYMD(date, &ymd);
+
+	buff = strecpy(buff, GetStringPtr(ymd.day + STR_01AC_1ST - 1), last);
+	buff = strecpy(buff, " ", last);
+	buff = strecpy(buff, GetStringPtr(STR_0162_JAN + ymd.month), last);
+	buff = strecpy(buff, " ", last);
+
+	return FormatNoCommaNumber(buff, ymd.year, last);
+}
+
+static char *FormatMonthAndYear(char *buff, Date date, const char* last)
+{
+	YearMonthDay ymd;
+
+	ConvertDateToYMD(date, &ymd);
+
+	buff = strecpy(buff, GetStringPtr(STR_MONTH_JAN + ymd.month), last);
+	buff = strecpy(buff, " ", last);
+
+	return FormatNoCommaNumber(buff, ymd.year, last);
+}
+
+static char *FormatTinyDate(char *buff, Date date, const char* last)
+{
+	YearMonthDay ymd;
+
+	ConvertDateToYMD(date, &ymd);
+	buff += snprintf(
+		buff, last - buff + 1,
+		" %02i-%02i-%04i", ymd.day, ymd.month + 1, ymd.year
+	);
+
+	return buff;
+}
+
+static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 number, bool compact, const char* last)
+{
+	const char* multiplier = "";
+	char buf[40];
+	char* p;
+	int j;
+
+	// multiply by exchange rate
+	number *= spec->rate;
+
+	// convert from negative
+	if (number < 0) {
+		buff = strecpy(buff, "-", last);
+		number = -number;
+	}
+
+	/* Add prefix part, folowing symbol_pos specification.
+	 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
+	 * The only remaining value is 1 (suffix), so everything that is not 1 */
+	if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
+
+	// for huge numbers, compact the number into k or M
+	if (compact) {
+		if (number >= 1000000000) {
+			number = (number + 500000) / 1000000;
+			multiplier = "M";
+		} else if (number >= 1000000) {
+			number = (number + 500) / 1000;
+			multiplier = "k";
+		}
+	}
+
+	// convert to ascii number and add commas
+	p = endof(buf);
+	*--p = '\0';
+	j = 4;
+	do {
+		if (--j == 0) {
+			*--p = spec->separator;
+			j = 3;
+		}
+		*--p = '0' + number % 10;
+	} while ((number /= 10) != 0);
+	buff = strecpy(buff, p, last);
+
+	buff = strecpy(buff, multiplier, last);
+
+	/* Add suffix part, folowing symbol_pos specification.
+	 * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
+	 * The only remaining value is 1 (prefix), so everything that is not 0 */
+	if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
+
+	return buff;
+}
+
+static int DeterminePluralForm(int32 n)
+{
+	// The absolute value determines plurality
+	if (n < 0) n = -n;
+
+	switch (_langpack->plural_form) {
+	// Two forms, singular used for one only
+	// Used in:
+	//   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
+	//   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto
+	case 0:
+	default:
+		return n != 1;
+
+	// Only one form
+	// Used in:
+	//   Hungarian, Japanese, Korean, Turkish
+	case 1:
+		return 0;
+
+	// Two forms, singular used for zero and one
+	// Used in:
+	//   French, Brazilian Portuguese
+	case 2:
+		return n > 1;
+
+	// Three forms, special case for zero
+	// Used in:
+	//   Latvian
+	case 3:
+		return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;
+
+	// Three forms, special case for one and two
+	// Used in:
+	//   Gaelige (Irish)
+	case 4:
+		return n==1 ? 0 : n==2 ? 1 : 2;
+
+	// Three forms, special case for numbers ending in 1[2-9]
+	// Used in:
+	//   Lithuanian
+	case 5:
+		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;
+
+	// Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
+	// Used in:
+	//   Croatian, Czech, Russian, Slovak, Ukrainian
+	case 6:
+		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
+
+	// Three forms, special case for one and some numbers ending in 2, 3, or 4
+	// Used in:
+	//   Polish
+	case 7:
+		return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
+
+	// Four forms, special case for one and all numbers ending in 02, 03, or 04
+	// Used in:
+	//   Slovenian
+	case 8:
+		return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
+	}
+}
+
+static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
+{
+	//<NUM> {Length of each string} {each string}
+	uint n = (byte)*b++;
+	uint pos,i, mylen=0,mypos=0;
+
+	for (i = pos = 0; i != n; i++) {
+		uint len = (byte)*b++;
+		if (i == form) {
+			mypos = pos;
+			mylen = len;
+		}
+		pos += len;
+	}
+	*dstlen = mylen;
+	memcpy(dst, b + mypos, mylen);
+	return b + pos;
+}
+
+typedef struct Units {
+	int s_m;           ///< Multiplier for velocity
+	int s_s;           ///< Shift for velocity
+	StringID velocity; ///< String for velocity
+	int p_m;           ///< Multiplier for power
+	int p_s;           ///< Shift for power
+	StringID power;    ///< String for velocity
+	int w_m;           ///< Multiplier for weight
+	int w_s;           ///< Shift for weight
+	StringID s_weight; ///< Short string for weight
+	StringID l_weight; ///< Long string for weight
+	int v_m;           ///< Multiplier for volume
+	int v_s;           ///< Shift for volume
+	StringID s_volume; ///< Short string for volume
+	StringID l_volume; ///< Long string for volume
+	int f_m;           ///< Multiplier for force
+	int f_s;           ///< Shift for force
+	StringID force;    ///< String for force
+} Units;
+
+/* Unit conversions */
+static const Units units[] = {
+	{ // Imperial (Original, mph, hp, metric ton, litre, kN)
+		  10,  4, STR_UNITS_VELOCITY_IMPERIAL,
+		   1,  0, STR_UNITS_POWER_IMPERIAL,
+		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
+		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
+		   1,  0, STR_UNITS_FORCE_SI,
+	},
+	{ // Metric (km/h, hp, metric ton, litre, kN)
+		   1,  0, STR_UNITS_VELOCITY_METRIC,
+		   1,  0, STR_UNITS_POWER_METRIC,
+		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
+		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
+		   1,  0, STR_UNITS_FORCE_SI,
+	},
+	{ // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
+		 284, 10, STR_UNITS_VELOCITY_SI,
+		 764, 10, STR_UNITS_POWER_SI,
+		1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
+		   1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
+		   1,  0, STR_UNITS_FORCE_SI,
+	},
+};
+
+static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last)
+{
+	extern const char _openttd_revision[];
+	WChar b;
+	const int32 *argv_orig = argv;
+	uint modifier = 0;
+
+	while ((b = Utf8Consume(&str)) != '\0') {
+		switch (b) {
+			case SCC_SETX: // {SETX}
+				if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
+					buff += Utf8Encode(buff, SCC_SETX);
+					*buff++ = *str++;
+				}
+				break;
+
+			case SCC_SETXY: // {SETXY}
+				if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
+					buff += Utf8Encode(buff, SCC_SETXY);
+					*buff++ = *str++;
+					*buff++ = *str++;
+				}
+				break;
+
+			case SCC_STRING_ID: // {STRINL}
+				buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
+				break;
+
+			case SCC_DATE_LONG: // {DATE_LONG}
+				buff = FormatYmdString(buff, GetInt32(&argv), last);
+				break;
+
+			case SCC_DATE_SHORT: // {DATE_SHORT}
+				buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
+				break;
+
+			case SCC_VELOCITY: {// {VELOCITY}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */
+				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
+				break;
+
+			case SCC_REVISION: /* {REV} */
+				buff = strecpy(buff, _openttd_revision, last);
+				break;
+
+			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
+				// Short description of cargotypes. Layout:
+				// 8-bit = cargo type
+				// 16-bit = cargo count
+				StringID cargo_str = _cargo_types_base_values[_opt_ptr->landscape].units_volume[GetInt32(&argv)];
+				switch (cargo_str) {
+					case STR_TONS: {
+						int32 args[1];
+						assert(_opt_ptr->units < lengthof(units));
+						args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
+						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
+						modifier = 0;
+						break;
+					}
+
+					case STR_LITERS: {
+						int32 args[1];
+						assert(_opt_ptr->units < lengthof(units));
+						args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
+						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
+						modifier = 0;
+						break;
+					}
+
+					default:
+						buff = FormatCommaNumber(buff, GetInt32(&argv), last);
+						buff = strecpy(buff, " ", last);
+						buff = strecpy(buff, GetStringPtr(cargo_str), last);
+						break;
+				}
+			} break;
+
+			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
+				// 64 bit compact currency-unit
+				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
+				break;
+			}
+
+			case SCC_STRING1: { /* {STRING1} */
+				// String that consumes ONE argument
+				uint str = modifier + GetInt32(&argv);
+				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_STRING2: { /* {STRING2} */
+				// String that consumes TWO arguments
+				uint str = modifier + GetInt32(&argv);
+				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_STRING3: { /* {STRING3} */
+				// String that consumes THREE arguments
+				uint str = modifier + GetInt32(&argv);
+				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_STRING4: { /* {STRING4} */
+				// String that consumes FOUR arguments
+				uint str = modifier + GetInt32(&argv);
+				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_STRING5: { /* {STRING5} */
+				// String that consumes FIVE arguments
+				uint str = modifier + GetInt32(&argv);
+				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */
+				buff = StationGetSpecialString(buff, GetInt32(&argv), last);
+				break;
+			}
+
+			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
+				const Industry* i = GetIndustry(GetInt32(&argv));
+				int32 args[2];
+
+				// industry not valid anymore?
+				if (!IsValidIndustry(i)) break;
+
+				// First print the town name and the industry type name
+				// The string STR_INDUSTRY_PATTERN controls the formatting
+				args[0] = i->town->index;
+				args[1] = GetIndustrySpec(i->type)->name;
+				buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_VOLUME: { // {VOLUME}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_GENDER_LIST: { // {G 0 Der Die Das}
+				const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
+				int len;
+				int gender = 0;
+				if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0];
+				str = ParseStringChoice(str, gender, buff, &len);
+				buff += len;
+				break;
+			}
+
+			case SCC_DATE_TINY: { // {DATE_TINY}
+				buff = FormatTinyDate(buff, GetInt32(&argv), last);
+				break;
+			}
+
+			case SCC_CARGO: { // {CARGO}
+				// Layout now is:
+				//   8bit   - cargo type
+				//   16-bit - cargo count
+				CargoID cargo = GetInt32(&argv);
+				StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : _cargoc.names_long[cargo];
+				buff = GetStringWithArgs(buff, cargo_str, argv++, last);
+				break;
+			}
+
+			case SCC_POWER: { // {POWER}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].power), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_VOLUME_SHORT: { // {VOLUME_S}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_volume), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_WEIGHT: { // {WEIGHT}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_weight), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_FORCE: { // {FORCE}
+				int32 args[1];
+				assert(_opt_ptr->units < lengthof(units));
+				args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s;
+				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].force), args, modifier >> 24, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_SKIP: // {SKIP}
+				argv++;
+				break;
+
+			// This sets up the gender for the string.
+			// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
+			case SCC_GENDER_INDEX: // {GENDER 0}
+				str++;
+				break;
+
+			case SCC_STRING: {// {STRING}
+				uint str = modifier + GetInt32(&argv);
+				// WARNING. It's prohibited for the included string to consume any arguments.
+				// For included strings that consume argument, you should use STRING1, STRING2 etc.
+				// To debug stuff you can set argv to NULL and it will tell you
+				buff = GetStringWithArgs(buff, str, argv, last);
+				modifier = 0;
+				break;
+			}
+
+			case SCC_COMMA: // {COMMA}
+				buff = FormatCommaNumber(buff, GetInt32(&argv), last);
+				break;
+
+			case SCC_ARG_INDEX: // Move argument pointer
+				argv = argv_orig + (byte)*str++;
+				break;
+
+			case SCC_PLURAL_LIST: { // {P}
+				int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
+				int len;
+				str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
+				buff += len;
+				break;
+			}
+
+			case SCC_NUM: // {NUM}
+				buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
+				break;
+
+			case SCC_CURRENCY: // {CURRENCY}
+				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
+				break;
+
+			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
+				int32 temp[2];
+				Waypoint *wp = GetWaypoint(GetInt32(&argv));
+				StringID str;
+				if (wp->string != STR_NULL) {
+					str = wp->string;
+				} else {
+					temp[0] = wp->town_index;
+					temp[1] = wp->town_cn + 1;
+					str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
+				}
+				buff = GetStringWithArgs(buff, str, temp, last);
+				break;
+			}
+
+			case SCC_STATION_NAME: { // {STATION}
+				const Station* st = GetStation(GetInt32(&argv));
+
+				if (!IsValidStation(st)) { // station doesn't exist anymore
+					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
+				} else {
+					int32 temp[2];
+					temp[0] = st->town->townnametype;
+					temp[1] = st->town->townnameparts;
+					buff = GetStringWithArgs(buff, st->string_id, temp, last);
+				}
+				break;
+			}
+
+			case SCC_TOWN_NAME: { // {TOWN}
+				const Town* t = GetTown(GetInt32(&argv));
+				int32 temp[1];
+
+				assert(IsValidTown(t));
+
+				temp[0] = t->townnameparts;
+				buff = GetStringWithArgs(buff, t->townnametype, temp, last);
+				break;
+			}
+
+			case SCC_CURRENCY_64: { // {CURRENCY64}
+				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
+				break;
+			}
+
+			case SCC_SETCASE: { // {SETCASE}
+				// This is a pseudo command, it's outputted when someone does {STRING.ack}
+				// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
+				modifier = (byte)*str++ << 24;
+				break;
+			}
+
+			case SCC_SWITCH_CASE: { // {Used to implement case switching}
+				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
+				// Each LEN is printed using 2 bytes in big endian order.
+				uint num = (byte)*str++;
+				while (num) {
+					if ((byte)str[0] == casei) {
+						// Found the case, adjust str pointer and continue
+						str += 3;
+						break;
+					}
+					// Otherwise skip to the next case
+					str += 3 + (str[1] << 8) + str[2];
+					num--;
+				}
+				break;
+			}
+
+			default:
+				if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
+				break;
+		}
+	}
+	*buff = '\0';
+	return buff;
+}
+
+
+static char *StationGetSpecialString(char *buff, int x, const char* last)
+{
+	if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
+	if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
+	if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
+	if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
+	if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
+	*buff = '\0';
+	return buff;
+}
+
+static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last)
+{
+	char name[512];
+
+	_town_name_generators[ind](name, seed, lastof(name));
+	return strecpy(buff, name, last);
+}
+
+static const char* const _silly_company_names[] = {
+	"Bloggs Brothers",
+	"Tiny Transport Ltd.",
+	"Express Travel",
+	"Comfy-Coach & Co.",
+	"Crush & Bump Ltd.",
+	"Broken & Late Ltd.",
+	"Sam Speedy & Son",
+	"Supersonic Travel",
+	"Mike's Motors",
+	"Lightning International",
+	"Pannik & Loozit Ltd.",
+	"Inter-City Transport",
+	"Getout & Pushit Ltd."
+};
+
+static const char* const _surname_list[] = {
+	"Adams",
+	"Allan",
+	"Baker",
+	"Bigwig",
+	"Black",
+	"Bloggs",
+	"Brown",
+	"Campbell",
+	"Gordon",
+	"Hamilton",
+	"Hawthorn",
+	"Higgins",
+	"Green",
+	"Gribble",
+	"Jones",
+	"McAlpine",
+	"MacDonald",
+	"McIntosh",
+	"Muir",
+	"Murphy",
+	"Nelson",
+	"O'Donnell",
+	"Parker",
+	"Phillips",
+	"Pilkington",
+	"Quigley",
+	"Sharkey",
+	"Thomson",
+	"Watkins"
+};
+
+static const char* const _silly_surname_list[] = {
+	"Grumpy",
+	"Dozy",
+	"Speedy",
+	"Nosey",
+	"Dribble",
+	"Mushroom",
+	"Cabbage",
+	"Sniffle",
+	"Fishy",
+	"Swindle",
+	"Sneaky",
+	"Nutkins"
+};
+
+static const char _initial_name_letters[] = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+	'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
+};
+
+static char *GenAndCoName(char *buff, uint32 arg, const char* last)
+{
+	const char* const* base;
+	uint num;
+
+	if (_opt_ptr->landscape == LT_CANDY) {
+		base = _silly_surname_list;
+		num  = lengthof(_silly_surname_list);
+	} else {
+		base = _surname_list;
+		num  = lengthof(_surname_list);
+	}
+
+	buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
+	buff = strecpy(buff, " & Co.", last);
+
+	return buff;
+}
+
+static char *GenPresidentName(char *buff, uint32 x, const char* last)
+{
+	char initial[] = "?. ";
+	const char* const* base;
+	uint num;
+	uint i;
+
+	initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
+	buff = strecpy(buff, initial, last);
+
+	i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
+	if (i < sizeof(_initial_name_letters)) {
+		initial[0] = _initial_name_letters[i];
+		buff = strecpy(buff, initial, last);
+	}
+
+	if (_opt_ptr->landscape == LT_CANDY) {
+		base = _silly_surname_list;
+		num  = lengthof(_silly_surname_list);
+	} else {
+		base = _surname_list;
+		num  = lengthof(_surname_list);
+	}
+
+	buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
+
+	return buff;
+}
+
+static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last)
+{
+	switch (ind) {
+		case 1: // not used
+			return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
+
+		case 2: // used for Foobar & Co company names
+			return GenAndCoName(buff, GetInt32(&argv), last);
+
+		case 3: // President name
+			return GenPresidentName(buff, GetInt32(&argv), last);
+
+		case 4: // song names
+			return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
+	}
+
+	// town name?
+	if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
+		buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
+		return strecpy(buff, " Transport", last);
+	}
+
+	// language name?
+	if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
+		int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
+		return strecpy(buff,
+			i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
+	}
+
+	// resolution size?
+	if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
+		int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
+		buff += snprintf(
+			buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1]
+		);
+		return buff;
+	}
+
+	// screenshot format name?
+	if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
+		int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
+		return strecpy(buff, GetScreenshotFormatDesc(i), last);
+	}
+
+	assert(0);
+	return NULL;
+}
+
+// remap a string ID from the old format to the new format
+StringID RemapOldStringID(StringID s)
+{
+	switch (s) {
+		case 0x0006: return STR_SV_EMPTY;
+		case 0x7000: return STR_SV_UNNAMED;
+		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
+		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
+		case 0x8864: return STR_SV_TRAIN_NAME;
+		case 0x902B: return STR_SV_ROADVEH_NAME;
+		case 0x9830: return STR_SV_SHIP_NAME;
+		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
+
+		default:
+			if (IS_INT_INSIDE(s, 0x300F, 0x3030)) {
+				return s - 0x300F + STR_SV_STNAME;
+			} else {
+				return s;
+			}
+	}
+}
+
+bool ReadLanguagePack(int lang_index)
+{
+	int tot_count, i;
+	LanguagePack *lang_pack;
+	size_t len;
+	char **langpack_offs;
+	char *s;
+
+	{
+		char *lang = str_fmt("%s%s", _paths.lang_dir, _dynlang.ent[lang_index].file);
+		lang_pack = ReadFileToMem(lang, &len, 200000);
+		free(lang);
+	}
+	if (lang_pack == NULL) return false;
+	if (len < sizeof(LanguagePack) ||
+			lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
+			lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
+		free(lang_pack);
+		return false;
+	}
+
+#if defined(TTD_BIG_ENDIAN)
+	for (i = 0; i != 32; i++) {
+		lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
+	}
+#endif
+
+	tot_count = 0;
+	for (i = 0; i != 32; i++) {
+		uint num = lang_pack->offsets[i];
+		_langtab_start[i] = tot_count;
+		_langtab_num[i] = num;
+		tot_count += num;
+	}
+
+	// Allocate offsets
+	langpack_offs = malloc(tot_count * sizeof(*langpack_offs));
+
+	// Fill offsets
+	s = lang_pack->data;
+	for (i = 0; i != tot_count; i++) {
+		len = (byte)*s;
+		*s++ = '\0'; // zero terminate the string before.
+		if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
+		langpack_offs[i] = s;
+		s += len;
+	}
+
+	free(_langpack);
+	_langpack = lang_pack;
+
+	free(_langpack_offs);
+	_langpack_offs = langpack_offs;
+
+	ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, sizeof(_dynlang.curr_file));
+
+	_dynlang.curr = lang_index;
+	SetCurrentGrfLangID(_langpack->isocode);
+	return true;
+}
+
+/** Determine the current charset based on the environment
+ * First check some default values, after this one we passed ourselves
+ * and if none exist return the value for $LANG
+ * @param environment variable to check conditionally if default ones are not
+ *        set. Pass NULL if you don't want additional checks.
+ * @return return string containing current charset, or NULL if not-determinable */
+const char *GetCurrentLocale(const char *param)
+{
+	const char *env;
+
+	env = getenv("LANGUAGE");
+	if (env != NULL) return env;
+
+	env = getenv("LC_ALL");
+	if (env != NULL) return env;
+
+	if (param != NULL) {
+		env = getenv(param);
+		if (env != NULL) return env;
+	}
+
+	return getenv("LANG");
+}
+
+static int CDECL LanguageCompareFunc(const void *a, const void *b)
+{
+	return strcmp(*(const char* const *)a, *(const char* const *)b);
+}
+
+static int GetLanguageList(char **languages, int max)
+{
+	DIR *dir;
+	struct dirent *dirent;
+	int num = 0;
+
+	dir = opendir(_paths.lang_dir);
+	if (dir != NULL) {
+		while ((dirent = readdir(dir)) != NULL) {
+			const char *d_name = FS2OTTD(dirent->d_name);
+			char *t = strrchr(d_name, '.');
+
+			if (t != NULL && strcmp(t, ".lng") == 0) {
+				languages[num++] = strdup(d_name);
+				if (num == max) break;
+			}
+		}
+		closedir(dir);
+	}
+
+	qsort(languages, num, sizeof(char*), LanguageCompareFunc);
+	return num;
+}
+
+// make a list of the available language packs. put the data in _dynlang struct.
+void InitializeLanguagePacks(void)
+{
+	DynamicLanguages *dl = &_dynlang;
+	int i;
+	int n;
+	int m;
+	int def;
+	int def2;
+	int fallback;
+	LanguagePack hdr;
+	FILE *in;
+	char *files[MAX_LANG];
+	const char* lang;
+
+	lang = GetCurrentLocale("LC_MESSAGES");
+	if (lang == NULL) lang = "en_GB";
+
+	n = GetLanguageList(files, lengthof(files));
+
+	def = -1;
+	def2 = -1;
+	fallback = 0;
+
+	// go through the language files and make sure that they are valid.
+	for (i = m = 0; i != n; i++) {
+		size_t j;
+
+		char *s = str_fmt("%s%s", _paths.lang_dir, files[i]);
+		in = fopen(s, "rb");
+		free(s);
+		if (in == NULL ||
+				(j = fread(&hdr, sizeof(hdr), 1, in), fclose(in), j) != 1 ||
+				hdr.ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
+				hdr.version != TO_LE32(LANGUAGE_PACK_VERSION)) {
+			free(files[i]);
+			continue;
+		}
+
+		dl->ent[m].file = files[i];
+		dl->ent[m].name = strdup(hdr.name);
+
+		if (strcmp(hdr.isocode, "en_GB")  == 0) fallback = m;
+		if (strncmp(hdr.isocode, lang, 2) == 0) def2 = m;
+		if (strncmp(hdr.isocode, lang, 5) == 0) def = m;
+
+		m++;
+	}
+	if (def == -1) def = (def2 != -1 ? def2 : fallback);
+
+	if (m == 0)
+		error(n == 0 ? "No available language packs" : "Invalid version of language packs");
+
+	dl->num = m;
+	for (i = 0; i != dl->num; i++) dl->dropdown[i] = SPECSTR_LANGUAGE_START + i;
+	dl->dropdown[i] = INVALID_STRING_ID;
+
+	for (i = 0; i != dl->num; i++)
+		if (strcmp(dl->ent[i].file, dl->curr_file) == 0) {
+			def = i;
+			break;
+		}
+
+	if (!ReadLanguagePack(def))
+		error("can't read language pack '%s'", dl->ent[def].file);
+}
deleted file mode 100644
--- a/src/subsidy_gui.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "window.h"
-#include "station.h"
-#include "industry.h"
-#include "town.h"
-#include "player.h"
-#include "gfx.h"
-#include "economy.h"
-#include "variables.h"
-#include "date.h"
-
-static void HandleSubsidyClick(int y)
-{
-	const Subsidy *s;
-	uint num;
-	int offs;
-	TileIndex xy;
-
-	if (y < 0) return;
-
-	num = 0;
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12) {
-			y -= 10;
-			if (y < 0) goto handle_click;
-			num++;
-		}
-	}
-
-	if (num == 0) {
-		y -= 10;
-		if (y < 0) return;
-	}
-
-	y -= 11;
-	if (y < 0) return;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age >= 12) {
-			y -= 10;
-			if (y < 0) goto handle_click;
-		}
-	}
-	return;
-
-handle_click:
-
-	/* determine from coordinate for subsidy and try to scroll to it */
-	offs = s->from;
-	if (s->age >= 12) {
-		xy = GetStation(offs)->xy;
-	} else if (s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL) {
-		xy = GetTown(offs)->xy;
-	} else {
-		xy = GetIndustry(offs)->xy;
-
-	}
-	if (!ScrollMainWindowToTile(xy)) {
-		/* otherwise determine to coordinate for subsidy and scroll to it */
-		offs = s->to;
-		if (s->age >= 12) {
-			xy = GetStation(offs)->xy;
-		} else if (s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL || s->cargo_type == CT_GOODS || s->cargo_type == CT_FOOD) {
-			xy = GetTown(offs)->xy;
-		} else {
-			xy = GetIndustry(offs)->xy;
-		}
-		ScrollMainWindowToTile(xy);
-	}
-}
-
-static void DrawSubsidiesWindow(const Window *w)
-{
-	YearMonthDay ymd;
-	const Subsidy *s;
-	uint num;
-	int x;
-	int y;
-
-	DrawWindowWidgets(w);
-
-	ConvertDateToYMD(_date, &ymd);
-
-	y = 15;
-	x = 1;
-	DrawString(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, 0);
-	y += 10;
-	num = 0;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12) {
-			int x2;
-
-			SetupSubsidyDecodeParam(s, 1);
-			x2 = DrawString(x + 2, y, STR_2027_FROM_TO, 0);
-
-			SetDParam(0, _date - ymd.day + 384 - s->age * 32);
-			DrawString(x2, y, STR_2028_BY, 0);
-			y += 10;
-			num++;
-		}
-	}
-
-	if (num == 0) {
-		DrawString(x + 2, y, STR_202A_NONE, 0);
-		y += 10;
-	}
-
-	DrawString(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, 0);
-	y += 10;
-	num = 0;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age >= 12) {
-			const Player *p;
-			int xt;
-
-			SetupSubsidyDecodeParam(s, 1);
-
-			p = GetPlayer(GetStation(s->to)->owner);
-			SetDParam(3, p->name_1);
-			SetDParam(4, p->name_2);
-
-			xt = DrawString(x + 2, y, STR_202C_FROM_TO, 0);
-
-			SetDParam(0, _date - ymd.day + 768 - s->age * 32);
-			DrawString(xt, y, STR_202D_UNTIL, 0);
-			y += 10;
-			num++;
-		}
-	}
-
-	if (num == 0) DrawString(x + 2, y, STR_202A_NONE, 0);
-}
-
-static void SubsidiesListWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: DrawSubsidiesWindow(w); break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3:
-					HandleSubsidyClick(e->we.click.pt.y - 25);
-					break;
-			}
-		break;
-	}
-}
-
-static const Widget _subsidies_list_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,           STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE, 13,  11, 617,   0,  13, STR_2025_SUBSIDIES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE, 13, 618, 629,   0,  13, STR_NULL,           STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE, 13,   0, 629,  14, 126, 0x0,                STR_01FD_CLICK_ON_SERVICE_TO_CENTER},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _subsidies_list_desc = {
-	WDP_AUTO, WDP_AUTO, 630, 127,
-	WC_SUBSIDIES_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_subsidies_list_widgets,
-	SubsidiesListWndProc
-};
-
-
-void ShowSubsidiesList(void)
-{
-	AllocateWindowDescFront(&_subsidies_list_desc, 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/subsidy_gui.cpp
@@ -0,0 +1,176 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "window.h"
+#include "station.h"
+#include "industry.h"
+#include "town.h"
+#include "player.h"
+#include "gfx.h"
+#include "economy.h"
+#include "variables.h"
+#include "date.h"
+
+static void HandleSubsidyClick(int y)
+{
+	const Subsidy *s;
+	uint num;
+	int offs;
+	TileIndex xy;
+
+	if (y < 0) return;
+
+	num = 0;
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age < 12) {
+			y -= 10;
+			if (y < 0) goto handle_click;
+			num++;
+		}
+	}
+
+	if (num == 0) {
+		y -= 10;
+		if (y < 0) return;
+	}
+
+	y -= 11;
+	if (y < 0) return;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age >= 12) {
+			y -= 10;
+			if (y < 0) goto handle_click;
+		}
+	}
+	return;
+
+handle_click:
+
+	/* determine from coordinate for subsidy and try to scroll to it */
+	offs = s->from;
+	if (s->age >= 12) {
+		xy = GetStation(offs)->xy;
+	} else if (s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL) {
+		xy = GetTown(offs)->xy;
+	} else {
+		xy = GetIndustry(offs)->xy;
+
+	}
+	if (!ScrollMainWindowToTile(xy)) {
+		/* otherwise determine to coordinate for subsidy and scroll to it */
+		offs = s->to;
+		if (s->age >= 12) {
+			xy = GetStation(offs)->xy;
+		} else if (s->cargo_type == CT_PASSENGERS || s->cargo_type == CT_MAIL || s->cargo_type == CT_GOODS || s->cargo_type == CT_FOOD) {
+			xy = GetTown(offs)->xy;
+		} else {
+			xy = GetIndustry(offs)->xy;
+		}
+		ScrollMainWindowToTile(xy);
+	}
+}
+
+static void DrawSubsidiesWindow(const Window *w)
+{
+	YearMonthDay ymd;
+	const Subsidy *s;
+	uint num;
+	int x;
+	int y;
+
+	DrawWindowWidgets(w);
+
+	ConvertDateToYMD(_date, &ymd);
+
+	y = 15;
+	x = 1;
+	DrawString(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, 0);
+	y += 10;
+	num = 0;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age < 12) {
+			int x2;
+
+			SetupSubsidyDecodeParam(s, 1);
+			x2 = DrawString(x + 2, y, STR_2027_FROM_TO, 0);
+
+			SetDParam(0, _date - ymd.day + 384 - s->age * 32);
+			DrawString(x2, y, STR_2028_BY, 0);
+			y += 10;
+			num++;
+		}
+	}
+
+	if (num == 0) {
+		DrawString(x + 2, y, STR_202A_NONE, 0);
+		y += 10;
+	}
+
+	DrawString(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, 0);
+	y += 10;
+	num = 0;
+
+	for (s = _subsidies; s != endof(_subsidies); s++) {
+		if (s->cargo_type != CT_INVALID && s->age >= 12) {
+			const Player *p;
+			int xt;
+
+			SetupSubsidyDecodeParam(s, 1);
+
+			p = GetPlayer(GetStation(s->to)->owner);
+			SetDParam(3, p->name_1);
+			SetDParam(4, p->name_2);
+
+			xt = DrawString(x + 2, y, STR_202C_FROM_TO, 0);
+
+			SetDParam(0, _date - ymd.day + 768 - s->age * 32);
+			DrawString(xt, y, STR_202D_UNTIL, 0);
+			y += 10;
+			num++;
+		}
+	}
+
+	if (num == 0) DrawString(x + 2, y, STR_202A_NONE, 0);
+}
+
+static void SubsidiesListWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: DrawSubsidiesWindow(w); break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case 3:
+					HandleSubsidyClick(e->we.click.pt.y - 25);
+					break;
+			}
+		break;
+	}
+}
+
+static const Widget _subsidies_list_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE, 13,   0,  10,   0,  13, STR_00C5,           STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE, 13,  11, 617,   0,  13, STR_2025_SUBSIDIES, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE, 13, 618, 629,   0,  13, STR_NULL,           STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE, 13,   0, 629,  14, 126, 0x0,                STR_01FD_CLICK_ON_SERVICE_TO_CENTER},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _subsidies_list_desc = {
+	WDP_AUTO, WDP_AUTO, 630, 127,
+	WC_SUBSIDIES_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_subsidies_list_widgets,
+	SubsidiesListWndProc
+};
+
+
+void ShowSubsidiesList(void)
+{
+	AllocateWindowDescFront(&_subsidies_list_desc, 0);
+}
deleted file mode 100644
--- a/src/terraform_gui.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "clear_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "player.h"
-#include "tile.h"
-#include "window.h"
-#include "gui.h"
-#include "viewport.h"
-#include "gfx.h"
-#include "sound.h"
-#include "command.h"
-#include "vehicle.h"
-#include "signs.h"
-#include "variables.h"
-
-void CcTerraform(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) {
-		SndPlayTileFx(SND_1F_SPLAT, tile);
-	} else {
-		SetRedErrorSquare(_terraform_err_tile);
-	}
-}
-
-
-/** Scenario editor command that generates desert areas */
-static void GenerateDesertArea(TileIndex end, TileIndex start)
-{
-	int size_x, size_y;
-	int sx = TileX(start);
-	int sy = TileY(start);
-	int ex = TileX(end);
-	int ey = TileY(end);
-
-	if (_game_mode != GM_EDITOR) return;
-
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-	size_x = (ex - sx) + 1;
-	size_y = (ey - sy) + 1;
-
-	_generating_world = true;
-	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
-		if (GetTileType(tile) != MP_WATER) {
-			SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_INVALID : TROPICZONE_DESERT);
-			DoCommandP(tile, 0, 0, NULL, CMD_LANDSCAPE_CLEAR);
-			MarkTileDirtyByTile(tile);
-		}
-	} END_TILE_LOOP(tile, size_x, size_y, 0);
-	_generating_world = false;
-}
-
-/** Scenario editor command that generates rocky areas */
-static void GenerateRockyArea(TileIndex end, TileIndex start)
-{
-	int size_x, size_y;
-	bool success = false;
-	int sx = TileX(start);
-	int sy = TileY(start);
-	int ex = TileX(end);
-	int ey = TileY(end);
-
-	if (_game_mode != GM_EDITOR) return;
-
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-	size_x = (ex - sx) + 1;
-	size_y = (ey - sy) + 1;
-
-	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
-		switch (GetTileType(tile)) {
-			case MP_CLEAR:
-			case MP_TREES:
-				MakeClear(tile, CLEAR_ROCKS, 3);
-				break;
-
-			default: continue;
-		}
-		MarkTileDirtyByTile(tile);
-		success = true;
-	} END_TILE_LOOP(tile, size_x, size_y, 0);
-
-	if (success) SndPlayTileFx(SND_1F_SPLAT, end);
-}
-
-/**
- * A central place to handle all X_AND_Y dragged GUI functions.
- * @param e @WindowEvent variable holding in its higher bits (excluding the lower
- * 4, since that defined the X_Y drag) the type of action to be performed
- * @return Returns true if the action was found and handled, and false otherwise. This
- * allows for additional implements that are more local. For example X_Y drag
- * of convertrail which belongs in rail_gui.c and not terraform_gui.c
- **/
-bool GUIPlaceProcDragXY(const WindowEvent *e)
-{
-	TileIndex start_tile = e->we.place.starttile;
-	TileIndex end_tile = e->we.place.tile;
-
-	switch (e->we.place.userdata >> 4) {
-	case GUI_PlaceProc_DemolishArea >> 4:
-		DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
-		break;
-	case GUI_PlaceProc_LevelArea >> 4:
-		DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_LEVEL_LAND | CMD_AUTO);
-		break;
-	case GUI_PlaceProc_RockyArea >> 4:
-		GenerateRockyArea(end_tile, start_tile);
-		break;
-	case GUI_PlaceProc_DesertArea >> 4:
-		GenerateDesertArea(end_tile, start_tile);
-		break;
-	case GUI_PlaceProc_WaterArea >> 4:
-		DoCommandP(end_tile, start_tile, _ctrl_pressed, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
-		break;
-	default: return false;
-	}
-
-	return true;
-}
-
-typedef void OnButtonClick(Window *w);
-
-static const uint16 _terraform_keycodes[] = {
-	'Q',
-	'W',
-	'E',
-	'D',
-	'U',
-	'I',
-	'O',
-};
-
-void PlaceProc_DemolishArea(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea);
-}
-
-static void PlaceProc_RaiseLand(TileIndex tile)
-{
-	DoCommandP(
-		tile, SLOPE_N, 1, CcTerraform,
-		CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0808_CAN_T_RAISE_LAND_HERE)
-	);
-}
-
-static void PlaceProc_LowerLand(TileIndex tile)
-{
-	DoCommandP(
-		tile, SLOPE_N, 0, CcTerraform,
-		CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0809_CAN_T_LOWER_LAND_HERE)
-	);
-}
-
-void PlaceProc_LevelLand(TileIndex tile)
-{
-	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_LevelArea);
-}
-
-static void TerraformClick_Lower(Window *w)
-{
-	HandlePlacePushButton(w, 4, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerLand);
-}
-
-static void TerraformClick_Raise(Window *w)
-{
-	HandlePlacePushButton(w, 5, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseLand);
-}
-
-static void TerraformClick_Level(Window *w)
-{
-	HandlePlacePushButton(w, 6, SPR_CURSOR_LEVEL_LAND, 2, PlaceProc_LevelLand);
-}
-
-static void TerraformClick_Dynamite(Window *w)
-{
-	HandlePlacePushButton(w, 7, ANIMCURSOR_DEMOLISH , 1, PlaceProc_DemolishArea);
-}
-
-static void TerraformClick_BuyLand(Window *w)
-{
-	HandlePlacePushButton(w, 8, SPR_CURSOR_BUY_LAND, 1, PlaceProc_BuyLand);
-}
-
-static void TerraformClick_Trees(Window *w)
-{
-	/* This button is NOT a place-push-button, so don't treat it as such */
-	ShowBuildTreesToolbar();
-}
-
-static void TerraformClick_PlaceSign(Window *w)
-{
-	HandlePlacePushButton(w, 10, SPR_CURSOR_SIGN, 1, PlaceProc_Sign);
-}
-
-static OnButtonClick * const _terraform_button_proc[] = {
-	TerraformClick_Lower,
-	TerraformClick_Raise,
-	TerraformClick_Level,
-	TerraformClick_Dynamite,
-	TerraformClick_BuyLand,
-	TerraformClick_Trees,
-	TerraformClick_PlaceSign,
-};
-
-static void TerraformToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
-
-	case WE_CLICK:
-		if (e->we.click.widget >= 4) _terraform_button_proc[e->we.click.widget - 4](w);
-		break;
-
-	case WE_KEYPRESS: {
-		uint i;
-
-		for (i = 0; i != lengthof(_terraform_keycodes); i++) {
-			if (e->we.keypress.keycode == _terraform_keycodes[i]) {
-				e->we.keypress.cont = false;
-				_terraform_button_proc[i](w);
-				break;
-			}
-		}
-		break;
-	}
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		return;
-
-	case WE_PLACE_DRAG:
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
-		break;
-
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1 &&
-				(e->we.place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
-			GUIPlaceProcDragXY(e);
-		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		RaiseWindowButtons(w);
-		break;
-	}
-}
-
-static const Widget _terraform_widgets[] = {
-{ WWT_CLOSEBOX,   RESIZE_NONE,     7,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
-{  WWT_CAPTION,   RESIZE_NONE,     7,  11, 145,   0,  13, STR_LANDSCAPING_TOOLBAR, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{WWT_STICKYBOX,   RESIZE_NONE,     7, 146, 157,   0,  13, STR_NULL,                STR_STICKY_BUTTON},
-
-{    WWT_PANEL,   RESIZE_NONE,     7,  66,  69,  14,  35, 0x0,                    STR_NULL},
-{   WWT_IMGBTN,   RESIZE_NONE,     7,   0,  21,  14,  35, SPR_IMG_TERRAFORM_DOWN,  STR_018E_LOWER_A_CORNER_OF_LAND},
-{   WWT_IMGBTN,   RESIZE_NONE,     7,  22,  43,  14,  35, SPR_IMG_TERRAFORM_UP,    STR_018F_RAISE_A_CORNER_OF_LAND},
-{   WWT_IMGBTN,   RESIZE_NONE,     7,  44,  65,  14,  35, SPR_IMG_LEVEL_LAND,      STR_LEVEL_LAND_TOOLTIP},
-{   WWT_IMGBTN,   RESIZE_NONE,     7,  70,  91,  14,  35, SPR_IMG_DYNAMITE,        STR_018D_DEMOLISH_BUILDINGS_ETC},
-{   WWT_IMGBTN,   RESIZE_NONE,     7,  92, 113,  14,  35, SPR_IMG_BUY_LAND,        STR_0329_PURCHASE_LAND_FOR_FUTURE},
-{   WWT_IMGBTN,   RESIZE_NONE,     7, 114, 135,  14,  35, SPR_IMG_PLANTTREES,      STR_0185_PLANT_TREES_PLACE_SIGNS},
-{   WWT_IMGBTN,   RESIZE_NONE,     7, 136, 157,  14,  35, SPR_IMG_PLACE_SIGN,      STR_0289_PLACE_SIGN},
-
-{   WIDGETS_END},
-};
-
-static const WindowDesc _terraform_desc = {
-	WDP_ALIGN_TBR, 22+36, 158, 36,
-	WC_SCEN_LAND_GEN, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
-	_terraform_widgets,
-	TerraformToolbWndProc
-};
-
-void ShowTerraformToolbar(void)
-{
-	if (!IsValidPlayer(_current_player)) return;
-	AllocateWindowDescFront(&_terraform_desc, 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/terraform_gui.cpp
@@ -0,0 +1,285 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "clear_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "player.h"
+#include "tile.h"
+#include "window.h"
+#include "gui.h"
+#include "viewport.h"
+#include "gfx.h"
+#include "sound.h"
+#include "command.h"
+#include "vehicle.h"
+#include "signs.h"
+#include "variables.h"
+
+void CcTerraform(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) {
+		SndPlayTileFx(SND_1F_SPLAT, tile);
+	} else {
+		SetRedErrorSquare(_terraform_err_tile);
+	}
+}
+
+
+/** Scenario editor command that generates desert areas */
+static void GenerateDesertArea(TileIndex end, TileIndex start)
+{
+	int size_x, size_y;
+	int sx = TileX(start);
+	int sy = TileY(start);
+	int ex = TileX(end);
+	int ey = TileY(end);
+
+	if (_game_mode != GM_EDITOR) return;
+
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+	size_x = (ex - sx) + 1;
+	size_y = (ey - sy) + 1;
+
+	_generating_world = true;
+	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+		if (GetTileType(tile) != MP_WATER) {
+			SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_INVALID : TROPICZONE_DESERT);
+			DoCommandP(tile, 0, 0, NULL, CMD_LANDSCAPE_CLEAR);
+			MarkTileDirtyByTile(tile);
+		}
+	} END_TILE_LOOP(tile, size_x, size_y, 0);
+	_generating_world = false;
+}
+
+/** Scenario editor command that generates rocky areas */
+static void GenerateRockyArea(TileIndex end, TileIndex start)
+{
+	int size_x, size_y;
+	bool success = false;
+	int sx = TileX(start);
+	int sy = TileY(start);
+	int ex = TileX(end);
+	int ey = TileY(end);
+
+	if (_game_mode != GM_EDITOR) return;
+
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+	size_x = (ex - sx) + 1;
+	size_y = (ey - sy) + 1;
+
+	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+		switch (GetTileType(tile)) {
+			case MP_CLEAR:
+			case MP_TREES:
+				MakeClear(tile, CLEAR_ROCKS, 3);
+				break;
+
+			default: continue;
+		}
+		MarkTileDirtyByTile(tile);
+		success = true;
+	} END_TILE_LOOP(tile, size_x, size_y, 0);
+
+	if (success) SndPlayTileFx(SND_1F_SPLAT, end);
+}
+
+/**
+ * A central place to handle all X_AND_Y dragged GUI functions.
+ * @param e @WindowEvent variable holding in its higher bits (excluding the lower
+ * 4, since that defined the X_Y drag) the type of action to be performed
+ * @return Returns true if the action was found and handled, and false otherwise. This
+ * allows for additional implements that are more local. For example X_Y drag
+ * of convertrail which belongs in rail_gui.c and not terraform_gui.c
+ **/
+bool GUIPlaceProcDragXY(const WindowEvent *e)
+{
+	TileIndex start_tile = e->we.place.starttile;
+	TileIndex end_tile = e->we.place.tile;
+
+	switch (e->we.place.userdata >> 4) {
+	case GUI_PlaceProc_DemolishArea >> 4:
+		DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
+		break;
+	case GUI_PlaceProc_LevelArea >> 4:
+		DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_LEVEL_LAND | CMD_AUTO);
+		break;
+	case GUI_PlaceProc_RockyArea >> 4:
+		GenerateRockyArea(end_tile, start_tile);
+		break;
+	case GUI_PlaceProc_DesertArea >> 4:
+		GenerateDesertArea(end_tile, start_tile);
+		break;
+	case GUI_PlaceProc_WaterArea >> 4:
+		DoCommandP(end_tile, start_tile, _ctrl_pressed, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
+		break;
+	default: return false;
+	}
+
+	return true;
+}
+
+typedef void OnButtonClick(Window *w);
+
+static const uint16 _terraform_keycodes[] = {
+	'Q',
+	'W',
+	'E',
+	'D',
+	'U',
+	'I',
+	'O',
+};
+
+void PlaceProc_DemolishArea(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea);
+}
+
+static void PlaceProc_RaiseLand(TileIndex tile)
+{
+	DoCommandP(
+		tile, SLOPE_N, 1, CcTerraform,
+		CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0808_CAN_T_RAISE_LAND_HERE)
+	);
+}
+
+static void PlaceProc_LowerLand(TileIndex tile)
+{
+	DoCommandP(
+		tile, SLOPE_N, 0, CcTerraform,
+		CMD_TERRAFORM_LAND | CMD_AUTO | CMD_MSG(STR_0809_CAN_T_LOWER_LAND_HERE)
+	);
+}
+
+void PlaceProc_LevelLand(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_LevelArea);
+}
+
+static void TerraformClick_Lower(Window *w)
+{
+	HandlePlacePushButton(w, 4, ANIMCURSOR_LOWERLAND, 2, PlaceProc_LowerLand);
+}
+
+static void TerraformClick_Raise(Window *w)
+{
+	HandlePlacePushButton(w, 5, ANIMCURSOR_RAISELAND, 2, PlaceProc_RaiseLand);
+}
+
+static void TerraformClick_Level(Window *w)
+{
+	HandlePlacePushButton(w, 6, SPR_CURSOR_LEVEL_LAND, 2, PlaceProc_LevelLand);
+}
+
+static void TerraformClick_Dynamite(Window *w)
+{
+	HandlePlacePushButton(w, 7, ANIMCURSOR_DEMOLISH , 1, PlaceProc_DemolishArea);
+}
+
+static void TerraformClick_BuyLand(Window *w)
+{
+	HandlePlacePushButton(w, 8, SPR_CURSOR_BUY_LAND, 1, PlaceProc_BuyLand);
+}
+
+static void TerraformClick_Trees(Window *w)
+{
+	/* This button is NOT a place-push-button, so don't treat it as such */
+	ShowBuildTreesToolbar();
+}
+
+static void TerraformClick_PlaceSign(Window *w)
+{
+	HandlePlacePushButton(w, 10, SPR_CURSOR_SIGN, 1, PlaceProc_Sign);
+}
+
+static OnButtonClick * const _terraform_button_proc[] = {
+	TerraformClick_Lower,
+	TerraformClick_Raise,
+	TerraformClick_Level,
+	TerraformClick_Dynamite,
+	TerraformClick_BuyLand,
+	TerraformClick_Trees,
+	TerraformClick_PlaceSign,
+};
+
+static void TerraformToolbWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawWindowWidgets(w);
+		break;
+
+	case WE_CLICK:
+		if (e->we.click.widget >= 4) _terraform_button_proc[e->we.click.widget - 4](w);
+		break;
+
+	case WE_KEYPRESS: {
+		uint i;
+
+		for (i = 0; i != lengthof(_terraform_keycodes); i++) {
+			if (e->we.keypress.keycode == _terraform_keycodes[i]) {
+				e->we.keypress.cont = false;
+				_terraform_button_proc[i](w);
+				break;
+			}
+		}
+		break;
+	}
+
+	case WE_PLACE_OBJ:
+		_place_proc(e->we.place.tile);
+		return;
+
+	case WE_PLACE_DRAG:
+		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata & 0xF);
+		break;
+
+	case WE_PLACE_MOUSEUP:
+		if (e->we.place.pt.x != -1 &&
+				(e->we.place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
+			GUIPlaceProcDragXY(e);
+		}
+		break;
+
+	case WE_ABORT_PLACE_OBJ:
+		RaiseWindowButtons(w);
+		break;
+	}
+}
+
+static const Widget _terraform_widgets[] = {
+{ WWT_CLOSEBOX,   RESIZE_NONE,     7,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
+{  WWT_CAPTION,   RESIZE_NONE,     7,  11, 145,   0,  13, STR_LANDSCAPING_TOOLBAR, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{WWT_STICKYBOX,   RESIZE_NONE,     7, 146, 157,   0,  13, STR_NULL,                STR_STICKY_BUTTON},
+
+{    WWT_PANEL,   RESIZE_NONE,     7,  66,  69,  14,  35, 0x0,                    STR_NULL},
+{   WWT_IMGBTN,   RESIZE_NONE,     7,   0,  21,  14,  35, SPR_IMG_TERRAFORM_DOWN,  STR_018E_LOWER_A_CORNER_OF_LAND},
+{   WWT_IMGBTN,   RESIZE_NONE,     7,  22,  43,  14,  35, SPR_IMG_TERRAFORM_UP,    STR_018F_RAISE_A_CORNER_OF_LAND},
+{   WWT_IMGBTN,   RESIZE_NONE,     7,  44,  65,  14,  35, SPR_IMG_LEVEL_LAND,      STR_LEVEL_LAND_TOOLTIP},
+{   WWT_IMGBTN,   RESIZE_NONE,     7,  70,  91,  14,  35, SPR_IMG_DYNAMITE,        STR_018D_DEMOLISH_BUILDINGS_ETC},
+{   WWT_IMGBTN,   RESIZE_NONE,     7,  92, 113,  14,  35, SPR_IMG_BUY_LAND,        STR_0329_PURCHASE_LAND_FOR_FUTURE},
+{   WWT_IMGBTN,   RESIZE_NONE,     7, 114, 135,  14,  35, SPR_IMG_PLANTTREES,      STR_0185_PLANT_TREES_PLACE_SIGNS},
+{   WWT_IMGBTN,   RESIZE_NONE,     7, 136, 157,  14,  35, SPR_IMG_PLACE_SIGN,      STR_0289_PLACE_SIGN},
+
+{   WIDGETS_END},
+};
+
+static const WindowDesc _terraform_desc = {
+	WDP_ALIGN_TBR, 22+36, 158, 36,
+	WC_SCEN_LAND_GEN, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+	_terraform_widgets,
+	TerraformToolbWndProc
+};
+
+void ShowTerraformToolbar(void)
+{
+	if (!IsValidPlayer(_current_player)) return;
+	AllocateWindowDescFront(&_terraform_desc, 0);
+}
deleted file mode 100644
--- a/src/texteff.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "macros.h"
-#include "strings.h"
-#include "gfx.h"
-#include "viewport.h"
-#include "saveload.h"
-#include "hal.h"
-#include "console.h"
-#include "string.h"
-#include "variables.h"
-#include "table/sprites.h"
-#include <stdarg.h> /* va_list */
-#include "date.h"
-
-enum {
-	MAX_TEXTMESSAGE_LENGTH = 150,
-	MAX_TEXT_MESSAGES      =  30,
-	MAX_CHAT_MESSAGES      =  10,
-	MAX_ANIMATED_TILES     = 256,
-};
-
-typedef struct TextEffect {
-	StringID string_id;
-	int32 x;
-	int32 y;
-	int32 right;
-	int32 bottom;
-	uint16 duration;
-	uint32 params_1;
-	uint32 params_2;
-} TextEffect;
-
-
-typedef struct TextMessage {
-	char message[MAX_TEXTMESSAGE_LENGTH];
-	uint16 color;
-	Date end_date;
-} TextMessage;
-
-static TextEffect _text_effect_list[MAX_TEXT_MESSAGES];
-static TextMessage _textmsg_list[MAX_CHAT_MESSAGES];
-TileIndex _animated_tile_list[MAX_ANIMATED_TILES];
-
-static bool _textmessage_dirty = false;
-static bool _textmessage_visible = false;
-
-/* The chatbox grows from the bottom so the coordinates are pixels from
- * the left and pixels from the bottom. The height is the maximum height */
-static const Oblong _textmsg_box = {10, 30, 500, 150};
-static Pixel _textmessage_backup[150 * 500]; // (height * width)
-
-extern void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch);
-
-static inline uint GetTextMessageCount(void)
-{
-	uint i;
-
-	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
-		if (_textmsg_list[i].message[0] == '\0') break;
-	}
-
-	return i;
-}
-
-/* Add a text message to the 'chat window' to be shown
- * @param color The colour this message is to be shown in
- * @param duration The duration of the chat message in game-days
- * @param message message itself in printf() style */
-void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...)
-{
-	char buf[MAX_TEXTMESSAGE_LENGTH];
-	const char *bufp;
-	va_list va;
-	uint msg_count;
-	uint16 lines;
-
-	va_start(va, message);
-	vsnprintf(buf, lengthof(buf), message, va);
-	va_end(va);
-
-	/* Force linebreaks for strings that are too long */
-	lines = GB(FormatStringLinebreaks(buf, _textmsg_box.width - 8), 0, 16) + 1;
-	if (lines >= MAX_CHAT_MESSAGES) return;
-
-	msg_count = GetTextMessageCount();
-	/* We want to add more chat messages than there is free space for, remove 'old' */
-	if (lines > MAX_CHAT_MESSAGES - msg_count) {
-		int i = lines - (MAX_CHAT_MESSAGES - msg_count);
-		memmove(&_textmsg_list[0], &_textmsg_list[i], sizeof(_textmsg_list[0]) * (msg_count - i));
-		msg_count = MAX_CHAT_MESSAGES - lines;
-	}
-
-	for (bufp = buf; lines != 0; lines--) {
-		TextMessage *tmsg = &_textmsg_list[msg_count++];
-		ttd_strlcpy(tmsg->message, bufp, sizeof(tmsg->message));
-
-		/* The default colour for a message is player colour. Replace this with
-		 * white for any additional lines */
-		tmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR;
-		tmsg->end_date = _date + duration;
-
-		bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
-	}
-
-	_textmessage_dirty = true;
-}
-
-void InitTextMessage(void)
-{
-	uint i;
-
-	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
-		_textmsg_list[i].message[0] = '\0';
-	}
-}
-
-/* Hide the textbox */
-void UndrawTextMessage(void)
-{
-	if (_textmessage_visible) {
-		/* Sometimes we also need to hide the cursor
-		 *   This is because both textmessage and the cursor take a shot of the
-		 *   screen before drawing.
-		 *   Now the textmessage takes his shot and paints his data before the cursor
-		 *   does, so in the shot of the cursor is the screen-data of the textmessage
-		 *   included when the cursor hangs somewhere over the textmessage. To
-		 *   avoid wrong repaints, we undraw the cursor in that case, and everything
-		 *   looks nicely ;)
-		 * (and now hope this story above makes sense to you ;))
-		 */
-
-		if (_cursor.visible) {
-			if (_cursor.draw_pos.x + _cursor.draw_size.x >= _textmsg_box.x &&
-				_cursor.draw_pos.x <= _textmsg_box.x + _textmsg_box.width &&
-				_cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _textmsg_box.y - _textmsg_box.height &&
-				_cursor.draw_pos.y <= _screen.height - _textmsg_box.y) {
-				UndrawMouseCursor();
-			}
-		}
-
-		_textmessage_visible = false;
-		/* Put our 'shot' back to the screen */
-		memcpy_pitch(
-			_screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch,
-			_textmessage_backup,
-			_textmsg_box.width, _textmsg_box.height, _textmsg_box.width, _screen.pitch);
-
-		/* And make sure it is updated next time */
-		_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);
-
-		_textmessage_dirty = true;
-	}
-}
-
-/* Check if a message is expired every day */
-void TextMessageDailyLoop(void)
-{
-	uint i;
-
-	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
-		TextMessage *tmsg = &_textmsg_list[i];
-		if (tmsg->message[0] == '\0') continue;
-
-		/* Message has expired, remove from the list */
-		if (tmsg->end_date < _date) {
-			/* Move the remaining messages over the current message */
-			if (i != MAX_CHAT_MESSAGES - 1) memmove(tmsg, tmsg + 1, sizeof(*tmsg) * (MAX_CHAT_MESSAGES - i - 1));
-
-			/* Mark the last item as empty */
-			_textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
-			_textmessage_dirty = true;
-
-			/* Go one item back, because we moved the array 1 to the left */
-			i--;
-		}
-	}
-}
-
-/* Draw the textmessage-box */
-void DrawTextMessage(void)
-{
-	uint y, count;
-
-	if (!_textmessage_dirty) return;
-
-	/* First undraw if needed */
-	UndrawTextMessage();
-
-	if (_iconsole_mode == ICONSOLE_FULL) return;
-
-	/* Check if we have anything to draw at all */
-	count = GetTextMessageCount();
-	if (count == 0) return;
-
-	/* Make a copy of the screen as it is before painting (for undraw) */
-	memcpy_pitch(
-		_textmessage_backup,
-		_screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch,
-		_textmsg_box.width, _textmsg_box.height, _screen.pitch, _textmsg_box.width);
-
-	_cur_dpi = &_screen; // switch to _screen painting
-
-	/* Paint a half-transparent box behind the text messages */
-	GfxFillRect(
-			_textmsg_box.x,
-			_screen.height - _textmsg_box.y - count * 13 - 2,
-			_textmsg_box.x + _textmsg_box.width - 1,
-			_screen.height - _textmsg_box.y - 2,
-			0x322 | USE_COLORTABLE // black, but with some alpha for background
-		);
-
-	/* Paint the messages starting with the lowest at the bottom */
-	for (y = 13; count-- != 0; y += 13) {
-		DoDrawString(_textmsg_list[count].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - y + 1, _textmsg_list[count].color);
- 	}
-
-	/* Make sure the data is updated next flush */
-	_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);
-
-	_textmessage_visible = true;
-	_textmessage_dirty = false;
-}
-
-static void MarkTextEffectAreaDirty(TextEffect *te)
-{
-	MarkAllViewportsDirty(
-		te->x,
-		te->y - 1,
-		(te->right - te->x)*2 + te->x + 1,
-		(te->bottom - (te->y - 1)) * 2 + (te->y - 1) + 1
-	);
-}
-
-void AddTextEffect(StringID msg, int x, int y, uint16 duration)
-{
-	TextEffect *te;
-	int w;
-	char buffer[100];
-
-	if (_game_mode == GM_MENU) return;
-
-	for (te = _text_effect_list; te->string_id != INVALID_STRING_ID; ) {
-		if (++te == endof(_text_effect_list)) return;
-	}
-
-	te->string_id = msg;
-	te->duration = duration;
-	te->y = y - 5;
-	te->bottom = y + 5;
-	te->params_1 = GetDParam(0);
-	te->params_2 = GetDParam(4);
-
-	GetString(buffer, msg, lastof(buffer));
-	w = GetStringBoundingBox(buffer).width;
-
-	te->x = x - (w >> 1);
-	te->right = x + (w >> 1) - 1;
-	MarkTextEffectAreaDirty(te);
-}
-
-static void MoveTextEffect(TextEffect *te)
-{
-	if (te->duration < 8) {
-		te->string_id = INVALID_STRING_ID;
-	} else {
-		te->duration -= 8;
-		te->y--;
-		te->bottom--;
-	}
-	MarkTextEffectAreaDirty(te);
-}
-
-void MoveAllTextEffects(void)
-{
-	TextEffect *te;
-
-	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-		if (te->string_id != INVALID_STRING_ID) MoveTextEffect(te);
-	}
-}
-
-void InitTextEffects(void)
-{
-	TextEffect *te;
-
-	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-		te->string_id = INVALID_STRING_ID;
-	}
-}
-
-void DrawTextEffects(DrawPixelInfo *dpi)
-{
-	const TextEffect* te;
-
-	switch (dpi->zoom) {
-		case 0:
-			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-				if (te->string_id != INVALID_STRING_ID &&
-						dpi->left <= te->right &&
-						dpi->top  <= te->bottom &&
-						dpi->left + dpi->width  > te->x &&
-						dpi->top  + dpi->height > te->y) {
-					AddStringToDraw(te->x, te->y, te->string_id, te->params_1, te->params_2);
-				}
-			}
-			break;
-
-		case 1:
-			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-				if (te->string_id != INVALID_STRING_ID &&
-						dpi->left <= te->right  * 2 - te->x &&
-						dpi->top  <= te->bottom * 2 - te->y &&
-						dpi->left + dpi->width  > te->x &&
-						dpi->top  + dpi->height > te->y) {
-					AddStringToDraw(te->x, te->y, (StringID)(te->string_id-1), te->params_1, te->params_2);
-				}
-			}
-			break;
-	}
-}
-
-void DeleteAnimatedTile(TileIndex tile)
-{
-	TileIndex *ti;
-
-	for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) {
-		if (tile == *ti) {
-			/* remove the hole */
-			memmove(ti, ti + 1, (lastof(_animated_tile_list) - ti) * sizeof(*ti));
-			/* and clear last item */
-			*lastof(_animated_tile_list) = 0;
-			MarkTileDirtyByTile(tile);
-			return;
-		}
-	}
-}
-
-bool AddAnimatedTile(TileIndex tile)
-{
-	TileIndex *ti;
-
-	for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) {
-		if (tile == *ti || *ti == 0) {
-			*ti = tile;
-			MarkTileDirtyByTile(tile);
-			return true;
-		}
-	}
-
-	return false;
-}
-
-void AnimateAnimatedTiles(void)
-{
-	const TileIndex* ti;
-
-	for (ti = _animated_tile_list; ti != endof(_animated_tile_list) && *ti != 0; ti++) {
-		AnimateTile(*ti);
-	}
-}
-
-void InitializeAnimatedTiles(void)
-{
-	memset(_animated_tile_list, 0, sizeof(_animated_tile_list));
-}
-
-static void SaveLoad_ANIT(void)
-{
-	/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
-	if (CheckSavegameVersion(6)) {
-		SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_FILE_U16 | SLE_VAR_U32);
-	} else {
-		SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_UINT32);
-	}
-}
-
-
-const ChunkHandler _animated_tile_chunk_handlers[] = {
-	{ 'ANIT', SaveLoad_ANIT, SaveLoad_ANIT, CH_RIFF | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/texteff.cpp
@@ -0,0 +1,384 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "macros.h"
+#include "strings.h"
+#include "gfx.h"
+#include "viewport.h"
+#include "saveload.h"
+#include "hal.h"
+#include "console.h"
+#include "string.h"
+#include "variables.h"
+#include "table/sprites.h"
+#include <stdarg.h> /* va_list */
+#include "date.h"
+
+enum {
+	MAX_TEXTMESSAGE_LENGTH = 150,
+	MAX_TEXT_MESSAGES      =  30,
+	MAX_CHAT_MESSAGES      =  10,
+	MAX_ANIMATED_TILES     = 256,
+};
+
+typedef struct TextEffect {
+	StringID string_id;
+	int32 x;
+	int32 y;
+	int32 right;
+	int32 bottom;
+	uint16 duration;
+	uint32 params_1;
+	uint32 params_2;
+} TextEffect;
+
+
+typedef struct TextMessage {
+	char message[MAX_TEXTMESSAGE_LENGTH];
+	uint16 color;
+	Date end_date;
+} TextMessage;
+
+static TextEffect _text_effect_list[MAX_TEXT_MESSAGES];
+static TextMessage _textmsg_list[MAX_CHAT_MESSAGES];
+TileIndex _animated_tile_list[MAX_ANIMATED_TILES];
+
+static bool _textmessage_dirty = false;
+static bool _textmessage_visible = false;
+
+/* The chatbox grows from the bottom so the coordinates are pixels from
+ * the left and pixels from the bottom. The height is the maximum height */
+static const Oblong _textmsg_box = {10, 30, 500, 150};
+static Pixel _textmessage_backup[150 * 500]; // (height * width)
+
+extern void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch);
+
+static inline uint GetTextMessageCount(void)
+{
+	uint i;
+
+	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		if (_textmsg_list[i].message[0] == '\0') break;
+	}
+
+	return i;
+}
+
+/* Add a text message to the 'chat window' to be shown
+ * @param color The colour this message is to be shown in
+ * @param duration The duration of the chat message in game-days
+ * @param message message itself in printf() style */
+void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...)
+{
+	char buf[MAX_TEXTMESSAGE_LENGTH];
+	const char *bufp;
+	va_list va;
+	uint msg_count;
+	uint16 lines;
+
+	va_start(va, message);
+	vsnprintf(buf, lengthof(buf), message, va);
+	va_end(va);
+
+	/* Force linebreaks for strings that are too long */
+	lines = GB(FormatStringLinebreaks(buf, _textmsg_box.width - 8), 0, 16) + 1;
+	if (lines >= MAX_CHAT_MESSAGES) return;
+
+	msg_count = GetTextMessageCount();
+	/* We want to add more chat messages than there is free space for, remove 'old' */
+	if (lines > MAX_CHAT_MESSAGES - msg_count) {
+		int i = lines - (MAX_CHAT_MESSAGES - msg_count);
+		memmove(&_textmsg_list[0], &_textmsg_list[i], sizeof(_textmsg_list[0]) * (msg_count - i));
+		msg_count = MAX_CHAT_MESSAGES - lines;
+	}
+
+	for (bufp = buf; lines != 0; lines--) {
+		TextMessage *tmsg = &_textmsg_list[msg_count++];
+		ttd_strlcpy(tmsg->message, bufp, sizeof(tmsg->message));
+
+		/* The default colour for a message is player colour. Replace this with
+		 * white for any additional lines */
+		tmsg->color = (bufp == buf && color & IS_PALETTE_COLOR) ? color : (0x1D - 15) | IS_PALETTE_COLOR;
+		tmsg->end_date = _date + duration;
+
+		bufp += strlen(bufp) + 1; // jump to 'next line' in the formatted string
+	}
+
+	_textmessage_dirty = true;
+}
+
+void InitTextMessage(void)
+{
+	uint i;
+
+	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		_textmsg_list[i].message[0] = '\0';
+	}
+}
+
+/* Hide the textbox */
+void UndrawTextMessage(void)
+{
+	if (_textmessage_visible) {
+		/* Sometimes we also need to hide the cursor
+		 *   This is because both textmessage and the cursor take a shot of the
+		 *   screen before drawing.
+		 *   Now the textmessage takes his shot and paints his data before the cursor
+		 *   does, so in the shot of the cursor is the screen-data of the textmessage
+		 *   included when the cursor hangs somewhere over the textmessage. To
+		 *   avoid wrong repaints, we undraw the cursor in that case, and everything
+		 *   looks nicely ;)
+		 * (and now hope this story above makes sense to you ;))
+		 */
+
+		if (_cursor.visible) {
+			if (_cursor.draw_pos.x + _cursor.draw_size.x >= _textmsg_box.x &&
+				_cursor.draw_pos.x <= _textmsg_box.x + _textmsg_box.width &&
+				_cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _textmsg_box.y - _textmsg_box.height &&
+				_cursor.draw_pos.y <= _screen.height - _textmsg_box.y) {
+				UndrawMouseCursor();
+			}
+		}
+
+		_textmessage_visible = false;
+		/* Put our 'shot' back to the screen */
+		memcpy_pitch(
+			_screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch,
+			_textmessage_backup,
+			_textmsg_box.width, _textmsg_box.height, _textmsg_box.width, _screen.pitch);
+
+		/* And make sure it is updated next time */
+		_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);
+
+		_textmessage_dirty = true;
+	}
+}
+
+/* Check if a message is expired every day */
+void TextMessageDailyLoop(void)
+{
+	uint i;
+
+	for (i = 0; i < MAX_CHAT_MESSAGES; i++) {
+		TextMessage *tmsg = &_textmsg_list[i];
+		if (tmsg->message[0] == '\0') continue;
+
+		/* Message has expired, remove from the list */
+		if (tmsg->end_date < _date) {
+			/* Move the remaining messages over the current message */
+			if (i != MAX_CHAT_MESSAGES - 1) memmove(tmsg, tmsg + 1, sizeof(*tmsg) * (MAX_CHAT_MESSAGES - i - 1));
+
+			/* Mark the last item as empty */
+			_textmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0';
+			_textmessage_dirty = true;
+
+			/* Go one item back, because we moved the array 1 to the left */
+			i--;
+		}
+	}
+}
+
+/* Draw the textmessage-box */
+void DrawTextMessage(void)
+{
+	uint y, count;
+
+	if (!_textmessage_dirty) return;
+
+	/* First undraw if needed */
+	UndrawTextMessage();
+
+	if (_iconsole_mode == ICONSOLE_FULL) return;
+
+	/* Check if we have anything to draw at all */
+	count = GetTextMessageCount();
+	if (count == 0) return;
+
+	/* Make a copy of the screen as it is before painting (for undraw) */
+	memcpy_pitch(
+		_textmessage_backup,
+		_screen.dst_ptr + _textmsg_box.x + (_screen.height - _textmsg_box.y - _textmsg_box.height) * _screen.pitch,
+		_textmsg_box.width, _textmsg_box.height, _screen.pitch, _textmsg_box.width);
+
+	_cur_dpi = &_screen; // switch to _screen painting
+
+	/* Paint a half-transparent box behind the text messages */
+	GfxFillRect(
+			_textmsg_box.x,
+			_screen.height - _textmsg_box.y - count * 13 - 2,
+			_textmsg_box.x + _textmsg_box.width - 1,
+			_screen.height - _textmsg_box.y - 2,
+			0x322 | USE_COLORTABLE // black, but with some alpha for background
+		);
+
+	/* Paint the messages starting with the lowest at the bottom */
+	for (y = 13; count-- != 0; y += 13) {
+		DoDrawString(_textmsg_list[count].message, _textmsg_box.x + 3, _screen.height - _textmsg_box.y - y + 1, _textmsg_list[count].color);
+ 	}
+
+	/* Make sure the data is updated next flush */
+	_video_driver->make_dirty(_textmsg_box.x, _screen.height - _textmsg_box.y - _textmsg_box.height, _textmsg_box.width, _textmsg_box.height);
+
+	_textmessage_visible = true;
+	_textmessage_dirty = false;
+}
+
+static void MarkTextEffectAreaDirty(TextEffect *te)
+{
+	MarkAllViewportsDirty(
+		te->x,
+		te->y - 1,
+		(te->right - te->x)*2 + te->x + 1,
+		(te->bottom - (te->y - 1)) * 2 + (te->y - 1) + 1
+	);
+}
+
+void AddTextEffect(StringID msg, int x, int y, uint16 duration)
+{
+	TextEffect *te;
+	int w;
+	char buffer[100];
+
+	if (_game_mode == GM_MENU) return;
+
+	for (te = _text_effect_list; te->string_id != INVALID_STRING_ID; ) {
+		if (++te == endof(_text_effect_list)) return;
+	}
+
+	te->string_id = msg;
+	te->duration = duration;
+	te->y = y - 5;
+	te->bottom = y + 5;
+	te->params_1 = GetDParam(0);
+	te->params_2 = GetDParam(4);
+
+	GetString(buffer, msg, lastof(buffer));
+	w = GetStringBoundingBox(buffer).width;
+
+	te->x = x - (w >> 1);
+	te->right = x + (w >> 1) - 1;
+	MarkTextEffectAreaDirty(te);
+}
+
+static void MoveTextEffect(TextEffect *te)
+{
+	if (te->duration < 8) {
+		te->string_id = INVALID_STRING_ID;
+	} else {
+		te->duration -= 8;
+		te->y--;
+		te->bottom--;
+	}
+	MarkTextEffectAreaDirty(te);
+}
+
+void MoveAllTextEffects(void)
+{
+	TextEffect *te;
+
+	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+		if (te->string_id != INVALID_STRING_ID) MoveTextEffect(te);
+	}
+}
+
+void InitTextEffects(void)
+{
+	TextEffect *te;
+
+	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+		te->string_id = INVALID_STRING_ID;
+	}
+}
+
+void DrawTextEffects(DrawPixelInfo *dpi)
+{
+	const TextEffect* te;
+
+	switch (dpi->zoom) {
+		case 0:
+			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+				if (te->string_id != INVALID_STRING_ID &&
+						dpi->left <= te->right &&
+						dpi->top  <= te->bottom &&
+						dpi->left + dpi->width  > te->x &&
+						dpi->top  + dpi->height > te->y) {
+					AddStringToDraw(te->x, te->y, te->string_id, te->params_1, te->params_2);
+				}
+			}
+			break;
+
+		case 1:
+			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+				if (te->string_id != INVALID_STRING_ID &&
+						dpi->left <= te->right  * 2 - te->x &&
+						dpi->top  <= te->bottom * 2 - te->y &&
+						dpi->left + dpi->width  > te->x &&
+						dpi->top  + dpi->height > te->y) {
+					AddStringToDraw(te->x, te->y, (StringID)(te->string_id-1), te->params_1, te->params_2);
+				}
+			}
+			break;
+	}
+}
+
+void DeleteAnimatedTile(TileIndex tile)
+{
+	TileIndex *ti;
+
+	for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) {
+		if (tile == *ti) {
+			/* remove the hole */
+			memmove(ti, ti + 1, (lastof(_animated_tile_list) - ti) * sizeof(*ti));
+			/* and clear last item */
+			*lastof(_animated_tile_list) = 0;
+			MarkTileDirtyByTile(tile);
+			return;
+		}
+	}
+}
+
+bool AddAnimatedTile(TileIndex tile)
+{
+	TileIndex *ti;
+
+	for (ti = _animated_tile_list; ti != endof(_animated_tile_list); ti++) {
+		if (tile == *ti || *ti == 0) {
+			*ti = tile;
+			MarkTileDirtyByTile(tile);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void AnimateAnimatedTiles(void)
+{
+	const TileIndex* ti;
+
+	for (ti = _animated_tile_list; ti != endof(_animated_tile_list) && *ti != 0; ti++) {
+		AnimateTile(*ti);
+	}
+}
+
+void InitializeAnimatedTiles(void)
+{
+	memset(_animated_tile_list, 0, sizeof(_animated_tile_list));
+}
+
+static void SaveLoad_ANIT(void)
+{
+	/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
+	if (CheckSavegameVersion(6)) {
+		SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_FILE_U16 | SLE_VAR_U32);
+	} else {
+		SlArray(_animated_tile_list, lengthof(_animated_tile_list), SLE_UINT32);
+	}
+}
+
+
+const ChunkHandler _animated_tile_chunk_handlers[] = {
+	{ 'ANIT', SaveLoad_ANIT, SaveLoad_ANIT, CH_RIFF | CH_LAST},
+};
deleted file mode 100644
--- a/src/tgp.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include <math.h>
-#include "openttd.h"
-#include "clear_map.h"
-#include "functions.h"
-#include "map.h"
-#include "table/strings.h"
-#include "clear_map.h"
-#include "tile.h"
-#include "variables.h"
-#include "void_map.h"
-#include "tgp.h"
-#include "console.h"
-#include "genworld.h"
-
-/*
- * OTTD Perlin Noise Landscape Generator, aka TerraGenesis Perlin
- *
- * Quickie guide to Perlin Noise
- * Perlin noise is a predictable pseudo random number sequence. By generating
- * it in 2 dimensions, it becomes a useful random map, that for a given seed
- * and starting X & Y is entirely predictable. On the face of it, that may not
- * be useful. However, it means that if you want to replay a map in a different
- * terrain, or just vary the sea level, you just re-run the generator with the
- * same seed. The seed is an int32, and is randomised on each run of New Game.
- * The Scenario Generator does not randomise the value, so that you can
- * experiment with one terrain until you are happy, or click "Random" for a new
- * random seed.
- *
- * Perlin Noise is a series of "octaves" of random noise added together. By
- * reducing the amplitude of the noise with each octave, the first octave of
- * noise defines the main terrain sweep, the next the ripples on that, and the
- * next the ripples on that. I use 6 octaves, with the amplitude controlled by
- * a power ratio, usually known as a persistence or p value. This I vary by the
- * smoothness selection, as can be seen in the table below. The closer to 1,
- * the more of that octave is added. Each octave is however raised to the power
- * of its position in the list, so the last entry in the "smooth" row, 0.35, is
- * raised to the power of 6, so can only add 0.001838...  of the amplitude to
- * the running total.
- *
- * In other words; the first p value sets the general shape of the terrain, the
- * second sets the major variations to that, ... until finally the smallest
- * bumps are added.
- *
- * Usefully, this routine is totally scaleable; so when 32bpp comes along, the
- * terrain can be as bumpy as you like! It is also infinitely expandable; a
- * single random seed terrain continues in X & Y as far as you care to
- * calculate. In theory, we could use just one seed value, but randomly select
- * where in the Perlin XY space we use for the terrain. Personally I prefer
- * using a simple (0, 0) to (X, Y), with a varying seed.
- *
- *
- * Other things i have had to do: mountainous wasnt mountainous enough, and
- * since we only have 0..15 heights available, I add a second generated map
- * (with a modified seed), onto the original. This generally raises the
- * terrain, which then needs scaling back down. Overall effect is a general
- * uplift.
- *
- * However, the values on the top of mountains are then almost guaranteed to go
- * too high, so large flat plateaus appeared at height 15. To counter this, I
- * scale all heights above 12 to proportion up to 15. It still makes the
- * mountains have flatish tops, rather than craggy peaks, but at least they
- * arent smooth as glass.
- *
- *
- * For a full discussion of Perlin Noise, please visit:
- * http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
- *
- *
- * Evolution II
- *
- * The algorithm as described in the above link suggests to compute each tile height
- * as composition of several noise waves. Some of them are computed directly by
- * noise(x, y) function, some are calculated using linear approximation. Our
- * first implementation of perlin_noise_2D() used 4 noise(x, y) calls plus
- * 3 linear interpolations. It was called 6 times for each tile. This was a bit
- * CPU expensive.
- *
- * The following implementation uses optimized algorithm that should produce
- * the same quality result with much less computations, but more memory accesses.
- * The overal speedup should be 300% to 800% depending on CPU and memory speed.
- *
- * I will try to explain it on the example below:
- *
- * Have a map of 4 x 4 tiles, our simplifiead noise generator produces only two
- * values -1 and +1, use 3 octaves with wave lenght 1, 2 and 4, with amplitudes
- * 3, 2, 1. Original algorithm produces:
- *
- * h00 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 0/4) + lerp(lerp(-2,  2, 0/2), lerp( 2, -2, 0/2), 0/2) + -1 = lerp(-3.0,  3.0, 0/4) + lerp(-2,  2, 0/2) + -1 = -3.0  + -2 + -1 = -6.0
- * h01 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 0/4) + lerp(lerp(-2,  2, 1/2), lerp( 2, -2, 1/2), 0/2) +  1 = lerp(-1.5,  1.5, 0/4) + lerp( 0,  0, 0/2) +  1 = -1.5  +  0 +  1 = -0.5
- * h02 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 0/4) + lerp(lerp( 2, -2, 0/2), lerp(-2,  2, 0/2), 0/2) + -1 = lerp(   0,    0, 0/4) + lerp( 2, -2, 0/2) + -1 =    0  +  2 + -1 =  1.0
- * h03 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 0/4) + lerp(lerp( 2, -2, 1/2), lerp(-2,  2, 1/2), 0/2) +  1 = lerp( 1.5, -1.5, 0/4) + lerp( 0,  0, 0/2) +  1 =  1.5  +  0 +  1 =  2.5
- *
- * h10 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 1/4) + lerp(lerp(-2,  2, 0/2), lerp( 2, -2, 0/2), 1/2) +  1 = lerp(-3.0,  3.0, 1/4) + lerp(-2,  2, 1/2) +  1 = -1.5  +  0 +  1 = -0.5
- * h11 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 1/4) + lerp(lerp(-2,  2, 1/2), lerp( 2, -2, 1/2), 1/2) + -1 = lerp(-1.5,  1.5, 1/4) + lerp( 0,  0, 1/2) + -1 = -0.75 +  0 + -1 = -1.75
- * h12 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 1/4) + lerp(lerp( 2, -2, 0/2), lerp(-2,  2, 0/2), 1/2) +  1 = lerp(   0,    0, 1/4) + lerp( 2, -2, 1/2) +  1 =    0  +  0 +  1 =  1.0
- * h13 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 1/4) + lerp(lerp( 2, -2, 1/2), lerp(-2,  2, 1/2), 1/2) + -1 = lerp( 1.5, -1.5, 1/4) + lerp( 0,  0, 1/2) + -1 =  0.75 +  0 + -1 = -0.25
- *
- *
- * Optimization 1:
- *
- * 1) we need to allocate a bit more tiles: (size_x + 1) * (size_y + 1) = (5 * 5):
- *
- * 2) setup corner values using amplitude 3
- * {    -3.0        X          X          X          3.0   }
- * {     X          X          X          X          X     }
- * {     X          X          X          X          X     }
- * {     X          X          X          X          X     }
- * {     3.0        X          X          X         -3.0   }
- *
- * 3a) interpolate values in the middle
- * {    -3.0        X          0.0        X          3.0   }
- * {     X          X          X          X          X     }
- * {     0.0        X          0.0        X          0.0   }
- * {     X          X          X          X          X     }
- * {     3.0        X          0.0        X         -3.0   }
- *
- * 3b) add patches with amplitude 2 to them
- * {    -5.0        X          2.0        X          1.0   }
- * {     X          X          X          X          X     }
- * {     2.0        X         -2.0        X          2.0   }
- * {     X          X          X          X          X     }
- * {     1.0        X          2.0        X         -5.0   }
- *
- * 4a) interpolate values in the middle
- * {    -5.0       -1.5        2.0        1.5        1.0   }
- * {    -1.5       -0.75       0.0        0.75       1.5   }
- * {     2.0        0.0       -2.0        0.0        2.0   }
- * {     1.5        0.75       0.0       -0.75      -1.5   }
- * {     1.0        1.5        2.0       -1.5       -5.0   }
- *
- * 4b) add patches with amplitude 1 to them
- * {    -6.0       -0.5        1.0        2.5        0.0   }
- * {    -0.5       -1.75       1.0       -0.25       2.5   }
- * {     1.0        1.0       -3.0        1.0        1.0   }
- * {     2.5       -0.25       1.0       -1.75      -0.5   }
- * {     0.0        2.5        1.0       -0.5       -6.0   }
- *
- *
- *
- * Optimization 2:
- *
- * As you can see above, each noise function was called just once. Therefore
- * we don't need to use noise function that calculates the noise from x, y and
- * some prime. The same quality result we can obtain using standard Random()
- * function instead.
- *
- */
-
-#ifndef M_PI_2
-#define M_PI_2 1.57079632679489661923
-#define M_PI   3.14159265358979323846
-#endif /* M_PI_2 */
-
-/** Fixed point type for heights */
-typedef int16 height_t;
-static const int height_decimal_bits = 4;
-static const height_t _invalid_height = -32768;
-
-/** Fixed point array for amplitudes (and percent values) */
-typedef int amplitude_t;
-static const int amplitude_decimal_bits = 10;
-
-/** Height map - allocated array of heights (MapSizeX() + 1) x (MapSizeY() + 1) */
-typedef struct HeightMap
-{
-	height_t *h;         //! array of heights
-	uint     dim_x;      //! height map size_x MapSizeX() + 1
-	uint     total_size; //! height map total size
-	uint     size_x;     //! MapSizeX()
-	uint     size_y;     //! MapSizeY()
-} HeightMap;
-
-/** Global height map instance */
-static HeightMap _height_map = {NULL, 0, 0, 0, 0};
-
-/** Height map accessors */
-#define HeightMapXY(x, y) _height_map.h[(x) + (y) * _height_map.dim_x]
-
-/** Conversion: int to height_t */
-#define I2H(i) ((i) << height_decimal_bits)
-/** Conversion: height_t to int */
-#define H2I(i) ((i) >> height_decimal_bits)
-
-/** Conversion: int to amplitude_t */
-#define I2A(i) ((i) << amplitude_decimal_bits)
-/** Conversion: amplitude_t to int */
-#define A2I(i) ((i) >> amplitude_decimal_bits)
-
-/** Conversion: amplitude_t to height_t */
-#define A2H(a) ((height_decimal_bits < amplitude_decimal_bits) \
-	? ((a) >> (amplitude_decimal_bits - height_decimal_bits)) \
-	: ((a) << (height_decimal_bits - amplitude_decimal_bits)))
-
-/** Walk through all items of _height_map.h */
-#define FOR_ALL_TILES_IN_HEIGHT(h) for (h = _height_map.h; h < &_height_map.h[_height_map.total_size]; h++)
-
-/** Noise amplitudes (multiplied by 1024)
- * - indexed by "smoothness setting" and log2(frequency) */
-static const amplitude_t _amplitudes_by_smoothness_and_frequency[4][12] = {
-	// Very smooth
-	{1000,  350,  123,   43,   15,    1,     1,    0,    0,    0,    0,    0},
-	// Smooth
-	{1000, 1000,  403,  200,   64,    8,     1,    0,    0,    0,    0,    0},
-	// Rough
-	{1000, 1200,  800,  500,  200,   16,     4,    0,    0,    0,    0,    0},
-	// Very Rough
-	{1500, 1000, 1200, 1000,  500,   32,    20,    0,    0,    0,    0,    0},
-};
-
-/** Desired water percentage (100% == 1024) - indexed by _opt.diff.quantity_sea_lakes */
-static const amplitude_t _water_percent[4] = {20, 80, 250, 400};
-
-/** Desired maximum height - indexed by _opt.diff.terrain_type */
-static const int8 _max_height[4] = {
-	6,       // Very flat
-	9,       // Flat
-	12,      // Hilly
-	15       // Mountainous
-};
-
-/** Check if a X/Y set are within the map. */
-static inline bool IsValidXY(uint x, uint y)
-{
-	return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y;
-}
-
-
-/** Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members */
-static inline bool AllocHeightMap(void)
-{
-	height_t *h;
-
-	_height_map.size_x = MapSizeX();
-	_height_map.size_y = MapSizeY();
-
-	/* Allocate memory block for height map row pointers */
-	_height_map.total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1);
-	_height_map.dim_x = _height_map.size_x + 1;
-	_height_map.h = calloc(_height_map.total_size, sizeof(*_height_map.h));
-	if (_height_map.h == NULL) return false;
-
-	/* Iterate through height map initialize values */
-	FOR_ALL_TILES_IN_HEIGHT(h) *h = _invalid_height;
-
-	return true;
-}
-
-/** Free height map */
-static inline void FreeHeightMap(void)
-{
-	if (_height_map.h == NULL) return;
-	free(_height_map.h);
-	_height_map.h = NULL;
-}
-
-/** RandomHeight() generator */
-static inline height_t RandomHeight(amplitude_t rMax)
-{
-	amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF);
-	height_t rh;
-	/* Scale the amplitude for better resolution */
-	rMax *= 16;
-	/* Spread height into range -rMax..+rMax */
-	rh = A2H(ra % (2 * rMax + 1) - rMax);
-	return rh;
-}
-
-/** One interpolation and noise round */
-static bool ApplyNoise(uint log_frequency, amplitude_t amplitude)
-{
-	uint size_min = min(_height_map.size_x, _height_map.size_y);
-	uint step = size_min >> log_frequency;
-	uint x, y;
-
-	assert(_height_map.h != NULL);
-
-	/* Are we finished? */
-	if (step == 0) return false;
-
-	if (log_frequency == 0) {
-		/* This is first round, we need to establish base heights with step = size_min */
-		for (y = 0; y <= _height_map.size_y; y += step) {
-			for (x = 0; x <= _height_map.size_x; x += step) {
-				height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0;
-				HeightMapXY(x, y) = height;
-			}
-		}
-		return true;
-	}
-
-	/* It is regular iteration round.
-	 * Interpolate height values at odd x, even y tiles */
-	for (y = 0; y <= _height_map.size_y; y += 2 * step) {
-		for (x = 0; x < _height_map.size_x; x += 2 * step) {
-			height_t h00 = HeightMapXY(x + 0 * step, y);
-			height_t h02 = HeightMapXY(x + 2 * step, y);
-			height_t h01 = (h00 + h02) / 2;
-			HeightMapXY(x + 1 * step, y) = h01;
-		}
-	}
-
-	/* Interpolate height values at odd y tiles */
-	for (y = 0; y < _height_map.size_y; y += 2 * step) {
-		for (x = 0; x <= _height_map.size_x; x += step) {
-			height_t h00 = HeightMapXY(x, y + 0 * step);
-			height_t h20 = HeightMapXY(x, y + 2 * step);
-			height_t h10 = (h00 + h20) / 2;
-			HeightMapXY(x, y + 1 * step) = h10;
-		}
-	}
-
-	for (y = 0; y <= _height_map.size_y; y += step) {
-		for (x = 0; x <= _height_map.size_x; x += step) {
-			HeightMapXY(x, y) += RandomHeight(amplitude);
-		}
-	}
-	return (step > 1);
-}
-
-/** Base Perlin noise generator - fills height map with raw Perlin noise */
-static void HeightMapGenerate(void)
-{
-	uint size_min = min(_height_map.size_x, _height_map.size_y);
-	uint iteration_round = 0;
-	amplitude_t amplitude;
-	bool continue_iteration;
-	uint log_size_min, log_frequency_min;
-	int log_frequency;
-
-	/* Find first power of two that fits */
-	for (log_size_min = 6; (1U << log_size_min) < size_min; log_size_min++) { }
-	log_frequency_min = log_size_min - 6;
-
-	do {
-		log_frequency = iteration_round - log_frequency_min;
-		if (log_frequency >= 0) {
-			amplitude = _amplitudes_by_smoothness_and_frequency[_patches.tgen_smoothness][log_frequency];
-		} else {
-			amplitude = 0;
-		}
-		continue_iteration = ApplyNoise(iteration_round, amplitude);
-		iteration_round++;
-	} while(continue_iteration);
-}
-
-/** Returns min, max and average height from height map */
-static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr)
-{
-	height_t h_min, h_max, h_avg, *h;
-	int64 h_accu = 0;
-	h_min = h_max = HeightMapXY(0, 0);
-
-	/* Get h_min, h_max and accumulate heights into h_accu */
-	FOR_ALL_TILES_IN_HEIGHT(h) {
-		if (*h < h_min) h_min = *h;
-		if (*h > h_max) h_max = *h;
-		h_accu += *h;
-	}
-
-	/* Get average height */
-	h_avg = (height_t)(h_accu / (_height_map.size_x * _height_map.size_y));
-
-	/* Return required results */
-	if (min_ptr != NULL) *min_ptr = h_min;
-	if (max_ptr != NULL) *max_ptr = h_max;
-	if (avg_ptr != NULL) *avg_ptr = h_avg;
-}
-
-/** Dill histogram and return pointer to its base point - to the count of zero heights */
-static int *HeightMapMakeHistogram(height_t h_min, height_t h_max, int *hist_buf)
-{
-	int *hist = hist_buf - h_min;
-	height_t *h;
-
-	/* Fill histogram */
-	FOR_ALL_TILES_IN_HEIGHT(h) {
-		assert(*h >= h_min);
-		assert(*h <= h_max);
-		hist[*h]++;
-	}
-	return hist;
-}
-
-/** Applies sine wave redistribution onto height map */
-static void HeightMapSineTransform(height_t h_min, height_t h_max)
-{
-	height_t *h;
-
-	FOR_ALL_TILES_IN_HEIGHT(h) {
-		double fheight;
-
-		if (*h < h_min) continue;
-
-		/* Transform height into 0..1 space */
-		fheight = (double)(*h - h_min) / (double)(h_max - h_min);
-		/* Apply sine transform depending on landscape type */
-		switch(_opt.landscape) {
-			case LT_CANDY:
-			case LT_NORMAL:
-				/* Move and scale 0..1 into -1..+1 */
-				fheight = 2 * fheight - 1;
-				/* Sine transform */
-				fheight = sin(fheight * M_PI_2);
-				/* Transform it back from -1..1 into 0..1 space */
-				fheight = 0.5 * (fheight + 1);
-				break;
-
-			case LT_HILLY:
-				{
-					/* Arctic terrain needs special height distribution.
-					 * Redistribute heights to have more tiles at highest (75%..100%) range */
-					double sine_upper_limit = 0.75;
-					double linear_compression = 2;
-					if (fheight >= sine_upper_limit) {
-						/* Over the limit we do linear compression up */
-						fheight = 1.0 - (1.0 - fheight) / linear_compression;
-					} else {
-						double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression;
-						/* Get 0..sine_upper_limit into -1..1 */
-						fheight = 2.0 * fheight / sine_upper_limit - 1.0;
-						/* Sine wave transform */
-						fheight = sin(fheight * M_PI_2);
-						/* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */
-						fheight = 0.5 * (fheight + 1.0) * m;
-					}
-				}
-				break;
-
-			case LT_DESERT:
-				{
-					/* Desert terrain needs special height distribution.
-					 * Half of tiles should be at lowest (0..25%) heights */
-					double sine_lower_limit = 0.5;
-					double linear_compression = 2;
-					if (fheight <= sine_lower_limit) {
-						/* Under the limit we do linear compression down */
-						fheight = fheight / linear_compression;
-					} else {
-						double m = sine_lower_limit / linear_compression;
-						/* Get sine_lower_limit..1 into -1..1 */
-						fheight = 2.0 * ((fheight - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0;
-						/* Sine wave transform */
-						fheight = sin(fheight * M_PI_2);
-						/* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */
-						fheight = 0.5 * ((1.0 - m) * fheight + (1.0 + m));
-					}
-				}
-				break;
-
-			default:
-				NOT_REACHED();
-				break;
-		}
-		/* Transform it back into h_min..h_max space */
-		*h = fheight * (h_max - h_min) + h_min;
-		if (*h < 0) *h = I2H(0);
-		if (*h >= h_max) *h = h_max - 1;
-	}
-}
-
-/** Adjusts heights in height map to contain required amount of water tiles */
-static void HeightMapAdjustWaterLevel(amplitude_t water_percent, height_t h_max_new)
-{
-	height_t h_min, h_max, h_avg, h_water_level;
-	int water_tiles, desired_water_tiles;
-	height_t *h;
-	int *hist_buf, *hist;
-
-	HeightMapGetMinMaxAvg(&h_min, &h_max, &h_avg);
-
-	/* Allocate histogram buffer and clear its cells */
-	hist_buf = calloc(h_max - h_min + 1, sizeof(*hist_buf));
-	/* Fill histogram */
-	hist = HeightMapMakeHistogram(h_min, h_max, hist_buf);
-
-	/* How many water tiles do we want? */
-	desired_water_tiles = (int)(((int64)water_percent) * (int64)(_height_map.size_x * _height_map.size_y)) >> amplitude_decimal_bits;
-
-	/* Raise water_level and accumulate values from histogram until we reach required number of water tiles */
-	for (h_water_level = h_min, water_tiles = 0; h_water_level < h_max; h_water_level++) {
-		water_tiles += hist[h_water_level];
-		if (water_tiles >= desired_water_tiles) break;
-	}
-
-	/* We now have the proper water level value.
-	 * Transform the height map into new (normalized) height map:
-	 *   values from range: h_min..h_water_level will become negative so it will be clamped to 0
-	 *   values from range: h_water_level..h_max are transformed into 0..h_max_new
-	 * , where h_max_new is 4, 8, 12 or 16 depending on terrain type (very flat, flat, hilly, mountains)
-	 */
-	FOR_ALL_TILES_IN_HEIGHT(h) {
-		/* Transform height from range h_water_level..h_max into 0..h_max_new range */
-		*h = (height_t)(((int)h_max_new) * (*h - h_water_level) / (h_max - h_water_level)) + I2H(1);
-		/* Make sure all values are in the proper range (0..h_max_new) */
-		if (*h < 0) *h = I2H(0);
-		if (*h >= h_max_new) *h = h_max_new - 1;
-	}
-
-	free(hist_buf);
-}
-
-static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime);
-
-/**
- * This routine sculpts in from the edge a random amount, again a Perlin
- * sequence, to avoid the rigid flat-edge slopes that were present before. The
- * Perlin noise map doesnt know where we are going to slice across, and so we
- * often cut straight through high terrain. the smoothing routine makes it
- * legal, gradually increasing up from the edge to the original terrain height.
- * By cutting parts of this away, it gives a far more irregular edge to the
- * map-edge. Sometimes it works beautifully with the existing sea & lakes, and
- * creates a very realistic coastline. Other times the variation is less, and
- * the map-edge shows its cliff-like roots.
- *
- * This routine may be extended to randomly sculpt the height of the terrain
- * near the edge. This will have the coast edge at low level (1-3), rising in
- * smoothed steps inland to about 15 tiles in. This should make it look as
- * though the map has been built for the map size, rather than a slice through
- * a larger map.
- *
- * Please note that all the small numbers; 53, 101, 167, etc. are small primes
- * to help give the perlin noise a bit more of a random feel.
- */
-static void HeightMapCoastLines(void)
-{
-	int smallest_size = min(_patches.map_x, _patches.map_y);
-	const int margin = 4;
-	uint y, x;
-	uint max_x;
-	uint max_y;
-
-	/* Lower to sea level */
-	for (y = 0; y <= _height_map.size_y; y++) {
-		/* Top right */
-		max_x = myabs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12);
-		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
-		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
-		for (x = 0; x < max_x; x++) {
-			HeightMapXY(x, y) = 0;
-		}
-
-		/* Bottom left */
-		max_x = myabs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45,  67) + 0.75) * 8);
-		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
-		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
-		for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) {
-			HeightMapXY(x, y) = 0;
-		}
-	}
-
-	/* Lower to sea level */
-	for (x = 0; x <= _height_map.size_x; x++) {
-		/* Top left */
-		max_y = myabs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9);
-		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
-		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
-		for (y = 0; y < max_y; y++) {
-			HeightMapXY(x, y) = 0;
-		}
-
-
-		/* Bottom right */
-		max_y = myabs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12);
-		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
-		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
-		for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) {
-			HeightMapXY(x, y) = 0;
-		}
-	}
-}
-
-/** Start at given point, move in given direction, find and Smooth coast in that direction */
-static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y)
-{
-	const int max_coast_dist_from_edge = 35;
-	const int max_coast_Smooth_depth = 35;
-
-	int x, y;
-	int ed; // coast distance from edge
-	int depth;
-
-	height_t h_prev = 16;
-	height_t h;
-
-	assert(IsValidXY(org_x, org_y));
-
-	/* Search for the coast (first non-water tile) */
-	for (x = org_x, y = org_y, ed = 0; IsValidXY(x, y) && ed < max_coast_dist_from_edge; x += dir_x, y += dir_y, ed++) {
-		/* Coast found? */
-		if (HeightMapXY(x, y) > 15) break;
-
-		/* Coast found in the neighborhood? */
-		if (IsValidXY(x + dir_y, y + dir_x) && HeightMapXY(x + dir_y, y + dir_x) > 0) break;
-
-		/* Coast found in the neighborhood on the other side */
-		if (IsValidXY(x - dir_y, y - dir_x) && HeightMapXY(x - dir_y, y - dir_x) > 0) break;
-	}
-
-	/* Coast found or max_coast_dist_from_edge has been reached.
-	 * Soften the coast slope */
-	for (depth = 0; IsValidXY(x, y) && depth <= max_coast_Smooth_depth; depth++, x += dir_x, y += dir_y) {
-		h = HeightMapXY(x, y);
-		h = min(h, h_prev + (4 + depth)); // coast softening formula
-		HeightMapXY(x, y) = h;
-		h_prev = h;
-	}
-}
-
-/** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */
-static void HeightMapSmoothCoasts(void)
-{
-	uint x, y;
-	/* First Smooth NW and SE coasts (y close to 0 and y close to size_y) */
-	for (x = 0; x < _height_map.size_x; x++) {
-		HeightMapSmoothCoastInDirection(x, 0, 0, 1);
-		HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1);
-	}
-	/* First Smooth NE and SW coasts (x close to 0 and x close to size_x) */
-	for (y = 0; y < _height_map.size_y; y++) {
-		HeightMapSmoothCoastInDirection(0, y, 1, 0);
-		HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0);
-	}
-}
-
-/**
- * This routine provides the essential cleanup necessary before OTTD can
- * display the terrain. When generated, the terrain heights can jump more than
- * one level between tiles. This routine smooths out those differences so that
- * the most it can change is one level. When OTTD can support cliffs, this
- * routine may not be necessary.
- */
-static void HeightMapSmoothSlopes(height_t dh_max)
-{
-	int x, y;
-	for (y = 1; y <= (int)_height_map.size_y; y++) {
-		for (x = 1; x <= (int)_height_map.size_x; x++) {
-			height_t h_max = min(HeightMapXY(x - 1, y), HeightMapXY(x, y - 1)) + dh_max;
-			if (HeightMapXY(x, y) > h_max) HeightMapXY(x, y) = h_max;
-		}
-	}
-	for (y = _height_map.size_y - 1; y >= 0; y--) {
-		for (x = _height_map.size_x - 1; x >= 0; x--) {
-			height_t h_max = min(HeightMapXY(x + 1, y), HeightMapXY(x, y + 1)) + dh_max;
-			if (HeightMapXY(x, y) > h_max) HeightMapXY(x, y) = h_max;
-		}
-	}
-}
-
-/** Height map terraform post processing:
- *  - water level adjusting
- *  - coast Smoothing
- *  - slope Smoothing
- *  - height histogram redistribution by sine wave transform */
-static void HeightMapNormalize(void)
-{
-	const amplitude_t water_percent = _water_percent[_opt.diff.quantity_sea_lakes];
-	const height_t h_max_new = I2H(_max_height[_opt.diff.terrain_type]);
-	const height_t roughness = 7 + 3 * _patches.tgen_smoothness;
-
-	HeightMapAdjustWaterLevel(water_percent, h_max_new);
-
-	HeightMapCoastLines();
-	HeightMapSmoothSlopes(roughness);
-
-	HeightMapSmoothCoasts();
-	HeightMapSmoothSlopes(roughness);
-
-	HeightMapSineTransform(12, h_max_new);
-	HeightMapSmoothSlopes(16);
-}
-
-static inline int perlin_landXY(uint x, uint y)
-{
-	return HeightMapXY(x, y);
-}
-
-
-/* The following decimals are the octave power modifiers for the Perlin noise */
-static const double _perlin_p_values[][7] = {    // perlin frequency per power
-	{ 0.35, 0.35, 0.35, 0.35, 0.35, 0.25, 0.539 }, // Very smooth
-	{ 0.45, 0.55, 0.45, 0.45, 0.35, 0.25, 0.89  }, // Smooth
-	{ 0.85, 0.80, 0.70, 0.45, 0.45, 0.35, 1.825 }, // Rough 1.825
-	{ 0.95, 0.85, 0.80, 0.55, 0.55, 0.45, 2.245 }  // Very Rough 2.25
-};
-
-/**
- * The Perlin Noise calculation using large primes
- * The initial number is adjusted by two values; the generation_seed, and the
- * passed parameter; prime.
- * prime is used to allow the perlin noise generator to create useful random
- * numbers from slightly different series.
- */
-static double int_noise(const long x, const long y, const int prime)
-{
-	long n = x + y * prime + _patches.generation_seed;
-
-	n = (n << 13) ^ n;
-
-	/* Pseudo-random number generator, using several large primes */
-	return 1.0 - (double)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0;
-}
-
-
-/**
- * Hj. Malthaner's routine included 2 different noise smoothing methods.
- * We now use the "raw" int_noise one.
- * However, it may be useful to move to the other routine in future.
- * So it is included too.
- */
-static double smoothed_noise(const int x, const int y, const int prime)
-{
-#if 0
-	/* A hilly world (four corner smooth) */
-	const double sides = int_noise(x - 1, y) + int_noise(x + 1, y) + int_noise(x, y - 1) + int_noise(x, y + 1);
-	const double center  =  int_noise(x, y);
-	return (sides + sides + center * 4) / 8.0;
-#endif
-
-	/* This gives very hilly world */
-	return int_noise(x, y, prime);
-}
-
-
-/**
- * This routine determines the interpolated value between a and b
- */
-static inline double linear_interpolate(const double a, const double b, const double x)
-{
-	return a + x * (b - a);
-}
-
-
-/**
- * This routine returns the smoothed interpolated noise for an x and y, using
- * the values from the surrounding positions.
- */
-static double interpolated_noise(const double x, const double y, const int prime)
-{
-	const int integer_X = (int)x;
-	const int integer_Y = (int)y;
-
-	const double fractional_X = x - (double)integer_X;
-	const double fractional_Y = y - (double)integer_Y;
-
-	const double v1 = smoothed_noise(integer_X,     integer_Y,     prime);
-	const double v2 = smoothed_noise(integer_X + 1, integer_Y,     prime);
-	const double v3 = smoothed_noise(integer_X,     integer_Y + 1, prime);
-	const double v4 = smoothed_noise(integer_X + 1, integer_Y + 1, prime);
-
-	const double i1 = linear_interpolate(v1, v2, fractional_X);
-	const double i2 = linear_interpolate(v3, v4, fractional_X);
-
-	return linear_interpolate(i1, i2, fractional_Y);
-}
-
-
-/**
- * This is a similar function to the main perlin noise calculation, but uses
- * the value p passed as a parameter rather than selected from the predefined
- * sequences. as you can guess by its title, i use this to create the indented
- * coastline, which is just another perlin sequence.
- */
-static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime)
-{
-	double total = 0.0;
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		const double frequency = (double)(1 << i);
-		const double amplitude = pow(p, (double)i);
-
-		total += interpolated_noise((x * frequency) / 64.0, (y * frequency) / 64.0, prime) * amplitude;
-	}
-
-	return total;
-}
-
-
-/** A small helper function */
-static void TgenSetTileHeight(TileIndex tile, int height)
-{
-	SetTileHeight(tile, height);
-	MakeClear(tile, CLEAR_GRASS, 3);
-}
-
-/**
- * The main new land generator using Perlin noise. Desert landscape is handled
- * different to all others to give a desert valley between two high mountains.
- * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic
- * areas wont be high enough, and there will be very little tropic on the map.
- * Thus Tropic works best on Hilly or Mountainous.
- */
-void GenerateTerrainPerlin(void)
-{
-	uint x, y;
-
-	if (!AllocHeightMap()) return;
-	GenerateWorldSetAbortCallback(FreeHeightMap);
-
-	HeightMapGenerate();
-
-	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-	HeightMapNormalize();
-
-	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-	/* Transfer height map into OTTD map */
-	for (y = 2; y < _height_map.size_y - 2; y++) {
-		for (x = 2; x < _height_map.size_x - 2; x++) {
-			int height = H2I(HeightMapXY(x, y));
-			if (height < 0) height = 0;
-			if (height > 15) height = 15;
-			TgenSetTileHeight(TileXY(x, y), height);
-		}
-	}
-
-	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
-
-	/* Recreate void tiles at the border in case they have been affected by generation */
-	for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y + _height_map.size_x - 1);
-	for (x = 0; x < _height_map.size_x;     x++) MakeVoid(_height_map.size_x * y + x);
-
-	FreeHeightMap();
-	GenerateWorldSetAbortCallback(NULL);
-}
new file mode 100644
--- /dev/null
+++ b/src/tgp.cpp
@@ -0,0 +1,829 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include <math.h>
+#include "openttd.h"
+#include "clear_map.h"
+#include "functions.h"
+#include "map.h"
+#include "table/strings.h"
+#include "clear_map.h"
+#include "tile.h"
+#include "variables.h"
+#include "void_map.h"
+#include "tgp.h"
+#include "console.h"
+#include "genworld.h"
+
+/*
+ * OTTD Perlin Noise Landscape Generator, aka TerraGenesis Perlin
+ *
+ * Quickie guide to Perlin Noise
+ * Perlin noise is a predictable pseudo random number sequence. By generating
+ * it in 2 dimensions, it becomes a useful random map, that for a given seed
+ * and starting X & Y is entirely predictable. On the face of it, that may not
+ * be useful. However, it means that if you want to replay a map in a different
+ * terrain, or just vary the sea level, you just re-run the generator with the
+ * same seed. The seed is an int32, and is randomised on each run of New Game.
+ * The Scenario Generator does not randomise the value, so that you can
+ * experiment with one terrain until you are happy, or click "Random" for a new
+ * random seed.
+ *
+ * Perlin Noise is a series of "octaves" of random noise added together. By
+ * reducing the amplitude of the noise with each octave, the first octave of
+ * noise defines the main terrain sweep, the next the ripples on that, and the
+ * next the ripples on that. I use 6 octaves, with the amplitude controlled by
+ * a power ratio, usually known as a persistence or p value. This I vary by the
+ * smoothness selection, as can be seen in the table below. The closer to 1,
+ * the more of that octave is added. Each octave is however raised to the power
+ * of its position in the list, so the last entry in the "smooth" row, 0.35, is
+ * raised to the power of 6, so can only add 0.001838...  of the amplitude to
+ * the running total.
+ *
+ * In other words; the first p value sets the general shape of the terrain, the
+ * second sets the major variations to that, ... until finally the smallest
+ * bumps are added.
+ *
+ * Usefully, this routine is totally scaleable; so when 32bpp comes along, the
+ * terrain can be as bumpy as you like! It is also infinitely expandable; a
+ * single random seed terrain continues in X & Y as far as you care to
+ * calculate. In theory, we could use just one seed value, but randomly select
+ * where in the Perlin XY space we use for the terrain. Personally I prefer
+ * using a simple (0, 0) to (X, Y), with a varying seed.
+ *
+ *
+ * Other things i have had to do: mountainous wasnt mountainous enough, and
+ * since we only have 0..15 heights available, I add a second generated map
+ * (with a modified seed), onto the original. This generally raises the
+ * terrain, which then needs scaling back down. Overall effect is a general
+ * uplift.
+ *
+ * However, the values on the top of mountains are then almost guaranteed to go
+ * too high, so large flat plateaus appeared at height 15. To counter this, I
+ * scale all heights above 12 to proportion up to 15. It still makes the
+ * mountains have flatish tops, rather than craggy peaks, but at least they
+ * arent smooth as glass.
+ *
+ *
+ * For a full discussion of Perlin Noise, please visit:
+ * http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
+ *
+ *
+ * Evolution II
+ *
+ * The algorithm as described in the above link suggests to compute each tile height
+ * as composition of several noise waves. Some of them are computed directly by
+ * noise(x, y) function, some are calculated using linear approximation. Our
+ * first implementation of perlin_noise_2D() used 4 noise(x, y) calls plus
+ * 3 linear interpolations. It was called 6 times for each tile. This was a bit
+ * CPU expensive.
+ *
+ * The following implementation uses optimized algorithm that should produce
+ * the same quality result with much less computations, but more memory accesses.
+ * The overal speedup should be 300% to 800% depending on CPU and memory speed.
+ *
+ * I will try to explain it on the example below:
+ *
+ * Have a map of 4 x 4 tiles, our simplifiead noise generator produces only two
+ * values -1 and +1, use 3 octaves with wave lenght 1, 2 and 4, with amplitudes
+ * 3, 2, 1. Original algorithm produces:
+ *
+ * h00 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 0/4) + lerp(lerp(-2,  2, 0/2), lerp( 2, -2, 0/2), 0/2) + -1 = lerp(-3.0,  3.0, 0/4) + lerp(-2,  2, 0/2) + -1 = -3.0  + -2 + -1 = -6.0
+ * h01 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 0/4) + lerp(lerp(-2,  2, 1/2), lerp( 2, -2, 1/2), 0/2) +  1 = lerp(-1.5,  1.5, 0/4) + lerp( 0,  0, 0/2) +  1 = -1.5  +  0 +  1 = -0.5
+ * h02 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 0/4) + lerp(lerp( 2, -2, 0/2), lerp(-2,  2, 0/2), 0/2) + -1 = lerp(   0,    0, 0/4) + lerp( 2, -2, 0/2) + -1 =    0  +  2 + -1 =  1.0
+ * h03 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 0/4) + lerp(lerp( 2, -2, 1/2), lerp(-2,  2, 1/2), 0/2) +  1 = lerp( 1.5, -1.5, 0/4) + lerp( 0,  0, 0/2) +  1 =  1.5  +  0 +  1 =  2.5
+ *
+ * h10 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 1/4) + lerp(lerp(-2,  2, 0/2), lerp( 2, -2, 0/2), 1/2) +  1 = lerp(-3.0,  3.0, 1/4) + lerp(-2,  2, 1/2) +  1 = -1.5  +  0 +  1 = -0.5
+ * h11 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 1/4) + lerp(lerp(-2,  2, 1/2), lerp( 2, -2, 1/2), 1/2) + -1 = lerp(-1.5,  1.5, 1/4) + lerp( 0,  0, 1/2) + -1 = -0.75 +  0 + -1 = -1.75
+ * h12 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 1/4) + lerp(lerp( 2, -2, 0/2), lerp(-2,  2, 0/2), 1/2) +  1 = lerp(   0,    0, 1/4) + lerp( 2, -2, 1/2) +  1 =    0  +  0 +  1 =  1.0
+ * h13 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 1/4) + lerp(lerp( 2, -2, 1/2), lerp(-2,  2, 1/2), 1/2) + -1 = lerp( 1.5, -1.5, 1/4) + lerp( 0,  0, 1/2) + -1 =  0.75 +  0 + -1 = -0.25
+ *
+ *
+ * Optimization 1:
+ *
+ * 1) we need to allocate a bit more tiles: (size_x + 1) * (size_y + 1) = (5 * 5):
+ *
+ * 2) setup corner values using amplitude 3
+ * {    -3.0        X          X          X          3.0   }
+ * {     X          X          X          X          X     }
+ * {     X          X          X          X          X     }
+ * {     X          X          X          X          X     }
+ * {     3.0        X          X          X         -3.0   }
+ *
+ * 3a) interpolate values in the middle
+ * {    -3.0        X          0.0        X          3.0   }
+ * {     X          X          X          X          X     }
+ * {     0.0        X          0.0        X          0.0   }
+ * {     X          X          X          X          X     }
+ * {     3.0        X          0.0        X         -3.0   }
+ *
+ * 3b) add patches with amplitude 2 to them
+ * {    -5.0        X          2.0        X          1.0   }
+ * {     X          X          X          X          X     }
+ * {     2.0        X         -2.0        X          2.0   }
+ * {     X          X          X          X          X     }
+ * {     1.0        X          2.0        X         -5.0   }
+ *
+ * 4a) interpolate values in the middle
+ * {    -5.0       -1.5        2.0        1.5        1.0   }
+ * {    -1.5       -0.75       0.0        0.75       1.5   }
+ * {     2.0        0.0       -2.0        0.0        2.0   }
+ * {     1.5        0.75       0.0       -0.75      -1.5   }
+ * {     1.0        1.5        2.0       -1.5       -5.0   }
+ *
+ * 4b) add patches with amplitude 1 to them
+ * {    -6.0       -0.5        1.0        2.5        0.0   }
+ * {    -0.5       -1.75       1.0       -0.25       2.5   }
+ * {     1.0        1.0       -3.0        1.0        1.0   }
+ * {     2.5       -0.25       1.0       -1.75      -0.5   }
+ * {     0.0        2.5        1.0       -0.5       -6.0   }
+ *
+ *
+ *
+ * Optimization 2:
+ *
+ * As you can see above, each noise function was called just once. Therefore
+ * we don't need to use noise function that calculates the noise from x, y and
+ * some prime. The same quality result we can obtain using standard Random()
+ * function instead.
+ *
+ */
+
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#define M_PI   3.14159265358979323846
+#endif /* M_PI_2 */
+
+/** Fixed point type for heights */
+typedef int16 height_t;
+static const int height_decimal_bits = 4;
+static const height_t _invalid_height = -32768;
+
+/** Fixed point array for amplitudes (and percent values) */
+typedef int amplitude_t;
+static const int amplitude_decimal_bits = 10;
+
+/** Height map - allocated array of heights (MapSizeX() + 1) x (MapSizeY() + 1) */
+typedef struct HeightMap
+{
+	height_t *h;         //! array of heights
+	uint     dim_x;      //! height map size_x MapSizeX() + 1
+	uint     total_size; //! height map total size
+	uint     size_x;     //! MapSizeX()
+	uint     size_y;     //! MapSizeY()
+} HeightMap;
+
+/** Global height map instance */
+static HeightMap _height_map = {NULL, 0, 0, 0, 0};
+
+/** Height map accessors */
+#define HeightMapXY(x, y) _height_map.h[(x) + (y) * _height_map.dim_x]
+
+/** Conversion: int to height_t */
+#define I2H(i) ((i) << height_decimal_bits)
+/** Conversion: height_t to int */
+#define H2I(i) ((i) >> height_decimal_bits)
+
+/** Conversion: int to amplitude_t */
+#define I2A(i) ((i) << amplitude_decimal_bits)
+/** Conversion: amplitude_t to int */
+#define A2I(i) ((i) >> amplitude_decimal_bits)
+
+/** Conversion: amplitude_t to height_t */
+#define A2H(a) ((height_decimal_bits < amplitude_decimal_bits) \
+	? ((a) >> (amplitude_decimal_bits - height_decimal_bits)) \
+	: ((a) << (height_decimal_bits - amplitude_decimal_bits)))
+
+/** Walk through all items of _height_map.h */
+#define FOR_ALL_TILES_IN_HEIGHT(h) for (h = _height_map.h; h < &_height_map.h[_height_map.total_size]; h++)
+
+/** Noise amplitudes (multiplied by 1024)
+ * - indexed by "smoothness setting" and log2(frequency) */
+static const amplitude_t _amplitudes_by_smoothness_and_frequency[4][12] = {
+	// Very smooth
+	{1000,  350,  123,   43,   15,    1,     1,    0,    0,    0,    0,    0},
+	// Smooth
+	{1000, 1000,  403,  200,   64,    8,     1,    0,    0,    0,    0,    0},
+	// Rough
+	{1000, 1200,  800,  500,  200,   16,     4,    0,    0,    0,    0,    0},
+	// Very Rough
+	{1500, 1000, 1200, 1000,  500,   32,    20,    0,    0,    0,    0,    0},
+};
+
+/** Desired water percentage (100% == 1024) - indexed by _opt.diff.quantity_sea_lakes */
+static const amplitude_t _water_percent[4] = {20, 80, 250, 400};
+
+/** Desired maximum height - indexed by _opt.diff.terrain_type */
+static const int8 _max_height[4] = {
+	6,       // Very flat
+	9,       // Flat
+	12,      // Hilly
+	15       // Mountainous
+};
+
+/** Check if a X/Y set are within the map. */
+static inline bool IsValidXY(uint x, uint y)
+{
+	return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y;
+}
+
+
+/** Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members */
+static inline bool AllocHeightMap(void)
+{
+	height_t *h;
+
+	_height_map.size_x = MapSizeX();
+	_height_map.size_y = MapSizeY();
+
+	/* Allocate memory block for height map row pointers */
+	_height_map.total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1);
+	_height_map.dim_x = _height_map.size_x + 1;
+	_height_map.h = calloc(_height_map.total_size, sizeof(*_height_map.h));
+	if (_height_map.h == NULL) return false;
+
+	/* Iterate through height map initialize values */
+	FOR_ALL_TILES_IN_HEIGHT(h) *h = _invalid_height;
+
+	return true;
+}
+
+/** Free height map */
+static inline void FreeHeightMap(void)
+{
+	if (_height_map.h == NULL) return;
+	free(_height_map.h);
+	_height_map.h = NULL;
+}
+
+/** RandomHeight() generator */
+static inline height_t RandomHeight(amplitude_t rMax)
+{
+	amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF);
+	height_t rh;
+	/* Scale the amplitude for better resolution */
+	rMax *= 16;
+	/* Spread height into range -rMax..+rMax */
+	rh = A2H(ra % (2 * rMax + 1) - rMax);
+	return rh;
+}
+
+/** One interpolation and noise round */
+static bool ApplyNoise(uint log_frequency, amplitude_t amplitude)
+{
+	uint size_min = min(_height_map.size_x, _height_map.size_y);
+	uint step = size_min >> log_frequency;
+	uint x, y;
+
+	assert(_height_map.h != NULL);
+
+	/* Are we finished? */
+	if (step == 0) return false;
+
+	if (log_frequency == 0) {
+		/* This is first round, we need to establish base heights with step = size_min */
+		for (y = 0; y <= _height_map.size_y; y += step) {
+			for (x = 0; x <= _height_map.size_x; x += step) {
+				height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0;
+				HeightMapXY(x, y) = height;
+			}
+		}
+		return true;
+	}
+
+	/* It is regular iteration round.
+	 * Interpolate height values at odd x, even y tiles */
+	for (y = 0; y <= _height_map.size_y; y += 2 * step) {
+		for (x = 0; x < _height_map.size_x; x += 2 * step) {
+			height_t h00 = HeightMapXY(x + 0 * step, y);
+			height_t h02 = HeightMapXY(x + 2 * step, y);
+			height_t h01 = (h00 + h02) / 2;
+			HeightMapXY(x + 1 * step, y) = h01;
+		}
+	}
+
+	/* Interpolate height values at odd y tiles */
+	for (y = 0; y < _height_map.size_y; y += 2 * step) {
+		for (x = 0; x <= _height_map.size_x; x += step) {
+			height_t h00 = HeightMapXY(x, y + 0 * step);
+			height_t h20 = HeightMapXY(x, y + 2 * step);
+			height_t h10 = (h00 + h20) / 2;
+			HeightMapXY(x, y + 1 * step) = h10;
+		}
+	}
+
+	for (y = 0; y <= _height_map.size_y; y += step) {
+		for (x = 0; x <= _height_map.size_x; x += step) {
+			HeightMapXY(x, y) += RandomHeight(amplitude);
+		}
+	}
+	return (step > 1);
+}
+
+/** Base Perlin noise generator - fills height map with raw Perlin noise */
+static void HeightMapGenerate(void)
+{
+	uint size_min = min(_height_map.size_x, _height_map.size_y);
+	uint iteration_round = 0;
+	amplitude_t amplitude;
+	bool continue_iteration;
+	uint log_size_min, log_frequency_min;
+	int log_frequency;
+
+	/* Find first power of two that fits */
+	for (log_size_min = 6; (1U << log_size_min) < size_min; log_size_min++) { }
+	log_frequency_min = log_size_min - 6;
+
+	do {
+		log_frequency = iteration_round - log_frequency_min;
+		if (log_frequency >= 0) {
+			amplitude = _amplitudes_by_smoothness_and_frequency[_patches.tgen_smoothness][log_frequency];
+		} else {
+			amplitude = 0;
+		}
+		continue_iteration = ApplyNoise(iteration_round, amplitude);
+		iteration_round++;
+	} while(continue_iteration);
+}
+
+/** Returns min, max and average height from height map */
+static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr)
+{
+	height_t h_min, h_max, h_avg, *h;
+	int64 h_accu = 0;
+	h_min = h_max = HeightMapXY(0, 0);
+
+	/* Get h_min, h_max and accumulate heights into h_accu */
+	FOR_ALL_TILES_IN_HEIGHT(h) {
+		if (*h < h_min) h_min = *h;
+		if (*h > h_max) h_max = *h;
+		h_accu += *h;
+	}
+
+	/* Get average height */
+	h_avg = (height_t)(h_accu / (_height_map.size_x * _height_map.size_y));
+
+	/* Return required results */
+	if (min_ptr != NULL) *min_ptr = h_min;
+	if (max_ptr != NULL) *max_ptr = h_max;
+	if (avg_ptr != NULL) *avg_ptr = h_avg;
+}
+
+/** Dill histogram and return pointer to its base point - to the count of zero heights */
+static int *HeightMapMakeHistogram(height_t h_min, height_t h_max, int *hist_buf)
+{
+	int *hist = hist_buf - h_min;
+	height_t *h;
+
+	/* Fill histogram */
+	FOR_ALL_TILES_IN_HEIGHT(h) {
+		assert(*h >= h_min);
+		assert(*h <= h_max);
+		hist[*h]++;
+	}
+	return hist;
+}
+
+/** Applies sine wave redistribution onto height map */
+static void HeightMapSineTransform(height_t h_min, height_t h_max)
+{
+	height_t *h;
+
+	FOR_ALL_TILES_IN_HEIGHT(h) {
+		double fheight;
+
+		if (*h < h_min) continue;
+
+		/* Transform height into 0..1 space */
+		fheight = (double)(*h - h_min) / (double)(h_max - h_min);
+		/* Apply sine transform depending on landscape type */
+		switch(_opt.landscape) {
+			case LT_CANDY:
+			case LT_NORMAL:
+				/* Move and scale 0..1 into -1..+1 */
+				fheight = 2 * fheight - 1;
+				/* Sine transform */
+				fheight = sin(fheight * M_PI_2);
+				/* Transform it back from -1..1 into 0..1 space */
+				fheight = 0.5 * (fheight + 1);
+				break;
+
+			case LT_HILLY:
+				{
+					/* Arctic terrain needs special height distribution.
+					 * Redistribute heights to have more tiles at highest (75%..100%) range */
+					double sine_upper_limit = 0.75;
+					double linear_compression = 2;
+					if (fheight >= sine_upper_limit) {
+						/* Over the limit we do linear compression up */
+						fheight = 1.0 - (1.0 - fheight) / linear_compression;
+					} else {
+						double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression;
+						/* Get 0..sine_upper_limit into -1..1 */
+						fheight = 2.0 * fheight / sine_upper_limit - 1.0;
+						/* Sine wave transform */
+						fheight = sin(fheight * M_PI_2);
+						/* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */
+						fheight = 0.5 * (fheight + 1.0) * m;
+					}
+				}
+				break;
+
+			case LT_DESERT:
+				{
+					/* Desert terrain needs special height distribution.
+					 * Half of tiles should be at lowest (0..25%) heights */
+					double sine_lower_limit = 0.5;
+					double linear_compression = 2;
+					if (fheight <= sine_lower_limit) {
+						/* Under the limit we do linear compression down */
+						fheight = fheight / linear_compression;
+					} else {
+						double m = sine_lower_limit / linear_compression;
+						/* Get sine_lower_limit..1 into -1..1 */
+						fheight = 2.0 * ((fheight - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0;
+						/* Sine wave transform */
+						fheight = sin(fheight * M_PI_2);
+						/* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */
+						fheight = 0.5 * ((1.0 - m) * fheight + (1.0 + m));
+					}
+				}
+				break;
+
+			default:
+				NOT_REACHED();
+				break;
+		}
+		/* Transform it back into h_min..h_max space */
+		*h = fheight * (h_max - h_min) + h_min;
+		if (*h < 0) *h = I2H(0);
+		if (*h >= h_max) *h = h_max - 1;
+	}
+}
+
+/** Adjusts heights in height map to contain required amount of water tiles */
+static void HeightMapAdjustWaterLevel(amplitude_t water_percent, height_t h_max_new)
+{
+	height_t h_min, h_max, h_avg, h_water_level;
+	int water_tiles, desired_water_tiles;
+	height_t *h;
+	int *hist_buf, *hist;
+
+	HeightMapGetMinMaxAvg(&h_min, &h_max, &h_avg);
+
+	/* Allocate histogram buffer and clear its cells */
+	hist_buf = calloc(h_max - h_min + 1, sizeof(*hist_buf));
+	/* Fill histogram */
+	hist = HeightMapMakeHistogram(h_min, h_max, hist_buf);
+
+	/* How many water tiles do we want? */
+	desired_water_tiles = (int)(((int64)water_percent) * (int64)(_height_map.size_x * _height_map.size_y)) >> amplitude_decimal_bits;
+
+	/* Raise water_level and accumulate values from histogram until we reach required number of water tiles */
+	for (h_water_level = h_min, water_tiles = 0; h_water_level < h_max; h_water_level++) {
+		water_tiles += hist[h_water_level];
+		if (water_tiles >= desired_water_tiles) break;
+	}
+
+	/* We now have the proper water level value.
+	 * Transform the height map into new (normalized) height map:
+	 *   values from range: h_min..h_water_level will become negative so it will be clamped to 0
+	 *   values from range: h_water_level..h_max are transformed into 0..h_max_new
+	 * , where h_max_new is 4, 8, 12 or 16 depending on terrain type (very flat, flat, hilly, mountains)
+	 */
+	FOR_ALL_TILES_IN_HEIGHT(h) {
+		/* Transform height from range h_water_level..h_max into 0..h_max_new range */
+		*h = (height_t)(((int)h_max_new) * (*h - h_water_level) / (h_max - h_water_level)) + I2H(1);
+		/* Make sure all values are in the proper range (0..h_max_new) */
+		if (*h < 0) *h = I2H(0);
+		if (*h >= h_max_new) *h = h_max_new - 1;
+	}
+
+	free(hist_buf);
+}
+
+static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime);
+
+/**
+ * This routine sculpts in from the edge a random amount, again a Perlin
+ * sequence, to avoid the rigid flat-edge slopes that were present before. The
+ * Perlin noise map doesnt know where we are going to slice across, and so we
+ * often cut straight through high terrain. the smoothing routine makes it
+ * legal, gradually increasing up from the edge to the original terrain height.
+ * By cutting parts of this away, it gives a far more irregular edge to the
+ * map-edge. Sometimes it works beautifully with the existing sea & lakes, and
+ * creates a very realistic coastline. Other times the variation is less, and
+ * the map-edge shows its cliff-like roots.
+ *
+ * This routine may be extended to randomly sculpt the height of the terrain
+ * near the edge. This will have the coast edge at low level (1-3), rising in
+ * smoothed steps inland to about 15 tiles in. This should make it look as
+ * though the map has been built for the map size, rather than a slice through
+ * a larger map.
+ *
+ * Please note that all the small numbers; 53, 101, 167, etc. are small primes
+ * to help give the perlin noise a bit more of a random feel.
+ */
+static void HeightMapCoastLines(void)
+{
+	int smallest_size = min(_patches.map_x, _patches.map_y);
+	const int margin = 4;
+	uint y, x;
+	uint max_x;
+	uint max_y;
+
+	/* Lower to sea level */
+	for (y = 0; y <= _height_map.size_y; y++) {
+		/* Top right */
+		max_x = myabs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12);
+		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
+		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
+		for (x = 0; x < max_x; x++) {
+			HeightMapXY(x, y) = 0;
+		}
+
+		/* Bottom left */
+		max_x = myabs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45,  67) + 0.75) * 8);
+		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
+		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
+		for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) {
+			HeightMapXY(x, y) = 0;
+		}
+	}
+
+	/* Lower to sea level */
+	for (x = 0; x <= _height_map.size_x; x++) {
+		/* Top left */
+		max_y = myabs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9);
+		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
+		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
+		for (y = 0; y < max_y; y++) {
+			HeightMapXY(x, y) = 0;
+		}
+
+
+		/* Bottom right */
+		max_y = myabs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12);
+		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
+		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
+		for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) {
+			HeightMapXY(x, y) = 0;
+		}
+	}
+}
+
+/** Start at given point, move in given direction, find and Smooth coast in that direction */
+static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y)
+{
+	const int max_coast_dist_from_edge = 35;
+	const int max_coast_Smooth_depth = 35;
+
+	int x, y;
+	int ed; // coast distance from edge
+	int depth;
+
+	height_t h_prev = 16;
+	height_t h;
+
+	assert(IsValidXY(org_x, org_y));
+
+	/* Search for the coast (first non-water tile) */
+	for (x = org_x, y = org_y, ed = 0; IsValidXY(x, y) && ed < max_coast_dist_from_edge; x += dir_x, y += dir_y, ed++) {
+		/* Coast found? */
+		if (HeightMapXY(x, y) > 15) break;
+
+		/* Coast found in the neighborhood? */
+		if (IsValidXY(x + dir_y, y + dir_x) && HeightMapXY(x + dir_y, y + dir_x) > 0) break;
+
+		/* Coast found in the neighborhood on the other side */
+		if (IsValidXY(x - dir_y, y - dir_x) && HeightMapXY(x - dir_y, y - dir_x) > 0) break;
+	}
+
+	/* Coast found or max_coast_dist_from_edge has been reached.
+	 * Soften the coast slope */
+	for (depth = 0; IsValidXY(x, y) && depth <= max_coast_Smooth_depth; depth++, x += dir_x, y += dir_y) {
+		h = HeightMapXY(x, y);
+		h = min(h, h_prev + (4 + depth)); // coast softening formula
+		HeightMapXY(x, y) = h;
+		h_prev = h;
+	}
+}
+
+/** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */
+static void HeightMapSmoothCoasts(void)
+{
+	uint x, y;
+	/* First Smooth NW and SE coasts (y close to 0 and y close to size_y) */
+	for (x = 0; x < _height_map.size_x; x++) {
+		HeightMapSmoothCoastInDirection(x, 0, 0, 1);
+		HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1);
+	}
+	/* First Smooth NE and SW coasts (x close to 0 and x close to size_x) */
+	for (y = 0; y < _height_map.size_y; y++) {
+		HeightMapSmoothCoastInDirection(0, y, 1, 0);
+		HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0);
+	}
+}
+
+/**
+ * This routine provides the essential cleanup necessary before OTTD can
+ * display the terrain. When generated, the terrain heights can jump more than
+ * one level between tiles. This routine smooths out those differences so that
+ * the most it can change is one level. When OTTD can support cliffs, this
+ * routine may not be necessary.
+ */
+static void HeightMapSmoothSlopes(height_t dh_max)
+{
+	int x, y;
+	for (y = 1; y <= (int)_height_map.size_y; y++) {
+		for (x = 1; x <= (int)_height_map.size_x; x++) {
+			height_t h_max = min(HeightMapXY(x - 1, y), HeightMapXY(x, y - 1)) + dh_max;
+			if (HeightMapXY(x, y) > h_max) HeightMapXY(x, y) = h_max;
+		}
+	}
+	for (y = _height_map.size_y - 1; y >= 0; y--) {
+		for (x = _height_map.size_x - 1; x >= 0; x--) {
+			height_t h_max = min(HeightMapXY(x + 1, y), HeightMapXY(x, y + 1)) + dh_max;
+			if (HeightMapXY(x, y) > h_max) HeightMapXY(x, y) = h_max;
+		}
+	}
+}
+
+/** Height map terraform post processing:
+ *  - water level adjusting
+ *  - coast Smoothing
+ *  - slope Smoothing
+ *  - height histogram redistribution by sine wave transform */
+static void HeightMapNormalize(void)
+{
+	const amplitude_t water_percent = _water_percent[_opt.diff.quantity_sea_lakes];
+	const height_t h_max_new = I2H(_max_height[_opt.diff.terrain_type]);
+	const height_t roughness = 7 + 3 * _patches.tgen_smoothness;
+
+	HeightMapAdjustWaterLevel(water_percent, h_max_new);
+
+	HeightMapCoastLines();
+	HeightMapSmoothSlopes(roughness);
+
+	HeightMapSmoothCoasts();
+	HeightMapSmoothSlopes(roughness);
+
+	HeightMapSineTransform(12, h_max_new);
+	HeightMapSmoothSlopes(16);
+}
+
+static inline int perlin_landXY(uint x, uint y)
+{
+	return HeightMapXY(x, y);
+}
+
+
+/* The following decimals are the octave power modifiers for the Perlin noise */
+static const double _perlin_p_values[][7] = {    // perlin frequency per power
+	{ 0.35, 0.35, 0.35, 0.35, 0.35, 0.25, 0.539 }, // Very smooth
+	{ 0.45, 0.55, 0.45, 0.45, 0.35, 0.25, 0.89  }, // Smooth
+	{ 0.85, 0.80, 0.70, 0.45, 0.45, 0.35, 1.825 }, // Rough 1.825
+	{ 0.95, 0.85, 0.80, 0.55, 0.55, 0.45, 2.245 }  // Very Rough 2.25
+};
+
+/**
+ * The Perlin Noise calculation using large primes
+ * The initial number is adjusted by two values; the generation_seed, and the
+ * passed parameter; prime.
+ * prime is used to allow the perlin noise generator to create useful random
+ * numbers from slightly different series.
+ */
+static double int_noise(const long x, const long y, const int prime)
+{
+	long n = x + y * prime + _patches.generation_seed;
+
+	n = (n << 13) ^ n;
+
+	/* Pseudo-random number generator, using several large primes */
+	return 1.0 - (double)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0;
+}
+
+
+/**
+ * Hj. Malthaner's routine included 2 different noise smoothing methods.
+ * We now use the "raw" int_noise one.
+ * However, it may be useful to move to the other routine in future.
+ * So it is included too.
+ */
+static double smoothed_noise(const int x, const int y, const int prime)
+{
+#if 0
+	/* A hilly world (four corner smooth) */
+	const double sides = int_noise(x - 1, y) + int_noise(x + 1, y) + int_noise(x, y - 1) + int_noise(x, y + 1);
+	const double center  =  int_noise(x, y);
+	return (sides + sides + center * 4) / 8.0;
+#endif
+
+	/* This gives very hilly world */
+	return int_noise(x, y, prime);
+}
+
+
+/**
+ * This routine determines the interpolated value between a and b
+ */
+static inline double linear_interpolate(const double a, const double b, const double x)
+{
+	return a + x * (b - a);
+}
+
+
+/**
+ * This routine returns the smoothed interpolated noise for an x and y, using
+ * the values from the surrounding positions.
+ */
+static double interpolated_noise(const double x, const double y, const int prime)
+{
+	const int integer_X = (int)x;
+	const int integer_Y = (int)y;
+
+	const double fractional_X = x - (double)integer_X;
+	const double fractional_Y = y - (double)integer_Y;
+
+	const double v1 = smoothed_noise(integer_X,     integer_Y,     prime);
+	const double v2 = smoothed_noise(integer_X + 1, integer_Y,     prime);
+	const double v3 = smoothed_noise(integer_X,     integer_Y + 1, prime);
+	const double v4 = smoothed_noise(integer_X + 1, integer_Y + 1, prime);
+
+	const double i1 = linear_interpolate(v1, v2, fractional_X);
+	const double i2 = linear_interpolate(v3, v4, fractional_X);
+
+	return linear_interpolate(i1, i2, fractional_Y);
+}
+
+
+/**
+ * This is a similar function to the main perlin noise calculation, but uses
+ * the value p passed as a parameter rather than selected from the predefined
+ * sequences. as you can guess by its title, i use this to create the indented
+ * coastline, which is just another perlin sequence.
+ */
+static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime)
+{
+	double total = 0.0;
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		const double frequency = (double)(1 << i);
+		const double amplitude = pow(p, (double)i);
+
+		total += interpolated_noise((x * frequency) / 64.0, (y * frequency) / 64.0, prime) * amplitude;
+	}
+
+	return total;
+}
+
+
+/** A small helper function */
+static void TgenSetTileHeight(TileIndex tile, int height)
+{
+	SetTileHeight(tile, height);
+	MakeClear(tile, CLEAR_GRASS, 3);
+}
+
+/**
+ * The main new land generator using Perlin noise. Desert landscape is handled
+ * different to all others to give a desert valley between two high mountains.
+ * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic
+ * areas wont be high enough, and there will be very little tropic on the map.
+ * Thus Tropic works best on Hilly or Mountainous.
+ */
+void GenerateTerrainPerlin(void)
+{
+	uint x, y;
+
+	if (!AllocHeightMap()) return;
+	GenerateWorldSetAbortCallback(FreeHeightMap);
+
+	HeightMapGenerate();
+
+	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+	HeightMapNormalize();
+
+	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+	/* Transfer height map into OTTD map */
+	for (y = 2; y < _height_map.size_y - 2; y++) {
+		for (x = 2; x < _height_map.size_x - 2; x++) {
+			int height = H2I(HeightMapXY(x, y));
+			if (height < 0) height = 0;
+			if (height > 15) height = 15;
+			TgenSetTileHeight(TileXY(x, y), height);
+		}
+	}
+
+	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
+	/* Recreate void tiles at the border in case they have been affected by generation */
+	for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y + _height_map.size_x - 1);
+	for (x = 0; x < _height_map.size_x;     x++) MakeVoid(_height_map.size_x * y + x);
+
+	FreeHeightMap();
+	GenerateWorldSetAbortCallback(NULL);
+}
deleted file mode 100644
--- a/src/thread.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "thread.h"
-#include <stdlib.h>
-
-#if defined(__AMIGA__) || defined(__MORPHOS__) || defined(NO_THREADS)
-OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
-void *OTTDJoinThread(OTTDThread *t) { return NULL; }
-void OTTDExitThread(void) { NOT_REACHED(); };
-
-#elif defined(__OS2__)
-
-#define INCL_DOS
-#include <os2.h>
-#include <process.h>
-
-struct OTTDThread {
-	TID thread;
-	OTTDThreadFunc func;
-	void* arg;
-	void* ret;
-};
-
-static void Proxy(void* arg)
-{
-	OTTDThread* t = arg;
-	t->ret = t->func(t->arg);
-}
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
-	OTTDThread* t = malloc(sizeof(*t));
-
-	if (t == NULL) return NULL;
-
-	t->func = function;
-	t->arg  = arg;
-	t->thread = _beginthread(Proxy, NULL, 32768, t);
-	if (t->thread != -1) {
-		return t;
-	} else {
-		free(t);
-		return NULL;
-	}
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
-	void* ret;
-
-	if (t == NULL) return NULL;
-
-	DosWaitThread(&t->thread, DCWW_WAIT);
-	ret = t->ret;
-	free(t);
-	return ret;
-}
-
-void OTTDExitThread(void)
-{
-	_endthread();
-}
-
-#elif defined(UNIX)
-
-#include <pthread.h>
-
-struct OTTDThread {
-	pthread_t thread;
-};
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
-	OTTDThread* t = malloc(sizeof(*t));
-
-	if (t == NULL) return NULL;
-
-	if (pthread_create(&t->thread, NULL, function, arg) == 0) {
-		return t;
-	} else {
-		free(t);
-		return NULL;
-	}
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
-	void* ret;
-
-	if (t == NULL) return NULL;
-
-	pthread_join(t->thread, &ret);
-	free(t);
-	return ret;
-}
-
-void OTTDExitThread(void)
-{
-	pthread_exit(NULL);
-}
-
-#elif defined(WIN32)
-
-#include <windows.h>
-
-struct OTTDThread {
-	HANDLE thread;
-	OTTDThreadFunc func;
-	void* arg;
-	void* ret;
-};
-
-static DWORD WINAPI Proxy(LPVOID arg)
-{
-	OTTDThread* t = arg;
-	t->ret = t->func(t->arg);
-	return 0;
-}
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
-	OTTDThread* t = malloc(sizeof(*t));
-	DWORD dwThreadId;
-
-	if (t == NULL) return NULL;
-
-	t->func = function;
-	t->arg  = arg;
-	t->thread = CreateThread(NULL, 0, Proxy, t, 0, &dwThreadId);
-
-	if (t->thread != NULL) {
-		return t;
-	} else {
-		free(t);
-		return NULL;
-	}
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
-	void* ret;
-
-	if (t == NULL) return NULL;
-
-	WaitForSingleObject(t->thread, INFINITE);
-	CloseHandle(t->thread);
-	ret = t->ret;
-	free(t);
-	return ret;
-}
-
-void OTTDExitThread(void)
-{
-	ExitThread(0);
-}
-#endif
new file mode 100644
--- /dev/null
+++ b/src/thread.cpp
@@ -0,0 +1,157 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "thread.h"
+#include <stdlib.h>
+
+#if defined(__AMIGA__) || defined(__MORPHOS__) || defined(NO_THREADS)
+OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
+void *OTTDJoinThread(OTTDThread *t) { return NULL; }
+void OTTDExitThread(void) { NOT_REACHED(); };
+
+#elif defined(__OS2__)
+
+#define INCL_DOS
+#include <os2.h>
+#include <process.h>
+
+struct OTTDThread {
+	TID thread;
+	OTTDThreadFunc func;
+	void* arg;
+	void* ret;
+};
+
+static void Proxy(void* arg)
+{
+	OTTDThread* t = arg;
+	t->ret = t->func(t->arg);
+}
+
+OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
+{
+	OTTDThread* t = malloc(sizeof(*t));
+
+	if (t == NULL) return NULL;
+
+	t->func = function;
+	t->arg  = arg;
+	t->thread = _beginthread(Proxy, NULL, 32768, t);
+	if (t->thread != -1) {
+		return t;
+	} else {
+		free(t);
+		return NULL;
+	}
+}
+
+void* OTTDJoinThread(OTTDThread* t)
+{
+	void* ret;
+
+	if (t == NULL) return NULL;
+
+	DosWaitThread(&t->thread, DCWW_WAIT);
+	ret = t->ret;
+	free(t);
+	return ret;
+}
+
+void OTTDExitThread(void)
+{
+	_endthread();
+}
+
+#elif defined(UNIX)
+
+#include <pthread.h>
+
+struct OTTDThread {
+	pthread_t thread;
+};
+
+OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
+{
+	OTTDThread* t = malloc(sizeof(*t));
+
+	if (t == NULL) return NULL;
+
+	if (pthread_create(&t->thread, NULL, function, arg) == 0) {
+		return t;
+	} else {
+		free(t);
+		return NULL;
+	}
+}
+
+void* OTTDJoinThread(OTTDThread* t)
+{
+	void* ret;
+
+	if (t == NULL) return NULL;
+
+	pthread_join(t->thread, &ret);
+	free(t);
+	return ret;
+}
+
+void OTTDExitThread(void)
+{
+	pthread_exit(NULL);
+}
+
+#elif defined(WIN32)
+
+#include <windows.h>
+
+struct OTTDThread {
+	HANDLE thread;
+	OTTDThreadFunc func;
+	void* arg;
+	void* ret;
+};
+
+static DWORD WINAPI Proxy(LPVOID arg)
+{
+	OTTDThread* t = arg;
+	t->ret = t->func(t->arg);
+	return 0;
+}
+
+OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
+{
+	OTTDThread* t = malloc(sizeof(*t));
+	DWORD dwThreadId;
+
+	if (t == NULL) return NULL;
+
+	t->func = function;
+	t->arg  = arg;
+	t->thread = CreateThread(NULL, 0, Proxy, t, 0, &dwThreadId);
+
+	if (t->thread != NULL) {
+		return t;
+	} else {
+		free(t);
+		return NULL;
+	}
+}
+
+void* OTTDJoinThread(OTTDThread* t)
+{
+	void* ret;
+
+	if (t == NULL) return NULL;
+
+	WaitForSingleObject(t->thread, INFINITE);
+	CloseHandle(t->thread);
+	ret = t->ret;
+	free(t);
+	return ret;
+}
+
+void OTTDExitThread(void)
+{
+	ExitThread(0);
+}
+#endif
deleted file mode 100644
--- a/src/tile.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "tile.h"
-
-Slope GetTileSlope(TileIndex tile, uint *h)
-{
-	uint a;
-	uint b;
-	uint c;
-	uint d;
-	uint min;
-	uint r;
-
-	assert(tile < MapSize());
-
-	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) {
-		if (h != NULL) *h = 0;
-		return 0;
-	}
-
-	min = a = TileHeight(tile);
-	b = TileHeight(tile + TileDiffXY(1, 0));
-	if (min >= b) min = b;
-	c = TileHeight(tile + TileDiffXY(0, 1));
-	if (min >= c) min = c;
-	d = TileHeight(tile + TileDiffXY(1, 1));
-	if (min >= d) min = d;
-
-	r = SLOPE_FLAT;
-	if ((a -= min) != 0) r += (--a << 4) + SLOPE_N;
-	if ((c -= min) != 0) r += (--c << 4) + SLOPE_E;
-	if ((d -= min) != 0) r += (--d << 4) + SLOPE_S;
-	if ((b -= min) != 0) r += (--b << 4) + SLOPE_W;
-
-	if (h != NULL) *h = min * TILE_HEIGHT;
-
-	return r;
-}
-
-uint GetTileZ(TileIndex tile)
-{
-	uint h;
-	GetTileSlope(tile, &h);
-	return h;
-}
-
-
-uint GetTileMaxZ(TileIndex t)
-{
-	uint max;
-	uint h;
-
-	h = TileHeight(t);
-	max = h;
-	h = TileHeight(t + TileDiffXY(1, 0));
-	if (h > max) max = h;
-	h = TileHeight(t + TileDiffXY(0, 1));
-	if (h > max) max = h;
-	h = TileHeight(t + TileDiffXY(1, 1));
-	if (h > max) max = h;
-	return max * 8;
-}
new file mode 100644
--- /dev/null
+++ b/src/tile.cpp
@@ -0,0 +1,63 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "tile.h"
+
+Slope GetTileSlope(TileIndex tile, uint *h)
+{
+	uint a;
+	uint b;
+	uint c;
+	uint d;
+	uint min;
+	uint r;
+
+	assert(tile < MapSize());
+
+	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) {
+		if (h != NULL) *h = 0;
+		return 0;
+	}
+
+	min = a = TileHeight(tile);
+	b = TileHeight(tile + TileDiffXY(1, 0));
+	if (min >= b) min = b;
+	c = TileHeight(tile + TileDiffXY(0, 1));
+	if (min >= c) min = c;
+	d = TileHeight(tile + TileDiffXY(1, 1));
+	if (min >= d) min = d;
+
+	r = SLOPE_FLAT;
+	if ((a -= min) != 0) r += (--a << 4) + SLOPE_N;
+	if ((c -= min) != 0) r += (--c << 4) + SLOPE_E;
+	if ((d -= min) != 0) r += (--d << 4) + SLOPE_S;
+	if ((b -= min) != 0) r += (--b << 4) + SLOPE_W;
+
+	if (h != NULL) *h = min * TILE_HEIGHT;
+
+	return r;
+}
+
+uint GetTileZ(TileIndex tile)
+{
+	uint h;
+	GetTileSlope(tile, &h);
+	return h;
+}
+
+
+uint GetTileMaxZ(TileIndex t)
+{
+	uint max;
+	uint h;
+
+	h = TileHeight(t);
+	max = h;
+	h = TileHeight(t + TileDiffXY(1, 0));
+	if (h > max) max = h;
+	h = TileHeight(t + TileDiffXY(0, 1));
+	if (h > max) max = h;
+	h = TileHeight(t + TileDiffXY(1, 1));
+	if (h > max) max = h;
+	return max * 8;
+}
deleted file mode 100644
--- a/src/town_cmd.c
+++ /dev/null
@@ -1,1965 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "strings.h"
-#include "road_map.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "map.h"
-#include "tile.h"
-#include "town_map.h"
-#include "tunnel_map.h"
-#include "viewport.h"
-#include "town.h"
-#include "command.h"
-#include "gfx.h"
-#include "industry.h"
-#include "station.h"
-#include "player.h"
-#include "news.h"
-#include "saveload.h"
-#include "economy.h"
-#include "gui.h"
-#include "unmovable_map.h"
-#include "water_map.h"
-#include "variables.h"
-#include "bridge.h"
-#include "bridge_map.h"
-#include "date.h"
-#include "table/town_land.h"
-#include "genworld.h"
-
-/**
- * Called if a new block is added to the town-pool
- */
-static void TownPoolNewBlock(uint start_item)
-{
-	Town *t;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (t = GetTown(start_item); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) t->index = start_item++;
-}
-
-/* Initialize the town-pool */
-DEFINE_OLD_POOL(Town, Town, TownPoolNewBlock, NULL)
-
-void DestroyTown(Town *t)
-{
-	Industry *i;
-	TileIndex tile;
-
-	/* Delete town authority window
-	 * and remove from list of sorted towns */
-	DeleteWindowById(WC_TOWN_VIEW, t->index);
-	_town_sort_dirty = true;
-	_total_towns--;
-
-	/* Delete all industries belonging to the town */
-	FOR_ALL_INDUSTRIES(i) if (i->town == t) DeleteIndustry(i);
-
-	/* Go through all tiles and delete those belonging to the town */
-	for (tile = 0; tile < MapSize(); ++tile) {
-		switch (GetTileType(tile)) {
-			case MP_HOUSE:
-				if (GetTownByTile(tile) == t) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-				break;
-
-			case MP_STREET:
-			case MP_TUNNELBRIDGE:
-				if (IsTileOwner(tile, OWNER_TOWN) &&
-						ClosestTownFromTile(tile, (uint)-1) == t)
-					DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-				break;
-
-			default:
-				break;
-		}
-	}
-
-	DeleteName(t->townnametype);
-	DeleteSubsidyWithTown(t->index);
-
-	MarkWholeScreenDirty();
-}
-
-// Local
-static int _grow_town_result;
-
-static bool BuildTownHouse(Town *t, TileIndex tile);
-static void ClearTownHouse(Town *t, TileIndex tile);
-static void DoBuildTownHouse(Town *t, TileIndex tile);
-
-static void TownDrawHouseLift(const TileInfo *ti)
-{
-	AddChildSpriteScreen(SPR_LIFT, 14, 60 - GetLiftPosition(ti->tile));
-}
-
-typedef void TownDrawTileProc(const TileInfo *ti);
-static TownDrawTileProc * const _town_draw_tile_procs[1] = {
-	TownDrawHouseLift
-};
-
-
-static void DrawTile_Town(TileInfo *ti)
-{
-	const DrawBuildingsTileStruct *dcts;
-	uint32 image;
-
-	/* Retrieve pointer to the draw town tile struct */
-	{
-		/* this "randomizes" on the (up to) 4 variants of a building */
-		uint variant;
-		variant  = ti->x >> 4;
-		variant ^= ti->x >> 6;
-		variant ^= ti->y >> 4;
-		variant -= ti->y >> 6;
-		variant &= 3;
-		dcts = &_town_draw_tile_data[GetHouseType(ti->tile) << 4 | variant << 2 | GetHouseBuildingStage(ti->tile)];
-	}
-
-	if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-	DrawGroundSprite(dcts->ground);
-
-	/* Add a house on top of the ground? */
-	image = dcts->building;
-	if (image != 0) {
-		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-		AddSortableSpriteToDraw(image,
-			ti->x + dcts->subtile_x,
-			ti->y + dcts->subtile_y,
-			dcts->width + 1,
-			dcts->height + 1,
-			dcts->dz,
-			ti->z
-		);
-
-		if (_display_opt & DO_TRANS_BUILDINGS) return;
-	}
-
-	{
-		int proc = dcts->draw_proc - 1;
-
-		if (proc >= 0) _town_draw_tile_procs[proc](ti);
-	}
-}
-
-static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
-{
-	return GetTileMaxZ(tile);
-}
-
-static Slope GetSlopeTileh_Town(TileIndex tile, Slope tileh)
-{
-	return SLOPE_FLAT;
-}
-
-static void AnimateTile_Town(TileIndex tile)
-{
-	int pos, dest;
-
-	if (_tick_counter & 3) return;
-
-	// If the house is not one with a lift anymore, then stop this animating.
-	// Not exactly sure when this happens, but probably when a house changes.
-	// Before this was just a return...so it'd leak animated tiles..
-	// That bug seems to have been here since day 1??
-	if (!(_housetype_extra_flags[GetHouseType(tile)] & 0x20)) {
-		DeleteAnimatedTile(tile);
-		return;
-	}
-
-	if (!IsLiftMoving(tile)) {
-		int i;
-
-		/** Building has 6 floors, number 0 .. 6, where 1 is illegal.
-		 *  This is due to the fact that the first floor is, in the graphics,
-		 *  the height of 2 'normal' floors.
-		 *  Furthermore, there are 6 lift positions from floor N (incl) to floor N + 1 (excl) */
-		do {
-			i = (Random() & 7) - 1;
-		} while (i < 0 || i == 1 || i * 6 == GetLiftPosition(tile));
-
-		SetLiftDestination(tile, i);
-	}
-
-	pos = GetLiftPosition(tile);
-	dest = GetLiftDestination(tile) * 6;
-	pos += (pos < dest) ? 1 : -1;
-	SetLiftPosition(tile, pos);
-
-	if (pos == dest) HaltLift(tile);
-
-	MarkTileDirtyByTile(tile);
-}
-
-static void UpdateTownRadius(Town *t);
-
-static bool IsCloseToTown(TileIndex tile, uint dist)
-{
-	const Town* t;
-
-	FOR_ALL_TOWNS(t) {
-		if (DistanceManhattan(tile, t->xy) < dist) return true;
-	}
-	return false;
-}
-
-static void MarkTownSignDirty(Town *t)
-{
-	MarkAllViewportsDirty(
-		t->sign.left-6,
-		t->sign.top-3,
-		t->sign.left+t->sign.width_1*4+12,
-		t->sign.top + 45
-	);
-}
-
-void UpdateTownVirtCoord(Town *t)
-{
-	Point pt;
-
-	MarkTownSignDirty(t);
-	pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE);
-	SetDParam(0, t->index);
-	SetDParam(1, t->population);
-	UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24,
-		_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL);
-	MarkTownSignDirty(t);
-}
-
-static void ChangePopulation(Town *t, int mod)
-{
-	t->population += mod;
-	InvalidateWindow(WC_TOWN_VIEW, t->index);
-	UpdateTownVirtCoord(t);
-
-	if (_town_sort_order & 2) _town_sort_dirty = true;
-}
-
-uint32 GetWorldPopulation(void)
-{
-	uint32 pop;
-	const Town* t;
-
-	pop = 0;
-	FOR_ALL_TOWNS(t) pop += t->population;
-	return pop;
-}
-
-static void MakeSingleHouseBigger(TileIndex tile)
-{
-	assert(IsTileType(tile, MP_HOUSE));
-
-	if (LiftHasDestination(tile)) return;
-
-	IncHouseConstructionTick(tile);
-	if (GetHouseConstructionTick(tile) != 0) return;
-
-	IncHouseBuildingStage(tile);  /*increase construction stage of one more step*/
-
-	if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED){
-		/*Now, construction is completed.  Can add population of building to the town*/
-		ChangePopulation(GetTownByTile(tile), _housetype_population[GetHouseType(tile)]);
-	}
-	MarkTileDirtyByTile(tile);
-}
-
-static void MakeTownHouseBigger(TileIndex tile)
-{
-	uint flags = _house_more_flags[GetHouseType(tile)];
-	if (flags & 8) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
-	if (flags & 4) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
-	if (flags & 2) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
-	if (flags & 1) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
-}
-
-static void TileLoop_Town(TileIndex tile)
-{
-	int house;
-	Town *t;
-	uint32 r;
-
-	if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
-		/*Construction is not completed. See if we can go further in construction*/
-		MakeTownHouseBigger(tile);
-		return;
-	}
-
-	house = GetHouseType(tile);
-	if ((_housetype_extra_flags[house] & 0x20) && !LiftHasDestination(tile) && CHANCE16(1, 2) && AddAnimatedTile(tile)) BeginLiftMovement(tile);
-
-	t = GetTownByTile(tile);
-
-	r = Random();
-
-	if (GB(r, 0, 8) < _housetype_population[house]) {
-		uint amt = GB(r, 0, 8) / 8 + 1;
-		uint moved;
-
-		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-		t->new_max_pass += amt;
-		moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
-		t->new_act_pass += moved;
-	}
-
-	if (GB(r, 8, 8) < _housetype_mailamount[house] ) {
-		uint amt = GB(r, 8, 8) / 8 + 1;
-		uint moved;
-
-		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-		t->new_max_mail += amt;
-		moved = MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt);
-		t->new_act_mail += moved;
-	}
-
-	if (_house_more_flags[house] & 8 && HASBIT(t->flags12, TOWN_IS_FUNDED) && --t->time_until_rebuild == 0) {
-		t->time_until_rebuild = GB(r, 16, 6) + 130;
-
-		_current_player = OWNER_TOWN;
-
-		ClearTownHouse(t, tile);
-
-		// rebuild with another house?
-		if (GB(r, 24, 8) >= 12) DoBuildTownHouse(t, tile);
-
-		_current_player = OWNER_NONE;
-	}
-}
-
-static void ClickTile_Town(TileIndex tile)
-{
-	/* not used */
-}
-
-static int32 ClearTile_Town(TileIndex tile, byte flags)
-{
-	int house, rating;
-	int32 cost;
-	Town *t;
-
-	// safety checks
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-	if (flags&DC_AUTO && !(flags&DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
-
-	house = GetHouseType(tile);
-	cost = _price.remove_house * _housetype_remove_cost[house] >> 8;
-
-	rating = _housetype_remove_ratingmod[house];
-	_cleared_town_rating += rating;
-	_cleared_town = t = GetTownByTile(tile);
-
-	if (IsValidPlayer(_current_player)) {
-		if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
-			SetDParam(0, t->index);
-			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM);
-		ClearTownHouse(t, tile);
-	}
-
-	return cost;
-}
-
-static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
-{
-	byte type = GetHouseType(tile);
-
-	ac[CT_PASSENGERS] = _housetype_cargo_passengers[type];
-	ac[CT_MAIL]       = _housetype_cargo_mail[type];
-	ac[CT_GOODS]      = _housetype_cargo_goods[type];
-	ac[CT_FOOD]       = _housetype_cargo_food[type];
-}
-
-static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
-{
-	td->str = _town_tile_names[GetHouseType(tile)];
-	if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
-		SetDParamX(td->dparam, 0, td->str);
-		td->str = STR_2058_UNDER_CONSTRUCTION;
-	}
-
-	td->owner = OWNER_TOWN;
-}
-
-static uint32 GetTileTrackStatus_Town(TileIndex tile, TransportType mode)
-{
-	/* not used */
-	return 0;
-}
-
-static void ChangeTileOwner_Town(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	/* not used */
-}
-
-
-static const TileIndexDiffC _roadblock_tileadd[] = {
-	{ 0, -1},
-	{ 1,  0},
-	{ 0,  1},
-	{-1,  0},
-
-	// Store the first 3 elements again.
-	// Lets us rotate without using &3.
-	{ 0, -1},
-	{ 1,  0},
-	{ 0,  1}
-};
-
-
-static bool GrowTown(Town *t);
-
-static void TownTickHandler(Town *t)
-{
-	if (HASBIT(t->flags12, TOWN_IS_FUNDED)) {
-		int i = t->grow_counter - 1;
-		if (i < 0) {
-			if (GrowTown(t)) {
-				i = t->growth_rate;
-			} else {
-				i = 0;
-			}
-		}
-		t->grow_counter = i;
-	}
-
-	UpdateTownRadius(t);
-}
-
-void OnTick_Town(void)
-{
-	if (_game_mode == GM_EDITOR) return;
-
-	/* Make sure each town's tickhandler invocation frequency is about the
-	 * same - TOWN_GROWTH_FREQUENCY - independent on the number of towns. */
-	for (_cur_town_iter += GetMaxTownIndex() + 1;
-	     _cur_town_iter >= TOWN_GROWTH_FREQUENCY;
-	     _cur_town_iter -= TOWN_GROWTH_FREQUENCY) {
-		uint32 i = _cur_town_ctr;
-
-		if (++_cur_town_ctr > GetMaxTownIndex())
-			_cur_town_ctr = 0;
-
-		if (IsValidTownID(i)) TownTickHandler(GetTown(i));
-	}
-}
-
-static RoadBits GetTownRoadMask(TileIndex tile)
-{
-	TrackBits b = GetAnyRoadTrackBits(tile);
-	RoadBits r = 0;
-
-	if (b & TRACK_BIT_X)     r |= ROAD_X;
-	if (b & TRACK_BIT_Y)     r |= ROAD_Y;
-	if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW;
-	if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW;
-	if (b & TRACK_BIT_LEFT)  r |= ROAD_NW | ROAD_SW;
-	if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE;
-	return r;
-}
-
-static bool IsRoadAllowedHere(TileIndex tile, int dir)
-{
-	Slope k;
-	Slope slope;
-
-	// If this assertion fails, it might be because the world contains
-	//  land at the edges. This is not ok.
-	TILE_ASSERT(tile);
-
-	for (;;) {
-		// Check if there already is a road at this point?
-		if (GetAnyRoadTrackBits(tile) == 0) {
-			// No, try to build one in the direction.
-			// if that fails clear the land, and if that fails exit.
-			// This is to make sure that we can build a road here later.
-			if (CmdFailed(DoCommand(tile, (dir & 1 ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
-					CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
-				return false;
-		}
-
-		slope = GetTileSlope(tile, NULL);
-		if (slope == SLOPE_FLAT) {
-no_slope:
-			// Tile has no slope
-			// Disallow the road if any neighboring tile has a road.
-			if (HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+1]))), dir^2) ||
-					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+3]))), dir^2) ||
-					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+1]) + ToTileIndexDiff(_roadblock_tileadd[dir+2]))), dir) ||
-					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+3]) + ToTileIndexDiff(_roadblock_tileadd[dir+2]))), dir))
-				return false;
-
-			// Otherwise allow
-			return true;
-		}
-
-		// If the tile is not a slope in the right direction, then
-		// maybe terraform some.
-		k = (dir & 1) ? SLOPE_NE : SLOPE_NW;
-		if (k != slope && ComplementSlope(k) != slope) {
-			uint32 r = Random();
-
-			if (CHANCE16I(1, 8, r) && !_generating_world) {
-				int32 res;
-
-				if (CHANCE16I(1, 16, r)) {
-					res = DoCommand(tile, slope, 0, DC_EXEC | DC_AUTO | DC_NO_WATER,
-					                      CMD_TERRAFORM_LAND);
-				} else {
-					res = DoCommand(tile, slope ^ 0xF, 1, DC_EXEC | DC_AUTO | DC_NO_WATER,
-					                      CMD_TERRAFORM_LAND);
-				}
-				if (CmdFailed(res) && CHANCE16I(1, 3, r)) {
-					// We can consider building on the slope, though.
-					goto no_slope;
-				}
-			}
-			return false;
-		}
-		return true;
-	}
-}
-
-static bool TerraformTownTile(TileIndex tile, int edges, int dir)
-{
-	int32 r;
-
-	TILE_ASSERT(tile);
-
-	r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
-	if (CmdFailed(r) || r >= 126 * 16) return false;
-	DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
-	return true;
-}
-
-static void LevelTownLand(TileIndex tile)
-{
-	Slope tileh;
-
-	TILE_ASSERT(tile);
-
-	// Don't terraform if land is plain or if there's a house there.
-	if (IsTileType(tile, MP_HOUSE)) return;
-	tileh = GetTileSlope(tile, NULL);
-	if (tileh == SLOPE_FLAT) return;
-
-	// First try up, then down
-	if (!TerraformTownTile(tile, ~tileh & 0xF, 1)) {
-		TerraformTownTile(tile, tileh & 0xF, 0);
-	}
-}
-
-static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1)
-{
-	RoadBits rcmd;
-	TileIndex tmptile;
-	DiagDirection i;
-	int j;
-	TileIndex tile = *tile_ptr;
-
-	TILE_ASSERT(tile);
-
-	if (mask == 0) {
-		int a;
-		int b;
-
-		// Tile has no road. First reset the status counter
-		// to say that this is the last iteration.
-		_grow_town_result = 0;
-
-		// Remove hills etc
-		LevelTownLand(tile);
-
-		// Is a road allowed here?
-		if (!IsRoadAllowedHere(tile, block)) return;
-
-		// Randomize new road block numbers
-		a = block;
-		b = block ^ 2;
-		if (CHANCE16(1, 4)) {
-			do {
-				a = GB(Random(), 0, 2);
-			} while (a == b);
-		}
-
-		if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) {
-			// A road is not allowed to continue the randomized road,
-			//   return if the road we're trying to build is curved.
-			if (a != (b ^ 2)) return;
-
-			// Return if neither side of the new road is a house
-			if (!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 1])), MP_HOUSE) &&
-					!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 3])), MP_HOUSE))
-				return;
-
-			// That means that the road is only allowed if there is a house
-			//  at any side of the new road.
-		}
-		rcmd = (1 << a) + (1 << b);
-
-	} else if (block < 5 && !HASBIT(mask,block^2)) {
-		// Continue building on a partial road.
-		// Always OK.
-		_grow_town_result = 0;
-		rcmd = 1 << (block ^ 2);
-	} else {
-		int i;
-
-		// Reached a tunnel/bridge? Then continue at the other side of it.
-		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-			if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) {
-				*tile_ptr = GetOtherTunnelEnd(tile);
-			} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD) {
-				*tile_ptr = GetOtherBridgeEnd(tile);
-			}
-			return;
-		}
-
-		// Possibly extend the road in a direction.
-		// Randomize a direction and if it has a road, bail out.
-		i = GB(Random(), 0, 2);
-		if (HASBIT(mask, i)) return;
-
-		// This is the tile we will reach if we extend to this direction.
-		tmptile = TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i]));
-
-		// Don't do it if it reaches to water.
-		if (IsClearWaterTile(tmptile)) return;
-
-		// Build a house at the edge. 60% chance or
-		//  always ok if no road allowed.
-		if (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10)) {
-			// But not if there already is a house there.
-			if (!IsTileType(tmptile, MP_HOUSE)) {
-				// Level the land if possible
-				LevelTownLand(tmptile);
-
-				// And build a house.
-				// Set result to -1 if we managed to build it.
-				if (BuildTownHouse(t1, tmptile)) _grow_town_result = -1;
-			}
-			return;
-		}
-
-		_grow_town_result = 0;
-		rcmd = 1 << i;
-	}
-
-	// Return if a water tile
-	if (IsClearWaterTile(tile)) return;
-
-	// Determine direction of slope,
-	//  and build a road if not a special slope.
-	switch (GetTileSlope(tile, NULL)) {
-		case SLOPE_SW: i = DIAGDIR_NE; break;
-		case SLOPE_SE: i = DIAGDIR_NW; break;
-		case SLOPE_NW: i = DIAGDIR_SE; break;
-		case SLOPE_NE: i = DIAGDIR_SW; break;
-
-		default:
-build_road_and_exit:
-			if (!CmdFailed(DoCommand(tile, rcmd, t1->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) {
-				_grow_town_result = -1;
-			}
-			return;
-	}
-
-	tmptile = tile;
-
-	// Now it contains the direction of the slope
-	j = -11; // max 11 tile long bridges
-	do {
-		if (++j == 0)
-			goto build_road_and_exit;
-		tmptile = TILE_MASK(tmptile + TileOffsByDiagDir(i));
-	} while (IsClearWaterTile(tmptile));
-
-	// no water tiles in between?
-	if (j == -10)
-		goto build_road_and_exit;
-
-	// Quit if it selecting an appropiate bridge type fails a large number of times.
-	j = 22;
-	{
-		int32 bridge_len = GetBridgeLength(tile, tmptile);
-		do {
-			byte bridge_type = RandomRange(MAX_BRIDGES - 1);
-			if (CheckBridge_Stuff(bridge_type, bridge_len)) {
-				if (!CmdFailed(DoCommand(tile, tmptile, 0x8000 + bridge_type, DC_EXEC | DC_AUTO, CMD_BUILD_BRIDGE)))
-					_grow_town_result = -1;
-
-				// obviously, if building any bridge would fail, there is no need to try other bridge-types
-				return;
-			}
-		} while (--j != 0);
-	}
-}
-
-// Returns true if a house was built, or no if the build failed.
-static int GrowTownAtRoad(Town *t, TileIndex tile)
-{
-	int block = 5; // special case
-
-	TILE_ASSERT(tile);
-
-	// Number of times to search.
-	_grow_town_result = 10 + t->num_houses * 4 / 9;
-
-	do {
-		// Get a bitmask of the road blocks on a tile
-		RoadBits mask = GetTownRoadMask(tile);
-
-		// Try to grow the town from this point
-		GrowTownInTile(&tile,mask,block,t);
-
-		// Exclude the source position from the bitmask
-		// and return if no more road blocks available
-		CLRBIT(mask, (block ^ 2));
-		if (mask == 0)
-			return _grow_town_result;
-
-		// Select a random bit from the blockmask, walk a step
-		// and continue the search from there.
-		do block = Random() & 3; while (!HASBIT(mask,block));
-		tile += ToTileIndexDiff(_roadblock_tileadd[block]);
-
-		if (IsTileType(tile, MP_STREET)) {
-			/* Don't allow building over roads of other cities */
-			if (IsTileOwner(tile, OWNER_TOWN) && GetTownByTile(tile) != t) {
-				_grow_town_result = -1;
-			} else if (_game_mode == GM_EDITOR) {
-				/* If we are in the SE, and this road-piece has no town owner yet, it just found an
-				 * owner :) (happy happy happy road now) */
-				SetTileOwner(tile, OWNER_TOWN);
-				SetTownIndex(tile, t->index);
-			}
-		}
-
-		// Max number of times is checked.
-	} while (--_grow_town_result >= 0);
-
-	return (_grow_town_result == -2);
-}
-
-// Generate a random road block
-// The probability of a straight road
-// is somewhat higher than a curved.
-static RoadBits GenRandomRoadBits(void)
-{
-	uint32 r = Random();
-	uint a = GB(r, 0, 2);
-	uint b = GB(r, 8, 2);
-	if (a == b) b ^= 2;
-	return (1 << a) + (1 << b);
-}
-
-// Grow the town
-// Returns true if a house was built, or no if the build failed.
-static bool GrowTown(Town *t)
-{
-	TileIndex tile;
-	const TileIndexDiffC *ptr;
-	PlayerID old_player;
-
-	static const TileIndexDiffC _town_coord_mod[] = {
-		{-1,  0},
-		{ 1,  1},
-		{ 1, -1},
-		{-1, -1},
-		{-1,  0},
-		{ 0,  2},
-		{ 2,  0},
-		{ 0, -2},
-		{-1, -1},
-		{-2,  2},
-		{ 2,  2},
-		{ 2, -2},
-		{ 0,  0}
-	};
-
-	// Current player is a town
-	old_player = _current_player;
-	_current_player = OWNER_TOWN;
-
-	// Find a road that we can base the construction on.
-	tile = t->xy;
-	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
-		if (GetAnyRoadTrackBits(tile) != 0) {
-			int r = GrowTownAtRoad(t, tile);
-			_current_player = old_player;
-			return r;
-		}
-		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
-	}
-
-	// No road available, try to build a random road block by
-	// clearing some land and then building a road there.
-	tile = t->xy;
-	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
-		/* Only work with plain land that not already has a house */
-		if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
-			if (!CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR))) {
-				DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
-				_current_player = old_player;
-				return true;
-			}
-		}
-		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
-	}
-
-	_current_player = old_player;
-	return false;
-}
-
-static void UpdateTownRadius(Town *t)
-{
-	static const uint16 _town_radius_data[23][5] = {
-		{  4,  0,  0,  0,  0}, // 0
-		{ 16,  0,  0,  0,  0},
-		{ 25,  0,  0,  0,  0},
-		{ 36,  0,  0,  0,  0},
-		{ 49,  0,  4,  0,  0},
-		{ 64,  0,  4,  0,  0}, // 20
-		{ 64,  0,  9,  0,  1},
-		{ 64,  0,  9,  0,  4},
-		{ 64,  0, 16,  0,  4},
-		{ 81,  0, 16,  0,  4},
-		{ 81,  0, 16,  0,  4}, // 40
-		{ 81,  0, 25,  0,  9},
-		{ 81, 36, 25,  0,  9},
-		{ 81, 36, 25, 16,  9},
-		{ 81, 49,  0, 25,  9},
-		{ 81, 64,  0, 25,  9}, // 60
-		{ 81, 64,  0, 36,  9},
-		{ 81, 64,  0, 36, 16},
-		{100, 81,  0, 49, 16},
-		{100, 81,  0, 49, 25},
-		{121, 81,  0, 49, 25}, // 80
-		{121, 81,  0, 49, 25},
-		{121, 81,  0, 49, 36}, // 88
-	};
-
-	if (t->num_houses < 92) {
-		memcpy(t->radius, _town_radius_data[t->num_houses / 4], sizeof(t->radius));
-	} else {
-		int mass = t->num_houses / 8;
-		// At least very roughly extrapolate. Empirical numbers dancing between
-		// overwhelming by cottages and skyscrapers outskirts.
-		t->radius[0] = mass * mass;
-		// Actually we are proportional to sqrt() but that's right because
-		// we are covering an area.
-		t->radius[1] = mass * 7;
-		t->radius[2] = 0;
-		t->radius[3] = mass * 4;
-		t->radius[4] = mass * 3;
-		//debug("%d (->%d): %d %d %d %d\n", t->num_houses, mass, t->radius[0], t->radius[1], t->radius[3], t->radius[4]);
-	}
-}
-
-static bool CreateTownName(uint32 *townnameparts)
-{
-	Town *t2;
-	char buf1[64];
-	char buf2[64];
-	uint32 r;
-	/* Do not set too low tries, since when we run out of names, we loop
-	 * for #tries only one time anyway - then we stop generating more
-	 * towns. Do not show it too high neither, since looping through all
-	 * the other towns may take considerable amount of time (10000 is
-	 * too much). */
-	int tries = 1000;
-	uint16 townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
-
-	assert(townnameparts);
-
-	for (;;) {
-restart:
-		r = Random();
-
-		SetDParam(0, r);
-		GetString(buf1, townnametype, lastof(buf1));
-
-		// Check size and width
-		if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue;
-
-		FOR_ALL_TOWNS(t2) {
-			// We can't just compare the numbers since
-			// several numbers may map to a single name.
-			SetDParam(0, t2->index);
-			GetString(buf2, STR_TOWN, lastof(buf2));
-			if (strcmp(buf1, buf2) == 0) {
-				if (tries-- < 0) return false;
-				goto restart;
-			}
-		}
-		*townnameparts = r;
-		return true;
-	}
-}
-
-void UpdateTownMaxPass(Town *t)
-{
-	t->max_pass = t->population >> 3;
-	t->max_mail = t->population >> 4;
-}
-
-static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, uint size_mode)
-{
-	int x, i;
-
-	// clear the town struct
-	i = t->index;
-	memset(t, 0, sizeof(Town));
-	t->index = i;
-	_total_towns++;
-
-	t->xy = tile;
-	t->num_houses = 0;
-	t->time_until_rebuild = 10;
-	UpdateTownRadius(t);
-	t->flags12 = 0;
-	t->population = 0;
-	t->grow_counter = 0;
-	t->growth_rate = 250;
-	t->new_max_pass = 0;
-	t->new_max_mail = 0;
-	t->new_act_pass = 0;
-	t->new_act_mail = 0;
-	t->max_pass = 0;
-	t->max_mail = 0;
-	t->act_pass = 0;
-	t->act_mail = 0;
-
-	t->pct_pass_transported = 0;
-	t->pct_mail_transported = 0;
-	t->fund_buildings_months = 0;
-	t->new_act_food = 0;
-	t->new_act_water = 0;
-	t->act_food = 0;
-	t->act_water = 0;
-
-	for (i = 0; i != MAX_PLAYERS; i++)
-		t->ratings[i] = 500;
-
-	t->have_ratings = 0;
-	t->exclusivity = (byte)-1;
-	t->exclusive_counter = 0;
-	t->statues = 0;
-
-	t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
-	t->townnameparts = townnameparts;
-
-	UpdateTownVirtCoord(t);
-	_town_sort_dirty = true;
-
-	if (size_mode == 0) {
-		x = (Random() & 0xF) + 8;
-	} else {
-		x = (size_mode - 1) * 16 + 3;
-	}
-
-	t->num_houses += x;
-	UpdateTownRadius(t);
-
-	i = x * 4;
-	do {
-		GrowTown(t);
-	} while (--i);
-
-	t->num_houses -= x;
-	UpdateTownRadius(t);
-	UpdateTownMaxPass(t);
-}
-
-static Town *AllocateTown(void)
-{
-	Town *t;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (t = GetTown(0); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) {
-		if (!IsValidTown(t)) {
-			TownID index = t->index;
-
-			memset(t, 0, sizeof(Town));
-			t->index = index;
-
-			return t;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Town_pool))
-		return AllocateTown();
-
-	return NULL;
-}
-
-/** Create a new town.
- * This obviously only works in the scenario editor. Function not removed
- * as it might be possible in the future to fund your own town :)
- * @param tile coordinates where town is built
- * @param p1 size of the town (0 = random, 1 = small, 2 = medium, 3 = large)
- * @param p2 unused
- */
-int32 CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Town *t;
-	uint32 townnameparts;
-
-	/* Only in the scenario editor */
-	if (_game_mode != GM_EDITOR) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-
-	// Check if too close to the edge of map
-	if (DistanceFromEdge(tile) < 12)
-		return_cmd_error(STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP);
-
-	// Can only build on clear flat areas, possibly with trees.
-	if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
-		return_cmd_error(STR_0239_SITE_UNSUITABLE);
-	}
-
-	// Check distance to all other towns.
-	if (IsCloseToTown(tile, 20))
-		return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN);
-
-	// Get a unique name for the town.
-	if (!CreateTownName(&townnameparts))
-		return_cmd_error(STR_023A_TOO_MANY_TOWNS);
-
-	// Allocate town struct
-	t = AllocateTown();
-	if (t == NULL) return_cmd_error(STR_023A_TOO_MANY_TOWNS);
-
-	// Create the town
-	if (flags & DC_EXEC) {
-		_generating_world = true;
-		DoCreateTown(t, tile, townnameparts, p1);
-		_generating_world = false;
-	}
-	return 0;
-}
-
-Town *CreateRandomTown(uint attempts, uint size_mode)
-{
-	TileIndex tile;
-	Town *t;
-	uint32 townnameparts;
-
-	do {
-		// Generate a tile index not too close from the edge
-		tile = RandomTile();
-		if (DistanceFromEdge(tile) < 20) continue;
-
-		// Make sure the tile is plain
-		if (!IsTileType(tile, MP_CLEAR) || GetTileSlope(tile, NULL) != SLOPE_FLAT) continue;
-
-		// Check not too close to a town
-		if (IsCloseToTown(tile, 20)) continue;
-
-		// Get a unique name for the town.
-		if (!CreateTownName(&townnameparts)) break;
-
-		// Allocate a town struct
-		t = AllocateTown();
-		if (t == NULL) break;
-
-		DoCreateTown(t, tile, townnameparts, size_mode);
-		return t;
-	} while (--attempts);
-	return NULL;
-}
-
-static const byte _num_initial_towns[3] = {11, 23, 46};
-
-bool GenerateTowns(void)
-{
-	uint num = 0;
-	uint n = ScaleByMapSize(_num_initial_towns[_opt.diff.number_towns] + (Random() & 7));
-
-	SetGeneratingWorldProgress(GWP_TOWN, n);
-
-	do {
-		IncreaseGeneratingWorldProgress(GWP_TOWN);
-		// try 20 times to create a random-sized town for the first loop.
-		if (CreateRandomTown(20, 0) != NULL) num++;
-	} while (--n);
-
-	// give it a last try, but now more aggressive
-	if (num == 0 && CreateRandomTown(10000, 0) == NULL) {
-		if (GetNumTowns() == 0) {
-			/* XXX - can we handle that more gracefully? */
-			if (_game_mode != GM_EDITOR) error("Could not generate any town");
-
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static bool CheckBuildHouseMode(TileIndex tile, Slope tileh, int mode)
-{
-	int b;
-	Slope slope;
-
-	static const byte _masks[8] = {
-		0xC,0x3,0x9,0x6,
-		0x3,0xC,0x6,0x9,
-	};
-
-	slope = GetTileSlope(tile, NULL);
-	if (IsSteepSlope(slope)) return false;
-
-	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
-
-	b = 0;
-	if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
-	if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b;
-	if (b)
-		return false;
-
-	return !CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
-}
-
-
-uint GetTownRadiusGroup(const Town* t, TileIndex tile)
-{
-	uint dist = DistanceSquare(tile, t->xy);
-	uint smallest;
-	uint i;
-
-	if (t->fund_buildings_months && dist <= 25) return 4;
-
-	smallest = 0;
-	for (i = 0; i != lengthof(t->radius); i++) {
-		if (dist < t->radius[i]) smallest = i;
-	}
-
-	return smallest;
-}
-
-static bool CheckFree2x2Area(TileIndex tile)
-{
-	int i;
-
-	static const TileIndexDiffC _tile_add[] = {
-		{0    , 0    },
-		{0 - 0, 1 - 0},
-		{1 - 0, 0 - 1},
-		{1 - 1, 1 - 0}
-	};
-
-	for (i = 0; i != 4; i++) {
-		tile += ToTileIndexDiff(_tile_add[i]);
-
-		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
-
-		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
-
-		if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
-			return false;
-	}
-
-	return true;
-}
-
-static void DoBuildTownHouse(Town *t, TileIndex tile)
-{
-	int i;
-	uint bitmask;
-	int house;
-	Slope slope;
-	uint z;
-	uint oneof = 0;
-
-	// Above snow?
-	slope = GetTileSlope(tile, &z);
-
-	// Get the town zone type
-	{
-		uint rad = GetTownRadiusGroup(t, tile);
-
-		int land = _opt.landscape;
-		if (land == LT_HILLY && z >= _opt.snow_line) land = -1;
-
-		bitmask = (1 << rad) + (1 << (land + 12));
-	}
-
-	// bits 0-4 are used
-	// bits 11-15 are used
-	// bits 5-10 are not used.
-	{
-		byte houses[lengthof(_housetype_flags)];
-		int num = 0;
-
-		// Generate a list of all possible houses that can be built.
-		for (i=0; i!=lengthof(_housetype_flags); i++) {
-			if ((~_housetype_flags[i] & bitmask) == 0)
-				houses[num++] = (byte)i;
-		}
-
-		for (;;) {
-			house = houses[RandomRange(num)];
-
-			if (_cur_year < _housetype_years[house].min || _cur_year > _housetype_years[house].max)
-				continue;
-
-			// Special houses that there can be only one of.
-			switch (house) {
-				case HOUSE_TEMP_CHURCH:
-				case HOUSE_ARCT_CHURCH:
-				case HOUSE_SNOW_CHURCH:
-				case HOUSE_TROP_CHURCH:
-				case HOUSE_TOY_CHURCH:
-					SETBIT(oneof, TOWN_HAS_CHURCH);
-					break;
-				case HOUSE_STADIUM:
-				case HOUSE_MODERN_STADIUM:
-					SETBIT(oneof, TOWN_HAS_STADIUM);
-					break;
-				default:
-					oneof = 0;
-					break;
-			}
-
-			if (HASBITS(t->flags12 , oneof)) continue;
-
-			// Make sure there is no slope?
-			if (_housetype_extra_flags[house] & 0x12 && slope != SLOPE_FLAT) continue;
-
-			if (_housetype_extra_flags[house] & 0x10) {
-				if (CheckFree2x2Area(tile) ||
-						CheckFree2x2Area(tile += TileDiffXY(-1,  0)) ||
-						CheckFree2x2Area(tile += TileDiffXY( 0, -1)) ||
-						CheckFree2x2Area(tile += TileDiffXY( 1,  0))) {
-					break;
-				}
-				tile += TileDiffXY(0, 1);
-			} else if (_housetype_extra_flags[house] & 4) {
-				if (CheckBuildHouseMode(tile + TileDiffXY(1, 0), slope, 0)) break;
-
-				if (CheckBuildHouseMode(tile + TileDiffXY(-1, 0), slope, 1)) {
-					tile += TileDiffXY(-1, 0);
-					break;
-				}
-			} else if (_housetype_extra_flags[house] & 8) {
-				if (CheckBuildHouseMode(tile + TileDiffXY(0, 1), slope, 2)) break;
-
-				if (CheckBuildHouseMode(tile + TileDiffXY(0, -1), slope, 3)) {
-					tile += TileDiffXY(0, -1);
-					break;
-				}
-			} else {
-				break;
-			}
-		}
-	}
-
-	t->num_houses++;
-
-	// Special houses that there can be only one of.
-	t->flags12 |= oneof;
-
-	{
-		byte construction_counter = 0, construction_stage = 0, size_flags;
-
-		if (_generating_world) {
-			uint32 r = Random();
-
-			construction_stage = TOWN_HOUSE_COMPLETED;
-			if (CHANCE16(1, 7)) construction_stage = GB(r, 0, 2);
-
-			if (construction_stage == TOWN_HOUSE_COMPLETED) {
-				ChangePopulation(t, _housetype_population[house]);
-			} else {
-				construction_counter = GB(r, 2, 2);
-			}
-		}
-		size_flags = GB(_housetype_extra_flags[house], 2, 3);
-		MakeTownHouse(tile, t->index, construction_counter, construction_stage, size_flags, house);
-	}
-}
-
-static bool BuildTownHouse(Town *t, TileIndex tile)
-{
-	int32 r;
-
-	// make sure it's possible
-	if (!EnsureNoVehicle(tile)) return false;
-	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
-	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
-
-	r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(r)) return false;
-
-	DoBuildTownHouse(t, tile);
-	return true;
-}
-
-
-static void DoClearTownHouseHelper(TileIndex tile)
-{
-	assert(IsTileType(tile, MP_HOUSE));
-	DoClearSquare(tile);
-	DeleteAnimatedTile(tile);
-}
-
-static void ClearTownHouse(Town *t, TileIndex tile)
-{
-	uint house = GetHouseType(tile);
-	uint eflags;
-
-	assert(IsTileType(tile, MP_HOUSE));
-
-	// need to align the tile to point to the upper left corner of the house
-	if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
-		if (_housetype_extra_flags[house-1] & 0x04) {
-			house--;
-			tile += TileDiffXY(-1, 0);
-		} else if (_housetype_extra_flags[house-1] & 0x18) {
-			house--;
-			tile += TileDiffXY(0, -1);
-		} else if (_housetype_extra_flags[house-2] & 0x10) {
-			house-=2;
-			tile += TileDiffXY(-1, 0);
-		} else if (_housetype_extra_flags[house-3] & 0x10) {
-			house-=3;
-			tile += TileDiffXY(-1, -1);
-		}
-	}
-
-	// Remove population from the town if the house is finished.
-	if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED) {
-		ChangePopulation(t, -_housetype_population[house]);
-	}
-
-	t->num_houses--;
-
-	// Clear flags for houses that only may exist once/town.
-	switch (house) {
-		case HOUSE_TEMP_CHURCH:
-		case HOUSE_ARCT_CHURCH:
-		case HOUSE_SNOW_CHURCH:
-		case HOUSE_TROP_CHURCH:
-		case HOUSE_TOY_CHURCH:
-			CLRBIT(t->flags12, TOWN_HAS_CHURCH);
-			break;
-		case HOUSE_STADIUM:
-		case HOUSE_MODERN_STADIUM:
-			CLRBIT(t->flags12, TOWN_HAS_STADIUM);
-			break;
-		default:
-			break;
-	}
-
-	// Do the actual clearing of tiles
-	eflags = _housetype_extra_flags[house];
-	DoClearTownHouseHelper(tile);
-	if (eflags & 0x14) DoClearTownHouseHelper(tile + TileDiffXY(1, 0));
-	if (eflags & 0x18) DoClearTownHouseHelper(tile + TileDiffXY(0, 1));
-	if (eflags & 0x10) DoClearTownHouseHelper(tile + TileDiffXY(1, 1));
-}
-
-/** Rename a town (server-only).
- * @param tile unused
- * @param p1 town ID to rename
- * @param p2 unused
- */
-int32 CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID str;
-	Town *t;
-
-	if (!IsValidTownID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
-
-	t = GetTown(p1);
-
-	str = AllocateNameUnique(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		DeleteName(t->townnametype);
-		t->townnametype = str;
-
-		UpdateTownVirtCoord(t);
-		_town_sort_dirty = true;
-		UpdateAllStationVirtCoord();
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-	return 0;
-}
-
-// Called from GUI
-void ExpandTown(Town *t)
-{
-	int amount, n;
-
-	_generating_world = true;
-
-	/* The more houses, the faster we grow */
-	amount = RandomRange(t->num_houses / 10) + 3;
-	t->num_houses += amount;
-	UpdateTownRadius(t);
-
-	n = amount * 10;
-	do GrowTown(t); while (--n);
-
-	t->num_houses -= amount;
-	UpdateTownRadius(t);
-
-	UpdateTownMaxPass(t);
-	_generating_world = false;
-}
-
-const byte _town_action_costs[8] = {
-	2, 4, 9, 35, 48, 53, 117, 175
-};
-
-static void TownActionAdvertiseSmall(Town* t)
-{
-	ModifyStationRatingAround(t->xy, _current_player, 0x40, 10);
-}
-
-static void TownActionAdvertiseMedium(Town* t)
-{
-	ModifyStationRatingAround(t->xy, _current_player, 0x70, 15);
-}
-
-static void TownActionAdvertiseLarge(Town* t)
-{
-	ModifyStationRatingAround(t->xy, _current_player, 0xA0, 20);
-}
-
-static void TownActionRoadRebuild(Town* t)
-{
-	const Player* p;
-
-	t->road_build_months = 6;
-
-	SetDParam(0, t->index);
-
-	p = GetPlayer(_current_player);
-	SetDParam(1, p->name_1);
-	SetDParam(2, p->name_2);
-
-	AddNewsItem(STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING,
-		NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_GENERAL, 0), t->xy, 0);
-}
-
-static bool DoBuildStatueOfCompany(TileIndex tile)
-{
-	PlayerID old;
-	int32 r;
-
-	if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
-
-	if (!IsTileType(tile, MP_HOUSE) &&
-			!IsTileType(tile, MP_CLEAR) &&
-			!IsTileType(tile, MP_TREES)) {
-		return false;
-	}
-
-	old = _current_player;
-	_current_player = OWNER_NONE;
-	r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-	_current_player = old;
-
-	if (CmdFailed(r)) return false;
-
-	MakeStatue(tile, _current_player);
-	MarkTileDirtyByTile(tile);
-
-	return true;
-}
-
-/**
- * Search callback function for TownActionBuildStatue
- * @param data that is passed by the caller.  In this case, nothing
- * @result of the test
- */
-static bool SearchTileForStatue(TileIndex tile, uint32 data)
-{
-	return DoBuildStatueOfCompany(tile);
-}
-
-/**
- * Perform a 9x9 tiles circular search from the center of the town
- * in order to find a free tile to place a statue
- * @param t town to search in
- */
-static void TownActionBuildStatue(Town* t)
-{
-	TileIndex tile = t->xy;
-
-	if (CircularTileSearch(tile, 9, SearchTileForStatue, 0))
-		SETBIT(t->statues, _current_player); ///< Once found and built, "inform" the Town
-}
-
-static void TownActionFundBuildings(Town* t)
-{
-	// Build next tick
-	t->grow_counter = 1;
-	// If we were not already growing
-	SETBIT(t->flags12, TOWN_IS_FUNDED);
-	// And grow for 3 months
-	t->fund_buildings_months = 3;
-}
-
-static void TownActionBuyRights(Town* t)
-{
-	t->exclusive_counter = 12;
-	t->exclusivity = _current_player;
-
-	ModifyStationRatingAround(t->xy, _current_player, 130, 17);
-}
-
-static void TownActionBribe(Town* t)
-{
-	if (!RandomRange(15)) {
-		Station *st;
-
-		// set as unwanted for 6 months
-		t->unwanted[_current_player] = 6;
-
-		// set all close by station ratings to 0
-		FOR_ALL_STATIONS(st) {
-			if (st->town == t && st->owner == _current_player) {
-				uint i;
-
-				for (i = 0; i != NUM_CARGO; i++) st->goods[i].rating = 0;
-			}
-		}
-
-		// only show errormessage to the executing player. All errors are handled command.c
-		// but this is special, because it can only 'fail' on a DC_EXEC
-		if (IsLocalPlayer()) ShowErrorMessage(STR_BRIBE_FAILED_2, STR_BRIBE_FAILED, 0, 0);
-
-		/* decrease by a lot!
-		 * ChangeTownRating is only for stuff in demolishing. Bribe failure should
-		 * be independent of any cheat settings
-		 */
-		if (t->ratings[_current_player] > RATING_BRIBE_DOWN_TO) {
-			t->ratings[_current_player] = RATING_BRIBE_DOWN_TO;
-		}
-	} else {
-		ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM);
-	}
-}
-
-typedef void TownActionProc(Town* t);
-static TownActionProc * const _town_action_proc[] = {
-	TownActionAdvertiseSmall,
-	TownActionAdvertiseMedium,
-	TownActionAdvertiseLarge,
-	TownActionRoadRebuild,
-	TownActionBuildStatue,
-	TownActionFundBuildings,
-	TownActionBuyRights,
-	TownActionBribe
-};
-
-extern uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t);
-
-/** Do a town action.
- * This performs an action such as advertising, building a statue, funding buildings,
- * but also bribing the town-council
- * @param tile unused
- * @param p1 town to do the action at
- * @param p2 action to perform, @see _town_action_proc for the list of available actions
- */
-int32 CmdDoTownAction(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost;
-	Town *t;
-
-	if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR;
-
-	t = GetTown(p1);
-
-	if (!HASBIT(GetMaskOfTownActions(NULL, _current_player, t), p2)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-
-	cost = (_price.build_industry >> 8) * _town_action_costs[p2];
-
-	if (flags & DC_EXEC) {
-		_town_action_proc[p2](t);
-		InvalidateWindow(WC_TOWN_AUTHORITY, p1);
-	}
-
-	return cost;
-}
-
-static void UpdateTownGrowRate(Town *t)
-{
-	int n;
-	Station *st;
-	byte m;
-	Player *p;
-
-	// Reset player ratings if they're low
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active && t->ratings[p->index] <= 200) {
-			t->ratings[p->index] += 5;
-		}
-	}
-
-	n = 0;
-	FOR_ALL_STATIONS(st) {
-		if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) {
-			if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
-				n++;
-				if (IsValidPlayer(st->owner) && t->ratings[st->owner] <= 1000-12)
-					t->ratings[st->owner] += 12;
-			} else {
-				if (IsValidPlayer(st->owner) && t->ratings[st->owner] >= -1000+15)
-					t->ratings[st->owner] -= 15;
-			}
-		}
-	}
-
-	CLRBIT(t->flags12, TOWN_IS_FUNDED);
-
-	if (t->fund_buildings_months != 0) {
-		static const byte _grow_count_values[6] = {
-			60, 60, 60, 50, 40, 30
-		};
-		m = _grow_count_values[min(n, 5)];
-		t->fund_buildings_months--;
-	} else if (n == 0) {
-		m = 160;
-		if (!CHANCE16(1, 12))
-			return;
-	} else {
-		static const byte _grow_count_values[5] = {
-			210, 150, 110, 80, 50
-		};
-		m = _grow_count_values[min(n, 5) - 1];
-	}
-
-	if (_opt.landscape == LT_HILLY) {
-		if (TilePixelHeight(t->xy) >= _opt.snow_line && t->act_food == 0 && t->population > 90)
-			return;
-	} else if (_opt.landscape == LT_DESERT) {
-		if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food==0 || t->act_water==0) && t->population > 60)
-			return;
-	}
-
-	t->growth_rate = m / (t->num_houses / 50 + 1);
-	if (m <= t->grow_counter)
-		t->grow_counter = m;
-
-	SETBIT(t->flags12, TOWN_IS_FUNDED);
-}
-
-static void UpdateTownAmounts(Town *t)
-{
-	// Using +1 here to prevent overflow and division by zero
-	t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
-
-	t->max_pass = t->new_max_pass; t->new_max_pass = 0;
-	t->act_pass = t->new_act_pass; t->new_act_pass = 0;
-	t->act_food = t->new_act_food; t->new_act_food = 0;
-	t->act_water = t->new_act_water; t->new_act_water = 0;
-
-	// Using +1 here to prevent overflow and division by zero
-	t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
-	t->max_mail = t->new_max_mail; t->new_max_mail = 0;
-	t->act_mail = t->new_act_mail; t->new_act_mail = 0;
-
-	InvalidateWindow(WC_TOWN_VIEW, t->index);
-}
-
-static void UpdateTownUnwanted(Town *t)
-{
-	const Player* p;
-
-	FOR_ALL_PLAYERS(p) {
-		if (t->unwanted[p->index] > 0) t->unwanted[p->index]--;
-	}
-}
-
-bool CheckIfAuthorityAllows(TileIndex tile)
-{
-	Town *t;
-
-	if (!IsValidPlayer(_current_player)) return true;
-
-	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-	if (t == NULL) return true;
-
-	if (t->ratings[_current_player] > -200) return true;
-
-	_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
-	SetDParam(0, t->index);
-
-	return false;
-}
-
-
-Town* CalcClosestTownFromTile(TileIndex tile, uint threshold)
-{
-	Town *t;
-	uint dist, best = threshold;
-	Town *best_town = NULL;
-
-	FOR_ALL_TOWNS(t) {
-		dist = DistanceManhattan(tile, t->xy);
-		if (dist < best) {
-			best = dist;
-			best_town = t;
-		}
-	}
-
-	return best_town;
-}
-
-
-Town *ClosestTownFromTile(TileIndex tile, uint threshold)
-{
-	if (IsTileType(tile, MP_HOUSE) || (
-				IsTileType(tile, MP_STREET) &&
-				(IsLevelCrossing(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile)) == OWNER_TOWN
-			)) {
-		return GetTownByTile(tile);
-	} else {
-		return CalcClosestTownFromTile(tile, threshold);
-	}
-}
-
-
-void ChangeTownRating(Town *t, int add, int max)
-{
-	int rating;
-
-	// if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff
-	if (t == NULL ||
-			!IsValidPlayer(_current_player) ||
-			(_cheats.magic_bulldozer.value && add < 0)) {
-		return;
-	}
-
-	SETBIT(t->have_ratings, _current_player);
-
-	rating = t->ratings[_current_player];
-
-	if (add < 0) {
-		if (rating > max) {
-			rating += add;
-			if (rating < max) rating = max;
-		}
-	} else {
-		if (rating < max) {
-			rating += add;
-			if (rating > max) rating = max;
-		}
-	}
-	t->ratings[_current_player] = rating;
-}
-
-/* penalty for removing town-owned stuff */
-static const int _default_rating_settings [3][3] = {
-	// ROAD_REMOVE, TUNNELBRIDGE_REMOVE, INDUSTRY_REMOVE
-	{  0, 128, 384}, // Permissive
-	{ 48, 192, 480}, // Neutral
-	{ 96, 384, 768}, // Hostile
-};
-
-bool CheckforTownRating(uint32 flags, Town *t, byte type)
-{
-	int modemod;
-
-	// if magic_bulldozer cheat is active, town doesn't restrict your destructive actions
-	if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value)
-		return true;
-
-	/* check if you're allowed to remove the street/bridge/tunnel/industry
-	 * owned by a town no removal if rating is lower than ... depends now on
-	 * difficulty setting. Minimum town rating selected by difficulty level
-	 */
-	modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type];
-
-	if (t->ratings[_current_player] < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) {
-		SetDParam(0, t->index);
-		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
-		return false;
-	}
-
-	return true;
-}
-
-void TownsMonthlyLoop(void)
-{
-	Town *t;
-
-	FOR_ALL_TOWNS(t) {
-		if (t->road_build_months != 0) t->road_build_months--;
-
-		if (t->exclusive_counter != 0)
-			if (--t->exclusive_counter == 0) t->exclusivity = (byte)-1;
-
-		UpdateTownGrowRate(t);
-		UpdateTownAmounts(t);
-		UpdateTownUnwanted(t);
-	}
-}
-
-void InitializeTowns(void)
-{
-	Subsidy *s;
-
-	/* Clean the town pool and create 1 block in it */
-	CleanPool(&_Town_pool);
-	AddBlockToPool(&_Town_pool);
-
-	memset(_subsidies, 0, sizeof(_subsidies));
-	for (s=_subsidies; s != endof(_subsidies); s++)
-		s->cargo_type = CT_INVALID;
-
-	_cur_town_ctr = 0;
-	_cur_town_iter = 0;
-	_total_towns = 0;
-	_town_sort_dirty = true;
-}
-
-const TileTypeProcs _tile_type_town_procs = {
-	DrawTile_Town,           /* draw_tile_proc */
-	GetSlopeZ_Town,          /* get_slope_z_proc */
-	ClearTile_Town,          /* clear_tile_proc */
-	GetAcceptedCargo_Town,   /* get_accepted_cargo_proc */
-	GetTileDesc_Town,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Town, /* get_tile_track_status_proc */
-	ClickTile_Town,          /* click_tile_proc */
-	AnimateTile_Town,        /* animate_tile_proc */
-	TileLoop_Town,           /* tile_loop_clear */
-	ChangeTileOwner_Town,    /* change_tile_owner_clear */
-	NULL,                    /* get_produced_cargo_proc */
-	NULL,                    /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Town,      /* get_slope_tileh_proc */
-};
-
-
-// Save and load of towns.
-static const SaveLoad _town_desc[] = {
-	SLE_CONDVAR(Town, xy,                    SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
-	SLE_CONDVAR(Town, xy,                    SLE_UINT32,                 6, SL_MAX_VERSION),
-
-	SLE_CONDVAR(Town, population,            SLE_FILE_U16 | SLE_VAR_U32, 0, 2),
-	SLE_CONDVAR(Town, population,            SLE_UINT32,                 3, SL_MAX_VERSION),
-
-
-	    SLE_VAR(Town, num_houses,            SLE_UINT16),
-	    SLE_VAR(Town, townnametype,          SLE_UINT16),
-	    SLE_VAR(Town, townnameparts,         SLE_UINT32),
-
-	    SLE_VAR(Town, flags12,               SLE_UINT8),
-	    SLE_VAR(Town, statues,               SLE_UINT8),
-
-	// sort_index_obsolete was stored here in savegame format 0 - 1
-	SLE_CONDNULL(1, 0, 1),
-
-	    SLE_VAR(Town, have_ratings,          SLE_UINT8),
-	    SLE_ARR(Town, ratings,               SLE_INT16, 8),
-	// failed bribe attempts are stored since savegame format 4
-	SLE_CONDARR(Town, unwanted,              SLE_INT8, 8, 4,SL_MAX_VERSION),
-
-	SLE_CONDVAR(Town, max_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, max_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, new_max_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, new_max_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, act_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, act_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, new_act_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-	SLE_CONDVAR(Town, new_act_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
-
-	SLE_CONDVAR(Town, max_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, max_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, new_max_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, new_max_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, act_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, act_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, new_act_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
-	SLE_CONDVAR(Town, new_act_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
-
-	    SLE_VAR(Town, pct_pass_transported,  SLE_UINT8),
-	    SLE_VAR(Town, pct_mail_transported,  SLE_UINT8),
-
-	    SLE_VAR(Town, act_food,              SLE_UINT16),
-	    SLE_VAR(Town, act_water,             SLE_UINT16),
-	    SLE_VAR(Town, new_act_food,          SLE_UINT16),
-	    SLE_VAR(Town, new_act_water,         SLE_UINT16),
-
-	    SLE_VAR(Town, time_until_rebuild,    SLE_UINT8),
-	    SLE_VAR(Town, grow_counter,          SLE_UINT8),
-	    SLE_VAR(Town, growth_rate,           SLE_UINT8),
-	    SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
-	    SLE_VAR(Town, road_build_months,     SLE_UINT8),
-
-	    SLE_VAR(Town, exclusivity,           SLE_UINT8),
-	    SLE_VAR(Town, exclusive_counter,     SLE_UINT8),
-	// reserve extra space in savegame here. (currently 30 bytes)
-	SLE_CONDNULL(30, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static void Save_TOWN(void)
-{
-	Town *t;
-
-	FOR_ALL_TOWNS(t) {
-		SlSetArrayIndex(t->index);
-		SlObject(t, _town_desc);
-	}
-}
-
-static void Load_TOWN(void)
-{
-	int index;
-
-	_total_towns = 0;
-
-	while ((index = SlIterateArray()) != -1) {
-		Town *t;
-
-		if (!AddBlockIfNeeded(&_Town_pool, index))
-			error("Towns: failed loading savegame: too many towns");
-
-		t = GetTown(index);
-		SlObject(t, _town_desc);
-
-		_total_towns++;
-	}
-
-	/* This is to ensure all pointers are within the limits of
-	 *  the size of the TownPool */
-	if (_cur_town_ctr > GetMaxTownIndex())
-		_cur_town_ctr = 0;
-}
-
-void AfterLoadTown(void)
-{
-	Town *t;
-	FOR_ALL_TOWNS(t) {
-		UpdateTownRadius(t);
-		UpdateTownVirtCoord(t);
-	}
-	_town_sort_dirty = true;
-}
-
-
-const ChunkHandler _town_chunk_handlers[] = {
-	{ 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/town_cmd.cpp
@@ -0,0 +1,1965 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "strings.h"
+#include "road_map.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "map.h"
+#include "tile.h"
+#include "town_map.h"
+#include "tunnel_map.h"
+#include "viewport.h"
+#include "town.h"
+#include "command.h"
+#include "gfx.h"
+#include "industry.h"
+#include "station.h"
+#include "player.h"
+#include "news.h"
+#include "saveload.h"
+#include "economy.h"
+#include "gui.h"
+#include "unmovable_map.h"
+#include "water_map.h"
+#include "variables.h"
+#include "bridge.h"
+#include "bridge_map.h"
+#include "date.h"
+#include "table/town_land.h"
+#include "genworld.h"
+
+/**
+ * Called if a new block is added to the town-pool
+ */
+static void TownPoolNewBlock(uint start_item)
+{
+	Town *t;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (t = GetTown(start_item); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) t->index = start_item++;
+}
+
+/* Initialize the town-pool */
+DEFINE_OLD_POOL(Town, Town, TownPoolNewBlock, NULL)
+
+void DestroyTown(Town *t)
+{
+	Industry *i;
+	TileIndex tile;
+
+	/* Delete town authority window
+	 * and remove from list of sorted towns */
+	DeleteWindowById(WC_TOWN_VIEW, t->index);
+	_town_sort_dirty = true;
+	_total_towns--;
+
+	/* Delete all industries belonging to the town */
+	FOR_ALL_INDUSTRIES(i) if (i->town == t) DeleteIndustry(i);
+
+	/* Go through all tiles and delete those belonging to the town */
+	for (tile = 0; tile < MapSize(); ++tile) {
+		switch (GetTileType(tile)) {
+			case MP_HOUSE:
+				if (GetTownByTile(tile) == t) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+				break;
+
+			case MP_STREET:
+			case MP_TUNNELBRIDGE:
+				if (IsTileOwner(tile, OWNER_TOWN) &&
+						ClosestTownFromTile(tile, (uint)-1) == t)
+					DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+				break;
+
+			default:
+				break;
+		}
+	}
+
+	DeleteName(t->townnametype);
+	DeleteSubsidyWithTown(t->index);
+
+	MarkWholeScreenDirty();
+}
+
+// Local
+static int _grow_town_result;
+
+static bool BuildTownHouse(Town *t, TileIndex tile);
+static void ClearTownHouse(Town *t, TileIndex tile);
+static void DoBuildTownHouse(Town *t, TileIndex tile);
+
+static void TownDrawHouseLift(const TileInfo *ti)
+{
+	AddChildSpriteScreen(SPR_LIFT, 14, 60 - GetLiftPosition(ti->tile));
+}
+
+typedef void TownDrawTileProc(const TileInfo *ti);
+static TownDrawTileProc * const _town_draw_tile_procs[1] = {
+	TownDrawHouseLift
+};
+
+
+static void DrawTile_Town(TileInfo *ti)
+{
+	const DrawBuildingsTileStruct *dcts;
+	uint32 image;
+
+	/* Retrieve pointer to the draw town tile struct */
+	{
+		/* this "randomizes" on the (up to) 4 variants of a building */
+		uint variant;
+		variant  = ti->x >> 4;
+		variant ^= ti->x >> 6;
+		variant ^= ti->y >> 4;
+		variant -= ti->y >> 6;
+		variant &= 3;
+		dcts = &_town_draw_tile_data[GetHouseType(ti->tile) << 4 | variant << 2 | GetHouseBuildingStage(ti->tile)];
+	}
+
+	if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+	DrawGroundSprite(dcts->ground);
+
+	/* Add a house on top of the ground? */
+	image = dcts->building;
+	if (image != 0) {
+		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+		AddSortableSpriteToDraw(image,
+			ti->x + dcts->subtile_x,
+			ti->y + dcts->subtile_y,
+			dcts->width + 1,
+			dcts->height + 1,
+			dcts->dz,
+			ti->z
+		);
+
+		if (_display_opt & DO_TRANS_BUILDINGS) return;
+	}
+
+	{
+		int proc = dcts->draw_proc - 1;
+
+		if (proc >= 0) _town_draw_tile_procs[proc](ti);
+	}
+}
+
+static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
+{
+	return GetTileMaxZ(tile);
+}
+
+static Slope GetSlopeTileh_Town(TileIndex tile, Slope tileh)
+{
+	return SLOPE_FLAT;
+}
+
+static void AnimateTile_Town(TileIndex tile)
+{
+	int pos, dest;
+
+	if (_tick_counter & 3) return;
+
+	// If the house is not one with a lift anymore, then stop this animating.
+	// Not exactly sure when this happens, but probably when a house changes.
+	// Before this was just a return...so it'd leak animated tiles..
+	// That bug seems to have been here since day 1??
+	if (!(_housetype_extra_flags[GetHouseType(tile)] & 0x20)) {
+		DeleteAnimatedTile(tile);
+		return;
+	}
+
+	if (!IsLiftMoving(tile)) {
+		int i;
+
+		/** Building has 6 floors, number 0 .. 6, where 1 is illegal.
+		 *  This is due to the fact that the first floor is, in the graphics,
+		 *  the height of 2 'normal' floors.
+		 *  Furthermore, there are 6 lift positions from floor N (incl) to floor N + 1 (excl) */
+		do {
+			i = (Random() & 7) - 1;
+		} while (i < 0 || i == 1 || i * 6 == GetLiftPosition(tile));
+
+		SetLiftDestination(tile, i);
+	}
+
+	pos = GetLiftPosition(tile);
+	dest = GetLiftDestination(tile) * 6;
+	pos += (pos < dest) ? 1 : -1;
+	SetLiftPosition(tile, pos);
+
+	if (pos == dest) HaltLift(tile);
+
+	MarkTileDirtyByTile(tile);
+}
+
+static void UpdateTownRadius(Town *t);
+
+static bool IsCloseToTown(TileIndex tile, uint dist)
+{
+	const Town* t;
+
+	FOR_ALL_TOWNS(t) {
+		if (DistanceManhattan(tile, t->xy) < dist) return true;
+	}
+	return false;
+}
+
+static void MarkTownSignDirty(Town *t)
+{
+	MarkAllViewportsDirty(
+		t->sign.left-6,
+		t->sign.top-3,
+		t->sign.left+t->sign.width_1*4+12,
+		t->sign.top + 45
+	);
+}
+
+void UpdateTownVirtCoord(Town *t)
+{
+	Point pt;
+
+	MarkTownSignDirty(t);
+	pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE);
+	SetDParam(0, t->index);
+	SetDParam(1, t->population);
+	UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24,
+		_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL);
+	MarkTownSignDirty(t);
+}
+
+static void ChangePopulation(Town *t, int mod)
+{
+	t->population += mod;
+	InvalidateWindow(WC_TOWN_VIEW, t->index);
+	UpdateTownVirtCoord(t);
+
+	if (_town_sort_order & 2) _town_sort_dirty = true;
+}
+
+uint32 GetWorldPopulation(void)
+{
+	uint32 pop;
+	const Town* t;
+
+	pop = 0;
+	FOR_ALL_TOWNS(t) pop += t->population;
+	return pop;
+}
+
+static void MakeSingleHouseBigger(TileIndex tile)
+{
+	assert(IsTileType(tile, MP_HOUSE));
+
+	if (LiftHasDestination(tile)) return;
+
+	IncHouseConstructionTick(tile);
+	if (GetHouseConstructionTick(tile) != 0) return;
+
+	IncHouseBuildingStage(tile);  /*increase construction stage of one more step*/
+
+	if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED){
+		/*Now, construction is completed.  Can add population of building to the town*/
+		ChangePopulation(GetTownByTile(tile), _housetype_population[GetHouseType(tile)]);
+	}
+	MarkTileDirtyByTile(tile);
+}
+
+static void MakeTownHouseBigger(TileIndex tile)
+{
+	uint flags = _house_more_flags[GetHouseType(tile)];
+	if (flags & 8) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
+	if (flags & 4) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
+	if (flags & 2) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
+	if (flags & 1) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
+}
+
+static void TileLoop_Town(TileIndex tile)
+{
+	int house;
+	Town *t;
+	uint32 r;
+
+	if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
+		/*Construction is not completed. See if we can go further in construction*/
+		MakeTownHouseBigger(tile);
+		return;
+	}
+
+	house = GetHouseType(tile);
+	if ((_housetype_extra_flags[house] & 0x20) && !LiftHasDestination(tile) && CHANCE16(1, 2) && AddAnimatedTile(tile)) BeginLiftMovement(tile);
+
+	t = GetTownByTile(tile);
+
+	r = Random();
+
+	if (GB(r, 0, 8) < _housetype_population[house]) {
+		uint amt = GB(r, 0, 8) / 8 + 1;
+		uint moved;
+
+		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
+		t->new_max_pass += amt;
+		moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
+		t->new_act_pass += moved;
+	}
+
+	if (GB(r, 8, 8) < _housetype_mailamount[house] ) {
+		uint amt = GB(r, 8, 8) / 8 + 1;
+		uint moved;
+
+		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
+		t->new_max_mail += amt;
+		moved = MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt);
+		t->new_act_mail += moved;
+	}
+
+	if (_house_more_flags[house] & 8 && HASBIT(t->flags12, TOWN_IS_FUNDED) && --t->time_until_rebuild == 0) {
+		t->time_until_rebuild = GB(r, 16, 6) + 130;
+
+		_current_player = OWNER_TOWN;
+
+		ClearTownHouse(t, tile);
+
+		// rebuild with another house?
+		if (GB(r, 24, 8) >= 12) DoBuildTownHouse(t, tile);
+
+		_current_player = OWNER_NONE;
+	}
+}
+
+static void ClickTile_Town(TileIndex tile)
+{
+	/* not used */
+}
+
+static int32 ClearTile_Town(TileIndex tile, byte flags)
+{
+	int house, rating;
+	int32 cost;
+	Town *t;
+
+	// safety checks
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+	if (flags&DC_AUTO && !(flags&DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+
+	house = GetHouseType(tile);
+	cost = _price.remove_house * _housetype_remove_cost[house] >> 8;
+
+	rating = _housetype_remove_ratingmod[house];
+	_cleared_town_rating += rating;
+	_cleared_town = t = GetTownByTile(tile);
+
+	if (IsValidPlayer(_current_player)) {
+		if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
+			SetDParam(0, t->index);
+			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM);
+		ClearTownHouse(t, tile);
+	}
+
+	return cost;
+}
+
+static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
+{
+	byte type = GetHouseType(tile);
+
+	ac[CT_PASSENGERS] = _housetype_cargo_passengers[type];
+	ac[CT_MAIL]       = _housetype_cargo_mail[type];
+	ac[CT_GOODS]      = _housetype_cargo_goods[type];
+	ac[CT_FOOD]       = _housetype_cargo_food[type];
+}
+
+static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
+{
+	td->str = _town_tile_names[GetHouseType(tile)];
+	if (GetHouseBuildingStage(tile) != TOWN_HOUSE_COMPLETED) {
+		SetDParamX(td->dparam, 0, td->str);
+		td->str = STR_2058_UNDER_CONSTRUCTION;
+	}
+
+	td->owner = OWNER_TOWN;
+}
+
+static uint32 GetTileTrackStatus_Town(TileIndex tile, TransportType mode)
+{
+	/* not used */
+	return 0;
+}
+
+static void ChangeTileOwner_Town(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	/* not used */
+}
+
+
+static const TileIndexDiffC _roadblock_tileadd[] = {
+	{ 0, -1},
+	{ 1,  0},
+	{ 0,  1},
+	{-1,  0},
+
+	// Store the first 3 elements again.
+	// Lets us rotate without using &3.
+	{ 0, -1},
+	{ 1,  0},
+	{ 0,  1}
+};
+
+
+static bool GrowTown(Town *t);
+
+static void TownTickHandler(Town *t)
+{
+	if (HASBIT(t->flags12, TOWN_IS_FUNDED)) {
+		int i = t->grow_counter - 1;
+		if (i < 0) {
+			if (GrowTown(t)) {
+				i = t->growth_rate;
+			} else {
+				i = 0;
+			}
+		}
+		t->grow_counter = i;
+	}
+
+	UpdateTownRadius(t);
+}
+
+void OnTick_Town(void)
+{
+	if (_game_mode == GM_EDITOR) return;
+
+	/* Make sure each town's tickhandler invocation frequency is about the
+	 * same - TOWN_GROWTH_FREQUENCY - independent on the number of towns. */
+	for (_cur_town_iter += GetMaxTownIndex() + 1;
+	     _cur_town_iter >= TOWN_GROWTH_FREQUENCY;
+	     _cur_town_iter -= TOWN_GROWTH_FREQUENCY) {
+		uint32 i = _cur_town_ctr;
+
+		if (++_cur_town_ctr > GetMaxTownIndex())
+			_cur_town_ctr = 0;
+
+		if (IsValidTownID(i)) TownTickHandler(GetTown(i));
+	}
+}
+
+static RoadBits GetTownRoadMask(TileIndex tile)
+{
+	TrackBits b = GetAnyRoadTrackBits(tile);
+	RoadBits r = 0;
+
+	if (b & TRACK_BIT_X)     r |= ROAD_X;
+	if (b & TRACK_BIT_Y)     r |= ROAD_Y;
+	if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW;
+	if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW;
+	if (b & TRACK_BIT_LEFT)  r |= ROAD_NW | ROAD_SW;
+	if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE;
+	return r;
+}
+
+static bool IsRoadAllowedHere(TileIndex tile, int dir)
+{
+	Slope k;
+	Slope slope;
+
+	// If this assertion fails, it might be because the world contains
+	//  land at the edges. This is not ok.
+	TILE_ASSERT(tile);
+
+	for (;;) {
+		// Check if there already is a road at this point?
+		if (GetAnyRoadTrackBits(tile) == 0) {
+			// No, try to build one in the direction.
+			// if that fails clear the land, and if that fails exit.
+			// This is to make sure that we can build a road here later.
+			if (CmdFailed(DoCommand(tile, (dir & 1 ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
+					CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
+				return false;
+		}
+
+		slope = GetTileSlope(tile, NULL);
+		if (slope == SLOPE_FLAT) {
+no_slope:
+			// Tile has no slope
+			// Disallow the road if any neighboring tile has a road.
+			if (HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+1]))), dir^2) ||
+					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+3]))), dir^2) ||
+					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+1]) + ToTileIndexDiff(_roadblock_tileadd[dir+2]))), dir) ||
+					HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir+3]) + ToTileIndexDiff(_roadblock_tileadd[dir+2]))), dir))
+				return false;
+
+			// Otherwise allow
+			return true;
+		}
+
+		// If the tile is not a slope in the right direction, then
+		// maybe terraform some.
+		k = (dir & 1) ? SLOPE_NE : SLOPE_NW;
+		if (k != slope && ComplementSlope(k) != slope) {
+			uint32 r = Random();
+
+			if (CHANCE16I(1, 8, r) && !_generating_world) {
+				int32 res;
+
+				if (CHANCE16I(1, 16, r)) {
+					res = DoCommand(tile, slope, 0, DC_EXEC | DC_AUTO | DC_NO_WATER,
+					                      CMD_TERRAFORM_LAND);
+				} else {
+					res = DoCommand(tile, slope ^ 0xF, 1, DC_EXEC | DC_AUTO | DC_NO_WATER,
+					                      CMD_TERRAFORM_LAND);
+				}
+				if (CmdFailed(res) && CHANCE16I(1, 3, r)) {
+					// We can consider building on the slope, though.
+					goto no_slope;
+				}
+			}
+			return false;
+		}
+		return true;
+	}
+}
+
+static bool TerraformTownTile(TileIndex tile, int edges, int dir)
+{
+	int32 r;
+
+	TILE_ASSERT(tile);
+
+	r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
+	if (CmdFailed(r) || r >= 126 * 16) return false;
+	DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
+	return true;
+}
+
+static void LevelTownLand(TileIndex tile)
+{
+	Slope tileh;
+
+	TILE_ASSERT(tile);
+
+	// Don't terraform if land is plain or if there's a house there.
+	if (IsTileType(tile, MP_HOUSE)) return;
+	tileh = GetTileSlope(tile, NULL);
+	if (tileh == SLOPE_FLAT) return;
+
+	// First try up, then down
+	if (!TerraformTownTile(tile, ~tileh & 0xF, 1)) {
+		TerraformTownTile(tile, tileh & 0xF, 0);
+	}
+}
+
+static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1)
+{
+	RoadBits rcmd;
+	TileIndex tmptile;
+	DiagDirection i;
+	int j;
+	TileIndex tile = *tile_ptr;
+
+	TILE_ASSERT(tile);
+
+	if (mask == 0) {
+		int a;
+		int b;
+
+		// Tile has no road. First reset the status counter
+		// to say that this is the last iteration.
+		_grow_town_result = 0;
+
+		// Remove hills etc
+		LevelTownLand(tile);
+
+		// Is a road allowed here?
+		if (!IsRoadAllowedHere(tile, block)) return;
+
+		// Randomize new road block numbers
+		a = block;
+		b = block ^ 2;
+		if (CHANCE16(1, 4)) {
+			do {
+				a = GB(Random(), 0, 2);
+			} while (a == b);
+		}
+
+		if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) {
+			// A road is not allowed to continue the randomized road,
+			//   return if the road we're trying to build is curved.
+			if (a != (b ^ 2)) return;
+
+			// Return if neither side of the new road is a house
+			if (!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 1])), MP_HOUSE) &&
+					!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 3])), MP_HOUSE))
+				return;
+
+			// That means that the road is only allowed if there is a house
+			//  at any side of the new road.
+		}
+		rcmd = (1 << a) + (1 << b);
+
+	} else if (block < 5 && !HASBIT(mask,block^2)) {
+		// Continue building on a partial road.
+		// Always OK.
+		_grow_town_result = 0;
+		rcmd = 1 << (block ^ 2);
+	} else {
+		int i;
+
+		// Reached a tunnel/bridge? Then continue at the other side of it.
+		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+			if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) {
+				*tile_ptr = GetOtherTunnelEnd(tile);
+			} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD) {
+				*tile_ptr = GetOtherBridgeEnd(tile);
+			}
+			return;
+		}
+
+		// Possibly extend the road in a direction.
+		// Randomize a direction and if it has a road, bail out.
+		i = GB(Random(), 0, 2);
+		if (HASBIT(mask, i)) return;
+
+		// This is the tile we will reach if we extend to this direction.
+		tmptile = TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i]));
+
+		// Don't do it if it reaches to water.
+		if (IsClearWaterTile(tmptile)) return;
+
+		// Build a house at the edge. 60% chance or
+		//  always ok if no road allowed.
+		if (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10)) {
+			// But not if there already is a house there.
+			if (!IsTileType(tmptile, MP_HOUSE)) {
+				// Level the land if possible
+				LevelTownLand(tmptile);
+
+				// And build a house.
+				// Set result to -1 if we managed to build it.
+				if (BuildTownHouse(t1, tmptile)) _grow_town_result = -1;
+			}
+			return;
+		}
+
+		_grow_town_result = 0;
+		rcmd = 1 << i;
+	}
+
+	// Return if a water tile
+	if (IsClearWaterTile(tile)) return;
+
+	// Determine direction of slope,
+	//  and build a road if not a special slope.
+	switch (GetTileSlope(tile, NULL)) {
+		case SLOPE_SW: i = DIAGDIR_NE; break;
+		case SLOPE_SE: i = DIAGDIR_NW; break;
+		case SLOPE_NW: i = DIAGDIR_SE; break;
+		case SLOPE_NE: i = DIAGDIR_SW; break;
+
+		default:
+build_road_and_exit:
+			if (!CmdFailed(DoCommand(tile, rcmd, t1->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) {
+				_grow_town_result = -1;
+			}
+			return;
+	}
+
+	tmptile = tile;
+
+	// Now it contains the direction of the slope
+	j = -11; // max 11 tile long bridges
+	do {
+		if (++j == 0)
+			goto build_road_and_exit;
+		tmptile = TILE_MASK(tmptile + TileOffsByDiagDir(i));
+	} while (IsClearWaterTile(tmptile));
+
+	// no water tiles in between?
+	if (j == -10)
+		goto build_road_and_exit;
+
+	// Quit if it selecting an appropiate bridge type fails a large number of times.
+	j = 22;
+	{
+		int32 bridge_len = GetBridgeLength(tile, tmptile);
+		do {
+			byte bridge_type = RandomRange(MAX_BRIDGES - 1);
+			if (CheckBridge_Stuff(bridge_type, bridge_len)) {
+				if (!CmdFailed(DoCommand(tile, tmptile, 0x8000 + bridge_type, DC_EXEC | DC_AUTO, CMD_BUILD_BRIDGE)))
+					_grow_town_result = -1;
+
+				// obviously, if building any bridge would fail, there is no need to try other bridge-types
+				return;
+			}
+		} while (--j != 0);
+	}
+}
+
+// Returns true if a house was built, or no if the build failed.
+static int GrowTownAtRoad(Town *t, TileIndex tile)
+{
+	int block = 5; // special case
+
+	TILE_ASSERT(tile);
+
+	// Number of times to search.
+	_grow_town_result = 10 + t->num_houses * 4 / 9;
+
+	do {
+		// Get a bitmask of the road blocks on a tile
+		RoadBits mask = GetTownRoadMask(tile);
+
+		// Try to grow the town from this point
+		GrowTownInTile(&tile,mask,block,t);
+
+		// Exclude the source position from the bitmask
+		// and return if no more road blocks available
+		CLRBIT(mask, (block ^ 2));
+		if (mask == 0)
+			return _grow_town_result;
+
+		// Select a random bit from the blockmask, walk a step
+		// and continue the search from there.
+		do block = Random() & 3; while (!HASBIT(mask,block));
+		tile += ToTileIndexDiff(_roadblock_tileadd[block]);
+
+		if (IsTileType(tile, MP_STREET)) {
+			/* Don't allow building over roads of other cities */
+			if (IsTileOwner(tile, OWNER_TOWN) && GetTownByTile(tile) != t) {
+				_grow_town_result = -1;
+			} else if (_game_mode == GM_EDITOR) {
+				/* If we are in the SE, and this road-piece has no town owner yet, it just found an
+				 * owner :) (happy happy happy road now) */
+				SetTileOwner(tile, OWNER_TOWN);
+				SetTownIndex(tile, t->index);
+			}
+		}
+
+		// Max number of times is checked.
+	} while (--_grow_town_result >= 0);
+
+	return (_grow_town_result == -2);
+}
+
+// Generate a random road block
+// The probability of a straight road
+// is somewhat higher than a curved.
+static RoadBits GenRandomRoadBits(void)
+{
+	uint32 r = Random();
+	uint a = GB(r, 0, 2);
+	uint b = GB(r, 8, 2);
+	if (a == b) b ^= 2;
+	return (1 << a) + (1 << b);
+}
+
+// Grow the town
+// Returns true if a house was built, or no if the build failed.
+static bool GrowTown(Town *t)
+{
+	TileIndex tile;
+	const TileIndexDiffC *ptr;
+	PlayerID old_player;
+
+	static const TileIndexDiffC _town_coord_mod[] = {
+		{-1,  0},
+		{ 1,  1},
+		{ 1, -1},
+		{-1, -1},
+		{-1,  0},
+		{ 0,  2},
+		{ 2,  0},
+		{ 0, -2},
+		{-1, -1},
+		{-2,  2},
+		{ 2,  2},
+		{ 2, -2},
+		{ 0,  0}
+	};
+
+	// Current player is a town
+	old_player = _current_player;
+	_current_player = OWNER_TOWN;
+
+	// Find a road that we can base the construction on.
+	tile = t->xy;
+	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
+		if (GetAnyRoadTrackBits(tile) != 0) {
+			int r = GrowTownAtRoad(t, tile);
+			_current_player = old_player;
+			return r;
+		}
+		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
+	}
+
+	// No road available, try to build a random road block by
+	// clearing some land and then building a road there.
+	tile = t->xy;
+	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
+		/* Only work with plain land that not already has a house */
+		if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
+			if (!CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR))) {
+				DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
+				_current_player = old_player;
+				return true;
+			}
+		}
+		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
+	}
+
+	_current_player = old_player;
+	return false;
+}
+
+static void UpdateTownRadius(Town *t)
+{
+	static const uint16 _town_radius_data[23][5] = {
+		{  4,  0,  0,  0,  0}, // 0
+		{ 16,  0,  0,  0,  0},
+		{ 25,  0,  0,  0,  0},
+		{ 36,  0,  0,  0,  0},
+		{ 49,  0,  4,  0,  0},
+		{ 64,  0,  4,  0,  0}, // 20
+		{ 64,  0,  9,  0,  1},
+		{ 64,  0,  9,  0,  4},
+		{ 64,  0, 16,  0,  4},
+		{ 81,  0, 16,  0,  4},
+		{ 81,  0, 16,  0,  4}, // 40
+		{ 81,  0, 25,  0,  9},
+		{ 81, 36, 25,  0,  9},
+		{ 81, 36, 25, 16,  9},
+		{ 81, 49,  0, 25,  9},
+		{ 81, 64,  0, 25,  9}, // 60
+		{ 81, 64,  0, 36,  9},
+		{ 81, 64,  0, 36, 16},
+		{100, 81,  0, 49, 16},
+		{100, 81,  0, 49, 25},
+		{121, 81,  0, 49, 25}, // 80
+		{121, 81,  0, 49, 25},
+		{121, 81,  0, 49, 36}, // 88
+	};
+
+	if (t->num_houses < 92) {
+		memcpy(t->radius, _town_radius_data[t->num_houses / 4], sizeof(t->radius));
+	} else {
+		int mass = t->num_houses / 8;
+		// At least very roughly extrapolate. Empirical numbers dancing between
+		// overwhelming by cottages and skyscrapers outskirts.
+		t->radius[0] = mass * mass;
+		// Actually we are proportional to sqrt() but that's right because
+		// we are covering an area.
+		t->radius[1] = mass * 7;
+		t->radius[2] = 0;
+		t->radius[3] = mass * 4;
+		t->radius[4] = mass * 3;
+		//debug("%d (->%d): %d %d %d %d\n", t->num_houses, mass, t->radius[0], t->radius[1], t->radius[3], t->radius[4]);
+	}
+}
+
+static bool CreateTownName(uint32 *townnameparts)
+{
+	Town *t2;
+	char buf1[64];
+	char buf2[64];
+	uint32 r;
+	/* Do not set too low tries, since when we run out of names, we loop
+	 * for #tries only one time anyway - then we stop generating more
+	 * towns. Do not show it too high neither, since looping through all
+	 * the other towns may take considerable amount of time (10000 is
+	 * too much). */
+	int tries = 1000;
+	uint16 townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
+
+	assert(townnameparts);
+
+	for (;;) {
+restart:
+		r = Random();
+
+		SetDParam(0, r);
+		GetString(buf1, townnametype, lastof(buf1));
+
+		// Check size and width
+		if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue;
+
+		FOR_ALL_TOWNS(t2) {
+			// We can't just compare the numbers since
+			// several numbers may map to a single name.
+			SetDParam(0, t2->index);
+			GetString(buf2, STR_TOWN, lastof(buf2));
+			if (strcmp(buf1, buf2) == 0) {
+				if (tries-- < 0) return false;
+				goto restart;
+			}
+		}
+		*townnameparts = r;
+		return true;
+	}
+}
+
+void UpdateTownMaxPass(Town *t)
+{
+	t->max_pass = t->population >> 3;
+	t->max_mail = t->population >> 4;
+}
+
+static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, uint size_mode)
+{
+	int x, i;
+
+	// clear the town struct
+	i = t->index;
+	memset(t, 0, sizeof(Town));
+	t->index = i;
+	_total_towns++;
+
+	t->xy = tile;
+	t->num_houses = 0;
+	t->time_until_rebuild = 10;
+	UpdateTownRadius(t);
+	t->flags12 = 0;
+	t->population = 0;
+	t->grow_counter = 0;
+	t->growth_rate = 250;
+	t->new_max_pass = 0;
+	t->new_max_mail = 0;
+	t->new_act_pass = 0;
+	t->new_act_mail = 0;
+	t->max_pass = 0;
+	t->max_mail = 0;
+	t->act_pass = 0;
+	t->act_mail = 0;
+
+	t->pct_pass_transported = 0;
+	t->pct_mail_transported = 0;
+	t->fund_buildings_months = 0;
+	t->new_act_food = 0;
+	t->new_act_water = 0;
+	t->act_food = 0;
+	t->act_water = 0;
+
+	for (i = 0; i != MAX_PLAYERS; i++)
+		t->ratings[i] = 500;
+
+	t->have_ratings = 0;
+	t->exclusivity = (byte)-1;
+	t->exclusive_counter = 0;
+	t->statues = 0;
+
+	t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
+	t->townnameparts = townnameparts;
+
+	UpdateTownVirtCoord(t);
+	_town_sort_dirty = true;
+
+	if (size_mode == 0) {
+		x = (Random() & 0xF) + 8;
+	} else {
+		x = (size_mode - 1) * 16 + 3;
+	}
+
+	t->num_houses += x;
+	UpdateTownRadius(t);
+
+	i = x * 4;
+	do {
+		GrowTown(t);
+	} while (--i);
+
+	t->num_houses -= x;
+	UpdateTownRadius(t);
+	UpdateTownMaxPass(t);
+}
+
+static Town *AllocateTown(void)
+{
+	Town *t;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (t = GetTown(0); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) {
+		if (!IsValidTown(t)) {
+			TownID index = t->index;
+
+			memset(t, 0, sizeof(Town));
+			t->index = index;
+
+			return t;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Town_pool))
+		return AllocateTown();
+
+	return NULL;
+}
+
+/** Create a new town.
+ * This obviously only works in the scenario editor. Function not removed
+ * as it might be possible in the future to fund your own town :)
+ * @param tile coordinates where town is built
+ * @param p1 size of the town (0 = random, 1 = small, 2 = medium, 3 = large)
+ * @param p2 unused
+ */
+int32 CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Town *t;
+	uint32 townnameparts;
+
+	/* Only in the scenario editor */
+	if (_game_mode != GM_EDITOR) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+
+	// Check if too close to the edge of map
+	if (DistanceFromEdge(tile) < 12)
+		return_cmd_error(STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP);
+
+	// Can only build on clear flat areas, possibly with trees.
+	if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
+		return_cmd_error(STR_0239_SITE_UNSUITABLE);
+	}
+
+	// Check distance to all other towns.
+	if (IsCloseToTown(tile, 20))
+		return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN);
+
+	// Get a unique name for the town.
+	if (!CreateTownName(&townnameparts))
+		return_cmd_error(STR_023A_TOO_MANY_TOWNS);
+
+	// Allocate town struct
+	t = AllocateTown();
+	if (t == NULL) return_cmd_error(STR_023A_TOO_MANY_TOWNS);
+
+	// Create the town
+	if (flags & DC_EXEC) {
+		_generating_world = true;
+		DoCreateTown(t, tile, townnameparts, p1);
+		_generating_world = false;
+	}
+	return 0;
+}
+
+Town *CreateRandomTown(uint attempts, uint size_mode)
+{
+	TileIndex tile;
+	Town *t;
+	uint32 townnameparts;
+
+	do {
+		// Generate a tile index not too close from the edge
+		tile = RandomTile();
+		if (DistanceFromEdge(tile) < 20) continue;
+
+		// Make sure the tile is plain
+		if (!IsTileType(tile, MP_CLEAR) || GetTileSlope(tile, NULL) != SLOPE_FLAT) continue;
+
+		// Check not too close to a town
+		if (IsCloseToTown(tile, 20)) continue;
+
+		// Get a unique name for the town.
+		if (!CreateTownName(&townnameparts)) break;
+
+		// Allocate a town struct
+		t = AllocateTown();
+		if (t == NULL) break;
+
+		DoCreateTown(t, tile, townnameparts, size_mode);
+		return t;
+	} while (--attempts);
+	return NULL;
+}
+
+static const byte _num_initial_towns[3] = {11, 23, 46};
+
+bool GenerateTowns(void)
+{
+	uint num = 0;
+	uint n = ScaleByMapSize(_num_initial_towns[_opt.diff.number_towns] + (Random() & 7));
+
+	SetGeneratingWorldProgress(GWP_TOWN, n);
+
+	do {
+		IncreaseGeneratingWorldProgress(GWP_TOWN);
+		// try 20 times to create a random-sized town for the first loop.
+		if (CreateRandomTown(20, 0) != NULL) num++;
+	} while (--n);
+
+	// give it a last try, but now more aggressive
+	if (num == 0 && CreateRandomTown(10000, 0) == NULL) {
+		if (GetNumTowns() == 0) {
+			/* XXX - can we handle that more gracefully? */
+			if (_game_mode != GM_EDITOR) error("Could not generate any town");
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static bool CheckBuildHouseMode(TileIndex tile, Slope tileh, int mode)
+{
+	int b;
+	Slope slope;
+
+	static const byte _masks[8] = {
+		0xC,0x3,0x9,0x6,
+		0x3,0xC,0x6,0x9,
+	};
+
+	slope = GetTileSlope(tile, NULL);
+	if (IsSteepSlope(slope)) return false;
+
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
+
+	b = 0;
+	if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
+	if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b;
+	if (b)
+		return false;
+
+	return !CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
+}
+
+
+uint GetTownRadiusGroup(const Town* t, TileIndex tile)
+{
+	uint dist = DistanceSquare(tile, t->xy);
+	uint smallest;
+	uint i;
+
+	if (t->fund_buildings_months && dist <= 25) return 4;
+
+	smallest = 0;
+	for (i = 0; i != lengthof(t->radius); i++) {
+		if (dist < t->radius[i]) smallest = i;
+	}
+
+	return smallest;
+}
+
+static bool CheckFree2x2Area(TileIndex tile)
+{
+	int i;
+
+	static const TileIndexDiffC _tile_add[] = {
+		{0    , 0    },
+		{0 - 0, 1 - 0},
+		{1 - 0, 0 - 1},
+		{1 - 1, 1 - 0}
+	};
+
+	for (i = 0; i != 4; i++) {
+		tile += ToTileIndexDiff(_tile_add[i]);
+
+		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
+
+		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
+
+		if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
+			return false;
+	}
+
+	return true;
+}
+
+static void DoBuildTownHouse(Town *t, TileIndex tile)
+{
+	int i;
+	uint bitmask;
+	int house;
+	Slope slope;
+	uint z;
+	uint oneof = 0;
+
+	// Above snow?
+	slope = GetTileSlope(tile, &z);
+
+	// Get the town zone type
+	{
+		uint rad = GetTownRadiusGroup(t, tile);
+
+		int land = _opt.landscape;
+		if (land == LT_HILLY && z >= _opt.snow_line) land = -1;
+
+		bitmask = (1 << rad) + (1 << (land + 12));
+	}
+
+	// bits 0-4 are used
+	// bits 11-15 are used
+	// bits 5-10 are not used.
+	{
+		byte houses[lengthof(_housetype_flags)];
+		int num = 0;
+
+		// Generate a list of all possible houses that can be built.
+		for (i=0; i!=lengthof(_housetype_flags); i++) {
+			if ((~_housetype_flags[i] & bitmask) == 0)
+				houses[num++] = (byte)i;
+		}
+
+		for (;;) {
+			house = houses[RandomRange(num)];
+
+			if (_cur_year < _housetype_years[house].min || _cur_year > _housetype_years[house].max)
+				continue;
+
+			// Special houses that there can be only one of.
+			switch (house) {
+				case HOUSE_TEMP_CHURCH:
+				case HOUSE_ARCT_CHURCH:
+				case HOUSE_SNOW_CHURCH:
+				case HOUSE_TROP_CHURCH:
+				case HOUSE_TOY_CHURCH:
+					SETBIT(oneof, TOWN_HAS_CHURCH);
+					break;
+				case HOUSE_STADIUM:
+				case HOUSE_MODERN_STADIUM:
+					SETBIT(oneof, TOWN_HAS_STADIUM);
+					break;
+				default:
+					oneof = 0;
+					break;
+			}
+
+			if (HASBITS(t->flags12 , oneof)) continue;
+
+			// Make sure there is no slope?
+			if (_housetype_extra_flags[house] & 0x12 && slope != SLOPE_FLAT) continue;
+
+			if (_housetype_extra_flags[house] & 0x10) {
+				if (CheckFree2x2Area(tile) ||
+						CheckFree2x2Area(tile += TileDiffXY(-1,  0)) ||
+						CheckFree2x2Area(tile += TileDiffXY( 0, -1)) ||
+						CheckFree2x2Area(tile += TileDiffXY( 1,  0))) {
+					break;
+				}
+				tile += TileDiffXY(0, 1);
+			} else if (_housetype_extra_flags[house] & 4) {
+				if (CheckBuildHouseMode(tile + TileDiffXY(1, 0), slope, 0)) break;
+
+				if (CheckBuildHouseMode(tile + TileDiffXY(-1, 0), slope, 1)) {
+					tile += TileDiffXY(-1, 0);
+					break;
+				}
+			} else if (_housetype_extra_flags[house] & 8) {
+				if (CheckBuildHouseMode(tile + TileDiffXY(0, 1), slope, 2)) break;
+
+				if (CheckBuildHouseMode(tile + TileDiffXY(0, -1), slope, 3)) {
+					tile += TileDiffXY(0, -1);
+					break;
+				}
+			} else {
+				break;
+			}
+		}
+	}
+
+	t->num_houses++;
+
+	// Special houses that there can be only one of.
+	t->flags12 |= oneof;
+
+	{
+		byte construction_counter = 0, construction_stage = 0, size_flags;
+
+		if (_generating_world) {
+			uint32 r = Random();
+
+			construction_stage = TOWN_HOUSE_COMPLETED;
+			if (CHANCE16(1, 7)) construction_stage = GB(r, 0, 2);
+
+			if (construction_stage == TOWN_HOUSE_COMPLETED) {
+				ChangePopulation(t, _housetype_population[house]);
+			} else {
+				construction_counter = GB(r, 2, 2);
+			}
+		}
+		size_flags = GB(_housetype_extra_flags[house], 2, 3);
+		MakeTownHouse(tile, t->index, construction_counter, construction_stage, size_flags, house);
+	}
+}
+
+static bool BuildTownHouse(Town *t, TileIndex tile)
+{
+	int32 r;
+
+	// make sure it's possible
+	if (!EnsureNoVehicle(tile)) return false;
+	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
+
+	r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(r)) return false;
+
+	DoBuildTownHouse(t, tile);
+	return true;
+}
+
+
+static void DoClearTownHouseHelper(TileIndex tile)
+{
+	assert(IsTileType(tile, MP_HOUSE));
+	DoClearSquare(tile);
+	DeleteAnimatedTile(tile);
+}
+
+static void ClearTownHouse(Town *t, TileIndex tile)
+{
+	uint house = GetHouseType(tile);
+	uint eflags;
+
+	assert(IsTileType(tile, MP_HOUSE));
+
+	// need to align the tile to point to the upper left corner of the house
+	if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
+		if (_housetype_extra_flags[house-1] & 0x04) {
+			house--;
+			tile += TileDiffXY(-1, 0);
+		} else if (_housetype_extra_flags[house-1] & 0x18) {
+			house--;
+			tile += TileDiffXY(0, -1);
+		} else if (_housetype_extra_flags[house-2] & 0x10) {
+			house-=2;
+			tile += TileDiffXY(-1, 0);
+		} else if (_housetype_extra_flags[house-3] & 0x10) {
+			house-=3;
+			tile += TileDiffXY(-1, -1);
+		}
+	}
+
+	// Remove population from the town if the house is finished.
+	if (GetHouseBuildingStage(tile) == TOWN_HOUSE_COMPLETED) {
+		ChangePopulation(t, -_housetype_population[house]);
+	}
+
+	t->num_houses--;
+
+	// Clear flags for houses that only may exist once/town.
+	switch (house) {
+		case HOUSE_TEMP_CHURCH:
+		case HOUSE_ARCT_CHURCH:
+		case HOUSE_SNOW_CHURCH:
+		case HOUSE_TROP_CHURCH:
+		case HOUSE_TOY_CHURCH:
+			CLRBIT(t->flags12, TOWN_HAS_CHURCH);
+			break;
+		case HOUSE_STADIUM:
+		case HOUSE_MODERN_STADIUM:
+			CLRBIT(t->flags12, TOWN_HAS_STADIUM);
+			break;
+		default:
+			break;
+	}
+
+	// Do the actual clearing of tiles
+	eflags = _housetype_extra_flags[house];
+	DoClearTownHouseHelper(tile);
+	if (eflags & 0x14) DoClearTownHouseHelper(tile + TileDiffXY(1, 0));
+	if (eflags & 0x18) DoClearTownHouseHelper(tile + TileDiffXY(0, 1));
+	if (eflags & 0x10) DoClearTownHouseHelper(tile + TileDiffXY(1, 1));
+}
+
+/** Rename a town (server-only).
+ * @param tile unused
+ * @param p1 town ID to rename
+ * @param p2 unused
+ */
+int32 CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID str;
+	Town *t;
+
+	if (!IsValidTownID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+
+	t = GetTown(p1);
+
+	str = AllocateNameUnique(_cmd_text, 4);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		DeleteName(t->townnametype);
+		t->townnametype = str;
+
+		UpdateTownVirtCoord(t);
+		_town_sort_dirty = true;
+		UpdateAllStationVirtCoord();
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+	return 0;
+}
+
+// Called from GUI
+void ExpandTown(Town *t)
+{
+	int amount, n;
+
+	_generating_world = true;
+
+	/* The more houses, the faster we grow */
+	amount = RandomRange(t->num_houses / 10) + 3;
+	t->num_houses += amount;
+	UpdateTownRadius(t);
+
+	n = amount * 10;
+	do GrowTown(t); while (--n);
+
+	t->num_houses -= amount;
+	UpdateTownRadius(t);
+
+	UpdateTownMaxPass(t);
+	_generating_world = false;
+}
+
+const byte _town_action_costs[8] = {
+	2, 4, 9, 35, 48, 53, 117, 175
+};
+
+static void TownActionAdvertiseSmall(Town* t)
+{
+	ModifyStationRatingAround(t->xy, _current_player, 0x40, 10);
+}
+
+static void TownActionAdvertiseMedium(Town* t)
+{
+	ModifyStationRatingAround(t->xy, _current_player, 0x70, 15);
+}
+
+static void TownActionAdvertiseLarge(Town* t)
+{
+	ModifyStationRatingAround(t->xy, _current_player, 0xA0, 20);
+}
+
+static void TownActionRoadRebuild(Town* t)
+{
+	const Player* p;
+
+	t->road_build_months = 6;
+
+	SetDParam(0, t->index);
+
+	p = GetPlayer(_current_player);
+	SetDParam(1, p->name_1);
+	SetDParam(2, p->name_2);
+
+	AddNewsItem(STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING,
+		NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_GENERAL, 0), t->xy, 0);
+}
+
+static bool DoBuildStatueOfCompany(TileIndex tile)
+{
+	PlayerID old;
+	int32 r;
+
+	if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
+
+	if (!IsTileType(tile, MP_HOUSE) &&
+			!IsTileType(tile, MP_CLEAR) &&
+			!IsTileType(tile, MP_TREES)) {
+		return false;
+	}
+
+	old = _current_player;
+	_current_player = OWNER_NONE;
+	r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	_current_player = old;
+
+	if (CmdFailed(r)) return false;
+
+	MakeStatue(tile, _current_player);
+	MarkTileDirtyByTile(tile);
+
+	return true;
+}
+
+/**
+ * Search callback function for TownActionBuildStatue
+ * @param data that is passed by the caller.  In this case, nothing
+ * @result of the test
+ */
+static bool SearchTileForStatue(TileIndex tile, uint32 data)
+{
+	return DoBuildStatueOfCompany(tile);
+}
+
+/**
+ * Perform a 9x9 tiles circular search from the center of the town
+ * in order to find a free tile to place a statue
+ * @param t town to search in
+ */
+static void TownActionBuildStatue(Town* t)
+{
+	TileIndex tile = t->xy;
+
+	if (CircularTileSearch(tile, 9, SearchTileForStatue, 0))
+		SETBIT(t->statues, _current_player); ///< Once found and built, "inform" the Town
+}
+
+static void TownActionFundBuildings(Town* t)
+{
+	// Build next tick
+	t->grow_counter = 1;
+	// If we were not already growing
+	SETBIT(t->flags12, TOWN_IS_FUNDED);
+	// And grow for 3 months
+	t->fund_buildings_months = 3;
+}
+
+static void TownActionBuyRights(Town* t)
+{
+	t->exclusive_counter = 12;
+	t->exclusivity = _current_player;
+
+	ModifyStationRatingAround(t->xy, _current_player, 130, 17);
+}
+
+static void TownActionBribe(Town* t)
+{
+	if (!RandomRange(15)) {
+		Station *st;
+
+		// set as unwanted for 6 months
+		t->unwanted[_current_player] = 6;
+
+		// set all close by station ratings to 0
+		FOR_ALL_STATIONS(st) {
+			if (st->town == t && st->owner == _current_player) {
+				uint i;
+
+				for (i = 0; i != NUM_CARGO; i++) st->goods[i].rating = 0;
+			}
+		}
+
+		// only show errormessage to the executing player. All errors are handled command.c
+		// but this is special, because it can only 'fail' on a DC_EXEC
+		if (IsLocalPlayer()) ShowErrorMessage(STR_BRIBE_FAILED_2, STR_BRIBE_FAILED, 0, 0);
+
+		/* decrease by a lot!
+		 * ChangeTownRating is only for stuff in demolishing. Bribe failure should
+		 * be independent of any cheat settings
+		 */
+		if (t->ratings[_current_player] > RATING_BRIBE_DOWN_TO) {
+			t->ratings[_current_player] = RATING_BRIBE_DOWN_TO;
+		}
+	} else {
+		ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM);
+	}
+}
+
+typedef void TownActionProc(Town* t);
+static TownActionProc * const _town_action_proc[] = {
+	TownActionAdvertiseSmall,
+	TownActionAdvertiseMedium,
+	TownActionAdvertiseLarge,
+	TownActionRoadRebuild,
+	TownActionBuildStatue,
+	TownActionFundBuildings,
+	TownActionBuyRights,
+	TownActionBribe
+};
+
+extern uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t);
+
+/** Do a town action.
+ * This performs an action such as advertising, building a statue, funding buildings,
+ * but also bribing the town-council
+ * @param tile unused
+ * @param p1 town to do the action at
+ * @param p2 action to perform, @see _town_action_proc for the list of available actions
+ */
+int32 CmdDoTownAction(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost;
+	Town *t;
+
+	if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR;
+
+	t = GetTown(p1);
+
+	if (!HASBIT(GetMaskOfTownActions(NULL, _current_player, t), p2)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+
+	cost = (_price.build_industry >> 8) * _town_action_costs[p2];
+
+	if (flags & DC_EXEC) {
+		_town_action_proc[p2](t);
+		InvalidateWindow(WC_TOWN_AUTHORITY, p1);
+	}
+
+	return cost;
+}
+
+static void UpdateTownGrowRate(Town *t)
+{
+	int n;
+	Station *st;
+	byte m;
+	Player *p;
+
+	// Reset player ratings if they're low
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active && t->ratings[p->index] <= 200) {
+			t->ratings[p->index] += 5;
+		}
+	}
+
+	n = 0;
+	FOR_ALL_STATIONS(st) {
+		if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) {
+			if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
+				n++;
+				if (IsValidPlayer(st->owner) && t->ratings[st->owner] <= 1000-12)
+					t->ratings[st->owner] += 12;
+			} else {
+				if (IsValidPlayer(st->owner) && t->ratings[st->owner] >= -1000+15)
+					t->ratings[st->owner] -= 15;
+			}
+		}
+	}
+
+	CLRBIT(t->flags12, TOWN_IS_FUNDED);
+
+	if (t->fund_buildings_months != 0) {
+		static const byte _grow_count_values[6] = {
+			60, 60, 60, 50, 40, 30
+		};
+		m = _grow_count_values[min(n, 5)];
+		t->fund_buildings_months--;
+	} else if (n == 0) {
+		m = 160;
+		if (!CHANCE16(1, 12))
+			return;
+	} else {
+		static const byte _grow_count_values[5] = {
+			210, 150, 110, 80, 50
+		};
+		m = _grow_count_values[min(n, 5) - 1];
+	}
+
+	if (_opt.landscape == LT_HILLY) {
+		if (TilePixelHeight(t->xy) >= _opt.snow_line && t->act_food == 0 && t->population > 90)
+			return;
+	} else if (_opt.landscape == LT_DESERT) {
+		if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food==0 || t->act_water==0) && t->population > 60)
+			return;
+	}
+
+	t->growth_rate = m / (t->num_houses / 50 + 1);
+	if (m <= t->grow_counter)
+		t->grow_counter = m;
+
+	SETBIT(t->flags12, TOWN_IS_FUNDED);
+}
+
+static void UpdateTownAmounts(Town *t)
+{
+	// Using +1 here to prevent overflow and division by zero
+	t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
+
+	t->max_pass = t->new_max_pass; t->new_max_pass = 0;
+	t->act_pass = t->new_act_pass; t->new_act_pass = 0;
+	t->act_food = t->new_act_food; t->new_act_food = 0;
+	t->act_water = t->new_act_water; t->new_act_water = 0;
+
+	// Using +1 here to prevent overflow and division by zero
+	t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
+	t->max_mail = t->new_max_mail; t->new_max_mail = 0;
+	t->act_mail = t->new_act_mail; t->new_act_mail = 0;
+
+	InvalidateWindow(WC_TOWN_VIEW, t->index);
+}
+
+static void UpdateTownUnwanted(Town *t)
+{
+	const Player* p;
+
+	FOR_ALL_PLAYERS(p) {
+		if (t->unwanted[p->index] > 0) t->unwanted[p->index]--;
+	}
+}
+
+bool CheckIfAuthorityAllows(TileIndex tile)
+{
+	Town *t;
+
+	if (!IsValidPlayer(_current_player)) return true;
+
+	t = ClosestTownFromTile(tile, _patches.dist_local_authority);
+	if (t == NULL) return true;
+
+	if (t->ratings[_current_player] > -200) return true;
+
+	_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
+	SetDParam(0, t->index);
+
+	return false;
+}
+
+
+Town* CalcClosestTownFromTile(TileIndex tile, uint threshold)
+{
+	Town *t;
+	uint dist, best = threshold;
+	Town *best_town = NULL;
+
+	FOR_ALL_TOWNS(t) {
+		dist = DistanceManhattan(tile, t->xy);
+		if (dist < best) {
+			best = dist;
+			best_town = t;
+		}
+	}
+
+	return best_town;
+}
+
+
+Town *ClosestTownFromTile(TileIndex tile, uint threshold)
+{
+	if (IsTileType(tile, MP_HOUSE) || (
+				IsTileType(tile, MP_STREET) &&
+				(IsLevelCrossing(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile)) == OWNER_TOWN
+			)) {
+		return GetTownByTile(tile);
+	} else {
+		return CalcClosestTownFromTile(tile, threshold);
+	}
+}
+
+
+void ChangeTownRating(Town *t, int add, int max)
+{
+	int rating;
+
+	// if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff
+	if (t == NULL ||
+			!IsValidPlayer(_current_player) ||
+			(_cheats.magic_bulldozer.value && add < 0)) {
+		return;
+	}
+
+	SETBIT(t->have_ratings, _current_player);
+
+	rating = t->ratings[_current_player];
+
+	if (add < 0) {
+		if (rating > max) {
+			rating += add;
+			if (rating < max) rating = max;
+		}
+	} else {
+		if (rating < max) {
+			rating += add;
+			if (rating > max) rating = max;
+		}
+	}
+	t->ratings[_current_player] = rating;
+}
+
+/* penalty for removing town-owned stuff */
+static const int _default_rating_settings [3][3] = {
+	// ROAD_REMOVE, TUNNELBRIDGE_REMOVE, INDUSTRY_REMOVE
+	{  0, 128, 384}, // Permissive
+	{ 48, 192, 480}, // Neutral
+	{ 96, 384, 768}, // Hostile
+};
+
+bool CheckforTownRating(uint32 flags, Town *t, byte type)
+{
+	int modemod;
+
+	// if magic_bulldozer cheat is active, town doesn't restrict your destructive actions
+	if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value)
+		return true;
+
+	/* check if you're allowed to remove the street/bridge/tunnel/industry
+	 * owned by a town no removal if rating is lower than ... depends now on
+	 * difficulty setting. Minimum town rating selected by difficulty level
+	 */
+	modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type];
+
+	if (t->ratings[_current_player] < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) {
+		SetDParam(0, t->index);
+		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
+		return false;
+	}
+
+	return true;
+}
+
+void TownsMonthlyLoop(void)
+{
+	Town *t;
+
+	FOR_ALL_TOWNS(t) {
+		if (t->road_build_months != 0) t->road_build_months--;
+
+		if (t->exclusive_counter != 0)
+			if (--t->exclusive_counter == 0) t->exclusivity = (byte)-1;
+
+		UpdateTownGrowRate(t);
+		UpdateTownAmounts(t);
+		UpdateTownUnwanted(t);
+	}
+}
+
+void InitializeTowns(void)
+{
+	Subsidy *s;
+
+	/* Clean the town pool and create 1 block in it */
+	CleanPool(&_Town_pool);
+	AddBlockToPool(&_Town_pool);
+
+	memset(_subsidies, 0, sizeof(_subsidies));
+	for (s=_subsidies; s != endof(_subsidies); s++)
+		s->cargo_type = CT_INVALID;
+
+	_cur_town_ctr = 0;
+	_cur_town_iter = 0;
+	_total_towns = 0;
+	_town_sort_dirty = true;
+}
+
+const TileTypeProcs _tile_type_town_procs = {
+	DrawTile_Town,           /* draw_tile_proc */
+	GetSlopeZ_Town,          /* get_slope_z_proc */
+	ClearTile_Town,          /* clear_tile_proc */
+	GetAcceptedCargo_Town,   /* get_accepted_cargo_proc */
+	GetTileDesc_Town,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Town, /* get_tile_track_status_proc */
+	ClickTile_Town,          /* click_tile_proc */
+	AnimateTile_Town,        /* animate_tile_proc */
+	TileLoop_Town,           /* tile_loop_clear */
+	ChangeTileOwner_Town,    /* change_tile_owner_clear */
+	NULL,                    /* get_produced_cargo_proc */
+	NULL,                    /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Town,      /* get_slope_tileh_proc */
+};
+
+
+// Save and load of towns.
+static const SaveLoad _town_desc[] = {
+	SLE_CONDVAR(Town, xy,                    SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+	SLE_CONDVAR(Town, xy,                    SLE_UINT32,                 6, SL_MAX_VERSION),
+
+	SLE_CONDVAR(Town, population,            SLE_FILE_U16 | SLE_VAR_U32, 0, 2),
+	SLE_CONDVAR(Town, population,            SLE_UINT32,                 3, SL_MAX_VERSION),
+
+
+	    SLE_VAR(Town, num_houses,            SLE_UINT16),
+	    SLE_VAR(Town, townnametype,          SLE_UINT16),
+	    SLE_VAR(Town, townnameparts,         SLE_UINT32),
+
+	    SLE_VAR(Town, flags12,               SLE_UINT8),
+	    SLE_VAR(Town, statues,               SLE_UINT8),
+
+	// sort_index_obsolete was stored here in savegame format 0 - 1
+	SLE_CONDNULL(1, 0, 1),
+
+	    SLE_VAR(Town, have_ratings,          SLE_UINT8),
+	    SLE_ARR(Town, ratings,               SLE_INT16, 8),
+	// failed bribe attempts are stored since savegame format 4
+	SLE_CONDARR(Town, unwanted,              SLE_INT8, 8, 4,SL_MAX_VERSION),
+
+	SLE_CONDVAR(Town, max_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, max_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, new_max_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, new_max_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, act_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, act_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, new_act_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+	SLE_CONDVAR(Town, new_act_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
+
+	SLE_CONDVAR(Town, max_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, max_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, new_max_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, new_max_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, act_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, act_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, new_act_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
+	SLE_CONDVAR(Town, new_act_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
+
+	    SLE_VAR(Town, pct_pass_transported,  SLE_UINT8),
+	    SLE_VAR(Town, pct_mail_transported,  SLE_UINT8),
+
+	    SLE_VAR(Town, act_food,              SLE_UINT16),
+	    SLE_VAR(Town, act_water,             SLE_UINT16),
+	    SLE_VAR(Town, new_act_food,          SLE_UINT16),
+	    SLE_VAR(Town, new_act_water,         SLE_UINT16),
+
+	    SLE_VAR(Town, time_until_rebuild,    SLE_UINT8),
+	    SLE_VAR(Town, grow_counter,          SLE_UINT8),
+	    SLE_VAR(Town, growth_rate,           SLE_UINT8),
+	    SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
+	    SLE_VAR(Town, road_build_months,     SLE_UINT8),
+
+	    SLE_VAR(Town, exclusivity,           SLE_UINT8),
+	    SLE_VAR(Town, exclusive_counter,     SLE_UINT8),
+	// reserve extra space in savegame here. (currently 30 bytes)
+	SLE_CONDNULL(30, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static void Save_TOWN(void)
+{
+	Town *t;
+
+	FOR_ALL_TOWNS(t) {
+		SlSetArrayIndex(t->index);
+		SlObject(t, _town_desc);
+	}
+}
+
+static void Load_TOWN(void)
+{
+	int index;
+
+	_total_towns = 0;
+
+	while ((index = SlIterateArray()) != -1) {
+		Town *t;
+
+		if (!AddBlockIfNeeded(&_Town_pool, index))
+			error("Towns: failed loading savegame: too many towns");
+
+		t = GetTown(index);
+		SlObject(t, _town_desc);
+
+		_total_towns++;
+	}
+
+	/* This is to ensure all pointers are within the limits of
+	 *  the size of the TownPool */
+	if (_cur_town_ctr > GetMaxTownIndex())
+		_cur_town_ctr = 0;
+}
+
+void AfterLoadTown(void)
+{
+	Town *t;
+	FOR_ALL_TOWNS(t) {
+		UpdateTownRadius(t);
+		UpdateTownVirtCoord(t);
+	}
+	_town_sort_dirty = true;
+}
+
+
+const ChunkHandler _town_chunk_handlers[] = {
+	{ 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/town_gui.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "town.h"
-#include "window.h"
-#include "gfx.h"
-#include "viewport.h"
-#include "gui.h"
-#include "command.h"
-#include "player.h"
-#include "network/network.h"
-#include "variables.h"
-
-static const Widget _town_authority_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   316,     0,    13, STR_2022_LOCAL_AUTHORITY, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   316,    14,   105, 0x0,                      STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   304,   106,   157, 0x0,                      STR_2043_LIST_OF_THINGS_TO_DO_AT},
-{  WWT_SCROLLBAR,   RESIZE_NONE,    13,   305,   316,   106,   157, 0x0,                      STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   316,   158,   209, 0x0,                      STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,   316,   210,   221, STR_2042_DO_IT,           STR_2044_CARRY_OUT_THE_HIGHLIGHTED},
-{   WIDGETS_END},
-};
-
-extern const byte _town_action_costs[8];
-extern void DrawPlayerIcon(PlayerID pid, int x, int y);
-
-/** Get a list of available actions to do at a town.
- * @param *nump if not NULL add put the number of available actions in it
- * @param pid the player that is querying the town
- * @param *t the town that is queried
- * @return bitmasked value of enabled actions
- */
-uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t)
-{
-	int32 avail, ref;
-	int num = 0;
-	uint avail_buttons = 0x7F; // by default all buttons except bribe are enabled.
-	uint buttons = 0;
-
-	if (pid != PLAYER_SPECTATOR) {
-		uint i;
-
-		// bribe option enabled?
-		if (_patches.bribe) {
-			// if unwanted, disable everything.
-			if (t->unwanted[pid]) {
-				avail_buttons = 0;
-			} else if (t->ratings[pid] < RATING_BRIBE_MAXIMUM) {
-				SETBIT(avail_buttons, 7); // Allow bribing
-			}
-		}
-
-		// Things worth more than this are not shown
-		avail = GetPlayer(pid)->player_money + _price.station_value * 200;
-		ref = _price.build_industry >> 8;
-
-		for (i = 0; i != lengthof(_town_action_costs); i++, avail_buttons >>= 1) {
-			if (HASBIT(avail_buttons, 0) && avail >= _town_action_costs[i] * ref) {
-				SETBIT(buttons, i);
-				num++;
-			}
-		}
-
-		/* Disable build statue if already built */
-		if (HASBIT(t->statues, pid)) {
-			CLRBIT(buttons, 4);
-			num--;
-		}
-
-	}
-
-	if (nump != NULL) *nump = num;
-	return buttons;
-}
-
-static int GetNthSetBit(uint32 bits, int n)
-{
-	int i = 0;
-
-	if (n >= 0) {
-		do {
-			if (bits & 1 && --n < 0) return i;
-			i++;
-		} while (bits >>= 1);
-	}
-	return -1;
-}
-
-static void TownAuthorityWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Town *t = GetTown(w->window_number);
-		int numact;
-		uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
-
-		SetVScrollCount(w, numact + 1);
-
-		if (WP(w,def_d).data_1 != -1 && !HASBIT(buttons, WP(w,def_d).data_1))
-			WP(w,def_d).data_1 = -1;
-
-		SetWindowWidgetDisabledState(w, 6, WP(w, def_d).data_1 == -1);
-
-		{
-			int y;
-			const Player *p;
-			int r;
-			StringID str;
-
-			SetDParam(0, w->window_number);
-			DrawWindowWidgets(w);
-
-			DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, 0);
-
-			// Draw list of players
-			y = 25;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active && (HASBIT(t->have_ratings, p->index) || t->exclusivity == p->index)) {
-					DrawPlayerIcon(p->index, 2, y);
-
-					SetDParam(0, p->name_1);
-					SetDParam(1, p->name_2);
-					SetDParam(2, GetPlayerNameString(p->index, 3));
-
-					r = t->ratings[p->index];
-					(str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
-					(str++,                    r <= RATING_VERYPOOR)  || // Very Poor
-					(str++,                    r <= RATING_POOR)      || // Poor
-					(str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
-					(str++,                    r <= RATING_GOOD)      || // Good
-					(str++,                    r <= RATING_VERYGOOD)  || // Very Good
-					(str++,                    r <= RATING_EXCELLENT) || // Excellent
-					(str++,                    true);                    // Outstanding
-
-					SetDParam(4, str);
-					if (t->exclusivity == p->index) // red icon for player with exclusive rights
-						DrawSprite(SPR_BLOT | PALETTE_TO_RED, 18, y);
-
-					DrawString(28, y, STR_2024, 0);
-					y += 10;
-				}
-			}
-		}
-
-		// Draw actions list
-		{
-			int y = 107, i;
-			int pos = w->vscroll.pos;
-
-			if (--pos < 0) {
-				DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, 0);
-				y += 10;
-			}
-			for (i = 0; buttons; i++, buttons >>= 1) {
-				if (pos <= -5) break;
-
-				if (buttons&1 && --pos < 0) {
-					DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, 6);
-					y += 10;
-				}
-			}
-		}
-
-		{
-			int i = WP(w,def_d).data_1;
-
-			if (i != -1) {
-				SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[i]);
-				SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i);
-				DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + i, 313);
-			}
-		}
-
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: { /* listbox */
-			const Town *t = GetTown(w->window_number);
-			int y = (e->we.click.pt.y - 0x6B) / 10;
-
-			if (!IS_INT_INSIDE(y, 0, 5)) return;
-
-			y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + w->vscroll.pos - 1);
-			if (y >= 0) {
-				WP(w,def_d).data_1 = y;
-				SetWindowDirty(w);
-			}
-			break;
-		}
-
-		case 6: { /* carry out the action */
-			DoCommandP(GetTown(w->window_number)->xy, w->window_number, WP(w,def_d).data_1, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
-			break;
-		}
-		}
-		break;
-
-	case WE_4:
-		SetWindowDirty(w);
-		break;
-	}
-}
-
-static const WindowDesc _town_authority_desc = {
-	WDP_AUTO, WDP_AUTO, 317, 222,
-	WC_TOWN_AUTHORITY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_town_authority_widgets,
-	TownAuthorityWndProc
-};
-
-static void ShowTownAuthorityWindow(uint town)
-{
-	Window *w = AllocateWindowDescFront(&_town_authority_desc, town);
-
-	if (w != NULL) {
-		w->vscroll.cap = 5;
-		WP(w,def_d).data_1 = -1;
-	}
-}
-
-static void TownViewWndProc(Window *w, WindowEvent *e)
-{
-	Town *t = GetTown(w->window_number);
-
-	switch (e->event) {
-	case WE_PAINT:
-		// disable renaming town in network games if you are not the server
-		SetWindowWidgetDisabledState(w, 8, _networking && !_network_server);
-
-		SetDParam(0, t->index);
-		DrawWindowWidgets(w);
-
-		SetDParam(0, t->population);
-		SetDParam(1, t->num_houses);
-		DrawString(2, 107, STR_2006_POPULATION, 0);
-
-		SetDParam(0, t->act_pass);
-		SetDParam(1, t->max_pass);
-		DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, 0);
-
-		SetDParam(0, t->act_mail);
-		SetDParam(1, t->max_mail);
-		DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, 0);
-
-		DrawWindowViewport(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 6: /* scroll to location */
-				ScrollMainWindowToTile(t->xy);
-				break;
-
-			case 7: /* town authority */
-				ShowTownAuthorityWindow(w->window_number);
-				break;
-
-			case 8: /* rename */
-				SetDParam(0, w->window_number);
-				ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, w, CS_ALPHANUMERAL);
-				break;
-
-			case 9: /* expand town */
-				ExpandTown(t);
-				break;
-
-			case 10: /* delete town */
-				DeleteTown(t);
-				break;
-		}
-		break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
-		}
-		break;
-	}
-}
-
-
-static const Widget _town_view_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   247,     0,    13, STR_2005,                 STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    13,   248,   259,     0,    13, 0x0,                      STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,    14,   105, 0x0,                      STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    13,     2,   257,    16,   103, 0x0,                      STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,   106,   137, 0x0,                      STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    85,   138,   149, STR_00E4_LOCATION,        STR_200B_CENTER_THE_MAIN_VIEW_ON},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    86,   171,   138,   149, STR_2020_LOCAL_AUTHORITY, STR_2021_SHOW_INFORMATION_ON_LOCAL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   172,   259,   138,   149, STR_0130_RENAME,          STR_200C_CHANGE_TOWN_NAME},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _town_view_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 150,
-	WC_TOWN_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_town_view_widgets,
-	TownViewWndProc
-};
-
-static const Widget _town_view_scen_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   172,     0,    13, STR_2005,          STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    13,   248,   259,     0,    13, 0x0,               STR_STICKY_BUTTON},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,    14,   105, 0x0,               STR_NULL},
-{      WWT_INSET,   RESIZE_NONE,    13,     2,   257,    16,   103, 0x0,               STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,   106,   137, 0x0,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    85,   138,   149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON},
-{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   173,   247,     0,    13, STR_0130_RENAME,   STR_200C_CHANGE_TOWN_NAME},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    86,   171,   138,   149, STR_023C_EXPAND,   STR_023B_INCREASE_SIZE_OF_TOWN},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   172,   259,   138,   149, STR_0290_DELETE,   STR_0291_DELETE_THIS_TOWN_COMPLETELY},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _town_view_scen_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 150,
-	WC_TOWN_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
-	_town_view_scen_widgets,
-	TownViewWndProc
-};
-
-void ShowTownViewWindow(TownID town)
-{
-	Window *w;
-
-	if (_game_mode != GM_EDITOR) {
-		w = AllocateWindowDescFront(&_town_view_desc, town);
-	} else {
-		w = AllocateWindowDescFront(&_town_view_scen_desc, town);
-	}
-
-	if (w != NULL) {
-		w->flags4 |= WF_DISABLE_VP_SCROLL;
-		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetTown(town)->xy, 1);
-	}
-}
-
-static const Widget _town_directory_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   195,     0,    13, STR_2000_TOWNS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    13,   196,   207,     0,    13, 0x0,                    STR_STICKY_BUTTON},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    98,    14,    25, STR_SORT_BY_NAME,       STR_SORT_ORDER_TIP},
-{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    99,   195,    14,    25, STR_SORT_BY_POPULATION, STR_SORT_ORDER_TIP},
-{      WWT_PANEL, RESIZE_BOTTOM,    13,     0,   195,    26,   189, 0x0,                    STR_200A_TOWN_NAMES_CLICK_ON_NAME},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    13,   196,   207,    14,   189, 0x0,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    13,     0,   195,   190,   201, 0x0,                    STR_NULL},
-{  WWT_RESIZEBOX,     RESIZE_TB,    13,   196,   207,   190,   201, 0x0,                    STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-
-// used to get a sorted list of the towns
-static uint _num_town_sort;
-
-static char _bufcache[64];
-static const Town* _last_town;
-
-static int CDECL TownNameSorter(const void *a, const void *b)
-{
-	const Town* ta = *(const Town**)a;
-	const Town* tb = *(const Town**)b;
-	char buf1[64];
-	int r;
-
-	SetDParam(0, ta->index);
-	GetString(buf1, STR_TOWN, lastof(buf1));
-
-	/* If 'b' is the same town as in the last round, use the cached value
-	 *  We do this to speed stuff up ('b' is called with the same value a lot of
-	 *  times after eachother) */
-	if (tb != _last_town) {
-		_last_town = tb;
-		SetDParam(0, tb->index);
-		GetString(_bufcache, STR_TOWN, lastof(_bufcache));
-	}
-
-	r = strcmp(buf1, _bufcache);
-	if (_town_sort_order & 1) r = -r;
-	return r;
-}
-
-static int CDECL TownPopSorter(const void *a, const void *b)
-{
-	const Town* ta = *(const Town**)a;
-	const Town* tb = *(const Town**)b;
-	int r = ta->population - tb->population;
-	if (_town_sort_order & 1) r = -r;
-	return r;
-}
-
-static void MakeSortedTownList(void)
-{
-	const Town* t;
-	uint n = 0;
-
-	/* Create array for sorting */
-	_town_sort = realloc((void*)_town_sort, (GetMaxTownIndex() + 1) * sizeof(_town_sort[0]));
-	if (_town_sort == NULL) error("Could not allocate memory for the town-sorting-list");
-
-	FOR_ALL_TOWNS(t) _town_sort[n++] = t;
-
-	_num_town_sort = n;
-
-	_last_town = NULL; // used for "cache"
-	qsort((void*)_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter);
-
-	DEBUG(misc, 3, "Resorting towns list");
-}
-
-
-static void TownDirectoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		if (_town_sort_dirty) {
-			_town_sort_dirty = false;
-			MakeSortedTownList();
-		}
-
-		SetVScrollCount(w, _num_town_sort);
-
-		DrawWindowWidgets(w);
-		DoDrawString(_town_sort_order & 1 ? DOWNARROW : UPARROW, (_town_sort_order <= 1) ? 88 : 187, 15, 0x10);
-
-		{
-			int n = 0;
-			uint16 i = w->vscroll.pos;
-			int y = 28;
-
-			while (i < _num_town_sort) {
-				const Town* t = _town_sort[i];
-
-				assert(t->xy);
-
-				SetDParam(0, t->index);
-				SetDParam(1, t->population);
-				DrawString(2, y, STR_2057, 0);
-
-				y += 10;
-				i++;
-				if (++n == w->vscroll.cap) break; // max number of towns in 1 window
-			}
-			SetDParam(0, GetWorldPopulation());
-			DrawString(3, w->height - 12 + 2, STR_TOWN_POPULATION, 0);
-		}
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: { /* Sort by Name ascending/descending */
-			_town_sort_order = (_town_sort_order == 0) ? 1 : 0;
-			_town_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 4: { /* Sort by Population ascending/descending */
-			_town_sort_order = (_town_sort_order == 2) ? 3 : 2;
-			_town_sort_dirty = true;
-			SetWindowDirty(w);
-		} break;
-
-		case 5: { /* Click on Town Matrix */
-			const Town* t;
-
-			uint16 id_v = (e->we.click.pt.y - 28) / 10;
-
-			if (id_v >= w->vscroll.cap) return; // click out of bounds
-
-			id_v += w->vscroll.pos;
-
-			if (id_v >= _num_town_sort) return; // click out of town bounds
-
-			t = _town_sort[id_v];
-			assert(t->xy);
-			ScrollMainWindowToTile(t->xy);
-			break;
-		}
-		}
-		break;
-
-	case WE_4:
-		SetWindowDirty(w);
-		break;
-
-	case WE_RESIZE:
-		w->vscroll.cap += e->we.sizing.diff.y / 10;
-		break;
-	}
-}
-
-static const WindowDesc _town_directory_desc = {
-	WDP_AUTO, WDP_AUTO, 208, 202,
-	WC_TOWN_DIRECTORY,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_town_directory_widgets,
-	TownDirectoryWndProc
-};
-
-
-void ShowTownDirectory(void)
-{
-	Window *w = AllocateWindowDescFront(&_town_directory_desc, 0);
-
-	if (w != NULL) {
-		w->vscroll.cap = 16;
-		w->resize.step_height = 10;
-		w->resize.height = w->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/town_gui.cpp
@@ -0,0 +1,524 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "town.h"
+#include "window.h"
+#include "gfx.h"
+#include "viewport.h"
+#include "gui.h"
+#include "command.h"
+#include "player.h"
+#include "network/network.h"
+#include "variables.h"
+
+static const Widget _town_authority_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   316,     0,    13, STR_2022_LOCAL_AUTHORITY, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   316,    14,   105, 0x0,                      STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   304,   106,   157, 0x0,                      STR_2043_LIST_OF_THINGS_TO_DO_AT},
+{  WWT_SCROLLBAR,   RESIZE_NONE,    13,   305,   316,   106,   157, 0x0,                      STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   316,   158,   209, 0x0,                      STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,   316,   210,   221, STR_2042_DO_IT,           STR_2044_CARRY_OUT_THE_HIGHLIGHTED},
+{   WIDGETS_END},
+};
+
+extern const byte _town_action_costs[8];
+extern void DrawPlayerIcon(PlayerID pid, int x, int y);
+
+/** Get a list of available actions to do at a town.
+ * @param *nump if not NULL add put the number of available actions in it
+ * @param pid the player that is querying the town
+ * @param *t the town that is queried
+ * @return bitmasked value of enabled actions
+ */
+uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t)
+{
+	int32 avail, ref;
+	int num = 0;
+	uint avail_buttons = 0x7F; // by default all buttons except bribe are enabled.
+	uint buttons = 0;
+
+	if (pid != PLAYER_SPECTATOR) {
+		uint i;
+
+		// bribe option enabled?
+		if (_patches.bribe) {
+			// if unwanted, disable everything.
+			if (t->unwanted[pid]) {
+				avail_buttons = 0;
+			} else if (t->ratings[pid] < RATING_BRIBE_MAXIMUM) {
+				SETBIT(avail_buttons, 7); // Allow bribing
+			}
+		}
+
+		// Things worth more than this are not shown
+		avail = GetPlayer(pid)->player_money + _price.station_value * 200;
+		ref = _price.build_industry >> 8;
+
+		for (i = 0; i != lengthof(_town_action_costs); i++, avail_buttons >>= 1) {
+			if (HASBIT(avail_buttons, 0) && avail >= _town_action_costs[i] * ref) {
+				SETBIT(buttons, i);
+				num++;
+			}
+		}
+
+		/* Disable build statue if already built */
+		if (HASBIT(t->statues, pid)) {
+			CLRBIT(buttons, 4);
+			num--;
+		}
+
+	}
+
+	if (nump != NULL) *nump = num;
+	return buttons;
+}
+
+static int GetNthSetBit(uint32 bits, int n)
+{
+	int i = 0;
+
+	if (n >= 0) {
+		do {
+			if (bits & 1 && --n < 0) return i;
+			i++;
+		} while (bits >>= 1);
+	}
+	return -1;
+}
+
+static void TownAuthorityWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Town *t = GetTown(w->window_number);
+		int numact;
+		uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
+
+		SetVScrollCount(w, numact + 1);
+
+		if (WP(w,def_d).data_1 != -1 && !HASBIT(buttons, WP(w,def_d).data_1))
+			WP(w,def_d).data_1 = -1;
+
+		SetWindowWidgetDisabledState(w, 6, WP(w, def_d).data_1 == -1);
+
+		{
+			int y;
+			const Player *p;
+			int r;
+			StringID str;
+
+			SetDParam(0, w->window_number);
+			DrawWindowWidgets(w);
+
+			DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, 0);
+
+			// Draw list of players
+			y = 25;
+			FOR_ALL_PLAYERS(p) {
+				if (p->is_active && (HASBIT(t->have_ratings, p->index) || t->exclusivity == p->index)) {
+					DrawPlayerIcon(p->index, 2, y);
+
+					SetDParam(0, p->name_1);
+					SetDParam(1, p->name_2);
+					SetDParam(2, GetPlayerNameString(p->index, 3));
+
+					r = t->ratings[p->index];
+					(str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
+					(str++,                    r <= RATING_VERYPOOR)  || // Very Poor
+					(str++,                    r <= RATING_POOR)      || // Poor
+					(str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
+					(str++,                    r <= RATING_GOOD)      || // Good
+					(str++,                    r <= RATING_VERYGOOD)  || // Very Good
+					(str++,                    r <= RATING_EXCELLENT) || // Excellent
+					(str++,                    true);                    // Outstanding
+
+					SetDParam(4, str);
+					if (t->exclusivity == p->index) // red icon for player with exclusive rights
+						DrawSprite(SPR_BLOT | PALETTE_TO_RED, 18, y);
+
+					DrawString(28, y, STR_2024, 0);
+					y += 10;
+				}
+			}
+		}
+
+		// Draw actions list
+		{
+			int y = 107, i;
+			int pos = w->vscroll.pos;
+
+			if (--pos < 0) {
+				DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, 0);
+				y += 10;
+			}
+			for (i = 0; buttons; i++, buttons >>= 1) {
+				if (pos <= -5) break;
+
+				if (buttons&1 && --pos < 0) {
+					DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, 6);
+					y += 10;
+				}
+			}
+		}
+
+		{
+			int i = WP(w,def_d).data_1;
+
+			if (i != -1) {
+				SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[i]);
+				SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i);
+				DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + i, 313);
+			}
+		}
+
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: { /* listbox */
+			const Town *t = GetTown(w->window_number);
+			int y = (e->we.click.pt.y - 0x6B) / 10;
+
+			if (!IS_INT_INSIDE(y, 0, 5)) return;
+
+			y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + w->vscroll.pos - 1);
+			if (y >= 0) {
+				WP(w,def_d).data_1 = y;
+				SetWindowDirty(w);
+			}
+			break;
+		}
+
+		case 6: { /* carry out the action */
+			DoCommandP(GetTown(w->window_number)->xy, w->window_number, WP(w,def_d).data_1, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+			break;
+		}
+		}
+		break;
+
+	case WE_4:
+		SetWindowDirty(w);
+		break;
+	}
+}
+
+static const WindowDesc _town_authority_desc = {
+	WDP_AUTO, WDP_AUTO, 317, 222,
+	WC_TOWN_AUTHORITY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_town_authority_widgets,
+	TownAuthorityWndProc
+};
+
+static void ShowTownAuthorityWindow(uint town)
+{
+	Window *w = AllocateWindowDescFront(&_town_authority_desc, town);
+
+	if (w != NULL) {
+		w->vscroll.cap = 5;
+		WP(w,def_d).data_1 = -1;
+	}
+}
+
+static void TownViewWndProc(Window *w, WindowEvent *e)
+{
+	Town *t = GetTown(w->window_number);
+
+	switch (e->event) {
+	case WE_PAINT:
+		// disable renaming town in network games if you are not the server
+		SetWindowWidgetDisabledState(w, 8, _networking && !_network_server);
+
+		SetDParam(0, t->index);
+		DrawWindowWidgets(w);
+
+		SetDParam(0, t->population);
+		SetDParam(1, t->num_houses);
+		DrawString(2, 107, STR_2006_POPULATION, 0);
+
+		SetDParam(0, t->act_pass);
+		SetDParam(1, t->max_pass);
+		DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, 0);
+
+		SetDParam(0, t->act_mail);
+		SetDParam(1, t->max_mail);
+		DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, 0);
+
+		DrawWindowViewport(w);
+		break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+			case 6: /* scroll to location */
+				ScrollMainWindowToTile(t->xy);
+				break;
+
+			case 7: /* town authority */
+				ShowTownAuthorityWindow(w->window_number);
+				break;
+
+			case 8: /* rename */
+				SetDParam(0, w->window_number);
+				ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, w, CS_ALPHANUMERAL);
+				break;
+
+			case 9: /* expand town */
+				ExpandTown(t);
+				break;
+
+			case 10: /* delete town */
+				DeleteTown(t);
+				break;
+		}
+		break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
+		}
+		break;
+	}
+}
+
+
+static const Widget _town_view_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   247,     0,    13, STR_2005,                 STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    13,   248,   259,     0,    13, 0x0,                      STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,    14,   105, 0x0,                      STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    13,     2,   257,    16,   103, 0x0,                      STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,   106,   137, 0x0,                      STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    85,   138,   149, STR_00E4_LOCATION,        STR_200B_CENTER_THE_MAIN_VIEW_ON},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    86,   171,   138,   149, STR_2020_LOCAL_AUTHORITY, STR_2021_SHOW_INFORMATION_ON_LOCAL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   172,   259,   138,   149, STR_0130_RENAME,          STR_200C_CHANGE_TOWN_NAME},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _town_view_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 150,
+	WC_TOWN_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_town_view_widgets,
+	TownViewWndProc
+};
+
+static const Widget _town_view_scen_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,          STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   172,     0,    13, STR_2005,          STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    13,   248,   259,     0,    13, 0x0,               STR_STICKY_BUTTON},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,    14,   105, 0x0,               STR_NULL},
+{      WWT_INSET,   RESIZE_NONE,    13,     2,   257,    16,   103, 0x0,               STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    13,     0,   259,   106,   137, 0x0,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    85,   138,   149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON},
+{      WWT_EMPTY,   RESIZE_NONE,     0,     0,     0,     0,     0, 0x0,               STR_NULL},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   173,   247,     0,    13, STR_0130_RENAME,   STR_200C_CHANGE_TOWN_NAME},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    86,   171,   138,   149, STR_023C_EXPAND,   STR_023B_INCREASE_SIZE_OF_TOWN},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,   172,   259,   138,   149, STR_0290_DELETE,   STR_0291_DELETE_THIS_TOWN_COMPLETELY},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _town_view_scen_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 150,
+	WC_TOWN_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
+	_town_view_scen_widgets,
+	TownViewWndProc
+};
+
+void ShowTownViewWindow(TownID town)
+{
+	Window *w;
+
+	if (_game_mode != GM_EDITOR) {
+		w = AllocateWindowDescFront(&_town_view_desc, town);
+	} else {
+		w = AllocateWindowDescFront(&_town_view_scen_desc, town);
+	}
+
+	if (w != NULL) {
+		w->flags4 |= WF_DISABLE_VP_SCROLL;
+		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetTown(town)->xy, 1);
+	}
+}
+
+static const Widget _town_directory_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    13,    11,   195,     0,    13, STR_2000_TOWNS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    13,   196,   207,     0,    13, 0x0,                    STR_STICKY_BUTTON},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,     0,    98,    14,    25, STR_SORT_BY_NAME,       STR_SORT_ORDER_TIP},
+{ WWT_PUSHTXTBTN,   RESIZE_NONE,    13,    99,   195,    14,    25, STR_SORT_BY_POPULATION, STR_SORT_ORDER_TIP},
+{      WWT_PANEL, RESIZE_BOTTOM,    13,     0,   195,    26,   189, 0x0,                    STR_200A_TOWN_NAMES_CLICK_ON_NAME},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    13,   196,   207,    14,   189, 0x0,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    13,     0,   195,   190,   201, 0x0,                    STR_NULL},
+{  WWT_RESIZEBOX,     RESIZE_TB,    13,   196,   207,   190,   201, 0x0,                    STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+
+// used to get a sorted list of the towns
+static uint _num_town_sort;
+
+static char _bufcache[64];
+static const Town* _last_town;
+
+static int CDECL TownNameSorter(const void *a, const void *b)
+{
+	const Town* ta = *(const Town**)a;
+	const Town* tb = *(const Town**)b;
+	char buf1[64];
+	int r;
+
+	SetDParam(0, ta->index);
+	GetString(buf1, STR_TOWN, lastof(buf1));
+
+	/* If 'b' is the same town as in the last round, use the cached value
+	 *  We do this to speed stuff up ('b' is called with the same value a lot of
+	 *  times after eachother) */
+	if (tb != _last_town) {
+		_last_town = tb;
+		SetDParam(0, tb->index);
+		GetString(_bufcache, STR_TOWN, lastof(_bufcache));
+	}
+
+	r = strcmp(buf1, _bufcache);
+	if (_town_sort_order & 1) r = -r;
+	return r;
+}
+
+static int CDECL TownPopSorter(const void *a, const void *b)
+{
+	const Town* ta = *(const Town**)a;
+	const Town* tb = *(const Town**)b;
+	int r = ta->population - tb->population;
+	if (_town_sort_order & 1) r = -r;
+	return r;
+}
+
+static void MakeSortedTownList(void)
+{
+	const Town* t;
+	uint n = 0;
+
+	/* Create array for sorting */
+	_town_sort = realloc((void*)_town_sort, (GetMaxTownIndex() + 1) * sizeof(_town_sort[0]));
+	if (_town_sort == NULL) error("Could not allocate memory for the town-sorting-list");
+
+	FOR_ALL_TOWNS(t) _town_sort[n++] = t;
+
+	_num_town_sort = n;
+
+	_last_town = NULL; // used for "cache"
+	qsort((void*)_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter);
+
+	DEBUG(misc, 3, "Resorting towns list");
+}
+
+
+static void TownDirectoryWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		if (_town_sort_dirty) {
+			_town_sort_dirty = false;
+			MakeSortedTownList();
+		}
+
+		SetVScrollCount(w, _num_town_sort);
+
+		DrawWindowWidgets(w);
+		DoDrawString(_town_sort_order & 1 ? DOWNARROW : UPARROW, (_town_sort_order <= 1) ? 88 : 187, 15, 0x10);
+
+		{
+			int n = 0;
+			uint16 i = w->vscroll.pos;
+			int y = 28;
+
+			while (i < _num_town_sort) {
+				const Town* t = _town_sort[i];
+
+				assert(t->xy);
+
+				SetDParam(0, t->index);
+				SetDParam(1, t->population);
+				DrawString(2, y, STR_2057, 0);
+
+				y += 10;
+				i++;
+				if (++n == w->vscroll.cap) break; // max number of towns in 1 window
+			}
+			SetDParam(0, GetWorldPopulation());
+			DrawString(3, w->height - 12 + 2, STR_TOWN_POPULATION, 0);
+		}
+	} break;
+
+	case WE_CLICK:
+		switch (e->we.click.widget) {
+		case 3: { /* Sort by Name ascending/descending */
+			_town_sort_order = (_town_sort_order == 0) ? 1 : 0;
+			_town_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 4: { /* Sort by Population ascending/descending */
+			_town_sort_order = (_town_sort_order == 2) ? 3 : 2;
+			_town_sort_dirty = true;
+			SetWindowDirty(w);
+		} break;
+
+		case 5: { /* Click on Town Matrix */
+			const Town* t;
+
+			uint16 id_v = (e->we.click.pt.y - 28) / 10;
+
+			if (id_v >= w->vscroll.cap) return; // click out of bounds
+
+			id_v += w->vscroll.pos;
+
+			if (id_v >= _num_town_sort) return; // click out of town bounds
+
+			t = _town_sort[id_v];
+			assert(t->xy);
+			ScrollMainWindowToTile(t->xy);
+			break;
+		}
+		}
+		break;
+
+	case WE_4:
+		SetWindowDirty(w);
+		break;
+
+	case WE_RESIZE:
+		w->vscroll.cap += e->we.sizing.diff.y / 10;
+		break;
+	}
+}
+
+static const WindowDesc _town_directory_desc = {
+	WDP_AUTO, WDP_AUTO, 208, 202,
+	WC_TOWN_DIRECTORY,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_town_directory_widgets,
+	TownDirectoryWndProc
+};
+
+
+void ShowTownDirectory(void)
+{
+	Window *w = AllocateWindowDescFront(&_town_directory_desc, 0);
+
+	if (w != NULL) {
+		w->vscroll.cap = 16;
+		w->resize.step_height = 10;
+		w->resize.height = w->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
+	}
+}
deleted file mode 100644
--- a/src/train_cmd.c
+++ /dev/null
@@ -1,3811 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "debug.h"
-#include "functions.h"
-#include "gui.h"
-#include "station_map.h"
-#include "table/strings.h"
-#include "map.h"
-#include "tile.h"
-#include "tunnel_map.h"
-#include "vehicle.h"
-#include "command.h"
-#include "pathfind.h"
-#include "npf.h"
-#include "station.h"
-#include "table/train_cmd.h"
-#include "news.h"
-#include "engine.h"
-#include "player.h"
-#include "sound.h"
-#include "depot.h"
-#include "waypoint.h"
-#include "vehicle_gui.h"
-#include "train.h"
-#include "bridge.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_engine.h"
-#include "newgrf_sound.h"
-#include "newgrf_text.h"
-#include "direction.h"
-#include "yapf/yapf.h"
-#include "date.h"
-
-static bool TrainCheckIfLineEnds(Vehicle *v);
-static void TrainController(Vehicle *v, bool update_image);
-
-static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
-static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
-static const byte _state_dir_table[4] = { 0x20, 8, 0x10, 4 };
-
-
-/** Return the cargo weight multiplier to use for a rail vehicle
- * @param cargo Cargo type to get multiplier for
- * @return Cargo weight multiplier
- */
-byte FreightWagonMult(CargoID cargo)
-{
-	// XXX NewCargos introduces a specific "is freight" flag for this test.
-	if (cargo == CT_PASSENGERS || cargo == CT_MAIL) return 1;
-	return _patches.freight_trains;
-}
-
-
-/**
- * Recalculates the cached total power of a train. Should be called when the consist is changed
- * @param v First vehicle of the consist.
- */
-void TrainPowerChanged(Vehicle* v)
-{
-	Vehicle* u;
-	uint32 power = 0;
-	uint32 max_te = 0;
-
-	for (u = v; u != NULL; u = u->next) {
-		const RailVehicleInfo *rvi_u;
-		bool engine_has_power = true;
-		bool wagon_has_power = true;
-
-		/* Power is not added for articulated parts */
-		if (IsArticulatedPart(u)) continue;
-
-		if (IsLevelCrossingTile(u->tile)) {
-			if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeCrossing(u->tile))) engine_has_power = false;
-			if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeCrossing(u->tile))) wagon_has_power = false;
-		} else {
-			if (!HasPowerOnRail(u->u.rail.railtype, GetRailType(u->tile))) engine_has_power = false;
-			if (!HasPowerOnRail(v->u.rail.railtype, GetRailType(u->tile))) wagon_has_power = false;
-		}
-
-		rvi_u = RailVehInfo(u->engine_type);
-
-		if (engine_has_power && rvi_u->power != 0) {
-			power += rvi_u->power;
-			/* Tractive effort in (tonnes * 1000 * 10 =) N */
-			max_te += (u->u.rail.cached_veh_weight * 10000 * rvi_u->tractive_effort) / 256;
-		}
-
-		if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON) && (wagon_has_power)) {
-			power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
-		}
-	}
-
-	if (v->u.rail.cached_power != power || v->u.rail.cached_max_te != max_te) {
-		v->u.rail.cached_power = power;
-		v->u.rail.cached_max_te = max_te;
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-}
-
-
-/**
- * Recalculates the cached weight of a train and its vehicles. Should be called each time the cargo on
- * the consist changes.
- * @param v First vehicle of the consist.
- */
-static void TrainCargoChanged(Vehicle* v)
-{
-	Vehicle *u;
-	uint32 weight = 0;
-
-	for (u = v; u != NULL; u = u->next) {
-		const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
-		uint32 vweight = (_cargoc.weights[u->cargo_type] * u->cargo_count * FreightWagonMult(u->cargo_type)) / 16;
-
-		// Vehicle weight is not added for articulated parts.
-		if (!IsArticulatedPart(u)) {
-			// vehicle weight is the sum of the weight of the vehicle and the weight of its cargo
-			vweight += rvi->weight;
-
-			// powered wagons have extra weight added
-			if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON))
-				vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
-		}
-
-		// consist weight is the sum of the weight of all vehicles in the consist
-		weight += vweight;
-
-		// store vehicle weight in cache
-		u->u.rail.cached_veh_weight = vweight;
-	};
-
-	// store consist weight in cache
-	v->u.rail.cached_weight = weight;
-
-	/* Now update train power (tractive effort is dependent on weight) */
-	TrainPowerChanged(v);
-}
-
-
-/**
- * Recalculates the cached stuff of a train. Should be called each time a vehicle is added
- * to/removed from the chain, and when the game is loaded.
- * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
- * @param v First vehicle of the chain.
- */
-void TrainConsistChanged(Vehicle* v)
-{
-	const RailVehicleInfo *rvi_v;
-	Vehicle *u;
-	uint16 max_speed = 0xFFFF;
-	EngineID first_engine;
-
-	assert(v->type == VEH_Train);
-
-	assert(IsFrontEngine(v) || IsFreeWagon(v));
-
-	rvi_v = RailVehInfo(v->engine_type);
-	first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
-	v->u.rail.cached_total_length = 0;
-	v->u.rail.compatible_railtypes = 0;
-
-	for (u = v; u != NULL; u = u->next) {
-		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
-		uint16 veh_len;
-
-		// Update the v->first cache. This is faster than having to brute force it later.
-		if (u->first == NULL) u->first = v;
-
-		// update the 'first engine'
-		u->u.rail.first_engine = (v == u) ? INVALID_ENGINE : first_engine;
-		u->u.rail.railtype = GetEngine(u->engine_type)->railtype;
-
-		if (IsTrainEngine(u)) first_engine = u->engine_type;
-
-		if (rvi_u->visual_effect != 0) {
-			u->u.rail.cached_vis_effect = rvi_u->visual_effect;
-		} else {
-			if (IsTrainWagon(u) || IsArticulatedPart(u)) {
-				// Wagons and articulated parts have no effect by default
-				u->u.rail.cached_vis_effect = 0x40;
-			} else if (rvi_u->engclass == 0) {
-				// Steam is offset by -4 units
-				u->u.rail.cached_vis_effect = 4;
-			} else {
-				// Diesel fumes and sparks come from the centre
-				u->u.rail.cached_vis_effect = 8;
-			}
-		}
-
-		if (!IsArticulatedPart(u)) {
-			// check if its a powered wagon
-			CLRBIT(u->u.rail.flags, VRF_POWEREDWAGON);
-
-			/* Check powered wagon / visual effect callback */
-			if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_WAGON_POWER)) {
-				uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
-
-				if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback;
-			}
-
-			if ((rvi_v->pow_wag_power != 0) && (rvi_u->flags & RVI_WAGON) && UsesWagonOverride(u)) {
-				if (u->u.rail.cached_vis_effect < 0x40) {
-					/* wagon is powered */
-					SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
-				}
-			}
-
-			/* Do not count powered wagons for the compatible railtypes, as wagons always
-			   have railtype normal */
-			if (rvi_u->power > 0) {
-				v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
-			}
-
-			/* Some electric engines can be allowed to run on normal rail. It happens to all
-			 * existing electric engines when elrails are disabled and then re-enabled */
-			if (HASBIT(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
-				u->u.rail.railtype = RAILTYPE_RAIL;
-				u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
-			}
-
-			// max speed is the minimum of the speed limits of all vehicles in the consist
-			if (!(rvi_u->flags & RVI_WAGON) || _patches.wagon_speed_limits)
-				if (rvi_u->max_speed != 0 && !UsesWagonOverride(u))
-					max_speed = min(rvi_u->max_speed, max_speed);
-		}
-
-		// check the vehicle length (callback)
-		veh_len = CALLBACK_FAILED;
-		if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
-			veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
-		}
-		if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
-		veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
-		u->u.rail.cached_veh_length = 8 - veh_len;
-		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
-
-	};
-
-	// store consist weight/max speed in cache
-	v->u.rail.cached_max_speed = max_speed;
-
-	// recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added)
-	TrainCargoChanged(v);
-}
-
-/* These two arrays are used for realistic acceleration. XXX: How should they
- * be interpreted? */
-static const byte _curve_neighbours45[8][2] = {
-	{7, 1},
-	{0, 2},
-	{1, 3},
-	{2, 4},
-	{3, 5},
-	{4, 6},
-	{5, 7},
-	{6, 0},
-};
-
-static const byte _curve_neighbours90[8][2] = {
-	{6, 2},
-	{7, 3},
-	{0, 4},
-	{1, 5},
-	{2, 6},
-	{3, 7},
-	{4, 0},
-	{5, 1},
-};
-
-enum AccelType {
-	AM_ACCEL,
-	AM_BRAKE
-};
-
-static bool TrainShouldStop(const Vehicle* v, TileIndex tile)
-{
-	const Order* o = &v->current_order;
-	StationID sid = GetStationIndex(tile);
-
-	assert(v->type == VEH_Train);
-	//When does a train drive through a station
-	//first we deal with the "new nonstop handling"
-	if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) {
-		return false;
-	}
-
-	if (v->last_station_visited == sid) return false;
-
-	if (sid != o->dest && (o->flags & OF_NON_STOP || _patches.new_nonstop)) {
-		return false;
-	}
-
-	return true;
-}
-
-//new acceleration
-static int GetTrainAcceleration(Vehicle *v, bool mode)
-{
-	const Vehicle *u;
-	int num = 0; //number of vehicles, change this into the number of axles later
-	int power = 0;
-	int mass = 0;
-	int max_speed = 2000;
-	int area = 120;
-	int friction = 35; //[1e-3]
-	int drag_coeff = 20; //[1e-4]
-	int incl = 0;
-	int resistance;
-	int speed = v->cur_speed; //[mph]
-	int force = 0x3FFFFFFF;
-	int pos = 0;
-	int lastpos = -1;
-	int curvecount[2] = {0, 0};
-	int sum = 0;
-	int numcurve = 0;
-	int max_te = v->u.rail.cached_max_te; // [N]
-
-	speed *= 10;
-	speed /= 16;
-
-	//first find the curve speed limit
-	for (u = v; u->next != NULL; u = u->next, pos++) {
-		Direction dir = u->direction;
-		Direction ndir = u->next->direction;
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			if ( _curve_neighbours45[dir][i] == ndir) {
-				curvecount[i]++;
-				if (lastpos != -1) {
-					numcurve++;
-					sum += pos - lastpos;
-					if (pos - lastpos == 1) {
-						max_speed = 88;
-					}
-				}
-				lastpos = pos;
-			}
-		}
-
-		//if we have a 90 degree turn, fix the speed limit to 60
-		if (_curve_neighbours90[dir][0] == ndir ||
-				_curve_neighbours90[dir][1] == ndir) {
-			max_speed = 61;
-		}
-	}
-
-	if (numcurve > 0) sum /= numcurve;
-
-	if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) {
-		int total = curvecount[0] + curvecount[1];
-
-		if (curvecount[0] == 1 && curvecount[1] == 1) {
-			max_speed = 0xFFFF;
-		} else if (total > 1) {
-			max_speed = 232 - (13 - clamp(sum, 1, 12)) * (13 - clamp(sum, 1, 12));
-		}
-	}
-
-	max_speed += (max_speed / 2) * v->u.rail.railtype;
-
-	if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
-		if (TrainShouldStop(v, v->tile)) {
-			uint station_length = GetPlatformLength(v->tile, DirToDiagDir(v->direction));
-			int delta_v;
-
-			max_speed = 120;
-
-			delta_v = v->cur_speed / (station_length + 1);
-			if (v->max_speed > (v->cur_speed - delta_v))
-				max_speed = v->cur_speed - (delta_v / 10);
-
-			max_speed = max(max_speed, 25 * station_length);
-		}
-	}
-
-	mass = v->u.rail.cached_weight;
-	power = v->u.rail.cached_power * 746;
-	max_speed = min(max_speed, v->u.rail.cached_max_speed);
-
-	for (u = v; u != NULL; u = u->next) {
-		num++;
-		drag_coeff += 3;
-
-		if (u->u.rail.track == 0x80) max_speed = min(max_speed, 61);
-
-		if (HASBIT(u->u.rail.flags, VRF_GOINGUP)) {
-			incl += u->u.rail.cached_veh_weight * 60; //3% slope, quite a bit actually
-		} else if (HASBIT(u->u.rail.flags, VRF_GOINGDOWN)) {
-			incl -= u->u.rail.cached_veh_weight * 60;
-		}
-	}
-
-	v->max_speed = max_speed;
-
-	if (v->u.rail.railtype != RAILTYPE_MAGLEV) {
-		resistance = 13 * mass / 10;
-		resistance += 60 * num;
-		resistance += friction * mass * speed / 1000;
-		resistance += (area * drag_coeff * speed * speed) / 10000;
-	} else {
-		resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
-	}
-	resistance += incl;
-	resistance *= 4; //[N]
-
-	/* Due to the mph to m/s conversion below, at speeds below 3 mph the force is
-	 * actually double the train's power */
-	if (speed > 2) {
-		switch (v->u.rail.railtype) {
-			case RAILTYPE_RAIL:
-			case RAILTYPE_ELECTRIC:
-			case RAILTYPE_MONO:
-				force = power / speed; //[N]
-				force *= 22;
-				force /= 10;
-				if (mode == AM_ACCEL && force > max_te) force = max_te;
-				break;
-
-			case RAILTYPE_MAGLEV:
-				force = power / 25;
-				break;
-		}
-	} else {
-		//"kickoff" acceleration
-		force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
-		force = max(force, (mass * 8) + resistance);
-	}
-
-	if (force <= 0) force = 10000;
-
-	if (v->u.rail.railtype != RAILTYPE_MAGLEV) force = min(force, mass * 10 * 200);
-
-	if (mode == AM_ACCEL) {
-		return (force - resistance) / (mass * 4);
-	} else {
-		return min((-force - resistance) / (mass * 4), -10000 / (mass * 4));
-	}
-}
-
-static void UpdateTrainAcceleration(Vehicle* v)
-{
-	uint power = 0;
-	uint weight = 0;
-
-	assert(IsFrontEngine(v));
-
-	weight = v->u.rail.cached_weight;
-	power = v->u.rail.cached_power;
-	v->max_speed = v->u.rail.cached_max_speed;
-
-	assert(weight != 0);
-
-	v->acceleration = clamp(power / weight * 4, 1, 255);
-}
-
-int GetTrainImage(const Vehicle* v, Direction direction)
-{
-	int img = v->spritenum;
-	int base;
-
-	if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
-
-	if (is_custom_sprite(img)) {
-		base = GetCustomVehicleSprite(v, direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img));
-		if (base != 0) return base;
-		img = orig_rail_vehicle_info[v->engine_type].image_index;
-	}
-
-	base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
-
-	if (v->cargo_count >= v->cargo_cap / 2) base += _wagon_full_adder[img];
-	return base;
-}
-
-void DrawTrainEngine(int x, int y, EngineID engine, uint32 image_ormod)
-{
-	const RailVehicleInfo *rvi = RailVehInfo(engine);
-
-	int img = rvi->image_index;
-	uint32 image = 0;
-
-	if (is_custom_sprite(img)) {
-		image = GetCustomVehicleIcon(engine, DIR_W);
-		if (image == 0) {
-			img = orig_rail_vehicle_info[engine].image_index;
-		} else {
-			y += _traininfo_vehicle_pitch;
-		}
-	}
-	if (image == 0) {
-		image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img];
-	}
-
-	if (rvi->flags & RVI_MULTIHEAD) {
-		DrawSprite(image | image_ormod, x - 14, y);
-		x += 15;
-		image = 0;
-		if (is_custom_sprite(img)) {
-			image = GetCustomVehicleIcon(engine, 2);
-			if (image == 0) img = orig_rail_vehicle_info[engine].image_index;
-		}
-		if (image == 0) {
-			image =
-				((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) +
-				_engine_sprite_base[img + 1];
-		}
-	}
-	DrawSprite(image | image_ormod, x, y);
-}
-
-uint CountArticulatedParts(EngineID engine_type)
-{
-	uint16 callback;
-	uint i;
-
-	if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0;
-
-	for (i = 1; i < 10; i++) {
-		callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, engine_type, NULL);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
-	}
-
-	return i - 1;
-}
-
-static void AddArticulatedParts(Vehicle **vl)
-{
-	const RailVehicleInfo *rvi_artic;
-	EngineID engine_type;
-	Vehicle *v = vl[0];
-	Vehicle *u = v;
-	uint16 callback;
-	bool flip_image;
-	uint i;
-
-	if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return;
-
-	for (i = 1; i < 10; i++) {
-		callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, v->engine_type, v);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) return;
-
-		/* Attempt to use pre-allocated vehicles until they run out. This can happen
-		 * if the callback returns different values depending on the cargo type. */
-		u->next = vl[i];
-		if (u->next == NULL) u->next = AllocateVehicle();
-		if (u->next == NULL) return;
-
-		u = u->next;
-
-		engine_type = GB(callback, 0, 7);
-		flip_image = HASBIT(callback, 7);
-		rvi_artic = RailVehInfo(engine_type);
-
-		// get common values from first engine
-		u->direction = v->direction;
-		u->owner = v->owner;
-		u->tile = v->tile;
-		u->x_pos = v->x_pos;
-		u->y_pos = v->y_pos;
-		u->z_pos = v->z_pos;
-		u->z_height = v->z_height;
-		u->u.rail.track = v->u.rail.track;
-		u->u.rail.railtype = v->u.rail.railtype;
-		u->build_year = v->build_year;
-		u->vehstatus = v->vehstatus & ~VS_STOPPED;
-		u->u.rail.first_engine = v->engine_type;
-
-		// get more settings from rail vehicle info
-		u->spritenum = rvi_artic->image_index;
-		if (flip_image) u->spritenum++;
-		u->cargo_type = rvi_artic->cargo_type;
-		u->cargo_subtype = 0;
-		u->cargo_cap = rvi_artic->capacity;
-		u->max_speed = 0;
-		u->max_age = 0;
-		u->engine_type = engine_type;
-		u->value = 0;
-		u->type = VEH_Train;
-		u->subtype = 0;
-		SetArticulatedPart(u);
-		u->cur_image = 0xAC2;
-		u->random_bits = VehicleRandomBits();
-
-		VehiclePositionChanged(u);
-	}
-}
-
-static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
-{
-	int32 value;
-	const RailVehicleInfo *rvi;
-	uint num_vehicles;
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	rvi = RailVehInfo(engine);
-	value = (rvi->base_cost * _price.build_railwagon) >> 8;
-
-	num_vehicles = 1 + CountArticulatedParts(engine);
-
-	if (!(flags & DC_QUERY_COST)) {
-		Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts.
-		Vehicle* v;
-		int x;
-		int y;
-
-		memset(&vl, 0, sizeof(vl));
-
-		if (!AllocateVehicles(vl, num_vehicles))
-			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-		if (flags & DC_EXEC) {
-			Vehicle *u, *w;
-			DiagDirection dir;
-
-			v = vl[0];
-			v->spritenum = rvi->image_index;
-
-			u = NULL;
-
-			FOR_ALL_VEHICLES(w) {
-				if (w->type == VEH_Train && w->tile == tile &&
-				    IsFreeWagon(w) && w->engine_type == engine) {
-					u = GetLastVehicleInChain(w);
-					break;
-				}
-			}
-
-			v->engine_type = engine;
-
-			dir = GetRailDepotDirection(tile);
-
-			v->direction = DiagDirToDir(dir);
-			v->tile = tile;
-
-			x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
-			y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
-
-			v->x_pos = x;
-			v->y_pos = y;
-			v->z_pos = GetSlopeZ(x,y);
-			v->owner = _current_player;
-			v->z_height = 6;
-			v->u.rail.track = 0x80;
-			v->vehstatus = VS_HIDDEN | VS_DEFPAL;
-
-			v->subtype = 0;
-			SetTrainWagon(v);
-			if (u != NULL) {
-				u->next = v;
-			} else {
-				SetFreeWagon(v);
-				InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-			}
-
-			v->cargo_type = rvi->cargo_type;
-			v->cargo_subtype = 0;
-			v->cargo_cap = rvi->capacity;
-			v->value = value;
-//			v->day_counter = 0;
-
-			v->u.rail.railtype = GetEngine(engine)->railtype;
-
-			v->build_year = _cur_year;
-			v->type = VEH_Train;
-			v->cur_image = 0xAC2;
-			v->random_bits = VehicleRandomBits();
-
-			AddArticulatedParts(vl);
-
-			_new_vehicle_id = v->index;
-
-			VehiclePositionChanged(v);
-			TrainConsistChanged(GetFirstVehicleInChain(v));
-			GetPlayer(_current_player)->num_engines[engine]++;
-
-			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-			if (IsLocalPlayer()) {
-				InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
-			}
-		}
-	}
-
-	return value;
-}
-
-// Move all free vehicles in the depot to the train
-static void NormalizeTrainVehInDepot(const Vehicle* u)
-{
-	const Vehicle* v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && IsFreeWagon(v) &&
-				v->tile == u->tile &&
-				v->u.rail.track == 0x80) {
-			if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
-					CMD_MOVE_RAIL_VEHICLE)))
-				break;
-		}
-	}
-}
-
-static int32 EstimateTrainCost(const RailVehicleInfo* rvi)
-{
-	return rvi->base_cost * (_price.build_railvehicle >> 3) >> 5;
-}
-
-static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
-{
-	u->direction = v->direction;
-	u->owner = v->owner;
-	u->tile = v->tile;
-	u->x_pos = v->x_pos;
-	u->y_pos = v->y_pos;
-	u->z_pos = v->z_pos;
-	u->z_height = 6;
-	u->u.rail.track = 0x80;
-	u->vehstatus = v->vehstatus & ~VS_STOPPED;
-	u->subtype = 0;
-	SetMultiheaded(u);
-	u->spritenum = v->spritenum + 1;
-	u->cargo_type = v->cargo_type;
-	u->cargo_subtype = v->cargo_subtype;
-	u->cargo_cap = v->cargo_cap;
-	u->u.rail.railtype = v->u.rail.railtype;
-	if (building) v->next = u;
-	u->engine_type = v->engine_type;
-	u->build_year = v->build_year;
-	if (building) v->value >>= 1;
-	u->value = v->value;
-	u->type = VEH_Train;
-	u->cur_image = 0xAC2;
-	u->random_bits = VehicleRandomBits();
-	VehiclePositionChanged(u);
-}
-
-/** Build a railroad vehicle.
- * @param tile tile of the depot where rail-vehicle is built
- * @param p1 engine type id
- * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number
- *           bit 1 prevents any free cars from being added to the train
- */
-int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	const RailVehicleInfo *rvi;
-	int value;
-	Vehicle *v;
-	UnitID unit_num;
-	Engine *e;
-	uint num_vehicles;
-
-	/* Check if the engine-type is valid (for the player) */
-	if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
-
-	/* Check if the train is actually being built in a depot belonging
-	 * to the player. Doesn't matter if only the cost is queried */
-	if (!(flags & DC_QUERY_COST)) {
-		if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR;
-		if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
-	}
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	rvi = RailVehInfo(p1);
-	e = GetEngine(p1);
-
-	/* Check if depot and new engine uses the same kind of tracks */
-	/* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
-	if (!HasPowerOnRail(e->railtype, GetRailType(tile))) return CMD_ERROR;
-
-	if (rvi->flags & RVI_WAGON) return CmdBuildRailWagon(p1, tile, flags);
-
-	value = EstimateTrainCost(rvi);
-
-	num_vehicles = (rvi->flags & RVI_MULTIHEAD) ? 2 : 1;
-	num_vehicles += CountArticulatedParts(p1);
-
-	if (!(flags & DC_QUERY_COST)) {
-		Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads
-
-		memset(&vl, 0, sizeof(vl));
-
-		if (!AllocateVehicles(vl, num_vehicles) || IsOrderPoolFull())
-			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-		v = vl[0];
-
-		unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train);
-		if (unit_num > _patches.max_trains)
-			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-		if (flags & DC_EXEC) {
-			DiagDirection dir = GetRailDepotDirection(tile);
-			int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
-			int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
-
-			v->unitnumber = unit_num;
-			v->direction = DiagDirToDir(dir);
-			v->tile = tile;
-			v->owner = _current_player;
-			v->x_pos = x;
-			v->y_pos = y;
-			v->z_pos = GetSlopeZ(x,y);
-			v->z_height = 6;
-			v->u.rail.track = 0x80;
-			v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
-			v->spritenum = rvi->image_index;
-			v->cargo_type = rvi->cargo_type;
-			v->cargo_subtype = 0;
-			v->cargo_cap = rvi->capacity;
-			v->max_speed = rvi->max_speed;
-			v->value = value;
-			v->last_station_visited = INVALID_STATION;
-			v->dest_tile = 0;
-
-			v->engine_type = p1;
-
-			v->reliability = e->reliability;
-			v->reliability_spd_dec = e->reliability_spd_dec;
-			v->max_age = e->lifelength * 366;
-
-			v->string_id = STR_SV_TRAIN_NAME;
-			v->u.rail.railtype = e->railtype;
-			_new_vehicle_id = v->index;
-
-			v->service_interval = _patches.servint_trains;
-			v->date_of_last_service = _date;
-			v->build_year = _cur_year;
-			v->type = VEH_Train;
-			v->cur_image = 0xAC2;
-			v->random_bits = VehicleRandomBits();
-
-			v->subtype = 0;
-			SetFrontEngine(v);
-			SetTrainEngine(v);
-
-			VehiclePositionChanged(v);
-
-			if (rvi->flags & RVI_MULTIHEAD) {
-				SetMultiheaded(v);
-				AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
-				/* Now we need to link the front and rear engines together
-				 * other_multiheaded_part is the pointer that links to the other half of the engine
-				 * vl[0] is the front and vl[1] is the rear
-				 */
-				vl[0]->u.rail.other_multiheaded_part = vl[1];
-				vl[1]->u.rail.other_multiheaded_part = vl[0];
-			} else {
-				AddArticulatedParts(vl);
-			}
-
-			TrainConsistChanged(v);
-			UpdateTrainAcceleration(v);
-
-			if (!HASBIT(p2, 1)) { // check if the cars should be added to the new vehicle
-				NormalizeTrainVehInDepot(v);
-			}
-
-			GetPlayer(_current_player)->num_engines[p1]++;
-			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-			RebuildVehicleLists();
-			InvalidateWindow(WC_COMPANY, v->owner);
-			if (IsLocalPlayer()) {
-				InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
-			}
-		}
-	}
-
-	return value;
-}
-
-
-/* Check if all the wagons of the given train are in a depot, returns the
- * number of cars (including loco) then. If not it returns -1 */
-int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped)
-{
-	int count;
-	TileIndex tile = v->tile;
-
-	/* check if stopped in a depot */
-	if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1;
-
-	count = 0;
-	for (; v != NULL; v = v->next) {
-		/* This count is used by the depot code to determine the number of engines
-		 * in the consist. Exclude articulated parts so that autoreplacing to
-		 * engines with more articulated parts than before works correctly.
-		 *
-		 * Also skip counting rear ends of multiheaded engines */
-		if (!IsArticulatedPart(v) && !(!IsTrainEngine(v) && IsMultiheaded(v))) count++;
-		if (v->u.rail.track != 0x80 || v->tile != tile ||
-				(IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
-			return -1;
-		}
-	}
-
-	return count;
-}
-
-/* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
-inline int CheckTrainStoppedInDepot(const Vehicle *v)
-{
-	return CheckTrainInDepot(v, true);
-}
-
-/* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
-inline bool CheckTrainIsInsideDepot(const Vehicle *v)
-{
-	return (CheckTrainInDepot(v, false) > 0);
-}
-
-/**
- * Unlink a rail wagon from the consist.
- * @param v Vehicle to remove.
- * @param first The first vehicle of the consist.
- * @return The first vehicle of the consist.
- */
-static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
-{
-	Vehicle *u;
-
-	// unlinking the first vehicle of the chain?
-	if (v == first) {
-		v = GetNextVehicle(v);
-		if (v == NULL) return NULL;
-
-		if (IsTrainWagon(v)) SetFreeWagon(v);
-
-		return v;
-	}
-
-	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
-	GetLastEnginePart(u)->next = GetNextVehicle(v);
-	return first;
-}
-
-static Vehicle *FindGoodVehiclePos(const Vehicle *src)
-{
-	Vehicle *dst;
-	EngineID eng = src->engine_type;
-	TileIndex tile = src->tile;
-
-	FOR_ALL_VEHICLES(dst) {
-		if (dst->type == VEH_Train && IsFreeWagon(dst) && dst->tile == tile) {
-			// check so all vehicles in the line have the same engine.
-			Vehicle *v = dst;
-
-			while (v->engine_type == eng) {
-				v = v->next;
-				if (v == NULL) return dst;
-			}
-		}
-	}
-
-	return NULL;
-}
-
-/*
- * add a vehicle v behind vehicle dest
- * use this function since it sets flags as needed
- */
-static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
-{
-	UnlinkWagon(v, GetFirstVehicleInChain(v));
-	if (dest == NULL) return;
-
-	v->next = dest->next;
-	dest->next = v;
-	ClearFreeWagon(v);
-	ClearFrontEngine(v);
-}
-
-/*
- * move around on the train so rear engines are placed correctly according to the other engines
- * always call with the front engine
- */
-static void NormaliseTrainConsist(Vehicle *v)
-{
-	Vehicle *u;
-
-	if (IsFreeWagon(v)) return;
-
-	assert(IsFrontEngine(v));
-
-	for (; v != NULL; v = GetNextVehicle(v)) {
-		if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
-
-		/* make sure that there are no free cars before next engine */
-		for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next);
-
-		if (u == v->u.rail.other_multiheaded_part) continue;
-		AddWagonToConsist(v->u.rail.other_multiheaded_part, u);
-	}
-}
-
-/** Move a rail vehicle around inside the depot.
- * @param tile unused
- * @param p1 various bitstuffed elements
- * - p1 (bit  0 - 15) source vehicle index
- * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line
- * @param p2 (bit 0) move all vehicles following the source vehicle
- */
-int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	VehicleID s = GB(p1, 0, 16);
-	VehicleID d = GB(p1, 16, 16);
-	Vehicle *src, *dst, *src_head, *dst_head;
-
-	if (!IsValidVehicleID(s)) return CMD_ERROR;
-
-	src = GetVehicle(s);
-
-	if (src->type != VEH_Train) return CMD_ERROR;
-
-	// if nothing is selected as destination, try and find a matching vehicle to drag to.
-	if (d == INVALID_VEHICLE) {
-		dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
-	} else {
-		dst = GetVehicle(d);
-	}
-
-	// if an articulated part is being handled, deal with its parent vehicle
-	while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src);
-	if (dst != NULL) {
-		while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst);
-	}
-
-	// don't move the same vehicle..
-	if (src == dst) return 0;
-
-	/* the player must be the owner */
-	if (!CheckOwnership(src->owner) || (dst != NULL && !CheckOwnership(dst->owner)))
-		return CMD_ERROR;
-
-	/* locate the head of the two chains */
-	src_head = GetFirstVehicleInChain(src);
-	dst_head = NULL;
-	if (dst != NULL) {
-		dst_head = GetFirstVehicleInChain(dst);
-		// Now deal with articulated part of destination wagon
-		dst = GetLastEnginePart(dst);
-	}
-
-	if (dst != NULL && IsMultiheaded(dst) && !IsTrainEngine(dst) && IsTrainWagon(src)) {
-		/* We are moving a wagon to the rear part of a multiheaded engine */
-		if (dst->next == NULL) {
-			/* It's the last one, so we will add the wagon just before the rear engine */
-			dst = GetPrevVehicleInChain(dst);
-			/* Now if the vehicle we want to link to is the vehicle itself, drop out */
-			if (dst == src) return CMD_ERROR;
-			// if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that
-			if (dst == NULL) return CMD_ERROR;
-		} else {
-			/* there are more units on this train, so we will add the wagon after the next one*/
-			dst = dst->next;
-		}
-	}
-
-	if (IsTrainEngine(src) && dst_head != NULL) {
-		/* we need to make sure that we didn't place it between a pair of multiheaded engines */
-		Vehicle *u, *engine = NULL;
-
-		for (u = dst_head; u != NULL; u = u->next) {
-			if (IsTrainEngine(u) && IsMultiheaded(u) && u->u.rail.other_multiheaded_part != NULL) {
-				engine = u;
-			}
-			if (engine != NULL && engine->u.rail.other_multiheaded_part == u) {
-				engine = NULL;
-			}
-			if (u == dst) {
-				if (engine != NULL) dst = engine->u.rail.other_multiheaded_part;
-				break;
-			}
-		}
-	}
-
-	if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
-
-	// when moving all wagons, we can't have the same src_head and dst_head
-	if (HASBIT(p2, 0) && src_head == dst_head) return 0;
-
-	{
-		int src_len = 0;
-		int max_len = _patches.mammoth_trains ? 100 : 9;
-
-		// check if all vehicles in the source train are stopped inside a depot.
-		src_len = CheckTrainStoppedInDepot(src_head);
-		if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
-
-		// check the destination row if the source and destination aren't the same.
-		if (src_head != dst_head) {
-			int dst_len = 0;
-
-			if (dst_head != NULL) {
-				// check if all vehicles in the dest train are stopped.
-				dst_len = CheckTrainStoppedInDepot(dst_head);
-				if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
-
-				assert(dst_head->tile == src_head->tile);
-			}
-
-			// We are moving between rows, so only count the wagons from the source
-			// row that are being moved.
-			if (HASBIT(p2, 0)) {
-				const Vehicle *u;
-				for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
-					src_len--;
-			} else {
-				// If moving only one vehicle, just count that.
-				src_len = 1;
-			}
-
-			if (src_len + dst_len > max_len) {
-				// Abort if we're adding too many wagons to a train.
-				if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
-				// Abort if we're making a train on a new row.
-				if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
-			}
-		} else {
-			// Abort if we're creating a new train on an existing row.
-			if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
-				return_cmd_error(STR_8819_TRAIN_TOO_LONG);
-		}
-	}
-
-	// moving a loco to a new line?, then we need to assign a unitnumber.
-	if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
-		UnitID unit_num = GetFreeUnitNumber(VEH_Train);
-		if (unit_num > _patches.max_trains)
-			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-
-		if (flags & DC_EXEC) src->unitnumber = unit_num;
-	}
-
-	if (dst_head != NULL) {
-		/* Check NewGRF Callback 0x1D */
-		uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, src, dst_head);
-		if (callback != CALLBACK_FAILED) {
-			if (callback == 0xFD) return_cmd_error(STR_INCOMPATIBLE_RAIL_TYPES);
-			if (callback < 0xFD) {
-				StringID error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback);
-				return_cmd_error(error);
-			}
-		}
-	}
-
-	/* do it? */
-	if (flags & DC_EXEC) {
-		/* clear the ->first cache */
-		{
-			Vehicle *u;
-
-			for (u = src_head; u != NULL; u = u->next) u->first = NULL;
-			for (u = dst_head; u != NULL; u = u->next) u->first = NULL;
-		}
-
-		if (HASBIT(p2, 0)) {
-			// unlink ALL wagons
-			if (src != src_head) {
-				Vehicle *v = src_head;
-				while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
-				GetLastEnginePart(v)->next = NULL;
-			} else {
-				InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
-				src_head = NULL;
-			}
-		} else {
-			// if moving within the same chain, dont use dst_head as it may get invalidated
-			if (src_head == dst_head) dst_head = NULL;
-			// unlink single wagon from linked list
-			src_head = UnlinkWagon(src, src_head);
-			GetLastEnginePart(src)->next = NULL;
-		}
-
-		if (dst == NULL) {
-			/* We make a new line in the depot, so we know already that we invalidate the window data */
-			InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
-
-			// move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4.
-			if (IsTrainEngine(src)) {
-				if (!IsFrontEngine(src)) {
-					// setting the type to 0 also involves setting up the orders field.
-					SetFrontEngine(src);
-					assert(src->orders == NULL);
-					src->num_orders = 0;
-				}
-			} else {
-				SetFreeWagon(src);
-			}
-			dst_head = src;
-		} else {
-			if (IsFrontEngine(src)) {
-				// the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
-				DeleteWindowById(WC_VEHICLE_VIEW, src->index);
-				DeleteVehicleOrders(src);
-			}
-
-			if (IsFrontEngine(src) || IsFreeWagon(src)) {
-				InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
-				ClearFrontEngine(src);
-				ClearFreeWagon(src);
-				src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
-			}
-
-			// link in the wagon(s) in the chain.
-			{
-				Vehicle *v;
-
-				for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v));
-				GetLastEnginePart(v)->next = dst->next;
-			}
-			dst->next = src;
-		}
-		if (src->u.rail.other_multiheaded_part != NULL) {
-			if (src->u.rail.other_multiheaded_part == src_head) {
-				src_head = src_head->next;
-			}
-			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
-			// previous line set the front engine to the old front. We need to clear that
-			src->u.rail.other_multiheaded_part->first = NULL;
-		}
-
-		if (HASBIT(p2, 0) && src_head != NULL && src_head != src) {
-			/* if we stole a rear multiheaded engine, we better give it back to the front end */
-			Vehicle *engine = NULL, *u;
-			for (u = src_head; u != NULL; u = u->next) {
-				if (IsMultiheaded(u)) {
-					if (IsTrainEngine(u)) {
-						engine = u;
-						continue;
-					}
-					/* we got the rear engine to match with the front one */
-					engine = NULL;
-				}
-			}
-			if (engine != NULL && engine->u.rail.other_multiheaded_part != NULL) {
-				AddWagonToConsist(engine->u.rail.other_multiheaded_part, engine);
-				// previous line set the front engine to the old front. We need to clear that
-				engine->u.rail.other_multiheaded_part->first = NULL;
-			}
-		}
-
-		/* If there is an engine behind first_engine we moved away, it should become new first_engine
-		 * To do this, CmdMoveRailVehicle must be called once more
-		 * we can't loop forever here because next time we reach this line we will have a front engine */
-		if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
-			CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1);
-			src_head = NULL; // don't do anything more to this train since the new call will do it
-		}
-
-		if (src_head != NULL) {
-			NormaliseTrainConsist(src_head);
-			TrainConsistChanged(src_head);
-			if (IsFrontEngine(src_head)) {
-				UpdateTrainAcceleration(src_head);
-				InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
-				/* Update the refit button and window */
-				InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12);
-			}
-			/* Update the depot window */
-			InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
-		};
-
-		if (dst_head != NULL) {
-			NormaliseTrainConsist(dst_head);
-			TrainConsistChanged(dst_head);
-			if (IsFrontEngine(dst_head)) {
-				UpdateTrainAcceleration(dst_head);
-				InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
-				/* Update the refit button and window */
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12);
-				InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
-			}
-			/* Update the depot window */
-			InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
-		}
-
-		RebuildVehicleLists();
-	}
-
-	return 0;
-}
-
-/** Start/Stop a train.
- * @param tile unused
- * @param p1 train to start/stop
- * @param p2 unused
- */
-int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	uint16 callback;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	/* Check if this train can be started/stopped. The callback will fail or
-	 * return 0xFF if it can. */
-	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
-		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
-		return_cmd_error(error);
-	}
-
-	if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
-
-	if (flags & DC_EXEC) {
-		if (v->vehstatus & VS_STOPPED && v->u.rail.track == 0x80) {
-			DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT);
-		}
-
-		v->u.rail.days_since_order_progr = 0;
-		v->vehstatus ^= VS_STOPPED;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-	}
-	return 0;
-}
-
-/** Sell a (single) train wagon/engine.
- * @param tile unused
- * @param p1 the wagon/engine index
- * @param p2 the selling mode
- * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines)
- * - p2 = 1: sell the vehicle and all vehicles following it in the chain
-             if the wagon is dragged, don't delete the possibly belonging rear-engine to some front
- * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines;
- *           all wagons of the same type will go on the same line. Used by the AI currently
- */
-int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v, *tmp, *first;
-	Vehicle *new_f = NULL;
-	int32 cost = 0;
-
-	if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-
-	while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
-	first = GetFirstVehicleInChain(v);
-
-	// make sure the vehicle is stopped in the depot
-	if (CheckTrainStoppedInDepot(first) < 0) {
-		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
-	}
-
-	if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
-
-	if (flags & DC_EXEC) {
-		if (v == first && IsFrontEngine(first)) {
-			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
-		}
-		if (IsLocalPlayer() && (p1 == 1 || !(RailVehInfo(v->engine_type)->flags & RVI_WAGON))) {
-			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
-		}
-		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
-		RebuildVehicleLists();
-	}
-
-	switch (p2) {
-		case 0: case 2: { /* Delete given wagon */
-			bool switch_engine = false;    // update second wagon to engine?
-			byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes
-
-			/* 1. Delete the engine, if it is dualheaded also delete the matching
-			 * rear engine of the loco (from the point of deletion onwards) */
-			Vehicle *rear = (IsMultiheaded(v) &&
-				IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
-
-			if (rear != NULL) {
-				cost -= rear->value;
-				if (flags & DC_EXEC) {
-					UnlinkWagon(rear, first);
-					DeleteDepotHighlightOfVehicle(rear);
-					DeleteVehicle(rear);
-				}
-			}
-
-			/* 2. We are selling the first engine, some special action might be required
-			 * here, so take attention */
-			if ((flags & DC_EXEC) && v == first) {
-				new_f = GetNextVehicle(first);
-
-				/* 2.1 If the first wagon is sold, update the first-> pointers to NULL */
-				for (tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL;
-
-				/* 2.2 If there are wagons present after the deleted front engine, check
-         * if the second wagon (which will be first) is an engine. If it is one,
-         * promote it as a new train, retaining the unitnumber, orders */
-				if (new_f != NULL) {
-					if (IsTrainEngine(new_f)) {
-						switch_engine = true;
-						/* Copy important data from the front engine */
-						new_f->unitnumber = first->unitnumber;
-						new_f->current_order = first->current_order;
-						new_f->cur_order_index = first->cur_order_index;
-						new_f->orders = first->orders;
-						if (first->prev_shared != NULL) {
-							first->prev_shared->next_shared = new_f;
-							new_f->prev_shared = first->prev_shared;
-						}
-
-						if (first->next_shared != NULL) {
-							first->next_shared->prev_shared = new_f;
-							new_f->next_shared = first->next_shared;
-						}
-
-						new_f->num_orders = first->num_orders;
-						first->orders = NULL; // XXX - to not to delete the orders */
-						if (IsLocalPlayer()) ShowTrainViewWindow(new_f);
-					}
-				}
-			}
-
-			/* 3. Delete the requested wagon */
-			cost -= v->value;
-			if (flags & DC_EXEC) {
-				first = UnlinkWagon(v, first);
-				DeleteDepotHighlightOfVehicle(v);
-				DeleteVehicle(v);
-
-				/* 4 If the second wagon was an engine, update it to front_engine
-					* which UnlinkWagon() has changed to TS_Free_Car */
-				if (switch_engine) SetFrontEngine(first);
-
-				/* 5. If the train still exists, update its acceleration, window, etc. */
-				if (first != NULL) {
-					NormaliseTrainConsist(first);
-					TrainConsistChanged(first);
-					if (IsFrontEngine(first)) {
-						InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
-						InvalidateWindow(WC_VEHICLE_REFIT, first->index);
-						UpdateTrainAcceleration(first);
-					}
-				}
-
-
-				/* (6.) Borked AI. If it sells an engine it expects all wagons lined
-				 * up on a new line to be added to the newly built loco. Replace it is.
-				 * Totally braindead cause building a new engine adds all loco-less
-				 * engines to its train anyways */
-				if (p2 == 2 && HASBIT(ori_subtype, Train_Front)) {
-					for (v = first; v != NULL; v = tmp) {
-						tmp = GetNextVehicle(v);
-						DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-					}
-				}
-			}
-		} break;
-		case 1: { /* Delete wagon and all wagons after it given certain criteria */
-			/* Start deleting every vehicle after the selected one
-			 * If we encounter a matching rear-engine to a front-engine
-			 * earlier in the chain (before deletion), leave it alone */
-			for (; v != NULL; v = tmp) {
-				tmp = GetNextVehicle(v);
-
-				if (IsMultiheaded(v)) {
-					if (IsTrainEngine(v)) {
-						/* We got a front engine of a multiheaded set. Now we will sell the rear end too */
-						Vehicle *rear = v->u.rail.other_multiheaded_part;
-
-						if (rear != NULL) {
-							cost -= rear->value;
-							if (flags & DC_EXEC) {
-								first = UnlinkWagon(rear, first);
-								DeleteDepotHighlightOfVehicle(rear);
-								DeleteVehicle(rear);
-							}
-						}
-					} else if (v->u.rail.other_multiheaded_part != NULL) {
-						/* The front to this engine is earlier in this train. Do nothing */
-						continue;
-					}
-				}
-
-				cost -= v->value;
-				if (flags & DC_EXEC) {
-					first = UnlinkWagon(v, first);
-					DeleteDepotHighlightOfVehicle(v);
-					DeleteVehicle(v);
-				}
-			}
-
-			/* 3. If it is still a valid train after selling, update its acceleration and cached values */
-			if (flags & DC_EXEC && first != NULL) {
-				NormaliseTrainConsist(first);
-				TrainConsistChanged(first);
-				if (IsFrontEngine(first)) UpdateTrainAcceleration(first);
-				InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
-				InvalidateWindow(WC_VEHICLE_REFIT, first->index);
-			}
-		} break;
-	}
-	return cost;
-}
-
-static void UpdateTrainDeltaXY(Vehicle *v, Direction direction)
-{
-#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
-	static const uint32 _delta_xy_table[8] = {
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
-	};
-#undef MKIT
-
-	uint32 x = _delta_xy_table[direction];
-
-	v->x_offs        = GB(x,  0, 8);
-	v->y_offs        = GB(x,  8, 8);
-	v->sprite_width  = GB(x, 16, 8);
-	v->sprite_height = GB(x, 24, 8);
-}
-
-static void UpdateVarsAfterSwap(Vehicle *v)
-{
-	UpdateTrainDeltaXY(v, v->direction);
-	v->cur_image = GetTrainImage(v, v->direction);
-	BeginVehicleMove(v);
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-}
-
-static void SetLastSpeed(Vehicle* v, int spd)
-{
-	int old = v->u.rail.last_speed;
-	if (spd != old) {
-		v->u.rail.last_speed = spd;
-		if (_patches.vehicle_speed || (old == 0) != (spd == 0))
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-	}
-}
-
-static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2)
-{
-	byte flag1, flag2;
-
-	flag1 = *swap_flag1;
-	flag2 = *swap_flag2;
-
-	/* Clear the flags */
-	CLRBIT(*swap_flag1, VRF_GOINGUP);
-	CLRBIT(*swap_flag1, VRF_GOINGDOWN);
-	CLRBIT(*swap_flag2, VRF_GOINGUP);
-	CLRBIT(*swap_flag2, VRF_GOINGDOWN);
-
-	/* Reverse the rail-flags (if needed) */
-	if (HASBIT(flag1, VRF_GOINGUP)) {
-		SETBIT(*swap_flag2, VRF_GOINGDOWN);
-	} else if (HASBIT(flag1, VRF_GOINGDOWN)) {
-		SETBIT(*swap_flag2, VRF_GOINGUP);
-	}
-	if (HASBIT(flag2, VRF_GOINGUP)) {
-		SETBIT(*swap_flag1, VRF_GOINGDOWN);
-	} else if (HASBIT(flag2, VRF_GOINGDOWN)) {
-		SETBIT(*swap_flag1, VRF_GOINGUP);
-	}
-}
-
-static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
-{
-	Vehicle *a, *b;
-
-	/* locate vehicles to swap */
-	for (a = v; l != 0; l--) a = a->next;
-	for (b = v; r != 0; r--) b = b->next;
-
-	if (a != b) {
-		/* swap the hidden bits */
-		{
-			uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN);
-			b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus&VS_HIDDEN);
-			a->vehstatus = tmp;
-		}
-
-		/* swap variables */
-		swap_byte(&a->u.rail.track, &b->u.rail.track);
-		swap_byte(&a->direction, &b->direction);
-
-		/* toggle direction */
-		if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
-		if (!(b->u.rail.track & 0x80)) b->direction = ReverseDir(b->direction);
-
-		/* swap more variables */
-		swap_int32(&a->x_pos, &b->x_pos);
-		swap_int32(&a->y_pos, &b->y_pos);
-		swap_tile(&a->tile, &b->tile);
-		swap_byte(&a->z_pos, &b->z_pos);
-
-		SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags);
-
-		/* update other vars */
-		UpdateVarsAfterSwap(a);
-		UpdateVarsAfterSwap(b);
-
-		/* call the proper EnterTile function unless we are in a wormhole */
-		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
-		if (!(b->u.rail.track & 0x40)) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
-	} else {
-		if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
-		UpdateVarsAfterSwap(a);
-
-		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
-	}
-
-	/* Update train's power incase tiles were different rail type */
-	TrainPowerChanged(v);
-}
-
-/* Check if the vehicle is a train and is on the tile we are testing */
-static void *TestTrainOnCrossing(Vehicle *v, void *data)
-{
-	if (v->tile != *(const TileIndex*)data || v->type != VEH_Train) return NULL;
-	return v;
-}
-
-static void DisableTrainCrossing(TileIndex tile)
-{
-	if (IsLevelCrossingTile(tile) &&
-			VehicleFromPos(tile, &tile, TestTrainOnCrossing) == NULL && // empty?
-			IsCrossingBarred(tile)) {
-		UnbarCrossing(tile);
-		MarkTileDirtyByTile(tile);
-	}
-}
-
-/**
- * Advances wagons for train reversing, needed for variable length wagons.
- * Needs to be called once before the train is reversed, and once after it.
- * @param v First vehicle in chain
- * @param before Set to true for the call before reversing, false otherwise
- */
-static void AdvanceWagons(Vehicle *v, bool before)
-{
-	Vehicle* base;
-	Vehicle* first;
-	int length;
-
-	base = v;
-	first = base->next;
-	length = CountVehiclesInChain(v);
-
-	while (length > 2) {
-		Vehicle* last;
-		int differential;
-		int i;
-
-		// find pairwise matching wagon
-		// start<>end, start+1<>end-1, ...
-		last = first;
-		for (i = length - 3; i > 0; i--) last = last->next;
-
-		differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
-		if (before) differential *= -1;
-
-		if (differential > 0) {
-			Vehicle* tempnext;
-
-			// disconnect last car to make sure only this subset moves
-			tempnext = last->next;
-			last->next = NULL;
-
-			for (i = 0; i < differential; i++) TrainController(first, false);
-
-			last->next = tempnext;
-		}
-
-		base = first;
-		first = first->next;
-		length -= 2;
-	}
-}
-
-
-static void ReverseTrainDirection(Vehicle *v)
-{
-	int l = 0, r = -1;
-	Vehicle *u;
-
-	if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-	}
-
-	/* Check if we were approaching a rail/road-crossing */
-	{
-		TileIndex tile = v->tile;
-		DiagDirection dir = DirToDiagDir(v->direction);
-
-		/* Determine the diagonal direction in which we will exit this tile */
-		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) {
-			dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT);
-		}
-		/* Calculate next tile */
-		tile += TileOffsByDiagDir(dir);
-
-		/* Check if the train left a rail/road-crossing */
-		DisableTrainCrossing(tile);
-	}
-
-	// count number of vehicles
-	u = v;
-	do r++; while ( (u = u->next) != NULL );
-
-	AdvanceWagons(v, true);
-
-	/* swap start<>end, start+1<>end-1, ... */
-	do {
-		ReverseTrainSwapVeh(v, l++, r--);
-	} while (l <= r);
-
-	AdvanceWagons(v, false);
-
-	if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-	}
-
-	CLRBIT(v->u.rail.flags, VRF_REVERSING);
-}
-
-/** Reverse train.
- * @param tile unused
- * @param p1 train to reverse
- * @param p2 if true, reverse a unit in a train (needs to be in a depot)
- */
-int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (p2) {
-		// turn a single unit around
-		Vehicle *front;
-
-		if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) {
-			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
-		}
-
-		front = GetFirstVehicleInChain(v);
-		// make sure the vehicle is stopped in the depot
-		if (CheckTrainStoppedInDepot(front) < 0) {
-			return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
-		}
-
-		if (flags & DC_EXEC) {
-			TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION);
-			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		}
-	} else {
-		//turn the whole train around
-		if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR;
-
-		if (flags & DC_EXEC) {
-			if (_patches.realistic_acceleration && v->cur_speed != 0) {
-				TOGGLEBIT(v->u.rail.flags, VRF_REVERSING);
-			} else {
-				v->cur_speed = 0;
-				SetLastSpeed(v, 0);
-				ReverseTrainDirection(v);
-			}
-		}
-	}
-	return 0;
-}
-
-/** Force a train through a red signal
- * @param tile unused
- * @param p1 train to ignore the red signal
- * @param p2 unused
- */
-int32 CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
-
-	return 0;
-}
-
-/** Refits a train to the specified cargo type.
- * @param tile unused
- * @param p1 vehicle ID of the train to refit
- * param p2 various bitstuffed elements
- * - p2 = (bit 0-7) - the new cargo type to refit to
- * - p2 = (bit 8-15) - the new cargo subtype to refit to
- */
-int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	CargoID new_cid = GB(p2, 0, 8);
-	byte new_subtype = GB(p2, 8, 8);
-	Vehicle *v;
-	int32 cost;
-	uint num;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-	if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
-
-	/* Check cargo */
-	if (new_cid > NUM_CARGO) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
-
-	cost = 0;
-	num = 0;
-
-	do {
-		/* XXX: We also refit all the attached wagons en-masse if they
-		 * can be refitted. This is how TTDPatch does it.  TODO: Have
-		 * some nice [Refit] button near each wagon. --pasky */
-		if (!CanRefitTo(v->engine_type, new_cid)) continue;
-
-		if (v->cargo_cap != 0) {
-			const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
-			uint16 amount = CALLBACK_FAILED;
-
-			if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
-				/* Back up the vehicle's cargo type */
-				CargoID temp_cid = v->cargo_type;
-				byte temp_subtype = v->cargo_subtype;
-				v->cargo_type = new_cid;
-				v->cargo_subtype = new_subtype;
-				/* Check the refit capacity callback */
-				amount = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
-				/* Restore the original cargo type */
-				v->cargo_type = temp_cid;
-				v->cargo_subtype = temp_subtype;
-			}
-
-			if (amount == CALLBACK_FAILED) { // callback failed or not used, use default
-				CargoID old_cid = rvi->cargo_type;
-				/* normally, the capacity depends on the cargo type, a rail vehicle can
-				 * carry twice as much mail/goods as normal cargo, and four times as
-				 * many passengers
-				 */
-				amount = rvi->capacity;
-				switch (old_cid) {
-					case CT_PASSENGERS: break;
-					case CT_MAIL:
-					case CT_GOODS: amount *= 2; break;
-					default:       amount *= 4; break;
-				}
-				switch (new_cid) {
-					case CT_PASSENGERS: break;
-					case CT_MAIL:
-					case CT_GOODS: amount /= 2; break;
-					default:       amount /= 4; break;
-				}
-			};
-
-			if (amount != 0) {
-				if (new_cid != v->cargo_type) {
-					cost += GetRefitCost(v->engine_type);
-				}
-
-				num += amount;
-				if (flags & DC_EXEC) {
-					v->cargo_count = (v->cargo_type == new_cid) ? min(amount, v->cargo_count) : 0;
-					v->cargo_type = new_cid;
-					v->cargo_cap = amount;
-					v->cargo_subtype = new_subtype;
-					InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-					InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-					RebuildVehicleLists();
-				}
-			}
-		}
-	} while ((v = v->next) != NULL);
-
-	_returned_refit_capacity = num;
-
-	/* Update the train's cached variables */
-	if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1)));
-
-	return cost;
-}
-
-typedef struct TrainFindDepotData {
-	uint best_length;
-	TileIndex tile;
-	PlayerID owner;
-	/**
-	 * true if reversing is necessary for the train to get to this depot
-	 * This value is unused when new depot finding and NPF are both disabled
-	 */
-	bool reverse;
-} TrainFindDepotData;
-
-static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
-{
-	if (IsTileType(tile, MP_RAILWAY) &&
-			IsTileOwner(tile, tfdd->owner) &&
-			IsRailDepot(tile)) {
-		/* approximate number of tiles by dividing by DIAG_FACTOR */
-		tfdd->best_length = length / DIAG_FACTOR;
-		tfdd->tile = tile;
-		return true;
-	}
-
-	return false;
-}
-
-// returns the tile of a depot to goto to. The given vehicle must not be
-// crashed!
-static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
-{
-	TrainFindDepotData tfdd;
-	TileIndex tile = v->tile;
-
-	assert(!(v->vehstatus & VS_CRASHED));
-
-	tfdd.owner = v->owner;
-	tfdd.best_length = (uint)-1;
-	tfdd.reverse = false;
-
-	if (IsTileDepotType(tile, TRANSPORT_RAIL)){
-		tfdd.tile = tile;
-		tfdd.best_length = 0;
-		return tfdd;
-	}
-
-	if (_patches.yapf.rail_use_yapf) {
-		bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
-		tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND
-	} else if (_patches.new_pathfinding_all) {
-		NPFFoundTargetData ftd;
-		Vehicle* last = GetLastVehicleInChain(v);
-		Trackdir trackdir = GetVehicleTrackdir(v);
-		Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
-
-		assert (trackdir != INVALID_TRACKDIR);
-		ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
-		if (ftd.best_bird_dist == 0) {
-			/* Found target */
-			tfdd.tile = ftd.node.tile;
-			/* Our caller expects a number of tiles, so we just approximate that
-			 * number by this. It might not be completely what we want, but it will
-			 * work for now :-) We can possibly change this when the old pathfinder
-			 * is removed. */
-			tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
-			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
-		}
-	} else {
-		// search in the forward direction first.
-		DiagDirection i;
-
-		i = DirToDiagDir(v->direction);
-		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
-			i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
-		}
-		NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
-		if (tfdd.best_length == (uint)-1){
-			tfdd.reverse = true;
-			// search in backwards direction
-			i = ReverseDiagDir(DirToDiagDir(v->direction));
-			if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
-				i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
-			}
-			NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
-		}
-	}
-
-	return tfdd;
-}
-
-/** Send a train to a depot
- * @param tile unused
- * @param p1 train to send to the depot
- * @param p2 various bitmasked elements
- * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
- * - p2 bit 8-10 - VLW flag (for mass goto depot)
- */
-int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	TrainFindDepotData tfdd;
-
-	if (p2 & DEPOT_MASS_SEND) {
-		/* Mass goto depot requested */
-		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
-		return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
-	}
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
-
-	if (v->current_order.type == OT_GOTO_DEPOT) {
-		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
-			/* We called with a different DEPOT_SERVICE setting.
-			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
-			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
-			if (flags & DC_EXEC) {
-				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-			}
-			return 0;
-		}
-
-		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
-		if (flags & DC_EXEC) {
-			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-				v->u.rail.days_since_order_progr = 0;
-				v->cur_order_index++;
-			}
-
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return 0;
-	}
-
-	/* check if at a standstill (not stopped only) in a depot
-	 * the check is down here to make it possible to alter stop/service for trains entering the depot */
-	if (IsTileDepotType(v->tile, TRANSPORT_RAIL) && v->cur_speed == 0) return CMD_ERROR;
-
-	tfdd = FindClosestTrainDepot(v, 0);
-	if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO);
-
-	if (flags & DC_EXEC) {
-		v->dest_tile = tfdd.tile;
-		v->current_order.type = OT_GOTO_DEPOT;
-		v->current_order.flags = OF_NON_STOP;
-		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
-		v->current_order.dest = GetDepotByTile(tfdd.tile)->index;
-		v->current_order.refit_cargo = CT_INVALID;
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		/* If there is no depot in front, reverse automatically */
-		if (tfdd.reverse)
-			DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
-	}
-
-	return 0;
-}
-
-
-void OnTick_Train(void)
-{
-	_age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
-}
-
-static const int8 _vehicle_smoke_pos[8] = {
-	1, 1, 1, 0, -1, -1, -1, 0
-};
-
-static void HandleLocomotiveSmokeCloud(const Vehicle* v)
-{
-	const Vehicle* u;
-	bool sound = false;
-
-	if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2)
-		return;
-
-	u = v;
-
-	do {
-		EngineID engtype = v->engine_type;
-		int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
-		byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
-		bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6);
-		int x, y;
-
-		// no smoke?
-		if ((RailVehInfo(engtype)->flags & RVI_WAGON && effect_type == 0) ||
-				disable_effect ||
-				GetEngine(engtype)->railtype > RAILTYPE_ELECTRIC ||
-				v->vehstatus & VS_HIDDEN) {
-			continue;
-		}
-
-		// No smoke in depots or tunnels
-		if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue;
-
-		// No sparks for electric vehicles on nonelectrified tracks
-		if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile, GetVehicleTrackdir(v)))) continue;
-
-		if (effect_type == 0) {
-			// Use default effect type for engine class.
-			effect_type = RailVehInfo(engtype)->engclass;
-		} else {
-			effect_type--;
-		}
-
-		x = _vehicle_smoke_pos[v->direction] * effect_offset;
-		y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
-
-		if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
-			x = -x;
-			y = -y;
-		}
-
-		switch (effect_type) {
-		case 0:
-			// steam smoke.
-			if (GB(v->tick_counter, 0, 4) == 0) {
-				CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
-				sound = true;
-			}
-			break;
-
-		case 1:
-			// diesel smoke
-			if (u->cur_speed <= 40 && CHANCE16(15, 128)) {
-				CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
-				sound = true;
-			}
-			break;
-
-		case 2:
-			// blue spark
-			if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) {
-				CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
-				sound = true;
-			}
-			break;
-		}
-	} while ((v = v->next) != NULL);
-
-	if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
-}
-
-static void TrainPlayLeaveStationSound(const Vehicle* v)
-{
-	static const SoundFx sfx[] = {
-		SND_04_TRAIN,
-		SND_0A_TRAIN_HORN,
-		SND_0A_TRAIN_HORN
-	};
-
-	EngineID engtype = v->engine_type;
-
-	if (PlayVehicleSound(v, VSE_START)) return;
-
-	switch (GetEngine(engtype)->railtype) {
-		case RAILTYPE_RAIL:
-		case RAILTYPE_ELECTRIC:
-			SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
-			break;
-
-		case RAILTYPE_MONO: SndPlayVehicleFx(SND_47_MAGLEV_2, v); break;
-		case RAILTYPE_MAGLEV: SndPlayVehicleFx(SND_41_MAGLEV, v); break;
-	}
-}
-
-static bool CheckTrainStayInDepot(Vehicle *v)
-{
-	Vehicle *u;
-
-	// bail out if not all wagons are in the same depot or not in a depot at all
-	for (u = v; u != NULL; u = u->next) {
-		if (u->u.rail.track != 0x80 || u->tile != v->tile) return false;
-	}
-
-	// if the train got no power, then keep it in the depot
-	if (v->u.rail.cached_power == 0) {
-		v->vehstatus |= VS_STOPPED;
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		return true;
-	}
-
-	if (v->u.rail.force_proceed == 0) {
-		if (++v->load_unload_time_rem < 37) {
-			InvalidateWindowClasses(WC_TRAINS_LIST);
-			return true;
-		}
-
-		v->load_unload_time_rem = 0;
-
-		if (UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction))) {
-			InvalidateWindowClasses(WC_TRAINS_LIST);
-			return true;
-		}
-	}
-
-	VehicleServiceInDepot(v);
-	InvalidateWindowClasses(WC_TRAINS_LIST);
-	TrainPlayLeaveStationSound(v);
-
-	v->u.rail.track = 1;
-	if (v->direction & 2) v->u.rail.track = 2;
-
-	v->vehstatus &= ~VS_HIDDEN;
-	v->cur_speed = 0;
-
-	UpdateTrainDeltaXY(v, v->direction);
-	v->cur_image = GetTrainImage(v, v->direction);
-	VehiclePositionChanged(v);
-	UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
-	UpdateTrainAcceleration(v);
-	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-
-	return false;
-}
-
-/* Check for station tiles */
-typedef struct TrainTrackFollowerData {
-	TileIndex dest_coords;
-	StationID station_index; // station index we're heading for
-	uint best_bird_dist;
-	uint best_track_dist;
-	byte best_track;
-} TrainTrackFollowerData;
-
-static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length)
-{
-	// heading for nowhere?
-	if (ttfd->dest_coords == 0) return false;
-
-	// did we reach the final station?
-	if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || (
-				IsTileType(tile, MP_STATION) &&
-				IsRailwayStation(tile) &&
-				GetStationIndex(tile) == ttfd->station_index
-			)) {
-		/* We do not check for dest_coords if we have a station_index,
-		 * because in that case the dest_coords are just an
-		 * approximation of where the station is */
-		// found station
-		ttfd->best_track = track;
-		return true;
-	} else {
-		uint dist;
-
-		// didn't find station, keep track of the best path so far.
-		dist = DistanceManhattan(tile, ttfd->dest_coords);
-		if (dist < ttfd->best_bird_dist) {
-			ttfd->best_bird_dist = dist;
-			ttfd->best_track = track;
-		}
-		return false;
-	}
-}
-
-static void FillWithStationData(TrainTrackFollowerData* fd, const Vehicle* v)
-{
-	fd->dest_coords = v->dest_tile;
-	if (v->current_order.type == OT_GOTO_STATION) {
-		fd->station_index = v->current_order.dest;
-	} else {
-		fd->station_index = INVALID_STATION;
-	}
-}
-
-static const byte _initial_tile_subcoord[6][4][3] = {
-{{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0,  0, 0 }},
-{{  0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
-{{  0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0,  0, 0 }},
-{{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
-{{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0,  0, 0 }},
-{{  0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
-};
-
-static const uint32 _reachable_tracks[4] = {
-	0x10091009,
-	0x00160016,
-	0x05200520,
-	0x2A002A00,
-};
-
-static const byte _search_directions[6][4] = {
-	{ 0, 9, 2, 9 }, // track 1
-	{ 9, 1, 9, 3 }, // track 2
-	{ 9, 0, 3, 9 }, // track upper
-	{ 1, 9, 9, 2 }, // track lower
-	{ 3, 2, 9, 9 }, // track left
-	{ 9, 9, 1, 0 }, // track right
-};
-
-static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0};
-
-/* choose a track */
-static byte ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirbits)
-{
-	TrainTrackFollowerData fd;
-	uint best_track;
-	// pathfinders are able to tell that route was only 'guessed'
-	bool path_not_found = false;
-
-#ifdef PF_BENCHMARK
-	TIC()
-#endif
-
-	assert((trackdirbits & ~0x3F) == 0);
-
-	/* quick return in case only one possible track is available */
-	if (KILL_FIRST_BIT(trackdirbits) == 0) return FIND_FIRST_BIT(trackdirbits);
-
-	if (_patches.yapf.rail_use_yapf) {
-		Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, trackdirbits, &path_not_found);
-		if (trackdir != INVALID_TRACKDIR) {
-			best_track = TrackdirToTrack(trackdir);
-		} else {
-			best_track = FIND_FIRST_BIT(TrackdirBitsToTrackBits(trackdirbits));
-		}
-	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
-		void* perf = NpfBeginInterval();
-		int time = 0;
-
-		NPFFindStationOrTileData fstd;
-		NPFFoundTargetData ftd;
-		Trackdir trackdir;
-
-		NPFFillWithOrderData(&fstd, v);
-		/* The enterdir for the new tile, is the exitdir for the old tile */
-		trackdir = GetVehicleTrackdir(v);
-		assert(trackdir != 0xff);
-
-		ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
-
-		if (ftd.best_trackdir == 0xff) {
-			/* We are already at our target. Just do something */
-			//TODO: maybe display error?
-			//TODO: go straight ahead if possible?
-			best_track = FIND_FIRST_BIT(trackdirbits);
-		} else {
-			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
-			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
-			we did not find our target, but ftd.best_trackdir contains the direction leading
-			to the tile closest to our target. */
-			if (ftd.best_bird_dist != 0) path_not_found = true;
-			/* Discard enterdir information, making it a normal track */
-			best_track = TrackdirToTrack(ftd.best_trackdir);
-		}
-
-		time = NpfEndInterval(perf);
-		DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
-	} else {
-		void* perf = NpfBeginInterval();
-		int time = 0;
-
-		FillWithStationData(&fd, v);
-
-		/* New train pathfinding */
-		fd.best_bird_dist = (uint)-1;
-		fd.best_track_dist = (uint)-1;
-		fd.best_track = 0xFF;
-
-		NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile,
-			v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
-
-		// check whether the path was found or only 'guessed'
-		if (fd.best_bird_dist != 0) path_not_found = true;
-
-		if (fd.best_track == 0xff) {
-			// blaha
-			best_track = FIND_FIRST_BIT(trackdirbits);
-		} else {
-			best_track = fd.best_track & 7;
-		}
-
-		time = NpfEndInterval(perf);
-		DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
-	}
-	// handle "path not found" state
-	if (path_not_found) {
-		// PF didn't find the route
-		if (!HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
-			// it is first time the problem occurred, set the "path not found" flag
-			SETBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
-			// and notify user about the event
-			if (_patches.lost_train_warn && v->owner == _local_player) {
-				SetDParam(0, v->unitnumber);
-				AddNewsItem(
-					STR_TRAIN_IS_LOST,
-					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
-					v->index,
-					0);
-			}
-		}
-	} else {
-		// route found, is the train marked with "path not found" flag?
-		if (HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
-			// clear the flag as the PF's problem was solved
-			CLRBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
-			// can we also delete the "News" item somehow?
-		}
-	}
-
-#ifdef PF_BENCHMARK
-	TOC("PF time = ", 1)
-#endif
-
-	return best_track;
-}
-
-
-static bool CheckReverseTrain(Vehicle *v)
-{
-	TrainTrackFollowerData fd;
-	int i, r;
-	int best_track;
-	uint best_bird_dist  = 0;
-	uint best_track_dist = 0;
-	uint reverse, reverse_best;
-
-	if (_opt.diff.line_reverse_mode != 0 ||
-			v->u.rail.track & 0xC0 ||
-			!(v->direction & 1))
-		return false;
-
-	FillWithStationData(&fd, v);
-
-	best_track = -1;
-	reverse_best = reverse = 0;
-
-	assert(v->u.rail.track);
-
-	i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)];
-
-	if (_patches.yapf.rail_use_yapf) {
-		reverse_best = YapfCheckReverseTrain(v);
-	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
-		NPFFindStationOrTileData fstd;
-		NPFFoundTargetData ftd;
-		byte trackdir, trackdir_rev;
-		Vehicle* last = GetLastVehicleInChain(v);
-
-		NPFFillWithOrderData(&fstd, v);
-
-		trackdir = GetVehicleTrackdir(v);
-		trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
-		assert(trackdir != 0xff);
-		assert(trackdir_rev != 0xff);
-
-		ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
-		if (ftd.best_bird_dist != 0) {
-			/* We didn't find anything, just keep on going straight ahead */
-			reverse_best = false;
-		} else {
-			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
-				reverse_best = true;
-			} else {
-				reverse_best = false;
-			}
-		}
-	} else {
-		for (;;) {
-			fd.best_bird_dist = (uint)-1;
-			fd.best_track_dist = (uint)-1;
-
-			NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd);
-
-			if (best_track != -1) {
-				if (best_bird_dist != 0) {
-					if (fd.best_bird_dist != 0) {
-						/* neither reached the destination, pick the one with the smallest bird dist */
-						if (fd.best_bird_dist > best_bird_dist) goto bad;
-						if (fd.best_bird_dist < best_bird_dist) goto good;
-					} else {
-						/* we found the destination for the first time */
-						goto good;
-					}
-				} else {
-					if (fd.best_bird_dist != 0) {
-						/* didn't find destination, but we've found the destination previously */
-						goto bad;
-					} else {
-						/* both old & new reached the destination, compare track length */
-						if (fd.best_track_dist > best_track_dist) goto bad;
-						if (fd.best_track_dist < best_track_dist) goto good;
-					}
-				}
-
-				/* if we reach this position, there's two paths of equal value so far.
-				 * pick one randomly. */
-				r = GB(Random(), 0, 8);
-				if (_pick_track_table[i] == (v->direction & 3)) r += 80;
-				if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
-				if (r <= 127) goto bad;
-			}
-good:;
-			best_track = i;
-			best_bird_dist = fd.best_bird_dist;
-			best_track_dist = fd.best_track_dist;
-			reverse_best = reverse;
-bad:;
-			if (reverse != 0) break;
-			reverse = 2;
-		}
-	}
-
-	return reverse_best != 0;
-}
-
-static bool ProcessTrainOrder(Vehicle *v)
-{
-	const Order *order;
-	bool at_waypoint = false;
-
-	switch (v->current_order.type) {
-		case OT_GOTO_DEPOT:
-			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return false;
-			if ((v->current_order.flags & OF_SERVICE_IF_NEEDED) &&
-					!VehicleNeedsService(v)) {
-				v->cur_order_index++;
-			}
-			break;
-
-		case OT_LOADING:
-		case OT_LEAVESTATION:
-			return false;
-
-		default: break;
-	}
-
-	// check if we've reached the waypoint?
-	if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) {
-		v->cur_order_index++;
-		at_waypoint = true;
-	}
-
-	// check if we've reached a non-stop station while TTDPatch nonstop is enabled..
-	if (_patches.new_nonstop &&
-			v->current_order.flags & OF_NON_STOP &&
-			IsTileType(v->tile, MP_STATION) &&
-			v->current_order.dest == GetStationIndex(v->tile)) {
-		v->cur_order_index++;
-	}
-
-	// Get the current order
-	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
-
-	order = GetVehicleOrder(v, v->cur_order_index);
-
-	// If no order, do nothing.
-	if (order == NULL) {
-		v->current_order.type = OT_NOTHING;
-		v->current_order.flags = 0;
-		v->dest_tile = 0;
-		return false;
-	}
-
-	// If it is unchanged, keep it.
-	if (order->type  == v->current_order.type &&
-			order->flags == v->current_order.flags &&
-			order->dest  == v->current_order.dest)
-		return false;
-
-	// Otherwise set it, and determine the destination tile.
-	v->current_order = *order;
-
-	v->dest_tile = 0;
-
-	InvalidateVehicleOrder(v);
-
-	switch (order->type) {
-		case OT_GOTO_STATION:
-			if (order->dest == v->last_station_visited)
-				v->last_station_visited = INVALID_STATION;
-			v->dest_tile = GetStation(order->dest)->xy;
-			break;
-
-		case OT_GOTO_DEPOT:
-			v->dest_tile = GetDepot(order->dest)->xy;
-			break;
-
-		case OT_GOTO_WAYPOINT:
-			v->dest_tile = GetWaypoint(order->dest)->xy;
-			break;
-
-		default:
-			return false;
-	}
-
-	return !at_waypoint && CheckReverseTrain(v);
-}
-
-static void MarkTrainDirty(Vehicle *v)
-{
-	do {
-		v->cur_image = GetTrainImage(v, v->direction);
-		MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
-	} while ((v = v->next) != NULL);
-}
-
-static void HandleTrainLoading(Vehicle *v, bool mode)
-{
-	if (v->current_order.type == OT_NOTHING) return;
-
-	if (v->current_order.type != OT_DUMMY) {
-		if (v->current_order.type != OT_LOADING) return;
-		if (mode) return;
-
-		// don't mark the train as lost if we're loading on the final station.
-		if (v->current_order.flags & OF_NON_STOP)
-			v->u.rail.days_since_order_progr = 0;
-
-		if (--v->load_unload_time_rem) return;
-
-		if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
-				(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
-			v->u.rail.days_since_order_progr = 0; /* Prevent a train lost message for full loading trains */
-			SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
-			if (LoadUnloadVehicle(v, false)) {
-				InvalidateWindow(WC_TRAINS_LIST, v->owner);
-				MarkTrainDirty(v);
-
-				// need to update acceleration and cached values since the goods on the train changed.
-				TrainCargoChanged(v);
-				UpdateTrainAcceleration(v);
-			}
-			return;
-		}
-
-		TrainPlayLeaveStationSound(v);
-
-		{
-			Order b = v->current_order;
-			v->current_order.type = OT_LEAVESTATION;
-			v->current_order.flags = 0;
-
-			// If this was not the final order, don't remove it from the list.
-			if (!(b.flags & OF_NON_STOP)) return;
-		}
-	}
-
-	v->u.rail.days_since_order_progr = 0;
-	v->cur_order_index++;
-	InvalidateVehicleOrder(v);
-}
-
-static int UpdateTrainSpeed(Vehicle *v)
-{
-	uint spd;
-	uint accel;
-
-	if (v->vehstatus & VS_STOPPED || HASBIT(v->u.rail.flags, VRF_REVERSING)) {
-		if (_patches.realistic_acceleration) {
-			accel = GetTrainAcceleration(v, AM_BRAKE) * 2;
-		} else {
-			accel = v->acceleration * -2;
-		}
-	} else {
-		if (_patches.realistic_acceleration) {
-			accel = GetTrainAcceleration(v, AM_ACCEL);
-		} else {
-			accel = v->acceleration;
-		}
-	}
-
-	spd = v->subspeed + accel * 2;
-	v->subspeed = (byte)spd;
-	{
-		int tempmax = v->max_speed;
-		if (v->cur_speed > v->max_speed)
-			tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
-		v->cur_speed = spd = clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
-	}
-
-	if (!(v->direction & 1)) spd = spd * 3 >> 2;
-
-	spd += v->progress;
-	v->progress = (byte)spd;
-	return (spd >> 8);
-}
-
-static void TrainEnterStation(Vehicle *v, StationID station)
-{
-	Station *st;
-	uint32 flags;
-
-	v->last_station_visited = station;
-
-	/* check if a train ever visited this station before */
-	st = GetStation(station);
-	if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
-		st->had_vehicle_of_type |= HVOT_TRAIN;
-		SetDParam(0, st->index);
-		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
-		AddNewsItem(
-			STR_8801_CITIZENS_CELEBRATE_FIRST,
-			flags,
-			v->index,
-			0
-		);
-	}
-
-	// Did we reach the final destination?
-	if (v->current_order.type == OT_GOTO_STATION &&
-			v->current_order.dest == station) {
-		// Yeah, keep the load/unload flags
-		// Non Stop now means if the order should be increased.
-		v->current_order.type = OT_LOADING;
-		v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
-		v->current_order.flags |= OF_NON_STOP;
-	} else {
-		// No, just do a simple load
-		v->current_order.type = OT_LOADING;
-		v->current_order.flags = 0;
-	}
-	v->current_order.dest = 0;
-
-	SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
-	if (LoadUnloadVehicle(v, true) != 0) {
-		InvalidateWindow(WC_TRAINS_LIST, v->owner);
-		TrainCargoChanged(v);
-		UpdateTrainAcceleration(v);
-	}
-	MarkTrainDirty(v);
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-}
-
-static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
-{
-	byte new_z, old_z;
-
-	// need this hint so it returns the right z coordinate on bridges.
-	new_z = GetSlopeZ(v->x_pos, v->y_pos);
-
-	old_z = v->z_pos;
-	v->z_pos = new_z;
-
-	if (new_tile) {
-		CLRBIT(v->u.rail.flags, VRF_GOINGUP);
-		CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
-
-		if (new_z != old_z) {
-			TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
-
-			// XXX workaround, whole UP/DOWN detection needs overhaul
-			if (!IsTunnelTile(tile)) {
-				SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
-			}
-		}
-	}
-
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-	return old_z;
-}
-
-static const Direction _new_vehicle_direction_table[11] = {
-	DIR_N , DIR_NW, DIR_W , 0,
-	DIR_NE, DIR_N , DIR_SW, 0,
-	DIR_E , DIR_SE, DIR_S
-};
-
-static Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
-{
-	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
-							TileX(new_tile) - TileX(old_tile) + 1;
-	assert(offs < 11);
-	return _new_vehicle_direction_table[offs];
-}
-
-static Direction GetNewVehicleDirection(const Vehicle *v, int x, int y)
-{
-	uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1);
-	assert(offs < 11);
-	return _new_vehicle_direction_table[offs];
-}
-
-static int GetDirectionToVehicle(const Vehicle *v, int x, int y)
-{
-	byte offs;
-
-	x -= v->x_pos;
-	if (x >= 0) {
-		offs = (x > 2) ? 0 : 1;
-	} else {
-		offs = (x < -2) ? 2 : 1;
-	}
-
-	y -= v->y_pos;
-	if (y >= 0) {
-		offs += ((y > 2) ? 0 : 1) * 4;
-	} else {
-		offs += ((y < -2) ? 2 : 1) * 4;
-	}
-
-	assert(offs < 11);
-	return _new_vehicle_direction_table[offs];
-}
-
-/* Check if the vehicle is compatible with the specified tile */
-static bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
-{
-	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-		case MP_RAILWAY:
-		case MP_STATION:
-			// normal tracks, jump to owner check
-			break;
-
-		case MP_STREET:
-			// tracks over roads, do owner check of tracks
-			return
-				IsTileOwner(tile, v->owner) && (
-					!IsFrontEngine(v) ||
-					IsCompatibleRail(v->u.rail.railtype, GetRailTypeCrossing(tile))
-				);
-
-		default:
-			return true;
-	}
-
-	return
-		IsTileOwner(tile, v->owner) && (
-			!IsFrontEngine(v) ||
-			HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile))
-		);
-}
-
-typedef struct {
-	byte small_turn, large_turn;
-	byte z_up; // fraction to remove when moving up
-	byte z_down; // fraction to remove when moving down
-} RailtypeSlowdownParams;
-
-static const RailtypeSlowdownParams _railtype_slowdown[] = {
-	// normal accel
-	{256 / 4, 256 / 2, 256 / 4, 2}, // normal
-	{256 / 4, 256 / 2, 256 / 4, 2}, // electrified
-	{256 / 4, 256 / 2, 256 / 4, 2}, // monorail
-	{0,       256 / 2, 256 / 4, 2}, // maglev
-};
-
-/* Modify the speed of the vehicle due to a turn */
-static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
-{
-	DirDiff diff;
-	const RailtypeSlowdownParams *rsp;
-
-	if (_patches.realistic_acceleration) return;
-
-	diff = DirDifference(v->direction, new_dir);
-	if (diff == DIRDIFF_SAME) return;
-
-	rsp = &_railtype_slowdown[v->u.rail.railtype];
-	v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
-}
-
-/* Modify the speed of the vehicle due to a change in altitude */
-static void AffectSpeedByZChange(Vehicle *v, byte old_z)
-{
-	const RailtypeSlowdownParams *rsp;
-	if (old_z == v->z_pos || _patches.realistic_acceleration) return;
-
-	rsp = &_railtype_slowdown[v->u.rail.railtype];
-
-	if (old_z < v->z_pos) {
-		v->cur_speed -= (v->cur_speed * rsp->z_up >> 8);
-	} else {
-		uint16 spd = v->cur_speed + rsp->z_down;
-		if (spd <= v->max_speed) v->cur_speed = spd;
-	}
-}
-
-static const DiagDirection _otherside_signal_directions[] = {
-	DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, 0, 0,
-	DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
-};
-
-static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
-{
-	if (IsTileType(tile, MP_RAILWAY) &&
-			GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
-		uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]);
-		UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]);
-	}
-}
-
-
-typedef struct TrainCollideChecker {
-	const Vehicle *v;
-	const Vehicle *v_skip;
-} TrainCollideChecker;
-
-static void *FindTrainCollideEnum(Vehicle *v, void *data)
-{
-	const TrainCollideChecker* tcc = data;
-
-	if (v != tcc->v &&
-			v != tcc->v_skip &&
-			v->type == VEH_Train &&
-			v->u.rail.track != 0x80 &&
-			myabs(v->z_pos - tcc->v->z_pos) <= 6 &&
-			myabs(v->x_pos - tcc->v->x_pos) < 6 &&
-			myabs(v->y_pos - tcc->v->y_pos) < 6) {
-		return v;
-	} else {
-		return NULL;
-	}
-}
-
-static void SetVehicleCrashed(Vehicle *v)
-{
-	Vehicle *u;
-
-	if (v->u.rail.crash_anim_pos != 0) return;
-
-	v->u.rail.crash_anim_pos++;
-
-	u = v;
-	BEGIN_ENUM_WAGONS(v)
-		v->vehstatus |= VS_CRASHED;
-	END_ENUM_WAGONS(v)
-
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, u->index, STATUS_BAR);
-}
-
-static uint CountPassengersInTrain(const Vehicle* v)
-{
-	uint num = 0;
-	BEGIN_ENUM_WAGONS(v)
-		if (v->cargo_type == CT_PASSENGERS) num += v->cargo_count;
-	END_ENUM_WAGONS(v)
-	return num;
-}
-
-/*
- * Checks whether the specified train has a collision with another vehicle. If
- * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
- * Reports the incident in a flashy news item, modifies station ratings and
- * plays a sound.
- */
-static void CheckTrainCollision(Vehicle *v)
-{
-	TrainCollideChecker tcc;
-	Vehicle *coll;
-	Vehicle *realcoll;
-	uint num;
-
-	/* can't collide in depot */
-	if (v->u.rail.track == 0x80) return;
-
-	assert(v->u.rail.track == 0x40 || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
-
-	tcc.v = v;
-	tcc.v_skip = v->next;
-
-	/* find colliding vehicle */
-	realcoll = VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum);
-	if (realcoll == NULL) return;
-
-	coll = GetFirstVehicleInChain(realcoll);
-
-	/* it can't collide with its own wagons */
-	if (v == coll ||
-			(v->u.rail.track & 0x40 && (v->direction & 2) != (realcoll->direction & 2)))
-		return;
-
-	//two drivers + passangers killed in train v
-	num = 2 + CountPassengersInTrain(v);
-	if (!(coll->vehstatus & VS_CRASHED))
-		//two drivers + passangers killed in train coll (if it was not crashed already)
-		num += 2 + CountPassengersInTrain(coll);
-
-	SetVehicleCrashed(v);
-	if (IsFrontEngine(coll)) SetVehicleCrashed(coll);
-
-	SetDParam(0, num);
-	AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
-		NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
-		v->index,
-		0
-	);
-
-	ModifyStationRatingAround(v->tile, v->owner, -160, 30);
-	SndPlayVehicleFx(SND_13_BIG_CRASH, v);
-}
-
-typedef struct VehicleAtSignalData {
-	TileIndex tile;
-	Direction direction;
-} VehicleAtSignalData;
-
-static void *CheckVehicleAtSignal(Vehicle *v, void *data)
-{
-	const VehicleAtSignalData* vasd = data;
-
-	if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == vasd->tile) {
-		DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT);
-
-		if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v;
-	}
-	return NULL;
-}
-
-static void TrainController(Vehicle *v, bool update_image)
-{
-	Vehicle *prev;
-	GetNewVehiclePosResult gp;
-	uint32 r, tracks,ts;
-	int i;
-	DiagDirection enterdir;
-	Direction dir;
-	Direction newdir;
-	Direction chosen_dir;
-	byte chosen_track;
-	byte old_z;
-
-	/* For every vehicle after and including the given vehicle */
-	for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) {
-		BeginVehicleMove(v);
-
-		if (v->u.rail.track != 0x40) {
-			/* Not inside tunnel */
-			if (GetNewVehiclePos(v, &gp)) {
-				/* Staying in the old tile */
-				if (v->u.rail.track == 0x80) {
-					/* inside depot */
-					gp.x = v->x_pos;
-					gp.y = v->y_pos;
-				} else {
-					/* is not inside depot */
-
-					if (!TrainCheckIfLineEnds(v)) return;
-
-					r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-					if (r & 0x8) {
-						//debug("%x & 0x8", r);
-						goto invalid_rail;
-					}
-					if (r & 0x2) {
-						TrainEnterStation(v, r >> 8);
-						return;
-					}
-
-					if (v->current_order.type == OT_LEAVESTATION) {
-						v->current_order.type = OT_NOTHING;
-						v->current_order.flags = 0;
-						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-					}
-				}
-			} else {
-				/* A new tile is about to be entered. */
-
-				byte bits;
-				/* Determine what direction we're entering the new tile from */
-				dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
-				enterdir = DirToDiagDir(dir);
-				assert(enterdir==0 || enterdir==1 || enterdir==2 || enterdir==3);
-
-				/* Get the status of the tracks in the new tile and mask
-				 * away the bits that aren't reachable. */
-				ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir];
-
-				/* Combine the from & to directions.
-				 * Now, the lower byte contains the track status, and the byte at bit 16 contains
-				 * the signal status. */
-				tracks = ts | (ts >> 8);
-				bits = tracks & 0xFF;
-				if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) {
-					/* We allow wagons to make 90 deg turns, because forbid_90_deg
-					 * can be switched on halfway a turn */
-					bits &= ~TrackCrossesTracks(FIND_FIRST_BIT(v->u.rail.track));
-				}
-
-				if (bits == 0) {
-					//debug("%x == 0", bits);
-					goto invalid_rail;
-				}
-
-				/* Check if the new tile contrains tracks that are compatible
-				 * with the current train, if not, bail out. */
-				if (!CheckCompatibleRail(v, gp.new_tile)) {
-					//debug("!CheckCompatibleRail(%p, %x)", v, gp.new_tile);
-					goto invalid_rail;
-				}
-
-				if (prev == NULL) {
-					/* Currently the locomotive is active. Determine which one of the
-					 * available tracks to choose */
-					chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits);
-					assert(chosen_track & tracks);
-
-					/* Check if it's a red signal and that force proceed is not clicked. */
-					if ( (tracks>>16)&chosen_track && v->u.rail.force_proceed == 0) goto red_light;
-				} else {
-					static byte _matching_tracks[8] = {0x30, 1, 0xC, 2, 0x30, 1, 0xC, 2};
-
-					/* The wagon is active, simply follow the prev vehicle. */
-					chosen_track = (byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
-				}
-
-				/* make sure chosen track is a valid track */
-				assert(chosen_track==1 || chosen_track==2 || chosen_track==4 || chosen_track==8 || chosen_track==16 || chosen_track==32);
-
-				/* Update XY to reflect the entrance to the new tile, and select the direction to use */
-				{
-					const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
-					gp.x = (gp.x & ~0xF) | b[0];
-					gp.y = (gp.y & ~0xF) | b[1];
-					chosen_dir = b[2];
-				}
-
-				/* Call the landscape function and tell it that the vehicle entered the tile */
-				r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-				if (r & 0x8) {
-					//debug("%x & 0x8", r);
-					goto invalid_rail;
-				}
-
-				if (IsLevelCrossingTile(v->tile) && v->next == NULL) {
-					UnbarCrossing(v->tile);
-					MarkTileDirtyByTile(v->tile);
-				}
-
-				if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
-
-				if (!(r&0x4)) {
-					v->tile = gp.new_tile;
-
-					if (GetTileRailType(gp.new_tile, chosen_track) != GetTileRailType(gp.old_tile, v->u.rail.track)) {
-						TrainPowerChanged(GetFirstVehicleInChain(v));
-					}
-
-					v->u.rail.track = chosen_track;
-					assert(v->u.rail.track);
-				}
-
-				if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
-
-				/* Signals can only change when the first
-				 * (above) or the last vehicle moves. */
-				if (v->next == NULL)
-					TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
-
-				if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
-
-				v->direction = chosen_dir;
-			}
-		} else {
-			/* in tunnel on on a bridge */
-			GetNewVehiclePos(v, &gp);
-
-			SetSpeedLimitOnBridge(v);
-
-			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 0x4)) {
-				v->x_pos = gp.x;
-				v->y_pos = gp.y;
-				VehiclePositionChanged(v);
-				if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
-				continue;
-			}
-		}
-
-		/* update image of train, as well as delta XY */
-		newdir = GetNewVehicleDirection(v, gp.x, gp.y);
-		UpdateTrainDeltaXY(v, newdir);
-		if (update_image) v->cur_image = GetTrainImage(v, newdir);
-
-		v->x_pos = gp.x;
-		v->y_pos = gp.y;
-
-		/* update the Z position of the vehicle */
-		old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile));
-
-		if (prev == NULL) {
-			/* This is the first vehicle in the train */
-			AffectSpeedByZChange(v, old_z);
-		}
-	}
-	return;
-
-invalid_rail:
-	/* We've reached end of line?? */
-	if (prev != NULL) error("!Disconnecting train");
-	goto reverse_train_direction;
-
-red_light: {
-	/* We're in front of a red signal ?? */
-		/* find the first set bit in ts. need to do it in 2 steps, since
-		 * FIND_FIRST_BIT only handles 6 bits at a time. */
-		i = FindFirstBit2x64(ts);
-
-		if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
-			v->cur_speed = 0;
-			v->subspeed = 0;
-			v->progress = 255 - 100;
-			if (++v->load_unload_time_rem < _patches.wait_oneway_signal * 20) return;
-		} else if (HasSignalOnTrackdir(gp.new_tile, i)){
-			v->cur_speed = 0;
-			v->subspeed = 0;
-			v->progress = 255-10;
-			if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) {
-				TileIndex o_tile = gp.new_tile + TileOffsByDiagDir(enterdir);
-				VehicleAtSignalData vasd;
-				vasd.tile = o_tile;
-				vasd.direction = ReverseDir(dir);
-
-				/* check if a train is waiting on the other side */
-				if (VehicleFromPos(o_tile, &vasd, CheckVehicleAtSignal) == NULL) return;
-			}
-		}
-	}
-
-reverse_train_direction:
-	v->load_unload_time_rem = 0;
-	v->cur_speed = 0;
-	v->subspeed = 0;
-	ReverseTrainDirection(v);
-}
-
-extern TileIndex CheckTunnelBusy(TileIndex tile, uint *length);
-
-/**
- * Deletes/Clears the last wagon of a crashed train. It takes the engine of the
- * train, then goes to the last wagon and deletes that. Each call to this function
- * will remove the last wagon of a crashed train. If this wagon was on a crossing,
- * or inside a tunnel, recalculate the signals as they might need updating
- * @param v the @Vehicle of which last wagon is to be removed
- */
-static void DeleteLastWagon(Vehicle *v)
-{
-	Vehicle *u = v;
-
-	/* Go to the last wagon and delete the link pointing there
-	 * *u is then the one-before-last wagon, and *v the last
-	 * one which will physicially be removed */
-	for (; v->next != NULL; v = v->next) u = v;
-	u->next = NULL;
-
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-	RebuildVehicleLists();
-	InvalidateWindow(WC_COMPANY, v->owner);
-
-	BeginVehicleMove(v);
-	EndVehicleMove(v);
-	DeleteVehicle(v);
-
-	if (!(v->u.rail.track & 0xC0))
-		SetSignalsOnBothDir(v->tile, FIND_FIRST_BIT(v->u.rail.track));
-
-	/* Check if the wagon was on a road/rail-crossing and disable it if no
-	 * others are on it */
-	DisableTrainCrossing(v->tile);
-
-	if ( (v->u.rail.track == 0x40 && v->vehstatus & VS_HIDDEN) ) { // inside a tunnel
-		TileIndex endtile = CheckTunnelBusy(v->tile, NULL);
-
-		if (endtile == INVALID_TILE) return; // tunnel is busy (error returned)
-
-		switch (v->direction) {
-			case 1:
-			case 5:
-				SetSignalsOnBothDir(v->tile, 0);
-				SetSignalsOnBothDir(endtile, 0);
-				break;
-
-			case 3:
-			case 7:
-				SetSignalsOnBothDir(v->tile, 1);
-				SetSignalsOnBothDir(endtile, 1);
-				break;
-
-			default:
-				break;
-		}
-	}
-}
-
-static void ChangeTrainDirRandomly(Vehicle *v)
-{
-	static const DirDiff delta[] = {
-		DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
-	};
-
-	do {
-		/* We don't need to twist around vehicles if they're not visible */
-		if (!(v->vehstatus & VS_HIDDEN)) {
-			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
-			BeginVehicleMove(v);
-			UpdateTrainDeltaXY(v, v->direction);
-			v->cur_image = GetTrainImage(v, v->direction);
-			/* Refrain from updating the z position of the vehicle when on
-			   a bridge, because AfterSetTrainPos will put the vehicle under
-			   the bridge in that case */
-			if (!(v->u.rail.track & 0x40)) AfterSetTrainPos(v, false);
-		}
-	} while ((v = v->next) != NULL);
-}
-
-static void HandleCrashedTrain(Vehicle *v)
-{
-	int state = ++v->u.rail.crash_anim_pos;
-	uint32 r;
-	Vehicle *u;
-
-	if (state == 4 && !(v->u.rail.track & VS_HIDDEN)) {
-		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
-	}
-
-	if (state <= 200 && CHANCE16R(1, 7, r)) {
-		int index = (r * 10 >> 16);
-
-		u = v;
-		do {
-			if (--index < 0) {
-				r = Random();
-
-				CreateEffectVehicleRel(u,
-					GB(r,  8, 3) + 2,
-					GB(r, 16, 3) + 2,
-					GB(r,  0, 3) + 5,
-					EV_EXPLOSION_SMALL);
-				break;
-			}
-		} while ((u = u->next) != NULL);
-	}
-
-	if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
-
-	if (state >= 4440 && !(v->tick_counter&0x1F)) {
-		DeleteLastWagon(v);
-		InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
-	}
-}
-
-static void HandleBrokenTrain(Vehicle *v)
-{
-	if (v->breakdown_ctr != 1) {
-		v->breakdown_ctr = 1;
-		v->cur_speed = 0;
-
-		if (v->breakdowns_since_last_service != 255)
-			v->breakdowns_since_last_service++;
-
-		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
-			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
-				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
-		}
-
-		if (!(v->vehstatus & VS_HIDDEN)) {
-			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
-		}
-	}
-
-	if (!(v->tick_counter & 3)) {
-		if (!--v->breakdown_delay) {
-			v->breakdown_ctr = 0;
-			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-		}
-	}
-}
-
-static const byte _breakdown_speeds[16] = {
-	225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
-};
-
-static bool TrainCheckIfLineEnds(Vehicle *v)
-{
-	TileIndex tile;
-	uint x,y;
-	uint16 break_speed;
-	DiagDirection dir;
-	int t;
-	uint32 ts;
-
-	t = v->breakdown_ctr;
-	if (t > 1) {
-		v->vehstatus |= VS_TRAIN_SLOWING;
-
-		break_speed = _breakdown_speeds[GB(~t, 4, 4)];
-		if (break_speed < v->cur_speed) v->cur_speed = break_speed;
-	} else {
-		v->vehstatus &= ~VS_TRAIN_SLOWING;
-	}
-
-	if (v->u.rail.track & 0x40) return true; // exit if inside a tunnel
-	if (v->u.rail.track & 0x80) return true; // exit if inside a depot
-
-	tile = v->tile;
-
-	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
-		DiagDirection dir;
-
-		dir = IsTunnel(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile);
-		if (DiagDirToDir(dir) == v->direction) return true;
-	}
-
-	// depot?
-	/* XXX -- When enabled, this makes it possible to crash trains of others
-	     (by building a depot right against a station) */
-/*	if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT_WAYPOINT)
-		return true;*/
-
-	/* Determine the non-diagonal direction in which we will exit this tile */
-	dir = DirToDiagDir(v->direction);
-	if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) {
-		dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT);
-	}
-	/* Calculate next tile */
-	tile += TileOffsByDiagDir(dir);
-	// determine the track status on the next tile.
-	ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[dir];
-
-	/* Calc position within the current tile ?? */
-	x = v->x_pos & 0xF;
-	y = v->y_pos & 0xF;
-
-	switch (v->direction) {
-		case DIR_N : x = ~x + ~y + 24; break;
-		case DIR_NW: x = y;            /* FALLTHROUGH */
-		case DIR_NE: x = ~x + 16;      break;
-		case DIR_E : x = ~x + y + 8;   break;
-		case DIR_SE: x = y;            break;
-		case DIR_S : x = x + y - 8;    break;
-		case DIR_W : x = ~y + x + 8;   break;
-	}
-
-	if (GB(ts, 0, 16) != 0) {
-		/* If we approach a rail-piece which we can't enter, or the back of a depot, don't enter it! */
-		if (x + 4 >= TILE_SIZE &&
-				(!CheckCompatibleRail(v, tile) ||
-				(IsTileDepotType(tile, TRANSPORT_RAIL) &&
-				GetRailDepotDirection(tile) == dir))) {
-			v->cur_speed = 0;
-			ReverseTrainDirection(v);
-			return false;
-		}
-		if ((ts &= (ts >> 16)) == 0) {
-			// make a rail/road crossing red
-			if (IsLevelCrossingTile(tile)) {
-				if (!IsCrossingBarred(tile)) {
-					BarCrossing(tile);
-					SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
-					MarkTileDirtyByTile(tile);
-				}
-			}
-			return true;
-		}
-	} else if (x + 4 >= TILE_SIZE) {
-		v->cur_speed = 0;
-		ReverseTrainDirection(v);
-		return false;
-	}
-
-	// slow down
-	v->vehstatus |= VS_TRAIN_SLOWING;
-	break_speed = _breakdown_speeds[x & 0xF];
-	if (!(v->direction & 1)) break_speed >>= 1;
-	if (break_speed < v->cur_speed) v->cur_speed = break_speed;
-
-	return true;
-}
-
-static void TrainLocoHandler(Vehicle *v, bool mode)
-{
-	int j;
-
-	/* train has crashed? */
-	if (v->u.rail.crash_anim_pos != 0) {
-		if (!mode) HandleCrashedTrain(v);
-		return;
-	}
-
-	if (v->u.rail.force_proceed != 0) v->u.rail.force_proceed--;
-
-	/* train is broken down? */
-	if (v->breakdown_ctr != 0) {
-		if (v->breakdown_ctr <= 2) {
-			HandleBrokenTrain(v);
-			return;
-		}
-		v->breakdown_ctr--;
-	}
-
-	if (HASBIT(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) {
-		ReverseTrainDirection(v);
-	}
-
-	/* exit if train is stopped */
-	if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return;
-
-	if (ProcessTrainOrder(v)) {
-		v->load_unload_time_rem = 0;
-		v->cur_speed = 0;
-		v->subspeed = 0;
-		ReverseTrainDirection(v);
-		return;
-	}
-
-	HandleTrainLoading(v, mode);
-
-	if (v->current_order.type == OT_LOADING) return;
-
-	if (CheckTrainStayInDepot(v)) return;
-
-	if (!mode) HandleLocomotiveSmokeCloud(v);
-
-	j = UpdateTrainSpeed(v);
-	if (j == 0) {
-		// if the vehicle has speed 0, update the last_speed field.
-		if (v->cur_speed != 0) return;
-	} else {
-		TrainCheckIfLineEnds(v);
-
-		do {
-			TrainController(v, true);
-			CheckTrainCollision(v);
-			if (v->cur_speed <= 0x100)
-				break;
-		} while (--j != 0);
-	}
-
-	SetLastSpeed(v, v->cur_speed);
-}
-
-
-void Train_Tick(Vehicle *v)
-{
-	if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff)
-		v->cargo_days++;
-
-	v->tick_counter++;
-
-	if (IsFrontEngine(v)) {
-		TrainLocoHandler(v, false);
-
-		// make sure vehicle wasn't deleted.
-		if (v->type == VEH_Train && IsFrontEngine(v))
-			TrainLocoHandler(v, true);
-	} else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) {
-		// Delete flooded standalone wagon
-		if (++v->u.rail.crash_anim_pos >= 4400)
-			DeleteVehicle(v);
-	}
-}
-
-#define MAX_ACCEPTABLE_DEPOT_DIST 16
-
-static void CheckIfTrainNeedsService(Vehicle *v)
-{
-	const Depot* depot;
-	TrainFindDepotData tfdd;
-
-	if (_patches.servint_trains == 0)                   return;
-	if (!VehicleNeedsService(v))                        return;
-	if (v->vehstatus & VS_STOPPED)                      return;
-	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
-
-	// Don't interfere with a depot visit scheduled by the user, or a
-	// depot visit by the order list.
-	if (v->current_order.type == OT_GOTO_DEPOT &&
-			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
-		return;
-
-	if (CheckTrainIsInsideDepot(v)) {
-		VehicleServiceInDepot(v);
-		return;
-	}
-
-	tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
-	/* Only go to the depot if it is not too far out of our way. */
-	if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
-		if (v->current_order.type == OT_GOTO_DEPOT) {
-			/* If we were already heading for a depot but it has
-			 * suddenly moved farther away, we continue our normal
-			 * schedule? */
-			v->current_order.type = OT_DUMMY;
-			v->current_order.flags = 0;
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		}
-		return;
-	}
-
-	depot = GetDepotByTile(tfdd.tile);
-
-	if (v->current_order.type == OT_GOTO_DEPOT &&
-			v->current_order.dest != depot->index &&
-			!CHANCE16(3, 16)) {
-		return;
-	}
-
-	v->current_order.type = OT_GOTO_DEPOT;
-	v->current_order.flags = OF_NON_STOP;
-	v->current_order.dest = depot->index;
-	v->dest_tile = tfdd.tile;
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-}
-
-int32 GetTrainRunningCost(const Vehicle *v)
-{
-	int32 cost = 0;
-
-	do {
-		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
-		if (rvi->running_cost_base > 0)
-			cost += rvi->running_cost_base * _price.running_rail[rvi->running_cost_class];
-	} while ((v = GetNextVehicle(v)) != NULL);
-
-	return cost;
-}
-
-void OnNewDay_Train(Vehicle *v)
-{
-	TileIndex tile;
-
-	if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v);
-
-	if (IsFrontEngine(v)) {
-		CheckVehicleBreakdown(v);
-		AgeVehicle(v);
-
-		CheckIfTrainNeedsService(v);
-
-		CheckOrders(v);
-
-		/* update destination */
-		if (v->current_order.type == OT_GOTO_STATION &&
-				(tile = GetStation(v->current_order.dest)->train_tile) != 0) {
-			v->dest_tile = tile;
-		}
-
-		if ((v->vehstatus & VS_STOPPED) == 0) {
-			/* running costs */
-			int32 cost = GetTrainRunningCost(v) / 364;
-
-			v->profit_this_year -= cost >> 8;
-
-			SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
-			SubtractMoneyFromPlayerFract(v->owner, cost);
-
-			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-			InvalidateWindowClasses(WC_TRAINS_LIST);
-		}
-	}
-}
-
-void TrainsYearlyLoop(void)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && IsFrontEngine(v)) {
-
-			// show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list)
-			if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) {
-				SetDParam(1, v->profit_this_year);
-				SetDParam(0, v->unitnumber);
-				AddNewsItem(
-					STR_TRAIN_IS_UNPROFITABLE,
-					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
-					v->index,
-					0);
-			}
-
-			v->profit_last_year = v->profit_this_year;
-			v->profit_this_year = 0;
-			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-		}
-	}
-}
-
-
-void InitializeTrains(void)
-{
-	_age_cargo_skip_counter = 1;
-}
-
-/*
- * Link front and rear multiheaded engines to each other
- * This is done when loading a savegame
- */
-void ConnectMultiheadedTrains(void)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train) {
-			v->u.rail.other_multiheaded_part = NULL;
-		}
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && IsFrontEngine(v)) {
-			Vehicle *u = v;
-
-			BEGIN_ENUM_WAGONS(u) {
-				if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
-
-				if (IsMultiheaded(u)) {
-					if (!IsTrainEngine(u)) {
-						/* we got a rear car without a front car. We will convert it to a front one */
-						SetTrainEngine(u);
-						u->spritenum--;
-					}
-
-					{
-						Vehicle *w;
-
-						for (w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w));
-						if (w != NULL) {
-							/* we found a car to partner with this engine. Now we will make sure it face the right way */
-							if (IsTrainEngine(w)) {
-								ClearTrainEngine(w);
-								w->spritenum++;
-							}
-						}
-
-						if (w != NULL) {
-							w->u.rail.other_multiheaded_part = u;
-							u->u.rail.other_multiheaded_part = w;
-						} else {
-							/* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
-							ClearMultiheaded(u);
-						}
-					}
-				}
-			} END_ENUM_WAGONS(u)
-		}
-	}
-}
-
-/*
- *  Converts all trains to the new subtype format introduced in savegame 16.2
- *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
- */
-void ConvertOldMultiheadToNew(void)
-{
-	Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train) {
-			SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
-		}
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train) {
-			if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
-				Vehicle *u = v;
-
-				BEGIN_ENUM_WAGONS(u) {
-					const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
-
-					CLRBIT(u->subtype, 7);
-					switch (u->subtype) {
-						case 0: /* TS_Front_Engine */
-							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
-							SetFrontEngine(u);
-							SetTrainEngine(u);
-							break;
-
-						case 1: /* TS_Artic_Part */
-							u->subtype = 0;
-							SetArticulatedPart(u);
-							break;
-
-						case 2: /* TS_Not_First */
-							u->subtype = 0;
-							if (rvi->flags & RVI_WAGON) {
-								// normal wagon
-								SetTrainWagon(u);
-								break;
-							}
-							if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
-								// rear end of a multiheaded engine
-								SetMultiheaded(u);
-								break;
-							}
-							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
-							SetTrainEngine(u);
-							break;
-
-						case 4: /* TS_Free_Car */
-							u->subtype = 0;
-							SetTrainWagon(u);
-							SetFreeWagon(u);
-							break;
-						default: NOT_REACHED(); break;
-					}
-				} END_ENUM_WAGONS(u)
-			}
-		}
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/train_cmd.cpp
@@ -0,0 +1,3811 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "debug.h"
+#include "functions.h"
+#include "gui.h"
+#include "station_map.h"
+#include "table/strings.h"
+#include "map.h"
+#include "tile.h"
+#include "tunnel_map.h"
+#include "vehicle.h"
+#include "command.h"
+#include "pathfind.h"
+#include "npf.h"
+#include "station.h"
+#include "table/train_cmd.h"
+#include "news.h"
+#include "engine.h"
+#include "player.h"
+#include "sound.h"
+#include "depot.h"
+#include "waypoint.h"
+#include "vehicle_gui.h"
+#include "train.h"
+#include "bridge.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+#include "newgrf_text.h"
+#include "direction.h"
+#include "yapf/yapf.h"
+#include "date.h"
+
+static bool TrainCheckIfLineEnds(Vehicle *v);
+static void TrainController(Vehicle *v, bool update_image);
+
+static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
+static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
+static const byte _state_dir_table[4] = { 0x20, 8, 0x10, 4 };
+
+
+/** Return the cargo weight multiplier to use for a rail vehicle
+ * @param cargo Cargo type to get multiplier for
+ * @return Cargo weight multiplier
+ */
+byte FreightWagonMult(CargoID cargo)
+{
+	// XXX NewCargos introduces a specific "is freight" flag for this test.
+	if (cargo == CT_PASSENGERS || cargo == CT_MAIL) return 1;
+	return _patches.freight_trains;
+}
+
+
+/**
+ * Recalculates the cached total power of a train. Should be called when the consist is changed
+ * @param v First vehicle of the consist.
+ */
+void TrainPowerChanged(Vehicle* v)
+{
+	Vehicle* u;
+	uint32 power = 0;
+	uint32 max_te = 0;
+
+	for (u = v; u != NULL; u = u->next) {
+		const RailVehicleInfo *rvi_u;
+		bool engine_has_power = true;
+		bool wagon_has_power = true;
+
+		/* Power is not added for articulated parts */
+		if (IsArticulatedPart(u)) continue;
+
+		if (IsLevelCrossingTile(u->tile)) {
+			if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeCrossing(u->tile))) engine_has_power = false;
+			if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeCrossing(u->tile))) wagon_has_power = false;
+		} else {
+			if (!HasPowerOnRail(u->u.rail.railtype, GetRailType(u->tile))) engine_has_power = false;
+			if (!HasPowerOnRail(v->u.rail.railtype, GetRailType(u->tile))) wagon_has_power = false;
+		}
+
+		rvi_u = RailVehInfo(u->engine_type);
+
+		if (engine_has_power && rvi_u->power != 0) {
+			power += rvi_u->power;
+			/* Tractive effort in (tonnes * 1000 * 10 =) N */
+			max_te += (u->u.rail.cached_veh_weight * 10000 * rvi_u->tractive_effort) / 256;
+		}
+
+		if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON) && (wagon_has_power)) {
+			power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
+		}
+	}
+
+	if (v->u.rail.cached_power != power || v->u.rail.cached_max_te != max_te) {
+		v->u.rail.cached_power = power;
+		v->u.rail.cached_max_te = max_te;
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+}
+
+
+/**
+ * Recalculates the cached weight of a train and its vehicles. Should be called each time the cargo on
+ * the consist changes.
+ * @param v First vehicle of the consist.
+ */
+static void TrainCargoChanged(Vehicle* v)
+{
+	Vehicle *u;
+	uint32 weight = 0;
+
+	for (u = v; u != NULL; u = u->next) {
+		const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
+		uint32 vweight = (_cargoc.weights[u->cargo_type] * u->cargo_count * FreightWagonMult(u->cargo_type)) / 16;
+
+		// Vehicle weight is not added for articulated parts.
+		if (!IsArticulatedPart(u)) {
+			// vehicle weight is the sum of the weight of the vehicle and the weight of its cargo
+			vweight += rvi->weight;
+
+			// powered wagons have extra weight added
+			if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON))
+				vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
+		}
+
+		// consist weight is the sum of the weight of all vehicles in the consist
+		weight += vweight;
+
+		// store vehicle weight in cache
+		u->u.rail.cached_veh_weight = vweight;
+	};
+
+	// store consist weight in cache
+	v->u.rail.cached_weight = weight;
+
+	/* Now update train power (tractive effort is dependent on weight) */
+	TrainPowerChanged(v);
+}
+
+
+/**
+ * Recalculates the cached stuff of a train. Should be called each time a vehicle is added
+ * to/removed from the chain, and when the game is loaded.
+ * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
+ * @param v First vehicle of the chain.
+ */
+void TrainConsistChanged(Vehicle* v)
+{
+	const RailVehicleInfo *rvi_v;
+	Vehicle *u;
+	uint16 max_speed = 0xFFFF;
+	EngineID first_engine;
+
+	assert(v->type == VEH_Train);
+
+	assert(IsFrontEngine(v) || IsFreeWagon(v));
+
+	rvi_v = RailVehInfo(v->engine_type);
+	first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
+	v->u.rail.cached_total_length = 0;
+	v->u.rail.compatible_railtypes = 0;
+
+	for (u = v; u != NULL; u = u->next) {
+		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
+		uint16 veh_len;
+
+		// Update the v->first cache. This is faster than having to brute force it later.
+		if (u->first == NULL) u->first = v;
+
+		// update the 'first engine'
+		u->u.rail.first_engine = (v == u) ? INVALID_ENGINE : first_engine;
+		u->u.rail.railtype = GetEngine(u->engine_type)->railtype;
+
+		if (IsTrainEngine(u)) first_engine = u->engine_type;
+
+		if (rvi_u->visual_effect != 0) {
+			u->u.rail.cached_vis_effect = rvi_u->visual_effect;
+		} else {
+			if (IsTrainWagon(u) || IsArticulatedPart(u)) {
+				// Wagons and articulated parts have no effect by default
+				u->u.rail.cached_vis_effect = 0x40;
+			} else if (rvi_u->engclass == 0) {
+				// Steam is offset by -4 units
+				u->u.rail.cached_vis_effect = 4;
+			} else {
+				// Diesel fumes and sparks come from the centre
+				u->u.rail.cached_vis_effect = 8;
+			}
+		}
+
+		if (!IsArticulatedPart(u)) {
+			// check if its a powered wagon
+			CLRBIT(u->u.rail.flags, VRF_POWEREDWAGON);
+
+			/* Check powered wagon / visual effect callback */
+			if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_WAGON_POWER)) {
+				uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
+
+				if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback;
+			}
+
+			if ((rvi_v->pow_wag_power != 0) && (rvi_u->flags & RVI_WAGON) && UsesWagonOverride(u)) {
+				if (u->u.rail.cached_vis_effect < 0x40) {
+					/* wagon is powered */
+					SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
+				}
+			}
+
+			/* Do not count powered wagons for the compatible railtypes, as wagons always
+			   have railtype normal */
+			if (rvi_u->power > 0) {
+				v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
+			}
+
+			/* Some electric engines can be allowed to run on normal rail. It happens to all
+			 * existing electric engines when elrails are disabled and then re-enabled */
+			if (HASBIT(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
+				u->u.rail.railtype = RAILTYPE_RAIL;
+				u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
+			}
+
+			// max speed is the minimum of the speed limits of all vehicles in the consist
+			if (!(rvi_u->flags & RVI_WAGON) || _patches.wagon_speed_limits)
+				if (rvi_u->max_speed != 0 && !UsesWagonOverride(u))
+					max_speed = min(rvi_u->max_speed, max_speed);
+		}
+
+		// check the vehicle length (callback)
+		veh_len = CALLBACK_FAILED;
+		if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
+			veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
+		}
+		if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
+		veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
+		u->u.rail.cached_veh_length = 8 - veh_len;
+		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
+
+	};
+
+	// store consist weight/max speed in cache
+	v->u.rail.cached_max_speed = max_speed;
+
+	// recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added)
+	TrainCargoChanged(v);
+}
+
+/* These two arrays are used for realistic acceleration. XXX: How should they
+ * be interpreted? */
+static const byte _curve_neighbours45[8][2] = {
+	{7, 1},
+	{0, 2},
+	{1, 3},
+	{2, 4},
+	{3, 5},
+	{4, 6},
+	{5, 7},
+	{6, 0},
+};
+
+static const byte _curve_neighbours90[8][2] = {
+	{6, 2},
+	{7, 3},
+	{0, 4},
+	{1, 5},
+	{2, 6},
+	{3, 7},
+	{4, 0},
+	{5, 1},
+};
+
+enum AccelType {
+	AM_ACCEL,
+	AM_BRAKE
+};
+
+static bool TrainShouldStop(const Vehicle* v, TileIndex tile)
+{
+	const Order* o = &v->current_order;
+	StationID sid = GetStationIndex(tile);
+
+	assert(v->type == VEH_Train);
+	//When does a train drive through a station
+	//first we deal with the "new nonstop handling"
+	if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) {
+		return false;
+	}
+
+	if (v->last_station_visited == sid) return false;
+
+	if (sid != o->dest && (o->flags & OF_NON_STOP || _patches.new_nonstop)) {
+		return false;
+	}
+
+	return true;
+}
+
+//new acceleration
+static int GetTrainAcceleration(Vehicle *v, bool mode)
+{
+	const Vehicle *u;
+	int num = 0; //number of vehicles, change this into the number of axles later
+	int power = 0;
+	int mass = 0;
+	int max_speed = 2000;
+	int area = 120;
+	int friction = 35; //[1e-3]
+	int drag_coeff = 20; //[1e-4]
+	int incl = 0;
+	int resistance;
+	int speed = v->cur_speed; //[mph]
+	int force = 0x3FFFFFFF;
+	int pos = 0;
+	int lastpos = -1;
+	int curvecount[2] = {0, 0};
+	int sum = 0;
+	int numcurve = 0;
+	int max_te = v->u.rail.cached_max_te; // [N]
+
+	speed *= 10;
+	speed /= 16;
+
+	//first find the curve speed limit
+	for (u = v; u->next != NULL; u = u->next, pos++) {
+		Direction dir = u->direction;
+		Direction ndir = u->next->direction;
+		int i;
+
+		for (i = 0; i < 2; i++) {
+			if ( _curve_neighbours45[dir][i] == ndir) {
+				curvecount[i]++;
+				if (lastpos != -1) {
+					numcurve++;
+					sum += pos - lastpos;
+					if (pos - lastpos == 1) {
+						max_speed = 88;
+					}
+				}
+				lastpos = pos;
+			}
+		}
+
+		//if we have a 90 degree turn, fix the speed limit to 60
+		if (_curve_neighbours90[dir][0] == ndir ||
+				_curve_neighbours90[dir][1] == ndir) {
+			max_speed = 61;
+		}
+	}
+
+	if (numcurve > 0) sum /= numcurve;
+
+	if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) {
+		int total = curvecount[0] + curvecount[1];
+
+		if (curvecount[0] == 1 && curvecount[1] == 1) {
+			max_speed = 0xFFFF;
+		} else if (total > 1) {
+			max_speed = 232 - (13 - clamp(sum, 1, 12)) * (13 - clamp(sum, 1, 12));
+		}
+	}
+
+	max_speed += (max_speed / 2) * v->u.rail.railtype;
+
+	if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
+		if (TrainShouldStop(v, v->tile)) {
+			uint station_length = GetPlatformLength(v->tile, DirToDiagDir(v->direction));
+			int delta_v;
+
+			max_speed = 120;
+
+			delta_v = v->cur_speed / (station_length + 1);
+			if (v->max_speed > (v->cur_speed - delta_v))
+				max_speed = v->cur_speed - (delta_v / 10);
+
+			max_speed = max(max_speed, 25 * station_length);
+		}
+	}
+
+	mass = v->u.rail.cached_weight;
+	power = v->u.rail.cached_power * 746;
+	max_speed = min(max_speed, v->u.rail.cached_max_speed);
+
+	for (u = v; u != NULL; u = u->next) {
+		num++;
+		drag_coeff += 3;
+
+		if (u->u.rail.track == 0x80) max_speed = min(max_speed, 61);
+
+		if (HASBIT(u->u.rail.flags, VRF_GOINGUP)) {
+			incl += u->u.rail.cached_veh_weight * 60; //3% slope, quite a bit actually
+		} else if (HASBIT(u->u.rail.flags, VRF_GOINGDOWN)) {
+			incl -= u->u.rail.cached_veh_weight * 60;
+		}
+	}
+
+	v->max_speed = max_speed;
+
+	if (v->u.rail.railtype != RAILTYPE_MAGLEV) {
+		resistance = 13 * mass / 10;
+		resistance += 60 * num;
+		resistance += friction * mass * speed / 1000;
+		resistance += (area * drag_coeff * speed * speed) / 10000;
+	} else {
+		resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
+	}
+	resistance += incl;
+	resistance *= 4; //[N]
+
+	/* Due to the mph to m/s conversion below, at speeds below 3 mph the force is
+	 * actually double the train's power */
+	if (speed > 2) {
+		switch (v->u.rail.railtype) {
+			case RAILTYPE_RAIL:
+			case RAILTYPE_ELECTRIC:
+			case RAILTYPE_MONO:
+				force = power / speed; //[N]
+				force *= 22;
+				force /= 10;
+				if (mode == AM_ACCEL && force > max_te) force = max_te;
+				break;
+
+			case RAILTYPE_MAGLEV:
+				force = power / 25;
+				break;
+		}
+	} else {
+		//"kickoff" acceleration
+		force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
+		force = max(force, (mass * 8) + resistance);
+	}
+
+	if (force <= 0) force = 10000;
+
+	if (v->u.rail.railtype != RAILTYPE_MAGLEV) force = min(force, mass * 10 * 200);
+
+	if (mode == AM_ACCEL) {
+		return (force - resistance) / (mass * 4);
+	} else {
+		return min((-force - resistance) / (mass * 4), -10000 / (mass * 4));
+	}
+}
+
+static void UpdateTrainAcceleration(Vehicle* v)
+{
+	uint power = 0;
+	uint weight = 0;
+
+	assert(IsFrontEngine(v));
+
+	weight = v->u.rail.cached_weight;
+	power = v->u.rail.cached_power;
+	v->max_speed = v->u.rail.cached_max_speed;
+
+	assert(weight != 0);
+
+	v->acceleration = clamp(power / weight * 4, 1, 255);
+}
+
+int GetTrainImage(const Vehicle* v, Direction direction)
+{
+	int img = v->spritenum;
+	int base;
+
+	if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
+
+	if (is_custom_sprite(img)) {
+		base = GetCustomVehicleSprite(v, direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img));
+		if (base != 0) return base;
+		img = orig_rail_vehicle_info[v->engine_type].image_index;
+	}
+
+	base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
+
+	if (v->cargo_count >= v->cargo_cap / 2) base += _wagon_full_adder[img];
+	return base;
+}
+
+void DrawTrainEngine(int x, int y, EngineID engine, uint32 image_ormod)
+{
+	const RailVehicleInfo *rvi = RailVehInfo(engine);
+
+	int img = rvi->image_index;
+	uint32 image = 0;
+
+	if (is_custom_sprite(img)) {
+		image = GetCustomVehicleIcon(engine, DIR_W);
+		if (image == 0) {
+			img = orig_rail_vehicle_info[engine].image_index;
+		} else {
+			y += _traininfo_vehicle_pitch;
+		}
+	}
+	if (image == 0) {
+		image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img];
+	}
+
+	if (rvi->flags & RVI_MULTIHEAD) {
+		DrawSprite(image | image_ormod, x - 14, y);
+		x += 15;
+		image = 0;
+		if (is_custom_sprite(img)) {
+			image = GetCustomVehicleIcon(engine, 2);
+			if (image == 0) img = orig_rail_vehicle_info[engine].image_index;
+		}
+		if (image == 0) {
+			image =
+				((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) +
+				_engine_sprite_base[img + 1];
+		}
+	}
+	DrawSprite(image | image_ormod, x, y);
+}
+
+uint CountArticulatedParts(EngineID engine_type)
+{
+	uint16 callback;
+	uint i;
+
+	if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0;
+
+	for (i = 1; i < 10; i++) {
+		callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, engine_type, NULL);
+		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
+	}
+
+	return i - 1;
+}
+
+static void AddArticulatedParts(Vehicle **vl)
+{
+	const RailVehicleInfo *rvi_artic;
+	EngineID engine_type;
+	Vehicle *v = vl[0];
+	Vehicle *u = v;
+	uint16 callback;
+	bool flip_image;
+	uint i;
+
+	if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return;
+
+	for (i = 1; i < 10; i++) {
+		callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, v->engine_type, v);
+		if (callback == CALLBACK_FAILED || callback == 0xFF) return;
+
+		/* Attempt to use pre-allocated vehicles until they run out. This can happen
+		 * if the callback returns different values depending on the cargo type. */
+		u->next = vl[i];
+		if (u->next == NULL) u->next = AllocateVehicle();
+		if (u->next == NULL) return;
+
+		u = u->next;
+
+		engine_type = GB(callback, 0, 7);
+		flip_image = HASBIT(callback, 7);
+		rvi_artic = RailVehInfo(engine_type);
+
+		// get common values from first engine
+		u->direction = v->direction;
+		u->owner = v->owner;
+		u->tile = v->tile;
+		u->x_pos = v->x_pos;
+		u->y_pos = v->y_pos;
+		u->z_pos = v->z_pos;
+		u->z_height = v->z_height;
+		u->u.rail.track = v->u.rail.track;
+		u->u.rail.railtype = v->u.rail.railtype;
+		u->build_year = v->build_year;
+		u->vehstatus = v->vehstatus & ~VS_STOPPED;
+		u->u.rail.first_engine = v->engine_type;
+
+		// get more settings from rail vehicle info
+		u->spritenum = rvi_artic->image_index;
+		if (flip_image) u->spritenum++;
+		u->cargo_type = rvi_artic->cargo_type;
+		u->cargo_subtype = 0;
+		u->cargo_cap = rvi_artic->capacity;
+		u->max_speed = 0;
+		u->max_age = 0;
+		u->engine_type = engine_type;
+		u->value = 0;
+		u->type = VEH_Train;
+		u->subtype = 0;
+		SetArticulatedPart(u);
+		u->cur_image = 0xAC2;
+		u->random_bits = VehicleRandomBits();
+
+		VehiclePositionChanged(u);
+	}
+}
+
+static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
+{
+	int32 value;
+	const RailVehicleInfo *rvi;
+	uint num_vehicles;
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	rvi = RailVehInfo(engine);
+	value = (rvi->base_cost * _price.build_railwagon) >> 8;
+
+	num_vehicles = 1 + CountArticulatedParts(engine);
+
+	if (!(flags & DC_QUERY_COST)) {
+		Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts.
+		Vehicle* v;
+		int x;
+		int y;
+
+		memset(&vl, 0, sizeof(vl));
+
+		if (!AllocateVehicles(vl, num_vehicles))
+			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+		if (flags & DC_EXEC) {
+			Vehicle *u, *w;
+			DiagDirection dir;
+
+			v = vl[0];
+			v->spritenum = rvi->image_index;
+
+			u = NULL;
+
+			FOR_ALL_VEHICLES(w) {
+				if (w->type == VEH_Train && w->tile == tile &&
+				    IsFreeWagon(w) && w->engine_type == engine) {
+					u = GetLastVehicleInChain(w);
+					break;
+				}
+			}
+
+			v->engine_type = engine;
+
+			dir = GetRailDepotDirection(tile);
+
+			v->direction = DiagDirToDir(dir);
+			v->tile = tile;
+
+			x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
+			y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
+
+			v->x_pos = x;
+			v->y_pos = y;
+			v->z_pos = GetSlopeZ(x,y);
+			v->owner = _current_player;
+			v->z_height = 6;
+			v->u.rail.track = 0x80;
+			v->vehstatus = VS_HIDDEN | VS_DEFPAL;
+
+			v->subtype = 0;
+			SetTrainWagon(v);
+			if (u != NULL) {
+				u->next = v;
+			} else {
+				SetFreeWagon(v);
+				InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+			}
+
+			v->cargo_type = rvi->cargo_type;
+			v->cargo_subtype = 0;
+			v->cargo_cap = rvi->capacity;
+			v->value = value;
+//			v->day_counter = 0;
+
+			v->u.rail.railtype = GetEngine(engine)->railtype;
+
+			v->build_year = _cur_year;
+			v->type = VEH_Train;
+			v->cur_image = 0xAC2;
+			v->random_bits = VehicleRandomBits();
+
+			AddArticulatedParts(vl);
+
+			_new_vehicle_id = v->index;
+
+			VehiclePositionChanged(v);
+			TrainConsistChanged(GetFirstVehicleInChain(v));
+			GetPlayer(_current_player)->num_engines[engine]++;
+
+			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+			if (IsLocalPlayer()) {
+				InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
+			}
+		}
+	}
+
+	return value;
+}
+
+// Move all free vehicles in the depot to the train
+static void NormalizeTrainVehInDepot(const Vehicle* u)
+{
+	const Vehicle* v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && IsFreeWagon(v) &&
+				v->tile == u->tile &&
+				v->u.rail.track == 0x80) {
+			if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
+					CMD_MOVE_RAIL_VEHICLE)))
+				break;
+		}
+	}
+}
+
+static int32 EstimateTrainCost(const RailVehicleInfo* rvi)
+{
+	return rvi->base_cost * (_price.build_railvehicle >> 3) >> 5;
+}
+
+static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
+{
+	u->direction = v->direction;
+	u->owner = v->owner;
+	u->tile = v->tile;
+	u->x_pos = v->x_pos;
+	u->y_pos = v->y_pos;
+	u->z_pos = v->z_pos;
+	u->z_height = 6;
+	u->u.rail.track = 0x80;
+	u->vehstatus = v->vehstatus & ~VS_STOPPED;
+	u->subtype = 0;
+	SetMultiheaded(u);
+	u->spritenum = v->spritenum + 1;
+	u->cargo_type = v->cargo_type;
+	u->cargo_subtype = v->cargo_subtype;
+	u->cargo_cap = v->cargo_cap;
+	u->u.rail.railtype = v->u.rail.railtype;
+	if (building) v->next = u;
+	u->engine_type = v->engine_type;
+	u->build_year = v->build_year;
+	if (building) v->value >>= 1;
+	u->value = v->value;
+	u->type = VEH_Train;
+	u->cur_image = 0xAC2;
+	u->random_bits = VehicleRandomBits();
+	VehiclePositionChanged(u);
+}
+
+/** Build a railroad vehicle.
+ * @param tile tile of the depot where rail-vehicle is built
+ * @param p1 engine type id
+ * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number
+ *           bit 1 prevents any free cars from being added to the train
+ */
+int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	const RailVehicleInfo *rvi;
+	int value;
+	Vehicle *v;
+	UnitID unit_num;
+	Engine *e;
+	uint num_vehicles;
+
+	/* Check if the engine-type is valid (for the player) */
+	if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
+
+	/* Check if the train is actually being built in a depot belonging
+	 * to the player. Doesn't matter if only the cost is queried */
+	if (!(flags & DC_QUERY_COST)) {
+		if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR;
+		if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
+	}
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	rvi = RailVehInfo(p1);
+	e = GetEngine(p1);
+
+	/* Check if depot and new engine uses the same kind of tracks */
+	/* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
+	if (!HasPowerOnRail(e->railtype, GetRailType(tile))) return CMD_ERROR;
+
+	if (rvi->flags & RVI_WAGON) return CmdBuildRailWagon(p1, tile, flags);
+
+	value = EstimateTrainCost(rvi);
+
+	num_vehicles = (rvi->flags & RVI_MULTIHEAD) ? 2 : 1;
+	num_vehicles += CountArticulatedParts(p1);
+
+	if (!(flags & DC_QUERY_COST)) {
+		Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads
+
+		memset(&vl, 0, sizeof(vl));
+
+		if (!AllocateVehicles(vl, num_vehicles) || IsOrderPoolFull())
+			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+		v = vl[0];
+
+		unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train);
+		if (unit_num > _patches.max_trains)
+			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+		if (flags & DC_EXEC) {
+			DiagDirection dir = GetRailDepotDirection(tile);
+			int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
+			int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
+
+			v->unitnumber = unit_num;
+			v->direction = DiagDirToDir(dir);
+			v->tile = tile;
+			v->owner = _current_player;
+			v->x_pos = x;
+			v->y_pos = y;
+			v->z_pos = GetSlopeZ(x,y);
+			v->z_height = 6;
+			v->u.rail.track = 0x80;
+			v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
+			v->spritenum = rvi->image_index;
+			v->cargo_type = rvi->cargo_type;
+			v->cargo_subtype = 0;
+			v->cargo_cap = rvi->capacity;
+			v->max_speed = rvi->max_speed;
+			v->value = value;
+			v->last_station_visited = INVALID_STATION;
+			v->dest_tile = 0;
+
+			v->engine_type = p1;
+
+			v->reliability = e->reliability;
+			v->reliability_spd_dec = e->reliability_spd_dec;
+			v->max_age = e->lifelength * 366;
+
+			v->string_id = STR_SV_TRAIN_NAME;
+			v->u.rail.railtype = e->railtype;
+			_new_vehicle_id = v->index;
+
+			v->service_interval = _patches.servint_trains;
+			v->date_of_last_service = _date;
+			v->build_year = _cur_year;
+			v->type = VEH_Train;
+			v->cur_image = 0xAC2;
+			v->random_bits = VehicleRandomBits();
+
+			v->subtype = 0;
+			SetFrontEngine(v);
+			SetTrainEngine(v);
+
+			VehiclePositionChanged(v);
+
+			if (rvi->flags & RVI_MULTIHEAD) {
+				SetMultiheaded(v);
+				AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
+				/* Now we need to link the front and rear engines together
+				 * other_multiheaded_part is the pointer that links to the other half of the engine
+				 * vl[0] is the front and vl[1] is the rear
+				 */
+				vl[0]->u.rail.other_multiheaded_part = vl[1];
+				vl[1]->u.rail.other_multiheaded_part = vl[0];
+			} else {
+				AddArticulatedParts(vl);
+			}
+
+			TrainConsistChanged(v);
+			UpdateTrainAcceleration(v);
+
+			if (!HASBIT(p2, 1)) { // check if the cars should be added to the new vehicle
+				NormalizeTrainVehInDepot(v);
+			}
+
+			GetPlayer(_current_player)->num_engines[p1]++;
+			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+			RebuildVehicleLists();
+			InvalidateWindow(WC_COMPANY, v->owner);
+			if (IsLocalPlayer()) {
+				InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train); // updates the replace Train window
+			}
+		}
+	}
+
+	return value;
+}
+
+
+/* Check if all the wagons of the given train are in a depot, returns the
+ * number of cars (including loco) then. If not it returns -1 */
+int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped)
+{
+	int count;
+	TileIndex tile = v->tile;
+
+	/* check if stopped in a depot */
+	if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1;
+
+	count = 0;
+	for (; v != NULL; v = v->next) {
+		/* This count is used by the depot code to determine the number of engines
+		 * in the consist. Exclude articulated parts so that autoreplacing to
+		 * engines with more articulated parts than before works correctly.
+		 *
+		 * Also skip counting rear ends of multiheaded engines */
+		if (!IsArticulatedPart(v) && !(!IsTrainEngine(v) && IsMultiheaded(v))) count++;
+		if (v->u.rail.track != 0x80 || v->tile != tile ||
+				(IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
+			return -1;
+		}
+	}
+
+	return count;
+}
+
+/* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
+inline int CheckTrainStoppedInDepot(const Vehicle *v)
+{
+	return CheckTrainInDepot(v, true);
+}
+
+/* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
+inline bool CheckTrainIsInsideDepot(const Vehicle *v)
+{
+	return (CheckTrainInDepot(v, false) > 0);
+}
+
+/**
+ * Unlink a rail wagon from the consist.
+ * @param v Vehicle to remove.
+ * @param first The first vehicle of the consist.
+ * @return The first vehicle of the consist.
+ */
+static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
+{
+	Vehicle *u;
+
+	// unlinking the first vehicle of the chain?
+	if (v == first) {
+		v = GetNextVehicle(v);
+		if (v == NULL) return NULL;
+
+		if (IsTrainWagon(v)) SetFreeWagon(v);
+
+		return v;
+	}
+
+	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
+	GetLastEnginePart(u)->next = GetNextVehicle(v);
+	return first;
+}
+
+static Vehicle *FindGoodVehiclePos(const Vehicle *src)
+{
+	Vehicle *dst;
+	EngineID eng = src->engine_type;
+	TileIndex tile = src->tile;
+
+	FOR_ALL_VEHICLES(dst) {
+		if (dst->type == VEH_Train && IsFreeWagon(dst) && dst->tile == tile) {
+			// check so all vehicles in the line have the same engine.
+			Vehicle *v = dst;
+
+			while (v->engine_type == eng) {
+				v = v->next;
+				if (v == NULL) return dst;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * add a vehicle v behind vehicle dest
+ * use this function since it sets flags as needed
+ */
+static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
+{
+	UnlinkWagon(v, GetFirstVehicleInChain(v));
+	if (dest == NULL) return;
+
+	v->next = dest->next;
+	dest->next = v;
+	ClearFreeWagon(v);
+	ClearFrontEngine(v);
+}
+
+/*
+ * move around on the train so rear engines are placed correctly according to the other engines
+ * always call with the front engine
+ */
+static void NormaliseTrainConsist(Vehicle *v)
+{
+	Vehicle *u;
+
+	if (IsFreeWagon(v)) return;
+
+	assert(IsFrontEngine(v));
+
+	for (; v != NULL; v = GetNextVehicle(v)) {
+		if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
+
+		/* make sure that there are no free cars before next engine */
+		for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next);
+
+		if (u == v->u.rail.other_multiheaded_part) continue;
+		AddWagonToConsist(v->u.rail.other_multiheaded_part, u);
+	}
+}
+
+/** Move a rail vehicle around inside the depot.
+ * @param tile unused
+ * @param p1 various bitstuffed elements
+ * - p1 (bit  0 - 15) source vehicle index
+ * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line
+ * @param p2 (bit 0) move all vehicles following the source vehicle
+ */
+int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	VehicleID s = GB(p1, 0, 16);
+	VehicleID d = GB(p1, 16, 16);
+	Vehicle *src, *dst, *src_head, *dst_head;
+
+	if (!IsValidVehicleID(s)) return CMD_ERROR;
+
+	src = GetVehicle(s);
+
+	if (src->type != VEH_Train) return CMD_ERROR;
+
+	// if nothing is selected as destination, try and find a matching vehicle to drag to.
+	if (d == INVALID_VEHICLE) {
+		dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
+	} else {
+		dst = GetVehicle(d);
+	}
+
+	// if an articulated part is being handled, deal with its parent vehicle
+	while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src);
+	if (dst != NULL) {
+		while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst);
+	}
+
+	// don't move the same vehicle..
+	if (src == dst) return 0;
+
+	/* the player must be the owner */
+	if (!CheckOwnership(src->owner) || (dst != NULL && !CheckOwnership(dst->owner)))
+		return CMD_ERROR;
+
+	/* locate the head of the two chains */
+	src_head = GetFirstVehicleInChain(src);
+	dst_head = NULL;
+	if (dst != NULL) {
+		dst_head = GetFirstVehicleInChain(dst);
+		// Now deal with articulated part of destination wagon
+		dst = GetLastEnginePart(dst);
+	}
+
+	if (dst != NULL && IsMultiheaded(dst) && !IsTrainEngine(dst) && IsTrainWagon(src)) {
+		/* We are moving a wagon to the rear part of a multiheaded engine */
+		if (dst->next == NULL) {
+			/* It's the last one, so we will add the wagon just before the rear engine */
+			dst = GetPrevVehicleInChain(dst);
+			/* Now if the vehicle we want to link to is the vehicle itself, drop out */
+			if (dst == src) return CMD_ERROR;
+			// if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that
+			if (dst == NULL) return CMD_ERROR;
+		} else {
+			/* there are more units on this train, so we will add the wagon after the next one*/
+			dst = dst->next;
+		}
+	}
+
+	if (IsTrainEngine(src) && dst_head != NULL) {
+		/* we need to make sure that we didn't place it between a pair of multiheaded engines */
+		Vehicle *u, *engine = NULL;
+
+		for (u = dst_head; u != NULL; u = u->next) {
+			if (IsTrainEngine(u) && IsMultiheaded(u) && u->u.rail.other_multiheaded_part != NULL) {
+				engine = u;
+			}
+			if (engine != NULL && engine->u.rail.other_multiheaded_part == u) {
+				engine = NULL;
+			}
+			if (u == dst) {
+				if (engine != NULL) dst = engine->u.rail.other_multiheaded_part;
+				break;
+			}
+		}
+	}
+
+	if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
+
+	// when moving all wagons, we can't have the same src_head and dst_head
+	if (HASBIT(p2, 0) && src_head == dst_head) return 0;
+
+	{
+		int src_len = 0;
+		int max_len = _patches.mammoth_trains ? 100 : 9;
+
+		// check if all vehicles in the source train are stopped inside a depot.
+		src_len = CheckTrainStoppedInDepot(src_head);
+		if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
+
+		// check the destination row if the source and destination aren't the same.
+		if (src_head != dst_head) {
+			int dst_len = 0;
+
+			if (dst_head != NULL) {
+				// check if all vehicles in the dest train are stopped.
+				dst_len = CheckTrainStoppedInDepot(dst_head);
+				if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
+
+				assert(dst_head->tile == src_head->tile);
+			}
+
+			// We are moving between rows, so only count the wagons from the source
+			// row that are being moved.
+			if (HASBIT(p2, 0)) {
+				const Vehicle *u;
+				for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
+					src_len--;
+			} else {
+				// If moving only one vehicle, just count that.
+				src_len = 1;
+			}
+
+			if (src_len + dst_len > max_len) {
+				// Abort if we're adding too many wagons to a train.
+				if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
+				// Abort if we're making a train on a new row.
+				if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
+			}
+		} else {
+			// Abort if we're creating a new train on an existing row.
+			if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
+				return_cmd_error(STR_8819_TRAIN_TOO_LONG);
+		}
+	}
+
+	// moving a loco to a new line?, then we need to assign a unitnumber.
+	if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
+		UnitID unit_num = GetFreeUnitNumber(VEH_Train);
+		if (unit_num > _patches.max_trains)
+			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+
+		if (flags & DC_EXEC) src->unitnumber = unit_num;
+	}
+
+	if (dst_head != NULL) {
+		/* Check NewGRF Callback 0x1D */
+		uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, src, dst_head);
+		if (callback != CALLBACK_FAILED) {
+			if (callback == 0xFD) return_cmd_error(STR_INCOMPATIBLE_RAIL_TYPES);
+			if (callback < 0xFD) {
+				StringID error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback);
+				return_cmd_error(error);
+			}
+		}
+	}
+
+	/* do it? */
+	if (flags & DC_EXEC) {
+		/* clear the ->first cache */
+		{
+			Vehicle *u;
+
+			for (u = src_head; u != NULL; u = u->next) u->first = NULL;
+			for (u = dst_head; u != NULL; u = u->next) u->first = NULL;
+		}
+
+		if (HASBIT(p2, 0)) {
+			// unlink ALL wagons
+			if (src != src_head) {
+				Vehicle *v = src_head;
+				while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
+				GetLastEnginePart(v)->next = NULL;
+			} else {
+				InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
+				src_head = NULL;
+			}
+		} else {
+			// if moving within the same chain, dont use dst_head as it may get invalidated
+			if (src_head == dst_head) dst_head = NULL;
+			// unlink single wagon from linked list
+			src_head = UnlinkWagon(src, src_head);
+			GetLastEnginePart(src)->next = NULL;
+		}
+
+		if (dst == NULL) {
+			/* We make a new line in the depot, so we know already that we invalidate the window data */
+			InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
+
+			// move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4.
+			if (IsTrainEngine(src)) {
+				if (!IsFrontEngine(src)) {
+					// setting the type to 0 also involves setting up the orders field.
+					SetFrontEngine(src);
+					assert(src->orders == NULL);
+					src->num_orders = 0;
+				}
+			} else {
+				SetFreeWagon(src);
+			}
+			dst_head = src;
+		} else {
+			if (IsFrontEngine(src)) {
+				// the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
+				DeleteWindowById(WC_VEHICLE_VIEW, src->index);
+				DeleteVehicleOrders(src);
+			}
+
+			if (IsFrontEngine(src) || IsFreeWagon(src)) {
+				InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
+				ClearFrontEngine(src);
+				ClearFreeWagon(src);
+				src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
+			}
+
+			// link in the wagon(s) in the chain.
+			{
+				Vehicle *v;
+
+				for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v));
+				GetLastEnginePart(v)->next = dst->next;
+			}
+			dst->next = src;
+		}
+		if (src->u.rail.other_multiheaded_part != NULL) {
+			if (src->u.rail.other_multiheaded_part == src_head) {
+				src_head = src_head->next;
+			}
+			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
+			// previous line set the front engine to the old front. We need to clear that
+			src->u.rail.other_multiheaded_part->first = NULL;
+		}
+
+		if (HASBIT(p2, 0) && src_head != NULL && src_head != src) {
+			/* if we stole a rear multiheaded engine, we better give it back to the front end */
+			Vehicle *engine = NULL, *u;
+			for (u = src_head; u != NULL; u = u->next) {
+				if (IsMultiheaded(u)) {
+					if (IsTrainEngine(u)) {
+						engine = u;
+						continue;
+					}
+					/* we got the rear engine to match with the front one */
+					engine = NULL;
+				}
+			}
+			if (engine != NULL && engine->u.rail.other_multiheaded_part != NULL) {
+				AddWagonToConsist(engine->u.rail.other_multiheaded_part, engine);
+				// previous line set the front engine to the old front. We need to clear that
+				engine->u.rail.other_multiheaded_part->first = NULL;
+			}
+		}
+
+		/* If there is an engine behind first_engine we moved away, it should become new first_engine
+		 * To do this, CmdMoveRailVehicle must be called once more
+		 * we can't loop forever here because next time we reach this line we will have a front engine */
+		if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
+			CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1);
+			src_head = NULL; // don't do anything more to this train since the new call will do it
+		}
+
+		if (src_head != NULL) {
+			NormaliseTrainConsist(src_head);
+			TrainConsistChanged(src_head);
+			if (IsFrontEngine(src_head)) {
+				UpdateTrainAcceleration(src_head);
+				InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
+				/* Update the refit button and window */
+				InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12);
+			}
+			/* Update the depot window */
+			InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
+		};
+
+		if (dst_head != NULL) {
+			NormaliseTrainConsist(dst_head);
+			TrainConsistChanged(dst_head);
+			if (IsFrontEngine(dst_head)) {
+				UpdateTrainAcceleration(dst_head);
+				InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
+				/* Update the refit button and window */
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12);
+				InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
+			}
+			/* Update the depot window */
+			InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
+		}
+
+		RebuildVehicleLists();
+	}
+
+	return 0;
+}
+
+/** Start/Stop a train.
+ * @param tile unused
+ * @param p1 train to start/stop
+ * @param p2 unused
+ */
+int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	uint16 callback;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	/* Check if this train can be started/stopped. The callback will fail or
+	 * return 0xFF if it can. */
+	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
+	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
+		return_cmd_error(error);
+	}
+
+	if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
+
+	if (flags & DC_EXEC) {
+		if (v->vehstatus & VS_STOPPED && v->u.rail.track == 0x80) {
+			DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT);
+		}
+
+		v->u.rail.days_since_order_progr = 0;
+		v->vehstatus ^= VS_STOPPED;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+	}
+	return 0;
+}
+
+/** Sell a (single) train wagon/engine.
+ * @param tile unused
+ * @param p1 the wagon/engine index
+ * @param p2 the selling mode
+ * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines)
+ * - p2 = 1: sell the vehicle and all vehicles following it in the chain
+             if the wagon is dragged, don't delete the possibly belonging rear-engine to some front
+ * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines;
+ *           all wagons of the same type will go on the same line. Used by the AI currently
+ */
+int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v, *tmp, *first;
+	Vehicle *new_f = NULL;
+	int32 cost = 0;
+
+	if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+
+	while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
+	first = GetFirstVehicleInChain(v);
+
+	// make sure the vehicle is stopped in the depot
+	if (CheckTrainStoppedInDepot(first) < 0) {
+		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
+	}
+
+	if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
+
+	if (flags & DC_EXEC) {
+		if (v == first && IsFrontEngine(first)) {
+			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
+		}
+		if (IsLocalPlayer() && (p1 == 1 || !(RailVehInfo(v->engine_type)->flags & RVI_WAGON))) {
+			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
+		}
+		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
+		RebuildVehicleLists();
+	}
+
+	switch (p2) {
+		case 0: case 2: { /* Delete given wagon */
+			bool switch_engine = false;    // update second wagon to engine?
+			byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes
+
+			/* 1. Delete the engine, if it is dualheaded also delete the matching
+			 * rear engine of the loco (from the point of deletion onwards) */
+			Vehicle *rear = (IsMultiheaded(v) &&
+				IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
+
+			if (rear != NULL) {
+				cost -= rear->value;
+				if (flags & DC_EXEC) {
+					UnlinkWagon(rear, first);
+					DeleteDepotHighlightOfVehicle(rear);
+					DeleteVehicle(rear);
+				}
+			}
+
+			/* 2. We are selling the first engine, some special action might be required
+			 * here, so take attention */
+			if ((flags & DC_EXEC) && v == first) {
+				new_f = GetNextVehicle(first);
+
+				/* 2.1 If the first wagon is sold, update the first-> pointers to NULL */
+				for (tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL;
+
+				/* 2.2 If there are wagons present after the deleted front engine, check
+         * if the second wagon (which will be first) is an engine. If it is one,
+         * promote it as a new train, retaining the unitnumber, orders */
+				if (new_f != NULL) {
+					if (IsTrainEngine(new_f)) {
+						switch_engine = true;
+						/* Copy important data from the front engine */
+						new_f->unitnumber = first->unitnumber;
+						new_f->current_order = first->current_order;
+						new_f->cur_order_index = first->cur_order_index;
+						new_f->orders = first->orders;
+						if (first->prev_shared != NULL) {
+							first->prev_shared->next_shared = new_f;
+							new_f->prev_shared = first->prev_shared;
+						}
+
+						if (first->next_shared != NULL) {
+							first->next_shared->prev_shared = new_f;
+							new_f->next_shared = first->next_shared;
+						}
+
+						new_f->num_orders = first->num_orders;
+						first->orders = NULL; // XXX - to not to delete the orders */
+						if (IsLocalPlayer()) ShowTrainViewWindow(new_f);
+					}
+				}
+			}
+
+			/* 3. Delete the requested wagon */
+			cost -= v->value;
+			if (flags & DC_EXEC) {
+				first = UnlinkWagon(v, first);
+				DeleteDepotHighlightOfVehicle(v);
+				DeleteVehicle(v);
+
+				/* 4 If the second wagon was an engine, update it to front_engine
+					* which UnlinkWagon() has changed to TS_Free_Car */
+				if (switch_engine) SetFrontEngine(first);
+
+				/* 5. If the train still exists, update its acceleration, window, etc. */
+				if (first != NULL) {
+					NormaliseTrainConsist(first);
+					TrainConsistChanged(first);
+					if (IsFrontEngine(first)) {
+						InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
+						InvalidateWindow(WC_VEHICLE_REFIT, first->index);
+						UpdateTrainAcceleration(first);
+					}
+				}
+
+
+				/* (6.) Borked AI. If it sells an engine it expects all wagons lined
+				 * up on a new line to be added to the newly built loco. Replace it is.
+				 * Totally braindead cause building a new engine adds all loco-less
+				 * engines to its train anyways */
+				if (p2 == 2 && HASBIT(ori_subtype, Train_Front)) {
+					for (v = first; v != NULL; v = tmp) {
+						tmp = GetNextVehicle(v);
+						DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+					}
+				}
+			}
+		} break;
+		case 1: { /* Delete wagon and all wagons after it given certain criteria */
+			/* Start deleting every vehicle after the selected one
+			 * If we encounter a matching rear-engine to a front-engine
+			 * earlier in the chain (before deletion), leave it alone */
+			for (; v != NULL; v = tmp) {
+				tmp = GetNextVehicle(v);
+
+				if (IsMultiheaded(v)) {
+					if (IsTrainEngine(v)) {
+						/* We got a front engine of a multiheaded set. Now we will sell the rear end too */
+						Vehicle *rear = v->u.rail.other_multiheaded_part;
+
+						if (rear != NULL) {
+							cost -= rear->value;
+							if (flags & DC_EXEC) {
+								first = UnlinkWagon(rear, first);
+								DeleteDepotHighlightOfVehicle(rear);
+								DeleteVehicle(rear);
+							}
+						}
+					} else if (v->u.rail.other_multiheaded_part != NULL) {
+						/* The front to this engine is earlier in this train. Do nothing */
+						continue;
+					}
+				}
+
+				cost -= v->value;
+				if (flags & DC_EXEC) {
+					first = UnlinkWagon(v, first);
+					DeleteDepotHighlightOfVehicle(v);
+					DeleteVehicle(v);
+				}
+			}
+
+			/* 3. If it is still a valid train after selling, update its acceleration and cached values */
+			if (flags & DC_EXEC && first != NULL) {
+				NormaliseTrainConsist(first);
+				TrainConsistChanged(first);
+				if (IsFrontEngine(first)) UpdateTrainAcceleration(first);
+				InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
+				InvalidateWindow(WC_VEHICLE_REFIT, first->index);
+			}
+		} break;
+	}
+	return cost;
+}
+
+static void UpdateTrainDeltaXY(Vehicle *v, Direction direction)
+{
+#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
+	static const uint32 _delta_xy_table[8] = {
+		MKIT(3, 3, -1, -1),
+		MKIT(3, 7, -1, -3),
+		MKIT(3, 3, -1, -1),
+		MKIT(7, 3, -3, -1),
+		MKIT(3, 3, -1, -1),
+		MKIT(3, 7, -1, -3),
+		MKIT(3, 3, -1, -1),
+		MKIT(7, 3, -3, -1),
+	};
+#undef MKIT
+
+	uint32 x = _delta_xy_table[direction];
+
+	v->x_offs        = GB(x,  0, 8);
+	v->y_offs        = GB(x,  8, 8);
+	v->sprite_width  = GB(x, 16, 8);
+	v->sprite_height = GB(x, 24, 8);
+}
+
+static void UpdateVarsAfterSwap(Vehicle *v)
+{
+	UpdateTrainDeltaXY(v, v->direction);
+	v->cur_image = GetTrainImage(v, v->direction);
+	BeginVehicleMove(v);
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+}
+
+static void SetLastSpeed(Vehicle* v, int spd)
+{
+	int old = v->u.rail.last_speed;
+	if (spd != old) {
+		v->u.rail.last_speed = spd;
+		if (_patches.vehicle_speed || (old == 0) != (spd == 0))
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+	}
+}
+
+static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2)
+{
+	byte flag1, flag2;
+
+	flag1 = *swap_flag1;
+	flag2 = *swap_flag2;
+
+	/* Clear the flags */
+	CLRBIT(*swap_flag1, VRF_GOINGUP);
+	CLRBIT(*swap_flag1, VRF_GOINGDOWN);
+	CLRBIT(*swap_flag2, VRF_GOINGUP);
+	CLRBIT(*swap_flag2, VRF_GOINGDOWN);
+
+	/* Reverse the rail-flags (if needed) */
+	if (HASBIT(flag1, VRF_GOINGUP)) {
+		SETBIT(*swap_flag2, VRF_GOINGDOWN);
+	} else if (HASBIT(flag1, VRF_GOINGDOWN)) {
+		SETBIT(*swap_flag2, VRF_GOINGUP);
+	}
+	if (HASBIT(flag2, VRF_GOINGUP)) {
+		SETBIT(*swap_flag1, VRF_GOINGDOWN);
+	} else if (HASBIT(flag2, VRF_GOINGDOWN)) {
+		SETBIT(*swap_flag1, VRF_GOINGUP);
+	}
+}
+
+static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
+{
+	Vehicle *a, *b;
+
+	/* locate vehicles to swap */
+	for (a = v; l != 0; l--) a = a->next;
+	for (b = v; r != 0; r--) b = b->next;
+
+	if (a != b) {
+		/* swap the hidden bits */
+		{
+			uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN);
+			b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus&VS_HIDDEN);
+			a->vehstatus = tmp;
+		}
+
+		/* swap variables */
+		swap_byte(&a->u.rail.track, &b->u.rail.track);
+		swap_byte(&a->direction, &b->direction);
+
+		/* toggle direction */
+		if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
+		if (!(b->u.rail.track & 0x80)) b->direction = ReverseDir(b->direction);
+
+		/* swap more variables */
+		swap_int32(&a->x_pos, &b->x_pos);
+		swap_int32(&a->y_pos, &b->y_pos);
+		swap_tile(&a->tile, &b->tile);
+		swap_byte(&a->z_pos, &b->z_pos);
+
+		SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags);
+
+		/* update other vars */
+		UpdateVarsAfterSwap(a);
+		UpdateVarsAfterSwap(b);
+
+		/* call the proper EnterTile function unless we are in a wormhole */
+		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
+		if (!(b->u.rail.track & 0x40)) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
+	} else {
+		if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
+		UpdateVarsAfterSwap(a);
+
+		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
+	}
+
+	/* Update train's power incase tiles were different rail type */
+	TrainPowerChanged(v);
+}
+
+/* Check if the vehicle is a train and is on the tile we are testing */
+static void *TestTrainOnCrossing(Vehicle *v, void *data)
+{
+	if (v->tile != *(const TileIndex*)data || v->type != VEH_Train) return NULL;
+	return v;
+}
+
+static void DisableTrainCrossing(TileIndex tile)
+{
+	if (IsLevelCrossingTile(tile) &&
+			VehicleFromPos(tile, &tile, TestTrainOnCrossing) == NULL && // empty?
+			IsCrossingBarred(tile)) {
+		UnbarCrossing(tile);
+		MarkTileDirtyByTile(tile);
+	}
+}
+
+/**
+ * Advances wagons for train reversing, needed for variable length wagons.
+ * Needs to be called once before the train is reversed, and once after it.
+ * @param v First vehicle in chain
+ * @param before Set to true for the call before reversing, false otherwise
+ */
+static void AdvanceWagons(Vehicle *v, bool before)
+{
+	Vehicle* base;
+	Vehicle* first;
+	int length;
+
+	base = v;
+	first = base->next;
+	length = CountVehiclesInChain(v);
+
+	while (length > 2) {
+		Vehicle* last;
+		int differential;
+		int i;
+
+		// find pairwise matching wagon
+		// start<>end, start+1<>end-1, ...
+		last = first;
+		for (i = length - 3; i > 0; i--) last = last->next;
+
+		differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
+		if (before) differential *= -1;
+
+		if (differential > 0) {
+			Vehicle* tempnext;
+
+			// disconnect last car to make sure only this subset moves
+			tempnext = last->next;
+			last->next = NULL;
+
+			for (i = 0; i < differential; i++) TrainController(first, false);
+
+			last->next = tempnext;
+		}
+
+		base = first;
+		first = first->next;
+		length -= 2;
+	}
+}
+
+
+static void ReverseTrainDirection(Vehicle *v)
+{
+	int l = 0, r = -1;
+	Vehicle *u;
+
+	if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	}
+
+	/* Check if we were approaching a rail/road-crossing */
+	{
+		TileIndex tile = v->tile;
+		DiagDirection dir = DirToDiagDir(v->direction);
+
+		/* Determine the diagonal direction in which we will exit this tile */
+		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) {
+			dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT);
+		}
+		/* Calculate next tile */
+		tile += TileOffsByDiagDir(dir);
+
+		/* Check if the train left a rail/road-crossing */
+		DisableTrainCrossing(tile);
+	}
+
+	// count number of vehicles
+	u = v;
+	do r++; while ( (u = u->next) != NULL );
+
+	AdvanceWagons(v, true);
+
+	/* swap start<>end, start+1<>end-1, ... */
+	do {
+		ReverseTrainSwapVeh(v, l++, r--);
+	} while (l <= r);
+
+	AdvanceWagons(v, false);
+
+	if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	}
+
+	CLRBIT(v->u.rail.flags, VRF_REVERSING);
+}
+
+/** Reverse train.
+ * @param tile unused
+ * @param p1 train to reverse
+ * @param p2 if true, reverse a unit in a train (needs to be in a depot)
+ */
+int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (p2) {
+		// turn a single unit around
+		Vehicle *front;
+
+		if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) {
+			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
+		}
+
+		front = GetFirstVehicleInChain(v);
+		// make sure the vehicle is stopped in the depot
+		if (CheckTrainStoppedInDepot(front) < 0) {
+			return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
+		}
+
+		if (flags & DC_EXEC) {
+			TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION);
+			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		}
+	} else {
+		//turn the whole train around
+		if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR;
+
+		if (flags & DC_EXEC) {
+			if (_patches.realistic_acceleration && v->cur_speed != 0) {
+				TOGGLEBIT(v->u.rail.flags, VRF_REVERSING);
+			} else {
+				v->cur_speed = 0;
+				SetLastSpeed(v, 0);
+				ReverseTrainDirection(v);
+			}
+		}
+	}
+	return 0;
+}
+
+/** Force a train through a red signal
+ * @param tile unused
+ * @param p1 train to ignore the red signal
+ * @param p2 unused
+ */
+int32 CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
+
+	return 0;
+}
+
+/** Refits a train to the specified cargo type.
+ * @param tile unused
+ * @param p1 vehicle ID of the train to refit
+ * param p2 various bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to
+ * - p2 = (bit 8-15) - the new cargo subtype to refit to
+ */
+int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	CargoID new_cid = GB(p2, 0, 8);
+	byte new_subtype = GB(p2, 8, 8);
+	Vehicle *v;
+	int32 cost;
+	uint num;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
+
+	/* Check cargo */
+	if (new_cid > NUM_CARGO) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
+
+	cost = 0;
+	num = 0;
+
+	do {
+		/* XXX: We also refit all the attached wagons en-masse if they
+		 * can be refitted. This is how TTDPatch does it.  TODO: Have
+		 * some nice [Refit] button near each wagon. --pasky */
+		if (!CanRefitTo(v->engine_type, new_cid)) continue;
+
+		if (v->cargo_cap != 0) {
+			const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
+			uint16 amount = CALLBACK_FAILED;
+
+			if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) {
+				/* Back up the vehicle's cargo type */
+				CargoID temp_cid = v->cargo_type;
+				byte temp_subtype = v->cargo_subtype;
+				v->cargo_type = new_cid;
+				v->cargo_subtype = new_subtype;
+				/* Check the refit capacity callback */
+				amount = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
+				/* Restore the original cargo type */
+				v->cargo_type = temp_cid;
+				v->cargo_subtype = temp_subtype;
+			}
+
+			if (amount == CALLBACK_FAILED) { // callback failed or not used, use default
+				CargoID old_cid = rvi->cargo_type;
+				/* normally, the capacity depends on the cargo type, a rail vehicle can
+				 * carry twice as much mail/goods as normal cargo, and four times as
+				 * many passengers
+				 */
+				amount = rvi->capacity;
+				switch (old_cid) {
+					case CT_PASSENGERS: break;
+					case CT_MAIL:
+					case CT_GOODS: amount *= 2; break;
+					default:       amount *= 4; break;
+				}
+				switch (new_cid) {
+					case CT_PASSENGERS: break;
+					case CT_MAIL:
+					case CT_GOODS: amount /= 2; break;
+					default:       amount /= 4; break;
+				}
+			};
+
+			if (amount != 0) {
+				if (new_cid != v->cargo_type) {
+					cost += GetRefitCost(v->engine_type);
+				}
+
+				num += amount;
+				if (flags & DC_EXEC) {
+					v->cargo_count = (v->cargo_type == new_cid) ? min(amount, v->cargo_count) : 0;
+					v->cargo_type = new_cid;
+					v->cargo_cap = amount;
+					v->cargo_subtype = new_subtype;
+					InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+					InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+					RebuildVehicleLists();
+				}
+			}
+		}
+	} while ((v = v->next) != NULL);
+
+	_returned_refit_capacity = num;
+
+	/* Update the train's cached variables */
+	if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1)));
+
+	return cost;
+}
+
+typedef struct TrainFindDepotData {
+	uint best_length;
+	TileIndex tile;
+	PlayerID owner;
+	/**
+	 * true if reversing is necessary for the train to get to this depot
+	 * This value is unused when new depot finding and NPF are both disabled
+	 */
+	bool reverse;
+} TrainFindDepotData;
+
+static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
+{
+	if (IsTileType(tile, MP_RAILWAY) &&
+			IsTileOwner(tile, tfdd->owner) &&
+			IsRailDepot(tile)) {
+		/* approximate number of tiles by dividing by DIAG_FACTOR */
+		tfdd->best_length = length / DIAG_FACTOR;
+		tfdd->tile = tile;
+		return true;
+	}
+
+	return false;
+}
+
+// returns the tile of a depot to goto to. The given vehicle must not be
+// crashed!
+static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
+{
+	TrainFindDepotData tfdd;
+	TileIndex tile = v->tile;
+
+	assert(!(v->vehstatus & VS_CRASHED));
+
+	tfdd.owner = v->owner;
+	tfdd.best_length = (uint)-1;
+	tfdd.reverse = false;
+
+	if (IsTileDepotType(tile, TRANSPORT_RAIL)){
+		tfdd.tile = tile;
+		tfdd.best_length = 0;
+		return tfdd;
+	}
+
+	if (_patches.yapf.rail_use_yapf) {
+		bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
+		tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND
+	} else if (_patches.new_pathfinding_all) {
+		NPFFoundTargetData ftd;
+		Vehicle* last = GetLastVehicleInChain(v);
+		Trackdir trackdir = GetVehicleTrackdir(v);
+		Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
+
+		assert (trackdir != INVALID_TRACKDIR);
+		ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
+		if (ftd.best_bird_dist == 0) {
+			/* Found target */
+			tfdd.tile = ftd.node.tile;
+			/* Our caller expects a number of tiles, so we just approximate that
+			 * number by this. It might not be completely what we want, but it will
+			 * work for now :-) We can possibly change this when the old pathfinder
+			 * is removed. */
+			tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
+			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
+		}
+	} else {
+		// search in the forward direction first.
+		DiagDirection i;
+
+		i = DirToDiagDir(v->direction);
+		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
+			i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
+		}
+		NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
+		if (tfdd.best_length == (uint)-1){
+			tfdd.reverse = true;
+			// search in backwards direction
+			i = ReverseDiagDir(DirToDiagDir(v->direction));
+			if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
+				i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
+			}
+			NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
+		}
+	}
+
+	return tfdd;
+}
+
+/** Send a train to a depot
+ * @param tile unused
+ * @param p1 train to send to the depot
+ * @param p2 various bitmasked elements
+ * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
+ * - p2 bit 8-10 - VLW flag (for mass goto depot)
+ */
+int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	TrainFindDepotData tfdd;
+
+	if (p2 & DEPOT_MASS_SEND) {
+		/* Mass goto depot requested */
+		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
+		return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
+	}
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
+
+	if (v->current_order.type == OT_GOTO_DEPOT) {
+		if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) {
+			/* We called with a different DEPOT_SERVICE setting.
+			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
+			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
+			if (flags & DC_EXEC) {
+				TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			}
+			return 0;
+		}
+
+		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
+		if (flags & DC_EXEC) {
+			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
+				v->u.rail.days_since_order_progr = 0;
+				v->cur_order_index++;
+			}
+
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return 0;
+	}
+
+	/* check if at a standstill (not stopped only) in a depot
+	 * the check is down here to make it possible to alter stop/service for trains entering the depot */
+	if (IsTileDepotType(v->tile, TRANSPORT_RAIL) && v->cur_speed == 0) return CMD_ERROR;
+
+	tfdd = FindClosestTrainDepot(v, 0);
+	if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO);
+
+	if (flags & DC_EXEC) {
+		v->dest_tile = tfdd.tile;
+		v->current_order.type = OT_GOTO_DEPOT;
+		v->current_order.flags = OF_NON_STOP;
+		if (!(p2 & DEPOT_SERVICE)) SETBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
+		v->current_order.dest = GetDepotByTile(tfdd.tile)->index;
+		v->current_order.refit_cargo = CT_INVALID;
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		/* If there is no depot in front, reverse automatically */
+		if (tfdd.reverse)
+			DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
+	}
+
+	return 0;
+}
+
+
+void OnTick_Train(void)
+{
+	_age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
+}
+
+static const int8 _vehicle_smoke_pos[8] = {
+	1, 1, 1, 0, -1, -1, -1, 0
+};
+
+static void HandleLocomotiveSmokeCloud(const Vehicle* v)
+{
+	const Vehicle* u;
+	bool sound = false;
+
+	if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2)
+		return;
+
+	u = v;
+
+	do {
+		EngineID engtype = v->engine_type;
+		int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
+		byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
+		bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6);
+		int x, y;
+
+		// no smoke?
+		if ((RailVehInfo(engtype)->flags & RVI_WAGON && effect_type == 0) ||
+				disable_effect ||
+				GetEngine(engtype)->railtype > RAILTYPE_ELECTRIC ||
+				v->vehstatus & VS_HIDDEN) {
+			continue;
+		}
+
+		// No smoke in depots or tunnels
+		if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue;
+
+		// No sparks for electric vehicles on nonelectrified tracks
+		if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile, GetVehicleTrackdir(v)))) continue;
+
+		if (effect_type == 0) {
+			// Use default effect type for engine class.
+			effect_type = RailVehInfo(engtype)->engclass;
+		} else {
+			effect_type--;
+		}
+
+		x = _vehicle_smoke_pos[v->direction] * effect_offset;
+		y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
+
+		if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
+			x = -x;
+			y = -y;
+		}
+
+		switch (effect_type) {
+		case 0:
+			// steam smoke.
+			if (GB(v->tick_counter, 0, 4) == 0) {
+				CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
+				sound = true;
+			}
+			break;
+
+		case 1:
+			// diesel smoke
+			if (u->cur_speed <= 40 && CHANCE16(15, 128)) {
+				CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
+				sound = true;
+			}
+			break;
+
+		case 2:
+			// blue spark
+			if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) {
+				CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
+				sound = true;
+			}
+			break;
+		}
+	} while ((v = v->next) != NULL);
+
+	if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
+}
+
+static void TrainPlayLeaveStationSound(const Vehicle* v)
+{
+	static const SoundFx sfx[] = {
+		SND_04_TRAIN,
+		SND_0A_TRAIN_HORN,
+		SND_0A_TRAIN_HORN
+	};
+
+	EngineID engtype = v->engine_type;
+
+	if (PlayVehicleSound(v, VSE_START)) return;
+
+	switch (GetEngine(engtype)->railtype) {
+		case RAILTYPE_RAIL:
+		case RAILTYPE_ELECTRIC:
+			SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
+			break;
+
+		case RAILTYPE_MONO: SndPlayVehicleFx(SND_47_MAGLEV_2, v); break;
+		case RAILTYPE_MAGLEV: SndPlayVehicleFx(SND_41_MAGLEV, v); break;
+	}
+}
+
+static bool CheckTrainStayInDepot(Vehicle *v)
+{
+	Vehicle *u;
+
+	// bail out if not all wagons are in the same depot or not in a depot at all
+	for (u = v; u != NULL; u = u->next) {
+		if (u->u.rail.track != 0x80 || u->tile != v->tile) return false;
+	}
+
+	// if the train got no power, then keep it in the depot
+	if (v->u.rail.cached_power == 0) {
+		v->vehstatus |= VS_STOPPED;
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+		return true;
+	}
+
+	if (v->u.rail.force_proceed == 0) {
+		if (++v->load_unload_time_rem < 37) {
+			InvalidateWindowClasses(WC_TRAINS_LIST);
+			return true;
+		}
+
+		v->load_unload_time_rem = 0;
+
+		if (UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction))) {
+			InvalidateWindowClasses(WC_TRAINS_LIST);
+			return true;
+		}
+	}
+
+	VehicleServiceInDepot(v);
+	InvalidateWindowClasses(WC_TRAINS_LIST);
+	TrainPlayLeaveStationSound(v);
+
+	v->u.rail.track = 1;
+	if (v->direction & 2) v->u.rail.track = 2;
+
+	v->vehstatus &= ~VS_HIDDEN;
+	v->cur_speed = 0;
+
+	UpdateTrainDeltaXY(v, v->direction);
+	v->cur_image = GetTrainImage(v, v->direction);
+	VehiclePositionChanged(v);
+	UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
+	UpdateTrainAcceleration(v);
+	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+
+	return false;
+}
+
+/* Check for station tiles */
+typedef struct TrainTrackFollowerData {
+	TileIndex dest_coords;
+	StationID station_index; // station index we're heading for
+	uint best_bird_dist;
+	uint best_track_dist;
+	byte best_track;
+} TrainTrackFollowerData;
+
+static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length)
+{
+	// heading for nowhere?
+	if (ttfd->dest_coords == 0) return false;
+
+	// did we reach the final station?
+	if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || (
+				IsTileType(tile, MP_STATION) &&
+				IsRailwayStation(tile) &&
+				GetStationIndex(tile) == ttfd->station_index
+			)) {
+		/* We do not check for dest_coords if we have a station_index,
+		 * because in that case the dest_coords are just an
+		 * approximation of where the station is */
+		// found station
+		ttfd->best_track = track;
+		return true;
+	} else {
+		uint dist;
+
+		// didn't find station, keep track of the best path so far.
+		dist = DistanceManhattan(tile, ttfd->dest_coords);
+		if (dist < ttfd->best_bird_dist) {
+			ttfd->best_bird_dist = dist;
+			ttfd->best_track = track;
+		}
+		return false;
+	}
+}
+
+static void FillWithStationData(TrainTrackFollowerData* fd, const Vehicle* v)
+{
+	fd->dest_coords = v->dest_tile;
+	if (v->current_order.type == OT_GOTO_STATION) {
+		fd->station_index = v->current_order.dest;
+	} else {
+		fd->station_index = INVALID_STATION;
+	}
+}
+
+static const byte _initial_tile_subcoord[6][4][3] = {
+{{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0,  0, 0 }},
+{{  0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
+{{  0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0,  0, 0 }},
+{{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
+{{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0,  0, 0 }},
+{{  0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
+};
+
+static const uint32 _reachable_tracks[4] = {
+	0x10091009,
+	0x00160016,
+	0x05200520,
+	0x2A002A00,
+};
+
+static const byte _search_directions[6][4] = {
+	{ 0, 9, 2, 9 }, // track 1
+	{ 9, 1, 9, 3 }, // track 2
+	{ 9, 0, 3, 9 }, // track upper
+	{ 1, 9, 9, 2 }, // track lower
+	{ 3, 2, 9, 9 }, // track left
+	{ 9, 9, 1, 0 }, // track right
+};
+
+static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0};
+
+/* choose a track */
+static byte ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirbits)
+{
+	TrainTrackFollowerData fd;
+	uint best_track;
+	// pathfinders are able to tell that route was only 'guessed'
+	bool path_not_found = false;
+
+#ifdef PF_BENCHMARK
+	TIC()
+#endif
+
+	assert((trackdirbits & ~0x3F) == 0);
+
+	/* quick return in case only one possible track is available */
+	if (KILL_FIRST_BIT(trackdirbits) == 0) return FIND_FIRST_BIT(trackdirbits);
+
+	if (_patches.yapf.rail_use_yapf) {
+		Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, trackdirbits, &path_not_found);
+		if (trackdir != INVALID_TRACKDIR) {
+			best_track = TrackdirToTrack(trackdir);
+		} else {
+			best_track = FIND_FIRST_BIT(TrackdirBitsToTrackBits(trackdirbits));
+		}
+	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
+		void* perf = NpfBeginInterval();
+		int time = 0;
+
+		NPFFindStationOrTileData fstd;
+		NPFFoundTargetData ftd;
+		Trackdir trackdir;
+
+		NPFFillWithOrderData(&fstd, v);
+		/* The enterdir for the new tile, is the exitdir for the old tile */
+		trackdir = GetVehicleTrackdir(v);
+		assert(trackdir != 0xff);
+
+		ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
+
+		if (ftd.best_trackdir == 0xff) {
+			/* We are already at our target. Just do something */
+			//TODO: maybe display error?
+			//TODO: go straight ahead if possible?
+			best_track = FIND_FIRST_BIT(trackdirbits);
+		} else {
+			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
+			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
+			we did not find our target, but ftd.best_trackdir contains the direction leading
+			to the tile closest to our target. */
+			if (ftd.best_bird_dist != 0) path_not_found = true;
+			/* Discard enterdir information, making it a normal track */
+			best_track = TrackdirToTrack(ftd.best_trackdir);
+		}
+
+		time = NpfEndInterval(perf);
+		DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
+	} else {
+		void* perf = NpfBeginInterval();
+		int time = 0;
+
+		FillWithStationData(&fd, v);
+
+		/* New train pathfinding */
+		fd.best_bird_dist = (uint)-1;
+		fd.best_track_dist = (uint)-1;
+		fd.best_track = 0xFF;
+
+		NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile,
+			v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
+
+		// check whether the path was found or only 'guessed'
+		if (fd.best_bird_dist != 0) path_not_found = true;
+
+		if (fd.best_track == 0xff) {
+			// blaha
+			best_track = FIND_FIRST_BIT(trackdirbits);
+		} else {
+			best_track = fd.best_track & 7;
+		}
+
+		time = NpfEndInterval(perf);
+		DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
+	}
+	// handle "path not found" state
+	if (path_not_found) {
+		// PF didn't find the route
+		if (!HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
+			// it is first time the problem occurred, set the "path not found" flag
+			SETBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
+			// and notify user about the event
+			if (_patches.lost_train_warn && v->owner == _local_player) {
+				SetDParam(0, v->unitnumber);
+				AddNewsItem(
+					STR_TRAIN_IS_LOST,
+					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
+					v->index,
+					0);
+			}
+		}
+	} else {
+		// route found, is the train marked with "path not found" flag?
+		if (HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
+			// clear the flag as the PF's problem was solved
+			CLRBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
+			// can we also delete the "News" item somehow?
+		}
+	}
+
+#ifdef PF_BENCHMARK
+	TOC("PF time = ", 1)
+#endif
+
+	return best_track;
+}
+
+
+static bool CheckReverseTrain(Vehicle *v)
+{
+	TrainTrackFollowerData fd;
+	int i, r;
+	int best_track;
+	uint best_bird_dist  = 0;
+	uint best_track_dist = 0;
+	uint reverse, reverse_best;
+
+	if (_opt.diff.line_reverse_mode != 0 ||
+			v->u.rail.track & 0xC0 ||
+			!(v->direction & 1))
+		return false;
+
+	FillWithStationData(&fd, v);
+
+	best_track = -1;
+	reverse_best = reverse = 0;
+
+	assert(v->u.rail.track);
+
+	i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)];
+
+	if (_patches.yapf.rail_use_yapf) {
+		reverse_best = YapfCheckReverseTrain(v);
+	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
+		NPFFindStationOrTileData fstd;
+		NPFFoundTargetData ftd;
+		byte trackdir, trackdir_rev;
+		Vehicle* last = GetLastVehicleInChain(v);
+
+		NPFFillWithOrderData(&fstd, v);
+
+		trackdir = GetVehicleTrackdir(v);
+		trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
+		assert(trackdir != 0xff);
+		assert(trackdir_rev != 0xff);
+
+		ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
+		if (ftd.best_bird_dist != 0) {
+			/* We didn't find anything, just keep on going straight ahead */
+			reverse_best = false;
+		} else {
+			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
+				reverse_best = true;
+			} else {
+				reverse_best = false;
+			}
+		}
+	} else {
+		for (;;) {
+			fd.best_bird_dist = (uint)-1;
+			fd.best_track_dist = (uint)-1;
+
+			NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd);
+
+			if (best_track != -1) {
+				if (best_bird_dist != 0) {
+					if (fd.best_bird_dist != 0) {
+						/* neither reached the destination, pick the one with the smallest bird dist */
+						if (fd.best_bird_dist > best_bird_dist) goto bad;
+						if (fd.best_bird_dist < best_bird_dist) goto good;
+					} else {
+						/* we found the destination for the first time */
+						goto good;
+					}
+				} else {
+					if (fd.best_bird_dist != 0) {
+						/* didn't find destination, but we've found the destination previously */
+						goto bad;
+					} else {
+						/* both old & new reached the destination, compare track length */
+						if (fd.best_track_dist > best_track_dist) goto bad;
+						if (fd.best_track_dist < best_track_dist) goto good;
+					}
+				}
+
+				/* if we reach this position, there's two paths of equal value so far.
+				 * pick one randomly. */
+				r = GB(Random(), 0, 8);
+				if (_pick_track_table[i] == (v->direction & 3)) r += 80;
+				if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
+				if (r <= 127) goto bad;
+			}
+good:;
+			best_track = i;
+			best_bird_dist = fd.best_bird_dist;
+			best_track_dist = fd.best_track_dist;
+			reverse_best = reverse;
+bad:;
+			if (reverse != 0) break;
+			reverse = 2;
+		}
+	}
+
+	return reverse_best != 0;
+}
+
+static bool ProcessTrainOrder(Vehicle *v)
+{
+	const Order *order;
+	bool at_waypoint = false;
+
+	switch (v->current_order.type) {
+		case OT_GOTO_DEPOT:
+			if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return false;
+			if ((v->current_order.flags & OF_SERVICE_IF_NEEDED) &&
+					!VehicleNeedsService(v)) {
+				v->cur_order_index++;
+			}
+			break;
+
+		case OT_LOADING:
+		case OT_LEAVESTATION:
+			return false;
+
+		default: break;
+	}
+
+	// check if we've reached the waypoint?
+	if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) {
+		v->cur_order_index++;
+		at_waypoint = true;
+	}
+
+	// check if we've reached a non-stop station while TTDPatch nonstop is enabled..
+	if (_patches.new_nonstop &&
+			v->current_order.flags & OF_NON_STOP &&
+			IsTileType(v->tile, MP_STATION) &&
+			v->current_order.dest == GetStationIndex(v->tile)) {
+		v->cur_order_index++;
+	}
+
+	// Get the current order
+	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
+
+	order = GetVehicleOrder(v, v->cur_order_index);
+
+	// If no order, do nothing.
+	if (order == NULL) {
+		v->current_order.type = OT_NOTHING;
+		v->current_order.flags = 0;
+		v->dest_tile = 0;
+		return false;
+	}
+
+	// If it is unchanged, keep it.
+	if (order->type  == v->current_order.type &&
+			order->flags == v->current_order.flags &&
+			order->dest  == v->current_order.dest)
+		return false;
+
+	// Otherwise set it, and determine the destination tile.
+	v->current_order = *order;
+
+	v->dest_tile = 0;
+
+	InvalidateVehicleOrder(v);
+
+	switch (order->type) {
+		case OT_GOTO_STATION:
+			if (order->dest == v->last_station_visited)
+				v->last_station_visited = INVALID_STATION;
+			v->dest_tile = GetStation(order->dest)->xy;
+			break;
+
+		case OT_GOTO_DEPOT:
+			v->dest_tile = GetDepot(order->dest)->xy;
+			break;
+
+		case OT_GOTO_WAYPOINT:
+			v->dest_tile = GetWaypoint(order->dest)->xy;
+			break;
+
+		default:
+			return false;
+	}
+
+	return !at_waypoint && CheckReverseTrain(v);
+}
+
+static void MarkTrainDirty(Vehicle *v)
+{
+	do {
+		v->cur_image = GetTrainImage(v, v->direction);
+		MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
+	} while ((v = v->next) != NULL);
+}
+
+static void HandleTrainLoading(Vehicle *v, bool mode)
+{
+	if (v->current_order.type == OT_NOTHING) return;
+
+	if (v->current_order.type != OT_DUMMY) {
+		if (v->current_order.type != OT_LOADING) return;
+		if (mode) return;
+
+		// don't mark the train as lost if we're loading on the final station.
+		if (v->current_order.flags & OF_NON_STOP)
+			v->u.rail.days_since_order_progr = 0;
+
+		if (--v->load_unload_time_rem) return;
+
+		if (CanFillVehicle(v) && (v->current_order.flags & OF_FULL_LOAD ||
+				(_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)))) {
+			v->u.rail.days_since_order_progr = 0; /* Prevent a train lost message for full loading trains */
+			SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
+			if (LoadUnloadVehicle(v, false)) {
+				InvalidateWindow(WC_TRAINS_LIST, v->owner);
+				MarkTrainDirty(v);
+
+				// need to update acceleration and cached values since the goods on the train changed.
+				TrainCargoChanged(v);
+				UpdateTrainAcceleration(v);
+			}
+			return;
+		}
+
+		TrainPlayLeaveStationSound(v);
+
+		{
+			Order b = v->current_order;
+			v->current_order.type = OT_LEAVESTATION;
+			v->current_order.flags = 0;
+
+			// If this was not the final order, don't remove it from the list.
+			if (!(b.flags & OF_NON_STOP)) return;
+		}
+	}
+
+	v->u.rail.days_since_order_progr = 0;
+	v->cur_order_index++;
+	InvalidateVehicleOrder(v);
+}
+
+static int UpdateTrainSpeed(Vehicle *v)
+{
+	uint spd;
+	uint accel;
+
+	if (v->vehstatus & VS_STOPPED || HASBIT(v->u.rail.flags, VRF_REVERSING)) {
+		if (_patches.realistic_acceleration) {
+			accel = GetTrainAcceleration(v, AM_BRAKE) * 2;
+		} else {
+			accel = v->acceleration * -2;
+		}
+	} else {
+		if (_patches.realistic_acceleration) {
+			accel = GetTrainAcceleration(v, AM_ACCEL);
+		} else {
+			accel = v->acceleration;
+		}
+	}
+
+	spd = v->subspeed + accel * 2;
+	v->subspeed = (byte)spd;
+	{
+		int tempmax = v->max_speed;
+		if (v->cur_speed > v->max_speed)
+			tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
+		v->cur_speed = spd = clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
+	}
+
+	if (!(v->direction & 1)) spd = spd * 3 >> 2;
+
+	spd += v->progress;
+	v->progress = (byte)spd;
+	return (spd >> 8);
+}
+
+static void TrainEnterStation(Vehicle *v, StationID station)
+{
+	Station *st;
+	uint32 flags;
+
+	v->last_station_visited = station;
+
+	/* check if a train ever visited this station before */
+	st = GetStation(station);
+	if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
+		st->had_vehicle_of_type |= HVOT_TRAIN;
+		SetDParam(0, st->index);
+		flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
+		AddNewsItem(
+			STR_8801_CITIZENS_CELEBRATE_FIRST,
+			flags,
+			v->index,
+			0
+		);
+	}
+
+	// Did we reach the final destination?
+	if (v->current_order.type == OT_GOTO_STATION &&
+			v->current_order.dest == station) {
+		// Yeah, keep the load/unload flags
+		// Non Stop now means if the order should be increased.
+		v->current_order.type = OT_LOADING;
+		v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
+		v->current_order.flags |= OF_NON_STOP;
+	} else {
+		// No, just do a simple load
+		v->current_order.type = OT_LOADING;
+		v->current_order.flags = 0;
+	}
+	v->current_order.dest = 0;
+
+	SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
+	if (LoadUnloadVehicle(v, true) != 0) {
+		InvalidateWindow(WC_TRAINS_LIST, v->owner);
+		TrainCargoChanged(v);
+		UpdateTrainAcceleration(v);
+	}
+	MarkTrainDirty(v);
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+}
+
+static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
+{
+	byte new_z, old_z;
+
+	// need this hint so it returns the right z coordinate on bridges.
+	new_z = GetSlopeZ(v->x_pos, v->y_pos);
+
+	old_z = v->z_pos;
+	v->z_pos = new_z;
+
+	if (new_tile) {
+		CLRBIT(v->u.rail.flags, VRF_GOINGUP);
+		CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
+
+		if (new_z != old_z) {
+			TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
+
+			// XXX workaround, whole UP/DOWN detection needs overhaul
+			if (!IsTunnelTile(tile)) {
+				SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
+			}
+		}
+	}
+
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+	return old_z;
+}
+
+static const Direction _new_vehicle_direction_table[11] = {
+	DIR_N , DIR_NW, DIR_W , 0,
+	DIR_NE, DIR_N , DIR_SW, 0,
+	DIR_E , DIR_SE, DIR_S
+};
+
+static Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
+{
+	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
+							TileX(new_tile) - TileX(old_tile) + 1;
+	assert(offs < 11);
+	return _new_vehicle_direction_table[offs];
+}
+
+static Direction GetNewVehicleDirection(const Vehicle *v, int x, int y)
+{
+	uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1);
+	assert(offs < 11);
+	return _new_vehicle_direction_table[offs];
+}
+
+static int GetDirectionToVehicle(const Vehicle *v, int x, int y)
+{
+	byte offs;
+
+	x -= v->x_pos;
+	if (x >= 0) {
+		offs = (x > 2) ? 0 : 1;
+	} else {
+		offs = (x < -2) ? 2 : 1;
+	}
+
+	y -= v->y_pos;
+	if (y >= 0) {
+		offs += ((y > 2) ? 0 : 1) * 4;
+	} else {
+		offs += ((y < -2) ? 2 : 1) * 4;
+	}
+
+	assert(offs < 11);
+	return _new_vehicle_direction_table[offs];
+}
+
+/* Check if the vehicle is compatible with the specified tile */
+static bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
+{
+	switch (GetTileType(tile)) {
+		case MP_TUNNELBRIDGE:
+		case MP_RAILWAY:
+		case MP_STATION:
+			// normal tracks, jump to owner check
+			break;
+
+		case MP_STREET:
+			// tracks over roads, do owner check of tracks
+			return
+				IsTileOwner(tile, v->owner) && (
+					!IsFrontEngine(v) ||
+					IsCompatibleRail(v->u.rail.railtype, GetRailTypeCrossing(tile))
+				);
+
+		default:
+			return true;
+	}
+
+	return
+		IsTileOwner(tile, v->owner) && (
+			!IsFrontEngine(v) ||
+			HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile))
+		);
+}
+
+typedef struct {
+	byte small_turn, large_turn;
+	byte z_up; // fraction to remove when moving up
+	byte z_down; // fraction to remove when moving down
+} RailtypeSlowdownParams;
+
+static const RailtypeSlowdownParams _railtype_slowdown[] = {
+	// normal accel
+	{256 / 4, 256 / 2, 256 / 4, 2}, // normal
+	{256 / 4, 256 / 2, 256 / 4, 2}, // electrified
+	{256 / 4, 256 / 2, 256 / 4, 2}, // monorail
+	{0,       256 / 2, 256 / 4, 2}, // maglev
+};
+
+/* Modify the speed of the vehicle due to a turn */
+static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
+{
+	DirDiff diff;
+	const RailtypeSlowdownParams *rsp;
+
+	if (_patches.realistic_acceleration) return;
+
+	diff = DirDifference(v->direction, new_dir);
+	if (diff == DIRDIFF_SAME) return;
+
+	rsp = &_railtype_slowdown[v->u.rail.railtype];
+	v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
+}
+
+/* Modify the speed of the vehicle due to a change in altitude */
+static void AffectSpeedByZChange(Vehicle *v, byte old_z)
+{
+	const RailtypeSlowdownParams *rsp;
+	if (old_z == v->z_pos || _patches.realistic_acceleration) return;
+
+	rsp = &_railtype_slowdown[v->u.rail.railtype];
+
+	if (old_z < v->z_pos) {
+		v->cur_speed -= (v->cur_speed * rsp->z_up >> 8);
+	} else {
+		uint16 spd = v->cur_speed + rsp->z_down;
+		if (spd <= v->max_speed) v->cur_speed = spd;
+	}
+}
+
+static const DiagDirection _otherside_signal_directions[] = {
+	DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, 0, 0,
+	DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
+};
+
+static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
+{
+	if (IsTileType(tile, MP_RAILWAY) &&
+			GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
+		uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]);
+		UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]);
+	}
+}
+
+
+typedef struct TrainCollideChecker {
+	const Vehicle *v;
+	const Vehicle *v_skip;
+} TrainCollideChecker;
+
+static void *FindTrainCollideEnum(Vehicle *v, void *data)
+{
+	const TrainCollideChecker* tcc = data;
+
+	if (v != tcc->v &&
+			v != tcc->v_skip &&
+			v->type == VEH_Train &&
+			v->u.rail.track != 0x80 &&
+			myabs(v->z_pos - tcc->v->z_pos) <= 6 &&
+			myabs(v->x_pos - tcc->v->x_pos) < 6 &&
+			myabs(v->y_pos - tcc->v->y_pos) < 6) {
+		return v;
+	} else {
+		return NULL;
+	}
+}
+
+static void SetVehicleCrashed(Vehicle *v)
+{
+	Vehicle *u;
+
+	if (v->u.rail.crash_anim_pos != 0) return;
+
+	v->u.rail.crash_anim_pos++;
+
+	u = v;
+	BEGIN_ENUM_WAGONS(v)
+		v->vehstatus |= VS_CRASHED;
+	END_ENUM_WAGONS(v)
+
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, u->index, STATUS_BAR);
+}
+
+static uint CountPassengersInTrain(const Vehicle* v)
+{
+	uint num = 0;
+	BEGIN_ENUM_WAGONS(v)
+		if (v->cargo_type == CT_PASSENGERS) num += v->cargo_count;
+	END_ENUM_WAGONS(v)
+	return num;
+}
+
+/*
+ * Checks whether the specified train has a collision with another vehicle. If
+ * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
+ * Reports the incident in a flashy news item, modifies station ratings and
+ * plays a sound.
+ */
+static void CheckTrainCollision(Vehicle *v)
+{
+	TrainCollideChecker tcc;
+	Vehicle *coll;
+	Vehicle *realcoll;
+	uint num;
+
+	/* can't collide in depot */
+	if (v->u.rail.track == 0x80) return;
+
+	assert(v->u.rail.track == 0x40 || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
+
+	tcc.v = v;
+	tcc.v_skip = v->next;
+
+	/* find colliding vehicle */
+	realcoll = VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum);
+	if (realcoll == NULL) return;
+
+	coll = GetFirstVehicleInChain(realcoll);
+
+	/* it can't collide with its own wagons */
+	if (v == coll ||
+			(v->u.rail.track & 0x40 && (v->direction & 2) != (realcoll->direction & 2)))
+		return;
+
+	//two drivers + passangers killed in train v
+	num = 2 + CountPassengersInTrain(v);
+	if (!(coll->vehstatus & VS_CRASHED))
+		//two drivers + passangers killed in train coll (if it was not crashed already)
+		num += 2 + CountPassengersInTrain(coll);
+
+	SetVehicleCrashed(v);
+	if (IsFrontEngine(coll)) SetVehicleCrashed(coll);
+
+	SetDParam(0, num);
+	AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
+		NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
+		v->index,
+		0
+	);
+
+	ModifyStationRatingAround(v->tile, v->owner, -160, 30);
+	SndPlayVehicleFx(SND_13_BIG_CRASH, v);
+}
+
+typedef struct VehicleAtSignalData {
+	TileIndex tile;
+	Direction direction;
+} VehicleAtSignalData;
+
+static void *CheckVehicleAtSignal(Vehicle *v, void *data)
+{
+	const VehicleAtSignalData* vasd = data;
+
+	if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == vasd->tile) {
+		DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT);
+
+		if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v;
+	}
+	return NULL;
+}
+
+static void TrainController(Vehicle *v, bool update_image)
+{
+	Vehicle *prev;
+	GetNewVehiclePosResult gp;
+	uint32 r, tracks,ts;
+	int i;
+	DiagDirection enterdir;
+	Direction dir;
+	Direction newdir;
+	Direction chosen_dir;
+	byte chosen_track;
+	byte old_z;
+
+	/* For every vehicle after and including the given vehicle */
+	for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) {
+		BeginVehicleMove(v);
+
+		if (v->u.rail.track != 0x40) {
+			/* Not inside tunnel */
+			if (GetNewVehiclePos(v, &gp)) {
+				/* Staying in the old tile */
+				if (v->u.rail.track == 0x80) {
+					/* inside depot */
+					gp.x = v->x_pos;
+					gp.y = v->y_pos;
+				} else {
+					/* is not inside depot */
+
+					if (!TrainCheckIfLineEnds(v)) return;
+
+					r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+					if (r & 0x8) {
+						//debug("%x & 0x8", r);
+						goto invalid_rail;
+					}
+					if (r & 0x2) {
+						TrainEnterStation(v, r >> 8);
+						return;
+					}
+
+					if (v->current_order.type == OT_LEAVESTATION) {
+						v->current_order.type = OT_NOTHING;
+						v->current_order.flags = 0;
+						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+					}
+				}
+			} else {
+				/* A new tile is about to be entered. */
+
+				byte bits;
+				/* Determine what direction we're entering the new tile from */
+				dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
+				enterdir = DirToDiagDir(dir);
+				assert(enterdir==0 || enterdir==1 || enterdir==2 || enterdir==3);
+
+				/* Get the status of the tracks in the new tile and mask
+				 * away the bits that aren't reachable. */
+				ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir];
+
+				/* Combine the from & to directions.
+				 * Now, the lower byte contains the track status, and the byte at bit 16 contains
+				 * the signal status. */
+				tracks = ts | (ts >> 8);
+				bits = tracks & 0xFF;
+				if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) {
+					/* We allow wagons to make 90 deg turns, because forbid_90_deg
+					 * can be switched on halfway a turn */
+					bits &= ~TrackCrossesTracks(FIND_FIRST_BIT(v->u.rail.track));
+				}
+
+				if (bits == 0) {
+					//debug("%x == 0", bits);
+					goto invalid_rail;
+				}
+
+				/* Check if the new tile contrains tracks that are compatible
+				 * with the current train, if not, bail out. */
+				if (!CheckCompatibleRail(v, gp.new_tile)) {
+					//debug("!CheckCompatibleRail(%p, %x)", v, gp.new_tile);
+					goto invalid_rail;
+				}
+
+				if (prev == NULL) {
+					/* Currently the locomotive is active. Determine which one of the
+					 * available tracks to choose */
+					chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits);
+					assert(chosen_track & tracks);
+
+					/* Check if it's a red signal and that force proceed is not clicked. */
+					if ( (tracks>>16)&chosen_track && v->u.rail.force_proceed == 0) goto red_light;
+				} else {
+					static byte _matching_tracks[8] = {0x30, 1, 0xC, 2, 0x30, 1, 0xC, 2};
+
+					/* The wagon is active, simply follow the prev vehicle. */
+					chosen_track = (byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
+				}
+
+				/* make sure chosen track is a valid track */
+				assert(chosen_track==1 || chosen_track==2 || chosen_track==4 || chosen_track==8 || chosen_track==16 || chosen_track==32);
+
+				/* Update XY to reflect the entrance to the new tile, and select the direction to use */
+				{
+					const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
+					gp.x = (gp.x & ~0xF) | b[0];
+					gp.y = (gp.y & ~0xF) | b[1];
+					chosen_dir = b[2];
+				}
+
+				/* Call the landscape function and tell it that the vehicle entered the tile */
+				r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+				if (r & 0x8) {
+					//debug("%x & 0x8", r);
+					goto invalid_rail;
+				}
+
+				if (IsLevelCrossingTile(v->tile) && v->next == NULL) {
+					UnbarCrossing(v->tile);
+					MarkTileDirtyByTile(v->tile);
+				}
+
+				if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
+
+				if (!(r&0x4)) {
+					v->tile = gp.new_tile;
+
+					if (GetTileRailType(gp.new_tile, chosen_track) != GetTileRailType(gp.old_tile, v->u.rail.track)) {
+						TrainPowerChanged(GetFirstVehicleInChain(v));
+					}
+
+					v->u.rail.track = chosen_track;
+					assert(v->u.rail.track);
+				}
+
+				if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
+
+				/* Signals can only change when the first
+				 * (above) or the last vehicle moves. */
+				if (v->next == NULL)
+					TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
+
+				if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
+
+				v->direction = chosen_dir;
+			}
+		} else {
+			/* in tunnel on on a bridge */
+			GetNewVehiclePos(v, &gp);
+
+			SetSpeedLimitOnBridge(v);
+
+			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 0x4)) {
+				v->x_pos = gp.x;
+				v->y_pos = gp.y;
+				VehiclePositionChanged(v);
+				if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
+				continue;
+			}
+		}
+
+		/* update image of train, as well as delta XY */
+		newdir = GetNewVehicleDirection(v, gp.x, gp.y);
+		UpdateTrainDeltaXY(v, newdir);
+		if (update_image) v->cur_image = GetTrainImage(v, newdir);
+
+		v->x_pos = gp.x;
+		v->y_pos = gp.y;
+
+		/* update the Z position of the vehicle */
+		old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile));
+
+		if (prev == NULL) {
+			/* This is the first vehicle in the train */
+			AffectSpeedByZChange(v, old_z);
+		}
+	}
+	return;
+
+invalid_rail:
+	/* We've reached end of line?? */
+	if (prev != NULL) error("!Disconnecting train");
+	goto reverse_train_direction;
+
+red_light: {
+	/* We're in front of a red signal ?? */
+		/* find the first set bit in ts. need to do it in 2 steps, since
+		 * FIND_FIRST_BIT only handles 6 bits at a time. */
+		i = FindFirstBit2x64(ts);
+
+		if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
+			v->cur_speed = 0;
+			v->subspeed = 0;
+			v->progress = 255 - 100;
+			if (++v->load_unload_time_rem < _patches.wait_oneway_signal * 20) return;
+		} else if (HasSignalOnTrackdir(gp.new_tile, i)){
+			v->cur_speed = 0;
+			v->subspeed = 0;
+			v->progress = 255-10;
+			if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) {
+				TileIndex o_tile = gp.new_tile + TileOffsByDiagDir(enterdir);
+				VehicleAtSignalData vasd;
+				vasd.tile = o_tile;
+				vasd.direction = ReverseDir(dir);
+
+				/* check if a train is waiting on the other side */
+				if (VehicleFromPos(o_tile, &vasd, CheckVehicleAtSignal) == NULL) return;
+			}
+		}
+	}
+
+reverse_train_direction:
+	v->load_unload_time_rem = 0;
+	v->cur_speed = 0;
+	v->subspeed = 0;
+	ReverseTrainDirection(v);
+}
+
+extern TileIndex CheckTunnelBusy(TileIndex tile, uint *length);
+
+/**
+ * Deletes/Clears the last wagon of a crashed train. It takes the engine of the
+ * train, then goes to the last wagon and deletes that. Each call to this function
+ * will remove the last wagon of a crashed train. If this wagon was on a crossing,
+ * or inside a tunnel, recalculate the signals as they might need updating
+ * @param v the @Vehicle of which last wagon is to be removed
+ */
+static void DeleteLastWagon(Vehicle *v)
+{
+	Vehicle *u = v;
+
+	/* Go to the last wagon and delete the link pointing there
+	 * *u is then the one-before-last wagon, and *v the last
+	 * one which will physicially be removed */
+	for (; v->next != NULL; v = v->next) u = v;
+	u->next = NULL;
+
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
+	RebuildVehicleLists();
+	InvalidateWindow(WC_COMPANY, v->owner);
+
+	BeginVehicleMove(v);
+	EndVehicleMove(v);
+	DeleteVehicle(v);
+
+	if (!(v->u.rail.track & 0xC0))
+		SetSignalsOnBothDir(v->tile, FIND_FIRST_BIT(v->u.rail.track));
+
+	/* Check if the wagon was on a road/rail-crossing and disable it if no
+	 * others are on it */
+	DisableTrainCrossing(v->tile);
+
+	if ( (v->u.rail.track == 0x40 && v->vehstatus & VS_HIDDEN) ) { // inside a tunnel
+		TileIndex endtile = CheckTunnelBusy(v->tile, NULL);
+
+		if (endtile == INVALID_TILE) return; // tunnel is busy (error returned)
+
+		switch (v->direction) {
+			case 1:
+			case 5:
+				SetSignalsOnBothDir(v->tile, 0);
+				SetSignalsOnBothDir(endtile, 0);
+				break;
+
+			case 3:
+			case 7:
+				SetSignalsOnBothDir(v->tile, 1);
+				SetSignalsOnBothDir(endtile, 1);
+				break;
+
+			default:
+				break;
+		}
+	}
+}
+
+static void ChangeTrainDirRandomly(Vehicle *v)
+{
+	static const DirDiff delta[] = {
+		DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
+	};
+
+	do {
+		/* We don't need to twist around vehicles if they're not visible */
+		if (!(v->vehstatus & VS_HIDDEN)) {
+			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
+			BeginVehicleMove(v);
+			UpdateTrainDeltaXY(v, v->direction);
+			v->cur_image = GetTrainImage(v, v->direction);
+			/* Refrain from updating the z position of the vehicle when on
+			   a bridge, because AfterSetTrainPos will put the vehicle under
+			   the bridge in that case */
+			if (!(v->u.rail.track & 0x40)) AfterSetTrainPos(v, false);
+		}
+	} while ((v = v->next) != NULL);
+}
+
+static void HandleCrashedTrain(Vehicle *v)
+{
+	int state = ++v->u.rail.crash_anim_pos;
+	uint32 r;
+	Vehicle *u;
+
+	if (state == 4 && !(v->u.rail.track & VS_HIDDEN)) {
+		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
+	}
+
+	if (state <= 200 && CHANCE16R(1, 7, r)) {
+		int index = (r * 10 >> 16);
+
+		u = v;
+		do {
+			if (--index < 0) {
+				r = Random();
+
+				CreateEffectVehicleRel(u,
+					GB(r,  8, 3) + 2,
+					GB(r, 16, 3) + 2,
+					GB(r,  0, 3) + 5,
+					EV_EXPLOSION_SMALL);
+				break;
+			}
+		} while ((u = u->next) != NULL);
+	}
+
+	if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
+
+	if (state >= 4440 && !(v->tick_counter&0x1F)) {
+		DeleteLastWagon(v);
+		InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
+	}
+}
+
+static void HandleBrokenTrain(Vehicle *v)
+{
+	if (v->breakdown_ctr != 1) {
+		v->breakdown_ctr = 1;
+		v->cur_speed = 0;
+
+		if (v->breakdowns_since_last_service != 255)
+			v->breakdowns_since_last_service++;
+
+		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+			SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+		}
+
+		if (!(v->vehstatus & VS_HIDDEN)) {
+			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
+			if (u != NULL) u->u.special.unk0 = v->breakdown_delay * 2;
+		}
+	}
+
+	if (!(v->tick_counter & 3)) {
+		if (!--v->breakdown_delay) {
+			v->breakdown_ctr = 0;
+			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+		}
+	}
+}
+
+static const byte _breakdown_speeds[16] = {
+	225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
+};
+
+static bool TrainCheckIfLineEnds(Vehicle *v)
+{
+	TileIndex tile;
+	uint x,y;
+	uint16 break_speed;
+	DiagDirection dir;
+	int t;
+	uint32 ts;
+
+	t = v->breakdown_ctr;
+	if (t > 1) {
+		v->vehstatus |= VS_TRAIN_SLOWING;
+
+		break_speed = _breakdown_speeds[GB(~t, 4, 4)];
+		if (break_speed < v->cur_speed) v->cur_speed = break_speed;
+	} else {
+		v->vehstatus &= ~VS_TRAIN_SLOWING;
+	}
+
+	if (v->u.rail.track & 0x40) return true; // exit if inside a tunnel
+	if (v->u.rail.track & 0x80) return true; // exit if inside a depot
+
+	tile = v->tile;
+
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		DiagDirection dir;
+
+		dir = IsTunnel(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile);
+		if (DiagDirToDir(dir) == v->direction) return true;
+	}
+
+	// depot?
+	/* XXX -- When enabled, this makes it possible to crash trains of others
+	     (by building a depot right against a station) */
+/*	if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT_WAYPOINT)
+		return true;*/
+
+	/* Determine the non-diagonal direction in which we will exit this tile */
+	dir = DirToDiagDir(v->direction);
+	if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) {
+		dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT);
+	}
+	/* Calculate next tile */
+	tile += TileOffsByDiagDir(dir);
+	// determine the track status on the next tile.
+	ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[dir];
+
+	/* Calc position within the current tile ?? */
+	x = v->x_pos & 0xF;
+	y = v->y_pos & 0xF;
+
+	switch (v->direction) {
+		case DIR_N : x = ~x + ~y + 24; break;
+		case DIR_NW: x = y;            /* FALLTHROUGH */
+		case DIR_NE: x = ~x + 16;      break;
+		case DIR_E : x = ~x + y + 8;   break;
+		case DIR_SE: x = y;            break;
+		case DIR_S : x = x + y - 8;    break;
+		case DIR_W : x = ~y + x + 8;   break;
+	}
+
+	if (GB(ts, 0, 16) != 0) {
+		/* If we approach a rail-piece which we can't enter, or the back of a depot, don't enter it! */
+		if (x + 4 >= TILE_SIZE &&
+				(!CheckCompatibleRail(v, tile) ||
+				(IsTileDepotType(tile, TRANSPORT_RAIL) &&
+				GetRailDepotDirection(tile) == dir))) {
+			v->cur_speed = 0;
+			ReverseTrainDirection(v);
+			return false;
+		}
+		if ((ts &= (ts >> 16)) == 0) {
+			// make a rail/road crossing red
+			if (IsLevelCrossingTile(tile)) {
+				if (!IsCrossingBarred(tile)) {
+					BarCrossing(tile);
+					SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
+					MarkTileDirtyByTile(tile);
+				}
+			}
+			return true;
+		}
+	} else if (x + 4 >= TILE_SIZE) {
+		v->cur_speed = 0;
+		ReverseTrainDirection(v);
+		return false;
+	}
+
+	// slow down
+	v->vehstatus |= VS_TRAIN_SLOWING;
+	break_speed = _breakdown_speeds[x & 0xF];
+	if (!(v->direction & 1)) break_speed >>= 1;
+	if (break_speed < v->cur_speed) v->cur_speed = break_speed;
+
+	return true;
+}
+
+static void TrainLocoHandler(Vehicle *v, bool mode)
+{
+	int j;
+
+	/* train has crashed? */
+	if (v->u.rail.crash_anim_pos != 0) {
+		if (!mode) HandleCrashedTrain(v);
+		return;
+	}
+
+	if (v->u.rail.force_proceed != 0) v->u.rail.force_proceed--;
+
+	/* train is broken down? */
+	if (v->breakdown_ctr != 0) {
+		if (v->breakdown_ctr <= 2) {
+			HandleBrokenTrain(v);
+			return;
+		}
+		v->breakdown_ctr--;
+	}
+
+	if (HASBIT(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) {
+		ReverseTrainDirection(v);
+	}
+
+	/* exit if train is stopped */
+	if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return;
+
+	if (ProcessTrainOrder(v)) {
+		v->load_unload_time_rem = 0;
+		v->cur_speed = 0;
+		v->subspeed = 0;
+		ReverseTrainDirection(v);
+		return;
+	}
+
+	HandleTrainLoading(v, mode);
+
+	if (v->current_order.type == OT_LOADING) return;
+
+	if (CheckTrainStayInDepot(v)) return;
+
+	if (!mode) HandleLocomotiveSmokeCloud(v);
+
+	j = UpdateTrainSpeed(v);
+	if (j == 0) {
+		// if the vehicle has speed 0, update the last_speed field.
+		if (v->cur_speed != 0) return;
+	} else {
+		TrainCheckIfLineEnds(v);
+
+		do {
+			TrainController(v, true);
+			CheckTrainCollision(v);
+			if (v->cur_speed <= 0x100)
+				break;
+		} while (--j != 0);
+	}
+
+	SetLastSpeed(v, v->cur_speed);
+}
+
+
+void Train_Tick(Vehicle *v)
+{
+	if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff)
+		v->cargo_days++;
+
+	v->tick_counter++;
+
+	if (IsFrontEngine(v)) {
+		TrainLocoHandler(v, false);
+
+		// make sure vehicle wasn't deleted.
+		if (v->type == VEH_Train && IsFrontEngine(v))
+			TrainLocoHandler(v, true);
+	} else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) {
+		// Delete flooded standalone wagon
+		if (++v->u.rail.crash_anim_pos >= 4400)
+			DeleteVehicle(v);
+	}
+}
+
+#define MAX_ACCEPTABLE_DEPOT_DIST 16
+
+static void CheckIfTrainNeedsService(Vehicle *v)
+{
+	const Depot* depot;
+	TrainFindDepotData tfdd;
+
+	if (_patches.servint_trains == 0)                   return;
+	if (!VehicleNeedsService(v))                        return;
+	if (v->vehstatus & VS_STOPPED)                      return;
+	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
+
+	// Don't interfere with a depot visit scheduled by the user, or a
+	// depot visit by the order list.
+	if (v->current_order.type == OT_GOTO_DEPOT &&
+			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
+		return;
+
+	if (CheckTrainIsInsideDepot(v)) {
+		VehicleServiceInDepot(v);
+		return;
+	}
+
+	tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
+	/* Only go to the depot if it is not too far out of our way. */
+	if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
+		if (v->current_order.type == OT_GOTO_DEPOT) {
+			/* If we were already heading for a depot but it has
+			 * suddenly moved farther away, we continue our normal
+			 * schedule? */
+			v->current_order.type = OT_DUMMY;
+			v->current_order.flags = 0;
+			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		}
+		return;
+	}
+
+	depot = GetDepotByTile(tfdd.tile);
+
+	if (v->current_order.type == OT_GOTO_DEPOT &&
+			v->current_order.dest != depot->index &&
+			!CHANCE16(3, 16)) {
+		return;
+	}
+
+	v->current_order.type = OT_GOTO_DEPOT;
+	v->current_order.flags = OF_NON_STOP;
+	v->current_order.dest = depot->index;
+	v->dest_tile = tfdd.tile;
+	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+}
+
+int32 GetTrainRunningCost(const Vehicle *v)
+{
+	int32 cost = 0;
+
+	do {
+		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
+		if (rvi->running_cost_base > 0)
+			cost += rvi->running_cost_base * _price.running_rail[rvi->running_cost_class];
+	} while ((v = GetNextVehicle(v)) != NULL);
+
+	return cost;
+}
+
+void OnNewDay_Train(Vehicle *v)
+{
+	TileIndex tile;
+
+	if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v);
+
+	if (IsFrontEngine(v)) {
+		CheckVehicleBreakdown(v);
+		AgeVehicle(v);
+
+		CheckIfTrainNeedsService(v);
+
+		CheckOrders(v);
+
+		/* update destination */
+		if (v->current_order.type == OT_GOTO_STATION &&
+				(tile = GetStation(v->current_order.dest)->train_tile) != 0) {
+			v->dest_tile = tile;
+		}
+
+		if ((v->vehstatus & VS_STOPPED) == 0) {
+			/* running costs */
+			int32 cost = GetTrainRunningCost(v) / 364;
+
+			v->profit_this_year -= cost >> 8;
+
+			SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
+			SubtractMoneyFromPlayerFract(v->owner, cost);
+
+			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+			InvalidateWindowClasses(WC_TRAINS_LIST);
+		}
+	}
+}
+
+void TrainsYearlyLoop(void)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && IsFrontEngine(v)) {
+
+			// show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list)
+			if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) {
+				SetDParam(1, v->profit_this_year);
+				SetDParam(0, v->unitnumber);
+				AddNewsItem(
+					STR_TRAIN_IS_UNPROFITABLE,
+					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
+					v->index,
+					0);
+			}
+
+			v->profit_last_year = v->profit_this_year;
+			v->profit_this_year = 0;
+			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+		}
+	}
+}
+
+
+void InitializeTrains(void)
+{
+	_age_cargo_skip_counter = 1;
+}
+
+/*
+ * Link front and rear multiheaded engines to each other
+ * This is done when loading a savegame
+ */
+void ConnectMultiheadedTrains(void)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train) {
+			v->u.rail.other_multiheaded_part = NULL;
+		}
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && IsFrontEngine(v)) {
+			Vehicle *u = v;
+
+			BEGIN_ENUM_WAGONS(u) {
+				if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
+
+				if (IsMultiheaded(u)) {
+					if (!IsTrainEngine(u)) {
+						/* we got a rear car without a front car. We will convert it to a front one */
+						SetTrainEngine(u);
+						u->spritenum--;
+					}
+
+					{
+						Vehicle *w;
+
+						for (w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w));
+						if (w != NULL) {
+							/* we found a car to partner with this engine. Now we will make sure it face the right way */
+							if (IsTrainEngine(w)) {
+								ClearTrainEngine(w);
+								w->spritenum++;
+							}
+						}
+
+						if (w != NULL) {
+							w->u.rail.other_multiheaded_part = u;
+							u->u.rail.other_multiheaded_part = w;
+						} else {
+							/* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
+							ClearMultiheaded(u);
+						}
+					}
+				}
+			} END_ENUM_WAGONS(u)
+		}
+	}
+}
+
+/*
+ *  Converts all trains to the new subtype format introduced in savegame 16.2
+ *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
+ */
+void ConvertOldMultiheadToNew(void)
+{
+	Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train) {
+			SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
+		}
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train) {
+			if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
+				Vehicle *u = v;
+
+				BEGIN_ENUM_WAGONS(u) {
+					const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
+
+					CLRBIT(u->subtype, 7);
+					switch (u->subtype) {
+						case 0: /* TS_Front_Engine */
+							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
+							SetFrontEngine(u);
+							SetTrainEngine(u);
+							break;
+
+						case 1: /* TS_Artic_Part */
+							u->subtype = 0;
+							SetArticulatedPart(u);
+							break;
+
+						case 2: /* TS_Not_First */
+							u->subtype = 0;
+							if (rvi->flags & RVI_WAGON) {
+								// normal wagon
+								SetTrainWagon(u);
+								break;
+							}
+							if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
+								// rear end of a multiheaded engine
+								SetMultiheaded(u);
+								break;
+							}
+							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
+							SetTrainEngine(u);
+							break;
+
+						case 4: /* TS_Free_Car */
+							u->subtype = 0;
+							SetTrainWagon(u);
+							SetFreeWagon(u);
+							break;
+						default: NOT_REACHED(); break;
+					}
+				} END_ENUM_WAGONS(u)
+			}
+		}
+	}
+}
deleted file mode 100644
--- a/src/train_gui.c
+++ /dev/null
@@ -1,1135 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "rail_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "engine.h"
-#include "window.h"
-#include "gui.h"
-#include "gfx.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "station.h"
-#include "command.h"
-#include "player.h"
-#include "vehicle_gui.h"
-#include "depot.h"
-#include "train.h"
-#include "newgrf_engine.h"
-#include "date.h"
-#include "strings.h"
-
-enum BuildTrainWidgets {
-	BUILD_TRAIN_WIDGET_CLOSEBOX = 0,
-	BUILD_TRAIN_WIDGET_CAPTION,
-	BUILD_TRAIN_WIDGET_SORT_ASCENDING_DESCENDING,
-	BUILD_TRAIN_WIDGET_SORT_TEXT,
-	BUILD_TRAIN_WIDGET_SORT_DROPDOWN,
-	BUILD_TRAIN_WIDGET_LIST,
-	BUILD_TRAIN_WIDGET_SCROLLBAR,
-	BUILD_TRAIN_WIDGET_PANEL,
-	BUILD_TRAIN_WIDGET_BUILD,
-	BUILD_TRAIN_WIDGET_RENAME,
-	BUILD_TRAIN_WIDGET_RESIZE,
-};
-
-static const Widget _new_rail_vehicle_widgets[] = {
-	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
-	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   227,     0,    13, STR_JUST_STRING,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,            STR_SORT_ORDER_TIP},
-	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   215,    14,    25, 0x0,                    STR_SORT_CRITERIA_TIP},
-	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   216,   227,    14,    25, STR_0225,               STR_SORT_CRITERIA_TIP},
-	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    26,   137, 0x801,                  STR_8843_TRAIN_VEHICLE_SELECTION},
-	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    26,   137, 0x0,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-	{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   138,   239, 0x0,                    STR_NULL},
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   107,   240,   251, STR_881F_BUILD_VEHICLE, STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN},
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   108,   215,   240,   251, STR_8820_RENAME,        STR_8845_RENAME_TRAIN_VEHICLE_TYPE},
-	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   216,   227,   240,   251, 0x0,                    STR_RESIZE_BUTTON},
-	{   WIDGETS_END},
-};
-
-static bool _internal_sort_order; // false = ascending, true = descending
-static byte _last_sort_criteria = 0;
-static bool _last_sort_order = false;
-
-static int CDECL TrainEngineNumberSorter(const void *a, const void *b)
-{
-	const EngineID va = *(const EngineID*)a;
-	const EngineID vb = *(const EngineID*)b;
-	int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b)
-{
-	EngineID va = *(const EngineID*)a;
-	EngineID vb = *(const EngineID*)b;
-	int val_a = ((RailVehInfo(va)->flags & RVI_WAGON) != 0) ? 1 : 0;
-	int val_b = ((RailVehInfo(vb)->flags & RVI_WAGON) != 0) ? 1 : 0;
-	int r = val_a - val_b;
-
-	/* Use EngineID to sort instead since we want consistent sorting */
-	if (r == 0) return TrainEngineNumberSorter(a, b);
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEngineCostSorter(const void *a, const void *b)
-{
-	int va = RailVehInfo(*(const EngineID*)a)->base_cost;
-	int vb = RailVehInfo(*(const EngineID*)b)->base_cost;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEngineSpeedSorter(const void *a, const void *b)
-{
-	int va = RailVehInfo(*(const EngineID*)a)->max_speed;
-	int vb = RailVehInfo(*(const EngineID*)b)->max_speed;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEnginePowerSorter(const void *a, const void *b)
-{
-	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
-	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
-
-	int va = rvi_a->power << (rvi_a->flags & RVI_MULTIHEAD ? 1 : 0);
-	int vb = rvi_b->power << (rvi_b->flags & RVI_MULTIHEAD ? 1 : 0);
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEngineIntroDateSorter(const void *a, const void *b)
-{
-	int va = GetEngine(*(const EngineID*)a)->intro_date;
-	int vb = GetEngine(*(const EngineID*)b)->intro_date;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static EngineID _last_engine; // cached vehicle to hopefully speed up name-sorting
-
-static char _bufcache[64]; // used together with _last_vehicle to hopefully speed up stringsorting
-static int CDECL TrainEngineNameSorter(const void *a, const void *b)
-{
-	const EngineID va = *(const EngineID*)a;
-	const EngineID vb = *(const EngineID*)b;
-	char buf1[64];
-	int r;
-
-	GetString(buf1, GetCustomEngineName(va), lastof(buf1));
-
-	if (vb != _last_engine) {
-		_last_engine = vb;
-		_bufcache[0] = '\0';
-
-		GetString(_bufcache, GetCustomEngineName(vb), lastof(_bufcache));
-	}
-
-	r =  strcasecmp(buf1, _bufcache); // sort by name
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEngineRunningCostSorter(const void *a, const void *b)
-{
-	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
-	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
-
-	int va = rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class] * (rvi_a->flags & RVI_MULTIHEAD ? 2 : 1);
-	int vb = rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class] * (rvi_b->flags & RVI_MULTIHEAD ? 2 : 1);
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b)
-{
-	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
-	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
-
-	/* Here we are using a few tricks to get the right sort.
-	 * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int,
-	 * we will actually calculate cunning cost/power (to make it more than 1).
-	 * Because of this, the return value have to be reversed as well and we return b - a instead of a - b.
-	 * Another thing is that both power and running costs should be doubled for multiheaded engines.
-	 * Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */
-	int va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max(1, rvi_a->power);
-	int vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max(1, rvi_b->power);
-	int r = vb - va;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static int CDECL TrainEngineReliabilitySorter(const void *a, const void *b)
-{
-	int va = GetEngine(*(const EngineID*)a)->reliability;
-	int vb = GetEngine(*(const EngineID*)b)->reliability;
-	int r = va - vb;
-
-	return _internal_sort_order ? -r : r;
-}
-
-static EngList_SortTypeFunction * const _engine_sorter[] = {
-	&TrainEngineNumberSorter,
-	&TrainEngineCostSorter,
-	&TrainEngineSpeedSorter,
-	&TrainEnginePowerSorter,
-	&TrainEngineIntroDateSorter,
-	&TrainEngineNameSorter,
-	&TrainEngineRunningCostSorter,
-	&TrainEnginePowerVsRunningCostSorter,
-	&TrainEngineReliabilitySorter,
-};
-
-static const StringID _engine_sort_listing[] = {
-	STR_ENGINE_SORT_ENGINE_ID,
-	STR_ENGINE_SORT_COST,
-	STR_SORT_BY_MAX_SPEED,
-	STR_ENGINE_SORT_POWER,
-	STR_ENGINE_SORT_INTRO_DATE,
-	STR_SORT_BY_DROPDOWN_NAME,
-	STR_ENGINE_SORT_RUNNING_COST,
-	STR_ENGINE_SORT_POWER_VS_RUNNING_COST,
-	STR_SORT_BY_RELIABILITY,
-	INVALID_STRING_ID
-};
-
-/**
- * Draw the purchase info details of train engine at a given location.
- * @param x,y location where to draw the info
- * @param engine_number the engine of which to draw the info of
- */
-void DrawTrainEnginePurchaseInfo(int x, int y, uint w, EngineID engine_number)
-{
-	const RailVehicleInfo *rvi = RailVehInfo(engine_number);
-	const Engine *e = GetEngine(engine_number);
-	int multihead = (rvi->flags&RVI_MULTIHEAD?1:0);
-	YearMonthDay ymd;
-	ConvertDateToYMD(e->intro_date, &ymd);
-
-	/* Purchase Cost - Engine weight */
-	SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5);
-	SetDParam(1, rvi->weight << multihead);
-	DrawString(x,y, STR_PURCHASE_INFO_COST_WEIGHT, 0);
-	y += 10;
-
-	/* Max speed - Engine power */
-	SetDParam(0, rvi->max_speed);
-	SetDParam(1, rvi->power << multihead);
-	DrawString(x,y, STR_PURCHASE_INFO_SPEED_POWER, 0);
-	y += 10;
-
-	/* Max tractive effort - not applicable if old acceleration or maglev */
-	if (_patches.realistic_acceleration && e->railtype != RAILTYPE_MAGLEV) {
-		SetDParam(0, ((rvi->weight << multihead) * 10 * rvi->tractive_effort) / 256);
-		DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, 0);
-		y += 10;
-	}
-
-	/* Running cost */
-	SetDParam(0, (rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8) << multihead);
-	DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
-	y += 10;
-
-	/* Powered wagons power - Powered wagons extra weight */
-	if (rvi->pow_wag_power != 0) {
-		SetDParam(0, rvi->pow_wag_power);
-		SetDParam(1, rvi->pow_wag_weight);
-		DrawString(x,y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, 0);
-		y += 10;
-	};
-
-	/* Cargo type + capacity, or N/A */
-	if (rvi->capacity == 0) {
-		SetDParam(0, CT_INVALID);
-		SetDParam(2, STR_EMPTY);
-	} else {
-		SetDParam(0, rvi->cargo_type);
-		SetDParam(1, (rvi->capacity * (CountArticulatedParts(engine_number) + 1)) << multihead);
-		SetDParam(2, STR_9842_REFITTABLE);
-	}
-	DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0);
-	y += 10;
-
-	/* Design date - Life length */
-	SetDParam(0, ymd.year);
-	SetDParam(1, e->lifelength);
-	DrawString(x,y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
-	y += 10;
-
-	/* Reliability */
-	SetDParam(0, e->reliability * 100 >> 16);
-	DrawString(x,y, STR_PURCHASE_INFO_RELIABILITY, 0);
-	y += 10;
-
-	/* Additional text from NewGRF */
-	y += ShowAdditionalText(x, y, w, engine_number);
-	if (rvi->capacity > 0) y += ShowRefitOptionsList(x, y, w, engine_number);
-}
-
-/**
- * Draw the purchase info details of a train wagon at a given location.
- * @param x,y location where to draw the info
- * @param engine_number the engine of which to draw the info of
- */
-void DrawTrainWagonPurchaseInfo(int x, int y, uint w, EngineID engine_number)
-{
-	const RailVehicleInfo *rvi = RailVehInfo(engine_number);
-	bool refittable = (EngInfo(engine_number)->refit_mask != 0);
-
-	/* Purchase cost */
-	SetDParam(0, (rvi->base_cost * _price.build_railwagon) >> 8);
-	DrawString(x, y, STR_PURCHASE_INFO_COST, 0);
-	y += 10;
-
-	/* Wagon weight - (including cargo) */
-	SetDParam(0, rvi->weight);
-	SetDParam(1, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight);
-	DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, 0);
-	y += 10;
-
-	/* Cargo type + capacity, or N/A */
-	if (rvi->capacity == 0) {
-		SetDParam(0, CT_INVALID);
-		SetDParam(2, STR_EMPTY);
-	} else {
-		SetDParam(0, rvi->cargo_type);
-		SetDParam(1, rvi->capacity * (CountArticulatedParts(engine_number) + 1));
-		SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
-	}
-	DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
-	y += 10;
-
-	/* Wagon speed limit, displayed if above zero */
-	if (rvi->max_speed > 0 && _patches.wagon_speed_limits) {
-		SetDParam(0, rvi->max_speed);
-		DrawString(x,y, STR_PURCHASE_INFO_SPEED, 0);
-		y += 10;
-	}
-
-	/* Additional text from NewGRF */
-	y += ShowAdditionalText(x, y, w, engine_number);
-	y += ShowRefitOptionsList(x, y, w, engine_number);
-}
-
-void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	Vehicle *v, *found;
-
-	if (!success) return;
-
-	// find a locomotive in the depot.
-	found = NULL;
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && IsFrontEngine(v) &&
-				v->tile == tile &&
-				v->u.rail.track == 0x80) {
-			if (found != NULL) return; // must be exactly one.
-			found = v;
-		}
-	}
-
-	// if we found a loco,
-	if (found != NULL) {
-		found = GetLastVehicleInChain(found);
-		// put the new wagon at the end of the loco.
-		DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
-		RebuildVehicleLists();
-	}
-}
-
-void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	const Vehicle *v;
-
-	if (!success) return;
-
-	v = GetVehicle(_new_vehicle_id);
-	if (tile == _backup_orders_tile) {
-		_backup_orders_tile = 0;
-		RestoreVehicleOrders(v, _backup_orders_data);
-	}
-	ShowTrainViewWindow(v);
-}
-
-void CcCloneTrain(bool success, TileIndex tile, uint32 p1, uint32 p2)
-{
-	if (success) ShowTrainViewWindow(GetVehicle(_new_vehicle_id));
-}
-
-static void engine_drawing_loop(const EngineList *engines, int x, int *y, EngineID sel, EngineID position, int16 show_max)
-{
-	int count = min(EngList_Count(engines), show_max);
-	for (; position < count; *y += 14, position++) {
-		EngineID id = (*engines)[position];
-		DrawString(x + 59, *y + 2, GetCustomEngineName(id), sel == id ? 0xC : 0x10);
-		DrawTrainEngine(x + 29, *y + 6, id, GetEnginePalette(id, _local_player));
-	}
-}
-
-static void GenerateBuildList(Window *w)
-{
-	EngineID eid, sel_id;
-	int num_engines = 0;
-	int num_wagons  = 0;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	bv->filter.railtype = (w->window_number == 0) ? RAILTYPE_END : GetRailType(w->window_number);
-
-	EngList_RemoveAll(&bv->eng_list);
-
-	/* Make list of all available train engines and wagons.
-	 * Also check to see if the previously selected engine is still available,
-	 * and if not, reset selection to INVALID_ENGINE. This could be the case
-	 * when engines become obsolete and are removed */
-	for (sel_id = INVALID_ENGINE, eid = 0; eid < NUM_TRAIN_ENGINES; eid++) {
-		const Engine *e = GetEngine(eid);
-		const RailVehicleInfo *rvi = RailVehInfo(eid);
-
-		if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(e->railtype, bv->filter.railtype)) continue;
-		if (!IsEngineBuildable(eid, VEH_Train, _local_player)) continue;
-
-		EngList_Add(&bv->eng_list, eid);
-		if ((rvi->flags & RVI_WAGON) == 0) {
-			num_engines++;
-		} else {
-			num_wagons++;
-		}
-
-		if (eid == bv->sel_engine) sel_id = eid;
-	}
-
-	bv->sel_engine = sel_id;
-
-	// make engines first, and then wagons, sorted by ListPositionOfEngine()
-	_internal_sort_order = false;
-	EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter);
-
-	// and then sort engines
-	_internal_sort_order = bv->descending_sort_order;
-	EngList_SortPartial(&bv->eng_list, _engine_sorter[bv->sort_criteria], 0, num_engines);
-
-	// and finally sort wagons
-	EngList_SortPartial(&bv->eng_list, _engine_sorter[bv->sort_criteria], num_engines, num_wagons);
-}
-
-static void DrawTrainBuildWindow(Window *w)
-{
-	const buildvehicle_d *bv = &WP(w, buildvehicle_d);
-	int x = 1;
-	int y = 27;
-	EngineID selected_id = bv->sel_engine;
-	int max = w->vscroll.pos + w->vscroll.cap;
-
-	SetWindowWidgetDisabledState(w, BUILD_TRAIN_WIDGET_BUILD, w->window_number == 0); // Disable unless we got a depot to build in
-
-	SetVScrollCount(w, EngList_Count(&bv->eng_list));
-	SetDParam(0, bv->filter.railtype + STR_881C_NEW_RAIL_VEHICLES);
-	DrawWindowWidgets(w);
-
-	/* Draw the engines */
-	engine_drawing_loop(&bv->eng_list, x, &y, selected_id, w->vscroll.pos, max);
-
-	if (selected_id != INVALID_ENGINE) {
-		const RailVehicleInfo *rvi = RailVehInfo(selected_id);
-		const Widget *wi = &w->widget[BUILD_TRAIN_WIDGET_PANEL];
-
-		if (rvi->flags & RVI_WAGON) {
-			DrawTrainWagonPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
-		} else {
-			DrawTrainEnginePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
-		}
-	}
-	DrawString(85, 15, _engine_sort_listing[bv->sort_criteria], 0x10);
-	DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
-}
-
-static void NewRailVehicleWndProc(Window *w, WindowEvent *e)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-	switch (e->event) {
-		case WE_CREATE:
-			EngList_Create(&bv->eng_list);
-			bv->sel_engine            = INVALID_ENGINE;
-			bv->sort_criteria         = _last_sort_criteria;
-			bv->descending_sort_order = _last_sort_order;
-			GenerateBuildList(w);
-			/* Select the first engine in the list as default when opening the window */
-			if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
-			break;
-
-		case WE_INVALIDATE_DATA:
-			GenerateBuildList(w);
-			break;
-
-		case WE_DESTROY:
-			EngList_Destroy(&bv->eng_list);
-			break;
-
-		case WE_PAINT:
-			DrawTrainBuildWindow(w);
-			break;
-
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				case BUILD_TRAIN_WIDGET_SORT_ASCENDING_DESCENDING:
-					bv->descending_sort_order ^= true;
-					_last_sort_order = bv->descending_sort_order;
-					GenerateBuildList(w);
-					SetWindowDirty(w);
-					break;
-
-				case BUILD_TRAIN_WIDGET_SORT_TEXT: case BUILD_TRAIN_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
-					ShowDropDownMenu(w, _engine_sort_listing, bv->sort_criteria, BUILD_TRAIN_WIDGET_SORT_DROPDOWN, 0, 0);
-					return;
-
-				case BUILD_TRAIN_WIDGET_LIST: {
-					uint i = ((e->we.click.pt.y - 26) / 14) + w->vscroll.pos;
-					uint num_items = EngList_Count(&bv->eng_list);
-					bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
-					SetWindowDirty(w);
-					break;
-				}
-
-				case BUILD_TRAIN_WIDGET_BUILD: {
-					EngineID sel_eng = bv->sel_engine;
-					if (sel_eng != INVALID_ENGINE)
-						DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->flags & RVI_WAGON) ? CcBuildWagon : CcBuildLoco, CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
-					break;
-				}
-
-				case BUILD_TRAIN_WIDGET_RENAME: {
-					EngineID sel_eng = bv->sel_engine;
-					if (sel_eng != INVALID_ENGINE) {
-						bv->rename_engine = sel_eng;
-						ShowQueryString(GetCustomEngineName(sel_eng), STR_886A_RENAME_TRAIN_VEHICLE_TYPE, 31, 160, w, CS_ALPHANUMERAL);
-					}
-					break;
-				}
-			}
-		}
-		break;
-
-		case WE_ON_EDIT_TEXT: {
-			if (e->we.edittext.str[0] != '\0') {
-				_cmd_text = e->we.edittext.str;
-				DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_886B_CAN_T_RENAME_TRAIN_VEHICLE));
-			}
-			break;
-		}
-
-		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-			if (bv->sort_criteria != e->we.dropdown.index) {
-				bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
-				GenerateBuildList(w);
-				SetWindowDirty(w);
-			}
-			break;
-
-		case WE_RESIZE: {
-			if (e->we.sizing.diff.y == 0) break;
-
-			w->vscroll.cap += e->we.sizing.diff.y / 14;
-			w->widget[BUILD_TRAIN_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-			break;
-		}
-	}
-}
-
-static const WindowDesc _new_rail_vehicle_desc = {
-	WDP_AUTO, WDP_AUTO, 228, 252,
-	WC_BUILD_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_new_rail_vehicle_widgets,
-	NewRailVehicleWndProc
-};
-
-void ShowBuildTrainWindow(TileIndex tile)
-{
-	Window *w;
-
-	DeleteWindowById(WC_BUILD_VEHICLE, tile);
-
-	w = AllocateWindowDescFront(&_new_rail_vehicle_desc, tile);
-	w->vscroll.cap = 8;
-	w->widget[BUILD_TRAIN_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-
-	w->resize.step_height = 14;
-	w->resize.height = w->height - 14 * 4; // Minimum of 4 vehicles in the display
-
-	if (tile != 0) {
-		w->caption_color = GetTileOwner(tile);
-		WP(w,buildvehicle_d).filter.railtype = GetRailType(tile);
-	} else {
-		w->caption_color = _local_player;
-		WP(w,buildvehicle_d).filter.railtype = RAILTYPE_END;
-	}
-}
-
-/**
- * Get the number of pixels for the given wagon length.
- * @param len Length measured in 1/8ths of a standard wagon.
- * @return Number of pixels across.
- */
-int WagonLengthToPixels(int len) {
-	return (len * _traininfo_vehicle_width) / 8;
-}
-
-void DrawTrainImage(const Vehicle *v, int x, int y, int count, int skip, VehicleID selection)
-{
-	DrawPixelInfo tmp_dpi, *old_dpi;
-	int dx = -(skip * 8) / _traininfo_vehicle_width;
-	/* Position of highlight box */
-	int highlight_l = 0;
-	int highlight_r = 0;
-
-	if (!FillDrawPixelInfo(&tmp_dpi, x - 2, y - 1, count + 1, 14)) return;
-
-	count = (count * 8) / _traininfo_vehicle_width;
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = &tmp_dpi;
-
-	do {
-		int width = v->u.rail.cached_veh_length;
-
-		if (dx + width > 0) {
-			if (dx <= count) {
-				PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-				DrawSprite(GetTrainImage(v, DIR_W) | pal, 16 + WagonLengthToPixels(dx), 7 + (is_custom_sprite(RailVehInfo(v->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
-				if (v->index == selection) {
-					/* Set the highlight position */
-					highlight_l = WagonLengthToPixels(dx) + 1;
-					highlight_r = WagonLengthToPixels(dx + width) + 1;
-				}
-			}
-		}
-		dx += width;
-
-		v = v->next;
-	} while (dx < count && v != NULL);
-
-	if (highlight_l != highlight_r) {
-		/* Draw the highlight. Now done after drawing all the engines, as
-		 * the next engine after the highlight could overlap it. */
-		DrawFrameRect(highlight_l, 0, highlight_r, 13, 15, FR_BORDERONLY);
-	}
-
-	_cur_dpi = old_dpi;
-}
-
-static const Widget _train_view_widgets[] = {
-{   WWT_CLOSEBOX,  RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
-{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_882E,                STR_018C_WINDOW_TITLE_DRAG_THIS },
-{  WWT_STICKYBOX,    RESIZE_LR, 14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON },
-{      WWT_PANEL,    RESIZE_RB, 14,   0, 231,  14, 121, 0x0,                     STR_NULL },
-{      WWT_INSET,    RESIZE_RB, 14,   2, 229,  16, 119, 0x0,                     STR_NULL },
-{    WWT_PUSHBTN,   RESIZE_RTB, 14,   0, 237, 122, 133, 0x0,                     STR_8846_CURRENT_TRAIN_ACTION_CLICK },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_8848_CENTER_MAIN_VIEW_ON_TRAIN },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  32,  49, SPR_SEND_TRAIN_TODEPOT,  STR_8849_SEND_TRAIN_TO_DEPOT },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  50,  67, SPR_IGNORE_SIGNALS,      STR_884A_FORCE_TRAIN_TO_PROCEED },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  68,  85, SPR_FORCE_VEHICLE_TURN,  STR_884B_REVERSE_DIRECTION_OF_TRAIN },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  86, 103, SPR_SHOW_ORDERS,         STR_8847_SHOW_TRAIN_S_ORDERS },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249, 104, 121, SPR_SHOW_VEHICLE_DETAILS,STR_884C_SHOW_TRAIN_DETAILS },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  68,  85, SPR_REFIT_VEHICLE,       STR_RAIL_REFIT_VEHICLE_TO_CARRY },
-{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  32,  49, SPR_CLONE_TRAIN,         STR_CLONE_TRAIN_INFO },
-{      WWT_PANEL,   RESIZE_LRB, 14, 232, 249, 122, 121, 0x0,                     STR_NULL },
-{  WWT_RESIZEBOX,  RESIZE_LRTB, 14, 238, 249, 122, 133, 0x0,                     STR_NULL },
-{ WIDGETS_END }
-};
-
-static void ShowTrainDetailsWindow(const Vehicle *v);
-
-static void TrainViewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		const Vehicle *v, *u;
-		StringID str;
-		bool is_localplayer;
-
-		v = GetVehicle(w->window_number);
-
-		is_localplayer = v->owner == _local_player;
-		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
-		SetWindowWidgetDisabledState(w,  8, !is_localplayer);
-		SetWindowWidgetDisabledState(w,  9, !is_localplayer);
-		SetWindowWidgetDisabledState(w, 13, !is_localplayer);
-
-		/* Disable cargo refit button, until we know we can enable it below. */
-		DisableWindowWidget(w, 12);
-
-		if (is_localplayer) {
-			/* See if any vehicle can be refitted */
-			for (u = v; u != NULL; u = u->next) {
-				if (EngInfo(u->engine_type)->refit_mask != 0 ||
-						(!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
-					EnableWindowWidget(w, 12);
-					/* We have a refittable carriage, bail out */
-					break;
-				}
-			}
-		}
-
-		/* draw widgets & caption */
-		SetDParam(0, v->string_id);
-		SetDParam(1, v->unitnumber);
-		DrawWindowWidgets(w);
-
-		if (v->u.rail.crash_anim_pos != 0) {
-			str = STR_8863_CRASHED;
-		} else if (v->breakdown_ctr == 1) {
-			str = STR_885C_BROKEN_DOWN;
-		} else if (v->vehstatus & VS_STOPPED) {
-			if (v->u.rail.last_speed == 0) {
-				if (v->u.rail.cached_power == 0) {
-					str = STR_TRAIN_NO_POWER;
-				} else {
-					str = STR_8861_STOPPED;
-				}
-			} else {
-				SetDParam(0, v->u.rail.last_speed);
-				str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
-			}
-		} else {
-			switch (v->current_order.type) {
-			case OT_GOTO_STATION: {
-				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
-				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->u.rail.last_speed);
-			} break;
-
-			case OT_GOTO_DEPOT: {
-				Depot *dep = GetDepot(v->current_order.dest);
-				SetDParam(0, dep->town_index);
-				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-					str = STR_HEADING_FOR_TRAIN_DEPOT + _patches.vehicle_speed;
-				} else {
-					str = STR_HEADING_FOR_TRAIN_DEPOT_SERVICE + _patches.vehicle_speed;
-				}
-				SetDParam(1, v->u.rail.last_speed);
-			} break;
-
-			case OT_LOADING:
-			case OT_LEAVESTATION:
-				str = STR_882F_LOADING_UNLOADING;
-				break;
-
-			case OT_GOTO_WAYPOINT: {
-				SetDParam(0, v->current_order.dest);
-				str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
-				SetDParam(1, v->u.rail.last_speed);
-				break;
-			}
-
-			default:
-				if (v->num_orders == 0) {
-					str = STR_NO_ORDERS + _patches.vehicle_speed;
-					SetDParam(0, v->u.rail.last_speed);
-				} else {
-					str = STR_EMPTY;
-				}
-				break;
-			}
-		}
-
-		/* draw the flag plus orders */
-		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
-		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
-		DrawWindowViewport(w);
-	}	break;
-
-	case WE_CLICK: {
-		int wid = e->we.click.widget;
-		Vehicle *v = GetVehicle(w->window_number);
-
-		switch (wid) {
-		case 5: /* start/stop train */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN));
-			break;
-		case 6: /* center main view */
-			ScrollMainWindowTo(v->x_pos, v->y_pos);
-			break;
-		case 7: /* goto depot */
-			/* TrainGotoDepot has a nice randomizer in the pathfinder, which causes desyncs... */
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_TRAIN_TO_DEPOT | CMD_NO_TEST_IF_IN_NETWORK | CMD_MSG(STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT));
-			break;
-		case 8: /* force proceed */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
-			break;
-		case 9: /* reverse direction */
-			DoCommandP(v->tile, v->index, 0, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_8869_CAN_T_REVERSE_DIRECTION));
-			break;
-		case 10: /* show train orders */
-			ShowOrdersWindow(v);
-			break;
-		case 11: /* show train details */
-			ShowTrainDetailsWindow(v);
-			break;
-		case 12:
-			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
-			break;
-		case 13:
-			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, NULL, CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
-			break;
-		}
-	} break;
-
-	case WE_RESIZE:
-		w->viewport->width          += e->we.sizing.diff.x;
-		w->viewport->height         += e->we.sizing.diff.y;
-		w->viewport->virtual_width  += e->we.sizing.diff.x;
-		w->viewport->virtual_height += e->we.sizing.diff.y;
-		break;
-
-	case WE_DESTROY:
-		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
-		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
-		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
-		break;
-
-	case WE_MOUSELOOP: {
-		const Vehicle *v = GetVehicle(w->window_number);
-		bool train_stopped = CheckTrainStoppedInDepot(v)  >= 0;
-
-		/* Widget 7 (send to depot) must be hidden if the train is already stopped in hangar.
-		 * Widget 13 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
-		 * This sytem allows to have two buttons, on top of each other.
-		 * The same system applies to widget 9 and 12, reverse direction and refit*/
-		if (train_stopped != IsWindowWidgetHidden(w, 7) || train_stopped == IsWindowWidgetHidden(w, 13)) {
-			SetWindowWidgetHiddenState(w,  7, train_stopped);  // send to depot
-			SetWindowWidgetHiddenState(w,  9, train_stopped);  // reverse direction
-			SetWindowWidgetHiddenState(w, 12, !train_stopped); // refit
-			SetWindowWidgetHiddenState(w, 13, !train_stopped); // clone
-			SetWindowDirty(w);
-		}
-		break;
-	}
-
-	}
-}
-
-static const WindowDesc _train_view_desc = {
-	WDP_AUTO, WDP_AUTO, 250, 134,
-	WC_VEHICLE_VIEW,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_train_view_widgets,
-	TrainViewWndProc
-};
-
-void ShowTrainViewWindow(const Vehicle *v)
-{
-	Window *w = AllocateWindowDescFront(&_train_view_desc,v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		AssignWindowViewport(w, 3, 17, 0xE2, 0x66, w->window_number | (1 << 31), 0);
-	}
-}
-
-static void TrainDetailsCargoTab(const Vehicle *v, int x, int y)
-{
-	if (v->cargo_cap != 0) {
-		uint num = v->cargo_count;
-		StringID str = STR_8812_EMPTY;
-
-		if (num != 0) {
-			SetDParam(0, v->cargo_type);
-			SetDParam(1, num);
-			SetDParam(2, v->cargo_source);
-			SetDParam(3, _patches.freight_trains);
-			str = FreightWagonMult(v->cargo_type) > 1 ? STR_FROM_MULT : STR_8813_FROM;
-		}
-		DrawString(x, y, str, 0);
-	}
-}
-
-static void TrainDetailsInfoTab(const Vehicle *v, int x, int y)
-{
-	if (RailVehInfo(v->engine_type)->flags & RVI_WAGON) {
-		SetDParam(0, GetCustomEngineName(v->engine_type));
-		SetDParam(1, v->value);
-		DrawString(x, y, STR_882D_VALUE, 0x10);
-	} else {
-		SetDParam(0, GetCustomEngineName(v->engine_type));
-		SetDParam(1, v->build_year);
-		SetDParam(2, v->value);
-		DrawString(x, y, STR_882C_BUILT_VALUE, 0x10);
-	}
-}
-
-static void TrainDetailsCapacityTab(const Vehicle *v, int x, int y)
-{
-	if (v->cargo_cap != 0) {
-		SetDParam(0, v->cargo_type);
-		SetDParam(1, v->cargo_cap);
-		SetDParam(2, _patches.freight_trains);
-		DrawString(x, y, FreightWagonMult(v->cargo_type) > 1 ? STR_CAPACITY_MULT : STR_013F_CAPACITY, 0);
-	}
-}
-
-
-static void DrawTrainDetailsWindow(Window *w)
-{
-	byte det_tab = WP(w, traindetails_d).tab;
-	const Vehicle *v;
-	const Vehicle *u;
-	AcceptedCargo act_cargo;
-	AcceptedCargo max_cargo;
-	uint i;
-	int num;
-	int x;
-	int y;
-	int sel;
-
-	num = 0;
-	u = v = GetVehicle(w->window_number);
-	if (det_tab == 3) { // Total cargo tab
-		for (i = 0; i < lengthof(act_cargo); i++) {
-			act_cargo[i] = 0;
-			max_cargo[i] = 0;
-		}
-
-		do {
-			act_cargo[u->cargo_type] += u->cargo_count;
-			max_cargo[u->cargo_type] += u->cargo_cap;
-		} while ((u = u->next) != NULL);
-
-		/* Set scroll-amount seperately from counting, as to not compute num double
-		 * for more carriages of the same type
-		 */
-		for (i = 0; i != NUM_CARGO; i++) {
-			if (max_cargo[i] > 0) num++; // only count carriages that the train has
-		}
-		num++; // needs one more because first line is description string
-	} else {
-		do {
-			if (!IsArticulatedPart(u) || u->cargo_cap != 0) num++;
-		} while ((u = u->next) != NULL);
-	}
-
-	SetVScrollCount(w, num);
-
-	DisableWindowWidget(w, det_tab + 9);
-	SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
-
-	/* disable service-scroller when interval is set to disabled */
-	SetWindowWidgetDisabledState(w, 6, !_patches.servint_trains);
-	SetWindowWidgetDisabledState(w, 7, !_patches.servint_trains);
-
-	SetDParam(0, v->string_id);
-	SetDParam(1, v->unitnumber);
-	DrawWindowWidgets(w);
-
-	SetDParam(1, v->age / 366);
-
-	x = 2;
-
-	SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
-	SetDParam(2, v->max_age / 366);
-	SetDParam(3, GetTrainRunningCost(v) >> 8);
-	DrawString(x, 15, STR_885D_AGE_RUNNING_COST_YR, 0);
-
-	SetDParam(2, v->u.rail.cached_max_speed);
-	SetDParam(1, v->u.rail.cached_power);
-	SetDParam(0, v->u.rail.cached_weight);
-	SetDParam(3, v->u.rail.cached_max_te / 1000);
-	DrawString(x, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
-		STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
-		STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, 0);
-
-	SetDParam(0, v->profit_this_year);
-	SetDParam(1, v->profit_last_year);
-	DrawString(x, 35, STR_885F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
-
-	SetDParam(0, 100 * (v->reliability>>8) >> 8);
-	SetDParam(1, v->breakdowns_since_last_service);
-	DrawString(x, 45, STR_8860_RELIABILITY_BREAKDOWNS, 0);
-
-	SetDParam(0, v->service_interval);
-	SetDParam(1, v->date_of_last_service);
-	DrawString(x + 11, 57 + (w->vscroll.cap * 14), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, 0);
-
-	y = 57;
-	sel = w->vscroll.pos;
-
-	// draw the first 3 details tabs
-	if (det_tab != 3) {
-		x = 1;
-		for (;;) {
-			if (--sel < 0 && sel >= -w->vscroll.cap) {
-				int dx = 0;
-				int px;
-				int py;
-
-				u = v;
-				do {
-					PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-					DrawSprite(GetTrainImage(u, DIR_W) | pal, x + WagonLengthToPixels(4 + dx), y + 6 + (is_custom_sprite(RailVehInfo(u->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
-					dx += u->u.rail.cached_veh_length;
-					u = u->next;
-				} while (u != NULL && IsArticulatedPart(u) && u->cargo_cap == 0);
-
-				px = x + WagonLengthToPixels(dx) + 2;
-				py = y + 2;
-				switch (det_tab) {
-					default: NOT_REACHED();
-					case 0: TrainDetailsCargoTab(   v, px, py); break;
-					case 1:
-						// Only show name and value for the 'real' part
-						if (!IsArticulatedPart(v)) {
-							TrainDetailsInfoTab(v, px, py);
-						}
-						break;
-					case 2: TrainDetailsCapacityTab(v, px, py); break;
-				}
-				y += 14;
-
-				v = u;
-			} else {
-				// Move to the next line
-				do {
-					v = v->next;
-				} while (v != NULL && IsArticulatedPart(v) && v->cargo_cap == 0);
-			}
-			if (v == NULL) return;
-		}
-	} else {
-		// draw total cargo tab
-		DrawString(x, y + 2, STR_013F_TOTAL_CAPACITY_TEXT, 0);
-		for (i = 0; i != NUM_CARGO; i++) {
-			if (max_cargo[i] > 0 && --sel < 0 && sel > -w->vscroll.cap) {
-				y += 14;
-				SetDParam(0, i);            // {CARGO} #1
-				SetDParam(1, act_cargo[i]); // {CARGO} #2
-				SetDParam(2, i);            // {SHORTCARGO} #1
-				SetDParam(3, max_cargo[i]); // {SHORTCARGO} #2
-				SetDParam(4, _patches.freight_trains);
-				DrawString(x, y + 2, FreightWagonMult(i) > 1 ? STR_TOTAL_CAPACITY_MULT : STR_013F_TOTAL_CAPACITY, 0);
-			}
-		}
-	}
-}
-
-static void TrainDetailsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawTrainDetailsWindow(w);
-		break;
-	case WE_CLICK: {
-		int mod;
-		const Vehicle *v;
-		switch (e->we.click.widget) {
-		case 2: /* name train */
-			v = GetVehicle(w->window_number);
-			SetDParam(0, v->unitnumber);
-			ShowQueryString(v->string_id, STR_8865_NAME_TRAIN, 31, 150, w, CS_ALPHANUMERAL);
-			break;
-		case 6: /* inc serv interval */
-			mod = _ctrl_pressed? 5 : 10;
-			goto do_change_service_int;
-
-		case 7: /* dec serv interval */
-			mod = _ctrl_pressed? -5 : -10;
-do_change_service_int:
-			v = GetVehicle(w->window_number);
-
-			mod = GetServiceIntervalClamped(mod + v->service_interval);
-			if (mod == v->service_interval) return;
-
-			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
-			break;
-		/* details buttons*/
-		case 9:  // Cargo
-		case 10: // Information
-		case 11: // Capacities
-		case 12: // Total cargo
-			EnableWindowWidget(w,  9);
-			EnableWindowWidget(w, 10);
-			EnableWindowWidget(w, 11);
-			EnableWindowWidget(w, 12);
-			EnableWindowWidget(w, e->we.click.widget);
-			WP(w,traindetails_d).tab = e->we.click.widget - 9;
-			SetWindowDirty(w);
-			break;
-		}
-	} break;
-
-	case WE_ON_EDIT_TEXT:
-		if (e->we.edittext.str[0] != '\0') {
-			_cmd_text = e->we.edittext.str;
-			DoCommandP(0, w->window_number, 0, NULL,
-				CMD_NAME_VEHICLE | CMD_MSG(STR_8866_CAN_T_NAME_TRAIN));
-		}
-		break;
-
-	case WE_RESIZE:
-		if (e->we.sizing.diff.y == 0) break;
-
-		w->vscroll.cap += e->we.sizing.diff.y / 14;
-		w->widget[4].data = (w->vscroll.cap << 8) + 1;
-		break;
-	}
-}
-
-static const Widget _train_details_widgets[] = {
-{   WWT_CLOSEBOX, RESIZE_NONE,   14,   0,  10,   0,  13, STR_00C5,             STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION, RESIZE_NONE,   14,  11, 329,   0,  13, STR_8802_DETAILS,     STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN, RESIZE_NONE,   14, 330, 369,   0,  13, STR_01AA_NAME,        STR_8867_NAME_TRAIN},
-{      WWT_PANEL, RESIZE_NONE,   14,   0, 369,  14,  55, 0x0,                  STR_NULL},
-{     WWT_MATRIX, RESIZE_BOTTOM, 14,   0, 357,  56, 139, 0x601,                STR_NULL},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 358, 369,  56, 139, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  10, 140, 145, STR_0188,             STR_884D_INCREASE_SERVICING_INTERVAL},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  10, 146, 151, STR_0189,             STR_884E_DECREASE_SERVICING_INTERVAL},
-{      WWT_PANEL, RESIZE_TB,     14,  11, 369, 140, 151, 0x0,                  STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  89, 152, 163, STR_013C_CARGO,       STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14,  90, 178, 152, 163, STR_013D_INFORMATION, STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14, 179, 268, 152, 163, STR_013E_CAPACITIES,  STR_8851_SHOW_CAPACITIES_OF_EACH},
-{ WWT_PUSHTXTBTN, RESIZE_TB,     14, 269, 357, 152, 163, STR_013E_TOTAL_CARGO, STR_8852_SHOW_TOTAL_CARGO},
-{  WWT_RESIZEBOX, RESIZE_TB,     14, 358, 369, 152, 163, 0x0,                  STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-
-static const WindowDesc _train_details_desc = {
-	WDP_AUTO, WDP_AUTO, 370, 164,
-	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_train_details_widgets,
-	TrainDetailsWndProc
-};
-
-
-static void ShowTrainDetailsWindow(const Vehicle *v)
-{
-	Window *w;
-	VehicleID veh = v->index;
-
-	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
-	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
-
-	w = AllocateWindowDescFront(&_train_details_desc, veh);
-
-	w->caption_color = v->owner;
-	w->vscroll.cap = 6;
-	w->widget[4].data = (w->vscroll.cap << 8) + 1;
-
-	w->resize.step_height = 14;
-	w->resize.height = w->height - 14 * 2; /* Minimum of 4 wagons in the display */
-
-	WP(w,traindetails_d).tab = 0;
-}
new file mode 100644
--- /dev/null
+++ b/src/train_gui.cpp
@@ -0,0 +1,1135 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "rail_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "engine.h"
+#include "window.h"
+#include "gui.h"
+#include "gfx.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "station.h"
+#include "command.h"
+#include "player.h"
+#include "vehicle_gui.h"
+#include "depot.h"
+#include "train.h"
+#include "newgrf_engine.h"
+#include "date.h"
+#include "strings.h"
+
+enum BuildTrainWidgets {
+	BUILD_TRAIN_WIDGET_CLOSEBOX = 0,
+	BUILD_TRAIN_WIDGET_CAPTION,
+	BUILD_TRAIN_WIDGET_SORT_ASCENDING_DESCENDING,
+	BUILD_TRAIN_WIDGET_SORT_TEXT,
+	BUILD_TRAIN_WIDGET_SORT_DROPDOWN,
+	BUILD_TRAIN_WIDGET_LIST,
+	BUILD_TRAIN_WIDGET_SCROLLBAR,
+	BUILD_TRAIN_WIDGET_PANEL,
+	BUILD_TRAIN_WIDGET_BUILD,
+	BUILD_TRAIN_WIDGET_RENAME,
+	BUILD_TRAIN_WIDGET_RESIZE,
+};
+
+static const Widget _new_rail_vehicle_widgets[] = {
+	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
+	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   227,     0,    13, STR_JUST_STRING,        STR_018C_WINDOW_TITLE_DRAG_THIS},
+	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,            STR_SORT_ORDER_TIP},
+	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   215,    14,    25, 0x0,                    STR_SORT_CRITERIA_TIP},
+	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   216,   227,    14,    25, STR_0225,               STR_SORT_CRITERIA_TIP},
+	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    26,   137, 0x801,                  STR_8843_TRAIN_VEHICLE_SELECTION},
+	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    26,   137, 0x0,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+	{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   138,   239, 0x0,                    STR_NULL},
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   107,   240,   251, STR_881F_BUILD_VEHICLE, STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN},
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   108,   215,   240,   251, STR_8820_RENAME,        STR_8845_RENAME_TRAIN_VEHICLE_TYPE},
+	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   216,   227,   240,   251, 0x0,                    STR_RESIZE_BUTTON},
+	{   WIDGETS_END},
+};
+
+static bool _internal_sort_order; // false = ascending, true = descending
+static byte _last_sort_criteria = 0;
+static bool _last_sort_order = false;
+
+static int CDECL TrainEngineNumberSorter(const void *a, const void *b)
+{
+	const EngineID va = *(const EngineID*)a;
+	const EngineID vb = *(const EngineID*)b;
+	int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b)
+{
+	EngineID va = *(const EngineID*)a;
+	EngineID vb = *(const EngineID*)b;
+	int val_a = ((RailVehInfo(va)->flags & RVI_WAGON) != 0) ? 1 : 0;
+	int val_b = ((RailVehInfo(vb)->flags & RVI_WAGON) != 0) ? 1 : 0;
+	int r = val_a - val_b;
+
+	/* Use EngineID to sort instead since we want consistent sorting */
+	if (r == 0) return TrainEngineNumberSorter(a, b);
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEngineCostSorter(const void *a, const void *b)
+{
+	int va = RailVehInfo(*(const EngineID*)a)->base_cost;
+	int vb = RailVehInfo(*(const EngineID*)b)->base_cost;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEngineSpeedSorter(const void *a, const void *b)
+{
+	int va = RailVehInfo(*(const EngineID*)a)->max_speed;
+	int vb = RailVehInfo(*(const EngineID*)b)->max_speed;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEnginePowerSorter(const void *a, const void *b)
+{
+	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
+	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
+
+	int va = rvi_a->power << (rvi_a->flags & RVI_MULTIHEAD ? 1 : 0);
+	int vb = rvi_b->power << (rvi_b->flags & RVI_MULTIHEAD ? 1 : 0);
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEngineIntroDateSorter(const void *a, const void *b)
+{
+	int va = GetEngine(*(const EngineID*)a)->intro_date;
+	int vb = GetEngine(*(const EngineID*)b)->intro_date;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static EngineID _last_engine; // cached vehicle to hopefully speed up name-sorting
+
+static char _bufcache[64]; // used together with _last_vehicle to hopefully speed up stringsorting
+static int CDECL TrainEngineNameSorter(const void *a, const void *b)
+{
+	const EngineID va = *(const EngineID*)a;
+	const EngineID vb = *(const EngineID*)b;
+	char buf1[64];
+	int r;
+
+	GetString(buf1, GetCustomEngineName(va), lastof(buf1));
+
+	if (vb != _last_engine) {
+		_last_engine = vb;
+		_bufcache[0] = '\0';
+
+		GetString(_bufcache, GetCustomEngineName(vb), lastof(_bufcache));
+	}
+
+	r =  strcasecmp(buf1, _bufcache); // sort by name
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEngineRunningCostSorter(const void *a, const void *b)
+{
+	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
+	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
+
+	int va = rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class] * (rvi_a->flags & RVI_MULTIHEAD ? 2 : 1);
+	int vb = rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class] * (rvi_b->flags & RVI_MULTIHEAD ? 2 : 1);
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b)
+{
+	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
+	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
+
+	/* Here we are using a few tricks to get the right sort.
+	 * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int,
+	 * we will actually calculate cunning cost/power (to make it more than 1).
+	 * Because of this, the return value have to be reversed as well and we return b - a instead of a - b.
+	 * Another thing is that both power and running costs should be doubled for multiheaded engines.
+	 * Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */
+	int va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max(1, rvi_a->power);
+	int vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max(1, rvi_b->power);
+	int r = vb - va;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static int CDECL TrainEngineReliabilitySorter(const void *a, const void *b)
+{
+	int va = GetEngine(*(const EngineID*)a)->reliability;
+	int vb = GetEngine(*(const EngineID*)b)->reliability;
+	int r = va - vb;
+
+	return _internal_sort_order ? -r : r;
+}
+
+static EngList_SortTypeFunction * const _engine_sorter[] = {
+	&TrainEngineNumberSorter,
+	&TrainEngineCostSorter,
+	&TrainEngineSpeedSorter,
+	&TrainEnginePowerSorter,
+	&TrainEngineIntroDateSorter,
+	&TrainEngineNameSorter,
+	&TrainEngineRunningCostSorter,
+	&TrainEnginePowerVsRunningCostSorter,
+	&TrainEngineReliabilitySorter,
+};
+
+static const StringID _engine_sort_listing[] = {
+	STR_ENGINE_SORT_ENGINE_ID,
+	STR_ENGINE_SORT_COST,
+	STR_SORT_BY_MAX_SPEED,
+	STR_ENGINE_SORT_POWER,
+	STR_ENGINE_SORT_INTRO_DATE,
+	STR_SORT_BY_DROPDOWN_NAME,
+	STR_ENGINE_SORT_RUNNING_COST,
+	STR_ENGINE_SORT_POWER_VS_RUNNING_COST,
+	STR_SORT_BY_RELIABILITY,
+	INVALID_STRING_ID
+};
+
+/**
+ * Draw the purchase info details of train engine at a given location.
+ * @param x,y location where to draw the info
+ * @param engine_number the engine of which to draw the info of
+ */
+void DrawTrainEnginePurchaseInfo(int x, int y, uint w, EngineID engine_number)
+{
+	const RailVehicleInfo *rvi = RailVehInfo(engine_number);
+	const Engine *e = GetEngine(engine_number);
+	int multihead = (rvi->flags&RVI_MULTIHEAD?1:0);
+	YearMonthDay ymd;
+	ConvertDateToYMD(e->intro_date, &ymd);
+
+	/* Purchase Cost - Engine weight */
+	SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5);
+	SetDParam(1, rvi->weight << multihead);
+	DrawString(x,y, STR_PURCHASE_INFO_COST_WEIGHT, 0);
+	y += 10;
+
+	/* Max speed - Engine power */
+	SetDParam(0, rvi->max_speed);
+	SetDParam(1, rvi->power << multihead);
+	DrawString(x,y, STR_PURCHASE_INFO_SPEED_POWER, 0);
+	y += 10;
+
+	/* Max tractive effort - not applicable if old acceleration or maglev */
+	if (_patches.realistic_acceleration && e->railtype != RAILTYPE_MAGLEV) {
+		SetDParam(0, ((rvi->weight << multihead) * 10 * rvi->tractive_effort) / 256);
+		DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, 0);
+		y += 10;
+	}
+
+	/* Running cost */
+	SetDParam(0, (rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8) << multihead);
+	DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
+	y += 10;
+
+	/* Powered wagons power - Powered wagons extra weight */
+	if (rvi->pow_wag_power != 0) {
+		SetDParam(0, rvi->pow_wag_power);
+		SetDParam(1, rvi->pow_wag_weight);
+		DrawString(x,y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, 0);
+		y += 10;
+	};
+
+	/* Cargo type + capacity, or N/A */
+	if (rvi->capacity == 0) {
+		SetDParam(0, CT_INVALID);
+		SetDParam(2, STR_EMPTY);
+	} else {
+		SetDParam(0, rvi->cargo_type);
+		SetDParam(1, (rvi->capacity * (CountArticulatedParts(engine_number) + 1)) << multihead);
+		SetDParam(2, STR_9842_REFITTABLE);
+	}
+	DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0);
+	y += 10;
+
+	/* Design date - Life length */
+	SetDParam(0, ymd.year);
+	SetDParam(1, e->lifelength);
+	DrawString(x,y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
+	y += 10;
+
+	/* Reliability */
+	SetDParam(0, e->reliability * 100 >> 16);
+	DrawString(x,y, STR_PURCHASE_INFO_RELIABILITY, 0);
+	y += 10;
+
+	/* Additional text from NewGRF */
+	y += ShowAdditionalText(x, y, w, engine_number);
+	if (rvi->capacity > 0) y += ShowRefitOptionsList(x, y, w, engine_number);
+}
+
+/**
+ * Draw the purchase info details of a train wagon at a given location.
+ * @param x,y location where to draw the info
+ * @param engine_number the engine of which to draw the info of
+ */
+void DrawTrainWagonPurchaseInfo(int x, int y, uint w, EngineID engine_number)
+{
+	const RailVehicleInfo *rvi = RailVehInfo(engine_number);
+	bool refittable = (EngInfo(engine_number)->refit_mask != 0);
+
+	/* Purchase cost */
+	SetDParam(0, (rvi->base_cost * _price.build_railwagon) >> 8);
+	DrawString(x, y, STR_PURCHASE_INFO_COST, 0);
+	y += 10;
+
+	/* Wagon weight - (including cargo) */
+	SetDParam(0, rvi->weight);
+	SetDParam(1, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight);
+	DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, 0);
+	y += 10;
+
+	/* Cargo type + capacity, or N/A */
+	if (rvi->capacity == 0) {
+		SetDParam(0, CT_INVALID);
+		SetDParam(2, STR_EMPTY);
+	} else {
+		SetDParam(0, rvi->cargo_type);
+		SetDParam(1, rvi->capacity * (CountArticulatedParts(engine_number) + 1));
+		SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
+	}
+	DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
+	y += 10;
+
+	/* Wagon speed limit, displayed if above zero */
+	if (rvi->max_speed > 0 && _patches.wagon_speed_limits) {
+		SetDParam(0, rvi->max_speed);
+		DrawString(x,y, STR_PURCHASE_INFO_SPEED, 0);
+		y += 10;
+	}
+
+	/* Additional text from NewGRF */
+	y += ShowAdditionalText(x, y, w, engine_number);
+	y += ShowRefitOptionsList(x, y, w, engine_number);
+}
+
+void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	Vehicle *v, *found;
+
+	if (!success) return;
+
+	// find a locomotive in the depot.
+	found = NULL;
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && IsFrontEngine(v) &&
+				v->tile == tile &&
+				v->u.rail.track == 0x80) {
+			if (found != NULL) return; // must be exactly one.
+			found = v;
+		}
+	}
+
+	// if we found a loco,
+	if (found != NULL) {
+		found = GetLastVehicleInChain(found);
+		// put the new wagon at the end of the loco.
+		DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
+		RebuildVehicleLists();
+	}
+}
+
+void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	const Vehicle *v;
+
+	if (!success) return;
+
+	v = GetVehicle(_new_vehicle_id);
+	if (tile == _backup_orders_tile) {
+		_backup_orders_tile = 0;
+		RestoreVehicleOrders(v, _backup_orders_data);
+	}
+	ShowTrainViewWindow(v);
+}
+
+void CcCloneTrain(bool success, TileIndex tile, uint32 p1, uint32 p2)
+{
+	if (success) ShowTrainViewWindow(GetVehicle(_new_vehicle_id));
+}
+
+static void engine_drawing_loop(const EngineList *engines, int x, int *y, EngineID sel, EngineID position, int16 show_max)
+{
+	int count = min(EngList_Count(engines), show_max);
+	for (; position < count; *y += 14, position++) {
+		EngineID id = (*engines)[position];
+		DrawString(x + 59, *y + 2, GetCustomEngineName(id), sel == id ? 0xC : 0x10);
+		DrawTrainEngine(x + 29, *y + 6, id, GetEnginePalette(id, _local_player));
+	}
+}
+
+static void GenerateBuildList(Window *w)
+{
+	EngineID eid, sel_id;
+	int num_engines = 0;
+	int num_wagons  = 0;
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+
+	bv->filter.railtype = (w->window_number == 0) ? RAILTYPE_END : GetRailType(w->window_number);
+
+	EngList_RemoveAll(&bv->eng_list);
+
+	/* Make list of all available train engines and wagons.
+	 * Also check to see if the previously selected engine is still available,
+	 * and if not, reset selection to INVALID_ENGINE. This could be the case
+	 * when engines become obsolete and are removed */
+	for (sel_id = INVALID_ENGINE, eid = 0; eid < NUM_TRAIN_ENGINES; eid++) {
+		const Engine *e = GetEngine(eid);
+		const RailVehicleInfo *rvi = RailVehInfo(eid);
+
+		if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(e->railtype, bv->filter.railtype)) continue;
+		if (!IsEngineBuildable(eid, VEH_Train, _local_player)) continue;
+
+		EngList_Add(&bv->eng_list, eid);
+		if ((rvi->flags & RVI_WAGON) == 0) {
+			num_engines++;
+		} else {
+			num_wagons++;
+		}
+
+		if (eid == bv->sel_engine) sel_id = eid;
+	}
+
+	bv->sel_engine = sel_id;
+
+	// make engines first, and then wagons, sorted by ListPositionOfEngine()
+	_internal_sort_order = false;
+	EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter);
+
+	// and then sort engines
+	_internal_sort_order = bv->descending_sort_order;
+	EngList_SortPartial(&bv->eng_list, _engine_sorter[bv->sort_criteria], 0, num_engines);
+
+	// and finally sort wagons
+	EngList_SortPartial(&bv->eng_list, _engine_sorter[bv->sort_criteria], num_engines, num_wagons);
+}
+
+static void DrawTrainBuildWindow(Window *w)
+{
+	const buildvehicle_d *bv = &WP(w, buildvehicle_d);
+	int x = 1;
+	int y = 27;
+	EngineID selected_id = bv->sel_engine;
+	int max = w->vscroll.pos + w->vscroll.cap;
+
+	SetWindowWidgetDisabledState(w, BUILD_TRAIN_WIDGET_BUILD, w->window_number == 0); // Disable unless we got a depot to build in
+
+	SetVScrollCount(w, EngList_Count(&bv->eng_list));
+	SetDParam(0, bv->filter.railtype + STR_881C_NEW_RAIL_VEHICLES);
+	DrawWindowWidgets(w);
+
+	/* Draw the engines */
+	engine_drawing_loop(&bv->eng_list, x, &y, selected_id, w->vscroll.pos, max);
+
+	if (selected_id != INVALID_ENGINE) {
+		const RailVehicleInfo *rvi = RailVehInfo(selected_id);
+		const Widget *wi = &w->widget[BUILD_TRAIN_WIDGET_PANEL];
+
+		if (rvi->flags & RVI_WAGON) {
+			DrawTrainWagonPurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
+		} else {
+			DrawTrainEnginePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, selected_id);
+		}
+	}
+	DrawString(85, 15, _engine_sort_listing[bv->sort_criteria], 0x10);
+	DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
+}
+
+static void NewRailVehicleWndProc(Window *w, WindowEvent *e)
+{
+	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+	switch (e->event) {
+		case WE_CREATE:
+			EngList_Create(&bv->eng_list);
+			bv->sel_engine            = INVALID_ENGINE;
+			bv->sort_criteria         = _last_sort_criteria;
+			bv->descending_sort_order = _last_sort_order;
+			GenerateBuildList(w);
+			/* Select the first engine in the list as default when opening the window */
+			if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
+			break;
+
+		case WE_INVALIDATE_DATA:
+			GenerateBuildList(w);
+			break;
+
+		case WE_DESTROY:
+			EngList_Destroy(&bv->eng_list);
+			break;
+
+		case WE_PAINT:
+			DrawTrainBuildWindow(w);
+			break;
+
+		case WE_CLICK: {
+			switch (e->we.click.widget) {
+				case BUILD_TRAIN_WIDGET_SORT_ASCENDING_DESCENDING:
+					bv->descending_sort_order ^= true;
+					_last_sort_order = bv->descending_sort_order;
+					GenerateBuildList(w);
+					SetWindowDirty(w);
+					break;
+
+				case BUILD_TRAIN_WIDGET_SORT_TEXT: case BUILD_TRAIN_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
+					ShowDropDownMenu(w, _engine_sort_listing, bv->sort_criteria, BUILD_TRAIN_WIDGET_SORT_DROPDOWN, 0, 0);
+					return;
+
+				case BUILD_TRAIN_WIDGET_LIST: {
+					uint i = ((e->we.click.pt.y - 26) / 14) + w->vscroll.pos;
+					uint num_items = EngList_Count(&bv->eng_list);
+					bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
+					SetWindowDirty(w);
+					break;
+				}
+
+				case BUILD_TRAIN_WIDGET_BUILD: {
+					EngineID sel_eng = bv->sel_engine;
+					if (sel_eng != INVALID_ENGINE)
+						DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->flags & RVI_WAGON) ? CcBuildWagon : CcBuildLoco, CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
+					break;
+				}
+
+				case BUILD_TRAIN_WIDGET_RENAME: {
+					EngineID sel_eng = bv->sel_engine;
+					if (sel_eng != INVALID_ENGINE) {
+						bv->rename_engine = sel_eng;
+						ShowQueryString(GetCustomEngineName(sel_eng), STR_886A_RENAME_TRAIN_VEHICLE_TYPE, 31, 160, w, CS_ALPHANUMERAL);
+					}
+					break;
+				}
+			}
+		}
+		break;
+
+		case WE_ON_EDIT_TEXT: {
+			if (e->we.edittext.str[0] != '\0') {
+				_cmd_text = e->we.edittext.str;
+				DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_886B_CAN_T_RENAME_TRAIN_VEHICLE));
+			}
+			break;
+		}
+
+		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+			if (bv->sort_criteria != e->we.dropdown.index) {
+				bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
+				GenerateBuildList(w);
+				SetWindowDirty(w);
+			}
+			break;
+
+		case WE_RESIZE: {
+			if (e->we.sizing.diff.y == 0) break;
+
+			w->vscroll.cap += e->we.sizing.diff.y / 14;
+			w->widget[BUILD_TRAIN_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+			break;
+		}
+	}
+}
+
+static const WindowDesc _new_rail_vehicle_desc = {
+	WDP_AUTO, WDP_AUTO, 228, 252,
+	WC_BUILD_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_new_rail_vehicle_widgets,
+	NewRailVehicleWndProc
+};
+
+void ShowBuildTrainWindow(TileIndex tile)
+{
+	Window *w;
+
+	DeleteWindowById(WC_BUILD_VEHICLE, tile);
+
+	w = AllocateWindowDescFront(&_new_rail_vehicle_desc, tile);
+	w->vscroll.cap = 8;
+	w->widget[BUILD_TRAIN_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+
+	w->resize.step_height = 14;
+	w->resize.height = w->height - 14 * 4; // Minimum of 4 vehicles in the display
+
+	if (tile != 0) {
+		w->caption_color = GetTileOwner(tile);
+		WP(w,buildvehicle_d).filter.railtype = GetRailType(tile);
+	} else {
+		w->caption_color = _local_player;
+		WP(w,buildvehicle_d).filter.railtype = RAILTYPE_END;
+	}
+}
+
+/**
+ * Get the number of pixels for the given wagon length.
+ * @param len Length measured in 1/8ths of a standard wagon.
+ * @return Number of pixels across.
+ */
+int WagonLengthToPixels(int len) {
+	return (len * _traininfo_vehicle_width) / 8;
+}
+
+void DrawTrainImage(const Vehicle *v, int x, int y, int count, int skip, VehicleID selection)
+{
+	DrawPixelInfo tmp_dpi, *old_dpi;
+	int dx = -(skip * 8) / _traininfo_vehicle_width;
+	/* Position of highlight box */
+	int highlight_l = 0;
+	int highlight_r = 0;
+
+	if (!FillDrawPixelInfo(&tmp_dpi, x - 2, y - 1, count + 1, 14)) return;
+
+	count = (count * 8) / _traininfo_vehicle_width;
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = &tmp_dpi;
+
+	do {
+		int width = v->u.rail.cached_veh_length;
+
+		if (dx + width > 0) {
+			if (dx <= count) {
+				PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
+				DrawSprite(GetTrainImage(v, DIR_W) | pal, 16 + WagonLengthToPixels(dx), 7 + (is_custom_sprite(RailVehInfo(v->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
+				if (v->index == selection) {
+					/* Set the highlight position */
+					highlight_l = WagonLengthToPixels(dx) + 1;
+					highlight_r = WagonLengthToPixels(dx + width) + 1;
+				}
+			}
+		}
+		dx += width;
+
+		v = v->next;
+	} while (dx < count && v != NULL);
+
+	if (highlight_l != highlight_r) {
+		/* Draw the highlight. Now done after drawing all the engines, as
+		 * the next engine after the highlight could overlap it. */
+		DrawFrameRect(highlight_l, 0, highlight_r, 13, 15, FR_BORDERONLY);
+	}
+
+	_cur_dpi = old_dpi;
+}
+
+static const Widget _train_view_widgets[] = {
+{   WWT_CLOSEBOX,  RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW },
+{    WWT_CAPTION, RESIZE_RIGHT, 14,  11, 237,   0,  13, STR_882E,                STR_018C_WINDOW_TITLE_DRAG_THIS },
+{  WWT_STICKYBOX,    RESIZE_LR, 14, 238, 249,   0,  13, 0x0,                     STR_STICKY_BUTTON },
+{      WWT_PANEL,    RESIZE_RB, 14,   0, 231,  14, 121, 0x0,                     STR_NULL },
+{      WWT_INSET,    RESIZE_RB, 14,   2, 229,  16, 119, 0x0,                     STR_NULL },
+{    WWT_PUSHBTN,   RESIZE_RTB, 14,   0, 237, 122, 133, 0x0,                     STR_8846_CURRENT_TRAIN_ACTION_CLICK },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  14,  31, SPR_CENTRE_VIEW_VEHICLE, STR_8848_CENTER_MAIN_VIEW_ON_TRAIN },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  32,  49, SPR_SEND_TRAIN_TODEPOT,  STR_8849_SEND_TRAIN_TO_DEPOT },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  50,  67, SPR_IGNORE_SIGNALS,      STR_884A_FORCE_TRAIN_TO_PROCEED },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  68,  85, SPR_FORCE_VEHICLE_TURN,  STR_884B_REVERSE_DIRECTION_OF_TRAIN },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  86, 103, SPR_SHOW_ORDERS,         STR_8847_SHOW_TRAIN_S_ORDERS },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249, 104, 121, SPR_SHOW_VEHICLE_DETAILS,STR_884C_SHOW_TRAIN_DETAILS },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  68,  85, SPR_REFIT_VEHICLE,       STR_RAIL_REFIT_VEHICLE_TO_CARRY },
+{ WWT_PUSHIMGBTN,    RESIZE_LR, 14, 232, 249,  32,  49, SPR_CLONE_TRAIN,         STR_CLONE_TRAIN_INFO },
+{      WWT_PANEL,   RESIZE_LRB, 14, 232, 249, 122, 121, 0x0,                     STR_NULL },
+{  WWT_RESIZEBOX,  RESIZE_LRTB, 14, 238, 249, 122, 133, 0x0,                     STR_NULL },
+{ WIDGETS_END }
+};
+
+static void ShowTrainDetailsWindow(const Vehicle *v);
+
+static void TrainViewWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT: {
+		const Vehicle *v, *u;
+		StringID str;
+		bool is_localplayer;
+
+		v = GetVehicle(w->window_number);
+
+		is_localplayer = v->owner == _local_player;
+		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
+		SetWindowWidgetDisabledState(w,  8, !is_localplayer);
+		SetWindowWidgetDisabledState(w,  9, !is_localplayer);
+		SetWindowWidgetDisabledState(w, 13, !is_localplayer);
+
+		/* Disable cargo refit button, until we know we can enable it below. */
+		DisableWindowWidget(w, 12);
+
+		if (is_localplayer) {
+			/* See if any vehicle can be refitted */
+			for (u = v; u != NULL; u = u->next) {
+				if (EngInfo(u->engine_type)->refit_mask != 0 ||
+						(!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
+					EnableWindowWidget(w, 12);
+					/* We have a refittable carriage, bail out */
+					break;
+				}
+			}
+		}
+
+		/* draw widgets & caption */
+		SetDParam(0, v->string_id);
+		SetDParam(1, v->unitnumber);
+		DrawWindowWidgets(w);
+
+		if (v->u.rail.crash_anim_pos != 0) {
+			str = STR_8863_CRASHED;
+		} else if (v->breakdown_ctr == 1) {
+			str = STR_885C_BROKEN_DOWN;
+		} else if (v->vehstatus & VS_STOPPED) {
+			if (v->u.rail.last_speed == 0) {
+				if (v->u.rail.cached_power == 0) {
+					str = STR_TRAIN_NO_POWER;
+				} else {
+					str = STR_8861_STOPPED;
+				}
+			} else {
+				SetDParam(0, v->u.rail.last_speed);
+				str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
+			}
+		} else {
+			switch (v->current_order.type) {
+			case OT_GOTO_STATION: {
+				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+				SetDParam(0, v->current_order.dest);
+				SetDParam(1, v->u.rail.last_speed);
+			} break;
+
+			case OT_GOTO_DEPOT: {
+				Depot *dep = GetDepot(v->current_order.dest);
+				SetDParam(0, dep->town_index);
+				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
+					str = STR_HEADING_FOR_TRAIN_DEPOT + _patches.vehicle_speed;
+				} else {
+					str = STR_HEADING_FOR_TRAIN_DEPOT_SERVICE + _patches.vehicle_speed;
+				}
+				SetDParam(1, v->u.rail.last_speed);
+			} break;
+
+			case OT_LOADING:
+			case OT_LEAVESTATION:
+				str = STR_882F_LOADING_UNLOADING;
+				break;
+
+			case OT_GOTO_WAYPOINT: {
+				SetDParam(0, v->current_order.dest);
+				str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
+				SetDParam(1, v->u.rail.last_speed);
+				break;
+			}
+
+			default:
+				if (v->num_orders == 0) {
+					str = STR_NO_ORDERS + _patches.vehicle_speed;
+					SetDParam(0, v->u.rail.last_speed);
+				} else {
+					str = STR_EMPTY;
+				}
+				break;
+			}
+		}
+
+		/* draw the flag plus orders */
+		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
+		DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
+		DrawWindowViewport(w);
+	}	break;
+
+	case WE_CLICK: {
+		int wid = e->we.click.widget;
+		Vehicle *v = GetVehicle(w->window_number);
+
+		switch (wid) {
+		case 5: /* start/stop train */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN));
+			break;
+		case 6: /* center main view */
+			ScrollMainWindowTo(v->x_pos, v->y_pos);
+			break;
+		case 7: /* goto depot */
+			/* TrainGotoDepot has a nice randomizer in the pathfinder, which causes desyncs... */
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_TRAIN_TO_DEPOT | CMD_NO_TEST_IF_IN_NETWORK | CMD_MSG(STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT));
+			break;
+		case 8: /* force proceed */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
+			break;
+		case 9: /* reverse direction */
+			DoCommandP(v->tile, v->index, 0, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_8869_CAN_T_REVERSE_DIRECTION));
+			break;
+		case 10: /* show train orders */
+			ShowOrdersWindow(v);
+			break;
+		case 11: /* show train details */
+			ShowTrainDetailsWindow(v);
+			break;
+		case 12:
+			ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+			break;
+		case 13:
+			DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, NULL, CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
+			break;
+		}
+	} break;
+
+	case WE_RESIZE:
+		w->viewport->width          += e->we.sizing.diff.x;
+		w->viewport->height         += e->we.sizing.diff.y;
+		w->viewport->virtual_width  += e->we.sizing.diff.x;
+		w->viewport->virtual_height += e->we.sizing.diff.y;
+		break;
+
+	case WE_DESTROY:
+		DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
+		DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
+		DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
+		break;
+
+	case WE_MOUSELOOP: {
+		const Vehicle *v = GetVehicle(w->window_number);
+		bool train_stopped = CheckTrainStoppedInDepot(v)  >= 0;
+
+		/* Widget 7 (send to depot) must be hidden if the train is already stopped in hangar.
+		 * Widget 13 (clone) should then be shown, since cloning is allowed only while in depot and stopped.
+		 * This sytem allows to have two buttons, on top of each other.
+		 * The same system applies to widget 9 and 12, reverse direction and refit*/
+		if (train_stopped != IsWindowWidgetHidden(w, 7) || train_stopped == IsWindowWidgetHidden(w, 13)) {
+			SetWindowWidgetHiddenState(w,  7, train_stopped);  // send to depot
+			SetWindowWidgetHiddenState(w,  9, train_stopped);  // reverse direction
+			SetWindowWidgetHiddenState(w, 12, !train_stopped); // refit
+			SetWindowWidgetHiddenState(w, 13, !train_stopped); // clone
+			SetWindowDirty(w);
+		}
+		break;
+	}
+
+	}
+}
+
+static const WindowDesc _train_view_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 134,
+	WC_VEHICLE_VIEW,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_train_view_widgets,
+	TrainViewWndProc
+};
+
+void ShowTrainViewWindow(const Vehicle *v)
+{
+	Window *w = AllocateWindowDescFront(&_train_view_desc,v->index);
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		AssignWindowViewport(w, 3, 17, 0xE2, 0x66, w->window_number | (1 << 31), 0);
+	}
+}
+
+static void TrainDetailsCargoTab(const Vehicle *v, int x, int y)
+{
+	if (v->cargo_cap != 0) {
+		uint num = v->cargo_count;
+		StringID str = STR_8812_EMPTY;
+
+		if (num != 0) {
+			SetDParam(0, v->cargo_type);
+			SetDParam(1, num);
+			SetDParam(2, v->cargo_source);
+			SetDParam(3, _patches.freight_trains);
+			str = FreightWagonMult(v->cargo_type) > 1 ? STR_FROM_MULT : STR_8813_FROM;
+		}
+		DrawString(x, y, str, 0);
+	}
+}
+
+static void TrainDetailsInfoTab(const Vehicle *v, int x, int y)
+{
+	if (RailVehInfo(v->engine_type)->flags & RVI_WAGON) {
+		SetDParam(0, GetCustomEngineName(v->engine_type));
+		SetDParam(1, v->value);
+		DrawString(x, y, STR_882D_VALUE, 0x10);
+	} else {
+		SetDParam(0, GetCustomEngineName(v->engine_type));
+		SetDParam(1, v->build_year);
+		SetDParam(2, v->value);
+		DrawString(x, y, STR_882C_BUILT_VALUE, 0x10);
+	}
+}
+
+static void TrainDetailsCapacityTab(const Vehicle *v, int x, int y)
+{
+	if (v->cargo_cap != 0) {
+		SetDParam(0, v->cargo_type);
+		SetDParam(1, v->cargo_cap);
+		SetDParam(2, _patches.freight_trains);
+		DrawString(x, y, FreightWagonMult(v->cargo_type) > 1 ? STR_CAPACITY_MULT : STR_013F_CAPACITY, 0);
+	}
+}
+
+
+static void DrawTrainDetailsWindow(Window *w)
+{
+	byte det_tab = WP(w, traindetails_d).tab;
+	const Vehicle *v;
+	const Vehicle *u;
+	AcceptedCargo act_cargo;
+	AcceptedCargo max_cargo;
+	uint i;
+	int num;
+	int x;
+	int y;
+	int sel;
+
+	num = 0;
+	u = v = GetVehicle(w->window_number);
+	if (det_tab == 3) { // Total cargo tab
+		for (i = 0; i < lengthof(act_cargo); i++) {
+			act_cargo[i] = 0;
+			max_cargo[i] = 0;
+		}
+
+		do {
+			act_cargo[u->cargo_type] += u->cargo_count;
+			max_cargo[u->cargo_type] += u->cargo_cap;
+		} while ((u = u->next) != NULL);
+
+		/* Set scroll-amount seperately from counting, as to not compute num double
+		 * for more carriages of the same type
+		 */
+		for (i = 0; i != NUM_CARGO; i++) {
+			if (max_cargo[i] > 0) num++; // only count carriages that the train has
+		}
+		num++; // needs one more because first line is description string
+	} else {
+		do {
+			if (!IsArticulatedPart(u) || u->cargo_cap != 0) num++;
+		} while ((u = u->next) != NULL);
+	}
+
+	SetVScrollCount(w, num);
+
+	DisableWindowWidget(w, det_tab + 9);
+	SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
+
+	/* disable service-scroller when interval is set to disabled */
+	SetWindowWidgetDisabledState(w, 6, !_patches.servint_trains);
+	SetWindowWidgetDisabledState(w, 7, !_patches.servint_trains);
+
+	SetDParam(0, v->string_id);
+	SetDParam(1, v->unitnumber);
+	DrawWindowWidgets(w);
+
+	SetDParam(1, v->age / 366);
+
+	x = 2;
+
+	SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+	SetDParam(2, v->max_age / 366);
+	SetDParam(3, GetTrainRunningCost(v) >> 8);
+	DrawString(x, 15, STR_885D_AGE_RUNNING_COST_YR, 0);
+
+	SetDParam(2, v->u.rail.cached_max_speed);
+	SetDParam(1, v->u.rail.cached_power);
+	SetDParam(0, v->u.rail.cached_weight);
+	SetDParam(3, v->u.rail.cached_max_te / 1000);
+	DrawString(x, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
+		STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
+		STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, 0);
+
+	SetDParam(0, v->profit_this_year);
+	SetDParam(1, v->profit_last_year);
+	DrawString(x, 35, STR_885F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+	SetDParam(0, 100 * (v->reliability>>8) >> 8);
+	SetDParam(1, v->breakdowns_since_last_service);
+	DrawString(x, 45, STR_8860_RELIABILITY_BREAKDOWNS, 0);
+
+	SetDParam(0, v->service_interval);
+	SetDParam(1, v->date_of_last_service);
+	DrawString(x + 11, 57 + (w->vscroll.cap * 14), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, 0);
+
+	y = 57;
+	sel = w->vscroll.pos;
+
+	// draw the first 3 details tabs
+	if (det_tab != 3) {
+		x = 1;
+		for (;;) {
+			if (--sel < 0 && sel >= -w->vscroll.cap) {
+				int dx = 0;
+				int px;
+				int py;
+
+				u = v;
+				do {
+					PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
+					DrawSprite(GetTrainImage(u, DIR_W) | pal, x + WagonLengthToPixels(4 + dx), y + 6 + (is_custom_sprite(RailVehInfo(u->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
+					dx += u->u.rail.cached_veh_length;
+					u = u->next;
+				} while (u != NULL && IsArticulatedPart(u) && u->cargo_cap == 0);
+
+				px = x + WagonLengthToPixels(dx) + 2;
+				py = y + 2;
+				switch (det_tab) {
+					default: NOT_REACHED();
+					case 0: TrainDetailsCargoTab(   v, px, py); break;
+					case 1:
+						// Only show name and value for the 'real' part
+						if (!IsArticulatedPart(v)) {
+							TrainDetailsInfoTab(v, px, py);
+						}
+						break;
+					case 2: TrainDetailsCapacityTab(v, px, py); break;
+				}
+				y += 14;
+
+				v = u;
+			} else {
+				// Move to the next line
+				do {
+					v = v->next;
+				} while (v != NULL && IsArticulatedPart(v) && v->cargo_cap == 0);
+			}
+			if (v == NULL) return;
+		}
+	} else {
+		// draw total cargo tab
+		DrawString(x, y + 2, STR_013F_TOTAL_CAPACITY_TEXT, 0);
+		for (i = 0; i != NUM_CARGO; i++) {
+			if (max_cargo[i] > 0 && --sel < 0 && sel > -w->vscroll.cap) {
+				y += 14;
+				SetDParam(0, i);            // {CARGO} #1
+				SetDParam(1, act_cargo[i]); // {CARGO} #2
+				SetDParam(2, i);            // {SHORTCARGO} #1
+				SetDParam(3, max_cargo[i]); // {SHORTCARGO} #2
+				SetDParam(4, _patches.freight_trains);
+				DrawString(x, y + 2, FreightWagonMult(i) > 1 ? STR_TOTAL_CAPACITY_MULT : STR_013F_TOTAL_CAPACITY, 0);
+			}
+		}
+	}
+}
+
+static void TrainDetailsWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+	case WE_PAINT:
+		DrawTrainDetailsWindow(w);
+		break;
+	case WE_CLICK: {
+		int mod;
+		const Vehicle *v;
+		switch (e->we.click.widget) {
+		case 2: /* name train */
+			v = GetVehicle(w->window_number);
+			SetDParam(0, v->unitnumber);
+			ShowQueryString(v->string_id, STR_8865_NAME_TRAIN, 31, 150, w, CS_ALPHANUMERAL);
+			break;
+		case 6: /* inc serv interval */
+			mod = _ctrl_pressed? 5 : 10;
+			goto do_change_service_int;
+
+		case 7: /* dec serv interval */
+			mod = _ctrl_pressed? -5 : -10;
+do_change_service_int:
+			v = GetVehicle(w->window_number);
+
+			mod = GetServiceIntervalClamped(mod + v->service_interval);
+			if (mod == v->service_interval) return;
+
+			DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+			break;
+		/* details buttons*/
+		case 9:  // Cargo
+		case 10: // Information
+		case 11: // Capacities
+		case 12: // Total cargo
+			EnableWindowWidget(w,  9);
+			EnableWindowWidget(w, 10);
+			EnableWindowWidget(w, 11);
+			EnableWindowWidget(w, 12);
+			EnableWindowWidget(w, e->we.click.widget);
+			WP(w,traindetails_d).tab = e->we.click.widget - 9;
+			SetWindowDirty(w);
+			break;
+		}
+	} break;
+
+	case WE_ON_EDIT_TEXT:
+		if (e->we.edittext.str[0] != '\0') {
+			_cmd_text = e->we.edittext.str;
+			DoCommandP(0, w->window_number, 0, NULL,
+				CMD_NAME_VEHICLE | CMD_MSG(STR_8866_CAN_T_NAME_TRAIN));
+		}
+		break;
+
+	case WE_RESIZE:
+		if (e->we.sizing.diff.y == 0) break;
+
+		w->vscroll.cap += e->we.sizing.diff.y / 14;
+		w->widget[4].data = (w->vscroll.cap << 8) + 1;
+		break;
+	}
+}
+
+static const Widget _train_details_widgets[] = {
+{   WWT_CLOSEBOX, RESIZE_NONE,   14,   0,  10,   0,  13, STR_00C5,             STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION, RESIZE_NONE,   14,  11, 329,   0,  13, STR_8802_DETAILS,     STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN, RESIZE_NONE,   14, 330, 369,   0,  13, STR_01AA_NAME,        STR_8867_NAME_TRAIN},
+{      WWT_PANEL, RESIZE_NONE,   14,   0, 369,  14,  55, 0x0,                  STR_NULL},
+{     WWT_MATRIX, RESIZE_BOTTOM, 14,   0, 357,  56, 139, 0x601,                STR_NULL},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 358, 369,  56, 139, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  10, 140, 145, STR_0188,             STR_884D_INCREASE_SERVICING_INTERVAL},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  10, 146, 151, STR_0189,             STR_884E_DECREASE_SERVICING_INTERVAL},
+{      WWT_PANEL, RESIZE_TB,     14,  11, 369, 140, 151, 0x0,                  STR_NULL},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14,   0,  89, 152, 163, STR_013C_CARGO,       STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14,  90, 178, 152, 163, STR_013D_INFORMATION, STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14, 179, 268, 152, 163, STR_013E_CAPACITIES,  STR_8851_SHOW_CAPACITIES_OF_EACH},
+{ WWT_PUSHTXTBTN, RESIZE_TB,     14, 269, 357, 152, 163, STR_013E_TOTAL_CARGO, STR_8852_SHOW_TOTAL_CARGO},
+{  WWT_RESIZEBOX, RESIZE_TB,     14, 358, 369, 152, 163, 0x0,                  STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+
+static const WindowDesc _train_details_desc = {
+	WDP_AUTO, WDP_AUTO, 370, 164,
+	WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_train_details_widgets,
+	TrainDetailsWndProc
+};
+
+
+static void ShowTrainDetailsWindow(const Vehicle *v)
+{
+	Window *w;
+	VehicleID veh = v->index;
+
+	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
+	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
+
+	w = AllocateWindowDescFront(&_train_details_desc, veh);
+
+	w->caption_color = v->owner;
+	w->vscroll.cap = 6;
+	w->widget[4].data = (w->vscroll.cap << 8) + 1;
+
+	w->resize.step_height = 14;
+	w->resize.height = w->height - 14 * 2; /* Minimum of 4 wagons in the display */
+
+	WP(w,traindetails_d).tab = 0;
+}
deleted file mode 100644
--- a/src/tree_cmd.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "clear_map.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "table/tree_land.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "tree_map.h"
-#include "viewport.h"
-#include "command.h"
-#include "town.h"
-#include "sound.h"
-#include "variables.h"
-#include "genworld.h"
-
-enum TreePlacer {
-	TP_NONE,
-	TP_ORIGINAL,
-	TP_IMPROVED,
-};
-
-static TreeType GetRandomTreeType(TileIndex tile, uint seed)
-{
-	switch (_opt.landscape) {
-		case LT_NORMAL:
-			return seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE;
-
-		case LT_HILLY:
-			return seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC;
-
-		case LT_DESERT:
-			switch (GetTropicZone(tile)) {
-				case TROPICZONE_INVALID: return seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL;
-				case TROPICZONE_DESERT:  return (seed > 12) ? TREE_INVALID : TREE_CACTUS;
-				default:                 return seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST;
-			}
-
-		default:
-			return seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND;
-	}
-}
-
-static void PlaceTree(TileIndex tile, uint32 r)
-{
-	TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
-
-	if (tree != TREE_INVALID) {
-		MakeTree(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6), TREE_GROUND_GRASS, 0);
-
-		// above snowline?
-		if (_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) {
-			SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3);
-			SetTreeCounter(tile, GB(r, 24, 3));
-		} else {
-			SetTreeGroundDensity(tile, GB(r, 28, 1), 0);
-			SetTreeCounter(tile, GB(r, 24, 4));
-		}
-	}
-}
-
-static void DoPlaceMoreTrees(TileIndex tile)
-{
-	uint i;
-
-	for (i = 0; i < 1000; i++) {
-		uint32 r = Random();
-		int x = GB(r, 0, 5) - 16;
-		int y = GB(r, 8, 5) - 16;
-		uint dist = myabs(x) + myabs(y);
-		TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y));
-
-		if (dist <= 13 &&
-				IsTileType(cur_tile, MP_CLEAR) &&
-				!IsBridgeAbove(cur_tile) &&
-				!IsClearGround(cur_tile, CLEAR_FIELDS) &&
-				!IsClearGround(cur_tile, CLEAR_ROCKS)) {
-			PlaceTree(cur_tile, r);
-		}
-	}
-}
-
-static void PlaceMoreTrees(void)
-{
-	uint i = ScaleByMapSize(GB(Random(), 0, 5) + 25);
-	do {
-		DoPlaceMoreTrees(RandomTile());
-	} while (--i);
-}
-
-/**
- * Place a tree at the same height as an existing tree.
- *  This gives cool effects to the map.
- */
-void PlaceTreeAtSameHeight(TileIndex tile, uint height)
-{
-	uint i;
-
-	for (i = 0; i < 1000; i++) {
-		uint32 r = Random();
-		int x = GB(r, 0, 5) - 16;
-		int y = GB(r, 8, 5) - 16;
-		TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y));
-
-		/* Keep in range of the existing tree */
-		if (myabs(x) + myabs(y) > 16) continue;
-
-		/* Clear tile, no farm-tiles or rocks */
-		if (!IsTileType(cur_tile, MP_CLEAR) ||
-				IsClearGround(cur_tile, CLEAR_FIELDS) ||
-				IsClearGround(cur_tile, CLEAR_ROCKS))
-			continue;
-
-		/* Not too much height difference */
-		if (myabs(GetTileZ(cur_tile) - height) > 2) continue;
-
-		/* Place one tree and quit */
-		PlaceTree(cur_tile, r);
-		break;
-	}
-}
-
-void PlaceTreesRandomly(void)
-{
-	uint i, j, ht;
-
-	i = ScaleByMapSize(1000);
-	do {
-		uint32 r = Random();
-		TileIndex tile = RandomTileSeed(r);
-
-		IncreaseGeneratingWorldProgress(GWP_TREE);
-
-		if (IsTileType(tile, MP_CLEAR) &&
-				!IsBridgeAbove(tile) &&
-				!IsClearGround(tile, CLEAR_FIELDS) &&
-				!IsClearGround(tile, CLEAR_ROCKS)) {
-			PlaceTree(tile, r);
-			if (_patches.tree_placer != TP_IMPROVED) continue;
-
-			/* Place a number of trees based on the tile height.
-			 *  This gives a cool effect of multiple trees close together.
-			 *  It is almost real life ;) */
-			ht = GetTileZ(tile);
-			/* The higher we get, the more trees we plant */
-			j = GetTileZ(tile) / TILE_HEIGHT * 2;
-			while (j--) {
-				/* Above snowline more trees! */
-				if (_opt.landscape == LT_HILLY && ht > _opt.snow_line) {
-					PlaceTreeAtSameHeight(tile, ht);
-					PlaceTreeAtSameHeight(tile, ht);
-				};
-
-				PlaceTreeAtSameHeight(tile, ht);
-			}
-		}
-	} while (--i);
-
-	/* place extra trees at rainforest area */
-	if (_opt.landscape == LT_DESERT) {
-		i = ScaleByMapSize(15000);
-
-		do {
-			uint32 r = Random();
-			TileIndex tile = RandomTileSeed(r);
-
-			IncreaseGeneratingWorldProgress(GWP_TREE);
-
-			if (IsTileType(tile, MP_CLEAR) &&
-					!IsBridgeAbove(tile) &&
-					!IsClearGround(tile, CLEAR_FIELDS) &&
-					GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
-				PlaceTree(tile, r);
-			}
-		} while (--i);
-	}
-}
-
-void GenerateTrees(void)
-{
-	uint i, total;
-
-	if (_patches.tree_placer == TP_NONE) return;
-
-	if (_opt.landscape != LT_CANDY) PlaceMoreTrees();
-
-	switch (_patches.tree_placer) {
-		case TP_ORIGINAL: i = _opt.landscape == LT_HILLY ? 15 : 6; break;
-		case TP_IMPROVED: i = _opt.landscape == LT_HILLY ?  4 : 2; break;
-		default: NOT_REACHED(); return;
-	}
-
-	total = ScaleByMapSize(1000);
-	if (_opt.landscape == LT_DESERT) total += ScaleByMapSize(15000);
-	total *= i;
-	SetGeneratingWorldProgress(GWP_TREE, total);
-
-	for (; i != 0; i--) {
-		PlaceTreesRandomly();
-	}
-}
-
-/** Plant a tree.
- * @param tile start tile of area-drag of tree plantation
- * @param p1 tree type, -1 means random.
- * @param p2 end tile of area-drag
- */
-int32 CmdPlantTree(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	StringID msg = INVALID_STRING_ID;
-	int32 cost;
-	int ex;
-	int ey;
-	int sx, sy, x, y;
-
-	if (p2 >= MapSize()) return CMD_ERROR;
-	/* Check the tree type. It can be random or some valid value within the current climate */
-	if (p1 != (uint)-1 && p1 - _tree_base_by_landscape[_opt.landscape] >= _tree_count_by_landscape[_opt.landscape]) return CMD_ERROR;
-
-	SET_EXPENSES_TYPE(EXPENSES_OTHER);
-
-	// make sure sx,sy are smaller than ex,ey
-	ex = TileX(tile);
-	ey = TileY(tile);
-	sx = TileX(p2);
-	sy = TileY(p2);
-	if (ex < sx) intswap(ex, sx);
-	if (ey < sy) intswap(ey, sy);
-
-	cost = 0; // total cost
-
-	for (x = sx; x <= ex; x++) {
-		for (y = sy; y <= ey; y++) {
-			TileIndex tile = TileXY(x, y);
-
-			if (!EnsureNoVehicle(tile)) continue;
-
-			switch (GetTileType(tile)) {
-				case MP_TREES:
-					// no more space for trees?
-					if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 3) {
-						msg = STR_2803_TREE_ALREADY_HERE;
-						continue;
-					}
-
-					if (flags & DC_EXEC) {
-						AddTreeCount(tile, 1);
-						MarkTileDirtyByTile(tile);
-					}
-					// 2x as expensive to add more trees to an existing tile
-					cost += _price.build_trees * 2;
-					break;
-
-				case MP_CLEAR:
-					if (!IsTileOwner(tile, OWNER_NONE) ||
-							IsBridgeAbove(tile)) {
-						msg = STR_2804_SITE_UNSUITABLE;
-						continue;
-					}
-
-					switch (GetClearGround(tile)) {
-						case CLEAR_FIELDS: cost += _price.clear_3; break;
-						case CLEAR_ROCKS:  cost += _price.clear_2; break;
-						default: break;
-					}
-
-					if (flags & DC_EXEC) {
-						TreeType treetype;
-						uint growth;
-
-						if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) {
-							Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-							if (t != NULL)
-								ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
-						}
-
-						treetype = p1;
-						if (treetype == TREE_INVALID) {
-							treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
-							if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
-						}
-
-						growth = _game_mode == GM_EDITOR ? 3 : 0;
-						switch (GetClearGround(tile)) {
-							case CLEAR_ROUGH: MakeTree(tile, treetype, 0, growth, TREE_GROUND_ROUGH, 0); break;
-							case CLEAR_SNOW:  MakeTree(tile, treetype, 0, growth, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
-							default:          MakeTree(tile, treetype, 0, growth, TREE_GROUND_GRASS, 0); break;
-						}
-						MarkTileDirtyByTile(tile);
-
-						if (_game_mode == GM_EDITOR && IS_INT_INSIDE(treetype, TREE_RAINFOREST, TREE_CACTUS))
-							SetTropicZone(tile, TROPICZONE_RAINFOREST);
-					}
-					cost += _price.build_trees;
-					break;
-
-				default:
-					msg = STR_2804_SITE_UNSUITABLE;
-					break;
-			}
-		}
-	}
-
-	if (cost == 0) {
-		return_cmd_error(msg);
-	} else {
-		return cost;
-	}
-}
-
-typedef struct TreeListEnt {
-	uint32 image;
-	byte x,y;
-} TreeListEnt;
-
-static void DrawTile_Trees(TileInfo *ti)
-{
-	const uint32 *s;
-	const TreePos* d;
-	byte z;
-
-	switch (GetTreeGround(ti->tile)) {
-		case TREE_GROUND_GRASS: DrawClearLandTile(ti, 3); break;
-		case TREE_GROUND_ROUGH: DrawHillyLandTile(ti); break;
-		default: DrawGroundSprite(_tree_sprites_1[GetTreeDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]); break;
-	}
-
-	DrawClearLandFence(ti);
-
-	z = ti->z;
-	if (ti->tileh != SLOPE_FLAT) {
-		z += 4;
-		if (IsSteepSlope(ti->tileh)) z += 4;
-	}
-
-	{
-		uint16 tmp = ti->x;
-		uint index;
-
-		tmp = ROR(tmp, 2);
-		tmp -= ti->y;
-		tmp = ROR(tmp, 3);
-		tmp -= ti->x;
-		tmp = ROR(tmp, 1);
-		tmp += ti->y;
-
-		d = _tree_layout_xy[GB(tmp, 4, 2)];
-
-		index = GB(tmp, 6, 2) + (GetTreeType(ti->tile) << 2);
-
-		/* different tree styles above one of the grounds */
-		if (GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT &&
-				GetTreeDensity(ti->tile) >= 2 &&
-				IS_INT_INSIDE(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) {
-			index += 164 - (TREE_SUB_ARCTIC << 2);
-		}
-
-		assert(index < lengthof(_tree_layout_sprite));
-		s = _tree_layout_sprite[index];
-	}
-
-	StartSpriteCombine();
-
-	if (!(_display_opt & DO_TRANS_BUILDINGS) || !_patches.invisible_trees) {
-		TreeListEnt te[4];
-		uint i;
-
-		/* put the trees to draw in a list */
-		i = GetTreeCount(ti->tile) + 1;
-		do {
-			uint32 image = s[0] + (--i == 0 ? GetTreeGrowth(ti->tile) : 3);
-			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-			te[i].image = image;
-			te[i].x = d->x;
-			te[i].y = d->y;
-			s++;
-			d++;
-		} while (i);
-
-		/* draw them in a sorted way */
-		for (;;) {
-			byte min = 0xFF;
-			TreeListEnt *tep = NULL;
-
-			i = GetTreeCount(ti->tile) + 1;
-			do {
-				if (te[--i].image != 0 && te[i].x + te[i].y < min) {
-					min = te[i].x + te[i].y;
-					tep = &te[i];
-				}
-			} while (i);
-
-			if (tep == NULL) break;
-
-			AddSortableSpriteToDraw(tep->image, ti->x + tep->x, ti->y + tep->y, 5, 5, 0x10, z);
-			tep->image = 0;
-		}
-	}
-
-	EndSpriteCombine();
-}
-
-
-static uint GetSlopeZ_Trees(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	uint tileh = GetTileSlope(tile, &z);
-
-	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-}
-
-static Slope GetSlopeTileh_Trees(TileIndex tile, Slope tileh)
-{
-	return tileh;
-}
-
-static int32 ClearTile_Trees(TileIndex tile, byte flags)
-{
-	uint num;
-
-	if ((flags & DC_EXEC) && IsValidPlayer(_current_player)) {
-		Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-		if (t != NULL)
-			ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM);
-	}
-
-	num = GetTreeCount(tile) + 1;
-	if (IS_INT_INSIDE(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4;
-
-	if (flags & DC_EXEC) DoClearSquare(tile);
-
-	return num * _price.remove_trees;
-}
-
-static void GetAcceptedCargo_Trees(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void GetTileDesc_Trees(TileIndex tile, TileDesc *td)
-{
-	TreeType tt = GetTreeType(tile);
-
-	if (IS_INT_INSIDE(tt, TREE_RAINFOREST, TREE_CACTUS)) {
-		td->str = STR_280F_RAINFOREST;
-	} else if (tt == TREE_CACTUS) {
-		td->str = STR_2810_CACTUS_PLANTS;
-	} else {
-		td->str = STR_280E_TREES;
-	}
-
-	td->owner = GetTileOwner(tile);
-}
-
-static void AnimateTile_Trees(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoopTreesDesert(TileIndex tile)
-{
-	switch (GetTropicZone(tile)) {
-		case TROPICZONE_DESERT:
-			if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) {
-				SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3);
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		case TROPICZONE_RAINFOREST: {
-			static const SoundFx forest_sounds[] = {
-				SND_42_LOON_BIRD,
-				SND_43_LION,
-				SND_44_MONKEYS,
-				SND_48_DISTANT_BIRD
-			};
-			uint32 r = Random();
-
-			if (CHANCE16I(1, 200, r)) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
-			break;
-		}
-
-		default: break;
-	}
-}
-
-static void TileLoopTreesAlps(TileIndex tile)
-{
-	int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
-
-	if (k < 0) {
-		if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) return;
-		SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 0);
-	} else {
-		uint density = min((uint)k / TILE_HEIGHT, 3);
-
-		if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT ||
-				GetTreeDensity(tile) != density) {
-			SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, density);
-		} else {
-			if (GetTreeDensity(tile) == 3) {
-				uint32 r = Random();
-				if (CHANCE16I(1, 200, r)) {
-					SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile);
-				}
-			}
-			return;
-		}
-	}
-	MarkTileDirtyByTile(tile);
-}
-
-static void TileLoop_Trees(TileIndex tile)
-{
-	switch (_opt.landscape) {
-		case LT_DESERT: TileLoopTreesDesert(tile); break;
-		case LT_HILLY:  TileLoopTreesAlps(tile);   break;
-	}
-
-	TileLoopClearHelper(tile);
-
-	if (GetTreeCounter(tile) < 15) {
-		AddTreeCounter(tile, 1);
-		return;
-	}
-	SetTreeCounter(tile, 0);
-
-	switch (GetTreeGrowth(tile)) {
-		case 3: /* regular sized tree */
-			if (_opt.landscape == LT_DESERT &&
-					GetTreeType(tile) != TREE_CACTUS &&
-					GetTropicZone(tile) == TROPICZONE_DESERT) {
-				AddTreeGrowth(tile, 1);
-			} else {
-				switch (GB(Random(), 0, 3)) {
-					case 0: /* start destructing */
-						AddTreeGrowth(tile, 1);
-						break;
-
-					case 1: /* add a tree */
-						if (GetTreeCount(tile) < 3) {
-							AddTreeCount(tile, 1);
-							SetTreeGrowth(tile, 0);
-							break;
-						}
-						/* FALL THROUGH */
-
-					case 2: { /* add a neighbouring tree */
-						TreeType treetype = GetTreeType(tile);
-
-						tile += TileOffsByDir(Random() & 7);
-
-						if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return;
-
-						switch (GetClearGround(tile)) {
-							case CLEAR_GRASS:
-								if (GetClearDensity(tile) != 3) return;
-								MakeTree(tile, treetype, 0, 0, TREE_GROUND_GRASS, 0);
-								break;
-
-							case CLEAR_ROUGH: MakeTree(tile, treetype, 0, 0, TREE_GROUND_ROUGH, 0); break;
-							case CLEAR_SNOW:  MakeTree(tile, treetype, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
-							default: return;
-						}
-						break;
-					}
-
-					default:
-						return;
-				}
-			}
-			break;
-
-		case 6: /* final stage of tree destruction */
-			if (GetTreeCount(tile) > 0) {
-				/* more than one tree, delete it */
-				AddTreeCount(tile, -1);
-				SetTreeGrowth(tile, 3);
-			} else {
-				/* just one tree, change type into MP_CLEAR */
-				switch (GetTreeGround(tile)) {
-					case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, 3); break;
-					case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
-					default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break;
-				}
-			}
-			break;
-
-		default:
-			AddTreeGrowth(tile, 1);
-			break;
-	}
-
-	MarkTileDirtyByTile(tile);
-}
-
-void OnTick_Trees(void)
-{
-	uint32 r;
-	TileIndex tile;
-	ClearGround ct;
-	TreeType tree;
-
-	/* place a tree at a random rainforest spot */
-	if (_opt.landscape == LT_DESERT &&
-			(r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
-			IsTileType(tile, MP_CLEAR) &&
-			!IsBridgeAbove(tile) &&
-			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) &&
-			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
-		MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0);
-	}
-
-	// byte underflow
-	if (--_trees_tick_ctr != 0) return;
-
-	/* place a tree at a random spot */
-	r = Random();
-	tile = TILE_MASK(r);
-	if (IsTileType(tile, MP_CLEAR) &&
-			!IsBridgeAbove(tile) &&
-			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) &&
-			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
-		switch (ct) {
-			case CLEAR_GRASS: MakeTree(tile, tree, 0, 0, TREE_GROUND_GRASS, 0); break;
-			case CLEAR_ROUGH: MakeTree(tile, tree, 0, 0, TREE_GROUND_ROUGH, 0); break;
-			default: MakeTree(tile, tree, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
-		}
-	}
-}
-
-static void ClickTile_Trees(TileIndex tile)
-{
-	/* not used */
-}
-
-static uint32 GetTileTrackStatus_Trees(TileIndex tile, TransportType mode)
-{
-	return 0;
-}
-
-static void ChangeTileOwner_Trees(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	/* not used */
-}
-
-void InitializeTrees(void)
-{
-	_trees_tick_ctr = 0;
-}
-
-
-const TileTypeProcs _tile_type_trees_procs = {
-	DrawTile_Trees,           /* draw_tile_proc */
-	GetSlopeZ_Trees,          /* get_slope_z_proc */
-	ClearTile_Trees,          /* clear_tile_proc */
-	GetAcceptedCargo_Trees,   /* get_accepted_cargo_proc */
-	GetTileDesc_Trees,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Trees, /* get_tile_track_status_proc */
-	ClickTile_Trees,          /* click_tile_proc */
-	AnimateTile_Trees,        /* animate_tile_proc */
-	TileLoop_Trees,           /* tile_loop_clear */
-	ChangeTileOwner_Trees,    /* change_tile_owner_clear */
-	NULL,                     /* get_produced_cargo_proc */
-	NULL,                     /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Trees,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/tree_cmd.cpp
@@ -0,0 +1,671 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "clear_map.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "table/tree_land.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "tree_map.h"
+#include "viewport.h"
+#include "command.h"
+#include "town.h"
+#include "sound.h"
+#include "variables.h"
+#include "genworld.h"
+
+enum TreePlacer {
+	TP_NONE,
+	TP_ORIGINAL,
+	TP_IMPROVED,
+};
+
+static TreeType GetRandomTreeType(TileIndex tile, uint seed)
+{
+	switch (_opt.landscape) {
+		case LT_NORMAL:
+			return seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE;
+
+		case LT_HILLY:
+			return seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC;
+
+		case LT_DESERT:
+			switch (GetTropicZone(tile)) {
+				case TROPICZONE_INVALID: return seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL;
+				case TROPICZONE_DESERT:  return (seed > 12) ? TREE_INVALID : TREE_CACTUS;
+				default:                 return seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST;
+			}
+
+		default:
+			return seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND;
+	}
+}
+
+static void PlaceTree(TileIndex tile, uint32 r)
+{
+	TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
+
+	if (tree != TREE_INVALID) {
+		MakeTree(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6), TREE_GROUND_GRASS, 0);
+
+		// above snowline?
+		if (_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) {
+			SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3);
+			SetTreeCounter(tile, GB(r, 24, 3));
+		} else {
+			SetTreeGroundDensity(tile, GB(r, 28, 1), 0);
+			SetTreeCounter(tile, GB(r, 24, 4));
+		}
+	}
+}
+
+static void DoPlaceMoreTrees(TileIndex tile)
+{
+	uint i;
+
+	for (i = 0; i < 1000; i++) {
+		uint32 r = Random();
+		int x = GB(r, 0, 5) - 16;
+		int y = GB(r, 8, 5) - 16;
+		uint dist = myabs(x) + myabs(y);
+		TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y));
+
+		if (dist <= 13 &&
+				IsTileType(cur_tile, MP_CLEAR) &&
+				!IsBridgeAbove(cur_tile) &&
+				!IsClearGround(cur_tile, CLEAR_FIELDS) &&
+				!IsClearGround(cur_tile, CLEAR_ROCKS)) {
+			PlaceTree(cur_tile, r);
+		}
+	}
+}
+
+static void PlaceMoreTrees(void)
+{
+	uint i = ScaleByMapSize(GB(Random(), 0, 5) + 25);
+	do {
+		DoPlaceMoreTrees(RandomTile());
+	} while (--i);
+}
+
+/**
+ * Place a tree at the same height as an existing tree.
+ *  This gives cool effects to the map.
+ */
+void PlaceTreeAtSameHeight(TileIndex tile, uint height)
+{
+	uint i;
+
+	for (i = 0; i < 1000; i++) {
+		uint32 r = Random();
+		int x = GB(r, 0, 5) - 16;
+		int y = GB(r, 8, 5) - 16;
+		TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y));
+
+		/* Keep in range of the existing tree */
+		if (myabs(x) + myabs(y) > 16) continue;
+
+		/* Clear tile, no farm-tiles or rocks */
+		if (!IsTileType(cur_tile, MP_CLEAR) ||
+				IsClearGround(cur_tile, CLEAR_FIELDS) ||
+				IsClearGround(cur_tile, CLEAR_ROCKS))
+			continue;
+
+		/* Not too much height difference */
+		if (myabs(GetTileZ(cur_tile) - height) > 2) continue;
+
+		/* Place one tree and quit */
+		PlaceTree(cur_tile, r);
+		break;
+	}
+}
+
+void PlaceTreesRandomly(void)
+{
+	uint i, j, ht;
+
+	i = ScaleByMapSize(1000);
+	do {
+		uint32 r = Random();
+		TileIndex tile = RandomTileSeed(r);
+
+		IncreaseGeneratingWorldProgress(GWP_TREE);
+
+		if (IsTileType(tile, MP_CLEAR) &&
+				!IsBridgeAbove(tile) &&
+				!IsClearGround(tile, CLEAR_FIELDS) &&
+				!IsClearGround(tile, CLEAR_ROCKS)) {
+			PlaceTree(tile, r);
+			if (_patches.tree_placer != TP_IMPROVED) continue;
+
+			/* Place a number of trees based on the tile height.
+			 *  This gives a cool effect of multiple trees close together.
+			 *  It is almost real life ;) */
+			ht = GetTileZ(tile);
+			/* The higher we get, the more trees we plant */
+			j = GetTileZ(tile) / TILE_HEIGHT * 2;
+			while (j--) {
+				/* Above snowline more trees! */
+				if (_opt.landscape == LT_HILLY && ht > _opt.snow_line) {
+					PlaceTreeAtSameHeight(tile, ht);
+					PlaceTreeAtSameHeight(tile, ht);
+				};
+
+				PlaceTreeAtSameHeight(tile, ht);
+			}
+		}
+	} while (--i);
+
+	/* place extra trees at rainforest area */
+	if (_opt.landscape == LT_DESERT) {
+		i = ScaleByMapSize(15000);
+
+		do {
+			uint32 r = Random();
+			TileIndex tile = RandomTileSeed(r);
+
+			IncreaseGeneratingWorldProgress(GWP_TREE);
+
+			if (IsTileType(tile, MP_CLEAR) &&
+					!IsBridgeAbove(tile) &&
+					!IsClearGround(tile, CLEAR_FIELDS) &&
+					GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
+				PlaceTree(tile, r);
+			}
+		} while (--i);
+	}
+}
+
+void GenerateTrees(void)
+{
+	uint i, total;
+
+	if (_patches.tree_placer == TP_NONE) return;
+
+	if (_opt.landscape != LT_CANDY) PlaceMoreTrees();
+
+	switch (_patches.tree_placer) {
+		case TP_ORIGINAL: i = _opt.landscape == LT_HILLY ? 15 : 6; break;
+		case TP_IMPROVED: i = _opt.landscape == LT_HILLY ?  4 : 2; break;
+		default: NOT_REACHED(); return;
+	}
+
+	total = ScaleByMapSize(1000);
+	if (_opt.landscape == LT_DESERT) total += ScaleByMapSize(15000);
+	total *= i;
+	SetGeneratingWorldProgress(GWP_TREE, total);
+
+	for (; i != 0; i--) {
+		PlaceTreesRandomly();
+	}
+}
+
+/** Plant a tree.
+ * @param tile start tile of area-drag of tree plantation
+ * @param p1 tree type, -1 means random.
+ * @param p2 end tile of area-drag
+ */
+int32 CmdPlantTree(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	StringID msg = INVALID_STRING_ID;
+	int32 cost;
+	int ex;
+	int ey;
+	int sx, sy, x, y;
+
+	if (p2 >= MapSize()) return CMD_ERROR;
+	/* Check the tree type. It can be random or some valid value within the current climate */
+	if (p1 != (uint)-1 && p1 - _tree_base_by_landscape[_opt.landscape] >= _tree_count_by_landscape[_opt.landscape]) return CMD_ERROR;
+
+	SET_EXPENSES_TYPE(EXPENSES_OTHER);
+
+	// make sure sx,sy are smaller than ex,ey
+	ex = TileX(tile);
+	ey = TileY(tile);
+	sx = TileX(p2);
+	sy = TileY(p2);
+	if (ex < sx) intswap(ex, sx);
+	if (ey < sy) intswap(ey, sy);
+
+	cost = 0; // total cost
+
+	for (x = sx; x <= ex; x++) {
+		for (y = sy; y <= ey; y++) {
+			TileIndex tile = TileXY(x, y);
+
+			if (!EnsureNoVehicle(tile)) continue;
+
+			switch (GetTileType(tile)) {
+				case MP_TREES:
+					// no more space for trees?
+					if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 3) {
+						msg = STR_2803_TREE_ALREADY_HERE;
+						continue;
+					}
+
+					if (flags & DC_EXEC) {
+						AddTreeCount(tile, 1);
+						MarkTileDirtyByTile(tile);
+					}
+					// 2x as expensive to add more trees to an existing tile
+					cost += _price.build_trees * 2;
+					break;
+
+				case MP_CLEAR:
+					if (!IsTileOwner(tile, OWNER_NONE) ||
+							IsBridgeAbove(tile)) {
+						msg = STR_2804_SITE_UNSUITABLE;
+						continue;
+					}
+
+					switch (GetClearGround(tile)) {
+						case CLEAR_FIELDS: cost += _price.clear_3; break;
+						case CLEAR_ROCKS:  cost += _price.clear_2; break;
+						default: break;
+					}
+
+					if (flags & DC_EXEC) {
+						TreeType treetype;
+						uint growth;
+
+						if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) {
+							Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
+							if (t != NULL)
+								ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
+						}
+
+						treetype = p1;
+						if (treetype == TREE_INVALID) {
+							treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
+							if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
+						}
+
+						growth = _game_mode == GM_EDITOR ? 3 : 0;
+						switch (GetClearGround(tile)) {
+							case CLEAR_ROUGH: MakeTree(tile, treetype, 0, growth, TREE_GROUND_ROUGH, 0); break;
+							case CLEAR_SNOW:  MakeTree(tile, treetype, 0, growth, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
+							default:          MakeTree(tile, treetype, 0, growth, TREE_GROUND_GRASS, 0); break;
+						}
+						MarkTileDirtyByTile(tile);
+
+						if (_game_mode == GM_EDITOR && IS_INT_INSIDE(treetype, TREE_RAINFOREST, TREE_CACTUS))
+							SetTropicZone(tile, TROPICZONE_RAINFOREST);
+					}
+					cost += _price.build_trees;
+					break;
+
+				default:
+					msg = STR_2804_SITE_UNSUITABLE;
+					break;
+			}
+		}
+	}
+
+	if (cost == 0) {
+		return_cmd_error(msg);
+	} else {
+		return cost;
+	}
+}
+
+typedef struct TreeListEnt {
+	uint32 image;
+	byte x,y;
+} TreeListEnt;
+
+static void DrawTile_Trees(TileInfo *ti)
+{
+	const uint32 *s;
+	const TreePos* d;
+	byte z;
+
+	switch (GetTreeGround(ti->tile)) {
+		case TREE_GROUND_GRASS: DrawClearLandTile(ti, 3); break;
+		case TREE_GROUND_ROUGH: DrawHillyLandTile(ti); break;
+		default: DrawGroundSprite(_tree_sprites_1[GetTreeDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]); break;
+	}
+
+	DrawClearLandFence(ti);
+
+	z = ti->z;
+	if (ti->tileh != SLOPE_FLAT) {
+		z += 4;
+		if (IsSteepSlope(ti->tileh)) z += 4;
+	}
+
+	{
+		uint16 tmp = ti->x;
+		uint index;
+
+		tmp = ROR(tmp, 2);
+		tmp -= ti->y;
+		tmp = ROR(tmp, 3);
+		tmp -= ti->x;
+		tmp = ROR(tmp, 1);
+		tmp += ti->y;
+
+		d = _tree_layout_xy[GB(tmp, 4, 2)];
+
+		index = GB(tmp, 6, 2) + (GetTreeType(ti->tile) << 2);
+
+		/* different tree styles above one of the grounds */
+		if (GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT &&
+				GetTreeDensity(ti->tile) >= 2 &&
+				IS_INT_INSIDE(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) {
+			index += 164 - (TREE_SUB_ARCTIC << 2);
+		}
+
+		assert(index < lengthof(_tree_layout_sprite));
+		s = _tree_layout_sprite[index];
+	}
+
+	StartSpriteCombine();
+
+	if (!(_display_opt & DO_TRANS_BUILDINGS) || !_patches.invisible_trees) {
+		TreeListEnt te[4];
+		uint i;
+
+		/* put the trees to draw in a list */
+		i = GetTreeCount(ti->tile) + 1;
+		do {
+			uint32 image = s[0] + (--i == 0 ? GetTreeGrowth(ti->tile) : 3);
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+			te[i].image = image;
+			te[i].x = d->x;
+			te[i].y = d->y;
+			s++;
+			d++;
+		} while (i);
+
+		/* draw them in a sorted way */
+		for (;;) {
+			byte min = 0xFF;
+			TreeListEnt *tep = NULL;
+
+			i = GetTreeCount(ti->tile) + 1;
+			do {
+				if (te[--i].image != 0 && te[i].x + te[i].y < min) {
+					min = te[i].x + te[i].y;
+					tep = &te[i];
+				}
+			} while (i);
+
+			if (tep == NULL) break;
+
+			AddSortableSpriteToDraw(tep->image, ti->x + tep->x, ti->y + tep->y, 5, 5, 0x10, z);
+			tep->image = 0;
+		}
+	}
+
+	EndSpriteCombine();
+}
+
+
+static uint GetSlopeZ_Trees(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	uint tileh = GetTileSlope(tile, &z);
+
+	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+}
+
+static Slope GetSlopeTileh_Trees(TileIndex tile, Slope tileh)
+{
+	return tileh;
+}
+
+static int32 ClearTile_Trees(TileIndex tile, byte flags)
+{
+	uint num;
+
+	if ((flags & DC_EXEC) && IsValidPlayer(_current_player)) {
+		Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
+		if (t != NULL)
+			ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM);
+	}
+
+	num = GetTreeCount(tile) + 1;
+	if (IS_INT_INSIDE(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4;
+
+	if (flags & DC_EXEC) DoClearSquare(tile);
+
+	return num * _price.remove_trees;
+}
+
+static void GetAcceptedCargo_Trees(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void GetTileDesc_Trees(TileIndex tile, TileDesc *td)
+{
+	TreeType tt = GetTreeType(tile);
+
+	if (IS_INT_INSIDE(tt, TREE_RAINFOREST, TREE_CACTUS)) {
+		td->str = STR_280F_RAINFOREST;
+	} else if (tt == TREE_CACTUS) {
+		td->str = STR_2810_CACTUS_PLANTS;
+	} else {
+		td->str = STR_280E_TREES;
+	}
+
+	td->owner = GetTileOwner(tile);
+}
+
+static void AnimateTile_Trees(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoopTreesDesert(TileIndex tile)
+{
+	switch (GetTropicZone(tile)) {
+		case TROPICZONE_DESERT:
+			if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) {
+				SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		case TROPICZONE_RAINFOREST: {
+			static const SoundFx forest_sounds[] = {
+				SND_42_LOON_BIRD,
+				SND_43_LION,
+				SND_44_MONKEYS,
+				SND_48_DISTANT_BIRD
+			};
+			uint32 r = Random();
+
+			if (CHANCE16I(1, 200, r)) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
+			break;
+		}
+
+		default: break;
+	}
+}
+
+static void TileLoopTreesAlps(TileIndex tile)
+{
+	int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
+
+	if (k < 0) {
+		if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) return;
+		SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 0);
+	} else {
+		uint density = min((uint)k / TILE_HEIGHT, 3);
+
+		if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT ||
+				GetTreeDensity(tile) != density) {
+			SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, density);
+		} else {
+			if (GetTreeDensity(tile) == 3) {
+				uint32 r = Random();
+				if (CHANCE16I(1, 200, r)) {
+					SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile);
+				}
+			}
+			return;
+		}
+	}
+	MarkTileDirtyByTile(tile);
+}
+
+static void TileLoop_Trees(TileIndex tile)
+{
+	switch (_opt.landscape) {
+		case LT_DESERT: TileLoopTreesDesert(tile); break;
+		case LT_HILLY:  TileLoopTreesAlps(tile);   break;
+	}
+
+	TileLoopClearHelper(tile);
+
+	if (GetTreeCounter(tile) < 15) {
+		AddTreeCounter(tile, 1);
+		return;
+	}
+	SetTreeCounter(tile, 0);
+
+	switch (GetTreeGrowth(tile)) {
+		case 3: /* regular sized tree */
+			if (_opt.landscape == LT_DESERT &&
+					GetTreeType(tile) != TREE_CACTUS &&
+					GetTropicZone(tile) == TROPICZONE_DESERT) {
+				AddTreeGrowth(tile, 1);
+			} else {
+				switch (GB(Random(), 0, 3)) {
+					case 0: /* start destructing */
+						AddTreeGrowth(tile, 1);
+						break;
+
+					case 1: /* add a tree */
+						if (GetTreeCount(tile) < 3) {
+							AddTreeCount(tile, 1);
+							SetTreeGrowth(tile, 0);
+							break;
+						}
+						/* FALL THROUGH */
+
+					case 2: { /* add a neighbouring tree */
+						TreeType treetype = GetTreeType(tile);
+
+						tile += TileOffsByDir(Random() & 7);
+
+						if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return;
+
+						switch (GetClearGround(tile)) {
+							case CLEAR_GRASS:
+								if (GetClearDensity(tile) != 3) return;
+								MakeTree(tile, treetype, 0, 0, TREE_GROUND_GRASS, 0);
+								break;
+
+							case CLEAR_ROUGH: MakeTree(tile, treetype, 0, 0, TREE_GROUND_ROUGH, 0); break;
+							case CLEAR_SNOW:  MakeTree(tile, treetype, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
+							default: return;
+						}
+						break;
+					}
+
+					default:
+						return;
+				}
+			}
+			break;
+
+		case 6: /* final stage of tree destruction */
+			if (GetTreeCount(tile) > 0) {
+				/* more than one tree, delete it */
+				AddTreeCount(tile, -1);
+				SetTreeGrowth(tile, 3);
+			} else {
+				/* just one tree, change type into MP_CLEAR */
+				switch (GetTreeGround(tile)) {
+					case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, 3); break;
+					case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
+					default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break;
+				}
+			}
+			break;
+
+		default:
+			AddTreeGrowth(tile, 1);
+			break;
+	}
+
+	MarkTileDirtyByTile(tile);
+}
+
+void OnTick_Trees(void)
+{
+	uint32 r;
+	TileIndex tile;
+	ClearGround ct;
+	TreeType tree;
+
+	/* place a tree at a random rainforest spot */
+	if (_opt.landscape == LT_DESERT &&
+			(r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
+			IsTileType(tile, MP_CLEAR) &&
+			!IsBridgeAbove(tile) &&
+			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) &&
+			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
+		MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0);
+	}
+
+	// byte underflow
+	if (--_trees_tick_ctr != 0) return;
+
+	/* place a tree at a random spot */
+	r = Random();
+	tile = TILE_MASK(r);
+	if (IsTileType(tile, MP_CLEAR) &&
+			!IsBridgeAbove(tile) &&
+			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) &&
+			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
+		switch (ct) {
+			case CLEAR_GRASS: MakeTree(tile, tree, 0, 0, TREE_GROUND_GRASS, 0); break;
+			case CLEAR_ROUGH: MakeTree(tile, tree, 0, 0, TREE_GROUND_ROUGH, 0); break;
+			default: MakeTree(tile, tree, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break;
+		}
+	}
+}
+
+static void ClickTile_Trees(TileIndex tile)
+{
+	/* not used */
+}
+
+static uint32 GetTileTrackStatus_Trees(TileIndex tile, TransportType mode)
+{
+	return 0;
+}
+
+static void ChangeTileOwner_Trees(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	/* not used */
+}
+
+void InitializeTrees(void)
+{
+	_trees_tick_ctr = 0;
+}
+
+
+const TileTypeProcs _tile_type_trees_procs = {
+	DrawTile_Trees,           /* draw_tile_proc */
+	GetSlopeZ_Trees,          /* get_slope_z_proc */
+	ClearTile_Trees,          /* clear_tile_proc */
+	GetAcceptedCargo_Trees,   /* get_accepted_cargo_proc */
+	GetTileDesc_Trees,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Trees, /* get_tile_track_status_proc */
+	ClickTile_Trees,          /* click_tile_proc */
+	AnimateTile_Trees,        /* animate_tile_proc */
+	TileLoop_Trees,           /* tile_loop_clear */
+	ChangeTileOwner_Trees,    /* change_tile_owner_clear */
+	NULL,                     /* get_produced_cargo_proc */
+	NULL,                     /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Trees,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/tunnel_map.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "tile.h"
-#include "tunnel_map.h"
-
-TileIndex GetOtherTunnelEnd(TileIndex tile)
-{
-	DiagDirection dir = GetTunnelDirection(tile);
-	TileIndexDiff delta = TileOffsByDiagDir(dir);
-	uint z = GetTileZ(tile);
-
-	dir = ReverseDiagDir(dir);
-	do {
-		tile += delta;
-	} while (
-		!IsTunnelTile(tile) ||
-		GetTunnelDirection(tile) != dir ||
-		GetTileZ(tile) != z
-	);
-
-	return tile;
-}
-
-
-static bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir)
-{
-	TileIndexDiff delta = TileOffsByDiagDir(dir);
-	uint height;
-
-	do {
-		tile -= delta;
-		height = GetTileZ(tile);
-	} while (z < height);
-
-	return
-		z == height &&
-		IsTunnelTile(tile) &&
-		GetTunnelDirection(tile) == dir;
-}
-
-bool IsTunnelInWay(TileIndex tile, uint z)
-{
-	return
-		IsTunnelInWayDir(tile, z, DIAGDIR_NE) ||
-		IsTunnelInWayDir(tile, z, DIAGDIR_SE) ||
-		IsTunnelInWayDir(tile, z, DIAGDIR_SW) ||
-		IsTunnelInWayDir(tile, z, DIAGDIR_NW);
-}
new file mode 100644
--- /dev/null
+++ b/src/tunnel_map.cpp
@@ -0,0 +1,50 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "tile.h"
+#include "tunnel_map.h"
+
+TileIndex GetOtherTunnelEnd(TileIndex tile)
+{
+	DiagDirection dir = GetTunnelDirection(tile);
+	TileIndexDiff delta = TileOffsByDiagDir(dir);
+	uint z = GetTileZ(tile);
+
+	dir = ReverseDiagDir(dir);
+	do {
+		tile += delta;
+	} while (
+		!IsTunnelTile(tile) ||
+		GetTunnelDirection(tile) != dir ||
+		GetTileZ(tile) != z
+	);
+
+	return tile;
+}
+
+
+static bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir)
+{
+	TileIndexDiff delta = TileOffsByDiagDir(dir);
+	uint height;
+
+	do {
+		tile -= delta;
+		height = GetTileZ(tile);
+	} while (z < height);
+
+	return
+		z == height &&
+		IsTunnelTile(tile) &&
+		GetTunnelDirection(tile) == dir;
+}
+
+bool IsTunnelInWay(TileIndex tile, uint z)
+{
+	return
+		IsTunnelInWayDir(tile, z, DIAGDIR_NE) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_SE) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_SW) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_NW);
+}
deleted file mode 100644
--- a/src/tunnelbridge_cmd.c
+++ /dev/null
@@ -1,1316 +0,0 @@
-/* $Id$ */
-
-/** @file tunnelbridge_cmd.c
- * This file deals with tunnels and bridges (non-gui stuff)
- * @todo seperate this file into two
- */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "rail_map.h"
-#include "road_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "tunnel_map.h"
-#include "unmovable_map.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
-#include "player.h"
-#include "town.h"
-#include "sound.h"
-#include "variables.h"
-#include "bridge.h"
-#include "train.h"
-#include "water_map.h"
-#include "yapf/yapf.h"
-#include "date.h"
-#include "newgrf_sound.h"
-
-#include "table/bridge_land.h"
-
-const Bridge orig_bridge[] = {
-/*
-	     year of availablity
-	     |  minimum length
-	     |  |   maximum length
-	     |  |   |    price
-	     |  |   |    |    maximum speed
-	     |  |   |    |    |  sprite to use in GUI                string with description
-	     |  |   |    |    |  |                                   |                            */
-	{    0, 0, 16,  80,  32, 0xA24                             , STR_5012_WOODEN             , NULL, 0 },
-	{    0, 0,  2, 112,  48, 0xA26 | PALETTE_TO_STRUCT_RED     , STR_5013_CONCRETE           , NULL, 0 },
-	{ 1930, 0,  5, 144,  64, 0xA25                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
-	{    0, 2, 10, 168,  80, 0xA22 | PALETTE_TO_STRUCT_CONCRETE, STR_5011_SUSPENSION_CONCRETE, NULL, 0 },
-	{ 1930, 3, 16, 185,  96, 0xA22                             , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
-	{ 1930, 3, 16, 192, 112, 0xA22 | PALETTE_TO_STRUCT_YELLOW  , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
-	{ 1930, 3,  7, 224, 160, 0xA23                             , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
-	{ 1930, 3,  8, 232, 208, 0xA23 | PALETTE_TO_STRUCT_BROWN   , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
-	{ 1930, 3,  9, 248, 240, 0xA23 | PALETTE_TO_STRUCT_RED     , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
-	{ 1930, 0,  2, 240, 256, 0xA27                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
-	{ 1995, 2, 16, 255, 320, 0xA28                             , STR_5014_TUBULAR_STEEL      , NULL, 0 },
-	{ 2005, 2, 32, 380, 512, 0xA28 | PALETTE_TO_STRUCT_YELLOW  , STR_5014_TUBULAR_STEEL      , NULL, 0 },
-	{ 2010, 2, 32, 510, 608, 0xA28 | PALETTE_TO_STRUCT_GREY    , STR_BRIDGE_TUBULAR_SILICON  , NULL, 0 }
-};
-
-Bridge _bridge[MAX_BRIDGES];
-
-
-// calculate the price factor for building a long bridge.
-// basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6,  7,7,7,7,7,7,7,  8,8,8,8,8,8,8,8,
-int CalcBridgeLenCostFactor(int x)
-{
-	int n;
-	int r;
-
-	if (x < 2) return x;
-	x -= 2;
-	for (n = 0, r = 2;; n++) {
-		if (x <= n) return r + x * n;
-		r += n * n;
-		x -= n;
-	}
-}
-
-#define M(x) (1 << (x))
-enum {
-	// foundation, whole tile is leveled up --> 3 corners raised
-	BRIDGE_FULL_LEVELED_FOUNDATION = M(SLOPE_WSE) | M(SLOPE_NWS) | M(SLOPE_ENW) | M(SLOPE_SEN),
-	// foundation, tile is partly leveled up --> 1 corner raised
-	BRIDGE_PARTLY_LEVELED_FOUNDATION = M(SLOPE_W) | M(SLOPE_S) | M(SLOPE_E) | M(SLOPE_N),
-	// no foundations (X,Y direction)
-	BRIDGE_NO_FOUNDATION = M(SLOPE_FLAT) | M(SLOPE_SW) | M(SLOPE_SE) | M(SLOPE_NW) | M(SLOPE_NE),
-	BRIDGE_HORZ_RAMP = (BRIDGE_PARTLY_LEVELED_FOUNDATION | BRIDGE_NO_FOUNDATION) & ~M(SLOPE_FLAT)
-};
-#undef M
-
-static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
-{
-	const Bridge *bridge = &_bridge[index];
-	assert(table < 7);
-	if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
-		return _bridge_sprite_table[index][table];
-	} else {
-		return bridge->sprite_table[table];
-	}
-}
-
-static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;}
-
-
-/** Check the slope at the bridge ramps in three easy steps:
- * - valid slopes without foundation
- * - valid slopes with foundation
- * - rest is invalid
- */
-#define M(x) (1 << (x))
-static int32 CheckBridgeSlopeNorth(Axis axis, Slope tileh)
-{
-	uint32 valid;
-
-	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW));
-	if (HASBIT(valid, tileh)) return 0;
-
-	valid =
-		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) |
-		(axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W));
-	if (HASBIT(valid, tileh)) return _price.terraform;
-
-	return CMD_ERROR;
-}
-
-static int32 CheckBridgeSlopeSouth(Axis axis, Slope tileh)
-{
-	uint32 valid;
-
-	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_SW) : M(SLOPE_SE));
-	if (HASBIT(valid, tileh)) return 0;
-
-	valid =
-		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_S) | M(SLOPE_STEEP_S) |
-		(axis == AXIS_X ? M(SLOPE_W) | M(SLOPE_STEEP_W) : M(SLOPE_E) | M(SLOPE_STEEP_E));
-	if (HASBIT(valid, tileh)) return _price.terraform;
-
-	return CMD_ERROR;
-}
-#undef M
-
-
-uint32 GetBridgeLength(TileIndex begin, TileIndex end)
-{
-	int x1 = TileX(begin);
-	int y1 = TileY(begin);
-	int x2 = TileX(end);
-	int y2 = TileY(end);
-
-	return abs(x2 + y2 - x1 - y1) - 1;
-}
-
-bool CheckBridge_Stuff(byte bridge_type, uint bridge_len)
-{
-	const Bridge *b = &_bridge[bridge_type];
-	uint max; // max possible length of a bridge (with patch 100)
-
-	if (bridge_type >= MAX_BRIDGES) return false;
-	if (b->avail_year > _cur_year) return false;
-
-	max = b->max_length;
-	if (max >= 16 && _patches.longbridges) max = 100;
-
-	return b->min_length <= bridge_len && bridge_len <= max;
-}
-
-/** Build a Bridge
- * @param end_tile end tile
- * @param p1 packed start tile coords (~ dx)
- * @param p2 various bitstuffed elements
- * - p2 = (bit 0- 7) - bridge type (hi bh)
- * - p2 = (bit 8-..) - rail type. bit15 ((x>>8)&0x80) means road bridge.
- */
-int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int bridge_type;
-	TransportType transport;
-	RailType railtype;
-	uint x;
-	uint y;
-	uint sx;
-	uint sy;
-	TileIndex tile_start;
-	TileIndex tile_end;
-	Slope tileh_start;
-	Slope tileh_end;
-	uint z_start;
-	uint z_end;
-	TileIndex tile;
-	TileIndexDiff delta;
-	uint bridge_len;
-	Axis direction;
-	int32 cost, terraformcost, ret;
-	bool allow_on_slopes;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* unpack parameters */
-	bridge_type = GB(p2, 0, 8);
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	// type of bridge
-	if (HASBIT(p2, 15)) {
-		railtype = 0;
-		transport = TRANSPORT_ROAD;
-	} else {
-		if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR;
-		railtype = GB(p2, 8, 8);
-		transport = TRANSPORT_RAIL;
-	}
-
-	x = TileX(end_tile);
-	y = TileY(end_tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
-
-	/* check if valid, and make sure that (x,y) are smaller than (sx,sy) */
-	if (x == sx) {
-		if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
-		direction = AXIS_Y;
-		if (y > sy) uintswap(y,sy);
-	} else if (y == sy) {
-		direction = AXIS_X;
-		if (x > sx) uintswap(x,sx);
-	} else {
-		return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
-	}
-
-	/* set and test bridge length, availability */
-	bridge_len = sx + sy - x - y - 1;
-	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
-
-	/* retrieve landscape height and ensure it's on land */
-	tile_start = TileXY(x, y);
-	tile_end = TileXY(sx, sy);
-	if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) {
-		return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
-	}
-
-	tileh_start = GetTileSlope(tile_start, &z_start);
-	tileh_end = GetTileSlope(tile_end, &z_end);
-
-	if (IsSteepSlope(tileh_start)) z_start += TILE_HEIGHT;
-	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) {
-		z_start += TILE_HEIGHT;
-		tileh_start = SLOPE_FLAT;
-	}
-
-	if (IsSteepSlope(tileh_end)) z_end += TILE_HEIGHT;
-	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) {
-		z_end += TILE_HEIGHT;
-		tileh_end = SLOPE_FLAT;
-	}
-
-	if (z_start != z_end) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
-
-	// Towns are not allowed to use bridges on slopes.
-	allow_on_slopes = (!_is_old_ai_player
-	                   && _current_player != OWNER_TOWN && _patches.build_on_slopes);
-
-	/* Try and clear the start landscape */
-
-	ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return ret;
-	cost = ret;
-
-	terraformcost = CheckBridgeSlopeNorth(direction, tileh_start);
-	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
-		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	cost += terraformcost;
-
-	/* Try and clear the end landscape */
-
-	ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return ret;
-	cost += ret;
-
-	// false - end tile slope check
-	terraformcost = CheckBridgeSlopeSouth(direction, tileh_end);
-	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
-		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	cost += terraformcost;
-
-	{
-		TileIndex Heads[] = {tile_start, tile_end};
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			if (MayHaveBridgeAbove(Heads[i])) {
-				if (IsBridgeAbove(Heads[i])) {
-					TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
-
-					if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-					if (z_start + TILE_HEIGHT == GetBridgeHeight(north_head)) {
-						return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-					}
-				}
-			}
-		}
-	}
-
-	/* do the drill? */
-	if (flags & DC_EXEC) {
-		DiagDirection dir = AxisToDiagDir(direction);
-
-		if (transport == TRANSPORT_RAIL) {
-			MakeRailBridgeRamp(tile_start, _current_player, bridge_type, dir, railtype);
-			MakeRailBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir), railtype);
-		} else {
-			MakeRoadBridgeRamp(tile_start, _current_player, bridge_type, dir);
-			MakeRoadBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir));
-		}
-		MarkTileDirtyByTile(tile_start);
-		MarkTileDirtyByTile(tile_end);
-	}
-
-	delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
-	for (tile = tile_start + delta; tile != tile_end; tile += delta) {
-		uint z;
-
-		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
-
-		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
-			/* Disallow crossing bridges for the time being */
-			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-		}
-
-		switch (GetTileType(tile)) {
-			case MP_WATER:
-				if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
-				if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
-				break;
-
-			case MP_RAILWAY:
-				if (!IsPlainRailTile(tile)) goto not_valid_below;
-				break;
-
-			case MP_STREET:
-				if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) goto not_valid_below;
-				break;
-
-			case MP_TUNNELBRIDGE:
-				if (IsTunnel(tile)) break;
-				if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below;
-				if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
-				break;
-
-			case MP_UNMOVABLE:
-				if (!IsOwnedLand(tile)) goto not_valid_below;
-				break;
-
-			case MP_CLEAR:
-				if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-				break;
-
-			default:
-not_valid_below:;
-				/* try and clear the middle landscape */
-				ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-				if (CmdFailed(ret)) return ret;
-				cost += ret;
-				break;
-		}
-
-		if (flags & DC_EXEC) {
-			SetBridgeMiddle(tile, direction);
-			MarkTileDirtyByTile(tile);
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		Track track = AxisToTrack(direction);
-		SetSignalsOnBothDir(tile_start, track);
-		YapfNotifyTrackLayoutChange(tile_start, track);
-	}
-
-	/* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
-	 * It's unnecessary to execute this command every time for every bridge. So it is done only
-	 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
-	 */
-	if (!(flags & DC_QUERY_COST)) {
-		const Bridge *b = &_bridge[bridge_type];
-
-		bridge_len += 2; // begin and end tiles/ramps
-
-		if (IsValidPlayer(_current_player) && !_is_old_ai_player)
-			bridge_len = CalcBridgeLenCostFactor(bridge_len);
-
-		cost += (int64)bridge_len * _price.build_bridge * b->price >> 8;
-	}
-
-	return cost;
-}
-
-
-/** Build Tunnel.
- * @param tile start tile of tunnel
- * @param p1 railtype, 0x200 for road tunnel
- * @param p2 unused
- */
-int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TileIndexDiff delta;
-	TileIndex end_tile;
-	DiagDirection direction;
-	Slope start_tileh;
-	Slope end_tileh;
-	uint start_z;
-	uint end_z;
-	int32 cost;
-	int32 ret;
-
-	_build_tunnel_endtile = 0;
-
-	if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR;
-
-	start_tileh = GetTileSlope(start_tile, &start_z);
-
-	switch (start_tileh) {
-		case SLOPE_SW: direction = DIAGDIR_SW; break;
-		case SLOPE_SE: direction = DIAGDIR_SE; break;
-		case SLOPE_NW: direction = DIAGDIR_NW; break;
-		case SLOPE_NE: direction = DIAGDIR_NE; break;
-		default: return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
-	}
-
-	ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return ret;
-
-	/* XXX - do NOT change 'ret' in the loop, as it is used as the price
-	 * for the clearing of the entrance of the tunnel. Assigning it to
-	 * cost before the loop will yield different costs depending on start-
-	 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
-	cost = 0;
-	delta = TileOffsByDiagDir(direction);
-	end_tile = start_tile;
-	for (;;) {
-		end_tile += delta;
-		end_tileh = GetTileSlope(end_tile, &end_z);
-
-		if (start_z == end_z) break;
-
-		if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z)) {
-			return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
-		}
-
-		cost += _price.build_tunnel;
-		cost += cost >> 3; // add a multiplier for longer tunnels
-		if (cost >= 400000000) cost = 400000000;
-	}
-
-	/* Add the cost of the entrance */
-	cost += _price.build_tunnel + ret;
-
-	// if the command fails from here on we want the end tile to be highlighted
-	_build_tunnel_endtile = end_tile;
-
-	// slope of end tile must be complementary to the slope of the start tile
-	if (end_tileh != ComplementSlope(start_tileh)) {
-		ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
-		if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
-	} else {
-		ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-		if (CmdFailed(ret)) return ret;
-	}
-	cost += _price.build_tunnel + ret;
-
-	if (flags & DC_EXEC) {
-		if (GB(p1, 9, 1) == TRANSPORT_RAIL) {
-			MakeRailTunnel(start_tile, _current_player, direction,                 GB(p1, 0, 4));
-			MakeRailTunnel(end_tile,   _current_player, ReverseDiagDir(direction), GB(p1, 0, 4));
-			UpdateSignalsOnSegment(start_tile, direction);
-			YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
-		} else {
-			MakeRoadTunnel(start_tile, _current_player, direction);
-			MakeRoadTunnel(end_tile,   _current_player, ReverseDiagDir(direction));
-		}
-	}
-
-	return cost;
-}
-
-TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
-{
-	uint z = GetTileZ(tile);
-	DiagDirection dir = GetTunnelDirection(tile);
-	TileIndexDiff delta = TileOffsByDiagDir(dir);
-	uint len = 0;
-	TileIndex starttile = tile;
-	Vehicle *v;
-
-	do {
-		tile += delta;
-		len++;
-	} while (
-		!IsTunnelTile(tile) ||
-		ReverseDiagDir(GetTunnelDirection(tile)) != dir ||
-		GetTileZ(tile) != z
-	);
-
-	v = FindVehicleBetween(starttile, tile, z);
-	if (v != NULL) {
-		_error_message = v->type == VEH_Train ?
-			STR_5000_TRAIN_IN_TUNNEL : STR_5001_ROAD_VEHICLE_IN_TUNNEL;
-		return INVALID_TILE;
-	}
-
-	if (length != NULL) *length = len;
-	return tile;
-}
-
-static inline bool CheckAllowRemoveTunnelBridge(TileIndex tile)
-{
-	/* Floods can remove anything as well as the scenario editor */
-	if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true;
-	/* Obviously if the bridge/tunnel belongs to us, or no-one, we can remove it */
-	if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true;
-	/* Otherwise we can only remove town-owned stuff with extra patch-settings, or cheat */
-	if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true;
-	return false;
-}
-
-static int32 DoClearTunnel(TileIndex tile, uint32 flags)
-{
-	Town *t = NULL;
-	TileIndex endtile;
-	uint length;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
-
-	endtile = CheckTunnelBusy(tile, &length);
-	if (endtile == INVALID_TILE) return CMD_ERROR;
-
-	_build_tunnel_endtile = endtile;
-
-	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
-		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
-
-		/* Check if you are allowed to remove the tunnel owned by a town
-		 * Removal depends on difficulty settings */
-		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
-			SetDParam(0, t->index);
-			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		// We first need to request the direction before calling DoClearSquare
-		//  else the direction is always 0.. dah!! ;)
-		DiagDirection dir = GetTunnelDirection(tile);
-		Track track;
-
-		// Adjust the town's player rating. Do this before removing the tile owner info.
-		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
-			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
-
-		DoClearSquare(tile);
-		DoClearSquare(endtile);
-		UpdateSignalsOnSegment(tile, ReverseDiagDir(dir));
-		UpdateSignalsOnSegment(endtile, dir);
-		track = AxisToTrack(DiagDirToAxis(dir));
-		YapfNotifyTrackLayoutChange(tile, track);
-		YapfNotifyTrackLayoutChange(endtile, track);
-	}
-	return _price.clear_tunnel * (length + 1);
-}
-
-
-static bool IsVehicleOnBridge(TileIndex starttile, TileIndex endtile, uint z)
-{
-	const Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if ((v->tile == starttile || v->tile == endtile) && v->z_pos == z) {
-			_error_message = VehicleInTheWayErrMsg(v);
-			return true;
-		}
-	}
-	return false;
-}
-
-static int32 DoClearBridge(TileIndex tile, uint32 flags)
-{
-	DiagDirection direction;
-	TileIndexDiff delta;
-	TileIndex endtile;
-	Town *t = NULL;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
-
-	endtile = GetOtherBridgeEnd(tile);
-
-	if (!EnsureNoVehicle(tile) ||
-			!EnsureNoVehicle(endtile) ||
-			IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
-		return CMD_ERROR;
-	}
-
-	direction = GetBridgeRampDirection(tile);
-	delta = TileOffsByDiagDir(direction);
-
-	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
-		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
-
-		/* Check if you are allowed to remove the bridge owned by a town
-		 * Removal depends on difficulty settings */
-		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
-			SetDParam(0, t->index);
-			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		TileIndex c;
-		Track track;
-
-		//checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
-		// you have a "Poor" (0) town rating
-		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
-			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
-
-		DoClearSquare(tile);
-		DoClearSquare(endtile);
-		for (c = tile + delta; c != endtile; c += delta) {
-				ClearBridgeMiddle(c);
-			MarkTileDirtyByTile(c);
-		}
-
-		UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
-		UpdateSignalsOnSegment(endtile, direction);
-		track = AxisToTrack(DiagDirToAxis(direction));
-		YapfNotifyTrackLayoutChange(tile, track);
-		YapfNotifyTrackLayoutChange(endtile, track);
-	}
-
-	return (DistanceManhattan(tile, endtile) + 1) * _price.clear_bridge;
-}
-
-static int32 ClearTile_TunnelBridge(TileIndex tile, byte flags)
-{
-	if (IsTunnel(tile)) {
-		if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
-		return DoClearTunnel(tile, flags);
-	} else if (IsBridge(tile)) { // XXX Is this necessary?
-		if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-		return DoClearBridge(tile, flags);
-	}
-
-	return CMD_ERROR;
-}
-
-int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
-{
-	TileIndex endtile;
-
-	if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
-		uint length;
-
-		if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-		if (GetRailType(tile) == totype) return CMD_ERROR;
-
-		// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
-		if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
-
-		endtile = CheckTunnelBusy(tile, &length);
-		if (endtile == INVALID_TILE) return CMD_ERROR;
-
-		if (exec) {
-			Track track;
-			SetRailType(tile, totype);
-			SetRailType(endtile, totype);
-			MarkTileDirtyByTile(tile);
-			MarkTileDirtyByTile(endtile);
-
-			track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile)));
-			YapfNotifyTrackLayoutChange(tile, track);
-			YapfNotifyTrackLayoutChange(endtile, track);
-		}
-		return (length + 1) * (_price.build_rail >> 1);
-	} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
-
-		if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-		endtile = GetOtherBridgeEnd(tile);
-
-		if (!EnsureNoVehicle(tile) ||
-				!EnsureNoVehicle(endtile) ||
-				IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
-			return CMD_ERROR;
-		}
-
-		if (GetRailType(tile) == totype) return CMD_ERROR;
-
-		if (exec) {
-			TileIndexDiff delta;
-			Track track;
-
-			SetRailType(tile, totype);
-			SetRailType(endtile, totype);
-			MarkTileDirtyByTile(tile);
-			MarkTileDirtyByTile(endtile);
-
-			track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile)));
-			YapfNotifyTrackLayoutChange(tile, track);
-			YapfNotifyTrackLayoutChange(endtile, track);
-
-			delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
-			for (tile += delta; tile != endtile; tile += delta) {
-				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
-			}
-		}
-
-		return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
-	} else {
-		return CMD_ERROR;
-	}
-}
-
-
-static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
-{
-	if (image != 0) {
-		bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
-		int back_height, front_height;
-		int i = z;
-		const byte *p;
-
-		static const byte _tileh_bits[4][8] = {
-			{ 2, 1, 8, 4,  16,  2, 0, 9 },
-			{ 1, 8, 4, 2,   2, 16, 9, 0 },
-			{ 4, 8, 1, 2,  16,  2, 0, 9 },
-			{ 2, 4, 8, 1,   2, 16, 9, 0 }
-		};
-
-		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-		p = _tileh_bits[(image & 1) * 2 + (axis == AXIS_X ? 0 : 1)];
-		front_height = ti->z + (ti->tileh & p[0] ? TILE_HEIGHT : 0);
-		back_height  = ti->z + (ti->tileh & p[1] ? TILE_HEIGHT : 0);
-
-		if (IsSteepSlope(ti->tileh)) {
-			if (!(ti->tileh & p[2])) front_height += TILE_HEIGHT;
-			if (!(ti->tileh & p[3])) back_height  += TILE_HEIGHT;
-		}
-
-		for (; z >= front_height || z >= back_height; z -= TILE_HEIGHT) {
-			/* HACK set height of the BB of pillars to 1, because the origin of the
-			 * sprites is at the top
-			 */
-			if (z >= front_height) { // front facing pillar
-				AddSortableSpriteToDraw(image, x, y, p[4], p[5], 1, z);
-			}
-
-			if (drawfarpillar && z >= back_height && z < i - TILE_HEIGHT) { // back facing pillar
-				AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 1, z);
-			}
-		}
-	}
-}
-
-uint GetBridgeFoundation(Slope tileh, Axis axis)
-{
-	uint i;
-
-	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) return tileh;
-
-	// inclined sloped building
-	switch (tileh) {
-		case SLOPE_W:
-		case SLOPE_STEEP_W: i = 0; break;
-		case SLOPE_S:
-		case SLOPE_STEEP_S: i = 2; break;
-		case SLOPE_E:
-		case SLOPE_STEEP_E: i = 4; break;
-		case SLOPE_N:
-		case SLOPE_STEEP_N: i = 6; break;
-		default: return 0;
-	}
-	if (axis != AXIS_X) ++i;
-	return i + 15;
-}
-
-/**
- * Draws a tunnel of bridge tile.
- * For tunnels, this is rather simple, as you only needa draw the entrance.
- * Bridges are a bit more complex. base_offset is where the sprite selection comes into play
- * and it works a bit like a bitmask.<p> For bridge heads:
- * <ul><li>Bit 0: direction</li>
- * <li>Bit 1: northern or southern heads</li>
- * <li>Bit 2: Set if the bridge head is sloped</li>
- * <li>Bit 3 and more: Railtype Specific subset</li>
- * </ul>
- * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
- */
-static void DrawTile_TunnelBridge(TileInfo *ti)
-{
-	uint32 image;
-
-	if (IsTunnel(ti->tile)) {
-		if (GetTunnelTransportType(ti->tile) == TRANSPORT_RAIL) {
-			image = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.tunnel;
-		} else {
-			image = SPR_TUNNEL_ENTRY_REAR_ROAD;
-		}
-
-		if (HasTunnelSnowOrDesert(ti->tile)) image += 32;
-
-		image += GetTunnelDirection(ti->tile) * 2;
-		DrawGroundSprite(image);
-		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-		AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z);
-		DrawBridgeMiddle(ti);
-	} else if (IsBridge(ti->tile)) { // XXX is this necessary?
-		int base_offset;
-		bool ice = HasBridgeSnowOrDesert(ti->tile);
-
-		if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) {
-			base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
-			assert(base_offset != 8); /* This one is used for roads */
-		} else {
-			base_offset = 8;
-		}
-
-		/* as the lower 3 bits are used for other stuff, make sure they are clear */
-		assert( (base_offset & 0x07) == 0x00);
-
-		if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
-			int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
-			if (f != 0) DrawFoundation(ti, f);
-		}
-
-		// HACK Wizardry to convert the bridge ramp direction into a sprite offset
-		base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
-
-		if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
-
-		/* Table number 6 always refers to the bridge heads for any bridge type */
-		image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
-
-		if (!ice) {
-			DrawClearLandTile(ti, 3);
-		} else {
-			DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
-		}
-
-		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-		// draw ramp
-		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-		/* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
-		 * it doesn't disappear behind it
-		 */
-		AddSortableSpriteToDraw(
-			image, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 1 : 8, ti->z
-		);
-
-		DrawBridgeMiddle(ti);
-	}
-}
-
-
-/** Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge.
- * bridges pieces sequence (middle parts)
- * bridge len 1: 0
- * bridge len 2: 0 1
- * bridge len 3: 0 4 1
- * bridge len 4: 0 2 3 1
- * bridge len 5: 0 2 5 3 1
- * bridge len 6: 0 2 3 2 3 1
- * bridge len 7: 0 2 3 4 2 3 1
- * #0 - always as first, #1 - always as last (if len>1)
- * #2,#3 are to pair in order
- * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
- * @param north Northernmost tile of bridge
- * @param south Southernmost tile of bridge
- * @return Index of bridge piece
- */
-static uint CalcBridgePiece(uint north, uint south)
-{
-	if (north == 1) {
-		return 0;
-	} else if (south == 1) {
-		return 1;
-	} else if (north < south) {
-		return north & 1 ? 3 : 2;
-	} else if (north > south) {
-		return south & 1 ? 2 : 3;
-	} else {
-		return north & 1 ? 5 : 4;
-	}
-}
-
-
-void DrawBridgeMiddle(const TileInfo* ti)
-{
-	const PalSpriteID* b;
-	PalSpriteID image;
-	uint base_offset;
-	TileIndex rampnorth;
-	TileIndex rampsouth;
-	Axis axis;
-	uint piece;
-	uint type;
-	int x;
-	int y;
-	uint z;
-
-	if (!IsBridgeAbove(ti->tile)) return;
-
-	rampnorth = GetNorthernBridgeEnd(ti->tile);
-	rampsouth = GetSouthernBridgeEnd(ti->tile);
-
-	axis = GetBridgeAxis(ti->tile);
-	piece = CalcBridgePiece(
-		DistanceManhattan(ti->tile, rampnorth),
-		DistanceManhattan(ti->tile, rampsouth)
-	);
-	type = GetBridgeType(rampsouth);
-
-	if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) {
-		base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
-	} else {
-		base_offset = 8;
-	}
-
-	b = base_offset + GetBridgeSpriteTable(type, piece);
-	if (axis != AXIS_X) b += 4;
-
-	x = ti->x;
-	y = ti->y;
-	z = GetBridgeHeight(rampsouth) - 3;
-
-	image = b[0];
-	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-	if (axis == AXIS_X) {
-		AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z);
-	} else {
-		AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z);
-	}
-
-	image = b[1];
-	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-	// draw roof, the component of the bridge which is logically between the vehicle and the camera
-	if (axis == AXIS_X) {
-		y += 12;
-		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
-	} else {
-		x += 12;
-		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
-	}
-
-	if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-	if (ti->z + 5 == z) {
-		// draw poles below for small bridges
-		image = b[2];
-		if (image != 0) {
-			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-			DrawGroundSpriteAt(image, x, y, z);
-		}
-	} else if (_patches.bridge_pillars) {
-		// draw pillars below for high bridges
-		DrawBridgePillars(b[2], ti, axis, type, x, y, z);
-	}
-}
-
-
-uint SetSpeedLimitOnBridge(Vehicle *v)
-{
-	uint bridge_speed;
-	if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */
-
-	bridge_speed = _bridge[GetBridgeType(v->tile)].speed;
-
-	if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */
-
-	if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed;
-	return bridge_speed;
-}
-
-
-
-static uint GetSlopeZ_TunnelBridge(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	Slope tileh = GetTileSlope(tile, &z);
-
-	x &= 0xF;
-	y &= 0xF;
-
-	if (IsTunnel(tile)) {
-		uint pos = (DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? y : x);
-
-		// In the tunnel entrance?
-		if (5 <= pos && pos <= 10) return z;
-	} else {
-		DiagDirection dir = GetBridgeRampDirection(tile);
-		uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
-
-		// On the bridge ramp?
-		if (5 <= pos && pos <= 10) {
-			uint delta;
-
-			if (IsSteepSlope(tileh)) return z + TILE_HEIGHT * 2;
-			if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
-
-			if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
-			switch (dir) {
-				default: NOT_REACHED();
-				case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
-				case DIAGDIR_SE: delta = y / 2; break;
-				case DIAGDIR_SW: delta = x / 2; break;
-				case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
-			}
-			return z + 1 + delta;
-		} else {
-			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
-
-			if (f != 0) {
-				if (IsSteepSlope(tileh)) {
-					z += TILE_HEIGHT;
-				} else if (f < 15) {
-					return z + TILE_HEIGHT;
-				}
-				tileh = _inclined_tileh[f - 15];
-			}
-		}
-	}
-
-	return z + GetPartialZ(x, y, tileh);
-}
-
-static Slope GetSlopeTileh_TunnelBridge(TileIndex tile, Slope tileh)
-{
-	if (IsTunnel(tile)) {
-		return tileh;
-	} else {
-		if (HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
-			return tileh;
-		} else {
-			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(tile)));
-
-			if (f == 0) return tileh;
-			if (f < 15) return SLOPE_FLAT;
-			return _inclined_tileh[f - 15];
-		}
-	}
-}
-
-
-static void GetAcceptedCargo_TunnelBridge(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static const StringID _bridge_tile_str[(MAX_BRIDGES + 3) + (MAX_BRIDGES + 3)] = {
-	STR_501F_WOODEN_RAIL_BRIDGE,
-	STR_5020_CONCRETE_RAIL_BRIDGE,
-	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
-	STR_501E_REINFORCED_CONCRETE_SUSPENSION,
-	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
-	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
-	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
-	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
-	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
-	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
-	STR_5027_TUBULAR_RAIL_BRIDGE,
-	STR_5027_TUBULAR_RAIL_BRIDGE,
-	STR_5027_TUBULAR_RAIL_BRIDGE,
-	0, 0, 0,
-
-	STR_5025_WOODEN_ROAD_BRIDGE,
-	STR_5026_CONCRETE_ROAD_BRIDGE,
-	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
-	STR_5024_REINFORCED_CONCRETE_SUSPENSION,
-	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
-	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
-	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
-	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
-	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
-	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
-	STR_5028_TUBULAR_ROAD_BRIDGE,
-	STR_5028_TUBULAR_ROAD_BRIDGE,
-	STR_5028_TUBULAR_ROAD_BRIDGE,
-	0, 0, 0,
-};
-
-static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
-{
-	if (IsTunnel(tile)) {
-		td->str = (GetTunnelTransportType(tile) == TRANSPORT_RAIL) ?
-			STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
-	} else {
-		td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)];
-	}
-	td->owner = GetTileOwner(tile);
-}
-
-
-static void AnimateTile_TunnelBridge(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoop_TunnelBridge(TileIndex tile)
-{
-	bool snow_or_desert = IsTunnelTile(tile) ? HasTunnelSnowOrDesert(tile) : HasBridgeSnowOrDesert(tile);
-	switch (_opt.landscape) {
-		case LT_HILLY:
-			if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) {
-				if (IsTunnelTile(tile)) {
-					SetTunnelSnowOrDesert(tile, !snow_or_desert);
-				} else {
-					SetBridgeSnowOrDesert(tile, !snow_or_desert);
-				}
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-
-		case LT_DESERT:
-			if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
-				if (IsTunnelTile(tile)) {
-					SetTunnelSnowOrDesert(tile, true);
-				} else {
-					SetBridgeSnowOrDesert(tile, true);
-				}
-				MarkTileDirtyByTile(tile);
-			}
-			break;
-	}
-}
-
-static void ClickTile_TunnelBridge(TileIndex tile)
-{
-	/* not used */
-}
-
-
-static uint32 GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode)
-{
-	if (IsTunnel(tile)) {
-		if (GetTunnelTransportType(tile) != mode) return 0;
-		return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(tile))) * 0x101;
-	} else {
-		if (GetBridgeTransportType(tile) != mode) return 0;
-		return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(tile))) * 0x101;
-	}
-}
-
-static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (new_player != PLAYER_SPECTATOR) {
-		SetTileOwner(tile, new_player);
-	} else {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-	}
-}
-
-
-static const byte _tunnel_fractcoord_1[4]    = {0x8E, 0x18, 0x81, 0xE8};
-static const byte _tunnel_fractcoord_2[4]    = {0x81, 0x98, 0x87, 0x38};
-static const byte _tunnel_fractcoord_3[4]    = {0x82, 0x88, 0x86, 0x48};
-static const byte _exit_tunnel_track[4]      = {1, 2, 1, 2};
-
-static const byte _road_exit_tunnel_state[4] = {8, 9, 0, 1};
-static const byte _road_exit_tunnel_frame[4] = {2, 7, 9, 4};
-
-static const byte _tunnel_fractcoord_4[4]    = {0x52, 0x85, 0x98, 0x29};
-static const byte _tunnel_fractcoord_5[4]    = {0x92, 0x89, 0x58, 0x25};
-static const byte _tunnel_fractcoord_6[4]    = {0x92, 0x89, 0x56, 0x45};
-static const byte _tunnel_fractcoord_7[4]    = {0x52, 0x85, 0x96, 0x49};
-
-static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
-{
-	int z = GetSlopeZ(x, y) - v->z_pos;
-
-	if (myabs(z) > 2) return 8;
-
-	if (IsTunnel(tile)) {
-		byte fc;
-		DiagDirection dir;
-		DiagDirection vdir;
-
-		if (v->type == VEH_Train) {
-			fc = (x & 0xF) + (y << 4);
-
-			dir = GetTunnelDirection(tile);
-			vdir = DirToDiagDir(v->direction);
-
-			if (v->u.rail.track != 0x40 && dir == vdir) {
-				if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
-					if (!PlayVehicleSound(v, VSE_TUNNEL) && v->spritenum < 4) {
-						SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
-					}
-					return 0;
-				}
-				if (fc == _tunnel_fractcoord_2[dir]) {
-					v->tile = tile;
-					v->u.rail.track = 0x40;
-					v->vehstatus |= VS_HIDDEN;
-					return 4;
-				}
-			}
-
-			if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
-				/* We're at the tunnel exit ?? */
-				v->tile = tile;
-				v->u.rail.track = _exit_tunnel_track[dir];
-				assert(v->u.rail.track);
-				v->vehstatus &= ~VS_HIDDEN;
-				return 4;
-			}
-		} else if (v->type == VEH_Road) {
-			fc = (x & 0xF) + (y << 4);
-			dir = GetTunnelDirection(tile);
-			vdir = DirToDiagDir(v->direction);
-
-			// Enter tunnel?
-			if (v->u.road.state != 0xFF && dir == vdir) {
-				if (fc == _tunnel_fractcoord_4[dir] ||
-						fc == _tunnel_fractcoord_5[dir]) {
-					v->tile = tile;
-					v->u.road.state = 0xFF;
-					v->vehstatus |= VS_HIDDEN;
-					return 4;
-				} else {
-					return 0;
-				}
-			}
-
-			if (dir == ReverseDiagDir(vdir) && (
-						/* We're at the tunnel exit ?? */
-						fc == _tunnel_fractcoord_6[dir] ||
-						fc == _tunnel_fractcoord_7[dir]
-					) &&
-					z == 0) {
-				v->tile = tile;
-				v->u.road.state = _road_exit_tunnel_state[dir];
-				v->u.road.frame = _road_exit_tunnel_frame[dir];
-				v->vehstatus &= ~VS_HIDDEN;
-				return 4;
-			}
-		}
-	} else if (IsBridge(tile)) { // XXX is this necessary?
-		DiagDirection dir;
-
-		if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
-			/* modify speed of vehicle */
-			uint16 spd = _bridge[GetBridgeType(tile)].speed;
-
-			if (v->type == VEH_Road) spd *= 2;
-			if (v->cur_speed > spd) v->cur_speed = spd;
-		}
-
-		dir = GetBridgeRampDirection(tile);
-		if (DirToDiagDir(v->direction) == dir) {
-			switch (dir) {
-				default: NOT_REACHED();
-				case DIAGDIR_NE: if ((x & 0xF) != 0)             return 0; break;
-				case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break;
-				case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break;
-				case DIAGDIR_NW: if ((y & 0xF) != 0)             return 0; break;
-			}
-			if (v->type == VEH_Train) {
-				v->u.rail.track = 0x40;
-				CLRBIT(v->u.rail.flags, VRF_GOINGUP);
-				CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
-			} else {
-				v->u.road.state = 0xFF;
-			}
-			return 4;
-		} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
-			v->tile = tile;
-			if (v->type == VEH_Train) {
-				if (v->u.rail.track == 0x40) {
-					v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
-					return 4;
-				}
-			} else {
-				if (v->u.road.state == 0xFF) {
-					v->u.road.state = _road_exit_tunnel_state[dir];
-					v->u.road.frame = 0;
-					return 4;
-				}
-			}
-			return 0;
-		}
-	}
-	return 0;
-}
-
-const TileTypeProcs _tile_type_tunnelbridge_procs = {
-	DrawTile_TunnelBridge,           /* draw_tile_proc */
-	GetSlopeZ_TunnelBridge,          /* get_slope_z_proc */
-	ClearTile_TunnelBridge,          /* clear_tile_proc */
-	GetAcceptedCargo_TunnelBridge,   /* get_accepted_cargo_proc */
-	GetTileDesc_TunnelBridge,        /* get_tile_desc_proc */
-	GetTileTrackStatus_TunnelBridge, /* get_tile_track_status_proc */
-	ClickTile_TunnelBridge,          /* click_tile_proc */
-	AnimateTile_TunnelBridge,        /* animate_tile_proc */
-	TileLoop_TunnelBridge,           /* tile_loop_clear */
-	ChangeTileOwner_TunnelBridge,    /* change_tile_owner_clear */
-	NULL,                            /* get_produced_cargo_proc */
-	VehicleEnter_TunnelBridge,       /* vehicle_enter_tile_proc */
-	GetSlopeTileh_TunnelBridge,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/tunnelbridge_cmd.cpp
@@ -0,0 +1,1316 @@
+/* $Id$ */
+
+/** @file tunnelbridge_cmd.c
+ * This file deals with tunnels and bridges (non-gui stuff)
+ * @todo seperate this file into two
+ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "rail_map.h"
+#include "road_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "tunnel_map.h"
+#include "unmovable_map.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "command.h"
+#include "player.h"
+#include "town.h"
+#include "sound.h"
+#include "variables.h"
+#include "bridge.h"
+#include "train.h"
+#include "water_map.h"
+#include "yapf/yapf.h"
+#include "date.h"
+#include "newgrf_sound.h"
+
+#include "table/bridge_land.h"
+
+const Bridge orig_bridge[] = {
+/*
+	     year of availablity
+	     |  minimum length
+	     |  |   maximum length
+	     |  |   |    price
+	     |  |   |    |    maximum speed
+	     |  |   |    |    |  sprite to use in GUI                string with description
+	     |  |   |    |    |  |                                   |                            */
+	{    0, 0, 16,  80,  32, 0xA24                             , STR_5012_WOODEN             , NULL, 0 },
+	{    0, 0,  2, 112,  48, 0xA26 | PALETTE_TO_STRUCT_RED     , STR_5013_CONCRETE           , NULL, 0 },
+	{ 1930, 0,  5, 144,  64, 0xA25                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
+	{    0, 2, 10, 168,  80, 0xA22 | PALETTE_TO_STRUCT_CONCRETE, STR_5011_SUSPENSION_CONCRETE, NULL, 0 },
+	{ 1930, 3, 16, 185,  96, 0xA22                             , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
+	{ 1930, 3, 16, 192, 112, 0xA22 | PALETTE_TO_STRUCT_YELLOW  , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
+	{ 1930, 3,  7, 224, 160, 0xA23                             , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
+	{ 1930, 3,  8, 232, 208, 0xA23 | PALETTE_TO_STRUCT_BROWN   , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
+	{ 1930, 3,  9, 248, 240, 0xA23 | PALETTE_TO_STRUCT_RED     , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
+	{ 1930, 0,  2, 240, 256, 0xA27                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
+	{ 1995, 2, 16, 255, 320, 0xA28                             , STR_5014_TUBULAR_STEEL      , NULL, 0 },
+	{ 2005, 2, 32, 380, 512, 0xA28 | PALETTE_TO_STRUCT_YELLOW  , STR_5014_TUBULAR_STEEL      , NULL, 0 },
+	{ 2010, 2, 32, 510, 608, 0xA28 | PALETTE_TO_STRUCT_GREY    , STR_BRIDGE_TUBULAR_SILICON  , NULL, 0 }
+};
+
+Bridge _bridge[MAX_BRIDGES];
+
+
+// calculate the price factor for building a long bridge.
+// basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6,  7,7,7,7,7,7,7,  8,8,8,8,8,8,8,8,
+int CalcBridgeLenCostFactor(int x)
+{
+	int n;
+	int r;
+
+	if (x < 2) return x;
+	x -= 2;
+	for (n = 0, r = 2;; n++) {
+		if (x <= n) return r + x * n;
+		r += n * n;
+		x -= n;
+	}
+}
+
+#define M(x) (1 << (x))
+enum {
+	// foundation, whole tile is leveled up --> 3 corners raised
+	BRIDGE_FULL_LEVELED_FOUNDATION = M(SLOPE_WSE) | M(SLOPE_NWS) | M(SLOPE_ENW) | M(SLOPE_SEN),
+	// foundation, tile is partly leveled up --> 1 corner raised
+	BRIDGE_PARTLY_LEVELED_FOUNDATION = M(SLOPE_W) | M(SLOPE_S) | M(SLOPE_E) | M(SLOPE_N),
+	// no foundations (X,Y direction)
+	BRIDGE_NO_FOUNDATION = M(SLOPE_FLAT) | M(SLOPE_SW) | M(SLOPE_SE) | M(SLOPE_NW) | M(SLOPE_NE),
+	BRIDGE_HORZ_RAMP = (BRIDGE_PARTLY_LEVELED_FOUNDATION | BRIDGE_NO_FOUNDATION) & ~M(SLOPE_FLAT)
+};
+#undef M
+
+static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
+{
+	const Bridge *bridge = &_bridge[index];
+	assert(table < 7);
+	if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
+		return _bridge_sprite_table[index][table];
+	} else {
+		return bridge->sprite_table[table];
+	}
+}
+
+static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;}
+
+
+/** Check the slope at the bridge ramps in three easy steps:
+ * - valid slopes without foundation
+ * - valid slopes with foundation
+ * - rest is invalid
+ */
+#define M(x) (1 << (x))
+static int32 CheckBridgeSlopeNorth(Axis axis, Slope tileh)
+{
+	uint32 valid;
+
+	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW));
+	if (HASBIT(valid, tileh)) return 0;
+
+	valid =
+		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) |
+		(axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W));
+	if (HASBIT(valid, tileh)) return _price.terraform;
+
+	return CMD_ERROR;
+}
+
+static int32 CheckBridgeSlopeSouth(Axis axis, Slope tileh)
+{
+	uint32 valid;
+
+	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_SW) : M(SLOPE_SE));
+	if (HASBIT(valid, tileh)) return 0;
+
+	valid =
+		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_S) | M(SLOPE_STEEP_S) |
+		(axis == AXIS_X ? M(SLOPE_W) | M(SLOPE_STEEP_W) : M(SLOPE_E) | M(SLOPE_STEEP_E));
+	if (HASBIT(valid, tileh)) return _price.terraform;
+
+	return CMD_ERROR;
+}
+#undef M
+
+
+uint32 GetBridgeLength(TileIndex begin, TileIndex end)
+{
+	int x1 = TileX(begin);
+	int y1 = TileY(begin);
+	int x2 = TileX(end);
+	int y2 = TileY(end);
+
+	return abs(x2 + y2 - x1 - y1) - 1;
+}
+
+bool CheckBridge_Stuff(byte bridge_type, uint bridge_len)
+{
+	const Bridge *b = &_bridge[bridge_type];
+	uint max; // max possible length of a bridge (with patch 100)
+
+	if (bridge_type >= MAX_BRIDGES) return false;
+	if (b->avail_year > _cur_year) return false;
+
+	max = b->max_length;
+	if (max >= 16 && _patches.longbridges) max = 100;
+
+	return b->min_length <= bridge_len && bridge_len <= max;
+}
+
+/** Build a Bridge
+ * @param end_tile end tile
+ * @param p1 packed start tile coords (~ dx)
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0- 7) - bridge type (hi bh)
+ * - p2 = (bit 8-..) - rail type. bit15 ((x>>8)&0x80) means road bridge.
+ */
+int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int bridge_type;
+	TransportType transport;
+	RailType railtype;
+	uint x;
+	uint y;
+	uint sx;
+	uint sy;
+	TileIndex tile_start;
+	TileIndex tile_end;
+	Slope tileh_start;
+	Slope tileh_end;
+	uint z_start;
+	uint z_end;
+	TileIndex tile;
+	TileIndexDiff delta;
+	uint bridge_len;
+	Axis direction;
+	int32 cost, terraformcost, ret;
+	bool allow_on_slopes;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* unpack parameters */
+	bridge_type = GB(p2, 0, 8);
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	// type of bridge
+	if (HASBIT(p2, 15)) {
+		railtype = 0;
+		transport = TRANSPORT_ROAD;
+	} else {
+		if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR;
+		railtype = GB(p2, 8, 8);
+		transport = TRANSPORT_RAIL;
+	}
+
+	x = TileX(end_tile);
+	y = TileY(end_tile);
+	sx = TileX(p1);
+	sy = TileY(p1);
+
+	/* check if valid, and make sure that (x,y) are smaller than (sx,sy) */
+	if (x == sx) {
+		if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
+		direction = AXIS_Y;
+		if (y > sy) uintswap(y,sy);
+	} else if (y == sy) {
+		direction = AXIS_X;
+		if (x > sx) uintswap(x,sx);
+	} else {
+		return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
+	}
+
+	/* set and test bridge length, availability */
+	bridge_len = sx + sy - x - y - 1;
+	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
+
+	/* retrieve landscape height and ensure it's on land */
+	tile_start = TileXY(x, y);
+	tile_end = TileXY(sx, sy);
+	if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) {
+		return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
+	}
+
+	tileh_start = GetTileSlope(tile_start, &z_start);
+	tileh_end = GetTileSlope(tile_end, &z_end);
+
+	if (IsSteepSlope(tileh_start)) z_start += TILE_HEIGHT;
+	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) {
+		z_start += TILE_HEIGHT;
+		tileh_start = SLOPE_FLAT;
+	}
+
+	if (IsSteepSlope(tileh_end)) z_end += TILE_HEIGHT;
+	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) {
+		z_end += TILE_HEIGHT;
+		tileh_end = SLOPE_FLAT;
+	}
+
+	if (z_start != z_end) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
+
+	// Towns are not allowed to use bridges on slopes.
+	allow_on_slopes = (!_is_old_ai_player
+	                   && _current_player != OWNER_TOWN && _patches.build_on_slopes);
+
+	/* Try and clear the start landscape */
+
+	ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return ret;
+	cost = ret;
+
+	terraformcost = CheckBridgeSlopeNorth(direction, tileh_start);
+	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
+		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	cost += terraformcost;
+
+	/* Try and clear the end landscape */
+
+	ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return ret;
+	cost += ret;
+
+	// false - end tile slope check
+	terraformcost = CheckBridgeSlopeSouth(direction, tileh_end);
+	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
+		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	cost += terraformcost;
+
+	{
+		TileIndex Heads[] = {tile_start, tile_end};
+		int i;
+
+		for (i = 0; i < 2; i++) {
+			if (MayHaveBridgeAbove(Heads[i])) {
+				if (IsBridgeAbove(Heads[i])) {
+					TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
+
+					if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
+					if (z_start + TILE_HEIGHT == GetBridgeHeight(north_head)) {
+						return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+					}
+				}
+			}
+		}
+	}
+
+	/* do the drill? */
+	if (flags & DC_EXEC) {
+		DiagDirection dir = AxisToDiagDir(direction);
+
+		if (transport == TRANSPORT_RAIL) {
+			MakeRailBridgeRamp(tile_start, _current_player, bridge_type, dir, railtype);
+			MakeRailBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir), railtype);
+		} else {
+			MakeRoadBridgeRamp(tile_start, _current_player, bridge_type, dir);
+			MakeRoadBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir));
+		}
+		MarkTileDirtyByTile(tile_start);
+		MarkTileDirtyByTile(tile_end);
+	}
+
+	delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
+	for (tile = tile_start + delta; tile != tile_end; tile += delta) {
+		uint z;
+
+		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
+
+		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
+			/* Disallow crossing bridges for the time being */
+			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+		}
+
+		switch (GetTileType(tile)) {
+			case MP_WATER:
+				if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
+				if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
+				break;
+
+			case MP_RAILWAY:
+				if (!IsPlainRailTile(tile)) goto not_valid_below;
+				break;
+
+			case MP_STREET:
+				if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) goto not_valid_below;
+				break;
+
+			case MP_TUNNELBRIDGE:
+				if (IsTunnel(tile)) break;
+				if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below;
+				if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
+				break;
+
+			case MP_UNMOVABLE:
+				if (!IsOwnedLand(tile)) goto not_valid_below;
+				break;
+
+			case MP_CLEAR:
+				if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+				break;
+
+			default:
+not_valid_below:;
+				/* try and clear the middle landscape */
+				ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+				if (CmdFailed(ret)) return ret;
+				cost += ret;
+				break;
+		}
+
+		if (flags & DC_EXEC) {
+			SetBridgeMiddle(tile, direction);
+			MarkTileDirtyByTile(tile);
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		Track track = AxisToTrack(direction);
+		SetSignalsOnBothDir(tile_start, track);
+		YapfNotifyTrackLayoutChange(tile_start, track);
+	}
+
+	/* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
+	 * It's unnecessary to execute this command every time for every bridge. So it is done only
+	 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
+	 */
+	if (!(flags & DC_QUERY_COST)) {
+		const Bridge *b = &_bridge[bridge_type];
+
+		bridge_len += 2; // begin and end tiles/ramps
+
+		if (IsValidPlayer(_current_player) && !_is_old_ai_player)
+			bridge_len = CalcBridgeLenCostFactor(bridge_len);
+
+		cost += (int64)bridge_len * _price.build_bridge * b->price >> 8;
+	}
+
+	return cost;
+}
+
+
+/** Build Tunnel.
+ * @param tile start tile of tunnel
+ * @param p1 railtype, 0x200 for road tunnel
+ * @param p2 unused
+ */
+int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TileIndexDiff delta;
+	TileIndex end_tile;
+	DiagDirection direction;
+	Slope start_tileh;
+	Slope end_tileh;
+	uint start_z;
+	uint end_z;
+	int32 cost;
+	int32 ret;
+
+	_build_tunnel_endtile = 0;
+
+	if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR;
+
+	start_tileh = GetTileSlope(start_tile, &start_z);
+
+	switch (start_tileh) {
+		case SLOPE_SW: direction = DIAGDIR_SW; break;
+		case SLOPE_SE: direction = DIAGDIR_SE; break;
+		case SLOPE_NW: direction = DIAGDIR_NW; break;
+		case SLOPE_NE: direction = DIAGDIR_NE; break;
+		default: return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
+	}
+
+	ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return ret;
+
+	/* XXX - do NOT change 'ret' in the loop, as it is used as the price
+	 * for the clearing of the entrance of the tunnel. Assigning it to
+	 * cost before the loop will yield different costs depending on start-
+	 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
+	cost = 0;
+	delta = TileOffsByDiagDir(direction);
+	end_tile = start_tile;
+	for (;;) {
+		end_tile += delta;
+		end_tileh = GetTileSlope(end_tile, &end_z);
+
+		if (start_z == end_z) break;
+
+		if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z)) {
+			return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
+		}
+
+		cost += _price.build_tunnel;
+		cost += cost >> 3; // add a multiplier for longer tunnels
+		if (cost >= 400000000) cost = 400000000;
+	}
+
+	/* Add the cost of the entrance */
+	cost += _price.build_tunnel + ret;
+
+	// if the command fails from here on we want the end tile to be highlighted
+	_build_tunnel_endtile = end_tile;
+
+	// slope of end tile must be complementary to the slope of the start tile
+	if (end_tileh != ComplementSlope(start_tileh)) {
+		ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
+		if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
+	} else {
+		ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+		if (CmdFailed(ret)) return ret;
+	}
+	cost += _price.build_tunnel + ret;
+
+	if (flags & DC_EXEC) {
+		if (GB(p1, 9, 1) == TRANSPORT_RAIL) {
+			MakeRailTunnel(start_tile, _current_player, direction,                 GB(p1, 0, 4));
+			MakeRailTunnel(end_tile,   _current_player, ReverseDiagDir(direction), GB(p1, 0, 4));
+			UpdateSignalsOnSegment(start_tile, direction);
+			YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
+		} else {
+			MakeRoadTunnel(start_tile, _current_player, direction);
+			MakeRoadTunnel(end_tile,   _current_player, ReverseDiagDir(direction));
+		}
+	}
+
+	return cost;
+}
+
+TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
+{
+	uint z = GetTileZ(tile);
+	DiagDirection dir = GetTunnelDirection(tile);
+	TileIndexDiff delta = TileOffsByDiagDir(dir);
+	uint len = 0;
+	TileIndex starttile = tile;
+	Vehicle *v;
+
+	do {
+		tile += delta;
+		len++;
+	} while (
+		!IsTunnelTile(tile) ||
+		ReverseDiagDir(GetTunnelDirection(tile)) != dir ||
+		GetTileZ(tile) != z
+	);
+
+	v = FindVehicleBetween(starttile, tile, z);
+	if (v != NULL) {
+		_error_message = v->type == VEH_Train ?
+			STR_5000_TRAIN_IN_TUNNEL : STR_5001_ROAD_VEHICLE_IN_TUNNEL;
+		return INVALID_TILE;
+	}
+
+	if (length != NULL) *length = len;
+	return tile;
+}
+
+static inline bool CheckAllowRemoveTunnelBridge(TileIndex tile)
+{
+	/* Floods can remove anything as well as the scenario editor */
+	if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true;
+	/* Obviously if the bridge/tunnel belongs to us, or no-one, we can remove it */
+	if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true;
+	/* Otherwise we can only remove town-owned stuff with extra patch-settings, or cheat */
+	if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true;
+	return false;
+}
+
+static int32 DoClearTunnel(TileIndex tile, uint32 flags)
+{
+	Town *t = NULL;
+	TileIndex endtile;
+	uint length;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
+
+	endtile = CheckTunnelBusy(tile, &length);
+	if (endtile == INVALID_TILE) return CMD_ERROR;
+
+	_build_tunnel_endtile = endtile;
+
+	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
+		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
+
+		/* Check if you are allowed to remove the tunnel owned by a town
+		 * Removal depends on difficulty settings */
+		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
+			SetDParam(0, t->index);
+			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		// We first need to request the direction before calling DoClearSquare
+		//  else the direction is always 0.. dah!! ;)
+		DiagDirection dir = GetTunnelDirection(tile);
+		Track track;
+
+		// Adjust the town's player rating. Do this before removing the tile owner info.
+		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
+			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
+
+		DoClearSquare(tile);
+		DoClearSquare(endtile);
+		UpdateSignalsOnSegment(tile, ReverseDiagDir(dir));
+		UpdateSignalsOnSegment(endtile, dir);
+		track = AxisToTrack(DiagDirToAxis(dir));
+		YapfNotifyTrackLayoutChange(tile, track);
+		YapfNotifyTrackLayoutChange(endtile, track);
+	}
+	return _price.clear_tunnel * (length + 1);
+}
+
+
+static bool IsVehicleOnBridge(TileIndex starttile, TileIndex endtile, uint z)
+{
+	const Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if ((v->tile == starttile || v->tile == endtile) && v->z_pos == z) {
+			_error_message = VehicleInTheWayErrMsg(v);
+			return true;
+		}
+	}
+	return false;
+}
+
+static int32 DoClearBridge(TileIndex tile, uint32 flags)
+{
+	DiagDirection direction;
+	TileIndexDiff delta;
+	TileIndex endtile;
+	Town *t = NULL;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
+
+	endtile = GetOtherBridgeEnd(tile);
+
+	if (!EnsureNoVehicle(tile) ||
+			!EnsureNoVehicle(endtile) ||
+			IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
+		return CMD_ERROR;
+	}
+
+	direction = GetBridgeRampDirection(tile);
+	delta = TileOffsByDiagDir(direction);
+
+	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
+		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
+
+		/* Check if you are allowed to remove the bridge owned by a town
+		 * Removal depends on difficulty settings */
+		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
+			SetDParam(0, t->index);
+			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
+		}
+	}
+
+	if (flags & DC_EXEC) {
+		TileIndex c;
+		Track track;
+
+		//checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
+		// you have a "Poor" (0) town rating
+		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
+			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
+
+		DoClearSquare(tile);
+		DoClearSquare(endtile);
+		for (c = tile + delta; c != endtile; c += delta) {
+				ClearBridgeMiddle(c);
+			MarkTileDirtyByTile(c);
+		}
+
+		UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
+		UpdateSignalsOnSegment(endtile, direction);
+		track = AxisToTrack(DiagDirToAxis(direction));
+		YapfNotifyTrackLayoutChange(tile, track);
+		YapfNotifyTrackLayoutChange(endtile, track);
+	}
+
+	return (DistanceManhattan(tile, endtile) + 1) * _price.clear_bridge;
+}
+
+static int32 ClearTile_TunnelBridge(TileIndex tile, byte flags)
+{
+	if (IsTunnel(tile)) {
+		if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
+		return DoClearTunnel(tile, flags);
+	} else if (IsBridge(tile)) { // XXX Is this necessary?
+		if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+		return DoClearBridge(tile, flags);
+	}
+
+	return CMD_ERROR;
+}
+
+int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
+{
+	TileIndex endtile;
+
+	if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
+		uint length;
+
+		if (!CheckTileOwnership(tile)) return CMD_ERROR;
+
+		if (GetRailType(tile) == totype) return CMD_ERROR;
+
+		// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
+		if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
+
+		endtile = CheckTunnelBusy(tile, &length);
+		if (endtile == INVALID_TILE) return CMD_ERROR;
+
+		if (exec) {
+			Track track;
+			SetRailType(tile, totype);
+			SetRailType(endtile, totype);
+			MarkTileDirtyByTile(tile);
+			MarkTileDirtyByTile(endtile);
+
+			track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile)));
+			YapfNotifyTrackLayoutChange(tile, track);
+			YapfNotifyTrackLayoutChange(endtile, track);
+		}
+		return (length + 1) * (_price.build_rail >> 1);
+	} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
+
+		if (!CheckTileOwnership(tile)) return CMD_ERROR;
+
+		endtile = GetOtherBridgeEnd(tile);
+
+		if (!EnsureNoVehicle(tile) ||
+				!EnsureNoVehicle(endtile) ||
+				IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
+			return CMD_ERROR;
+		}
+
+		if (GetRailType(tile) == totype) return CMD_ERROR;
+
+		if (exec) {
+			TileIndexDiff delta;
+			Track track;
+
+			SetRailType(tile, totype);
+			SetRailType(endtile, totype);
+			MarkTileDirtyByTile(tile);
+			MarkTileDirtyByTile(endtile);
+
+			track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile)));
+			YapfNotifyTrackLayoutChange(tile, track);
+			YapfNotifyTrackLayoutChange(endtile, track);
+
+			delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
+			for (tile += delta; tile != endtile; tile += delta) {
+				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
+			}
+		}
+
+		return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
+	} else {
+		return CMD_ERROR;
+	}
+}
+
+
+static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
+{
+	if (image != 0) {
+		bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
+		int back_height, front_height;
+		int i = z;
+		const byte *p;
+
+		static const byte _tileh_bits[4][8] = {
+			{ 2, 1, 8, 4,  16,  2, 0, 9 },
+			{ 1, 8, 4, 2,   2, 16, 9, 0 },
+			{ 4, 8, 1, 2,  16,  2, 0, 9 },
+			{ 2, 4, 8, 1,   2, 16, 9, 0 }
+		};
+
+		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+		p = _tileh_bits[(image & 1) * 2 + (axis == AXIS_X ? 0 : 1)];
+		front_height = ti->z + (ti->tileh & p[0] ? TILE_HEIGHT : 0);
+		back_height  = ti->z + (ti->tileh & p[1] ? TILE_HEIGHT : 0);
+
+		if (IsSteepSlope(ti->tileh)) {
+			if (!(ti->tileh & p[2])) front_height += TILE_HEIGHT;
+			if (!(ti->tileh & p[3])) back_height  += TILE_HEIGHT;
+		}
+
+		for (; z >= front_height || z >= back_height; z -= TILE_HEIGHT) {
+			/* HACK set height of the BB of pillars to 1, because the origin of the
+			 * sprites is at the top
+			 */
+			if (z >= front_height) { // front facing pillar
+				AddSortableSpriteToDraw(image, x, y, p[4], p[5], 1, z);
+			}
+
+			if (drawfarpillar && z >= back_height && z < i - TILE_HEIGHT) { // back facing pillar
+				AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 1, z);
+			}
+		}
+	}
+}
+
+uint GetBridgeFoundation(Slope tileh, Axis axis)
+{
+	uint i;
+
+	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) return tileh;
+
+	// inclined sloped building
+	switch (tileh) {
+		case SLOPE_W:
+		case SLOPE_STEEP_W: i = 0; break;
+		case SLOPE_S:
+		case SLOPE_STEEP_S: i = 2; break;
+		case SLOPE_E:
+		case SLOPE_STEEP_E: i = 4; break;
+		case SLOPE_N:
+		case SLOPE_STEEP_N: i = 6; break;
+		default: return 0;
+	}
+	if (axis != AXIS_X) ++i;
+	return i + 15;
+}
+
+/**
+ * Draws a tunnel of bridge tile.
+ * For tunnels, this is rather simple, as you only needa draw the entrance.
+ * Bridges are a bit more complex. base_offset is where the sprite selection comes into play
+ * and it works a bit like a bitmask.<p> For bridge heads:
+ * <ul><li>Bit 0: direction</li>
+ * <li>Bit 1: northern or southern heads</li>
+ * <li>Bit 2: Set if the bridge head is sloped</li>
+ * <li>Bit 3 and more: Railtype Specific subset</li>
+ * </ul>
+ * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
+ */
+static void DrawTile_TunnelBridge(TileInfo *ti)
+{
+	uint32 image;
+
+	if (IsTunnel(ti->tile)) {
+		if (GetTunnelTransportType(ti->tile) == TRANSPORT_RAIL) {
+			image = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.tunnel;
+		} else {
+			image = SPR_TUNNEL_ENTRY_REAR_ROAD;
+		}
+
+		if (HasTunnelSnowOrDesert(ti->tile)) image += 32;
+
+		image += GetTunnelDirection(ti->tile) * 2;
+		DrawGroundSprite(image);
+		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+		AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z);
+		DrawBridgeMiddle(ti);
+	} else if (IsBridge(ti->tile)) { // XXX is this necessary?
+		int base_offset;
+		bool ice = HasBridgeSnowOrDesert(ti->tile);
+
+		if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) {
+			base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
+			assert(base_offset != 8); /* This one is used for roads */
+		} else {
+			base_offset = 8;
+		}
+
+		/* as the lower 3 bits are used for other stuff, make sure they are clear */
+		assert( (base_offset & 0x07) == 0x00);
+
+		if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
+			int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
+			if (f != 0) DrawFoundation(ti, f);
+		}
+
+		// HACK Wizardry to convert the bridge ramp direction into a sprite offset
+		base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
+
+		if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
+
+		/* Table number 6 always refers to the bridge heads for any bridge type */
+		image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
+
+		if (!ice) {
+			DrawClearLandTile(ti, 3);
+		} else {
+			DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
+		}
+
+		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+		// draw ramp
+		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+		/* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
+		 * it doesn't disappear behind it
+		 */
+		AddSortableSpriteToDraw(
+			image, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 1 : 8, ti->z
+		);
+
+		DrawBridgeMiddle(ti);
+	}
+}
+
+
+/** Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge.
+ * bridges pieces sequence (middle parts)
+ * bridge len 1: 0
+ * bridge len 2: 0 1
+ * bridge len 3: 0 4 1
+ * bridge len 4: 0 2 3 1
+ * bridge len 5: 0 2 5 3 1
+ * bridge len 6: 0 2 3 2 3 1
+ * bridge len 7: 0 2 3 4 2 3 1
+ * #0 - always as first, #1 - always as last (if len>1)
+ * #2,#3 are to pair in order
+ * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
+ * @param north Northernmost tile of bridge
+ * @param south Southernmost tile of bridge
+ * @return Index of bridge piece
+ */
+static uint CalcBridgePiece(uint north, uint south)
+{
+	if (north == 1) {
+		return 0;
+	} else if (south == 1) {
+		return 1;
+	} else if (north < south) {
+		return north & 1 ? 3 : 2;
+	} else if (north > south) {
+		return south & 1 ? 2 : 3;
+	} else {
+		return north & 1 ? 5 : 4;
+	}
+}
+
+
+void DrawBridgeMiddle(const TileInfo* ti)
+{
+	const PalSpriteID* b;
+	PalSpriteID image;
+	uint base_offset;
+	TileIndex rampnorth;
+	TileIndex rampsouth;
+	Axis axis;
+	uint piece;
+	uint type;
+	int x;
+	int y;
+	uint z;
+
+	if (!IsBridgeAbove(ti->tile)) return;
+
+	rampnorth = GetNorthernBridgeEnd(ti->tile);
+	rampsouth = GetSouthernBridgeEnd(ti->tile);
+
+	axis = GetBridgeAxis(ti->tile);
+	piece = CalcBridgePiece(
+		DistanceManhattan(ti->tile, rampnorth),
+		DistanceManhattan(ti->tile, rampsouth)
+	);
+	type = GetBridgeType(rampsouth);
+
+	if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) {
+		base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
+	} else {
+		base_offset = 8;
+	}
+
+	b = base_offset + GetBridgeSpriteTable(type, piece);
+	if (axis != AXIS_X) b += 4;
+
+	x = ti->x;
+	y = ti->y;
+	z = GetBridgeHeight(rampsouth) - 3;
+
+	image = b[0];
+	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+	if (axis == AXIS_X) {
+		AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z);
+	} else {
+		AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z);
+	}
+
+	image = b[1];
+	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+	// draw roof, the component of the bridge which is logically between the vehicle and the camera
+	if (axis == AXIS_X) {
+		y += 12;
+		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
+	} else {
+		x += 12;
+		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
+	}
+
+	if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+	if (ti->z + 5 == z) {
+		// draw poles below for small bridges
+		image = b[2];
+		if (image != 0) {
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+			DrawGroundSpriteAt(image, x, y, z);
+		}
+	} else if (_patches.bridge_pillars) {
+		// draw pillars below for high bridges
+		DrawBridgePillars(b[2], ti, axis, type, x, y, z);
+	}
+}
+
+
+uint SetSpeedLimitOnBridge(Vehicle *v)
+{
+	uint bridge_speed;
+	if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */
+
+	bridge_speed = _bridge[GetBridgeType(v->tile)].speed;
+
+	if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */
+
+	if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed;
+	return bridge_speed;
+}
+
+
+
+static uint GetSlopeZ_TunnelBridge(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	Slope tileh = GetTileSlope(tile, &z);
+
+	x &= 0xF;
+	y &= 0xF;
+
+	if (IsTunnel(tile)) {
+		uint pos = (DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? y : x);
+
+		// In the tunnel entrance?
+		if (5 <= pos && pos <= 10) return z;
+	} else {
+		DiagDirection dir = GetBridgeRampDirection(tile);
+		uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
+
+		// On the bridge ramp?
+		if (5 <= pos && pos <= 10) {
+			uint delta;
+
+			if (IsSteepSlope(tileh)) return z + TILE_HEIGHT * 2;
+			if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
+
+			if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
+			switch (dir) {
+				default: NOT_REACHED();
+				case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
+				case DIAGDIR_SE: delta = y / 2; break;
+				case DIAGDIR_SW: delta = x / 2; break;
+				case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
+			}
+			return z + 1 + delta;
+		} else {
+			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
+
+			if (f != 0) {
+				if (IsSteepSlope(tileh)) {
+					z += TILE_HEIGHT;
+				} else if (f < 15) {
+					return z + TILE_HEIGHT;
+				}
+				tileh = _inclined_tileh[f - 15];
+			}
+		}
+	}
+
+	return z + GetPartialZ(x, y, tileh);
+}
+
+static Slope GetSlopeTileh_TunnelBridge(TileIndex tile, Slope tileh)
+{
+	if (IsTunnel(tile)) {
+		return tileh;
+	} else {
+		if (HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
+			return tileh;
+		} else {
+			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(tile)));
+
+			if (f == 0) return tileh;
+			if (f < 15) return SLOPE_FLAT;
+			return _inclined_tileh[f - 15];
+		}
+	}
+}
+
+
+static void GetAcceptedCargo_TunnelBridge(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static const StringID _bridge_tile_str[(MAX_BRIDGES + 3) + (MAX_BRIDGES + 3)] = {
+	STR_501F_WOODEN_RAIL_BRIDGE,
+	STR_5020_CONCRETE_RAIL_BRIDGE,
+	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
+	STR_501E_REINFORCED_CONCRETE_SUSPENSION,
+	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
+	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
+	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
+	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
+	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
+	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
+	STR_5027_TUBULAR_RAIL_BRIDGE,
+	STR_5027_TUBULAR_RAIL_BRIDGE,
+	STR_5027_TUBULAR_RAIL_BRIDGE,
+	0, 0, 0,
+
+	STR_5025_WOODEN_ROAD_BRIDGE,
+	STR_5026_CONCRETE_ROAD_BRIDGE,
+	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
+	STR_5024_REINFORCED_CONCRETE_SUSPENSION,
+	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
+	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
+	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
+	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
+	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
+	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
+	STR_5028_TUBULAR_ROAD_BRIDGE,
+	STR_5028_TUBULAR_ROAD_BRIDGE,
+	STR_5028_TUBULAR_ROAD_BRIDGE,
+	0, 0, 0,
+};
+
+static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
+{
+	if (IsTunnel(tile)) {
+		td->str = (GetTunnelTransportType(tile) == TRANSPORT_RAIL) ?
+			STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
+	} else {
+		td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)];
+	}
+	td->owner = GetTileOwner(tile);
+}
+
+
+static void AnimateTile_TunnelBridge(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoop_TunnelBridge(TileIndex tile)
+{
+	bool snow_or_desert = IsTunnelTile(tile) ? HasTunnelSnowOrDesert(tile) : HasBridgeSnowOrDesert(tile);
+	switch (_opt.landscape) {
+		case LT_HILLY:
+			if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) {
+				if (IsTunnelTile(tile)) {
+					SetTunnelSnowOrDesert(tile, !snow_or_desert);
+				} else {
+					SetBridgeSnowOrDesert(tile, !snow_or_desert);
+				}
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		case LT_DESERT:
+			if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
+				if (IsTunnelTile(tile)) {
+					SetTunnelSnowOrDesert(tile, true);
+				} else {
+					SetBridgeSnowOrDesert(tile, true);
+				}
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+	}
+}
+
+static void ClickTile_TunnelBridge(TileIndex tile)
+{
+	/* not used */
+}
+
+
+static uint32 GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode)
+{
+	if (IsTunnel(tile)) {
+		if (GetTunnelTransportType(tile) != mode) return 0;
+		return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(tile))) * 0x101;
+	} else {
+		if (GetBridgeTransportType(tile) != mode) return 0;
+		return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(tile))) * 0x101;
+	}
+}
+
+static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (new_player != PLAYER_SPECTATOR) {
+		SetTileOwner(tile, new_player);
+	} else {
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	}
+}
+
+
+static const byte _tunnel_fractcoord_1[4]    = {0x8E, 0x18, 0x81, 0xE8};
+static const byte _tunnel_fractcoord_2[4]    = {0x81, 0x98, 0x87, 0x38};
+static const byte _tunnel_fractcoord_3[4]    = {0x82, 0x88, 0x86, 0x48};
+static const byte _exit_tunnel_track[4]      = {1, 2, 1, 2};
+
+static const byte _road_exit_tunnel_state[4] = {8, 9, 0, 1};
+static const byte _road_exit_tunnel_frame[4] = {2, 7, 9, 4};
+
+static const byte _tunnel_fractcoord_4[4]    = {0x52, 0x85, 0x98, 0x29};
+static const byte _tunnel_fractcoord_5[4]    = {0x92, 0x89, 0x58, 0x25};
+static const byte _tunnel_fractcoord_6[4]    = {0x92, 0x89, 0x56, 0x45};
+static const byte _tunnel_fractcoord_7[4]    = {0x52, 0x85, 0x96, 0x49};
+
+static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
+{
+	int z = GetSlopeZ(x, y) - v->z_pos;
+
+	if (myabs(z) > 2) return 8;
+
+	if (IsTunnel(tile)) {
+		byte fc;
+		DiagDirection dir;
+		DiagDirection vdir;
+
+		if (v->type == VEH_Train) {
+			fc = (x & 0xF) + (y << 4);
+
+			dir = GetTunnelDirection(tile);
+			vdir = DirToDiagDir(v->direction);
+
+			if (v->u.rail.track != 0x40 && dir == vdir) {
+				if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
+					if (!PlayVehicleSound(v, VSE_TUNNEL) && v->spritenum < 4) {
+						SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
+					}
+					return 0;
+				}
+				if (fc == _tunnel_fractcoord_2[dir]) {
+					v->tile = tile;
+					v->u.rail.track = 0x40;
+					v->vehstatus |= VS_HIDDEN;
+					return 4;
+				}
+			}
+
+			if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
+				/* We're at the tunnel exit ?? */
+				v->tile = tile;
+				v->u.rail.track = _exit_tunnel_track[dir];
+				assert(v->u.rail.track);
+				v->vehstatus &= ~VS_HIDDEN;
+				return 4;
+			}
+		} else if (v->type == VEH_Road) {
+			fc = (x & 0xF) + (y << 4);
+			dir = GetTunnelDirection(tile);
+			vdir = DirToDiagDir(v->direction);
+
+			// Enter tunnel?
+			if (v->u.road.state != 0xFF && dir == vdir) {
+				if (fc == _tunnel_fractcoord_4[dir] ||
+						fc == _tunnel_fractcoord_5[dir]) {
+					v->tile = tile;
+					v->u.road.state = 0xFF;
+					v->vehstatus |= VS_HIDDEN;
+					return 4;
+				} else {
+					return 0;
+				}
+			}
+
+			if (dir == ReverseDiagDir(vdir) && (
+						/* We're at the tunnel exit ?? */
+						fc == _tunnel_fractcoord_6[dir] ||
+						fc == _tunnel_fractcoord_7[dir]
+					) &&
+					z == 0) {
+				v->tile = tile;
+				v->u.road.state = _road_exit_tunnel_state[dir];
+				v->u.road.frame = _road_exit_tunnel_frame[dir];
+				v->vehstatus &= ~VS_HIDDEN;
+				return 4;
+			}
+		}
+	} else if (IsBridge(tile)) { // XXX is this necessary?
+		DiagDirection dir;
+
+		if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
+			/* modify speed of vehicle */
+			uint16 spd = _bridge[GetBridgeType(tile)].speed;
+
+			if (v->type == VEH_Road) spd *= 2;
+			if (v->cur_speed > spd) v->cur_speed = spd;
+		}
+
+		dir = GetBridgeRampDirection(tile);
+		if (DirToDiagDir(v->direction) == dir) {
+			switch (dir) {
+				default: NOT_REACHED();
+				case DIAGDIR_NE: if ((x & 0xF) != 0)             return 0; break;
+				case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break;
+				case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break;
+				case DIAGDIR_NW: if ((y & 0xF) != 0)             return 0; break;
+			}
+			if (v->type == VEH_Train) {
+				v->u.rail.track = 0x40;
+				CLRBIT(v->u.rail.flags, VRF_GOINGUP);
+				CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
+			} else {
+				v->u.road.state = 0xFF;
+			}
+			return 4;
+		} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
+			v->tile = tile;
+			if (v->type == VEH_Train) {
+				if (v->u.rail.track == 0x40) {
+					v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
+					return 4;
+				}
+			} else {
+				if (v->u.road.state == 0xFF) {
+					v->u.road.state = _road_exit_tunnel_state[dir];
+					v->u.road.frame = 0;
+					return 4;
+				}
+			}
+			return 0;
+		}
+	}
+	return 0;
+}
+
+const TileTypeProcs _tile_type_tunnelbridge_procs = {
+	DrawTile_TunnelBridge,           /* draw_tile_proc */
+	GetSlopeZ_TunnelBridge,          /* get_slope_z_proc */
+	ClearTile_TunnelBridge,          /* clear_tile_proc */
+	GetAcceptedCargo_TunnelBridge,   /* get_accepted_cargo_proc */
+	GetTileDesc_TunnelBridge,        /* get_tile_desc_proc */
+	GetTileTrackStatus_TunnelBridge, /* get_tile_track_status_proc */
+	ClickTile_TunnelBridge,          /* click_tile_proc */
+	AnimateTile_TunnelBridge,        /* animate_tile_proc */
+	TileLoop_TunnelBridge,           /* tile_loop_clear */
+	ChangeTileOwner_TunnelBridge,    /* change_tile_owner_clear */
+	NULL,                            /* get_produced_cargo_proc */
+	VehicleEnter_TunnelBridge,       /* vehicle_enter_tile_proc */
+	GetSlopeTileh_TunnelBridge,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/unix.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "window.h"
-#include "string.h"
-#include "table/strings.h"
-#include "variables.h"
-
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <signal.h>
-
-#ifdef USE_HOMEDIR
-#include <pwd.h>
-#endif
-
-#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)
-	#define HAS_STATVFS
-#endif
-
-#ifdef HAS_STATVFS
-#include <sys/statvfs.h>
-#endif
-
-
-#ifdef __MORPHOS__
-#include <exec/types.h>
-ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;)
-
-// The system supplied definition of SIG_IGN does not match
-#undef SIG_IGN
-#define SIG_IGN (void (*)(int))1
-#endif /* __MORPHOS__ */
-
-#ifdef __AMIGA__
-#warning add stack symbol to avoid that user needs to set stack manually (tokai)
-// ULONG __stack =
-#endif
-
-#if defined(__APPLE__)
-	#if defined(WITH_SDL)
-		//the mac implementation needs this file included in the same file as main()
-		#include <SDL.h>
-	#endif
-#endif
-
-bool FiosIsRoot(const char *path)
-{
-#if !defined(__MORPHOS__) && !defined(__AMIGAOS__)
-	return path[1] == '\0';
-#else
-	/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
-	const char *s = strchr(path, ':');
-	return s[1] == '\0';
-#endif
-}
-
-void FiosGetDrives(void)
-{
-	return;
-}
-
-bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
-{
-	uint32 free = 0;
-
-#ifdef HAS_STATVFS
-	{
-		struct statvfs s;
-
-		if (statvfs(path, &s) != 0) return false;
-		free = (uint64)s.f_frsize * s.f_bavail >> 20;
-	}
-#endif
-	if (tot != NULL) *tot = free;
-	return true;
-}
-
-bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
-{
-	char filename[MAX_PATH];
-
-#if defined(__MORPHOS__) || defined(__AMIGAOS__)
-	/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
-	if (FiosIsRoot(path)) {
-		snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name);
-	} else // XXX - only next line!
-#endif
-	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, ent->d_name);
-
-	if (stat(filename, sb) != 0) return false;
-
-	return (ent->d_name[0] != '.'); // hidden file
-}
-
-#if defined(__BEOS__) || defined(__linux__)
-static void ChangeWorkingDirectory(char *exe)
-{
-	char *s = strrchr(exe, '/');
-	if (s != NULL) {
-		*s = '\0';
-		chdir(exe);
-		*s = '/';
-	}
-}
-#endif
-
-void ShowInfo(const char *str)
-{
-	fprintf(stderr, str);
-}
-
-void ShowOSErrorBox(const char *buf)
-{
-#if defined(__APPLE__)
-	// this creates an NSAlertPanel with the contents of 'buf'
-	// this is the native and nicest way to do this on OSX
-	ShowMacDialog( buf, "See readme for more info\nMost likely you are missing files from the original TTD", "Quit" );
-#else
-	// all systems, but OSX
-	fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf);
-#endif
-}
-
-#ifdef WITH_COCOA
-void cocoaSetWorkingDirectory(void);
-void cocoaSetupAutoreleasePool(void);
-void cocoaReleaseAutoreleasePool(void);
-#endif
-
-int CDECL main(int argc, char* argv[])
-{
-	int ret;
-
-#ifdef WITH_COCOA
-	cocoaSetupAutoreleasePool();
-	/* This is passed if we are launched by double-clicking */
-	if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) {
-		argv[1] = NULL;
-		argc = 1;
-		cocoaSetWorkingDirectory();
-	}
-#endif
-
-	// change the working directory to enable doubleclicking in UIs
-#if defined(__BEOS__) || defined(__linux__)
-	ChangeWorkingDirectory(argv[0]);
-#endif
-
-	_random_seeds[1][1] = _random_seeds[1][0] = _random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
-	SeedMT(_random_seeds[0][1]);
-
-	signal(SIGPIPE, SIG_IGN);
-
-	ret = ttd_main(argc, argv);
-
-#ifdef WITH_COCOA
-	cocoaReleaseAutoreleasePool();
-#endif
-
-	return ret;
-}
-
-void DeterminePaths(void)
-{
-	char *s;
-
-	_paths.game_data_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.game_data_dir, GAME_DATA_DIR, MAX_PATH);
-	#if defined SECOND_DATA_DIR
-	_paths.second_data_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.second_data_dir, SECOND_DATA_DIR, MAX_PATH);
-	#endif
-
-#if defined(USE_HOMEDIR)
-	{
-		const char *homedir = getenv("HOME");
-
-		if (homedir == NULL) {
-			const struct passwd *pw = getpwuid(getuid());
-			if (pw != NULL) homedir = pw->pw_dir;
-		}
-
-		_paths.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR);
-	}
-
-#else /* not defined(USE_HOMEDIR) */
-
-	_paths.personal_dir = malloc(MAX_PATH);
-	ttd_strlcpy(_paths.personal_dir, PERSONAL_DIR, MAX_PATH);
-
-	// check if absolute or relative path
-	s = strchr(_paths.personal_dir, '/');
-
-	// add absolute path
-	if (s == NULL || _paths.personal_dir != s) {
-		getcwd(_paths.personal_dir, MAX_PATH);
-		s = strchr(_paths.personal_dir, 0);
-		*s++ = '/';
-		ttd_strlcpy(s, PERSONAL_DIR, MAX_PATH);
-	}
-
-#endif /* defined(USE_HOMEDIR) */
-
-	s = strchr(_paths.personal_dir, 0);
-
-	// append a / ?
-	if (s[-1] != '/') strcpy(s, "/");
-
-	_paths.save_dir = str_fmt("%ssave", _paths.personal_dir);
-	_paths.autosave_dir = str_fmt("%s/autosave", _paths.save_dir);
-	_paths.scenario_dir = str_fmt("%sscenario", _paths.personal_dir);
-	_paths.heightmap_dir = str_fmt("%sscenario/heightmap", _paths.personal_dir);
-	_paths.gm_dir = str_fmt("%sgm/", _paths.game_data_dir);
-	_paths.data_dir = str_fmt("%sdata/", _paths.game_data_dir);
-
-	if (_config_file == NULL)
-		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
-
-	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
-	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
-
-#if defined CUSTOM_LANG_DIR
-	// sets the search path for lng files to the custom one
-	_paths.lang_dir = malloc( MAX_PATH );
-	ttd_strlcpy( _paths.lang_dir, CUSTOM_LANG_DIR, MAX_PATH);
-#else
-	_paths.lang_dir = str_fmt("%slang/", _paths.game_data_dir);
-#endif
-
-	// create necessary folders
-	mkdir(_paths.personal_dir, 0755);
-	mkdir(_paths.save_dir, 0755);
-	mkdir(_paths.autosave_dir, 0755);
-	mkdir(_paths.scenario_dir, 0755);
-	mkdir(_paths.heightmap_dir, 0755);
-}
-
-bool InsertTextBufferClipboard(Textbuf *tb)
-{
-	return false;
-}
-
-
-// multi os compatible sleep function
-
-#ifdef __AMIGA__
-// usleep() implementation
-#	include <devices/timer.h>
-#	include <dos/dos.h>
-
-	extern struct Device      *TimerBase    = NULL;
-	extern struct MsgPort     *TimerPort    = NULL;
-	extern struct timerequest *TimerRequest = NULL;
-#endif // __AMIGA__
-
-void CSleep(int milliseconds)
-{
-	#if !defined(__BEOS__) && !defined(__AMIGA__)
-		usleep(milliseconds * 1000);
-	#endif
-	#ifdef __BEOS__
-		snooze(milliseconds * 1000);
-	#endif
-	#if defined(__AMIGA__)
-	{
-		ULONG signals;
-		ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
-
-		// send IORequest
-		TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
-		TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
-		TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
-		SendIO((struct IORequest *)TimerRequest);
-
-		if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
-			AbortIO((struct IORequest *)TimerRequest);
-		}
-		WaitIO((struct IORequest *)TimerRequest);
-	}
-	#endif // __AMIGA__
-}
-
-#ifdef WITH_ICONV
-
-#include <iconv.h>
-#include <errno.h>
-#include "debug.h"
-
-#define INTERNALCODE "UTF-8"
-
-/** Try and try to decipher the current locale from environmental
- * variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable
- * locale can be found, don't do any conversion "" */
-static const char *GetLocalCode(void)
-{
-#if defined(__APPLE__)
-	return "UTF-8-MAC";
-#else
-	/* Strip locale (eg en_US.UTF-8) to only have UTF-8 */
-	const char *locale = GetCurrentLocale("LC_CTYPE");
-	if (locale != NULL) locale = strchr(locale, '.');
-
-	return (locale == NULL) ? "" : locale + 1;
-#endif
-}
-
-/** FYI: This is not thread-safe.
- * convert between locales, which from and which to is set in the calling
- * functions OTTD2FS() and FS2OTTD(). You should NOT use this function directly
- * NOTE: iconv was added in OSX 10.3. 10.2.x will still have the invalid char
- * issues. There aren't any easy fix for this */
-static const char *convert_tofrom_fs(iconv_t convd, const char *name)
-{
-	static char buf[1024];
-	/* Work around buggy iconv implementation where inbuf is wrongly typed as
-	 * non-const. Correct implementation is at
-	 * http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html */
-#if defined (__GLIBC__) || defined (__GNU_LIBRARY__)
-	char *inbuf = (char*)name;
-#else
-	const char *inbuf = name;
-#endif
-
-	char *outbuf  = buf;
-	size_t outlen = sizeof(buf) - 1;
-	size_t inlen  = strlen(name);
-
-	ttd_strlcpy(outbuf, name, sizeof(buf));
-
-	iconv(convd, NULL, NULL, NULL, NULL);
-	if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) {
-		DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno);
-	}
-
-	*outbuf = '\0';
-	// FIX: invalid characters will abort conversion, but they shouldn't occur?
-	return buf;
-}
-
-/** Convert from OpenTTD's encoding to that of the local environment
- * @param name pointer to a valid string that will be converted
- * @return pointer to a new stringbuffer that contains the converted string */
-const char *OTTD2FS(const char *name)
-{
-	static iconv_t convd = (iconv_t)(-1);
-
-	if (convd == (iconv_t)(-1)) {
-		const char *env = GetLocalCode();
-		convd = iconv_open(env, INTERNALCODE);
-		if (convd == (iconv_t)(-1)) {
-			DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE, env);
-			return name;
-		}
-	}
-
-	return convert_tofrom_fs(convd, name);
-}
-
-/** Convert to OpenTTD's encoding from that of the local environment
- * @param name pointer to a valid string that will be converted
- * @return pointer to a new stringbuffer that contains the converted string */
-const char *FS2OTTD(const char *name)
-{
-	static iconv_t convd = (iconv_t)(-1);
-
-	if (convd == (iconv_t)(-1)) {
-		const char *env = GetLocalCode();
-		convd = iconv_open(INTERNALCODE, env);
-		if (convd == (iconv_t)(-1)) {
-			DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env, INTERNALCODE);
-			return name;
-		}
-	}
-
-	return convert_tofrom_fs(convd, name);
-}
-
-#else
-const char *FS2OTTD(const char *name) {return name;}
-const char *OTTD2FS(const char *name) {return name;}
-#endif /* WITH_ICONV */
new file mode 100644
--- /dev/null
+++ b/src/unix.cpp
@@ -0,0 +1,386 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "window.h"
+#include "string.h"
+#include "table/strings.h"
+#include "variables.h"
+
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+
+#ifdef USE_HOMEDIR
+#include <pwd.h>
+#endif
+
+#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)
+	#define HAS_STATVFS
+#endif
+
+#ifdef HAS_STATVFS
+#include <sys/statvfs.h>
+#endif
+
+
+#ifdef __MORPHOS__
+#include <exec/types.h>
+ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;)
+
+// The system supplied definition of SIG_IGN does not match
+#undef SIG_IGN
+#define SIG_IGN (void (*)(int))1
+#endif /* __MORPHOS__ */
+
+#ifdef __AMIGA__
+#warning add stack symbol to avoid that user needs to set stack manually (tokai)
+// ULONG __stack =
+#endif
+
+#if defined(__APPLE__)
+	#if defined(WITH_SDL)
+		//the mac implementation needs this file included in the same file as main()
+		#include <SDL.h>
+	#endif
+#endif
+
+bool FiosIsRoot(const char *path)
+{
+#if !defined(__MORPHOS__) && !defined(__AMIGAOS__)
+	return path[1] == '\0';
+#else
+	/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
+	const char *s = strchr(path, ':');
+	return s[1] == '\0';
+#endif
+}
+
+void FiosGetDrives(void)
+{
+	return;
+}
+
+bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
+{
+	uint32 free = 0;
+
+#ifdef HAS_STATVFS
+	{
+		struct statvfs s;
+
+		if (statvfs(path, &s) != 0) return false;
+		free = (uint64)s.f_frsize * s.f_bavail >> 20;
+	}
+#endif
+	if (tot != NULL) *tot = free;
+	return true;
+}
+
+bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
+{
+	char filename[MAX_PATH];
+
+#if defined(__MORPHOS__) || defined(__AMIGAOS__)
+	/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
+	if (FiosIsRoot(path)) {
+		snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name);
+	} else // XXX - only next line!
+#endif
+	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, ent->d_name);
+
+	if (stat(filename, sb) != 0) return false;
+
+	return (ent->d_name[0] != '.'); // hidden file
+}
+
+#if defined(__BEOS__) || defined(__linux__)
+static void ChangeWorkingDirectory(char *exe)
+{
+	char *s = strrchr(exe, '/');
+	if (s != NULL) {
+		*s = '\0';
+		chdir(exe);
+		*s = '/';
+	}
+}
+#endif
+
+void ShowInfo(const char *str)
+{
+	fprintf(stderr, str);
+}
+
+void ShowOSErrorBox(const char *buf)
+{
+#if defined(__APPLE__)
+	// this creates an NSAlertPanel with the contents of 'buf'
+	// this is the native and nicest way to do this on OSX
+	ShowMacDialog( buf, "See readme for more info\nMost likely you are missing files from the original TTD", "Quit" );
+#else
+	// all systems, but OSX
+	fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf);
+#endif
+}
+
+#ifdef WITH_COCOA
+void cocoaSetWorkingDirectory(void);
+void cocoaSetupAutoreleasePool(void);
+void cocoaReleaseAutoreleasePool(void);
+#endif
+
+int CDECL main(int argc, char* argv[])
+{
+	int ret;
+
+#ifdef WITH_COCOA
+	cocoaSetupAutoreleasePool();
+	/* This is passed if we are launched by double-clicking */
+	if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) {
+		argv[1] = NULL;
+		argc = 1;
+		cocoaSetWorkingDirectory();
+	}
+#endif
+
+	// change the working directory to enable doubleclicking in UIs
+#if defined(__BEOS__) || defined(__linux__)
+	ChangeWorkingDirectory(argv[0]);
+#endif
+
+	_random_seeds[1][1] = _random_seeds[1][0] = _random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
+	SeedMT(_random_seeds[0][1]);
+
+	signal(SIGPIPE, SIG_IGN);
+
+	ret = ttd_main(argc, argv);
+
+#ifdef WITH_COCOA
+	cocoaReleaseAutoreleasePool();
+#endif
+
+	return ret;
+}
+
+void DeterminePaths(void)
+{
+	char *s;
+
+	_paths.game_data_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.game_data_dir, GAME_DATA_DIR, MAX_PATH);
+	#if defined SECOND_DATA_DIR
+	_paths.second_data_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.second_data_dir, SECOND_DATA_DIR, MAX_PATH);
+	#endif
+
+#if defined(USE_HOMEDIR)
+	{
+		const char *homedir = getenv("HOME");
+
+		if (homedir == NULL) {
+			const struct passwd *pw = getpwuid(getuid());
+			if (pw != NULL) homedir = pw->pw_dir;
+		}
+
+		_paths.personal_dir = str_fmt("%s" PATHSEP "%s", homedir, PERSONAL_DIR);
+	}
+
+#else /* not defined(USE_HOMEDIR) */
+
+	_paths.personal_dir = malloc(MAX_PATH);
+	ttd_strlcpy(_paths.personal_dir, PERSONAL_DIR, MAX_PATH);
+
+	// check if absolute or relative path
+	s = strchr(_paths.personal_dir, '/');
+
+	// add absolute path
+	if (s == NULL || _paths.personal_dir != s) {
+		getcwd(_paths.personal_dir, MAX_PATH);
+		s = strchr(_paths.personal_dir, 0);
+		*s++ = '/';
+		ttd_strlcpy(s, PERSONAL_DIR, MAX_PATH);
+	}
+
+#endif /* defined(USE_HOMEDIR) */
+
+	s = strchr(_paths.personal_dir, 0);
+
+	// append a / ?
+	if (s[-1] != '/') strcpy(s, "/");
+
+	_paths.save_dir = str_fmt("%ssave", _paths.personal_dir);
+	_paths.autosave_dir = str_fmt("%s/autosave", _paths.save_dir);
+	_paths.scenario_dir = str_fmt("%sscenario", _paths.personal_dir);
+	_paths.heightmap_dir = str_fmt("%sscenario/heightmap", _paths.personal_dir);
+	_paths.gm_dir = str_fmt("%sgm/", _paths.game_data_dir);
+	_paths.data_dir = str_fmt("%sdata/", _paths.game_data_dir);
+
+	if (_config_file == NULL)
+		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
+
+	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
+	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
+
+#if defined CUSTOM_LANG_DIR
+	// sets the search path for lng files to the custom one
+	_paths.lang_dir = malloc( MAX_PATH );
+	ttd_strlcpy( _paths.lang_dir, CUSTOM_LANG_DIR, MAX_PATH);
+#else
+	_paths.lang_dir = str_fmt("%slang/", _paths.game_data_dir);
+#endif
+
+	// create necessary folders
+	mkdir(_paths.personal_dir, 0755);
+	mkdir(_paths.save_dir, 0755);
+	mkdir(_paths.autosave_dir, 0755);
+	mkdir(_paths.scenario_dir, 0755);
+	mkdir(_paths.heightmap_dir, 0755);
+}
+
+bool InsertTextBufferClipboard(Textbuf *tb)
+{
+	return false;
+}
+
+
+// multi os compatible sleep function
+
+#ifdef __AMIGA__
+// usleep() implementation
+#	include <devices/timer.h>
+#	include <dos/dos.h>
+
+	extern struct Device      *TimerBase    = NULL;
+	extern struct MsgPort     *TimerPort    = NULL;
+	extern struct timerequest *TimerRequest = NULL;
+#endif // __AMIGA__
+
+void CSleep(int milliseconds)
+{
+	#if !defined(__BEOS__) && !defined(__AMIGA__)
+		usleep(milliseconds * 1000);
+	#endif
+	#ifdef __BEOS__
+		snooze(milliseconds * 1000);
+	#endif
+	#if defined(__AMIGA__)
+	{
+		ULONG signals;
+		ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
+
+		// send IORequest
+		TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
+		TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
+		TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
+		SendIO((struct IORequest *)TimerRequest);
+
+		if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
+			AbortIO((struct IORequest *)TimerRequest);
+		}
+		WaitIO((struct IORequest *)TimerRequest);
+	}
+	#endif // __AMIGA__
+}
+
+#ifdef WITH_ICONV
+
+#include <iconv.h>
+#include <errno.h>
+#include "debug.h"
+
+#define INTERNALCODE "UTF-8"
+
+/** Try and try to decipher the current locale from environmental
+ * variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable
+ * locale can be found, don't do any conversion "" */
+static const char *GetLocalCode(void)
+{
+#if defined(__APPLE__)
+	return "UTF-8-MAC";
+#else
+	/* Strip locale (eg en_US.UTF-8) to only have UTF-8 */
+	const char *locale = GetCurrentLocale("LC_CTYPE");
+	if (locale != NULL) locale = strchr(locale, '.');
+
+	return (locale == NULL) ? "" : locale + 1;
+#endif
+}
+
+/** FYI: This is not thread-safe.
+ * convert between locales, which from and which to is set in the calling
+ * functions OTTD2FS() and FS2OTTD(). You should NOT use this function directly
+ * NOTE: iconv was added in OSX 10.3. 10.2.x will still have the invalid char
+ * issues. There aren't any easy fix for this */
+static const char *convert_tofrom_fs(iconv_t convd, const char *name)
+{
+	static char buf[1024];
+	/* Work around buggy iconv implementation where inbuf is wrongly typed as
+	 * non-const. Correct implementation is at
+	 * http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html */
+#if defined (__GLIBC__) || defined (__GNU_LIBRARY__)
+	char *inbuf = (char*)name;
+#else
+	const char *inbuf = name;
+#endif
+
+	char *outbuf  = buf;
+	size_t outlen = sizeof(buf) - 1;
+	size_t inlen  = strlen(name);
+
+	ttd_strlcpy(outbuf, name, sizeof(buf));
+
+	iconv(convd, NULL, NULL, NULL, NULL);
+	if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) {
+		DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno);
+	}
+
+	*outbuf = '\0';
+	// FIX: invalid characters will abort conversion, but they shouldn't occur?
+	return buf;
+}
+
+/** Convert from OpenTTD's encoding to that of the local environment
+ * @param name pointer to a valid string that will be converted
+ * @return pointer to a new stringbuffer that contains the converted string */
+const char *OTTD2FS(const char *name)
+{
+	static iconv_t convd = (iconv_t)(-1);
+
+	if (convd == (iconv_t)(-1)) {
+		const char *env = GetLocalCode();
+		convd = iconv_open(env, INTERNALCODE);
+		if (convd == (iconv_t)(-1)) {
+			DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE, env);
+			return name;
+		}
+	}
+
+	return convert_tofrom_fs(convd, name);
+}
+
+/** Convert to OpenTTD's encoding from that of the local environment
+ * @param name pointer to a valid string that will be converted
+ * @return pointer to a new stringbuffer that contains the converted string */
+const char *FS2OTTD(const char *name)
+{
+	static iconv_t convd = (iconv_t)(-1);
+
+	if (convd == (iconv_t)(-1)) {
+		const char *env = GetLocalCode();
+		convd = iconv_open(INTERNALCODE, env);
+		if (convd == (iconv_t)(-1)) {
+			DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env, INTERNALCODE);
+			return name;
+		}
+	}
+
+	return convert_tofrom_fs(convd, name);
+}
+
+#else
+const char *FS2OTTD(const char *name) {return name;}
+const char *OTTD2FS(const char *name) {return name;}
+#endif /* WITH_ICONV */
deleted file mode 100644
--- a/src/unmovable_cmd.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "table/strings.h"
-#include "table/sprites.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "command.h"
-#include "viewport.h"
-#include "player.h"
-#include "gui.h"
-#include "station.h"
-#include "economy.h"
-#include "town.h"
-#include "sprite.h"
-#include "unmovable_map.h"
-#include "variables.h"
-#include "table/unmovable_land.h"
-#include "genworld.h"
-
-/** Destroy a HQ.
- * During normal gameplay you can only implicitely destroy a HQ when you are
- * rebuilding it. Otherwise, only water can destroy it.
- * @param tile tile coordinates where HQ is located to destroy
- * @param flags docommand flags of calling function
- */
-static int32 DestroyCompanyHQ(PlayerID pid, uint32 flags)
-{
-	Player* p = GetPlayer(pid);
-
-	SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
-
-	if (flags & DC_EXEC) {
-		TileIndex t = p->location_of_house;
-
-		DoClearSquare(t + TileDiffXY(0, 0));
-		DoClearSquare(t + TileDiffXY(0, 1));
-		DoClearSquare(t + TileDiffXY(1, 0));
-		DoClearSquare(t + TileDiffXY(1, 1));
-		p->location_of_house = 0; // reset HQ position
-		InvalidateWindow(WC_COMPANY, pid);
-	}
-
-	// cost of relocating company is 1% of company value
-	return CalculateCompanyValue(p) / 100;
-}
-
-void UpdateCompanyHQ(Player *p, uint score)
-{
-	byte val;
-	TileIndex tile = p->location_of_house;
-
-	if (tile == 0) return;
-
-	(val = 0, score < 170) ||
-	(val++, score < 350) ||
-	(val++, score < 520) ||
-	(val++, score < 720) ||
-	(val++, true);
-
-	EnlargeCompanyHQ(tile, val);
-
-	MarkTileDirtyByTile(tile + TileDiffXY(0, 0));
-	MarkTileDirtyByTile(tile + TileDiffXY(0, 1));
-	MarkTileDirtyByTile(tile + TileDiffXY(1, 0));
-	MarkTileDirtyByTile(tile + TileDiffXY(1, 1));
-}
-
-/** Build or relocate the HQ. This depends if the HQ is already built or not
- * @param tile tile where the HQ will be built or relocated to
- * @param p1 unused
- * @param p2 unused
- */
-extern int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, int *);
-int32 CmdBuildCompanyHQ(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Player *p = GetPlayer(_current_player);
-	int cost;
-	int32 ret;
-
-	SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
-
-	ret = CheckFlatLandBelow(tile, 2, 2, flags, 0, NULL);
-	if (CmdFailed(ret)) return ret;
-	cost = ret;
-
-	if (p->location_of_house != 0) { /* Moving HQ */
-		cost += DestroyCompanyHQ(_current_player, flags);
-	}
-
-	if (flags & DC_EXEC) {
-		int score = UpdateCompanyRatingAndValue(p, false);
-
-		p->location_of_house = tile;
-
-		MakeCompanyHQ(tile, _current_player);
-
-		UpdateCompanyHQ(p, score);
-		InvalidateWindow(WC_COMPANY, p->index);
-	}
-
-	return cost;
-}
-
-static void DrawTile_Unmovable(TileInfo *ti)
-{
-	uint32 image, ormod;
-
-	switch (GetUnmovableType(ti->tile)) {
-		case UNMOVABLE_TRANSMITTER:
-		case UNMOVABLE_LIGHTHOUSE: {
-			const DrawTileUnmovableStruct* dtus;
-
-			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-			DrawClearLandTile(ti, 2);
-
-			dtus = &_draw_tile_unmovable_data[GetUnmovableType(ti->tile)];
-
-			image = dtus->image;
-			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-			AddSortableSpriteToDraw(
-				image, ti->x | dtus->subcoord_x, ti->y | dtus->subcoord_y,
-				dtus->width, dtus->height, dtus->z_size, ti->z
-			);
-			break;
-		}
-
-		case UNMOVABLE_STATUE:
-			DrawGroundSprite(SPR_CONCRETE_GROUND);
-
-			image = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
-			image += PALETTE_MODIFIER_COLOR | SPR_STATUE_COMPANY;
-			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-			AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 25, ti->z);
-			break;
-
-		case UNMOVABLE_OWNED_LAND:
-			DrawClearLandTile(ti, 0);
-
-			AddSortableSpriteToDraw(
-				PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)) + PALETTE_MODIFIER_COLOR + SPR_BOUGHT_LAND,
-				ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 10, GetSlopeZ(ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2)
-			);
-			DrawBridgeMiddle(ti);
-			break;
-
-		default: {
-			const DrawTileSeqStruct* dtss;
-			const DrawTileSprites* t;
-
-			assert(IsCompanyHQ(ti->tile));
-			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
-
-			ormod = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
-
-			t = &_unmovable_display_datas[GetCompanyHQSection(ti->tile)];
-			DrawGroundSprite(t->ground_sprite | ormod);
-
-			foreach_draw_tile_seq(dtss, t->seq) {
-				image = dtss->image;
-				if (_display_opt & DO_TRANS_BUILDINGS) {
-					MAKE_TRANSPARENT(image);
-				} else {
-					image |= ormod;
-				}
-				AddSortableSpriteToDraw(
-					image,
-					ti->x + dtss->delta_x, ti->y + dtss->delta_y,
-					dtss->size_x, dtss->size_y,
-					dtss->size_z, ti->z + dtss->delta_z
-				);
-			}
-			break;
-		}
-	}
-}
-
-static uint GetSlopeZ_Unmovable(TileIndex tile, uint x, uint y)
-{
-	if (IsOwnedLand(tile)) {
-		uint z;
-		uint tileh = GetTileSlope(tile, &z);
-
-		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-	} else {
-		return GetTileMaxZ(tile);
-	}
-}
-
-static Slope GetSlopeTileh_Unmovable(TileIndex tile, Slope tileh)
-{
-	return IsOwnedLand(tile) ? tileh : SLOPE_FLAT;
-}
-
-static int32 ClearTile_Unmovable(TileIndex tile, byte flags)
-{
-	if (IsCompanyHQ(tile)) {
-		if (_current_player == OWNER_WATER) {
-			return DestroyCompanyHQ(GetTileOwner(tile), DC_EXEC);
-		} else {
-			return_cmd_error(STR_5804_COMPANY_HEADQUARTERS_IN);
-		}
-	}
-
-	if (IsOwnedLand(tile)) {
-		return DoCommand(tile, 0, 0, flags, CMD_SELL_LAND_AREA);
-	}
-
-	// checks if you're allowed to remove unmovable things
-	if (_game_mode != GM_EDITOR && _current_player != OWNER_WATER && ((flags & DC_AUTO || !_cheats.magic_bulldozer.value)) )
-		return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
-
-	if (flags & DC_EXEC) {
-		DoClearSquare(tile);
-	}
-
-	return 0;
-}
-
-static void GetAcceptedCargo_Unmovable(TileIndex tile, AcceptedCargo ac)
-{
-	uint level; // HQ level (depends on company performance) in the range 1..5.
-
-	if (!IsCompanyHQ(tile)) return;
-
-	/* HQ accepts passenger and mail; but we have to divide the values
-	 * between 4 tiles it occupies! */
-
-	level = GetCompanyHQSize(tile) + 1;
-
-	// Top town building generates 10, so to make HQ interesting, the top
-	// type makes 20.
-	ac[CT_PASSENGERS] = max(1, level);
-
-	// Top town building generates 4, HQ can make up to 8. The
-	// proportion passengers:mail is different because such a huge
-	// commercial building generates unusually high amount of mail
-	// correspondence per physical visitor.
-	ac[CT_MAIL] = max(1, level / 2);
-}
-
-
-static void GetTileDesc_Unmovable(TileIndex tile, TileDesc *td)
-{
-	switch (GetUnmovableType(tile)) {
-		case UNMOVABLE_TRANSMITTER: td->str = STR_5801_TRANSMITTER; break;
-		case UNMOVABLE_LIGHTHOUSE:  td->str = STR_5802_LIGHTHOUSE; break;
-		case UNMOVABLE_STATUE:      td->str = STR_2016_STATUE; break;
-		case UNMOVABLE_OWNED_LAND:  td->str = STR_5805_COMPANY_OWNED_LAND; break;
-		default:                    td->str = STR_5803_COMPANY_HEADQUARTERS; break;
-	}
-	td->owner = GetTileOwner(tile);
-}
-
-static void AnimateTile_Unmovable(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoop_Unmovable(TileIndex tile)
-{
-	uint level; // HQ level (depends on company performance) in the range 1..5.
-	uint32 r;
-
-	if (!IsCompanyHQ(tile)) return;
-
-	/* HQ accepts passenger and mail; but we have to divide the values
-	 * between 4 tiles it occupies! */
-
-	level = GetCompanyHQSize(tile) + 1;
-	assert(level < 6);
-
-	r = Random();
-	// Top town buildings generate 250, so the top HQ type makes 256.
-	if (GB(r, 0, 8) < (256 / 4 / (6 - level))) {
-		uint amt = GB(r, 0, 8) / 8 / 4 + 1;
-		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-		MoveGoodsToStation(tile, 2, 2, CT_PASSENGERS, amt);
-	}
-
-	// Top town building generates 90, HQ can make up to 196. The
-	// proportion passengers:mail is about the same as in the acceptance
-	// equations.
-	if (GB(r, 8, 8) < (196 / 4 / (6 - level))) {
-		uint amt = GB(r, 8, 8) / 8 / 4 + 1;
-		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-		MoveGoodsToStation(tile, 2, 2, CT_MAIL, amt);
-	}
-}
-
-
-static uint32 GetTileTrackStatus_Unmovable(TileIndex tile, TransportType mode)
-{
-	return 0;
-}
-
-static void ClickTile_Unmovable(TileIndex tile)
-{
-	if (IsCompanyHQ(tile)) ShowPlayerCompany(GetTileOwner(tile));
-}
-
-
-/* checks, if a radio tower is within a 9x9 tile square around tile */
-static bool IsRadioTowerNearby(TileIndex tile)
-{
-	TileIndex tile_s = tile - TileDiffXY(4, 4);
-
-	BEGIN_TILE_LOOP(tile, 9, 9, tile_s)
-		if (IsTransmitterTile(tile)) return true;
-	END_TILE_LOOP(tile, 9, 9, tile_s)
-
-	return false;
-}
-
-void GenerateUnmovables(void)
-{
-	int i, li, j, loop_count;
-	TileIndex tile;
-	uint h;
-	uint maxx;
-	uint maxy;
-
-	if (_opt.landscape == LT_CANDY) return;
-
-	/* add radio tower */
-	i = ScaleByMapSize(1000);
-	j = ScaleByMapSize(15); // maximum number of radio towers on the map
-	li = ScaleByMapSize1D((Random() & 3) + 7);
-	SetGeneratingWorldProgress(GWP_UNMOVABLE, j + li);
-
-	do {
-		tile = RandomTile();
-		if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h >= TILE_HEIGHT * 4) {
-			if (IsRadioTowerNearby(tile)) continue;
-			MakeTransmitter(tile);
-			IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
-			if (--j == 0) break;
-		}
-	} while (--i);
-
-	if (_opt.landscape == LT_DESERT) return;
-
-	/* add lighthouses */
-	i = li;
-	maxx = MapMaxX();
-	maxy = MapMaxY();
-	loop_count = 0;
-	do {
-		uint32 r;
-		DiagDirection dir;
-		int perimeter;
-
-restart:
-		/* Avoid infinite loops */
-		if (++loop_count > 1000) break;
-
-		r = Random();
-
-		/* Scatter the lighthouses more evenly around the perimeter */
-		perimeter = (GB(r, 16, 16) % (2 * (maxx + maxy))) - maxy;
-		for (dir = DIAGDIR_NE; perimeter > 0; dir++) {
-			perimeter -= (DiagDirToAxis(dir) == AXIS_X) ? maxx : maxy;
-		}
-
-		switch (dir) {
-			default:
-			case DIAGDIR_NE: tile = TileXY(maxx,     r % maxy); break;
-			case DIAGDIR_SE: tile = TileXY(r % maxx, 0);        break;
-			case DIAGDIR_SW: tile = TileXY(0,        r % maxy); break;
-			case DIAGDIR_NW: tile = TileXY(r % maxx, maxy);     break;
-		}
-		j = 20;
-		do {
-			if (--j == 0) goto restart;
-			tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
-		} while (!(IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h <= TILE_HEIGHT * 2));
-
-		assert(tile == TILE_MASK(tile));
-
-		MakeLighthouse(tile);
-		IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
-	} while (--i);
-}
-
-static void ChangeTileOwner_Unmovable(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (IsOwnedLand(tile) && new_player != PLAYER_SPECTATOR) {
-		SetTileOwner(tile, new_player);
-	} else {
-		DoClearSquare(tile);
-	}
-}
-
-const TileTypeProcs _tile_type_unmovable_procs = {
-	DrawTile_Unmovable,             /* draw_tile_proc */
-	GetSlopeZ_Unmovable,            /* get_slope_z_proc */
-	ClearTile_Unmovable,            /* clear_tile_proc */
-	GetAcceptedCargo_Unmovable,     /* get_accepted_cargo_proc */
-	GetTileDesc_Unmovable,          /* get_tile_desc_proc */
-	GetTileTrackStatus_Unmovable,   /* get_tile_track_status_proc */
-	ClickTile_Unmovable,            /* click_tile_proc */
-	AnimateTile_Unmovable,          /* animate_tile_proc */
-	TileLoop_Unmovable,             /* tile_loop_clear */
-	ChangeTileOwner_Unmovable,      /* change_tile_owner_clear */
-	NULL,                           /* get_produced_cargo_proc */
-	NULL,                           /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Unmovable,        /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/unmovable_cmd.cpp
@@ -0,0 +1,414 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "command.h"
+#include "viewport.h"
+#include "player.h"
+#include "gui.h"
+#include "station.h"
+#include "economy.h"
+#include "town.h"
+#include "sprite.h"
+#include "unmovable_map.h"
+#include "variables.h"
+#include "table/unmovable_land.h"
+#include "genworld.h"
+
+/** Destroy a HQ.
+ * During normal gameplay you can only implicitely destroy a HQ when you are
+ * rebuilding it. Otherwise, only water can destroy it.
+ * @param tile tile coordinates where HQ is located to destroy
+ * @param flags docommand flags of calling function
+ */
+static int32 DestroyCompanyHQ(PlayerID pid, uint32 flags)
+{
+	Player* p = GetPlayer(pid);
+
+	SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
+
+	if (flags & DC_EXEC) {
+		TileIndex t = p->location_of_house;
+
+		DoClearSquare(t + TileDiffXY(0, 0));
+		DoClearSquare(t + TileDiffXY(0, 1));
+		DoClearSquare(t + TileDiffXY(1, 0));
+		DoClearSquare(t + TileDiffXY(1, 1));
+		p->location_of_house = 0; // reset HQ position
+		InvalidateWindow(WC_COMPANY, pid);
+	}
+
+	// cost of relocating company is 1% of company value
+	return CalculateCompanyValue(p) / 100;
+}
+
+void UpdateCompanyHQ(Player *p, uint score)
+{
+	byte val;
+	TileIndex tile = p->location_of_house;
+
+	if (tile == 0) return;
+
+	(val = 0, score < 170) ||
+	(val++, score < 350) ||
+	(val++, score < 520) ||
+	(val++, score < 720) ||
+	(val++, true);
+
+	EnlargeCompanyHQ(tile, val);
+
+	MarkTileDirtyByTile(tile + TileDiffXY(0, 0));
+	MarkTileDirtyByTile(tile + TileDiffXY(0, 1));
+	MarkTileDirtyByTile(tile + TileDiffXY(1, 0));
+	MarkTileDirtyByTile(tile + TileDiffXY(1, 1));
+}
+
+/** Build or relocate the HQ. This depends if the HQ is already built or not
+ * @param tile tile where the HQ will be built or relocated to
+ * @param p1 unused
+ * @param p2 unused
+ */
+extern int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, int *);
+int32 CmdBuildCompanyHQ(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Player *p = GetPlayer(_current_player);
+	int cost;
+	int32 ret;
+
+	SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
+
+	ret = CheckFlatLandBelow(tile, 2, 2, flags, 0, NULL);
+	if (CmdFailed(ret)) return ret;
+	cost = ret;
+
+	if (p->location_of_house != 0) { /* Moving HQ */
+		cost += DestroyCompanyHQ(_current_player, flags);
+	}
+
+	if (flags & DC_EXEC) {
+		int score = UpdateCompanyRatingAndValue(p, false);
+
+		p->location_of_house = tile;
+
+		MakeCompanyHQ(tile, _current_player);
+
+		UpdateCompanyHQ(p, score);
+		InvalidateWindow(WC_COMPANY, p->index);
+	}
+
+	return cost;
+}
+
+static void DrawTile_Unmovable(TileInfo *ti)
+{
+	uint32 image, ormod;
+
+	switch (GetUnmovableType(ti->tile)) {
+		case UNMOVABLE_TRANSMITTER:
+		case UNMOVABLE_LIGHTHOUSE: {
+			const DrawTileUnmovableStruct* dtus;
+
+			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+			DrawClearLandTile(ti, 2);
+
+			dtus = &_draw_tile_unmovable_data[GetUnmovableType(ti->tile)];
+
+			image = dtus->image;
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+			AddSortableSpriteToDraw(
+				image, ti->x | dtus->subcoord_x, ti->y | dtus->subcoord_y,
+				dtus->width, dtus->height, dtus->z_size, ti->z
+			);
+			break;
+		}
+
+		case UNMOVABLE_STATUE:
+			DrawGroundSprite(SPR_CONCRETE_GROUND);
+
+			image = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
+			image += PALETTE_MODIFIER_COLOR | SPR_STATUE_COMPANY;
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+			AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 25, ti->z);
+			break;
+
+		case UNMOVABLE_OWNED_LAND:
+			DrawClearLandTile(ti, 0);
+
+			AddSortableSpriteToDraw(
+				PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)) + PALETTE_MODIFIER_COLOR + SPR_BOUGHT_LAND,
+				ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 10, GetSlopeZ(ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2)
+			);
+			DrawBridgeMiddle(ti);
+			break;
+
+		default: {
+			const DrawTileSeqStruct* dtss;
+			const DrawTileSprites* t;
+
+			assert(IsCompanyHQ(ti->tile));
+			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh);
+
+			ormod = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
+
+			t = &_unmovable_display_datas[GetCompanyHQSection(ti->tile)];
+			DrawGroundSprite(t->ground_sprite | ormod);
+
+			foreach_draw_tile_seq(dtss, t->seq) {
+				image = dtss->image;
+				if (_display_opt & DO_TRANS_BUILDINGS) {
+					MAKE_TRANSPARENT(image);
+				} else {
+					image |= ormod;
+				}
+				AddSortableSpriteToDraw(
+					image,
+					ti->x + dtss->delta_x, ti->y + dtss->delta_y,
+					dtss->size_x, dtss->size_y,
+					dtss->size_z, ti->z + dtss->delta_z
+				);
+			}
+			break;
+		}
+	}
+}
+
+static uint GetSlopeZ_Unmovable(TileIndex tile, uint x, uint y)
+{
+	if (IsOwnedLand(tile)) {
+		uint z;
+		uint tileh = GetTileSlope(tile, &z);
+
+		return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+	} else {
+		return GetTileMaxZ(tile);
+	}
+}
+
+static Slope GetSlopeTileh_Unmovable(TileIndex tile, Slope tileh)
+{
+	return IsOwnedLand(tile) ? tileh : SLOPE_FLAT;
+}
+
+static int32 ClearTile_Unmovable(TileIndex tile, byte flags)
+{
+	if (IsCompanyHQ(tile)) {
+		if (_current_player == OWNER_WATER) {
+			return DestroyCompanyHQ(GetTileOwner(tile), DC_EXEC);
+		} else {
+			return_cmd_error(STR_5804_COMPANY_HEADQUARTERS_IN);
+		}
+	}
+
+	if (IsOwnedLand(tile)) {
+		return DoCommand(tile, 0, 0, flags, CMD_SELL_LAND_AREA);
+	}
+
+	// checks if you're allowed to remove unmovable things
+	if (_game_mode != GM_EDITOR && _current_player != OWNER_WATER && ((flags & DC_AUTO || !_cheats.magic_bulldozer.value)) )
+		return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
+
+	if (flags & DC_EXEC) {
+		DoClearSquare(tile);
+	}
+
+	return 0;
+}
+
+static void GetAcceptedCargo_Unmovable(TileIndex tile, AcceptedCargo ac)
+{
+	uint level; // HQ level (depends on company performance) in the range 1..5.
+
+	if (!IsCompanyHQ(tile)) return;
+
+	/* HQ accepts passenger and mail; but we have to divide the values
+	 * between 4 tiles it occupies! */
+
+	level = GetCompanyHQSize(tile) + 1;
+
+	// Top town building generates 10, so to make HQ interesting, the top
+	// type makes 20.
+	ac[CT_PASSENGERS] = max(1, level);
+
+	// Top town building generates 4, HQ can make up to 8. The
+	// proportion passengers:mail is different because such a huge
+	// commercial building generates unusually high amount of mail
+	// correspondence per physical visitor.
+	ac[CT_MAIL] = max(1, level / 2);
+}
+
+
+static void GetTileDesc_Unmovable(TileIndex tile, TileDesc *td)
+{
+	switch (GetUnmovableType(tile)) {
+		case UNMOVABLE_TRANSMITTER: td->str = STR_5801_TRANSMITTER; break;
+		case UNMOVABLE_LIGHTHOUSE:  td->str = STR_5802_LIGHTHOUSE; break;
+		case UNMOVABLE_STATUE:      td->str = STR_2016_STATUE; break;
+		case UNMOVABLE_OWNED_LAND:  td->str = STR_5805_COMPANY_OWNED_LAND; break;
+		default:                    td->str = STR_5803_COMPANY_HEADQUARTERS; break;
+	}
+	td->owner = GetTileOwner(tile);
+}
+
+static void AnimateTile_Unmovable(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoop_Unmovable(TileIndex tile)
+{
+	uint level; // HQ level (depends on company performance) in the range 1..5.
+	uint32 r;
+
+	if (!IsCompanyHQ(tile)) return;
+
+	/* HQ accepts passenger and mail; but we have to divide the values
+	 * between 4 tiles it occupies! */
+
+	level = GetCompanyHQSize(tile) + 1;
+	assert(level < 6);
+
+	r = Random();
+	// Top town buildings generate 250, so the top HQ type makes 256.
+	if (GB(r, 0, 8) < (256 / 4 / (6 - level))) {
+		uint amt = GB(r, 0, 8) / 8 / 4 + 1;
+		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
+		MoveGoodsToStation(tile, 2, 2, CT_PASSENGERS, amt);
+	}
+
+	// Top town building generates 90, HQ can make up to 196. The
+	// proportion passengers:mail is about the same as in the acceptance
+	// equations.
+	if (GB(r, 8, 8) < (196 / 4 / (6 - level))) {
+		uint amt = GB(r, 8, 8) / 8 / 4 + 1;
+		if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
+		MoveGoodsToStation(tile, 2, 2, CT_MAIL, amt);
+	}
+}
+
+
+static uint32 GetTileTrackStatus_Unmovable(TileIndex tile, TransportType mode)
+{
+	return 0;
+}
+
+static void ClickTile_Unmovable(TileIndex tile)
+{
+	if (IsCompanyHQ(tile)) ShowPlayerCompany(GetTileOwner(tile));
+}
+
+
+/* checks, if a radio tower is within a 9x9 tile square around tile */
+static bool IsRadioTowerNearby(TileIndex tile)
+{
+	TileIndex tile_s = tile - TileDiffXY(4, 4);
+
+	BEGIN_TILE_LOOP(tile, 9, 9, tile_s)
+		if (IsTransmitterTile(tile)) return true;
+	END_TILE_LOOP(tile, 9, 9, tile_s)
+
+	return false;
+}
+
+void GenerateUnmovables(void)
+{
+	int i, li, j, loop_count;
+	TileIndex tile;
+	uint h;
+	uint maxx;
+	uint maxy;
+
+	if (_opt.landscape == LT_CANDY) return;
+
+	/* add radio tower */
+	i = ScaleByMapSize(1000);
+	j = ScaleByMapSize(15); // maximum number of radio towers on the map
+	li = ScaleByMapSize1D((Random() & 3) + 7);
+	SetGeneratingWorldProgress(GWP_UNMOVABLE, j + li);
+
+	do {
+		tile = RandomTile();
+		if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h >= TILE_HEIGHT * 4) {
+			if (IsRadioTowerNearby(tile)) continue;
+			MakeTransmitter(tile);
+			IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
+			if (--j == 0) break;
+		}
+	} while (--i);
+
+	if (_opt.landscape == LT_DESERT) return;
+
+	/* add lighthouses */
+	i = li;
+	maxx = MapMaxX();
+	maxy = MapMaxY();
+	loop_count = 0;
+	do {
+		uint32 r;
+		DiagDirection dir;
+		int perimeter;
+
+restart:
+		/* Avoid infinite loops */
+		if (++loop_count > 1000) break;
+
+		r = Random();
+
+		/* Scatter the lighthouses more evenly around the perimeter */
+		perimeter = (GB(r, 16, 16) % (2 * (maxx + maxy))) - maxy;
+		for (dir = DIAGDIR_NE; perimeter > 0; dir++) {
+			perimeter -= (DiagDirToAxis(dir) == AXIS_X) ? maxx : maxy;
+		}
+
+		switch (dir) {
+			default:
+			case DIAGDIR_NE: tile = TileXY(maxx,     r % maxy); break;
+			case DIAGDIR_SE: tile = TileXY(r % maxx, 0);        break;
+			case DIAGDIR_SW: tile = TileXY(0,        r % maxy); break;
+			case DIAGDIR_NW: tile = TileXY(r % maxx, maxy);     break;
+		}
+		j = 20;
+		do {
+			if (--j == 0) goto restart;
+			tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
+		} while (!(IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h <= TILE_HEIGHT * 2));
+
+		assert(tile == TILE_MASK(tile));
+
+		MakeLighthouse(tile);
+		IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
+	} while (--i);
+}
+
+static void ChangeTileOwner_Unmovable(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (IsOwnedLand(tile) && new_player != PLAYER_SPECTATOR) {
+		SetTileOwner(tile, new_player);
+	} else {
+		DoClearSquare(tile);
+	}
+}
+
+const TileTypeProcs _tile_type_unmovable_procs = {
+	DrawTile_Unmovable,             /* draw_tile_proc */
+	GetSlopeZ_Unmovable,            /* get_slope_z_proc */
+	ClearTile_Unmovable,            /* clear_tile_proc */
+	GetAcceptedCargo_Unmovable,     /* get_accepted_cargo_proc */
+	GetTileDesc_Unmovable,          /* get_tile_desc_proc */
+	GetTileTrackStatus_Unmovable,   /* get_tile_track_status_proc */
+	ClickTile_Unmovable,            /* click_tile_proc */
+	AnimateTile_Unmovable,          /* animate_tile_proc */
+	TileLoop_Unmovable,             /* tile_loop_clear */
+	ChangeTileOwner_Unmovable,      /* change_tile_owner_clear */
+	NULL,                           /* get_produced_cargo_proc */
+	NULL,                           /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Unmovable,        /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/vehicle.c
+++ /dev/null
@@ -1,3228 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "road_map.h"
-#include "roadveh.h"
-#include "ship.h"
-#include "spritecache.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
-#include "gfx.h"
-#include "viewport.h"
-#include "news.h"
-#include "command.h"
-#include "saveload.h"
-#include "player.h"
-#include "engine.h"
-#include "sound.h"
-#include "debug.h"
-#include "vehicle_gui.h"
-#include "depot.h"
-#include "station.h"
-#include "rail.h"
-#include "train.h"
-#include "aircraft.h"
-#include "industry_map.h"
-#include "station_map.h"
-#include "water_map.h"
-#include "network/network.h"
-#include "yapf/yapf.h"
-#include "date.h"
-#include "newgrf_engine.h"
-#include "newgrf_sound.h"
-
-#define INVALID_COORD (-0x8000)
-#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
-
-/*
- * These command macros are used to call vehicle type specific commands with non type specific commands
- * it should be used like: DoCommandP(x, y, p1, p2, flags, CMD_STARTSTOP_VEH(v->type))
- * that line will start/stop a vehicle nomatter what type it is
- * VEH_Train is used as an offset because the vehicle type values doesn't start with 0
- */
-
-#define CMD_BUILD_VEH(x) _veh_build_proc_table[ x - VEH_Train]
-#define CMD_SELL_VEH(x)  _veh_sell_proc_table [ x - VEH_Train]
-#define CMD_REFIT_VEH(x) _veh_refit_proc_table[ x - VEH_Train]
-
-static const uint32 _veh_build_proc_table[] = {
-	CMD_BUILD_RAIL_VEHICLE,
-	CMD_BUILD_ROAD_VEH,
-	CMD_BUILD_SHIP,
-	CMD_BUILD_AIRCRAFT,
-};
-static const uint32 _veh_sell_proc_table[] = {
-	CMD_SELL_RAIL_WAGON,
-	CMD_SELL_ROAD_VEH,
-	CMD_SELL_SHIP,
-	CMD_SELL_AIRCRAFT,
-};
-
-static const uint32 _veh_refit_proc_table[] = {
-	CMD_REFIT_RAIL_VEHICLE,
-	CMD_REFIT_ROAD_VEH,
-	CMD_REFIT_SHIP,
-	CMD_REFIT_AIRCRAFT,
-};
-
-const uint32 _send_to_depot_proc_table[] = {
-	CMD_SEND_TRAIN_TO_DEPOT,
-	CMD_SEND_ROADVEH_TO_DEPOT,
-	CMD_SEND_SHIP_TO_DEPOT,
-	CMD_SEND_AIRCRAFT_TO_HANGAR,
-};
-
-
-enum {
-	BLOCKS_FOR_SPECIAL_VEHICLES   = 2, ///< Blocks needed for special vehicles
-};
-
-/**
- * Called if a new block is added to the vehicle-pool
- */
-static void VehiclePoolNewBlock(uint start_item)
-{
-	Vehicle *v;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) v->index = start_item++;
-}
-
-/* Initialize the vehicle-pool */
-DEFINE_OLD_POOL(Vehicle, Vehicle, VehiclePoolNewBlock, NULL)
-
-void VehicleServiceInDepot(Vehicle *v)
-{
-	v->date_of_last_service = _date;
-	v->breakdowns_since_last_service = 0;
-	v->reliability = GetEngine(v->engine_type)->reliability;
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
-}
-
-bool VehicleNeedsService(const Vehicle *v)
-{
-	if (v->vehstatus & VS_CRASHED)
-		return false; /* Crashed vehicles don't need service anymore */
-
-	if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
-		return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type);  /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */
-	}
-
-	return _patches.servint_ispercent ?
-		(v->reliability < GetEngine(v->engine_type)->reliability * (100 - v->service_interval) / 100) :
-		(v->date_of_last_service + v->service_interval < _date);
-}
-
-StringID VehicleInTheWayErrMsg(const Vehicle* v)
-{
-	switch (v->type) {
-		case VEH_Train:    return STR_8803_TRAIN_IN_THE_WAY;
-		case VEH_Road:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
-		case VEH_Aircraft: return STR_A015_AIRCRAFT_IN_THE_WAY;
-		default:           return STR_980E_SHIP_IN_THE_WAY;
-	}
-}
-
-static void *EnsureNoVehicleProc(Vehicle *v, void *data)
-{
-	if (v->tile != *(const TileIndex*)data || v->type == VEH_Disaster)
-		return NULL;
-
-	_error_message = VehicleInTheWayErrMsg(v);
-	return v;
-}
-
-bool EnsureNoVehicle(TileIndex tile)
-{
-	return VehicleFromPos(tile, &tile, EnsureNoVehicleProc) == NULL;
-}
-
-static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
-{
-	const TileInfo *ti = data;
-
-	if (v->tile != ti->tile || v->type == VEH_Disaster) return NULL;
-	if (v->z_pos > ti->z) return NULL;
-
-	_error_message = VehicleInTheWayErrMsg(v);
-	return v;
-}
-
-
-bool EnsureNoVehicleOnGround(TileIndex tile)
-{
-	TileInfo ti;
-
-	ti.tile = tile;
-	ti.z = GetTileMaxZ(tile);
-	return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ) == NULL;
-}
-
-Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
-{
-	TileInfo ti;
-
-	ti.tile = tile;
-	ti.z = z;
-
-	return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ);
-}
-
-Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z)
-{
-	int x1 = TileX(from);
-	int y1 = TileY(from);
-	int x2 = TileX(to);
-	int y2 = TileY(to);
-	Vehicle *veh;
-
-	/* Make sure x1 < x2 or y1 < y2 */
-	if (x1 > x2 || y1 > y2) {
-		intswap(x1,x2);
-		intswap(y1,y2);
-	}
-	FOR_ALL_VEHICLES(veh) {
-		if ((veh->type == VEH_Train || veh->type == VEH_Road) && (z==0xFF || veh->z_pos == z)) {
-			if ((veh->x_pos>>4) >= x1 && (veh->x_pos>>4) <= x2 &&
-					(veh->y_pos>>4) >= y1 && (veh->y_pos>>4) <= y2) {
-				return veh;
-			}
-		}
-	}
-	return NULL;
-}
-
-
-static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
-
-void VehiclePositionChanged(Vehicle *v)
-{
-	int img = v->cur_image;
-	Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
-	const Sprite* spr = GetSprite(img);
-
-	pt.x += spr->x_offs;
-	pt.y += spr->y_offs;
-
-	UpdateVehiclePosHash(v, pt.x, pt.y);
-
-	v->left_coord = pt.x;
-	v->top_coord = pt.y;
-	v->right_coord = pt.x + spr->width + 2;
-	v->bottom_coord = pt.y + spr->height + 2;
-}
-
-// Called after load to update coordinates
-void AfterLoadVehicles(void)
-{
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		v->first = NULL;
-		if (v->type == VEH_Train) v->u.rail.first_engine = INVALID_ENGINE;
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))
-			TrainConsistChanged(v);
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		switch (v->type) {
-			case VEH_Train: v->cur_image = GetTrainImage(v, v->direction); break;
-			case VEH_Road: v->cur_image = GetRoadVehImage(v, v->direction); break;
-			case VEH_Ship: v->cur_image = GetShipImage(v, v->direction); break;
-			case VEH_Aircraft:
-				if (v->subtype == 0 || v->subtype == 2) {
-					v->cur_image = GetAircraftImage(v, v->direction);
-					if (v->next != NULL) v->next->cur_image = v->cur_image;
-				}
-				break;
-			default: break;
-		}
-
-		v->left_coord = INVALID_COORD;
-		VehiclePositionChanged(v);
-	}
-}
-
-static Vehicle *InitializeVehicle(Vehicle *v)
-{
-	VehicleID index = v->index;
-	memset(v, 0, sizeof(Vehicle));
-	v->index = index;
-
-	assert(v->orders == NULL);
-
-	v->left_coord = INVALID_COORD;
-	v->first = NULL;
-	v->next = NULL;
-	v->next_hash = NULL;
-	v->string_id = 0;
-	v->next_shared = NULL;
-	v->prev_shared = NULL;
-	v->depot_list  = NULL;
-	v->random_bits = 0;
-	return v;
-}
-
-/**
- * Get a value for a vehicle's random_bits.
- * @return A random value from 0 to 255.
- */
-byte VehicleRandomBits(void)
-{
-	return GB(Random(), 0, 8);
-}
-
-Vehicle *ForceAllocateSpecialVehicle(void)
-{
-	/* This stays a strange story.. there should always be room for special
-	 * vehicles (special effects all over the map), but with 65k of vehicles
-	 * is this realistic to double-check for that? For now we just reserve
-	 * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only
-	 * be used for special vehicles.. should work nicely :) */
-
-	Vehicle *v;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (v = GetVehicle(0); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
-		/* No more room for the special vehicles, return NULL */
-		if (v->index >= (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES)
-			return NULL;
-
-		if (!IsValidVehicle(v)) return InitializeVehicle(v);
-	}
-
-	return NULL;
-}
-
-/*
- * finds a free vehicle in the memory or allocates a new one
- * returns a pointer to the first free vehicle or NULL if all vehicles are in use
- * *skip_vehicles is an offset to where in the array we should begin looking
- * this is to avoid looping though the same vehicles more than once after we learned that they are not free
- * this feature is used by AllocateVehicles() since it need to allocate more than one and when
- * another block is added to _Vehicle_pool, since we only do that when we know it's already full
- */
-static Vehicle *AllocateSingleVehicle(VehicleID *skip_vehicles)
-{
-	/* See note by ForceAllocateSpecialVehicle() why we skip the
-	 * first blocks */
-	Vehicle *v;
-	const int offset = (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	if (*skip_vehicles < (_Vehicle_pool.total_items - offset)) { // make sure the offset in the array is not larger than the array itself
-		for (v = GetVehicle(offset + *skip_vehicles); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
-			(*skip_vehicles)++;
-			if (!IsValidVehicle(v)) return InitializeVehicle(v);
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Vehicle_pool))
-		return AllocateSingleVehicle(skip_vehicles);
-
-	return NULL;
-}
-
-
-Vehicle *AllocateVehicle(void)
-{
-	VehicleID counter = 0;
-	return AllocateSingleVehicle(&counter);
-}
-
-
-/** Allocates a lot of vehicles and frees them again
- * @param vl pointer to an array of vehicles to get allocated. Can be NULL if the vehicles aren't needed (makes it test only)
- * @param num number of vehicles to allocate room for
- * @return true if there is room to allocate all the vehicles
- */
-bool AllocateVehicles(Vehicle **vl, int num)
-{
-	int i;
-	Vehicle *v;
-	VehicleID counter = 0;
-
-	for (i = 0; i != num; i++) {
-		v = AllocateSingleVehicle(&counter);
-		if (v == NULL) {
-			return false;
-		}
-		if (vl != NULL) {
-			vl[i] = v;
-		}
-	}
-
-	return true;
-}
-
-
-static Vehicle *_vehicle_position_hash[0x1000];
-
-void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
-{
-	Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, 0);
-
-	// The hash area to scan
-	const int xl = GB(pt.x - 174, 7, 6);
-	const int xu = GB(pt.x + 104, 7, 6);
-	const int yl = GB(pt.y - 294, 6, 6) << 6;
-	const int yu = GB(pt.y +  56, 6, 6) << 6;
-
-	int x;
-	int y;
-
-	for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
-		for (x = xl;; x = (x + 1) & 0x3F) {
-			Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF];
-
-			while (v != NULL) {
-				void* a = proc(v, data);
-
-				if (a != NULL) return a;
-				v = v->next_hash;
-			}
-
-			if (x == xu) break;
-		}
-
-		if (y == yu) break;
-	}
-	return NULL;
-}
-
-
-static void UpdateVehiclePosHash(Vehicle* v, int x, int y)
-{
-	Vehicle **old_hash, **new_hash;
-	int old_x = v->left_coord;
-	int old_y = v->top_coord;
-
-	new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x,y)];
-	old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
-
-	if (old_hash == new_hash) return;
-
-	/* remove from hash table? */
-	if (old_hash != NULL) {
-		Vehicle *last = NULL;
-		Vehicle *u = *old_hash;
-		while (u != v) {
-			last = u;
-			u = u->next_hash;
-			assert(u != NULL);
-		}
-
-		if (last == NULL) {
-			*old_hash = v->next_hash;
-		} else {
-			last->next_hash = v->next_hash;
-		}
-	}
-
-	/* insert into hash table? */
-	if (new_hash != NULL) {
-		v->next_hash = *new_hash;
-		*new_hash = v;
-	}
-}
-
-void ResetVehiclePosHash(void)
-{
-	memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
-}
-
-void InitializeVehicles(void)
-{
-	uint i;
-
-	/* Clean the vehicle pool, and reserve enough blocks
-	 *  for the special vehicles, plus one for all the other
-	 *  vehicles (which is increased on-the-fly) */
-	CleanPool(&_Vehicle_pool);
-	AddBlockToPool(&_Vehicle_pool);
-	for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++) {
-		AddBlockToPool(&_Vehicle_pool);
-	}
-
-	ResetVehiclePosHash();
-}
-
-Vehicle *GetLastVehicleInChain(Vehicle *v)
-{
-	while (v->next != NULL) v = v->next;
-	return v;
-}
-
-/** Finds the previous vehicle in a chain, by a brute force search.
- * This old function is REALLY slow because it searches through all vehicles to
- * find the previous vehicle, but if v->first has not been set, then this function
- * will need to be used to find the previous one. This function should never be
- * called by anything but GetFirstVehicleInChain
- */
-static Vehicle *GetPrevVehicleInChain_bruteforce(const Vehicle *v)
-{
-	Vehicle *u;
-
-	FOR_ALL_VEHICLES(u) if (u->type == VEH_Train && u->next == v) return u;
-
-	return NULL;
-}
-
-/** Find the previous vehicle in a chain, by using the v->first cache.
- * While this function is fast, it cannot be used in the GetFirstVehicleInChain
- * function, otherwise you'll end up in an infinite loop call
- */
-Vehicle *GetPrevVehicleInChain(const Vehicle *v)
-{
-	Vehicle *u;
-	assert(v != NULL);
-
-	u = GetFirstVehicleInChain(v);
-
-	// Check to see if this is the first
-	if (v == u) return NULL;
-
-	for (; u->next != v; u = u->next) assert(u->next != NULL);
-
-	return u;
-}
-
-/** Finds the first vehicle in a chain.
- * This function reads out the v->first cache. Should the cache be dirty,
- * it determines the first vehicle in a chain, and updates the cache.
- */
-Vehicle *GetFirstVehicleInChain(const Vehicle *v)
-{
-	Vehicle* u;
-
-	assert(v != NULL);
-
-	if (v->first != NULL) {
-		if (IsFrontEngine(v->first) || IsFreeWagon(v->first)) return v->first;
-
-		DEBUG(misc, 0, "v->first cache faulty. We shouldn't be here, rebuilding cache!");
-	}
-
-	/* It is the fact (currently) that newly built vehicles do not have
-	 * their ->first pointer set. When this is the case, go up to the
-	 * first engine and set the pointers correctly. Also the first pointer
-	 * is not saved in a savegame, so this has to be fixed up after loading */
-
-	/* Find the 'locomotive' or the first wagon in a chain */
-	while ((u = GetPrevVehicleInChain_bruteforce(v)) != NULL) v = u;
-
-	/* Set the first pointer of all vehicles in that chain to the first wagon */
-	if (IsFrontEngine(v) || IsFreeWagon(v))
-		for (u = (Vehicle *)v; u != NULL; u = u->next) u->first = (Vehicle *)v;
-
-	return (Vehicle*)v;
-}
-
-uint CountVehiclesInChain(const Vehicle* v)
-{
-	uint count = 0;
-	do count++; while ((v = v->next) != NULL);
-	return count;
-}
-
-/** Check if a vehicle is counted in num_engines in each player struct
- * @param *v Vehicle to test
- * @return true if the vehicle is counted in num_engines
- */
-bool IsEngineCountable(const Vehicle *v)
-{
-	switch (v->type) {
-		case VEH_Aircraft: return (v->subtype <= 2); // don't count plane shadows and helicopter rotors
-		case VEH_Train:
-			return !IsArticulatedPart(v) && // tenders and other articulated parts
-			(!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines
-		case VEH_Road:
-		case VEH_Ship:
-			return true;
-		default: return false; // Only count player buildable vehicles
-	}
-}
-
-void DestroyVehicle(Vehicle *v)
-{
-	if (IsEngineCountable(v)) GetPlayer(v->owner)->num_engines[v->engine_type]--;
-
-	DeleteVehicleNews(v->index, INVALID_STRING_ID);
-
-	DeleteName(v->string_id);
-	if (v->type == VEH_Road) ClearSlot(v);
-
-	if (v->type != VEH_Train || (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))) {
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-	}
-
-	UpdateVehiclePosHash(v, INVALID_COORD, 0);
-	v->next_hash = NULL;
-	if (v->orders != NULL) DeleteVehicleOrders(v);
-
-	/* Now remove any artic part. This will trigger an other
-	 *  destroy vehicle, which on his turn can remove any
-	 *  other artic parts. */
-	if (EngineHasArticPart(v)) DeleteVehicle(v->next);
-}
-
-void DeleteVehicleChain(Vehicle *v)
-{
-	do {
-		Vehicle *u = v;
-		v = GetNextVehicle(v);
-		DeleteVehicle(u);
-	} while (v != NULL);
-}
-
-
-void Aircraft_Tick(Vehicle *v);
-void RoadVeh_Tick(Vehicle *v);
-void Ship_Tick(Vehicle *v);
-void Train_Tick(Vehicle *v);
-static void EffectVehicle_Tick(Vehicle *v);
-void DisasterVehicle_Tick(Vehicle *v);
-static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs);
-
-// head of the linked list to tell what vehicles that visited a depot in a tick
-static Vehicle* _first_veh_in_depot_list;
-
-/** Adds a vehicle to the list of vehicles, that visited a depot this tick
- * @param *v vehicle to add
- */
-void VehicleEnteredDepotThisTick(Vehicle *v)
-{
-	// we need to set v->leave_depot_instantly as we have no control of it's contents at this time
-	if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) {
-		// we keep the vehicle in the depot since the user ordered it to stay
-		v->leave_depot_instantly = false;
-	} else {
-		// the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
-		// out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
-		// we store that we stopped the vehicle, so autoreplace can start it again
-		v->vehstatus |= VS_STOPPED;
-		v->leave_depot_instantly = true;
-	}
-
-	if (_first_veh_in_depot_list == NULL) {
-		_first_veh_in_depot_list = v;
-	} else {
-		Vehicle *w = _first_veh_in_depot_list;
-		while (w->depot_list != NULL) w = w->depot_list;
-		w->depot_list = v;
-	}
-}
-
-typedef void VehicleTickProc(Vehicle*);
-static VehicleTickProc* _vehicle_tick_procs[] = {
-	Train_Tick,
-	RoadVeh_Tick,
-	Ship_Tick,
-	Aircraft_Tick,
-	EffectVehicle_Tick,
-	DisasterVehicle_Tick,
-};
-
-void CallVehicleTicks(void)
-{
-	Vehicle *v;
-
-#ifdef ENABLE_NETWORK
-	// hotfix for desync problem:
-	//  for MP games invalidate the YAPF cache every tick to keep it exactly the same on the server and all clients
-	if (_networking) {
-		YapfNotifyTrackLayoutChange(0, 0);
-	}
-#endif //ENABLE_NETWORK
-
-	_first_veh_in_depot_list = NULL; // now we are sure it's initialized at the start of each tick
-
-	FOR_ALL_VEHICLES(v) {
-		_vehicle_tick_procs[v->type - 0x10](v);
-
-		switch (v->type) {
-			case VEH_Train:
-			case VEH_Road:
-			case VEH_Aircraft:
-			case VEH_Ship:
-				if (v->type == VEH_Train && IsTrainWagon(v)) continue;
-				if (v->type == VEH_Aircraft && v->subtype > 0) continue;
-
-				v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
-				/* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
-				if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
-
-				/* Play an alterate running sound every 16 ticks */
-				if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
-		}
-	}
-
-	// now we handle all the vehicles that entered a depot this tick
-	v = _first_veh_in_depot_list;
-	while (v != NULL) {
-		Vehicle *w = v->depot_list;
-		v->depot_list = NULL; // it should always be NULL at the end of each tick
-		MaybeReplaceVehicle(v, false, true);
-		v = w;
-	}
-}
-
-static bool CanFillVehicle_FullLoadAny(Vehicle *v)
-{
-	uint32 full = 0, not_full = 0;
-	bool keep_loading = false;
-	const GoodsEntry *ge = GetStation(v->last_station_visited)->goods;
-
-	//special handling of aircraft
-
-	//if the aircraft carries passengers and is NOT full, then
-	//continue loading, no matter how much mail is in
-	if (v->type == VEH_Aircraft &&
-			v->cargo_type == CT_PASSENGERS &&
-			v->cargo_cap != v->cargo_count) {
-		return true;
-	}
-
-	// patch should return "true" to continue loading, i.e. when there is no cargo type that is fully loaded.
-	do {
-		//Should never happen, but just in case future additions change this
-		assert(v->cargo_type<32);
-
-		if (v->cargo_cap != 0) {
-			uint32 mask = 1 << v->cargo_type;
-
-			if (v->cargo_cap == v->cargo_count) {
-				full |= mask;
-			} else if (GB(ge[v->cargo_type].waiting_acceptance, 0, 12) > 0 ||
-					(HASBIT(v->load_status, LS_CARGO_UNLOADING) && (ge[v->cargo_type].waiting_acceptance & 0x8000))) {
-				/* If there is any cargo waiting, or this vehicle is still unloading
-				 * and the station accepts the cargo, don't leave the station. */
-				keep_loading = true;
-			} else {
-				not_full |= mask;
-			}
-		}
-	} while ((v = v->next) != NULL);
-
-	// continue loading if there is a non full cargo type and no cargo type that is full
-	return keep_loading || (not_full && (full & ~not_full) == 0);
-}
-
-bool CanFillVehicle(Vehicle *v)
-{
-	TileIndex tile = v->tile;
-
-	if (IsTileType(tile, MP_STATION) ||
-			(v->type == VEH_Ship && (
-				IsTileType(TILE_ADDXY(tile,  1,  0), MP_STATION) ||
-				IsTileType(TILE_ADDXY(tile, -1,  0), MP_STATION) ||
-				IsTileType(TILE_ADDXY(tile,  0,  1), MP_STATION) ||
-				IsTileType(TILE_ADDXY(tile,  0, -1), MP_STATION) ||
-				IsTileType(TILE_ADDXY(tile, -2,  0), MP_STATION)
-			))) {
-
-		// If patch is active, use alternative CanFillVehicle-function
-		if (_patches.full_load_any && v->current_order.flags & OF_FULL_LOAD) return CanFillVehicle_FullLoadAny(v);
-
-		do {
-			if (v->cargo_count != v->cargo_cap) return true;
-		} while ((v = v->next) != NULL);
-	}
-	return false;
-}
-
-/** Check if a given engine type can be refitted to a given cargo
- * @param engine_type Engine type to check
- * @param cid_to check refit to this cargo-type
- * @return true if it is possible, false otherwise
- */
-bool CanRefitTo(EngineID engine_type, CargoID cid_to)
-{
-	CargoID cid = _global_cargo_id[_opt_ptr->landscape][cid_to];
-	return HASBIT(EngInfo(engine_type)->refit_mask, cid);
-}
-
-/** Find the first cargo type that an engine can be refitted to.
- * @param engine Which engine to find cargo for.
- * @return A climate dependent cargo type. CT_INVALID is returned if not refittable.
- */
-CargoID FindFirstRefittableCargo(EngineID engine_type)
-{
-	CargoID cid;
-	uint32 refit_mask = EngInfo(engine_type)->refit_mask;
-
-	if (refit_mask != 0) {
-		for (cid = CT_PASSENGERS; cid < NUM_CARGO; cid++) {
-			if (HASBIT(refit_mask, _global_cargo_id[_opt_ptr->landscape][cid])) return cid;
-		}
-	}
-
-	return CT_INVALID;
-}
-
-/** Learn the price of refitting a certain engine
-* @param engine Which engine to refit
-* @return Price for refitting
-*/
-int32 GetRefitCost(EngineID engine_type)
-{
-	int32 base_cost = 0;
-
-	switch (GetEngine(engine_type)->type) {
-		case VEH_Ship: base_cost = _price.ship_base; break;
-		case VEH_Road: base_cost = _price.roadveh_base; break;
-		case VEH_Aircraft: base_cost = _price.aircraft_base; break;
-		case VEH_Train:
-			base_cost = 2 * ((RailVehInfo(engine_type)->flags & RVI_WAGON) ?
-							 _price.build_railwagon : _price.build_railvehicle);
-			break;
-		default: NOT_REACHED(); break;
-	}
-	return (EngInfo(engine_type)->refit_cost * base_cost) >> 10;
-}
-
-static void DoDrawVehicle(const Vehicle *v)
-{
-	uint32 image = v->cur_image;
-
-	if (v->vehstatus & VS_SHADOW) {
-		MAKE_TRANSPARENT(image);
-	} else if (v->vehstatus & VS_DEFPAL) {
-		image |= (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-	}
-
-	AddSortableSpriteToDraw(image, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
-		v->sprite_width, v->sprite_height, v->z_height, v->z_pos);
-}
-
-void ViewportAddVehicles(DrawPixelInfo *dpi)
-{
-	// The bounding rectangle
-	const int l = dpi->left;
-	const int r = dpi->left + dpi->width;
-	const int t = dpi->top;
-	const int b = dpi->top + dpi->height;
-
-	// The hash area to scan
-	const int xl = GB(l - 70, 7, 6);
-	const int xu = GB(r,      7, 6);
-	const int yl = GB(t - 70, 6, 6) << 6;
-	const int yu = GB(b,      6, 6) << 6;
-
-	int x;
-	int y;
-
-	for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
-		for (x = xl;; x = (x + 1) & 0x3F) {
-			const Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF];
-
-			while (v != NULL) {
-				if (!(v->vehstatus & VS_HIDDEN) &&
-						l <= v->right_coord &&
-						t <= v->bottom_coord &&
-						r >= v->left_coord &&
-						b >= v->top_coord) {
-					DoDrawVehicle(v);
-				}
-				v = v->next_hash;
-			}
-
-			if (x == xu) break;
-		}
-
-		if (y == yu) break;
-	}
-}
-
-static void ChimneySmokeInit(Vehicle *v)
-{
-	uint32 r = Random();
-	v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
-	v->progress = GB(r, 16, 3);
-}
-
-static void ChimneySmokeTick(Vehicle *v)
-{
-	if (v->progress > 0) {
-		v->progress--;
-	} else {
-		TileIndex tile;
-
-		BeginVehicleMove(v);
-
-		tile = TileVirtXY(v->x_pos, v->y_pos);
-		if (!IsTileType(tile, MP_INDUSTRY)) {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-			return;
-		}
-
-		if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
-			v->cur_image++;
-		} else {
-			v->cur_image = SPR_CHIMNEY_SMOKE_0;
-		}
-		v->progress = 7;
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void SteamSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_STEAM_SMOKE_0;
-	v->progress = 12;
-}
-
-static void SteamSmokeTick(Vehicle *v)
-{
-	bool moved = false;
-
-	BeginVehicleMove(v);
-
-	v->progress++;
-
-	if ((v->progress & 7) == 0) {
-		v->z_pos++;
-		moved = true;
-	}
-
-	if ((v->progress & 0xF) == 4) {
-		if (v->cur_image != SPR_STEAM_SMOKE_4) {
-			v->cur_image++;
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-			return;
-		}
-		moved = true;
-	}
-
-	if (moved) {
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void DieselSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_DIESEL_SMOKE_0;
-	v->progress = 0;
-}
-
-static void DieselSmokeTick(Vehicle *v)
-{
-	v->progress++;
-
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		v->z_pos++;
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	} else if ((v->progress & 7) == 1) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_DIESEL_SMOKE_5) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-		}
-	}
-}
-
-static void ElectricSparkInit(Vehicle *v)
-{
-	v->cur_image = SPR_ELECTRIC_SPARK_0;
-	v->progress = 1;
-}
-
-static void ElectricSparkTick(Vehicle *v)
-{
-	if (v->progress < 2) {
-		v->progress++;
-	} else {
-		v->progress = 0;
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-		}
-	}
-}
-
-static void SmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_SMOKE_0;
-	v->progress = 12;
-}
-
-static void SmokeTick(Vehicle *v)
-{
-	bool moved = false;
-
-	BeginVehicleMove(v);
-
-	v->progress++;
-
-	if ((v->progress & 3) == 0) {
-		v->z_pos++;
-		moved = true;
-	}
-
-	if ((v->progress & 0xF) == 4) {
-		if (v->cur_image != SPR_SMOKE_4) {
-			v->cur_image++;
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-			return;
-		}
-		moved = true;
-	}
-
-	if (moved) {
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void ExplosionLargeInit(Vehicle *v)
-{
-	v->cur_image = SPR_EXPLOSION_LARGE_0;
-	v->progress = 0;
-}
-
-static void ExplosionLargeTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-		}
-	}
-}
-
-static void BreakdownSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_BREAKDOWN_SMOKE_0;
-	v->progress = 0;
-}
-
-static void BreakdownSmokeTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 7) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
-			v->cur_image++;
-		} else {
-			v->cur_image = SPR_BREAKDOWN_SMOKE_0;
-		}
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-
-	v->u.special.unk0--;
-	if (v->u.special.unk0 == 0) {
-		BeginVehicleMove(v);
-		EndVehicleMove(v);
-		DeleteVehicle(v);
-	}
-}
-
-static void ExplosionSmallInit(Vehicle *v)
-{
-	v->cur_image = SPR_EXPLOSION_SMALL_0;
-	v->progress = 0;
-}
-
-static void ExplosionSmallTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			DeleteVehicle(v);
-		}
-	}
-}
-
-static void BulldozerInit(Vehicle *v)
-{
-	v->cur_image = SPR_BULLDOZER_NE;
-	v->progress = 0;
-	v->u.special.unk0 = 0;
-	v->u.special.unk2 = 0;
-}
-
-typedef struct BulldozerMovement {
-	byte direction:2;
-	byte image:2;
-	byte duration:3;
-} BulldozerMovement;
-
-static const BulldozerMovement _bulldozer_movement[] = {
-	{ 0, 0, 4 },
-	{ 3, 3, 4 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 1, 1, 3 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 1, 1, 3 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 3, 3, 6 },
-	{ 2, 2, 6 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 },
-	{ 0, 0, 3 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 },
-	{ 0, 0, 3 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 }
-};
-
-static const struct {
-	int8 x;
-	int8 y;
-} _inc_by_dir[] = {
-	{ -1,  0 },
-	{  0,  1 },
-	{  1,  0 },
-	{  0, -1 }
-};
-
-static void BulldozerTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 7) == 0) {
-		const BulldozerMovement* b = &_bulldozer_movement[v->u.special.unk0];
-
-		BeginVehicleMove(v);
-
-		v->cur_image = SPR_BULLDOZER_NE + b->image;
-
-		v->x_pos += _inc_by_dir[b->direction].x;
-		v->y_pos += _inc_by_dir[b->direction].y;
-
-		v->u.special.unk2++;
-		if (v->u.special.unk2 >= b->duration) {
-			v->u.special.unk2 = 0;
-			v->u.special.unk0++;
-			if (v->u.special.unk0 == lengthof(_bulldozer_movement)) {
-				EndVehicleMove(v);
-				DeleteVehicle(v);
-				return;
-			}
-		}
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void BubbleInit(Vehicle *v)
-{
-	v->cur_image = SPR_BUBBLE_GENERATE_0;
-	v->spritenum = 0;
-	v->progress = 0;
-}
-
-typedef struct BubbleMovement {
-	int8 x:4;
-	int8 y:4;
-	int8 z:4;
-	byte image:4;
-} BubbleMovement;
-
-#define MK(x, y, z, i) { x, y, z, i }
-#define ME(i) { i, 4, 0, 0 }
-
-static const BubbleMovement _bubble_float_sw[] = {
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	ME(1)
-};
-
-
-static const BubbleMovement _bubble_float_ne[] = {
-	MK( 0, 0, 1, 0),
-	MK(-1, 0, 1, 1),
-	MK( 0, 0, 1, 0),
-	MK(-1, 0, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_float_se[] = {
-	MK(0, 0, 1, 0),
-	MK(0, 1, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 1, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_float_nw[] = {
-	MK(0,  0, 1, 0),
-	MK(0, -1, 1, 1),
-	MK(0,  0, 1, 0),
-	MK(0, -1, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_burst[] = {
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 7),
-	MK(0, 0, 1, 8),
-	MK(0, 0, 1, 9),
-	ME(0)
-};
-
-static const BubbleMovement _bubble_absorb[] = {
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 2),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	ME(2),
-	MK(0, 0, 0, 0xA),
-	MK(0, 0, 0, 0xB),
-	MK(0, 0, 0, 0xC),
-	MK(0, 0, 0, 0xD),
-	MK(0, 0, 0, 0xE),
-	ME(0)
-};
-#undef ME
-#undef MK
-
-static const BubbleMovement * const _bubble_movement[] = {
-	_bubble_float_sw,
-	_bubble_float_ne,
-	_bubble_float_se,
-	_bubble_float_nw,
-	_bubble_burst,
-	_bubble_absorb,
-};
-
-static void BubbleTick(Vehicle *v)
-{
-	/*
-	 * Warning: those effects can NOT use Random(), and have to use
-	 *  InteractiveRandom(), because somehow someone forgot to save
-	 *  spritenum to the savegame, and so it will cause desyncs in
-	 *  multiplayer!! (that is: in ToyLand)
-	 */
-	uint et;
-	const BubbleMovement *b;
-
-	v->progress++;
-	if ((v->progress & 3) != 0)
-		return;
-
-	BeginVehicleMove(v);
-
-	if (v->spritenum == 0) {
-		v->cur_image++;
-		if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-			return;
-		}
-		if (v->u.special.unk2 != 0) {
-			v->spritenum = GB(InteractiveRandom(), 0, 2) + 1;
-		} else {
-			v->spritenum = 6;
-		}
-		et = 0;
-	} else {
-		et = v->engine_type + 1;
-	}
-
-	b = &_bubble_movement[v->spritenum - 1][et];
-
-	if (b->y == 4 && b->x == 0) {
-		EndVehicleMove(v);
-		DeleteVehicle(v);
-		return;
-	}
-
-	if (b->y == 4 && b->x == 1) {
-		if (v->z_pos > 180 || CHANCE16I(1, 96, InteractiveRandom())) {
-			v->spritenum = 5;
-			SndPlayVehicleFx(SND_2F_POP, v);
-		}
-		et = 0;
-	}
-
-	if (b->y == 4 && b->x == 2) {
-		TileIndex tile;
-
-		et++;
-		SndPlayVehicleFx(SND_31_EXTRACT, v);
-
-		tile = TileVirtXY(v->x_pos, v->y_pos);
-		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == 0xA2) AddAnimatedTile(tile);
-	}
-
-	v->engine_type = et;
-	b = &_bubble_movement[v->spritenum - 1][et];
-
-	v->x_pos += b->x;
-	v->y_pos += b->y;
-	v->z_pos += b->z;
-	v->cur_image = SPR_BUBBLE_0 + b->image;
-
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-}
-
-
-typedef void EffectInitProc(Vehicle *v);
-typedef void EffectTickProc(Vehicle *v);
-
-static EffectInitProc * const _effect_init_procs[] = {
-	ChimneySmokeInit,
-	SteamSmokeInit,
-	DieselSmokeInit,
-	ElectricSparkInit,
-	SmokeInit,
-	ExplosionLargeInit,
-	BreakdownSmokeInit,
-	ExplosionSmallInit,
-	BulldozerInit,
-	BubbleInit,
-};
-
-static EffectTickProc * const _effect_tick_procs[] = {
-	ChimneySmokeTick,
-	SteamSmokeTick,
-	DieselSmokeTick,
-	ElectricSparkTick,
-	SmokeTick,
-	ExplosionLargeTick,
-	BreakdownSmokeTick,
-	ExplosionSmallTick,
-	BulldozerTick,
-	BubbleTick,
-};
-
-
-Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type)
-{
-	Vehicle *v;
-
-	v = ForceAllocateSpecialVehicle();
-	if (v != NULL) {
-		v->type = VEH_Special;
-		v->subtype = type;
-		v->x_pos = x;
-		v->y_pos = y;
-		v->z_pos = z;
-		v->z_height = v->sprite_width = v->sprite_height = 1;
-		v->x_offs = v->y_offs = 0;
-		v->tile = 0;
-		v->vehstatus = VS_UNCLICKABLE;
-
-		_effect_init_procs[type](v);
-
-		VehiclePositionChanged(v);
-		BeginVehicleMove(v);
-		EndVehicleMove(v);
-	}
-	return v;
-}
-
-Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type)
-{
-	int safe_x = clamp(x, 0, MapMaxX() * TILE_SIZE);
-	int safe_y = clamp(y, 0, MapMaxY() * TILE_SIZE);
-	return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
-}
-
-Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type)
-{
-	return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
-}
-
-static void EffectVehicle_Tick(Vehicle *v)
-{
-	_effect_tick_procs[v->subtype](v);
-}
-
-Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
-{
-	Vehicle *found = NULL, *v;
-	uint dist, best_dist = (uint)-1;
-
-	if ( (uint)(x -= vp->left) >= (uint)vp->width ||
-			 (uint)(y -= vp->top) >= (uint)vp->height)
-				return NULL;
-
-	x = (x << vp->zoom) + vp->virtual_left;
-	y = (y << vp->zoom) + vp->virtual_top;
-
-	FOR_ALL_VEHICLES(v) {
-		if ((v->vehstatus & (VS_HIDDEN|VS_UNCLICKABLE)) == 0 &&
-				x >= v->left_coord && x <= v->right_coord &&
-				y >= v->top_coord && y <= v->bottom_coord) {
-
-			dist = max(
-				myabs( ((v->left_coord + v->right_coord)>>1) - x ),
-				myabs( ((v->top_coord + v->bottom_coord)>>1) - y )
-			);
-
-			if (dist < best_dist) {
-				found = v;
-				best_dist = dist;
-			}
-		}
-	}
-
-	return found;
-}
-
-
-void DecreaseVehicleValue(Vehicle *v)
-{
-	v->value -= v->value >> 8;
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-}
-
-static const byte _breakdown_chance[64] = {
-	  3,   3,   3,   3,   3,   3,   3,   3,
-	  4,   4,   5,   5,   6,   6,   7,   7,
-	  8,   8,   9,   9,  10,  10,  11,  11,
-	 12,  13,  13,  13,  13,  14,  15,  16,
-	 17,  19,  21,  25,  28,  31,  34,  37,
-	 40,  44,  48,  52,  56,  60,  64,  68,
-	 72,  80,  90, 100, 110, 120, 130, 140,
-	150, 170, 190, 210, 230, 250, 250, 250,
-};
-
-void CheckVehicleBreakdown(Vehicle *v)
-{
-	int rel, rel_old;
-	uint32 r;
-	int chance;
-
-	/* decrease reliability */
-	v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
-	if ((rel_old >> 8) != (rel >> 8))
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-	if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
-			v->cur_speed < 5 || _game_mode == GM_MENU) {
-		return;
-	}
-
-	r = Random();
-
-	/* increase chance of failure */
-	chance = v->breakdown_chance + 1;
-	if (CHANCE16I(1,25,r)) chance += 25;
-	v->breakdown_chance = min(255, chance);
-
-	/* calculate reliability value to use in comparison */
-	rel = v->reliability;
-	if (v->type == VEH_Ship) rel += 0x6666;
-
-	/* disabled breakdowns? */
-	if (_opt.diff.vehicle_breakdowns < 1) return;
-
-	/* reduced breakdowns? */
-	if (_opt.diff.vehicle_breakdowns == 1) rel += 0x6666;
-
-	/* check if to break down */
-	if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
-		v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
-		v->breakdown_delay  = GB(r, 24, 7) + 0x80;
-		v->breakdown_chance = 0;
-	}
-}
-
-static const StringID _vehicle_type_names[4] = {
-	STR_019F_TRAIN,
-	STR_019C_ROAD_VEHICLE,
-	STR_019E_SHIP,
-	STR_019D_AIRCRAFT,
-};
-
-static void ShowVehicleGettingOld(Vehicle *v, StringID msg)
-{
-	if (v->owner != _local_player) return;
-
-	// Do not show getting-old message if autorenew is active
-	if (GetPlayer(v->owner)->engine_renew) return;
-
-	SetDParam(0, _vehicle_type_names[v->type - 0x10]);
-	SetDParam(1, v->unitnumber);
-	AddNewsItem(msg, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
-}
-
-void AgeVehicle(Vehicle *v)
-{
-	int age;
-
-	if (v->age < 65535)
-		v->age++;
-
-	age = v->age - v->max_age;
-	if (age == 366*0 || age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4)
-		v->reliability_spd_dec <<= 1;
-
-	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-
-	if (age == -366) {
-		ShowVehicleGettingOld(v, STR_01A0_IS_GETTING_OLD);
-	} else if (age == 0) {
-		ShowVehicleGettingOld(v, STR_01A1_IS_GETTING_VERY_OLD);
-	} else if (age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4 || age == 366*5) {
-		ShowVehicleGettingOld(v, STR_01A2_IS_GETTING_VERY_OLD_AND);
-	}
-}
-
-/** Starts or stops a lot of vehicles
- * @param tile Tile of the depot where the vehicles are started/stopped (only used for depots)
- * @param p1 Station/Order/Depot ID (only used for vehicle list windows)
- * @param p2 bitmask
- *   - bit 0-4 Vehicle type
- *   - bit 5 false = start vehicles, true = stop vehicles
- *   - bit 6 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case
- *   - bit 8-11 Vehicle List Window type (ignored unless bit 1 is set)
- */
-int32 CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle **vl = NULL;
-	uint16 engine_list_length = 0;
-	uint16 engine_count = 0;
-	int32 return_value = CMD_ERROR;
-	uint i;
-	uint stop_command;
-	byte vehicle_type = GB(p2, 0, 5);
-	bool start_stop = HASBIT(p2, 5);
-	bool vehicle_list_window = HASBIT(p2, 6);
-
-	switch (vehicle_type) {
-		case VEH_Train:    stop_command = CMD_START_STOP_TRAIN;    break;
-		case VEH_Road:     stop_command = CMD_START_STOP_ROADVEH;  break;
-		case VEH_Ship:     stop_command = CMD_START_STOP_SHIP;     break;
-		case VEH_Aircraft: stop_command = CMD_START_STOP_AIRCRAFT; break;
-		default: return CMD_ERROR;
-	}
-
-	if (vehicle_list_window) {
-		uint16 id = GB(p1, 0, 16);
-		uint16 window_type = p2 & VLW_MASK;
-
-		engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, id, id, window_type);
-	} else {
-		/* Get the list of vehicles in the depot */
-		BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
-	}
-
-	for (i = 0; i < engine_count; i++) {
-		const Vehicle *v = vl[i];
-		int32 ret;
-
-		if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
-
-		if (!vehicle_list_window) {
-			if (vehicle_type == VEH_Train) {
-				if (CheckTrainInDepot(v, false) == -1) continue;
-			} else {
-				if (!(v->vehstatus & VS_HIDDEN)) continue;
-			}
-		}
-
-		ret = DoCommand(tile, v->index, 0, flags, stop_command);
-
-		if (!CmdFailed(ret)) {
-			return_value = 0;
-			/* We know that the command is valid for at least one vehicle.
-			 * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
-			if (!(flags & DC_EXEC)) break;
-		}
-	}
-
-	free(vl);
-	return return_value;
-}
-
-/** Sells all vehicles in a depot
-* @param tile Tile of the depot where the depot is
-* @param p1 Vehicle type
-* @param p2 unused
-*/
-int32 CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle **engines = NULL;
-	Vehicle **wagons = NULL;
-	uint16 engine_list_length = 0;
-	uint16 engine_count = 0;
-	uint16 wagon_list_length = 0;
-	uint16 wagon_count = 0;
-
-	int32 cost = 0;
-	uint i, sell_command, total_number_vehicles;
-	byte vehicle_type = GB(p1, 0, 8);
-
-	switch (vehicle_type) {
-		case VEH_Train:    sell_command = CMD_SELL_RAIL_WAGON; break;
-		case VEH_Road:     sell_command = CMD_SELL_ROAD_VEH;   break;
-		case VEH_Ship:     sell_command = CMD_SELL_SHIP;       break;
-		case VEH_Aircraft: sell_command = CMD_SELL_AIRCRAFT;   break;
-		default: return CMD_ERROR;
-	}
-
-	/* Get the list of vehicles in the depot */
-	BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
-						                      &wagons,  &wagon_list_length,  &wagon_count);
-
-	total_number_vehicles = engine_count + wagon_count;
-	for (i = 0; i < total_number_vehicles; i++) {
-		const Vehicle *v;
-		int32 ret;
-
-		if (i < engine_count) {
-			v = engines[i];
-		} else {
-			v = wagons[i - engine_count];
-		}
-
-		ret = DoCommand(tile, v->index, 1, flags, sell_command);
-
-		if (!CmdFailed(ret)) cost += ret;
-	}
-
-	free(engines);
-	free(wagons);
-	if (cost == 0) return CMD_ERROR; // no vehicles to sell
-	return cost;
-}
-
-/** Autoreplace all vehicles in the depot
-* @param tile Tile of the depot where the vehicles are
-* @param p1 Type of vehicle
-* @param p2 Unused
-*/
-int32 CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle **vl = NULL;
-	uint16 engine_list_length = 0;
-	uint16 engine_count = 0;
-	uint i, x = 0, y = 0, z = 0;
-	int32 cost = 0;
-	byte vehicle_type = GB(p1, 0, 8);
-
-
-	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
-
-	/* Get the list of vehicles in the depot */
-	BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
-
-
-	for (i = 0; i < engine_count; i++) {
-		Vehicle *v = vl[i];
-		bool stopped = !(v->vehstatus & VS_STOPPED);
-		int32 ret;
-
-		/* Ensure that the vehicle completely in the depot */
-		if (!IsVehicleInDepot(v)) continue;
-
-		x = v->x_pos;
-		y = v->y_pos;
-		z = v->z_pos;
-
-		if (stopped) {
-			v->vehstatus |= VS_STOPPED; // Stop the vehicle
-			v->leave_depot_instantly = true;
-		}
-		ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false);
-
-		if (!CmdFailed(ret)) {
-			cost += ret;
-			if (!(flags & DC_EXEC)) break;
-			/* There is a problem with autoreplace and newgrf
-			 * It's impossible to tell the length of a train after it's being replaced before it's actually done
-			 * Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
-			 * Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
-			 * we should never reach a condition where the player will end up with negative money from doing this */
-			SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-			SubtractMoneyFromPlayer(ret);
-		}
-	}
-
-	if (cost == 0) {
-		cost = CMD_ERROR;
-	} else {
-		if (flags & DC_EXEC) {
-			/* Display the cost animation now that DoCommandP() can't do it for us (see previous comments) */
-			if (IsLocalPlayer()) ShowCostOrIncomeAnimation(x, y, z, cost);
-		}
-		cost = 0;
-	}
-
-	free(vl);
-	return cost;
-}
-
-/** Clone a vehicle. If it is a train, it will clone all the cars too
- * @param tile tile of the depot where the cloned vehicle is build
- * @param p1 the original vehicle's index
- * @param p2 1 = shared orders, else copied orders
- */
-int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v_front, *v;
-	Vehicle *w_front, *w, *w_rear;
-	int cost, total_cost = 0;
-	uint32 build_argument = 2;
-
-	if (!IsValidVehicleID(p1)) return CMD_ERROR;
-	v = GetVehicle(p1);
-	v_front = v;
-	w = NULL;
-	w_front = NULL;
-	w_rear = NULL;
-
-
-	/*
-	 * v_front is the front engine in the original vehicle
-	 * v is the car/vehicle of the original vehicle, that is currently being copied
-	 * w_front is the front engine of the cloned vehicle
-	 * w is the car/vehicle currently being cloned
-	 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
-	 */
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (v->type == VEH_Train && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
-
-	// check that we can allocate enough vehicles
-	if (!(flags & DC_EXEC)) {
-		int veh_counter = 0;
-		do {
-			veh_counter++;
-		} while ((v = v->next) != NULL);
-
-		if (!AllocateVehicles(NULL, veh_counter)) {
-			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
-		}
-	}
-
-	v = v_front;
-
-	do {
-
-		if (IsMultiheaded(v) && !IsTrainEngine(v)) {
-			/* we build the rear ends of multiheaded trains with the front ones */
-			continue;
-		}
-
-		cost = DoCommand(tile, v->engine_type, build_argument, flags, CMD_BUILD_VEH(v->type));
-		build_argument = 3; // ensure that we only assign a number to the first engine
-
-		if (CmdFailed(cost)) return cost;
-
-		total_cost += cost;
-
-		if (flags & DC_EXEC) {
-			w = GetVehicle(_new_vehicle_id);
-
-			if (v->cargo_type != w->cargo_type || v->cargo_subtype != w->cargo_subtype) {
-				// we can't pay for refitting because we can't estimate refitting costs for a vehicle before it's build
-				// if we pay for it anyway, the cost and the estimated cost will not be the same and we will have an assert
-				DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8), flags, CMD_REFIT_VEH(v->type));
-			}
-			if (v->type == VEH_Train && HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
-				SETBIT(w->u.rail.flags, VRF_REVERSE_DIRECTION);
-			}
-
-			if (v->type == VEH_Train && !IsFrontEngine(v)) {
-				// this s a train car
-				// add this unit to the end of the train
-				DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
-			} else {
-				// this is a front engine or not a train. It need orders
-				w_front = w;
-				w->service_interval = v->service_interval;
-				DoCommand(0, (v->index << 16) | w->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
-			}
-			w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
-		}
-	} while (v->type == VEH_Train && (v = GetNextVehicle(v)) != NULL);
-
-	if (flags & DC_EXEC && v_front->type == VEH_Train) {
-		// for trains this needs to be the front engine due to the callback function
-		_new_vehicle_id = w_front->index;
-	}
-
-	/* Set the expense type last as refitting will make the cost go towards
-	 * running costs... */
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-	return total_cost;
-}
-
-/*
- * move the cargo from one engine to another if possible
- */
-static void MoveVehicleCargo(Vehicle *dest, Vehicle *source)
-{
-	Vehicle *v = dest;
-	int units_moved;
-
-	do {
-		do {
-			if (source->cargo_type != dest->cargo_type)
-				continue; // cargo not compatible
-
-			if (dest->cargo_count == dest->cargo_cap)
-				continue; // the destination vehicle is already full
-
-			units_moved = min(source->cargo_count, dest->cargo_cap - dest->cargo_count);
-			source->cargo_count -= units_moved;
-			dest->cargo_count   += units_moved;
-			dest->cargo_source   = source->cargo_source;
-
-			// copy the age of the cargo
-			dest->cargo_days   = source->cargo_days;
-			dest->day_counter  = source->day_counter;
-			dest->tick_counter = source->tick_counter;
-
-		} while (source->cargo_count > 0 && (dest = dest->next) != NULL);
-		dest = v;
-	} while ((source = source->next) != NULL);
-}
-
-static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, const EngineID engine_type)
-{
-	const Order *o;
-	const Vehicle *u;
-
-	if (v->type == VEH_Train) {
-		u = GetFirstVehicleInChain(v);
-	} else {
-		u = v;
-	}
-
-	FOR_VEHICLE_ORDERS(u, o) {
-		if (!(o->refit_cargo < NUM_CARGO)) continue;
-		if (!CanRefitTo(v->engine_type, o->refit_cargo)) continue;
-		if (!CanRefitTo(engine_type, o->refit_cargo)) return false;
-	}
-
-	return true;
-}
-
-/**
- * Function to find what type of cargo to refit to when autoreplacing
- * @param *v Original vehicle, that is being replaced
- * @param engine_type The EngineID of the vehicle that is being replaced to
- * @return The cargo type to replace to
- *    CT_NO_REFIT is returned if no refit is needed
- *    CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible
- */
-static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type)
-{
-	bool new_cargo_capacity = true;
-	CargoID new_cargo_type = CT_INVALID;
-
-	switch (v->type) {
-		case VEH_Train:
-			new_cargo_capacity = (RailVehInfo(engine_type)->capacity > 0);
-			new_cargo_type     = RailVehInfo(engine_type)->cargo_type;
-			break;
-
-		case VEH_Road:
-			new_cargo_capacity = (RoadVehInfo(engine_type)->capacity > 0);
-			new_cargo_type     = RoadVehInfo(engine_type)->cargo_type;
-			break;
-		case VEH_Ship:
-			new_cargo_capacity = (ShipVehInfo(engine_type)->capacity > 0);
-			new_cargo_type     = ShipVehInfo(engine_type)->cargo_type;
-			break;
-
-		case VEH_Aircraft:
-			/* all aircraft starts as passenger planes with cargo capacity
-			 * new_cargo_capacity is always true for aircraft, which is the init value. No need to set it here */
-			new_cargo_type     = CT_PASSENGERS;
-			break;
-
-		default: NOT_REACHED(); break;
-	}
-
-	if (!new_cargo_capacity) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity
-
-	if (v->cargo_type == new_cargo_type || CanRefitTo(engine_type, v->cargo_type)) {
-		if (VerifyAutoreplaceRefitForOrders(v, engine_type)) {
-			return v->cargo_type == new_cargo_type ? CT_NO_REFIT : v->cargo_type;
-		} else {
-			return CT_INVALID;
-		}
-	}
-	if (v->type != VEH_Train) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want
-
-	/* Below this line it's safe to assume that the vehicle in question is a train */
-
-	if (v->cargo_cap != 0) return CT_INVALID; // trying to replace a vehicle with cargo capacity into another one with incompatible cargo type
-
-	/* the old engine didn't have cargo capacity, but the new one does
-	 * now we will figure out what cargo the train is carrying and refit to fit this */
-	v = GetFirstVehicleInChain(v);
-	do {
-		if (v->cargo_cap == 0) continue;
-		/* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */
-		if (v->cargo_type == new_cargo_type) return CT_NO_REFIT;
-		if (CanRefitTo(engine_type, v->cargo_type)) return v->cargo_type;
-	} while ((v=v->next) != NULL);
-	return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
-}
-
-/* Replaces a vehicle (used to be called autorenew)
- * This function is only called from MaybeReplaceVehicle()
- * Must be called with _current_player set to the owner of the vehicle
- * @param w Vehicle to replace
- * @param flags is the flags to use when calling DoCommand(). Mainly DC_EXEC counts
- * @return value is cost of the replacement or CMD_ERROR
- */
-static int32 ReplaceVehicle(Vehicle **w, byte flags, int32 total_cost)
-{
-	int32 cost;
-	int32 sell_value;
-	Vehicle *old_v = *w;
-	const Player *p = GetPlayer(old_v->owner);
-	EngineID new_engine_type;
-	const UnitID cached_unitnumber = old_v->unitnumber;
-	bool new_front = false;
-	Vehicle *new_v = NULL;
-	char vehicle_name[32];
-	CargoID replacement_cargo_type;
-
-	new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type);
-	if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type;
-
-	replacement_cargo_type = GetNewCargoTypeForReplace(old_v, new_engine_type);
-
-	/* check if we can't refit to the needed type, so no replace takes place to prevent the vehicle from altering cargo type */
-	if (replacement_cargo_type == CT_INVALID) return 0;
-
-	sell_value = DoCommand(0, old_v->index, 0, DC_QUERY_COST, CMD_SELL_VEH(old_v->type));
-
-	/* We give the player a loan of the same amount as the sell value.
-	 * This is needed in case he needs the income from the sale to build the new vehicle.
-	 * We take it back if building fails or when we really sell the old engine */
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-	SubtractMoneyFromPlayer(sell_value);
-
-	cost = DoCommand(old_v->tile, new_engine_type, 3, flags, CMD_BUILD_VEH(old_v->type));
-	if (CmdFailed(cost)) {
-		SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-		SubtractMoneyFromPlayer(-sell_value); // Take back the money we just gave the player
-		return cost;
-	}
-
-	if (replacement_cargo_type != CT_NO_REFIT) cost += GetRefitCost(new_engine_type); // add refit cost
-
-	if (flags & DC_EXEC) {
-		new_v = GetVehicle(_new_vehicle_id);
-		*w = new_v; //we changed the vehicle, so MaybeReplaceVehicle needs to work on the new one. Now we tell it what the new one is
-
-		/* refit if needed */
-		if (replacement_cargo_type != CT_NO_REFIT) {
-			if (CmdFailed(DoCommand(0, new_v->index, replacement_cargo_type, DC_EXEC, CMD_REFIT_VEH(new_v->type)))) {
-				/* Being here shows a failure, which most likely is in GetNewCargoTypeForReplace() or incorrect estimation costs */
-				error("Autoreplace failed to refit. Replace engine %d to %d and refit to cargo %d", old_v->engine_type, new_v->engine_type, replacement_cargo_type);
-			}
-		}
-
-		if (new_v->type == VEH_Train && HASBIT(old_v->u.rail.flags, VRF_REVERSE_DIRECTION) && !IsMultiheaded(new_v) && !(new_v->next != NULL && IsArticulatedPart(new_v->next))) {
-			// we are autorenewing to a single engine, so we will turn it as the old one was turned as well
-			SETBIT(new_v->u.rail.flags, VRF_REVERSE_DIRECTION);
-		}
-
-		if (old_v->type == VEH_Train && !IsFrontEngine(old_v)) {
-			/* this is a railcar. We need to move the car into the train
-			 * We add the new engine after the old one instead of replacing it. It will give the same result anyway when we
-			 * sell the old engine in a moment
-			 */
-			DoCommand(0, (GetPrevVehicleInChain(old_v)->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-			/* Now we move the old one out of the train */
-			DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-		} else {
-			// copy/clone the orders
-			DoCommand(0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
-			new_v->cur_order_index = old_v->cur_order_index;
-			ChangeVehicleViewWindow(old_v, new_v);
-			new_v->profit_this_year = old_v->profit_this_year;
-			new_v->profit_last_year = old_v->profit_last_year;
-			new_v->service_interval = old_v->service_interval;
-			new_front = true;
-			new_v->unitnumber = old_v->unitnumber; // use the same unit number
-
-			new_v->current_order = old_v->current_order;
-			if (old_v->type == VEH_Train && GetNextVehicle(old_v) != NULL){
-				Vehicle *temp_v = GetNextVehicle(old_v);
-
-				// move the entire train to the new engine, excluding the old engine
-				if (IsMultiheaded(old_v) && temp_v == old_v->u.rail.other_multiheaded_part) {
-					// we got front and rear of a multiheaded engine right after each other. We should work with the next in line instead
-					temp_v = GetNextVehicle(temp_v);
-				}
-
-				if (temp_v != NULL) {
-					DoCommand(0, (new_v->index << 16) | temp_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-				}
-			}
-		}
-		/* We are done setting up the new vehicle. Now we move the cargo from the old one to the new one */
-		MoveVehicleCargo(new_v->type == VEH_Train ? GetFirstVehicleInChain(new_v) : new_v, old_v);
-
-		// Get the name of the old vehicle if it has a custom name.
-		if (!IsCustomName(old_v->string_id)) {
-			vehicle_name[0] = '\0';
-		} else {
-			GetName(vehicle_name, old_v->string_id & 0x7FF, lastof(vehicle_name));
-		}
-	} else { // flags & DC_EXEC not set
-		/* Ensure that the player will not end up having negative money while autoreplacing
-		 * This is needed because the only other check is done after the income from selling the old vehicle is substracted from the cost */
-		if (p->money64 < (cost + total_cost)) {
-			SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-			SubtractMoneyFromPlayer(-sell_value); // Pay back the loan
-			return CMD_ERROR;
-		}
-	}
-
-	/* Take back the money we just gave the player just before building the vehicle
-	 * The player will get the same amount now that the sale actually takes place */
-	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
-	SubtractMoneyFromPlayer(-sell_value);
-
-	/* sell the engine/ find out how much you get for the old engine (income is returned as negative cost) */
-	cost += DoCommand(0, old_v->index, 0, flags, CMD_SELL_VEH(old_v->type));
-
-	if (new_front) {
-		/* now we assign the old unitnumber to the new vehicle */
-		new_v->unitnumber = cached_unitnumber;
-	}
-
-	/* Transfer the name of the old vehicle */
-	if ((flags & DC_EXEC) && vehicle_name[0] != '\0') {
-		_cmd_text = vehicle_name;
-		DoCommand(0, new_v->index, 0, DC_EXEC, CMD_NAME_VEHICLE);
-	}
-
-	return cost;
-}
-
-/** replaces a vehicle if it's set for autoreplace or is too old
- * (used to be called autorenew)
- * @param v The vehicle to replace
- * if the vehicle is a train, v needs to be the front engine
- * @param check Checks if the replace is valid. No action is done at all
- * @param display_costs If set, a cost animation is shown (only if check is false)
- * @return CMD_ERROR if something went wrong. Otherwise the price of the replace
- */
-static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs)
-{
-	Vehicle *w;
-	const Player *p = GetPlayer(v->owner);
-	byte flags = 0;
-	int32 cost, temp_cost = 0;
-	bool stopped = false;
-
-	/* Remember the length in case we need to trim train later on
-	 * If it's not a train, the value is unused
-	 * round up to the length of the tiles used for the train instead of the train length instead
-	 * Useful when newGRF uses custom length */
-	uint16 old_total_length = (v->type == VEH_Train ?
-		(v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE :
-		-1
-	);
-
-
-	_current_player = v->owner;
-
-	assert(v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship || v->type == VEH_Aircraft);
-
-	assert(v->vehstatus & VS_STOPPED); // the vehicle should have been stopped in VehicleEnteredDepotThisTick() if needed
-
-	if (v->leave_depot_instantly) {
-		// we stopped the vehicle to do this, so we have to remember to start it again when we are done
-		// we need to store this info as the engine might be replaced and lose this info
-		stopped = true;
-	}
-
-	for (;;) {
-		cost = 0;
-		w = v;
-		do {
-			if (w->type == VEH_Train && IsMultiheaded(w) && !IsTrainEngine(w)) {
-				/* we build the rear ends of multiheaded trains with the front ones */
-				continue;
-			}
-
-			// check if the vehicle should be replaced
-			if (!p->engine_renew ||
-					w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old
-					w->max_age == 0) { // rail cars got a max age of 0
-				if (!EngineHasReplacementForPlayer(p, w->engine_type)) // updates to a new model
-					continue;
-			}
-
-			/* Now replace the vehicle */
-			temp_cost = ReplaceVehicle(&w, flags, cost);
-
-			if (flags & DC_EXEC &&
-					(w->type != VEH_Train || w->u.rail.first_engine == INVALID_ENGINE)) {
-				/* now we bought a new engine and sold the old one. We need to fix the
-				 * pointers in order to avoid pointing to the old one for trains: these
-				 * pointers should point to the front engine and not the cars
-				 */
-				v = w;
-			}
-
-			if (!CmdFailed(temp_cost)) {
-				cost += temp_cost;
-			}
-		} while (w->type == VEH_Train && (w = GetNextVehicle(w)) != NULL);
-
-		if (!(flags & DC_EXEC) && (p->money64 < (int32)(cost + p->engine_renew_money) || cost == 0)) {
-			if (!check && p->money64 < (int32)(cost + p->engine_renew_money) && ( _local_player == v->owner ) && cost != 0) {
-				StringID message;
-				SetDParam(0, v->unitnumber);
-				switch (v->type) {
-					case VEH_Train:    message = STR_TRAIN_AUTORENEW_FAILED;       break;
-					case VEH_Road:     message = STR_ROADVEHICLE_AUTORENEW_FAILED; break;
-					case VEH_Ship:     message = STR_SHIP_AUTORENEW_FAILED;        break;
-					case VEH_Aircraft: message = STR_AIRCRAFT_AUTORENEW_FAILED;    break;
-						// This should never happen
-					default: NOT_REACHED(); message = 0; break;
-				}
-
-				AddNewsItem(message, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
-			}
-			if (stopped) v->vehstatus &= ~VS_STOPPED;
-			if (display_costs) _current_player = OWNER_NONE;
-			return CMD_ERROR;
-		}
-
-		if (flags & DC_EXEC) {
-			break; // we are done replacing since the loop ran once with DC_EXEC
-		} else if (check) {
-			/* It's a test only and we know that we can do this
-			 * NOTE: payment for wagon removal is NOT included in this price */
-			return cost;
-		}
-		// now we redo the loop, but this time we actually do stuff since we know that we can do it
-		flags |= DC_EXEC;
-	}
-
-	/* If setting is on to try not to exceed the old length of the train with the replacement */
-	if (v->type == VEH_Train && p->renew_keep_length) {
-		Vehicle *temp;
-		w = v;
-
-		while (v->u.rail.cached_total_length > old_total_length) {
-			// the train is too long. We will remove cars one by one from the start of the train until it's short enough
-			while (w != NULL && !(RailVehInfo(w->engine_type)->flags&RVI_WAGON) ) {
-				w = GetNextVehicle(w);
-			}
-			if (w == NULL) {
-				// we failed to make the train short enough
-				SetDParam(0, v->unitnumber);
-				AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
-				break;
-			}
-			temp = w;
-			w = GetNextVehicle(w);
-			DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-			MoveVehicleCargo(v, temp);
-			cost += DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
-		}
-	}
-
-	if (stopped) v->vehstatus &= ~VS_STOPPED;
-	if (display_costs) {
-		if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
-		_current_player = OWNER_NONE;
-	}
-	return cost;
-}
-
-/* Extend the list size for BuildDepotVehicleList() */
-static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
-{
-	*engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
-	*engine_list = realloc((void*)*engine_list, (*engine_list_length) * sizeof((*engine_list)[0]));
-}
-
-/** Generates a list of vehicles inside a depot
- * Will enlarge allocated space for the list if they are too small, so it's ok to call with (pointer to NULL array, pointer to uninitised uint16, pointer to 0)
- * If one of the lists is not needed (say wagons when finding ships), all the pointers regarding that list should be set to NULL
- * @param Type type of vehicle
- * @param tile The tile the depot is located in
- * @param ***engine_list Pointer to a pointer to an array of vehicles in the depot (old list is freed and a new one is malloced)
- * @param *engine_list_length Allocated size of engine_list. Needs to be set to 0 when engine_list points to a NULL array
- * @param *engine_count The number of engines stored in the list
- * @param ***wagon_list Pointer to a pointer to an array of free wagons in the depot (old list is freed and a new one is malloced)
- * @param *wagon_list_length Allocated size of wagon_list. Needs to be set to 0 when wagon_list points to a NULL array
- * @param *wagon_count The number of engines stored in the list
- */
-void BuildDepotVehicleList(byte type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
-{
-	Vehicle *v;
-
-	/* This function should never be called without an array to store results */
-	assert(!(engine_list == NULL && type != VEH_Train));
-	assert(!(type == VEH_Train && engine_list == NULL && wagon_list == NULL));
-
-	/* Both array and the length should either be NULL to disable the list or both should not be NULL */
-	assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
-	assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
-
-	assert(!(engine_list != NULL && engine_count == NULL));
-	assert(!(wagon_list != NULL && wagon_count == NULL));
-
-	if (engine_count != NULL) *engine_count = 0;
-	if (wagon_count != NULL) *wagon_count = 0;
-
-	switch (type) {
-		case VEH_Train:
-			FOR_ALL_VEHICLES(v) {
-				if (v->tile == tile && v->type == VEH_Train && v->u.rail.track == 0x80) {
-					if (IsFrontEngine(v)) {
-						if (engine_list == NULL) continue;
-						if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
-						(*engine_list)[(*engine_count)++] = v;
-					} else if (IsFreeWagon(v)) {
-						if (wagon_list == NULL) continue;
-						if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
-						(*wagon_list)[(*wagon_count)++] = v;
-					}
-				}
-			}
-			break;
-
-		case VEH_Road:
-			FOR_ALL_VEHICLES(v) {
-				if (v->tile == tile && v->type == VEH_Road && IsRoadVehInDepot(v)) {
-					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
-					(*engine_list)[(*engine_count)++] = v;
-				}
-			}
-			break;
-
-		case VEH_Ship:
-			FOR_ALL_VEHICLES(v) {
-				if (v->tile == tile && v->type == VEH_Ship && IsShipInDepot(v)) {
-					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
-					(*engine_list)[(*engine_count)++] = v;
-				}
-			}
-			break;
-
-		case VEH_Aircraft:
-			FOR_ALL_VEHICLES(v) {
-				if (v->tile == tile &&
-						v->type == VEH_Aircraft &&
-						v->subtype <= 2 &&
-						v->vehstatus & VS_HIDDEN) {
-					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
-					(*engine_list)[(*engine_count)++] = v;
-				}
-			}
-			break;
-
-		default: NOT_REACHED();
-	}
-}
-
-/**
-* @param sort_list list to store the list in. Either NULL or the length length_of_array tells
-* @param length_of_array informs the length allocated for sort_list. This is not the same as the number of vehicles in the list. Needs to be 0 when sort_list is NULL
-* @param type type of vehicle
-* @param owner PlayerID of owner to generate a list for
-* @param station index of station to generate a list for. INVALID_STATION when not used
-* @param order index of oder to generate a list for. INVALID_ORDER when not used
-* @param window_type tells what kind of window the list is for. Use the VLW flags in vehicle_gui.h
-* @return the number of vehicles added to the list
-*/
-uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, byte type, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type)
-{
-	const uint subtype = (type != VEH_Aircraft) ? Train_Front : 2;
-	uint n = 0;
-	const Vehicle *v;
-
-	switch (window_type) {
-		case VLW_STATION_LIST: {
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == type && (
-					(type == VEH_Train && IsFrontEngine(v)) ||
-					(type != VEH_Train && v->subtype <= subtype))) {
-					const Order *order;
-
-					FOR_VEHICLE_ORDERS(v, order) {
-						if (order->type == OT_GOTO_STATION && order->dest == station) {
-							if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
-							(*sort_list)[n++] = v;
-							break;
-						}
-					}
-				}
-			}
-			break;
-		}
-
-		case VLW_SHARED_ORDERS: {
-			FOR_ALL_VEHICLES(v) {
-				/* Find a vehicle with the order in question */
-				if (v->orders != NULL && v->orders->index == order) break;
-			}
-
-			if (v != NULL && v->orders != NULL && v->orders->index == order) {
-				/* Only try to make the list if we found a vehicle using the order in question */
-				for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
-					if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
-					(*sort_list)[n++] = v;
-				}
-			}
-			break;
-		}
-
-		case VLW_STANDARD: {
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == type && v->owner == owner && (
-					(type == VEH_Train && IsFrontEngine(v)) ||
-					(type != VEH_Train && v->subtype <= subtype))) {
-					/* TODO find a better estimate on the total number of vehicles for current player */
-					if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4);
-					(*sort_list)[n++] = v;
-				}
-			}
-			break;
-		}
-
-		case VLW_DEPOT_LIST: {
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == type && (
-					(type == VEH_Train && IsFrontEngine(v)) ||
-					(type != VEH_Train && v->subtype <= subtype))) {
-					const Order *order;
-
-					FOR_VEHICLE_ORDERS(v, order) {
-						if (order->type == OT_GOTO_DEPOT && order->dest == depot_airport_index) {
-							if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
-							(*sort_list)[n++] = v;
-							break;
-						}
-					}
-				}
-			}
-			break;
-		}
-
-		default: NOT_REACHED(); break;
-	}
-
-	if ((n + 100) < *length_of_array) {
-		/* We allocated way too much for sort_list.
-		 * Now we will reduce how much we allocated.
-		 * We will still make it have room for 50 extra vehicles to prevent having
-		 * to move the whole array if just one vehicle is added later */
-		*length_of_array = n + 50;
-		*sort_list = realloc((void*)*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
-	}
-
-	return n;
-}
-
-/** send all vehicles of type to depots
- * @param type type of vehicle
- * @param flags the flags used for DoCommand()
- * @param service should the vehicles only get service in the depots
- * @param owner PlayerID of owner of the vehicles to send
- * @param VLW_flag tells what kind of list requested the goto depot
- * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot
- */
-int32 SendAllVehiclesToDepot(byte type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
-{
-	const Vehicle **sort_list = NULL;
-	uint n, i;
-	uint16 array_length = 0;
-
-	n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, id, id, vlw_flag);
-
-	/* Send all the vehicles to a depot */
-	for (i = 0; i < n; i++) {
-		const Vehicle *v = sort_list[i];
-		int32 ret = DoCommand(v->tile, v->index, service | DEPOT_DONT_CANCEL, flags, CMD_SEND_TO_DEPOT(type));
-
-		/* Return 0 if DC_EXEC is not set this is a valid goto depot command)
-			* In this case we know that at least one vehicle can be sent to a depot
-			* and we will issue the command. We can now safely quit the loop, knowing
-			* it will succeed at least once. With DC_EXEC we really need to send them to the depot */
-		if (!CmdFailed(ret) && !(flags & DC_EXEC)) {
-			free((void*)sort_list);
-			return 0;
-		}
-	}
-
-	free((void*)sort_list);
-	return (flags & DC_EXEC) ? 0 : CMD_ERROR;
-}
-
-bool IsVehicleInDepot(const Vehicle *v)
-{
-	switch (v->type) {
-		case VEH_Train:    return CheckTrainInDepot(v, false) != -1;
-		case VEH_Road:     return IsRoadVehInDepot(v);
-		case VEH_Ship:     return IsShipInDepot(v);
-		case VEH_Aircraft: return IsAircraftInHangar(v);
-		default: NOT_REACHED();
-	}
-	return false;
-}
-
-void VehicleEnterDepot(Vehicle *v)
-{
-	switch (v->type) {
-		case VEH_Train:
-			InvalidateWindowClasses(WC_TRAINS_LIST);
-			if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
-			UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile));
-			v->load_unload_time_rem = 0;
-			break;
-
-		case VEH_Road:
-			InvalidateWindowClasses(WC_ROADVEH_LIST);
-			v->u.road.state = 254;
-			break;
-
-		case VEH_Ship:
-			InvalidateWindowClasses(WC_SHIPS_LIST);
-			v->u.ship.state = 0x80;
-			RecalcShipStuff(v);
-			break;
-
-		case VEH_Aircraft:
-			InvalidateWindowClasses(WC_AIRCRAFT_LIST);
-			HandleAircraftEnterHangar(v);
-			break;
-		default: NOT_REACHED();
-	}
-
-	if (v->type != VEH_Train) {
-		/* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
-		 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
-		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-	}
-	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-
-	v->vehstatus |= VS_HIDDEN;
-	v->cur_speed = 0;
-
-	VehicleServiceInDepot(v);
-
-	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
-
-	if (v->current_order.type == OT_GOTO_DEPOT) {
-		Order t;
-
-		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
-
-		t = v->current_order;
-		v->current_order.type = OT_DUMMY;
-		v->current_order.flags = 0;
-
-		if (t.refit_cargo < NUM_CARGO) {
-			int32 cost;
-
-			_current_player = v->owner;
-			cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_VEH(v->type));
-
-			if (CmdFailed(cost)) {
-				v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
-				if (v->owner == _local_player) {
-					/* Notify the user that we stopped the vehicle */
-					SetDParam(0, _vehicle_type_names[v->type - 0x10]);
-					SetDParam(1, v->unitnumber);
-					AddNewsItem(STR_ORDER_REFIT_FAILED, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
-				}
-			} else if (v->owner == _local_player && cost != 0) {
-				ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
-			}
-		}
-
-		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) {
-			/* Part of orders */
-			if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
-			v->cur_order_index++;
-		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) {
-			/* Force depot visit */
-			v->vehstatus |= VS_STOPPED;
-			if (v->owner == _local_player) {
-				StringID string;
-
-				switch (v->type) {
-					case VEH_Train:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
-					case VEH_Road:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
-					case VEH_Ship:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
-					case VEH_Aircraft: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
-					default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
-				}
-
-				SetDParam(0, v->unitnumber);
-				AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),	v->index, 0);
-			}
-		}
-	}
-}
-
-/** Give a custom name to your vehicle
- * @param tile unused
- * @param p1 vehicle ID to name
- * @param p2 unused
- */
-int32 CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle *v;
-	StringID str;
-
-	if (!IsValidVehicleID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	str = AllocateNameUnique(_cmd_text, 2);
-	if (str == 0) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		StringID old_str = v->string_id;
-		v->string_id = str;
-		DeleteName(old_str);
-		ResortVehicleLists();
-		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
-	}
-
-	return 0;
-}
-
-
-/** Change the service interval of a vehicle
- * @param tile unused
- * @param p1 vehicle ID that is being service-interval-changed
- * @param p2 new service interval
- */
-int32 CmdChangeServiceInt(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Vehicle* v;
-	uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
-
-	if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
-
-	v = GetVehicle(p1);
-
-	if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		v->service_interval = serv_int;
-		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
-	}
-
-	return 0;
-}
-
-
-static Rect _old_vehicle_coords;
-
-void BeginVehicleMove(Vehicle *v) {
-	_old_vehicle_coords.left = v->left_coord;
-	_old_vehicle_coords.top = v->top_coord;
-	_old_vehicle_coords.right = v->right_coord;
-	_old_vehicle_coords.bottom = v->bottom_coord;
-}
-
-void EndVehicleMove(Vehicle *v)
-{
-	MarkAllViewportsDirty(
-		min(_old_vehicle_coords.left,v->left_coord),
-		min(_old_vehicle_coords.top,v->top_coord),
-		max(_old_vehicle_coords.right,v->right_coord)+1,
-		max(_old_vehicle_coords.bottom,v->bottom_coord)+1
-	);
-}
-
-/* returns true if staying in the same tile */
-bool GetNewVehiclePos(const Vehicle *v, GetNewVehiclePosResult *gp)
-{
-	static const int8 _delta_coord[16] = {
-		-1,-1,-1, 0, 1, 1, 1, 0, /* x */
-		-1, 0, 1, 1, 1, 0,-1,-1, /* y */
-	};
-
-	int x = v->x_pos + _delta_coord[v->direction];
-	int y = v->y_pos + _delta_coord[v->direction + 8];
-
-	gp->x = x;
-	gp->y = y;
-	gp->old_tile = v->tile;
-	gp->new_tile = TileVirtXY(x, y);
-	return gp->old_tile == gp->new_tile;
-}
-
-static const Direction _new_direction_table[] = {
-	DIR_N , DIR_NW, DIR_W ,
-	DIR_NE, DIR_SE, DIR_SW,
-	DIR_E , DIR_SE, DIR_S
-};
-
-Direction GetDirectionTowards(const Vehicle* v, int x, int y)
-{
-	Direction dir;
-	DirDiff dirdiff;
-	int i = 0;
-
-	if (y >= v->y_pos) {
-		if (y != v->y_pos) i+=3;
-		i+=3;
-	}
-
-	if (x >= v->x_pos) {
-		if (x != v->x_pos) i++;
-		i++;
-	}
-
-	dir = v->direction;
-
-	dirdiff = DirDifference(_new_direction_table[i], dir);
-	if (dirdiff == DIRDIFF_SAME) return dir;
-	return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
-}
-
-Trackdir GetVehicleTrackdir(const Vehicle* v)
-{
-	if (v->vehstatus & VS_CRASHED) return 0xFF;
-
-	switch (v->type) {
-		case VEH_Train:
-			if (v->u.rail.track == 0x80) /* We'll assume the train is facing outwards */
-				return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); /* Train in depot */
-
-			if (v->u.rail.track == 0x40) /* train in tunnel, so just use his direction and assume a diagonal track */
-				return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
-
-			return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.rail.track),v->direction);
-
-		case VEH_Ship:
-			if (IsShipInDepot(v))
-				/* We'll assume the ship is facing outwards */
-				return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
-
-			return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.ship.state),v->direction);
-
-		case VEH_Road:
-			if (IsRoadVehInDepot(v)) /* We'll assume the road vehicle is facing outwards */
-				return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
-
-			if (IsRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */
-				return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); /* Road vehicle in a station */
-
-			/* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
-			if ((v->u.road.state & 7) < 6) return v->u.road.state;
-
-			/* Vehicle is turning around, get the direction from vehicle's direction */
-			return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
-
-		/* case VEH_Aircraft: case VEH_Special: case VEH_Disaster: */
-		default: return 0xFF;
-	}
-}
-/* Return value has bit 0x2 set, when the vehicle enters a station. Then,
- * result << 8 contains the id of the station entered. If the return value has
- * bit 0x8 set, the vehicle could not and did not enter the tile. Are there
- * other bits that can be set? */
-uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
-{
-	return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
-}
-
-UnitID GetFreeUnitNumber(byte type)
-{
-	UnitID unit, max = 0;
-	const Vehicle *u;
-	static bool *cache = NULL;
-	static UnitID gmax = 0;
-
-	switch (type) {
-		case VEH_Train:    max = _patches.max_trains; break;
-		case VEH_Road:     max = _patches.max_roadveh; break;
-		case VEH_Ship:     max = _patches.max_ships; break;
-		case VEH_Aircraft: max = _patches.max_aircraft; break;
-		default: NOT_REACHED();
-	}
-
-	if (max == 0) {
-		/* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number
-		 * a max of 0 will cause the following code to write to a NULL pointer
-		 * We know that 1 is bigger than the max allowed vehicle number, so it's the same as returning something, that is too big
-		 */
-		return 1;
-	}
-
-	if (max > gmax) {
-		gmax = max;
-		free(cache);
-		cache = malloc((max + 1) * sizeof(*cache));
-	}
-
-	// Clear the cache
-	memset(cache, 0, (max + 1) * sizeof(*cache));
-
-	// Fill the cache
-	FOR_ALL_VEHICLES(u) {
-		if (u->type == type && u->owner == _current_player && u->unitnumber != 0 && u->unitnumber <= max)
-			cache[u->unitnumber] = true;
-	}
-
-	// Find the first unused unit number
-	for (unit = 1; unit <= max; unit++) {
-		if (!cache[unit]) break;
-	}
-
-	return unit;
-}
-
-static PalSpriteID GetEngineColourMap(EngineID engine_type, PlayerID player, EngineID parent_engine_type, CargoID cargo_type)
-{
-	SpriteID map;
-	const Player *p = GetPlayer(player);
-	LiveryScheme scheme = LS_DEFAULT;
-
-	/* The default livery is always available for use, but its in_use flag determines
-	 * whether any _other_ liveries are in use. */
-	if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
-		/* Determine the livery scheme to use */
-		switch (GetEngine(engine_type)->type) {
-			case VEH_Train: {
-				switch (_engine_info[engine_type].railtype) {
-					case RAILTYPE_RAIL:
-					case RAILTYPE_ELECTRIC:
-					{
-						const RailVehicleInfo *rvi = RailVehInfo(engine_type);
-
-						if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
-						if (rvi->flags & RVI_WAGON) {
-							if (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL || cargo_type == CT_VALUABLES) {
-								if (parent_engine_type == INVALID_ENGINE) {
-									scheme = LS_PASSENGER_WAGON_STEAM;
-								} else {
-									switch (RailVehInfo(parent_engine_type)->engclass) {
-										case 0: scheme = LS_PASSENGER_WAGON_STEAM; break;
-										case 1: scheme = LS_PASSENGER_WAGON_DIESEL; break;
-										case 2: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
-									}
-								}
-							} else {
-								scheme = LS_FREIGHT_WAGON;
-							}
-						} else {
-							bool is_mu = HASBIT(_engine_info[engine_type].misc_flags, EF_RAIL_IS_MU);
-
-							switch (rvi->engclass) {
-								case 0: scheme = LS_STEAM; break;
-								case 1: scheme = is_mu ? LS_DMU : LS_DIESEL; break;
-								case 2: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
-							}
-						}
-						break;
-					}
-
-					case RAILTYPE_MONO: scheme = LS_MONORAIL; break;
-					case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break;
-				}
-				break;
-			}
-
-			case VEH_Road: {
-				const RoadVehicleInfo *rvi = RoadVehInfo(engine_type);
-				if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
-				scheme = (cargo_type == CT_PASSENGERS) ? LS_BUS : LS_TRUCK;
-				break;
-			}
-
-			case VEH_Ship: {
-				const ShipVehicleInfo *svi = ShipVehInfo(engine_type);
-				if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type;
-				scheme = (cargo_type == CT_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
-				break;
-			}
-
-			case VEH_Aircraft: {
-				const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type);
-				if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS;
-				switch (avi->subtype) {
-					case 0: scheme = LS_HELICOPTER; break;
-					case 1: scheme = LS_SMALL_PLANE; break;
-					case 3: scheme = LS_LARGE_PLANE; break;
-				}
-				break;
-			}
-		}
-
-		/* Switch back to the default scheme if the resolved scheme is not in use */
-		if (!p->livery[scheme].in_use) scheme = LS_DEFAULT;
-	}
-
-	map = HASBIT(EngInfo(engine_type)->misc_flags, EF_USES_2CC) ?
-		(SPR_2CCMAP_BASE + p->livery[scheme].colour1 + p->livery[scheme].colour2 * 16) :
-		(PALETTE_RECOLOR_START + p->livery[scheme].colour1);
-
-	return SPRITE_PALETTE(map << PALETTE_SPRITE_START);
-}
-
-PalSpriteID GetEnginePalette(EngineID engine_type, PlayerID player)
-{
-	return GetEngineColourMap(engine_type, player, INVALID_ENGINE, CT_INVALID);
-}
-
-PalSpriteID GetVehiclePalette(const Vehicle *v)
-{
-	if (v->type == VEH_Train) {
-		return GetEngineColourMap(
-			(v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ?
-				v->u.rail.first_engine : v->engine_type,
-			v->owner,
-			v->u.rail.first_engine,
-			v->cargo_type);
-	}
-
-	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v->cargo_type);
-}
-
-// Save and load of vehicles
-const SaveLoad _common_veh_desc[] = {
-	    SLE_VAR(Vehicle, subtype,              SLE_UINT8),
-
-	    SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
-	    SLE_VAR(Vehicle, string_id,            SLE_STRINGID),
-	SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
-	SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, owner,                SLE_UINT8),
-	SLE_CONDVAR(Vehicle, tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, dest_tile,            SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, dest_tile,            SLE_UINT32,                  6, SL_MAX_VERSION),
-
-	SLE_CONDVAR(Vehicle, x_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, x_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, y_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, y_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, z_pos,                SLE_UINT8),
-	    SLE_VAR(Vehicle, direction,            SLE_UINT8),
-
-	    SLE_VAR(Vehicle, cur_image,            SLE_UINT16),
-	    SLE_VAR(Vehicle, spritenum,            SLE_UINT8),
-	    SLE_VAR(Vehicle, sprite_width,         SLE_UINT8),
-	    SLE_VAR(Vehicle, sprite_height,        SLE_UINT8),
-	    SLE_VAR(Vehicle, z_height,             SLE_UINT8),
-	    SLE_VAR(Vehicle, x_offs,               SLE_INT8),
-	    SLE_VAR(Vehicle, y_offs,               SLE_INT8),
-	    SLE_VAR(Vehicle, engine_type,          SLE_UINT16),
-
-	    SLE_VAR(Vehicle, max_speed,            SLE_UINT16),
-	    SLE_VAR(Vehicle, cur_speed,            SLE_UINT16),
-	    SLE_VAR(Vehicle, subspeed,             SLE_UINT8),
-	    SLE_VAR(Vehicle, acceleration,         SLE_UINT8),
-	    SLE_VAR(Vehicle, progress,             SLE_UINT8),
-
-	    SLE_VAR(Vehicle, vehstatus,            SLE_UINT8),
-	SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8  | SLE_VAR_U16,  0, 4),
-	SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16,                  5, SL_MAX_VERSION),
-
-	    SLE_VAR(Vehicle, cargo_type,           SLE_UINT8),
-	SLE_CONDVAR(Vehicle, cargo_subtype,        SLE_UINT8,                  35, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, cargo_days,           SLE_UINT8),
-	SLE_CONDVAR(Vehicle, cargo_source,         SLE_FILE_U8  | SLE_VAR_U16,  0, 6),
-	SLE_CONDVAR(Vehicle, cargo_source,         SLE_UINT16,                  7, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, cargo_cap,            SLE_UINT16),
-	    SLE_VAR(Vehicle, cargo_count,          SLE_UINT16),
-
-	    SLE_VAR(Vehicle, day_counter,          SLE_UINT8),
-	    SLE_VAR(Vehicle, tick_counter,         SLE_UINT8),
-
-	    SLE_VAR(Vehicle, cur_order_index,      SLE_UINT8),
-	    SLE_VAR(Vehicle, num_orders,           SLE_UINT8),
-
-	/* This next line is for version 4 and prior compatibility.. it temporarily reads
-	    type and flags (which were both 4 bits) into type. Later on this is
-	    converted correctly */
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, type), SLE_UINT8,                 0, 4),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
-
-	/* Orders for version 5 and on */
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, type),  SLE_UINT8,  5, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, flags), SLE_UINT8,  5, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest),  SLE_UINT16, 5, SL_MAX_VERSION),
-
-	/* Refit in current order */
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, refit_cargo),    SLE_UINT8, 36, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, refit_subtype),  SLE_UINT8, 36, SL_MAX_VERSION),
-
-	    SLE_REF(Vehicle, orders,               REF_ORDER),
-
-	SLE_CONDVAR(Vehicle, age,                  SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, age,                  SLE_INT32,                  31, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, max_age,              SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, max_age,              SLE_INT32,                  31, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32,                  31, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, service_interval,     SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, service_interval,     SLE_INT32,                  31, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, reliability,          SLE_UINT16),
-	    SLE_VAR(Vehicle, reliability_spd_dec,  SLE_UINT16),
-	    SLE_VAR(Vehicle, breakdown_ctr,        SLE_UINT8),
-	    SLE_VAR(Vehicle, breakdown_delay,      SLE_UINT8),
-	    SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
-	    SLE_VAR(Vehicle, breakdown_chance,     SLE_UINT8),
-	SLE_CONDVAR(Vehicle, build_year,           SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, build_year,           SLE_INT32,                 31, SL_MAX_VERSION),
-
-	    SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
-	SLE_CONDVAR(Vehicle, load_status,          SLE_UINT8,                 40, SL_MAX_VERSION),
-
-	    SLE_VAR(Vehicle, profit_this_year,     SLE_INT32),
-	    SLE_VAR(Vehicle, profit_last_year,     SLE_INT32),
-	    SLE_VAR(Vehicle, value,                SLE_UINT32),
-
-	    SLE_VAR(Vehicle, random_bits,          SLE_UINT8),
-	    SLE_VAR(Vehicle, waiting_triggers,     SLE_UINT8),
-
-	    SLE_REF(Vehicle, next_shared,          REF_VEHICLE),
-	    SLE_REF(Vehicle, prev_shared,          REF_VEHICLE),
-
-	// reserve extra space in savegame here. (currently 10 bytes)
-	SLE_CONDNULL(10,                                                       2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-
-static const SaveLoad _train_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_Train, 0), // Train type. VEH_Train in mem, 0 in file.
-	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, crash_anim_pos),         SLE_UINT16),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, force_proceed),          SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, railtype),               SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, track),                  SLE_UINT8),
-
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRail, flags),                  SLE_UINT8,  2, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRail, days_since_order_progr), SLE_UINT16, 2, SL_MAX_VERSION),
-
-	SLE_CONDNULL(2, 2, 19),
-	// reserve extra space in savegame here. (currently 11 bytes)
-	SLE_CONDNULL(11, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _roadveh_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_Road, 1), // Road type. VEH_Road in mem, 1 in file.
-	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, state),          SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, frame),          SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, blocked_ctr),    SLE_UINT16),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking),     SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, crashed_ctr),    SLE_UINT16),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, reverse_ctr),    SLE_UINT8),
-
-	SLE_CONDREFX(offsetof(Vehicle, u) + offsetof(VehicleRoad, slot),     REF_ROADSTOPS, 6, SL_MAX_VERSION),
-	SLE_CONDNULL(1,                                                                     6, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, slot_age), SLE_UINT8,     6, SL_MAX_VERSION),
-	// reserve extra space in savegame here. (currently 16 bytes)
-	SLE_CONDNULL(16,                                                                    2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _ship_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_Ship, 2), // Ship type. VEH_Ship in mem, 2 in file.
-	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
-	SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleShip, state), SLE_UINT8),
-
-	// reserve extra space in savegame here. (currently 16 bytes)
-	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _aircraft_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_Aircraft, 3), // Aircraft type. VEH_Aircraft in mem, 3 in file.
-	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, crashed_counter), SLE_UINT16),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, pos),             SLE_UINT8),
-
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport),   SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport),   SLE_UINT16,                5, SL_MAX_VERSION),
-
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, state),           SLE_UINT8),
-
-	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, previous_pos),    SLE_UINT8,                 2, SL_MAX_VERSION),
-
-	// reserve extra space in savegame here. (currently 15 bytes)
-	SLE_CONDNULL(15,                                                                                      2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _special_desc[] = {
-	SLE_WRITEBYTE(Vehicle,type,VEH_Special, 4),
-
-	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
-
-	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
-	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
-
-	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
-	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
-	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
-
-	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
-	    SLE_VAR(Vehicle, sprite_width,  SLE_UINT8),
-	    SLE_VAR(Vehicle, sprite_height, SLE_UINT8),
-	    SLE_VAR(Vehicle, z_height,      SLE_UINT8),
-	    SLE_VAR(Vehicle, x_offs,        SLE_INT8),
-	    SLE_VAR(Vehicle, y_offs,        SLE_INT8),
-	    SLE_VAR(Vehicle, progress,      SLE_UINT8),
-	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
-
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleSpecial, unk0), SLE_UINT16),
-	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleSpecial, unk2), SLE_UINT8),
-
-	// reserve extra space in savegame here. (currently 16 bytes)
-	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static const SaveLoad _disaster_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_Disaster, 5),
-
-	    SLE_REF(Vehicle, next,          REF_VEHICLE_OLD),
-
-	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
-	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, dest_tile,     SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Vehicle, dest_tile,     SLE_UINT32,                  6, SL_MAX_VERSION),
-
-	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
-	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
-	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
-	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
-	    SLE_VAR(Vehicle, direction,     SLE_UINT8),
-
-	    SLE_VAR(Vehicle, x_offs,        SLE_INT8),
-	    SLE_VAR(Vehicle, y_offs,        SLE_INT8),
-	    SLE_VAR(Vehicle, sprite_width,  SLE_UINT8),
-	    SLE_VAR(Vehicle, sprite_height, SLE_UINT8),
-	    SLE_VAR(Vehicle, z_height,      SLE_UINT8),
-	    SLE_VAR(Vehicle, owner,         SLE_UINT8),
-	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
-	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_UINT16,                5, SL_MAX_VERSION),
-
-	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
-	SLE_CONDVAR(Vehicle, age,           SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
-	SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
-	    SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
-
-	   SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleDisaster, image_override), SLE_UINT16),
-	   SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleDisaster, unk2),           SLE_UINT16),
-
-	// reserve extra space in savegame here. (currently 16 bytes)
-	SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-
-static const void *_veh_descs[] = {
-	_train_desc,
-	_roadveh_desc,
-	_ship_desc,
-	_aircraft_desc,
-	_special_desc,
-	_disaster_desc,
-};
-
-// Will be called when the vehicles need to be saved.
-static void Save_VEHS(void)
-{
-	Vehicle *v;
-	// Write the vehicles
-	FOR_ALL_VEHICLES(v) {
-		SlSetArrayIndex(v->index);
-		SlObject(v, _veh_descs[v->type - 0x10]);
-	}
-}
-
-// Will be called when vehicles need to be loaded.
-static void Load_VEHS(void)
-{
-	int index;
-	Vehicle *v;
-
-	while ((index = SlIterateArray()) != -1) {
-		Vehicle *v;
-
-		if (!AddBlockIfNeeded(&_Vehicle_pool, index))
-			error("Vehicles: failed loading savegame: too many vehicles");
-
-		v = GetVehicle(index);
-		SlObject(v, _veh_descs[SlReadByte()]);
-
-		/* Old savegames used 'last_station_visited = 0xFF' */
-		if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
-			v->last_station_visited = INVALID_STATION;
-
-		if (CheckSavegameVersion(5)) {
-			/* Convert the current_order.type (which is a mix of type and flags, because
-			 *  in those versions, they both were 4 bits big) to type and flags */
-			v->current_order.flags = (v->current_order.type & 0xF0) >> 4;
-			v->current_order.type  =  v->current_order.type & 0x0F;
-		}
-	}
-
-	/* Check for shared order-lists (we now use pointers for that) */
-	if (CheckSavegameVersionOldStyle(5, 2)) {
-		FOR_ALL_VEHICLES(v) {
-			Vehicle *u;
-
-			FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
-				/* If a vehicle has the same orders, add the link to eachother
-				 *  in both vehicles */
-				if (v->orders == u->orders) {
-					v->next_shared = u;
-					u->prev_shared = v;
-					break;
-				}
-			}
-		}
-	}
-}
-
-const ChunkHandler _veh_chunk_handlers[] = {
-	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/vehicle.cpp
@@ -0,0 +1,3228 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "road_map.h"
+#include "roadveh.h"
+#include "ship.h"
+#include "spritecache.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "vehicle.h"
+#include "gfx.h"
+#include "viewport.h"
+#include "news.h"
+#include "command.h"
+#include "saveload.h"
+#include "player.h"
+#include "engine.h"
+#include "sound.h"
+#include "debug.h"
+#include "vehicle_gui.h"
+#include "depot.h"
+#include "station.h"
+#include "rail.h"
+#include "train.h"
+#include "aircraft.h"
+#include "industry_map.h"
+#include "station_map.h"
+#include "water_map.h"
+#include "network/network.h"
+#include "yapf/yapf.h"
+#include "date.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+
+#define INVALID_COORD (-0x8000)
+#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
+
+/*
+ * These command macros are used to call vehicle type specific commands with non type specific commands
+ * it should be used like: DoCommandP(x, y, p1, p2, flags, CMD_STARTSTOP_VEH(v->type))
+ * that line will start/stop a vehicle nomatter what type it is
+ * VEH_Train is used as an offset because the vehicle type values doesn't start with 0
+ */
+
+#define CMD_BUILD_VEH(x) _veh_build_proc_table[ x - VEH_Train]
+#define CMD_SELL_VEH(x)  _veh_sell_proc_table [ x - VEH_Train]
+#define CMD_REFIT_VEH(x) _veh_refit_proc_table[ x - VEH_Train]
+
+static const uint32 _veh_build_proc_table[] = {
+	CMD_BUILD_RAIL_VEHICLE,
+	CMD_BUILD_ROAD_VEH,
+	CMD_BUILD_SHIP,
+	CMD_BUILD_AIRCRAFT,
+};
+static const uint32 _veh_sell_proc_table[] = {
+	CMD_SELL_RAIL_WAGON,
+	CMD_SELL_ROAD_VEH,
+	CMD_SELL_SHIP,
+	CMD_SELL_AIRCRAFT,
+};
+
+static const uint32 _veh_refit_proc_table[] = {
+	CMD_REFIT_RAIL_VEHICLE,
+	CMD_REFIT_ROAD_VEH,
+	CMD_REFIT_SHIP,
+	CMD_REFIT_AIRCRAFT,
+};
+
+const uint32 _send_to_depot_proc_table[] = {
+	CMD_SEND_TRAIN_TO_DEPOT,
+	CMD_SEND_ROADVEH_TO_DEPOT,
+	CMD_SEND_SHIP_TO_DEPOT,
+	CMD_SEND_AIRCRAFT_TO_HANGAR,
+};
+
+
+enum {
+	BLOCKS_FOR_SPECIAL_VEHICLES   = 2, ///< Blocks needed for special vehicles
+};
+
+/**
+ * Called if a new block is added to the vehicle-pool
+ */
+static void VehiclePoolNewBlock(uint start_item)
+{
+	Vehicle *v;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) v->index = start_item++;
+}
+
+/* Initialize the vehicle-pool */
+DEFINE_OLD_POOL(Vehicle, Vehicle, VehiclePoolNewBlock, NULL)
+
+void VehicleServiceInDepot(Vehicle *v)
+{
+	v->date_of_last_service = _date;
+	v->breakdowns_since_last_service = 0;
+	v->reliability = GetEngine(v->engine_type)->reliability;
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
+}
+
+bool VehicleNeedsService(const Vehicle *v)
+{
+	if (v->vehstatus & VS_CRASHED)
+		return false; /* Crashed vehicles don't need service anymore */
+
+	if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
+		return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type);  /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */
+	}
+
+	return _patches.servint_ispercent ?
+		(v->reliability < GetEngine(v->engine_type)->reliability * (100 - v->service_interval) / 100) :
+		(v->date_of_last_service + v->service_interval < _date);
+}
+
+StringID VehicleInTheWayErrMsg(const Vehicle* v)
+{
+	switch (v->type) {
+		case VEH_Train:    return STR_8803_TRAIN_IN_THE_WAY;
+		case VEH_Road:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
+		case VEH_Aircraft: return STR_A015_AIRCRAFT_IN_THE_WAY;
+		default:           return STR_980E_SHIP_IN_THE_WAY;
+	}
+}
+
+static void *EnsureNoVehicleProc(Vehicle *v, void *data)
+{
+	if (v->tile != *(const TileIndex*)data || v->type == VEH_Disaster)
+		return NULL;
+
+	_error_message = VehicleInTheWayErrMsg(v);
+	return v;
+}
+
+bool EnsureNoVehicle(TileIndex tile)
+{
+	return VehicleFromPos(tile, &tile, EnsureNoVehicleProc) == NULL;
+}
+
+static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
+{
+	const TileInfo *ti = data;
+
+	if (v->tile != ti->tile || v->type == VEH_Disaster) return NULL;
+	if (v->z_pos > ti->z) return NULL;
+
+	_error_message = VehicleInTheWayErrMsg(v);
+	return v;
+}
+
+
+bool EnsureNoVehicleOnGround(TileIndex tile)
+{
+	TileInfo ti;
+
+	ti.tile = tile;
+	ti.z = GetTileMaxZ(tile);
+	return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ) == NULL;
+}
+
+Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
+{
+	TileInfo ti;
+
+	ti.tile = tile;
+	ti.z = z;
+
+	return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ);
+}
+
+Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z)
+{
+	int x1 = TileX(from);
+	int y1 = TileY(from);
+	int x2 = TileX(to);
+	int y2 = TileY(to);
+	Vehicle *veh;
+
+	/* Make sure x1 < x2 or y1 < y2 */
+	if (x1 > x2 || y1 > y2) {
+		intswap(x1,x2);
+		intswap(y1,y2);
+	}
+	FOR_ALL_VEHICLES(veh) {
+		if ((veh->type == VEH_Train || veh->type == VEH_Road) && (z==0xFF || veh->z_pos == z)) {
+			if ((veh->x_pos>>4) >= x1 && (veh->x_pos>>4) <= x2 &&
+					(veh->y_pos>>4) >= y1 && (veh->y_pos>>4) <= y2) {
+				return veh;
+			}
+		}
+	}
+	return NULL;
+}
+
+
+static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
+
+void VehiclePositionChanged(Vehicle *v)
+{
+	int img = v->cur_image;
+	Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
+	const Sprite* spr = GetSprite(img);
+
+	pt.x += spr->x_offs;
+	pt.y += spr->y_offs;
+
+	UpdateVehiclePosHash(v, pt.x, pt.y);
+
+	v->left_coord = pt.x;
+	v->top_coord = pt.y;
+	v->right_coord = pt.x + spr->width + 2;
+	v->bottom_coord = pt.y + spr->height + 2;
+}
+
+// Called after load to update coordinates
+void AfterLoadVehicles(void)
+{
+	Vehicle *v;
+
+	FOR_ALL_VEHICLES(v) {
+		v->first = NULL;
+		if (v->type == VEH_Train) v->u.rail.first_engine = INVALID_ENGINE;
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))
+			TrainConsistChanged(v);
+	}
+
+	FOR_ALL_VEHICLES(v) {
+		switch (v->type) {
+			case VEH_Train: v->cur_image = GetTrainImage(v, v->direction); break;
+			case VEH_Road: v->cur_image = GetRoadVehImage(v, v->direction); break;
+			case VEH_Ship: v->cur_image = GetShipImage(v, v->direction); break;
+			case VEH_Aircraft:
+				if (v->subtype == 0 || v->subtype == 2) {
+					v->cur_image = GetAircraftImage(v, v->direction);
+					if (v->next != NULL) v->next->cur_image = v->cur_image;
+				}
+				break;
+			default: break;
+		}
+
+		v->left_coord = INVALID_COORD;
+		VehiclePositionChanged(v);
+	}
+}
+
+static Vehicle *InitializeVehicle(Vehicle *v)
+{
+	VehicleID index = v->index;
+	memset(v, 0, sizeof(Vehicle));
+	v->index = index;
+
+	assert(v->orders == NULL);
+
+	v->left_coord = INVALID_COORD;
+	v->first = NULL;
+	v->next = NULL;
+	v->next_hash = NULL;
+	v->string_id = 0;
+	v->next_shared = NULL;
+	v->prev_shared = NULL;
+	v->depot_list  = NULL;
+	v->random_bits = 0;
+	return v;
+}
+
+/**
+ * Get a value for a vehicle's random_bits.
+ * @return A random value from 0 to 255.
+ */
+byte VehicleRandomBits(void)
+{
+	return GB(Random(), 0, 8);
+}
+
+Vehicle *ForceAllocateSpecialVehicle(void)
+{
+	/* This stays a strange story.. there should always be room for special
+	 * vehicles (special effects all over the map), but with 65k of vehicles
+	 * is this realistic to double-check for that? For now we just reserve
+	 * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only
+	 * be used for special vehicles.. should work nicely :) */
+
+	Vehicle *v;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (v = GetVehicle(0); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
+		/* No more room for the special vehicles, return NULL */
+		if (v->index >= (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES)
+			return NULL;
+
+		if (!IsValidVehicle(v)) return InitializeVehicle(v);
+	}
+
+	return NULL;
+}
+
+/*
+ * finds a free vehicle in the memory or allocates a new one
+ * returns a pointer to the first free vehicle or NULL if all vehicles are in use
+ * *skip_vehicles is an offset to where in the array we should begin looking
+ * this is to avoid looping though the same vehicles more than once after we learned that they are not free
+ * this feature is used by AllocateVehicles() since it need to allocate more than one and when
+ * another block is added to _Vehicle_pool, since we only do that when we know it's already full
+ */
+static Vehicle *AllocateSingleVehicle(VehicleID *skip_vehicles)
+{
+	/* See note by ForceAllocateSpecialVehicle() why we skip the
+	 * first blocks */
+	Vehicle *v;
+	const int offset = (1 << Vehicle_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	if (*skip_vehicles < (_Vehicle_pool.total_items - offset)) { // make sure the offset in the array is not larger than the array itself
+		for (v = GetVehicle(offset + *skip_vehicles); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) {
+			(*skip_vehicles)++;
+			if (!IsValidVehicle(v)) return InitializeVehicle(v);
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Vehicle_pool))
+		return AllocateSingleVehicle(skip_vehicles);
+
+	return NULL;
+}
+
+
+Vehicle *AllocateVehicle(void)
+{
+	VehicleID counter = 0;
+	return AllocateSingleVehicle(&counter);
+}
+
+
+/** Allocates a lot of vehicles and frees them again
+ * @param vl pointer to an array of vehicles to get allocated. Can be NULL if the vehicles aren't needed (makes it test only)
+ * @param num number of vehicles to allocate room for
+ * @return true if there is room to allocate all the vehicles
+ */
+bool AllocateVehicles(Vehicle **vl, int num)
+{
+	int i;
+	Vehicle *v;
+	VehicleID counter = 0;
+
+	for (i = 0; i != num; i++) {
+		v = AllocateSingleVehicle(&counter);
+		if (v == NULL) {
+			return false;
+		}
+		if (vl != NULL) {
+			vl[i] = v;
+		}
+	}
+
+	return true;
+}
+
+
+static Vehicle *_vehicle_position_hash[0x1000];
+
+void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
+{
+	Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, 0);
+
+	// The hash area to scan
+	const int xl = GB(pt.x - 174, 7, 6);
+	const int xu = GB(pt.x + 104, 7, 6);
+	const int yl = GB(pt.y - 294, 6, 6) << 6;
+	const int yu = GB(pt.y +  56, 6, 6) << 6;
+
+	int x;
+	int y;
+
+	for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
+		for (x = xl;; x = (x + 1) & 0x3F) {
+			Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF];
+
+			while (v != NULL) {
+				void* a = proc(v, data);
+
+				if (a != NULL) return a;
+				v = v->next_hash;
+			}
+
+			if (x == xu) break;
+		}
+
+		if (y == yu) break;
+	}
+	return NULL;
+}
+
+
+static void UpdateVehiclePosHash(Vehicle* v, int x, int y)
+{
+	Vehicle **old_hash, **new_hash;
+	int old_x = v->left_coord;
+	int old_y = v->top_coord;
+
+	new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x,y)];
+	old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
+
+	if (old_hash == new_hash) return;
+
+	/* remove from hash table? */
+	if (old_hash != NULL) {
+		Vehicle *last = NULL;
+		Vehicle *u = *old_hash;
+		while (u != v) {
+			last = u;
+			u = u->next_hash;
+			assert(u != NULL);
+		}
+
+		if (last == NULL) {
+			*old_hash = v->next_hash;
+		} else {
+			last->next_hash = v->next_hash;
+		}
+	}
+
+	/* insert into hash table? */
+	if (new_hash != NULL) {
+		v->next_hash = *new_hash;
+		*new_hash = v;
+	}
+}
+
+void ResetVehiclePosHash(void)
+{
+	memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
+}
+
+void InitializeVehicles(void)
+{
+	uint i;
+
+	/* Clean the vehicle pool, and reserve enough blocks
+	 *  for the special vehicles, plus one for all the other
+	 *  vehicles (which is increased on-the-fly) */
+	CleanPool(&_Vehicle_pool);
+	AddBlockToPool(&_Vehicle_pool);
+	for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++) {
+		AddBlockToPool(&_Vehicle_pool);
+	}
+
+	ResetVehiclePosHash();
+}
+
+Vehicle *GetLastVehicleInChain(Vehicle *v)
+{
+	while (v->next != NULL) v = v->next;
+	return v;
+}
+
+/** Finds the previous vehicle in a chain, by a brute force search.
+ * This old function is REALLY slow because it searches through all vehicles to
+ * find the previous vehicle, but if v->first has not been set, then this function
+ * will need to be used to find the previous one. This function should never be
+ * called by anything but GetFirstVehicleInChain
+ */
+static Vehicle *GetPrevVehicleInChain_bruteforce(const Vehicle *v)
+{
+	Vehicle *u;
+
+	FOR_ALL_VEHICLES(u) if (u->type == VEH_Train && u->next == v) return u;
+
+	return NULL;
+}
+
+/** Find the previous vehicle in a chain, by using the v->first cache.
+ * While this function is fast, it cannot be used in the GetFirstVehicleInChain
+ * function, otherwise you'll end up in an infinite loop call
+ */
+Vehicle *GetPrevVehicleInChain(const Vehicle *v)
+{
+	Vehicle *u;
+	assert(v != NULL);
+
+	u = GetFirstVehicleInChain(v);
+
+	// Check to see if this is the first
+	if (v == u) return NULL;
+
+	for (; u->next != v; u = u->next) assert(u->next != NULL);
+
+	return u;
+}
+
+/** Finds the first vehicle in a chain.
+ * This function reads out the v->first cache. Should the cache be dirty,
+ * it determines the first vehicle in a chain, and updates the cache.
+ */
+Vehicle *GetFirstVehicleInChain(const Vehicle *v)
+{
+	Vehicle* u;
+
+	assert(v != NULL);
+
+	if (v->first != NULL) {
+		if (IsFrontEngine(v->first) || IsFreeWagon(v->first)) return v->first;
+
+		DEBUG(misc, 0, "v->first cache faulty. We shouldn't be here, rebuilding cache!");
+	}
+
+	/* It is the fact (currently) that newly built vehicles do not have
+	 * their ->first pointer set. When this is the case, go up to the
+	 * first engine and set the pointers correctly. Also the first pointer
+	 * is not saved in a savegame, so this has to be fixed up after loading */
+
+	/* Find the 'locomotive' or the first wagon in a chain */
+	while ((u = GetPrevVehicleInChain_bruteforce(v)) != NULL) v = u;
+
+	/* Set the first pointer of all vehicles in that chain to the first wagon */
+	if (IsFrontEngine(v) || IsFreeWagon(v))
+		for (u = (Vehicle *)v; u != NULL; u = u->next) u->first = (Vehicle *)v;
+
+	return (Vehicle*)v;
+}
+
+uint CountVehiclesInChain(const Vehicle* v)
+{
+	uint count = 0;
+	do count++; while ((v = v->next) != NULL);
+	return count;
+}
+
+/** Check if a vehicle is counted in num_engines in each player struct
+ * @param *v Vehicle to test
+ * @return true if the vehicle is counted in num_engines
+ */
+bool IsEngineCountable(const Vehicle *v)
+{
+	switch (v->type) {
+		case VEH_Aircraft: return (v->subtype <= 2); // don't count plane shadows and helicopter rotors
+		case VEH_Train:
+			return !IsArticulatedPart(v) && // tenders and other articulated parts
+			(!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines
+		case VEH_Road:
+		case VEH_Ship:
+			return true;
+		default: return false; // Only count player buildable vehicles
+	}
+}
+
+void DestroyVehicle(Vehicle *v)
+{
+	if (IsEngineCountable(v)) GetPlayer(v->owner)->num_engines[v->engine_type]--;
+
+	DeleteVehicleNews(v->index, INVALID_STRING_ID);
+
+	DeleteName(v->string_id);
+	if (v->type == VEH_Road) ClearSlot(v);
+
+	if (v->type != VEH_Train || (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))) {
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	}
+
+	UpdateVehiclePosHash(v, INVALID_COORD, 0);
+	v->next_hash = NULL;
+	if (v->orders != NULL) DeleteVehicleOrders(v);
+
+	/* Now remove any artic part. This will trigger an other
+	 *  destroy vehicle, which on his turn can remove any
+	 *  other artic parts. */
+	if (EngineHasArticPart(v)) DeleteVehicle(v->next);
+}
+
+void DeleteVehicleChain(Vehicle *v)
+{
+	do {
+		Vehicle *u = v;
+		v = GetNextVehicle(v);
+		DeleteVehicle(u);
+	} while (v != NULL);
+}
+
+
+void Aircraft_Tick(Vehicle *v);
+void RoadVeh_Tick(Vehicle *v);
+void Ship_Tick(Vehicle *v);
+void Train_Tick(Vehicle *v);
+static void EffectVehicle_Tick(Vehicle *v);
+void DisasterVehicle_Tick(Vehicle *v);
+static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs);
+
+// head of the linked list to tell what vehicles that visited a depot in a tick
+static Vehicle* _first_veh_in_depot_list;
+
+/** Adds a vehicle to the list of vehicles, that visited a depot this tick
+ * @param *v vehicle to add
+ */
+void VehicleEnteredDepotThisTick(Vehicle *v)
+{
+	// we need to set v->leave_depot_instantly as we have no control of it's contents at this time
+	if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) {
+		// we keep the vehicle in the depot since the user ordered it to stay
+		v->leave_depot_instantly = false;
+	} else {
+		// the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
+		// out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
+		// we store that we stopped the vehicle, so autoreplace can start it again
+		v->vehstatus |= VS_STOPPED;
+		v->leave_depot_instantly = true;
+	}
+
+	if (_first_veh_in_depot_list == NULL) {
+		_first_veh_in_depot_list = v;
+	} else {
+		Vehicle *w = _first_veh_in_depot_list;
+		while (w->depot_list != NULL) w = w->depot_list;
+		w->depot_list = v;
+	}
+}
+
+typedef void VehicleTickProc(Vehicle*);
+static VehicleTickProc* _vehicle_tick_procs[] = {
+	Train_Tick,
+	RoadVeh_Tick,
+	Ship_Tick,
+	Aircraft_Tick,
+	EffectVehicle_Tick,
+	DisasterVehicle_Tick,
+};
+
+void CallVehicleTicks(void)
+{
+	Vehicle *v;
+
+#ifdef ENABLE_NETWORK
+	// hotfix for desync problem:
+	//  for MP games invalidate the YAPF cache every tick to keep it exactly the same on the server and all clients
+	if (_networking) {
+		YapfNotifyTrackLayoutChange(0, 0);
+	}
+#endif //ENABLE_NETWORK
+
+	_first_veh_in_depot_list = NULL; // now we are sure it's initialized at the start of each tick
+
+	FOR_ALL_VEHICLES(v) {
+		_vehicle_tick_procs[v->type - 0x10](v);
+
+		switch (v->type) {
+			case VEH_Train:
+			case VEH_Road:
+			case VEH_Aircraft:
+			case VEH_Ship:
+				if (v->type == VEH_Train && IsTrainWagon(v)) continue;
+				if (v->type == VEH_Aircraft && v->subtype > 0) continue;
+
+				v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
+				/* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
+				if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
+
+				/* Play an alterate running sound every 16 ticks */
+				if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
+		}
+	}
+
+	// now we handle all the vehicles that entered a depot this tick
+	v = _first_veh_in_depot_list;
+	while (v != NULL) {
+		Vehicle *w = v->depot_list;
+		v->depot_list = NULL; // it should always be NULL at the end of each tick
+		MaybeReplaceVehicle(v, false, true);
+		v = w;
+	}
+}
+
+static bool CanFillVehicle_FullLoadAny(Vehicle *v)
+{
+	uint32 full = 0, not_full = 0;
+	bool keep_loading = false;
+	const GoodsEntry *ge = GetStation(v->last_station_visited)->goods;
+
+	//special handling of aircraft
+
+	//if the aircraft carries passengers and is NOT full, then
+	//continue loading, no matter how much mail is in
+	if (v->type == VEH_Aircraft &&
+			v->cargo_type == CT_PASSENGERS &&
+			v->cargo_cap != v->cargo_count) {
+		return true;
+	}
+
+	// patch should return "true" to continue loading, i.e. when there is no cargo type that is fully loaded.
+	do {
+		//Should never happen, but just in case future additions change this
+		assert(v->cargo_type<32);
+
+		if (v->cargo_cap != 0) {
+			uint32 mask = 1 << v->cargo_type;
+
+			if (v->cargo_cap == v->cargo_count) {
+				full |= mask;
+			} else if (GB(ge[v->cargo_type].waiting_acceptance, 0, 12) > 0 ||
+					(HASBIT(v->load_status, LS_CARGO_UNLOADING) && (ge[v->cargo_type].waiting_acceptance & 0x8000))) {
+				/* If there is any cargo waiting, or this vehicle is still unloading
+				 * and the station accepts the cargo, don't leave the station. */
+				keep_loading = true;
+			} else {
+				not_full |= mask;
+			}
+		}
+	} while ((v = v->next) != NULL);
+
+	// continue loading if there is a non full cargo type and no cargo type that is full
+	return keep_loading || (not_full && (full & ~not_full) == 0);
+}
+
+bool CanFillVehicle(Vehicle *v)
+{
+	TileIndex tile = v->tile;
+
+	if (IsTileType(tile, MP_STATION) ||
+			(v->type == VEH_Ship && (
+				IsTileType(TILE_ADDXY(tile,  1,  0), MP_STATION) ||
+				IsTileType(TILE_ADDXY(tile, -1,  0), MP_STATION) ||
+				IsTileType(TILE_ADDXY(tile,  0,  1), MP_STATION) ||
+				IsTileType(TILE_ADDXY(tile,  0, -1), MP_STATION) ||
+				IsTileType(TILE_ADDXY(tile, -2,  0), MP_STATION)
+			))) {
+
+		// If patch is active, use alternative CanFillVehicle-function
+		if (_patches.full_load_any && v->current_order.flags & OF_FULL_LOAD) return CanFillVehicle_FullLoadAny(v);
+
+		do {
+			if (v->cargo_count != v->cargo_cap) return true;
+		} while ((v = v->next) != NULL);
+	}
+	return false;
+}
+
+/** Check if a given engine type can be refitted to a given cargo
+ * @param engine_type Engine type to check
+ * @param cid_to check refit to this cargo-type
+ * @return true if it is possible, false otherwise
+ */
+bool CanRefitTo(EngineID engine_type, CargoID cid_to)
+{
+	CargoID cid = _global_cargo_id[_opt_ptr->landscape][cid_to];
+	return HASBIT(EngInfo(engine_type)->refit_mask, cid);
+}
+
+/** Find the first cargo type that an engine can be refitted to.
+ * @param engine Which engine to find cargo for.
+ * @return A climate dependent cargo type. CT_INVALID is returned if not refittable.
+ */
+CargoID FindFirstRefittableCargo(EngineID engine_type)
+{
+	CargoID cid;
+	uint32 refit_mask = EngInfo(engine_type)->refit_mask;
+
+	if (refit_mask != 0) {
+		for (cid = CT_PASSENGERS; cid < NUM_CARGO; cid++) {
+			if (HASBIT(refit_mask, _global_cargo_id[_opt_ptr->landscape][cid])) return cid;
+		}
+	}
+
+	return CT_INVALID;
+}
+
+/** Learn the price of refitting a certain engine
+* @param engine Which engine to refit
+* @return Price for refitting
+*/
+int32 GetRefitCost(EngineID engine_type)
+{
+	int32 base_cost = 0;
+
+	switch (GetEngine(engine_type)->type) {
+		case VEH_Ship: base_cost = _price.ship_base; break;
+		case VEH_Road: base_cost = _price.roadveh_base; break;
+		case VEH_Aircraft: base_cost = _price.aircraft_base; break;
+		case VEH_Train:
+			base_cost = 2 * ((RailVehInfo(engine_type)->flags & RVI_WAGON) ?
+							 _price.build_railwagon : _price.build_railvehicle);
+			break;
+		default: NOT_REACHED(); break;
+	}
+	return (EngInfo(engine_type)->refit_cost * base_cost) >> 10;
+}
+
+static void DoDrawVehicle(const Vehicle *v)
+{
+	uint32 image = v->cur_image;
+
+	if (v->vehstatus & VS_SHADOW) {
+		MAKE_TRANSPARENT(image);
+	} else if (v->vehstatus & VS_DEFPAL) {
+		image |= (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
+	}
+
+	AddSortableSpriteToDraw(image, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
+		v->sprite_width, v->sprite_height, v->z_height, v->z_pos);
+}
+
+void ViewportAddVehicles(DrawPixelInfo *dpi)
+{
+	// The bounding rectangle
+	const int l = dpi->left;
+	const int r = dpi->left + dpi->width;
+	const int t = dpi->top;
+	const int b = dpi->top + dpi->height;
+
+	// The hash area to scan
+	const int xl = GB(l - 70, 7, 6);
+	const int xu = GB(r,      7, 6);
+	const int yl = GB(t - 70, 6, 6) << 6;
+	const int yu = GB(b,      6, 6) << 6;
+
+	int x;
+	int y;
+
+	for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
+		for (x = xl;; x = (x + 1) & 0x3F) {
+			const Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF];
+
+			while (v != NULL) {
+				if (!(v->vehstatus & VS_HIDDEN) &&
+						l <= v->right_coord &&
+						t <= v->bottom_coord &&
+						r >= v->left_coord &&
+						b >= v->top_coord) {
+					DoDrawVehicle(v);
+				}
+				v = v->next_hash;
+			}
+
+			if (x == xu) break;
+		}
+
+		if (y == yu) break;
+	}
+}
+
+static void ChimneySmokeInit(Vehicle *v)
+{
+	uint32 r = Random();
+	v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
+	v->progress = GB(r, 16, 3);
+}
+
+static void ChimneySmokeTick(Vehicle *v)
+{
+	if (v->progress > 0) {
+		v->progress--;
+	} else {
+		TileIndex tile;
+
+		BeginVehicleMove(v);
+
+		tile = TileVirtXY(v->x_pos, v->y_pos);
+		if (!IsTileType(tile, MP_INDUSTRY)) {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+			return;
+		}
+
+		if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
+			v->cur_image++;
+		} else {
+			v->cur_image = SPR_CHIMNEY_SMOKE_0;
+		}
+		v->progress = 7;
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void SteamSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_STEAM_SMOKE_0;
+	v->progress = 12;
+}
+
+static void SteamSmokeTick(Vehicle *v)
+{
+	bool moved = false;
+
+	BeginVehicleMove(v);
+
+	v->progress++;
+
+	if ((v->progress & 7) == 0) {
+		v->z_pos++;
+		moved = true;
+	}
+
+	if ((v->progress & 0xF) == 4) {
+		if (v->cur_image != SPR_STEAM_SMOKE_4) {
+			v->cur_image++;
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+			return;
+		}
+		moved = true;
+	}
+
+	if (moved) {
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void DieselSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_DIESEL_SMOKE_0;
+	v->progress = 0;
+}
+
+static void DieselSmokeTick(Vehicle *v)
+{
+	v->progress++;
+
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		v->z_pos++;
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	} else if ((v->progress & 7) == 1) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_DIESEL_SMOKE_5) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+		}
+	}
+}
+
+static void ElectricSparkInit(Vehicle *v)
+{
+	v->cur_image = SPR_ELECTRIC_SPARK_0;
+	v->progress = 1;
+}
+
+static void ElectricSparkTick(Vehicle *v)
+{
+	if (v->progress < 2) {
+		v->progress++;
+	} else {
+		v->progress = 0;
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+		}
+	}
+}
+
+static void SmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_SMOKE_0;
+	v->progress = 12;
+}
+
+static void SmokeTick(Vehicle *v)
+{
+	bool moved = false;
+
+	BeginVehicleMove(v);
+
+	v->progress++;
+
+	if ((v->progress & 3) == 0) {
+		v->z_pos++;
+		moved = true;
+	}
+
+	if ((v->progress & 0xF) == 4) {
+		if (v->cur_image != SPR_SMOKE_4) {
+			v->cur_image++;
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+			return;
+		}
+		moved = true;
+	}
+
+	if (moved) {
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void ExplosionLargeInit(Vehicle *v)
+{
+	v->cur_image = SPR_EXPLOSION_LARGE_0;
+	v->progress = 0;
+}
+
+static void ExplosionLargeTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+		}
+	}
+}
+
+static void BreakdownSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_BREAKDOWN_SMOKE_0;
+	v->progress = 0;
+}
+
+static void BreakdownSmokeTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 7) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
+			v->cur_image++;
+		} else {
+			v->cur_image = SPR_BREAKDOWN_SMOKE_0;
+		}
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+
+	v->u.special.unk0--;
+	if (v->u.special.unk0 == 0) {
+		BeginVehicleMove(v);
+		EndVehicleMove(v);
+		DeleteVehicle(v);
+	}
+}
+
+static void ExplosionSmallInit(Vehicle *v)
+{
+	v->cur_image = SPR_EXPLOSION_SMALL_0;
+	v->progress = 0;
+}
+
+static void ExplosionSmallTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			DeleteVehicle(v);
+		}
+	}
+}
+
+static void BulldozerInit(Vehicle *v)
+{
+	v->cur_image = SPR_BULLDOZER_NE;
+	v->progress = 0;
+	v->u.special.unk0 = 0;
+	v->u.special.unk2 = 0;
+}
+
+typedef struct BulldozerMovement {
+	byte direction:2;
+	byte image:2;
+	byte duration:3;
+} BulldozerMovement;
+
+static const BulldozerMovement _bulldozer_movement[] = {
+	{ 0, 0, 4 },
+	{ 3, 3, 4 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 1, 1, 3 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 1, 1, 3 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 3, 3, 6 },
+	{ 2, 2, 6 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 },
+	{ 0, 0, 3 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 },
+	{ 0, 0, 3 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 }
+};
+
+static const struct {
+	int8 x;
+	int8 y;
+} _inc_by_dir[] = {
+	{ -1,  0 },
+	{  0,  1 },
+	{  1,  0 },
+	{  0, -1 }
+};
+
+static void BulldozerTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 7) == 0) {
+		const BulldozerMovement* b = &_bulldozer_movement[v->u.special.unk0];
+
+		BeginVehicleMove(v);
+
+		v->cur_image = SPR_BULLDOZER_NE + b->image;
+
+		v->x_pos += _inc_by_dir[b->direction].x;
+		v->y_pos += _inc_by_dir[b->direction].y;
+
+		v->u.special.unk2++;
+		if (v->u.special.unk2 >= b->duration) {
+			v->u.special.unk2 = 0;
+			v->u.special.unk0++;
+			if (v->u.special.unk0 == lengthof(_bulldozer_movement)) {
+				EndVehicleMove(v);
+				DeleteVehicle(v);
+				return;
+			}
+		}
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void BubbleInit(Vehicle *v)
+{
+	v->cur_image = SPR_BUBBLE_GENERATE_0;
+	v->spritenum = 0;
+	v->progress = 0;
+}
+
+typedef struct BubbleMovement {
+	int8 x:4;
+	int8 y:4;
+	int8 z:4;
+	byte image:4;
+} BubbleMovement;
+
+#define MK(x, y, z, i) { x, y, z, i }
+#define ME(i) { i, 4, 0, 0 }
+
+static const BubbleMovement _bubble_float_sw[] = {
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	ME(1)
+};
+
+
+static const BubbleMovement _bubble_float_ne[] = {
+	MK( 0, 0, 1, 0),
+	MK(-1, 0, 1, 1),
+	MK( 0, 0, 1, 0),
+	MK(-1, 0, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_float_se[] = {
+	MK(0, 0, 1, 0),
+	MK(0, 1, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 1, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_float_nw[] = {
+	MK(0,  0, 1, 0),
+	MK(0, -1, 1, 1),
+	MK(0,  0, 1, 0),
+	MK(0, -1, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_burst[] = {
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 7),
+	MK(0, 0, 1, 8),
+	MK(0, 0, 1, 9),
+	ME(0)
+};
+
+static const BubbleMovement _bubble_absorb[] = {
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 2),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	ME(2),
+	MK(0, 0, 0, 0xA),
+	MK(0, 0, 0, 0xB),
+	MK(0, 0, 0, 0xC),
+	MK(0, 0, 0, 0xD),
+	MK(0, 0, 0, 0xE),
+	ME(0)
+};
+#undef ME
+#undef MK
+
+static const BubbleMovement * const _bubble_movement[] = {
+	_bubble_float_sw,
+	_bubble_float_ne,
+	_bubble_float_se,
+	_bubble_float_nw,
+	_bubble_burst,
+	_bubble_absorb,
+};
+
+static void BubbleTick(Vehicle *v)
+{
+	/*
+	 * Warning: those effects can NOT use Random(), and have to use
+	 *  InteractiveRandom(), because somehow someone forgot to save
+	 *  spritenum to the savegame, and so it will cause desyncs in
+	 *  multiplayer!! (that is: in ToyLand)
+	 */
+	uint et;
+	const BubbleMovement *b;
+
+	v->progress++;
+	if ((v->progress & 3) != 0)
+		return;
+
+	BeginVehicleMove(v);
+
+	if (v->spritenum == 0) {
+		v->cur_image++;
+		if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+			return;
+		}
+		if (v->u.special.unk2 != 0) {
+			v->spritenum = GB(InteractiveRandom(), 0, 2) + 1;
+		} else {
+			v->spritenum = 6;
+		}
+		et = 0;
+	} else {
+		et = v->engine_type + 1;
+	}
+
+	b = &_bubble_movement[v->spritenum - 1][et];
+
+	if (b->y == 4 && b->x == 0) {
+		EndVehicleMove(v);
+		DeleteVehicle(v);
+		return;
+	}
+
+	if (b->y == 4 && b->x == 1) {
+		if (v->z_pos > 180 || CHANCE16I(1, 96, InteractiveRandom())) {
+			v->spritenum = 5;
+			SndPlayVehicleFx(SND_2F_POP, v);
+		}
+		et = 0;
+	}
+
+	if (b->y == 4 && b->x == 2) {
+		TileIndex tile;
+
+		et++;
+		SndPlayVehicleFx(SND_31_EXTRACT, v);
+
+		tile = TileVirtXY(v->x_pos, v->y_pos);
+		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == 0xA2) AddAnimatedTile(tile);
+	}
+
+	v->engine_type = et;
+	b = &_bubble_movement[v->spritenum - 1][et];
+
+	v->x_pos += b->x;
+	v->y_pos += b->y;
+	v->z_pos += b->z;
+	v->cur_image = SPR_BUBBLE_0 + b->image;
+
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+}
+
+
+typedef void EffectInitProc(Vehicle *v);
+typedef void EffectTickProc(Vehicle *v);
+
+static EffectInitProc * const _effect_init_procs[] = {
+	ChimneySmokeInit,
+	SteamSmokeInit,
+	DieselSmokeInit,
+	ElectricSparkInit,
+	SmokeInit,
+	ExplosionLargeInit,
+	BreakdownSmokeInit,
+	ExplosionSmallInit,
+	BulldozerInit,
+	BubbleInit,
+};
+
+static EffectTickProc * const _effect_tick_procs[] = {
+	ChimneySmokeTick,
+	SteamSmokeTick,
+	DieselSmokeTick,
+	ElectricSparkTick,
+	SmokeTick,
+	ExplosionLargeTick,
+	BreakdownSmokeTick,
+	ExplosionSmallTick,
+	BulldozerTick,
+	BubbleTick,
+};
+
+
+Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type)
+{
+	Vehicle *v;
+
+	v = ForceAllocateSpecialVehicle();
+	if (v != NULL) {
+		v->type = VEH_Special;
+		v->subtype = type;
+		v->x_pos = x;
+		v->y_pos = y;
+		v->z_pos = z;
+		v->z_height = v->sprite_width = v->sprite_height = 1;
+		v->x_offs = v->y_offs = 0;
+		v->tile = 0;
+		v->vehstatus = VS_UNCLICKABLE;
+
+		_effect_init_procs[type](v);
+
+		VehiclePositionChanged(v);
+		BeginVehicleMove(v);
+		EndVehicleMove(v);
+	}
+	return v;
+}
+
+Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type)
+{
+	int safe_x = clamp(x, 0, MapMaxX() * TILE_SIZE);
+	int safe_y = clamp(y, 0, MapMaxY() * TILE_SIZE);
+	return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
+}
+
+Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type)
+{
+	return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
+}
+
+static void EffectVehicle_Tick(Vehicle *v)
+{
+	_effect_tick_procs[v->subtype](v);
+}
+
+Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
+{
+	Vehicle *found = NULL, *v;
+	uint dist, best_dist = (uint)-1;
+
+	if ( (uint)(x -= vp->left) >= (uint)vp->width ||
+			 (uint)(y -= vp->top) >= (uint)vp->height)
+				return NULL;
+
+	x = (x << vp->zoom) + vp->virtual_left;
+	y = (y << vp->zoom) + vp->virtual_top;
+
+	FOR_ALL_VEHICLES(v) {
+		if ((v->vehstatus & (VS_HIDDEN|VS_UNCLICKABLE)) == 0 &&
+				x >= v->left_coord && x <= v->right_coord &&
+				y >= v->top_coord && y <= v->bottom_coord) {
+
+			dist = max(
+				myabs( ((v->left_coord + v->right_coord)>>1) - x ),
+				myabs( ((v->top_coord + v->bottom_coord)>>1) - y )
+			);
+
+			if (dist < best_dist) {
+				found = v;
+				best_dist = dist;
+			}
+		}
+	}
+
+	return found;
+}
+
+
+void DecreaseVehicleValue(Vehicle *v)
+{
+	v->value -= v->value >> 8;
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+}
+
+static const byte _breakdown_chance[64] = {
+	  3,   3,   3,   3,   3,   3,   3,   3,
+	  4,   4,   5,   5,   6,   6,   7,   7,
+	  8,   8,   9,   9,  10,  10,  11,  11,
+	 12,  13,  13,  13,  13,  14,  15,  16,
+	 17,  19,  21,  25,  28,  31,  34,  37,
+	 40,  44,  48,  52,  56,  60,  64,  68,
+	 72,  80,  90, 100, 110, 120, 130, 140,
+	150, 170, 190, 210, 230, 250, 250, 250,
+};
+
+void CheckVehicleBreakdown(Vehicle *v)
+{
+	int rel, rel_old;
+	uint32 r;
+	int chance;
+
+	/* decrease reliability */
+	v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
+	if ((rel_old >> 8) != (rel >> 8))
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+	if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
+			v->cur_speed < 5 || _game_mode == GM_MENU) {
+		return;
+	}
+
+	r = Random();
+
+	/* increase chance of failure */
+	chance = v->breakdown_chance + 1;
+	if (CHANCE16I(1,25,r)) chance += 25;
+	v->breakdown_chance = min(255, chance);
+
+	/* calculate reliability value to use in comparison */
+	rel = v->reliability;
+	if (v->type == VEH_Ship) rel += 0x6666;
+
+	/* disabled breakdowns? */
+	if (_opt.diff.vehicle_breakdowns < 1) return;
+
+	/* reduced breakdowns? */
+	if (_opt.diff.vehicle_breakdowns == 1) rel += 0x6666;
+
+	/* check if to break down */
+	if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
+		v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
+		v->breakdown_delay  = GB(r, 24, 7) + 0x80;
+		v->breakdown_chance = 0;
+	}
+}
+
+static const StringID _vehicle_type_names[4] = {
+	STR_019F_TRAIN,
+	STR_019C_ROAD_VEHICLE,
+	STR_019E_SHIP,
+	STR_019D_AIRCRAFT,
+};
+
+static void ShowVehicleGettingOld(Vehicle *v, StringID msg)
+{
+	if (v->owner != _local_player) return;
+
+	// Do not show getting-old message if autorenew is active
+	if (GetPlayer(v->owner)->engine_renew) return;
+
+	SetDParam(0, _vehicle_type_names[v->type - 0x10]);
+	SetDParam(1, v->unitnumber);
+	AddNewsItem(msg, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+}
+
+void AgeVehicle(Vehicle *v)
+{
+	int age;
+
+	if (v->age < 65535)
+		v->age++;
+
+	age = v->age - v->max_age;
+	if (age == 366*0 || age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4)
+		v->reliability_spd_dec <<= 1;
+
+	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+
+	if (age == -366) {
+		ShowVehicleGettingOld(v, STR_01A0_IS_GETTING_OLD);
+	} else if (age == 0) {
+		ShowVehicleGettingOld(v, STR_01A1_IS_GETTING_VERY_OLD);
+	} else if (age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4 || age == 366*5) {
+		ShowVehicleGettingOld(v, STR_01A2_IS_GETTING_VERY_OLD_AND);
+	}
+}
+
+/** Starts or stops a lot of vehicles
+ * @param tile Tile of the depot where the vehicles are started/stopped (only used for depots)
+ * @param p1 Station/Order/Depot ID (only used for vehicle list windows)
+ * @param p2 bitmask
+ *   - bit 0-4 Vehicle type
+ *   - bit 5 false = start vehicles, true = stop vehicles
+ *   - bit 6 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case
+ *   - bit 8-11 Vehicle List Window type (ignored unless bit 1 is set)
+ */
+int32 CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle **vl = NULL;
+	uint16 engine_list_length = 0;
+	uint16 engine_count = 0;
+	int32 return_value = CMD_ERROR;
+	uint i;
+	uint stop_command;
+	byte vehicle_type = GB(p2, 0, 5);
+	bool start_stop = HASBIT(p2, 5);
+	bool vehicle_list_window = HASBIT(p2, 6);
+
+	switch (vehicle_type) {
+		case VEH_Train:    stop_command = CMD_START_STOP_TRAIN;    break;
+		case VEH_Road:     stop_command = CMD_START_STOP_ROADVEH;  break;
+		case VEH_Ship:     stop_command = CMD_START_STOP_SHIP;     break;
+		case VEH_Aircraft: stop_command = CMD_START_STOP_AIRCRAFT; break;
+		default: return CMD_ERROR;
+	}
+
+	if (vehicle_list_window) {
+		uint16 id = GB(p1, 0, 16);
+		uint16 window_type = p2 & VLW_MASK;
+
+		engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, id, id, window_type);
+	} else {
+		/* Get the list of vehicles in the depot */
+		BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
+	}
+
+	for (i = 0; i < engine_count; i++) {
+		const Vehicle *v = vl[i];
+		int32 ret;
+
+		if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
+
+		if (!vehicle_list_window) {
+			if (vehicle_type == VEH_Train) {
+				if (CheckTrainInDepot(v, false) == -1) continue;
+			} else {
+				if (!(v->vehstatus & VS_HIDDEN)) continue;
+			}
+		}
+
+		ret = DoCommand(tile, v->index, 0, flags, stop_command);
+
+		if (!CmdFailed(ret)) {
+			return_value = 0;
+			/* We know that the command is valid for at least one vehicle.
+			 * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
+			if (!(flags & DC_EXEC)) break;
+		}
+	}
+
+	free(vl);
+	return return_value;
+}
+
+/** Sells all vehicles in a depot
+* @param tile Tile of the depot where the depot is
+* @param p1 Vehicle type
+* @param p2 unused
+*/
+int32 CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle **engines = NULL;
+	Vehicle **wagons = NULL;
+	uint16 engine_list_length = 0;
+	uint16 engine_count = 0;
+	uint16 wagon_list_length = 0;
+	uint16 wagon_count = 0;
+
+	int32 cost = 0;
+	uint i, sell_command, total_number_vehicles;
+	byte vehicle_type = GB(p1, 0, 8);
+
+	switch (vehicle_type) {
+		case VEH_Train:    sell_command = CMD_SELL_RAIL_WAGON; break;
+		case VEH_Road:     sell_command = CMD_SELL_ROAD_VEH;   break;
+		case VEH_Ship:     sell_command = CMD_SELL_SHIP;       break;
+		case VEH_Aircraft: sell_command = CMD_SELL_AIRCRAFT;   break;
+		default: return CMD_ERROR;
+	}
+
+	/* Get the list of vehicles in the depot */
+	BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
+						                      &wagons,  &wagon_list_length,  &wagon_count);
+
+	total_number_vehicles = engine_count + wagon_count;
+	for (i = 0; i < total_number_vehicles; i++) {
+		const Vehicle *v;
+		int32 ret;
+
+		if (i < engine_count) {
+			v = engines[i];
+		} else {
+			v = wagons[i - engine_count];
+		}
+
+		ret = DoCommand(tile, v->index, 1, flags, sell_command);
+
+		if (!CmdFailed(ret)) cost += ret;
+	}
+
+	free(engines);
+	free(wagons);
+	if (cost == 0) return CMD_ERROR; // no vehicles to sell
+	return cost;
+}
+
+/** Autoreplace all vehicles in the depot
+* @param tile Tile of the depot where the vehicles are
+* @param p1 Type of vehicle
+* @param p2 Unused
+*/
+int32 CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle **vl = NULL;
+	uint16 engine_list_length = 0;
+	uint16 engine_count = 0;
+	uint i, x = 0, y = 0, z = 0;
+	int32 cost = 0;
+	byte vehicle_type = GB(p1, 0, 8);
+
+
+	if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
+
+	/* Get the list of vehicles in the depot */
+	BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
+
+
+	for (i = 0; i < engine_count; i++) {
+		Vehicle *v = vl[i];
+		bool stopped = !(v->vehstatus & VS_STOPPED);
+		int32 ret;
+
+		/* Ensure that the vehicle completely in the depot */
+		if (!IsVehicleInDepot(v)) continue;
+
+		x = v->x_pos;
+		y = v->y_pos;
+		z = v->z_pos;
+
+		if (stopped) {
+			v->vehstatus |= VS_STOPPED; // Stop the vehicle
+			v->leave_depot_instantly = true;
+		}
+		ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false);
+
+		if (!CmdFailed(ret)) {
+			cost += ret;
+			if (!(flags & DC_EXEC)) break;
+			/* There is a problem with autoreplace and newgrf
+			 * It's impossible to tell the length of a train after it's being replaced before it's actually done
+			 * Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
+			 * Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
+			 * we should never reach a condition where the player will end up with negative money from doing this */
+			SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+			SubtractMoneyFromPlayer(ret);
+		}
+	}
+
+	if (cost == 0) {
+		cost = CMD_ERROR;
+	} else {
+		if (flags & DC_EXEC) {
+			/* Display the cost animation now that DoCommandP() can't do it for us (see previous comments) */
+			if (IsLocalPlayer()) ShowCostOrIncomeAnimation(x, y, z, cost);
+		}
+		cost = 0;
+	}
+
+	free(vl);
+	return cost;
+}
+
+/** Clone a vehicle. If it is a train, it will clone all the cars too
+ * @param tile tile of the depot where the cloned vehicle is build
+ * @param p1 the original vehicle's index
+ * @param p2 1 = shared orders, else copied orders
+ */
+int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v_front, *v;
+	Vehicle *w_front, *w, *w_rear;
+	int cost, total_cost = 0;
+	uint32 build_argument = 2;
+
+	if (!IsValidVehicleID(p1)) return CMD_ERROR;
+	v = GetVehicle(p1);
+	v_front = v;
+	w = NULL;
+	w_front = NULL;
+	w_rear = NULL;
+
+
+	/*
+	 * v_front is the front engine in the original vehicle
+	 * v is the car/vehicle of the original vehicle, that is currently being copied
+	 * w_front is the front engine of the cloned vehicle
+	 * w is the car/vehicle currently being cloned
+	 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
+	 */
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (v->type == VEH_Train && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
+
+	// check that we can allocate enough vehicles
+	if (!(flags & DC_EXEC)) {
+		int veh_counter = 0;
+		do {
+			veh_counter++;
+		} while ((v = v->next) != NULL);
+
+		if (!AllocateVehicles(NULL, veh_counter)) {
+			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
+		}
+	}
+
+	v = v_front;
+
+	do {
+
+		if (IsMultiheaded(v) && !IsTrainEngine(v)) {
+			/* we build the rear ends of multiheaded trains with the front ones */
+			continue;
+		}
+
+		cost = DoCommand(tile, v->engine_type, build_argument, flags, CMD_BUILD_VEH(v->type));
+		build_argument = 3; // ensure that we only assign a number to the first engine
+
+		if (CmdFailed(cost)) return cost;
+
+		total_cost += cost;
+
+		if (flags & DC_EXEC) {
+			w = GetVehicle(_new_vehicle_id);
+
+			if (v->cargo_type != w->cargo_type || v->cargo_subtype != w->cargo_subtype) {
+				// we can't pay for refitting because we can't estimate refitting costs for a vehicle before it's build
+				// if we pay for it anyway, the cost and the estimated cost will not be the same and we will have an assert
+				DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8), flags, CMD_REFIT_VEH(v->type));
+			}
+			if (v->type == VEH_Train && HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
+				SETBIT(w->u.rail.flags, VRF_REVERSE_DIRECTION);
+			}
+
+			if (v->type == VEH_Train && !IsFrontEngine(v)) {
+				// this s a train car
+				// add this unit to the end of the train
+				DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
+			} else {
+				// this is a front engine or not a train. It need orders
+				w_front = w;
+				w->service_interval = v->service_interval;
+				DoCommand(0, (v->index << 16) | w->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
+			}
+			w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
+		}
+	} while (v->type == VEH_Train && (v = GetNextVehicle(v)) != NULL);
+
+	if (flags & DC_EXEC && v_front->type == VEH_Train) {
+		// for trains this needs to be the front engine due to the callback function
+		_new_vehicle_id = w_front->index;
+	}
+
+	/* Set the expense type last as refitting will make the cost go towards
+	 * running costs... */
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+	return total_cost;
+}
+
+/*
+ * move the cargo from one engine to another if possible
+ */
+static void MoveVehicleCargo(Vehicle *dest, Vehicle *source)
+{
+	Vehicle *v = dest;
+	int units_moved;
+
+	do {
+		do {
+			if (source->cargo_type != dest->cargo_type)
+				continue; // cargo not compatible
+
+			if (dest->cargo_count == dest->cargo_cap)
+				continue; // the destination vehicle is already full
+
+			units_moved = min(source->cargo_count, dest->cargo_cap - dest->cargo_count);
+			source->cargo_count -= units_moved;
+			dest->cargo_count   += units_moved;
+			dest->cargo_source   = source->cargo_source;
+
+			// copy the age of the cargo
+			dest->cargo_days   = source->cargo_days;
+			dest->day_counter  = source->day_counter;
+			dest->tick_counter = source->tick_counter;
+
+		} while (source->cargo_count > 0 && (dest = dest->next) != NULL);
+		dest = v;
+	} while ((source = source->next) != NULL);
+}
+
+static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, const EngineID engine_type)
+{
+	const Order *o;
+	const Vehicle *u;
+
+	if (v->type == VEH_Train) {
+		u = GetFirstVehicleInChain(v);
+	} else {
+		u = v;
+	}
+
+	FOR_VEHICLE_ORDERS(u, o) {
+		if (!(o->refit_cargo < NUM_CARGO)) continue;
+		if (!CanRefitTo(v->engine_type, o->refit_cargo)) continue;
+		if (!CanRefitTo(engine_type, o->refit_cargo)) return false;
+	}
+
+	return true;
+}
+
+/**
+ * Function to find what type of cargo to refit to when autoreplacing
+ * @param *v Original vehicle, that is being replaced
+ * @param engine_type The EngineID of the vehicle that is being replaced to
+ * @return The cargo type to replace to
+ *    CT_NO_REFIT is returned if no refit is needed
+ *    CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible
+ */
+static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type)
+{
+	bool new_cargo_capacity = true;
+	CargoID new_cargo_type = CT_INVALID;
+
+	switch (v->type) {
+		case VEH_Train:
+			new_cargo_capacity = (RailVehInfo(engine_type)->capacity > 0);
+			new_cargo_type     = RailVehInfo(engine_type)->cargo_type;
+			break;
+
+		case VEH_Road:
+			new_cargo_capacity = (RoadVehInfo(engine_type)->capacity > 0);
+			new_cargo_type     = RoadVehInfo(engine_type)->cargo_type;
+			break;
+		case VEH_Ship:
+			new_cargo_capacity = (ShipVehInfo(engine_type)->capacity > 0);
+			new_cargo_type     = ShipVehInfo(engine_type)->cargo_type;
+			break;
+
+		case VEH_Aircraft:
+			/* all aircraft starts as passenger planes with cargo capacity
+			 * new_cargo_capacity is always true for aircraft, which is the init value. No need to set it here */
+			new_cargo_type     = CT_PASSENGERS;
+			break;
+
+		default: NOT_REACHED(); break;
+	}
+
+	if (!new_cargo_capacity) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity
+
+	if (v->cargo_type == new_cargo_type || CanRefitTo(engine_type, v->cargo_type)) {
+		if (VerifyAutoreplaceRefitForOrders(v, engine_type)) {
+			return v->cargo_type == new_cargo_type ? CT_NO_REFIT : v->cargo_type;
+		} else {
+			return CT_INVALID;
+		}
+	}
+	if (v->type != VEH_Train) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want
+
+	/* Below this line it's safe to assume that the vehicle in question is a train */
+
+	if (v->cargo_cap != 0) return CT_INVALID; // trying to replace a vehicle with cargo capacity into another one with incompatible cargo type
+
+	/* the old engine didn't have cargo capacity, but the new one does
+	 * now we will figure out what cargo the train is carrying and refit to fit this */
+	v = GetFirstVehicleInChain(v);
+	do {
+		if (v->cargo_cap == 0) continue;
+		/* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */
+		if (v->cargo_type == new_cargo_type) return CT_NO_REFIT;
+		if (CanRefitTo(engine_type, v->cargo_type)) return v->cargo_type;
+	} while ((v=v->next) != NULL);
+	return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
+}
+
+/* Replaces a vehicle (used to be called autorenew)
+ * This function is only called from MaybeReplaceVehicle()
+ * Must be called with _current_player set to the owner of the vehicle
+ * @param w Vehicle to replace
+ * @param flags is the flags to use when calling DoCommand(). Mainly DC_EXEC counts
+ * @return value is cost of the replacement or CMD_ERROR
+ */
+static int32 ReplaceVehicle(Vehicle **w, byte flags, int32 total_cost)
+{
+	int32 cost;
+	int32 sell_value;
+	Vehicle *old_v = *w;
+	const Player *p = GetPlayer(old_v->owner);
+	EngineID new_engine_type;
+	const UnitID cached_unitnumber = old_v->unitnumber;
+	bool new_front = false;
+	Vehicle *new_v = NULL;
+	char vehicle_name[32];
+	CargoID replacement_cargo_type;
+
+	new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type);
+	if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type;
+
+	replacement_cargo_type = GetNewCargoTypeForReplace(old_v, new_engine_type);
+
+	/* check if we can't refit to the needed type, so no replace takes place to prevent the vehicle from altering cargo type */
+	if (replacement_cargo_type == CT_INVALID) return 0;
+
+	sell_value = DoCommand(0, old_v->index, 0, DC_QUERY_COST, CMD_SELL_VEH(old_v->type));
+
+	/* We give the player a loan of the same amount as the sell value.
+	 * This is needed in case he needs the income from the sale to build the new vehicle.
+	 * We take it back if building fails or when we really sell the old engine */
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+	SubtractMoneyFromPlayer(sell_value);
+
+	cost = DoCommand(old_v->tile, new_engine_type, 3, flags, CMD_BUILD_VEH(old_v->type));
+	if (CmdFailed(cost)) {
+		SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+		SubtractMoneyFromPlayer(-sell_value); // Take back the money we just gave the player
+		return cost;
+	}
+
+	if (replacement_cargo_type != CT_NO_REFIT) cost += GetRefitCost(new_engine_type); // add refit cost
+
+	if (flags & DC_EXEC) {
+		new_v = GetVehicle(_new_vehicle_id);
+		*w = new_v; //we changed the vehicle, so MaybeReplaceVehicle needs to work on the new one. Now we tell it what the new one is
+
+		/* refit if needed */
+		if (replacement_cargo_type != CT_NO_REFIT) {
+			if (CmdFailed(DoCommand(0, new_v->index, replacement_cargo_type, DC_EXEC, CMD_REFIT_VEH(new_v->type)))) {
+				/* Being here shows a failure, which most likely is in GetNewCargoTypeForReplace() or incorrect estimation costs */
+				error("Autoreplace failed to refit. Replace engine %d to %d and refit to cargo %d", old_v->engine_type, new_v->engine_type, replacement_cargo_type);
+			}
+		}
+
+		if (new_v->type == VEH_Train && HASBIT(old_v->u.rail.flags, VRF_REVERSE_DIRECTION) && !IsMultiheaded(new_v) && !(new_v->next != NULL && IsArticulatedPart(new_v->next))) {
+			// we are autorenewing to a single engine, so we will turn it as the old one was turned as well
+			SETBIT(new_v->u.rail.flags, VRF_REVERSE_DIRECTION);
+		}
+
+		if (old_v->type == VEH_Train && !IsFrontEngine(old_v)) {
+			/* this is a railcar. We need to move the car into the train
+			 * We add the new engine after the old one instead of replacing it. It will give the same result anyway when we
+			 * sell the old engine in a moment
+			 */
+			DoCommand(0, (GetPrevVehicleInChain(old_v)->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+			/* Now we move the old one out of the train */
+			DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+		} else {
+			// copy/clone the orders
+			DoCommand(0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
+			new_v->cur_order_index = old_v->cur_order_index;
+			ChangeVehicleViewWindow(old_v, new_v);
+			new_v->profit_this_year = old_v->profit_this_year;
+			new_v->profit_last_year = old_v->profit_last_year;
+			new_v->service_interval = old_v->service_interval;
+			new_front = true;
+			new_v->unitnumber = old_v->unitnumber; // use the same unit number
+
+			new_v->current_order = old_v->current_order;
+			if (old_v->type == VEH_Train && GetNextVehicle(old_v) != NULL){
+				Vehicle *temp_v = GetNextVehicle(old_v);
+
+				// move the entire train to the new engine, excluding the old engine
+				if (IsMultiheaded(old_v) && temp_v == old_v->u.rail.other_multiheaded_part) {
+					// we got front and rear of a multiheaded engine right after each other. We should work with the next in line instead
+					temp_v = GetNextVehicle(temp_v);
+				}
+
+				if (temp_v != NULL) {
+					DoCommand(0, (new_v->index << 16) | temp_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+				}
+			}
+		}
+		/* We are done setting up the new vehicle. Now we move the cargo from the old one to the new one */
+		MoveVehicleCargo(new_v->type == VEH_Train ? GetFirstVehicleInChain(new_v) : new_v, old_v);
+
+		// Get the name of the old vehicle if it has a custom name.
+		if (!IsCustomName(old_v->string_id)) {
+			vehicle_name[0] = '\0';
+		} else {
+			GetName(vehicle_name, old_v->string_id & 0x7FF, lastof(vehicle_name));
+		}
+	} else { // flags & DC_EXEC not set
+		/* Ensure that the player will not end up having negative money while autoreplacing
+		 * This is needed because the only other check is done after the income from selling the old vehicle is substracted from the cost */
+		if (p->money64 < (cost + total_cost)) {
+			SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+			SubtractMoneyFromPlayer(-sell_value); // Pay back the loan
+			return CMD_ERROR;
+		}
+	}
+
+	/* Take back the money we just gave the player just before building the vehicle
+	 * The player will get the same amount now that the sale actually takes place */
+	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
+	SubtractMoneyFromPlayer(-sell_value);
+
+	/* sell the engine/ find out how much you get for the old engine (income is returned as negative cost) */
+	cost += DoCommand(0, old_v->index, 0, flags, CMD_SELL_VEH(old_v->type));
+
+	if (new_front) {
+		/* now we assign the old unitnumber to the new vehicle */
+		new_v->unitnumber = cached_unitnumber;
+	}
+
+	/* Transfer the name of the old vehicle */
+	if ((flags & DC_EXEC) && vehicle_name[0] != '\0') {
+		_cmd_text = vehicle_name;
+		DoCommand(0, new_v->index, 0, DC_EXEC, CMD_NAME_VEHICLE);
+	}
+
+	return cost;
+}
+
+/** replaces a vehicle if it's set for autoreplace or is too old
+ * (used to be called autorenew)
+ * @param v The vehicle to replace
+ * if the vehicle is a train, v needs to be the front engine
+ * @param check Checks if the replace is valid. No action is done at all
+ * @param display_costs If set, a cost animation is shown (only if check is false)
+ * @return CMD_ERROR if something went wrong. Otherwise the price of the replace
+ */
+static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs)
+{
+	Vehicle *w;
+	const Player *p = GetPlayer(v->owner);
+	byte flags = 0;
+	int32 cost, temp_cost = 0;
+	bool stopped = false;
+
+	/* Remember the length in case we need to trim train later on
+	 * If it's not a train, the value is unused
+	 * round up to the length of the tiles used for the train instead of the train length instead
+	 * Useful when newGRF uses custom length */
+	uint16 old_total_length = (v->type == VEH_Train ?
+		(v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE :
+		-1
+	);
+
+
+	_current_player = v->owner;
+
+	assert(v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship || v->type == VEH_Aircraft);
+
+	assert(v->vehstatus & VS_STOPPED); // the vehicle should have been stopped in VehicleEnteredDepotThisTick() if needed
+
+	if (v->leave_depot_instantly) {
+		// we stopped the vehicle to do this, so we have to remember to start it again when we are done
+		// we need to store this info as the engine might be replaced and lose this info
+		stopped = true;
+	}
+
+	for (;;) {
+		cost = 0;
+		w = v;
+		do {
+			if (w->type == VEH_Train && IsMultiheaded(w) && !IsTrainEngine(w)) {
+				/* we build the rear ends of multiheaded trains with the front ones */
+				continue;
+			}
+
+			// check if the vehicle should be replaced
+			if (!p->engine_renew ||
+					w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old
+					w->max_age == 0) { // rail cars got a max age of 0
+				if (!EngineHasReplacementForPlayer(p, w->engine_type)) // updates to a new model
+					continue;
+			}
+
+			/* Now replace the vehicle */
+			temp_cost = ReplaceVehicle(&w, flags, cost);
+
+			if (flags & DC_EXEC &&
+					(w->type != VEH_Train || w->u.rail.first_engine == INVALID_ENGINE)) {
+				/* now we bought a new engine and sold the old one. We need to fix the
+				 * pointers in order to avoid pointing to the old one for trains: these
+				 * pointers should point to the front engine and not the cars
+				 */
+				v = w;
+			}
+
+			if (!CmdFailed(temp_cost)) {
+				cost += temp_cost;
+			}
+		} while (w->type == VEH_Train && (w = GetNextVehicle(w)) != NULL);
+
+		if (!(flags & DC_EXEC) && (p->money64 < (int32)(cost + p->engine_renew_money) || cost == 0)) {
+			if (!check && p->money64 < (int32)(cost + p->engine_renew_money) && ( _local_player == v->owner ) && cost != 0) {
+				StringID message;
+				SetDParam(0, v->unitnumber);
+				switch (v->type) {
+					case VEH_Train:    message = STR_TRAIN_AUTORENEW_FAILED;       break;
+					case VEH_Road:     message = STR_ROADVEHICLE_AUTORENEW_FAILED; break;
+					case VEH_Ship:     message = STR_SHIP_AUTORENEW_FAILED;        break;
+					case VEH_Aircraft: message = STR_AIRCRAFT_AUTORENEW_FAILED;    break;
+						// This should never happen
+					default: NOT_REACHED(); message = 0; break;
+				}
+
+				AddNewsItem(message, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+			}
+			if (stopped) v->vehstatus &= ~VS_STOPPED;
+			if (display_costs) _current_player = OWNER_NONE;
+			return CMD_ERROR;
+		}
+
+		if (flags & DC_EXEC) {
+			break; // we are done replacing since the loop ran once with DC_EXEC
+		} else if (check) {
+			/* It's a test only and we know that we can do this
+			 * NOTE: payment for wagon removal is NOT included in this price */
+			return cost;
+		}
+		// now we redo the loop, but this time we actually do stuff since we know that we can do it
+		flags |= DC_EXEC;
+	}
+
+	/* If setting is on to try not to exceed the old length of the train with the replacement */
+	if (v->type == VEH_Train && p->renew_keep_length) {
+		Vehicle *temp;
+		w = v;
+
+		while (v->u.rail.cached_total_length > old_total_length) {
+			// the train is too long. We will remove cars one by one from the start of the train until it's short enough
+			while (w != NULL && !(RailVehInfo(w->engine_type)->flags&RVI_WAGON) ) {
+				w = GetNextVehicle(w);
+			}
+			if (w == NULL) {
+				// we failed to make the train short enough
+				SetDParam(0, v->unitnumber);
+				AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+				break;
+			}
+			temp = w;
+			w = GetNextVehicle(w);
+			DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+			MoveVehicleCargo(v, temp);
+			cost += DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
+		}
+	}
+
+	if (stopped) v->vehstatus &= ~VS_STOPPED;
+	if (display_costs) {
+		if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
+		_current_player = OWNER_NONE;
+	}
+	return cost;
+}
+
+/* Extend the list size for BuildDepotVehicleList() */
+static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
+{
+	*engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
+	*engine_list = realloc((void*)*engine_list, (*engine_list_length) * sizeof((*engine_list)[0]));
+}
+
+/** Generates a list of vehicles inside a depot
+ * Will enlarge allocated space for the list if they are too small, so it's ok to call with (pointer to NULL array, pointer to uninitised uint16, pointer to 0)
+ * If one of the lists is not needed (say wagons when finding ships), all the pointers regarding that list should be set to NULL
+ * @param Type type of vehicle
+ * @param tile The tile the depot is located in
+ * @param ***engine_list Pointer to a pointer to an array of vehicles in the depot (old list is freed and a new one is malloced)
+ * @param *engine_list_length Allocated size of engine_list. Needs to be set to 0 when engine_list points to a NULL array
+ * @param *engine_count The number of engines stored in the list
+ * @param ***wagon_list Pointer to a pointer to an array of free wagons in the depot (old list is freed and a new one is malloced)
+ * @param *wagon_list_length Allocated size of wagon_list. Needs to be set to 0 when wagon_list points to a NULL array
+ * @param *wagon_count The number of engines stored in the list
+ */
+void BuildDepotVehicleList(byte type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
+{
+	Vehicle *v;
+
+	/* This function should never be called without an array to store results */
+	assert(!(engine_list == NULL && type != VEH_Train));
+	assert(!(type == VEH_Train && engine_list == NULL && wagon_list == NULL));
+
+	/* Both array and the length should either be NULL to disable the list or both should not be NULL */
+	assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
+	assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
+
+	assert(!(engine_list != NULL && engine_count == NULL));
+	assert(!(wagon_list != NULL && wagon_count == NULL));
+
+	if (engine_count != NULL) *engine_count = 0;
+	if (wagon_count != NULL) *wagon_count = 0;
+
+	switch (type) {
+		case VEH_Train:
+			FOR_ALL_VEHICLES(v) {
+				if (v->tile == tile && v->type == VEH_Train && v->u.rail.track == 0x80) {
+					if (IsFrontEngine(v)) {
+						if (engine_list == NULL) continue;
+						if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
+						(*engine_list)[(*engine_count)++] = v;
+					} else if (IsFreeWagon(v)) {
+						if (wagon_list == NULL) continue;
+						if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
+						(*wagon_list)[(*wagon_count)++] = v;
+					}
+				}
+			}
+			break;
+
+		case VEH_Road:
+			FOR_ALL_VEHICLES(v) {
+				if (v->tile == tile && v->type == VEH_Road && IsRoadVehInDepot(v)) {
+					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
+					(*engine_list)[(*engine_count)++] = v;
+				}
+			}
+			break;
+
+		case VEH_Ship:
+			FOR_ALL_VEHICLES(v) {
+				if (v->tile == tile && v->type == VEH_Ship && IsShipInDepot(v)) {
+					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
+					(*engine_list)[(*engine_count)++] = v;
+				}
+			}
+			break;
+
+		case VEH_Aircraft:
+			FOR_ALL_VEHICLES(v) {
+				if (v->tile == tile &&
+						v->type == VEH_Aircraft &&
+						v->subtype <= 2 &&
+						v->vehstatus & VS_HIDDEN) {
+					if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
+					(*engine_list)[(*engine_count)++] = v;
+				}
+			}
+			break;
+
+		default: NOT_REACHED();
+	}
+}
+
+/**
+* @param sort_list list to store the list in. Either NULL or the length length_of_array tells
+* @param length_of_array informs the length allocated for sort_list. This is not the same as the number of vehicles in the list. Needs to be 0 when sort_list is NULL
+* @param type type of vehicle
+* @param owner PlayerID of owner to generate a list for
+* @param station index of station to generate a list for. INVALID_STATION when not used
+* @param order index of oder to generate a list for. INVALID_ORDER when not used
+* @param window_type tells what kind of window the list is for. Use the VLW flags in vehicle_gui.h
+* @return the number of vehicles added to the list
+*/
+uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, byte type, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type)
+{
+	const uint subtype = (type != VEH_Aircraft) ? Train_Front : 2;
+	uint n = 0;
+	const Vehicle *v;
+
+	switch (window_type) {
+		case VLW_STATION_LIST: {
+			FOR_ALL_VEHICLES(v) {
+				if (v->type == type && (
+					(type == VEH_Train && IsFrontEngine(v)) ||
+					(type != VEH_Train && v->subtype <= subtype))) {
+					const Order *order;
+
+					FOR_VEHICLE_ORDERS(v, order) {
+						if (order->type == OT_GOTO_STATION && order->dest == station) {
+							if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
+							(*sort_list)[n++] = v;
+							break;
+						}
+					}
+				}
+			}
+			break;
+		}
+
+		case VLW_SHARED_ORDERS: {
+			FOR_ALL_VEHICLES(v) {
+				/* Find a vehicle with the order in question */
+				if (v->orders != NULL && v->orders->index == order) break;
+			}
+
+			if (v != NULL && v->orders != NULL && v->orders->index == order) {
+				/* Only try to make the list if we found a vehicle using the order in question */
+				for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+					if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
+					(*sort_list)[n++] = v;
+				}
+			}
+			break;
+		}
+
+		case VLW_STANDARD: {
+			FOR_ALL_VEHICLES(v) {
+				if (v->type == type && v->owner == owner && (
+					(type == VEH_Train && IsFrontEngine(v)) ||
+					(type != VEH_Train && v->subtype <= subtype))) {
+					/* TODO find a better estimate on the total number of vehicles for current player */
+					if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4);
+					(*sort_list)[n++] = v;
+				}
+			}
+			break;
+		}
+
+		case VLW_DEPOT_LIST: {
+			FOR_ALL_VEHICLES(v) {
+				if (v->type == type && (
+					(type == VEH_Train && IsFrontEngine(v)) ||
+					(type != VEH_Train && v->subtype <= subtype))) {
+					const Order *order;
+
+					FOR_VEHICLE_ORDERS(v, order) {
+						if (order->type == OT_GOTO_DEPOT && order->dest == depot_airport_index) {
+							if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
+							(*sort_list)[n++] = v;
+							break;
+						}
+					}
+				}
+			}
+			break;
+		}
+
+		default: NOT_REACHED(); break;
+	}
+
+	if ((n + 100) < *length_of_array) {
+		/* We allocated way too much for sort_list.
+		 * Now we will reduce how much we allocated.
+		 * We will still make it have room for 50 extra vehicles to prevent having
+		 * to move the whole array if just one vehicle is added later */
+		*length_of_array = n + 50;
+		*sort_list = realloc((void*)*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
+	}
+
+	return n;
+}
+
+/** send all vehicles of type to depots
+ * @param type type of vehicle
+ * @param flags the flags used for DoCommand()
+ * @param service should the vehicles only get service in the depots
+ * @param owner PlayerID of owner of the vehicles to send
+ * @param VLW_flag tells what kind of list requested the goto depot
+ * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot
+ */
+int32 SendAllVehiclesToDepot(byte type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
+{
+	const Vehicle **sort_list = NULL;
+	uint n, i;
+	uint16 array_length = 0;
+
+	n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, id, id, vlw_flag);
+
+	/* Send all the vehicles to a depot */
+	for (i = 0; i < n; i++) {
+		const Vehicle *v = sort_list[i];
+		int32 ret = DoCommand(v->tile, v->index, service | DEPOT_DONT_CANCEL, flags, CMD_SEND_TO_DEPOT(type));
+
+		/* Return 0 if DC_EXEC is not set this is a valid goto depot command)
+			* In this case we know that at least one vehicle can be sent to a depot
+			* and we will issue the command. We can now safely quit the loop, knowing
+			* it will succeed at least once. With DC_EXEC we really need to send them to the depot */
+		if (!CmdFailed(ret) && !(flags & DC_EXEC)) {
+			free((void*)sort_list);
+			return 0;
+		}
+	}
+
+	free((void*)sort_list);
+	return (flags & DC_EXEC) ? 0 : CMD_ERROR;
+}
+
+bool IsVehicleInDepot(const Vehicle *v)
+{
+	switch (v->type) {
+		case VEH_Train:    return CheckTrainInDepot(v, false) != -1;
+		case VEH_Road:     return IsRoadVehInDepot(v);
+		case VEH_Ship:     return IsShipInDepot(v);
+		case VEH_Aircraft: return IsAircraftInHangar(v);
+		default: NOT_REACHED();
+	}
+	return false;
+}
+
+void VehicleEnterDepot(Vehicle *v)
+{
+	switch (v->type) {
+		case VEH_Train:
+			InvalidateWindowClasses(WC_TRAINS_LIST);
+			if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
+			UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile));
+			v->load_unload_time_rem = 0;
+			break;
+
+		case VEH_Road:
+			InvalidateWindowClasses(WC_ROADVEH_LIST);
+			v->u.road.state = 254;
+			break;
+
+		case VEH_Ship:
+			InvalidateWindowClasses(WC_SHIPS_LIST);
+			v->u.ship.state = 0x80;
+			RecalcShipStuff(v);
+			break;
+
+		case VEH_Aircraft:
+			InvalidateWindowClasses(WC_AIRCRAFT_LIST);
+			HandleAircraftEnterHangar(v);
+			break;
+		default: NOT_REACHED();
+	}
+
+	if (v->type != VEH_Train) {
+		/* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
+		 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
+		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+	}
+	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+
+	v->vehstatus |= VS_HIDDEN;
+	v->cur_speed = 0;
+
+	VehicleServiceInDepot(v);
+
+	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
+
+	if (v->current_order.type == OT_GOTO_DEPOT) {
+		Order t;
+
+		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+
+		t = v->current_order;
+		v->current_order.type = OT_DUMMY;
+		v->current_order.flags = 0;
+
+		if (t.refit_cargo < NUM_CARGO) {
+			int32 cost;
+
+			_current_player = v->owner;
+			cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_VEH(v->type));
+
+			if (CmdFailed(cost)) {
+				v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
+				if (v->owner == _local_player) {
+					/* Notify the user that we stopped the vehicle */
+					SetDParam(0, _vehicle_type_names[v->type - 0x10]);
+					SetDParam(1, v->unitnumber);
+					AddNewsItem(STR_ORDER_REFIT_FAILED, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+				}
+			} else if (v->owner == _local_player && cost != 0) {
+				ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
+			}
+		}
+
+		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) {
+			/* Part of orders */
+			if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
+			v->cur_order_index++;
+		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) {
+			/* Force depot visit */
+			v->vehstatus |= VS_STOPPED;
+			if (v->owner == _local_player) {
+				StringID string;
+
+				switch (v->type) {
+					case VEH_Train:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
+					case VEH_Road:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
+					case VEH_Ship:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
+					case VEH_Aircraft: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
+					default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
+				}
+
+				SetDParam(0, v->unitnumber);
+				AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),	v->index, 0);
+			}
+		}
+	}
+}
+
+/** Give a custom name to your vehicle
+ * @param tile unused
+ * @param p1 vehicle ID to name
+ * @param p2 unused
+ */
+int32 CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle *v;
+	StringID str;
+
+	if (!IsValidVehicleID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	str = AllocateNameUnique(_cmd_text, 2);
+	if (str == 0) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		StringID old_str = v->string_id;
+		v->string_id = str;
+		DeleteName(old_str);
+		ResortVehicleLists();
+		MarkWholeScreenDirty();
+	} else {
+		DeleteName(str);
+	}
+
+	return 0;
+}
+
+
+/** Change the service interval of a vehicle
+ * @param tile unused
+ * @param p1 vehicle ID that is being service-interval-changed
+ * @param p2 new service interval
+ */
+int32 CmdChangeServiceInt(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Vehicle* v;
+	uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
+
+	if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
+
+	v = GetVehicle(p1);
+
+	if (!CheckOwnership(v->owner)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		v->service_interval = serv_int;
+		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
+	}
+
+	return 0;
+}
+
+
+static Rect _old_vehicle_coords;
+
+void BeginVehicleMove(Vehicle *v) {
+	_old_vehicle_coords.left = v->left_coord;
+	_old_vehicle_coords.top = v->top_coord;
+	_old_vehicle_coords.right = v->right_coord;
+	_old_vehicle_coords.bottom = v->bottom_coord;
+}
+
+void EndVehicleMove(Vehicle *v)
+{
+	MarkAllViewportsDirty(
+		min(_old_vehicle_coords.left,v->left_coord),
+		min(_old_vehicle_coords.top,v->top_coord),
+		max(_old_vehicle_coords.right,v->right_coord)+1,
+		max(_old_vehicle_coords.bottom,v->bottom_coord)+1
+	);
+}
+
+/* returns true if staying in the same tile */
+bool GetNewVehiclePos(const Vehicle *v, GetNewVehiclePosResult *gp)
+{
+	static const int8 _delta_coord[16] = {
+		-1,-1,-1, 0, 1, 1, 1, 0, /* x */
+		-1, 0, 1, 1, 1, 0,-1,-1, /* y */
+	};
+
+	int x = v->x_pos + _delta_coord[v->direction];
+	int y = v->y_pos + _delta_coord[v->direction + 8];
+
+	gp->x = x;
+	gp->y = y;
+	gp->old_tile = v->tile;
+	gp->new_tile = TileVirtXY(x, y);
+	return gp->old_tile == gp->new_tile;
+}
+
+static const Direction _new_direction_table[] = {
+	DIR_N , DIR_NW, DIR_W ,
+	DIR_NE, DIR_SE, DIR_SW,
+	DIR_E , DIR_SE, DIR_S
+};
+
+Direction GetDirectionTowards(const Vehicle* v, int x, int y)
+{
+	Direction dir;
+	DirDiff dirdiff;
+	int i = 0;
+
+	if (y >= v->y_pos) {
+		if (y != v->y_pos) i+=3;
+		i+=3;
+	}
+
+	if (x >= v->x_pos) {
+		if (x != v->x_pos) i++;
+		i++;
+	}
+
+	dir = v->direction;
+
+	dirdiff = DirDifference(_new_direction_table[i], dir);
+	if (dirdiff == DIRDIFF_SAME) return dir;
+	return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
+}
+
+Trackdir GetVehicleTrackdir(const Vehicle* v)
+{
+	if (v->vehstatus & VS_CRASHED) return 0xFF;
+
+	switch (v->type) {
+		case VEH_Train:
+			if (v->u.rail.track == 0x80) /* We'll assume the train is facing outwards */
+				return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); /* Train in depot */
+
+			if (v->u.rail.track == 0x40) /* train in tunnel, so just use his direction and assume a diagonal track */
+				return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+
+			return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.rail.track),v->direction);
+
+		case VEH_Ship:
+			if (IsShipInDepot(v))
+				/* We'll assume the ship is facing outwards */
+				return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
+
+			return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.ship.state),v->direction);
+
+		case VEH_Road:
+			if (IsRoadVehInDepot(v)) /* We'll assume the road vehicle is facing outwards */
+				return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
+
+			if (IsRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */
+				return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); /* Road vehicle in a station */
+
+			/* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
+			if ((v->u.road.state & 7) < 6) return v->u.road.state;
+
+			/* Vehicle is turning around, get the direction from vehicle's direction */
+			return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+
+		/* case VEH_Aircraft: case VEH_Special: case VEH_Disaster: */
+		default: return 0xFF;
+	}
+}
+/* Return value has bit 0x2 set, when the vehicle enters a station. Then,
+ * result << 8 contains the id of the station entered. If the return value has
+ * bit 0x8 set, the vehicle could not and did not enter the tile. Are there
+ * other bits that can be set? */
+uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
+{
+	return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
+}
+
+UnitID GetFreeUnitNumber(byte type)
+{
+	UnitID unit, max = 0;
+	const Vehicle *u;
+	static bool *cache = NULL;
+	static UnitID gmax = 0;
+
+	switch (type) {
+		case VEH_Train:    max = _patches.max_trains; break;
+		case VEH_Road:     max = _patches.max_roadveh; break;
+		case VEH_Ship:     max = _patches.max_ships; break;
+		case VEH_Aircraft: max = _patches.max_aircraft; break;
+		default: NOT_REACHED();
+	}
+
+	if (max == 0) {
+		/* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number
+		 * a max of 0 will cause the following code to write to a NULL pointer
+		 * We know that 1 is bigger than the max allowed vehicle number, so it's the same as returning something, that is too big
+		 */
+		return 1;
+	}
+
+	if (max > gmax) {
+		gmax = max;
+		free(cache);
+		cache = malloc((max + 1) * sizeof(*cache));
+	}
+
+	// Clear the cache
+	memset(cache, 0, (max + 1) * sizeof(*cache));
+
+	// Fill the cache
+	FOR_ALL_VEHICLES(u) {
+		if (u->type == type && u->owner == _current_player && u->unitnumber != 0 && u->unitnumber <= max)
+			cache[u->unitnumber] = true;
+	}
+
+	// Find the first unused unit number
+	for (unit = 1; unit <= max; unit++) {
+		if (!cache[unit]) break;
+	}
+
+	return unit;
+}
+
+static PalSpriteID GetEngineColourMap(EngineID engine_type, PlayerID player, EngineID parent_engine_type, CargoID cargo_type)
+{
+	SpriteID map;
+	const Player *p = GetPlayer(player);
+	LiveryScheme scheme = LS_DEFAULT;
+
+	/* The default livery is always available for use, but its in_use flag determines
+	 * whether any _other_ liveries are in use. */
+	if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
+		/* Determine the livery scheme to use */
+		switch (GetEngine(engine_type)->type) {
+			case VEH_Train: {
+				switch (_engine_info[engine_type].railtype) {
+					case RAILTYPE_RAIL:
+					case RAILTYPE_ELECTRIC:
+					{
+						const RailVehicleInfo *rvi = RailVehInfo(engine_type);
+
+						if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
+						if (rvi->flags & RVI_WAGON) {
+							if (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL || cargo_type == CT_VALUABLES) {
+								if (parent_engine_type == INVALID_ENGINE) {
+									scheme = LS_PASSENGER_WAGON_STEAM;
+								} else {
+									switch (RailVehInfo(parent_engine_type)->engclass) {
+										case 0: scheme = LS_PASSENGER_WAGON_STEAM; break;
+										case 1: scheme = LS_PASSENGER_WAGON_DIESEL; break;
+										case 2: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
+									}
+								}
+							} else {
+								scheme = LS_FREIGHT_WAGON;
+							}
+						} else {
+							bool is_mu = HASBIT(_engine_info[engine_type].misc_flags, EF_RAIL_IS_MU);
+
+							switch (rvi->engclass) {
+								case 0: scheme = LS_STEAM; break;
+								case 1: scheme = is_mu ? LS_DMU : LS_DIESEL; break;
+								case 2: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
+							}
+						}
+						break;
+					}
+
+					case RAILTYPE_MONO: scheme = LS_MONORAIL; break;
+					case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break;
+				}
+				break;
+			}
+
+			case VEH_Road: {
+				const RoadVehicleInfo *rvi = RoadVehInfo(engine_type);
+				if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
+				scheme = (cargo_type == CT_PASSENGERS) ? LS_BUS : LS_TRUCK;
+				break;
+			}
+
+			case VEH_Ship: {
+				const ShipVehicleInfo *svi = ShipVehInfo(engine_type);
+				if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type;
+				scheme = (cargo_type == CT_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
+				break;
+			}
+
+			case VEH_Aircraft: {
+				const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type);
+				if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS;
+				switch (avi->subtype) {
+					case 0: scheme = LS_HELICOPTER; break;
+					case 1: scheme = LS_SMALL_PLANE; break;
+					case 3: scheme = LS_LARGE_PLANE; break;
+				}
+				break;
+			}
+		}
+
+		/* Switch back to the default scheme if the resolved scheme is not in use */
+		if (!p->livery[scheme].in_use) scheme = LS_DEFAULT;
+	}
+
+	map = HASBIT(EngInfo(engine_type)->misc_flags, EF_USES_2CC) ?
+		(SPR_2CCMAP_BASE + p->livery[scheme].colour1 + p->livery[scheme].colour2 * 16) :
+		(PALETTE_RECOLOR_START + p->livery[scheme].colour1);
+
+	return SPRITE_PALETTE(map << PALETTE_SPRITE_START);
+}
+
+PalSpriteID GetEnginePalette(EngineID engine_type, PlayerID player)
+{
+	return GetEngineColourMap(engine_type, player, INVALID_ENGINE, CT_INVALID);
+}
+
+PalSpriteID GetVehiclePalette(const Vehicle *v)
+{
+	if (v->type == VEH_Train) {
+		return GetEngineColourMap(
+			(v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ?
+				v->u.rail.first_engine : v->engine_type,
+			v->owner,
+			v->u.rail.first_engine,
+			v->cargo_type);
+	}
+
+	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v->cargo_type);
+}
+
+// Save and load of vehicles
+const SaveLoad _common_veh_desc[] = {
+	    SLE_VAR(Vehicle, subtype,              SLE_UINT8),
+
+	    SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
+	    SLE_VAR(Vehicle, string_id,            SLE_STRINGID),
+	SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
+	SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, owner,                SLE_UINT8),
+	SLE_CONDVAR(Vehicle, tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, dest_tile,            SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, dest_tile,            SLE_UINT32,                  6, SL_MAX_VERSION),
+
+	SLE_CONDVAR(Vehicle, x_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, x_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, y_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, y_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, z_pos,                SLE_UINT8),
+	    SLE_VAR(Vehicle, direction,            SLE_UINT8),
+
+	    SLE_VAR(Vehicle, cur_image,            SLE_UINT16),
+	    SLE_VAR(Vehicle, spritenum,            SLE_UINT8),
+	    SLE_VAR(Vehicle, sprite_width,         SLE_UINT8),
+	    SLE_VAR(Vehicle, sprite_height,        SLE_UINT8),
+	    SLE_VAR(Vehicle, z_height,             SLE_UINT8),
+	    SLE_VAR(Vehicle, x_offs,               SLE_INT8),
+	    SLE_VAR(Vehicle, y_offs,               SLE_INT8),
+	    SLE_VAR(Vehicle, engine_type,          SLE_UINT16),
+
+	    SLE_VAR(Vehicle, max_speed,            SLE_UINT16),
+	    SLE_VAR(Vehicle, cur_speed,            SLE_UINT16),
+	    SLE_VAR(Vehicle, subspeed,             SLE_UINT8),
+	    SLE_VAR(Vehicle, acceleration,         SLE_UINT8),
+	    SLE_VAR(Vehicle, progress,             SLE_UINT8),
+
+	    SLE_VAR(Vehicle, vehstatus,            SLE_UINT8),
+	SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8  | SLE_VAR_U16,  0, 4),
+	SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16,                  5, SL_MAX_VERSION),
+
+	    SLE_VAR(Vehicle, cargo_type,           SLE_UINT8),
+	SLE_CONDVAR(Vehicle, cargo_subtype,        SLE_UINT8,                  35, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, cargo_days,           SLE_UINT8),
+	SLE_CONDVAR(Vehicle, cargo_source,         SLE_FILE_U8  | SLE_VAR_U16,  0, 6),
+	SLE_CONDVAR(Vehicle, cargo_source,         SLE_UINT16,                  7, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, cargo_cap,            SLE_UINT16),
+	    SLE_VAR(Vehicle, cargo_count,          SLE_UINT16),
+
+	    SLE_VAR(Vehicle, day_counter,          SLE_UINT8),
+	    SLE_VAR(Vehicle, tick_counter,         SLE_UINT8),
+
+	    SLE_VAR(Vehicle, cur_order_index,      SLE_UINT8),
+	    SLE_VAR(Vehicle, num_orders,           SLE_UINT8),
+
+	/* This next line is for version 4 and prior compatibility.. it temporarily reads
+	    type and flags (which were both 4 bits) into type. Later on this is
+	    converted correctly */
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, type), SLE_UINT8,                 0, 4),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+
+	/* Orders for version 5 and on */
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, type),  SLE_UINT8,  5, SL_MAX_VERSION),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, flags), SLE_UINT8,  5, SL_MAX_VERSION),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest),  SLE_UINT16, 5, SL_MAX_VERSION),
+
+	/* Refit in current order */
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, refit_cargo),    SLE_UINT8, 36, SL_MAX_VERSION),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, refit_subtype),  SLE_UINT8, 36, SL_MAX_VERSION),
+
+	    SLE_REF(Vehicle, orders,               REF_ORDER),
+
+	SLE_CONDVAR(Vehicle, age,                  SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, age,                  SLE_INT32,                  31, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, max_age,              SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, max_age,              SLE_INT32,                  31, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32,                  31, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, service_interval,     SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, service_interval,     SLE_INT32,                  31, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, reliability,          SLE_UINT16),
+	    SLE_VAR(Vehicle, reliability_spd_dec,  SLE_UINT16),
+	    SLE_VAR(Vehicle, breakdown_ctr,        SLE_UINT8),
+	    SLE_VAR(Vehicle, breakdown_delay,      SLE_UINT8),
+	    SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
+	    SLE_VAR(Vehicle, breakdown_chance,     SLE_UINT8),
+	SLE_CONDVAR(Vehicle, build_year,           SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, build_year,           SLE_INT32,                 31, SL_MAX_VERSION),
+
+	    SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
+	SLE_CONDVAR(Vehicle, load_status,          SLE_UINT8,                 40, SL_MAX_VERSION),
+
+	    SLE_VAR(Vehicle, profit_this_year,     SLE_INT32),
+	    SLE_VAR(Vehicle, profit_last_year,     SLE_INT32),
+	    SLE_VAR(Vehicle, value,                SLE_UINT32),
+
+	    SLE_VAR(Vehicle, random_bits,          SLE_UINT8),
+	    SLE_VAR(Vehicle, waiting_triggers,     SLE_UINT8),
+
+	    SLE_REF(Vehicle, next_shared,          REF_VEHICLE),
+	    SLE_REF(Vehicle, prev_shared,          REF_VEHICLE),
+
+	// reserve extra space in savegame here. (currently 10 bytes)
+	SLE_CONDNULL(10,                                                       2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+
+static const SaveLoad _train_desc[] = {
+	SLE_WRITEBYTE(Vehicle, type, VEH_Train, 0), // Train type. VEH_Train in mem, 0 in file.
+	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, crash_anim_pos),         SLE_UINT16),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, force_proceed),          SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, railtype),               SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, track),                  SLE_UINT8),
+
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRail, flags),                  SLE_UINT8,  2, SL_MAX_VERSION),
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRail, days_since_order_progr), SLE_UINT16, 2, SL_MAX_VERSION),
+
+	SLE_CONDNULL(2, 2, 19),
+	// reserve extra space in savegame here. (currently 11 bytes)
+	SLE_CONDNULL(11, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _roadveh_desc[] = {
+	SLE_WRITEBYTE(Vehicle, type, VEH_Road, 1), // Road type. VEH_Road in mem, 1 in file.
+	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, state),          SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, frame),          SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, blocked_ctr),    SLE_UINT16),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking),     SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, crashed_ctr),    SLE_UINT16),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, reverse_ctr),    SLE_UINT8),
+
+	SLE_CONDREFX(offsetof(Vehicle, u) + offsetof(VehicleRoad, slot),     REF_ROADSTOPS, 6, SL_MAX_VERSION),
+	SLE_CONDNULL(1,                                                                     6, SL_MAX_VERSION),
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, slot_age), SLE_UINT8,     6, SL_MAX_VERSION),
+	// reserve extra space in savegame here. (currently 16 bytes)
+	SLE_CONDNULL(16,                                                                    2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _ship_desc[] = {
+	SLE_WRITEBYTE(Vehicle, type, VEH_Ship, 2), // Ship type. VEH_Ship in mem, 2 in file.
+	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
+	SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleShip, state), SLE_UINT8),
+
+	// reserve extra space in savegame here. (currently 16 bytes)
+	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _aircraft_desc[] = {
+	SLE_WRITEBYTE(Vehicle, type, VEH_Aircraft, 3), // Aircraft type. VEH_Aircraft in mem, 3 in file.
+	SLE_INCLUDEX(0, INC_VEHICLE_COMMON),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, crashed_counter), SLE_UINT16),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, pos),             SLE_UINT8),
+
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport),   SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport),   SLE_UINT16,                5, SL_MAX_VERSION),
+
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, state),           SLE_UINT8),
+
+	SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, previous_pos),    SLE_UINT8,                 2, SL_MAX_VERSION),
+
+	// reserve extra space in savegame here. (currently 15 bytes)
+	SLE_CONDNULL(15,                                                                                      2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _special_desc[] = {
+	SLE_WRITEBYTE(Vehicle,type,VEH_Special, 4),
+
+	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
+
+	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
+	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
+
+	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
+	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
+
+	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
+	    SLE_VAR(Vehicle, sprite_width,  SLE_UINT8),
+	    SLE_VAR(Vehicle, sprite_height, SLE_UINT8),
+	    SLE_VAR(Vehicle, z_height,      SLE_UINT8),
+	    SLE_VAR(Vehicle, x_offs,        SLE_INT8),
+	    SLE_VAR(Vehicle, y_offs,        SLE_INT8),
+	    SLE_VAR(Vehicle, progress,      SLE_UINT8),
+	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
+
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleSpecial, unk0), SLE_UINT16),
+	    SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleSpecial, unk2), SLE_UINT8),
+
+	// reserve extra space in savegame here. (currently 16 bytes)
+	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static const SaveLoad _disaster_desc[] = {
+	SLE_WRITEBYTE(Vehicle, type, VEH_Disaster, 5),
+
+	    SLE_REF(Vehicle, next,          REF_VEHICLE_OLD),
+
+	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
+	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, dest_tile,     SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Vehicle, dest_tile,     SLE_UINT32,                  6, SL_MAX_VERSION),
+
+	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
+	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
+	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
+	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
+	    SLE_VAR(Vehicle, direction,     SLE_UINT8),
+
+	    SLE_VAR(Vehicle, x_offs,        SLE_INT8),
+	    SLE_VAR(Vehicle, y_offs,        SLE_INT8),
+	    SLE_VAR(Vehicle, sprite_width,  SLE_UINT8),
+	    SLE_VAR(Vehicle, sprite_height, SLE_UINT8),
+	    SLE_VAR(Vehicle, z_height,      SLE_UINT8),
+	    SLE_VAR(Vehicle, owner,         SLE_UINT8),
+	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+	SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, dest), SLE_UINT16,                5, SL_MAX_VERSION),
+
+	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
+	SLE_CONDVAR(Vehicle, age,           SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
+	SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
+	    SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
+
+	   SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleDisaster, image_override), SLE_UINT16),
+	   SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleDisaster, unk2),           SLE_UINT16),
+
+	// reserve extra space in savegame here. (currently 16 bytes)
+	SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+
+static const void *_veh_descs[] = {
+	_train_desc,
+	_roadveh_desc,
+	_ship_desc,
+	_aircraft_desc,
+	_special_desc,
+	_disaster_desc,
+};
+
+// Will be called when the vehicles need to be saved.
+static void Save_VEHS(void)
+{
+	Vehicle *v;
+	// Write the vehicles
+	FOR_ALL_VEHICLES(v) {
+		SlSetArrayIndex(v->index);
+		SlObject(v, _veh_descs[v->type - 0x10]);
+	}
+}
+
+// Will be called when vehicles need to be loaded.
+static void Load_VEHS(void)
+{
+	int index;
+	Vehicle *v;
+
+	while ((index = SlIterateArray()) != -1) {
+		Vehicle *v;
+
+		if (!AddBlockIfNeeded(&_Vehicle_pool, index))
+			error("Vehicles: failed loading savegame: too many vehicles");
+
+		v = GetVehicle(index);
+		SlObject(v, _veh_descs[SlReadByte()]);
+
+		/* Old savegames used 'last_station_visited = 0xFF' */
+		if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
+			v->last_station_visited = INVALID_STATION;
+
+		if (CheckSavegameVersion(5)) {
+			/* Convert the current_order.type (which is a mix of type and flags, because
+			 *  in those versions, they both were 4 bits big) to type and flags */
+			v->current_order.flags = (v->current_order.type & 0xF0) >> 4;
+			v->current_order.type  =  v->current_order.type & 0x0F;
+		}
+	}
+
+	/* Check for shared order-lists (we now use pointers for that) */
+	if (CheckSavegameVersionOldStyle(5, 2)) {
+		FOR_ALL_VEHICLES(v) {
+			Vehicle *u;
+
+			FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
+				/* If a vehicle has the same orders, add the link to eachother
+				 *  in both vehicles */
+				if (v->orders == u->orders) {
+					v->next_shared = u;
+					u->prev_shared = v;
+					break;
+				}
+			}
+		}
+	}
+}
+
+const ChunkHandler _veh_chunk_handlers[] = {
+	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/vehicle_gui.c
+++ /dev/null
@@ -1,1945 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "player.h"
-#include "station.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "vehicle.h"
-#include "window.h"
-#include "engine.h"
-#include "gui.h"
-#include "command.h"
-#include "gfx.h"
-#include "variables.h"
-#include "vehicle_gui.h"
-#include "viewport.h"
-#include "train.h"
-#include "newgrf_callbacks.h"
-#include "newgrf_engine.h"
-#include "newgrf_text.h"
-#include "date.h"
-#include "ship.h"
-#include "aircraft.h"
-#include "roadveh.h"
-#include "depot.h"
-
-typedef struct Sorting {
-	Listing aircraft;
-	Listing roadveh;
-	Listing ship;
-	Listing train;
-} Sorting;
-
-static Sorting _sorting;
-
-typedef struct vehiclelist_d {
-	const Vehicle** sort_list;  // List of vehicles (sorted)
-	Listing *_sorting;          // pointer to the appropiate subcategory of _sorting
-	uint16 length_of_sort_list; // Keeps track of how many vehicle pointers sort list got space for
-	byte vehicle_type;          // The vehicle type that is sorted
-	list_d l;                   // General list struct
-} vehiclelist_d;
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehiclelist_d));
-
-static bool   _internal_sort_order;     // descending/ascending
-
-static RailType _railtype_selected_in_replace_gui;
-
-
-typedef int CDECL VehicleSortListingTypeFunction(const void*, const void*);
-
-static VehicleSortListingTypeFunction VehicleNumberSorter;
-static VehicleSortListingTypeFunction VehicleNameSorter;
-static VehicleSortListingTypeFunction VehicleAgeSorter;
-static VehicleSortListingTypeFunction VehicleProfitThisYearSorter;
-static VehicleSortListingTypeFunction VehicleProfitLastYearSorter;
-static VehicleSortListingTypeFunction VehicleCargoSorter;
-static VehicleSortListingTypeFunction VehicleReliabilitySorter;
-static VehicleSortListingTypeFunction VehicleMaxSpeedSorter;
-static VehicleSortListingTypeFunction VehicleModelSorter;
-static VehicleSortListingTypeFunction VehicleValueSorter;
-
-static VehicleSortListingTypeFunction* const _vehicle_sorter[] = {
-	&VehicleNumberSorter,
-	&VehicleNameSorter,
-	&VehicleAgeSorter,
-	&VehicleProfitThisYearSorter,
-	&VehicleProfitLastYearSorter,
-	&VehicleCargoSorter,
-	&VehicleReliabilitySorter,
-	&VehicleMaxSpeedSorter,
-	&VehicleModelSorter,
-	&VehicleValueSorter,
-};
-
-static const StringID _vehicle_sort_listing[] = {
-	STR_SORT_BY_NUMBER,
-	STR_SORT_BY_DROPDOWN_NAME,
-	STR_SORT_BY_AGE,
-	STR_SORT_BY_PROFIT_THIS_YEAR,
-	STR_SORT_BY_PROFIT_LAST_YEAR,
-	STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
-	STR_SORT_BY_RELIABILITY,
-	STR_SORT_BY_MAX_SPEED,
-	STR_SORT_BY_MODEL,
-	STR_SORT_BY_VALUE,
-	INVALID_STRING_ID
-};
-
-static const StringID _rail_types_list[] = {
-	STR_RAIL_VEHICLES,
-	STR_ELRAIL_VEHICLES,
-	STR_MONORAIL_VEHICLES,
-	STR_MAGLEV_VEHICLES,
-	INVALID_STRING_ID
-};
-
-void RebuildVehicleLists(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		switch (w->window_class) {
-			case WC_TRAINS_LIST:
-			case WC_ROADVEH_LIST:
-			case WC_SHIPS_LIST:
-			case WC_AIRCRAFT_LIST:
-				WP(w, vehiclelist_d).l.flags |= VL_REBUILD;
-				SetWindowDirty(w);
-				break;
-		}
-	}
-}
-
-void ResortVehicleLists(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		switch (w->window_class) {
-			case WC_TRAINS_LIST:
-			case WC_ROADVEH_LIST:
-			case WC_SHIPS_LIST:
-			case WC_AIRCRAFT_LIST:
-				WP(w, vehiclelist_d).l.flags |= VL_RESORT;
-				SetWindowDirty(w);
-				break;
-		}
-	}
-}
-
-static void BuildVehicleList(vehiclelist_d* vl, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type)
-{
-	if (!(vl->l.flags & VL_REBUILD)) return;
-
-	DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, station);
-
-	vl->l.list_length = GenerateVehicleSortList(&vl->sort_list, &vl->length_of_sort_list, vl->vehicle_type, owner, station, order, depot_airport_index, window_type);
-
-	vl->l.flags &= ~VL_REBUILD;
-	vl->l.flags |= VL_RESORT;
-}
-
-static void SortVehicleList(vehiclelist_d *vl)
-{
-	if (!(vl->l.flags & VL_RESORT)) return;
-
-	_internal_sort_order = vl->l.flags & VL_DESC;
-	qsort((void*)vl->sort_list, vl->l.list_length, sizeof(vl->sort_list[0]),
-		_vehicle_sorter[vl->l.sort_type]);
-
-	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
-	vl->l.flags &= ~VL_RESORT;
-}
-
-void DepotSortList(Vehicle **v, uint16 length)
-{
-	_internal_sort_order = 0;
-	qsort((void*)v, length, sizeof(v[0]), _vehicle_sorter[0]);
-}
-
-/* General Vehicle GUI based procedures that are independent of vehicle types */
-void InitializeVehiclesGuiList(void)
-{
-	_railtype_selected_in_replace_gui = RAILTYPE_RAIL;
-}
-
-// draw the vehicle profit button in the vehicle list window.
-void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
-{
-	uint32 ormod;
-
-	// draw profit-based colored icons
-	if (v->age <= 365 * 2) {
-		ormod = PALETTE_TO_GREY;
-	} else if (v->profit_last_year < 0) {
-		ormod = PALETTE_TO_RED;
-	} else if (v->profit_last_year < 10000) {
-		ormod = PALETTE_TO_YELLOW;
-	} else {
-		ormod = PALETTE_TO_GREEN;
-	}
-	DrawSprite(SPR_BLOT | ormod, x, y);
-}
-
-typedef struct RefitOption {
-	CargoID cargo;
-	byte subtype;
-	uint16 value;
-	EngineID engine;
-} RefitOption;
-
-typedef struct RefitList {
-	uint num_lines;
-	RefitOption *items;
-} RefitList;
-
-static RefitList *BuildRefitList(const Vehicle *v)
-{
-	uint max_lines = 256;
-	RefitOption *refit = calloc(max_lines, sizeof(*refit));
-	RefitList *list = calloc(1, sizeof(*list));
-	Vehicle *u = (Vehicle*)v;
-	uint num_lines = 0;
-	uint i;
-
-	do {
-		CargoID cid;
-		uint32 cmask = EngInfo(u->engine_type)->refit_mask;
-		byte callbackmask = EngInfo(u->engine_type)->callbackmask;
-
-		/* Skip this engine if it has no capacity */
-		if (u->cargo_cap == 0) continue;
-
-		/* Loop through all cargos in the refit mask */
-		for (cid = 0; cmask != 0 && num_lines < max_lines; cmask >>= 1, cid++) {
-			CargoID lcid;
-
-			/* Skip cargo type if it's not listed */
-			if (!HASBIT(cmask, 0)) continue;
-
-			lcid = _local_cargo_id_ctype[cid];
-			if (lcid == CT_INVALID) continue;
-
-			/* Check the vehicle's callback mask for cargo suffixes */
-			if (HASBIT(callbackmask, CBM_CARGO_SUFFIX)) {
-				/* Make a note of the original cargo type. It has to be
-				 * changed to test the cargo & subtype... */
-				CargoID temp_cargo = u->cargo_type;
-				byte temp_subtype  = u->cargo_subtype;
-				byte refit_cyc;
-
-				u->cargo_type = lcid;
-
-				for (refit_cyc = 0; refit_cyc < 16 && num_lines < max_lines; refit_cyc++) {
-					bool duplicate = false;
-					uint16 callback;
-
-					u->cargo_subtype = refit_cyc;
-					callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u);
-
-					if (callback == 0xFF) callback = CALLBACK_FAILED;
-					if (refit_cyc != 0 && callback == CALLBACK_FAILED) break;
-
-					/* Check if this cargo and subtype combination are listed */
-					for (i = 0; i < num_lines && !duplicate; i++) {
-						if (refit[i].cargo == lcid && refit[i].value == callback) duplicate = true;
-					}
-
-					if (duplicate) continue;
-
-					refit[num_lines].cargo   = lcid;
-					refit[num_lines].subtype = refit_cyc;
-					refit[num_lines].value   = callback;
-					refit[num_lines].engine  = u->engine_type;
-					num_lines++;
-				}
-
-				/* Reset the vehicle's cargo type */
-				u->cargo_type    = temp_cargo;
-				u->cargo_subtype = temp_subtype;
-			} else {
-				/* No cargo suffix callback -- use no subtype */
-				bool duplicate = false;
-
-				for (i = 0; i < num_lines && !duplicate; i++) {
-					if (refit[i].cargo == lcid && refit[i].value == CALLBACK_FAILED) duplicate = true;
-				}
-
-				if (!duplicate) {
-					refit[num_lines].cargo   = lcid;
-					refit[num_lines].subtype = 0;
-					refit[num_lines].value   = CALLBACK_FAILED;
-					refit[num_lines].engine  = INVALID_ENGINE;
-					num_lines++;
-				}
-			}
-		}
-	} while (v->type == VEH_Train && (u = u->next) != NULL && num_lines < max_lines);
-
-	list->num_lines = num_lines;
-	list->items = refit;
-
-	return list;
-}
-
-/** Draw the list of available refit options for a consist.
- * Draw the list and highlight the selected refit option (if any)
- * @param *v first vehicle in consist to get the refit-options of
- * @param sel selected refit cargo-type in the window
- * @return the refit option that is hightlighted, NULL if none
- */
-static RefitOption *DrawVehicleRefitWindow(const RefitList *list, int sel, uint pos, uint rows, uint delta)
-{
-	RefitOption *refit = list->items;
-	RefitOption *selected = NULL;
-	uint num_lines = list->num_lines;
-	uint y = 31;
-	uint i;
-
-	/* Draw the list, and find the selected cargo (by its position in list) */
-	for (i = 0; i < num_lines; i++) {
-		byte colour = 16;
-		if (sel == 0) {
-			selected = &refit[i];
-			colour = 12;
-		}
-
-		if (i >= pos && i < pos + rows) {
-			/* Draw the cargo name */
-			int last_x = DrawString(2, y, _cargoc.names_s[refit[i].cargo], colour);
-
-			/* If the callback succeeded, draw the cargo suffix */
-			if (refit[i].value != CALLBACK_FAILED) {
-				DrawString(last_x + 1, y, GetGRFStringID(GetEngineGRFID(refit[i].engine), 0xD000 + refit[i].value), colour);
-			}
-			y += delta;
-		}
-
-		sel--;
-	}
-
-	return selected;
-}
-
-static void VehicleRefitWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			Vehicle *v = GetVehicle(w->window_number);
-
-			if (v->type == VEH_Train) {
-				uint length = CountVehiclesInChain(v);
-
-				if (length != WP(w, refit_d).length) {
-					/* Consist length has changed, so rebuild the refit list */
-					free(WP(w, refit_d).list->items);
-					free(WP(w, refit_d).list);
-					WP(w, refit_d).list = BuildRefitList(v);
-					WP(w, refit_d).length = length;
-				}
-			}
-
-			SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
-			SetDParam(0, v->string_id);
-			SetDParam(1, v->unitnumber);
-			DrawWindowWidgets(w);
-
-			WP(w,refit_d).cargo = DrawVehicleRefitWindow(WP(w, refit_d).list, WP(w, refit_d).sel, w->vscroll.pos, w->vscroll.cap, w->resize.step_height);
-
-			if (WP(w,refit_d).cargo != NULL) {
-				int32 cost = 0;
-				switch (GetVehicle(w->window_number)->type) {
-					case VEH_Train:    cost = CMD_REFIT_RAIL_VEHICLE; break;
-					case VEH_Road:     cost = CMD_REFIT_ROAD_VEH;     break;
-					case VEH_Ship:     cost = CMD_REFIT_SHIP;         break;
-					case VEH_Aircraft: cost = CMD_REFIT_AIRCRAFT;     break;
-				}
-
-				cost = DoCommand(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8, DC_QUERY_COST, cost);
-				if (!CmdFailed(cost)) {
-					SetDParam(0, WP(w,refit_d).cargo->cargo);
-					SetDParam(1, _returned_refit_capacity);
-					SetDParam(2, cost);
-					DrawString(2, w->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
-				}
-			}
-		}	break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3: { // listbox
-					int y = e->we.click.pt.y - w->widget[3].top;
-					if (y >= 0) {
-						WP(w,refit_d).sel = (y / (int)w->resize.step_height) + w->vscroll.pos;
-						SetWindowDirty(w);
-					}
-				} break;
-				case 6: // refit button
-					if (WP(w,refit_d).cargo != NULL) {
-						const Vehicle *v = GetVehicle(w->window_number);
-
-						if (WP(w, refit_d).order == INVALID_VEH_ORDER_ID) {
-							int command = 0;
-
-							switch (v->type) {
-								case VEH_Train:    command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE);  break;
-								case VEH_Road:     command = CMD_REFIT_ROAD_VEH     | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T);  break;
-								case VEH_Ship:     command = CMD_REFIT_SHIP         | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP);     break;
-								case VEH_Aircraft: command = CMD_REFIT_AIRCRAFT     | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
-							}
-							if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8, NULL, command)) DeleteWindow(w);
-						} else {
-							if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8 | WP(w, refit_d).order << 16, NULL, CMD_ORDER_REFIT)) DeleteWindow(w);
-						}
-					}
-					break;
-			}
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->widget[3].data = (w->vscroll.cap << 8) + 1;
-			break;
-
-		case WE_DESTROY:
-			free(WP(w, refit_d).list->items);
-			free(WP(w, refit_d).list);
-			break;
-	}
-}
-
-
-static const Widget _vehicle_refit_widgets[] = {
-	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                            STR_018B_CLOSE_WINDOW},
-	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   239,     0,    13, STR_983B_REFIT,                      STR_018C_WINDOW_TITLE_DRAG_THIS},
-	{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,   239,    14,    27, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, STR_983D_SELECT_TYPE_OF_CARGO_FOR},
-	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   227,    28,   139, 0x801,                               STR_EMPTY},
-	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   228,   239,    28,   139, 0x0,                                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
-	{      WWT_PANEL,     RESIZE_TB,    14,     0,   239,   140,   161, 0x0,                                 STR_NULL},
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   227,   162,   173, 0x0,                                 STR_NULL},
-	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   228,   239,   162,   173, 0x0,                                 STR_RESIZE_BUTTON},
-	{   WIDGETS_END},
-};
-
-static const WindowDesc _vehicle_refit_desc = {
-	WDP_AUTO, WDP_AUTO, 240, 174,
-	WC_VEHICLE_REFIT,WC_VEHICLE_VIEW,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
-	_vehicle_refit_widgets,
-	VehicleRefitWndProc,
-};
-
-/** Show the refit window for a vehicle
-* @param *v The vehicle to show the refit window for
-*/
-void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order)
-{
-	Window *w;
-
-	DeleteWindowById(WC_VEHICLE_REFIT, v->index);
-
-	w = AllocateWindowDescFront(&_vehicle_refit_desc, v->index);
-	WP(w, refit_d).order = order;
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		w->vscroll.cap = 8;
-		w->resize.step_height = 14;
-		WP(w, refit_d).sel  = -1;
-		WP(w, refit_d).list = BuildRefitList(v);
-		if (v->type == VEH_Train) WP(w, refit_d).length = CountVehiclesInChain(v);
-		SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
-		switch (v->type) {
-			case VEH_Train:
-				w->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_RAIL_REFIT_VEHICLE;
-				w->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_Road:
-				w->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_REFIT_ROAD_VEHICLE;
-				w->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_Ship:
-				w->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_983C_REFIT_SHIP;
-				w->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_Aircraft:
-				w->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_A03D_REFIT_AIRCRAFT;
-				w->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
-				break;
-			default: NOT_REACHED();
-		}
-	}
-}
-
-/* Display additional text from NewGRF in the purchase information window */
-uint ShowAdditionalText(int x, int y, uint w, EngineID engine)
-{
-	uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
-	if (callback == CALLBACK_FAILED) return 0;
-
-	// STR_02BD is used to start the string with {BLACK}
-	SetDParam(0, GetGRFStringID(GetEngineGRFID(engine), 0xD000 + callback));
-	return DrawStringMultiLine(x, y, STR_02BD, w);
-}
-
-/* Count the number of bits that are set in a mask */
-static uint CountBits(uint32 mask)
-{
-	uint c = 0;
-	for (; mask != 0; mask >>= 1) if (HASBIT(mask, 0)) c++;
-	return c;
-}
-
-/* Display list of cargo types of the engine, for the purchase information window */
-uint ShowRefitOptionsList(int x, int y, uint w, EngineID engine)
-{
-	/* List of cargo types of this engine */
-	uint32 cmask = EngInfo(engine)->refit_mask;
-	/* List of cargo types available in this climate */
-	uint32 lmask = _landscape_global_cargo_mask[_opt.landscape];
-	char *b = _userstring;
-
-	/* Draw nothing if the engine is not refittable */
-	if (CountBits(cmask) <= 1) return 0;
-
-	b = InlineString(b, STR_PURCHASE_INFO_REFITTABLE_TO);
-
-	if (cmask == lmask) {
-		/* Engine can be refitted to all types in this climate */
-		b = InlineString(b, STR_PURCHASE_INFO_ALL_TYPES);
-	} else {
-		CargoID cid;
-
-		/* Check if we are able to refit to more cargo types and unable to. If
-		 * so, invert the cargo types to list those that we can't refit to. */
-		if (CountBits(cmask ^ lmask) < CountBits(cmask)) {
-			cmask ^= lmask;
-			b = InlineString(b, STR_PURCHASE_INFO_ALL_BUT);
-		}
-
-		/* Add each cargo type to the list */
-		for (cid = 0; cmask != 0; cmask >>= 1, cid++) {
-			if (!HASBIT(cmask, 0)) continue;
-
-			b = InlineString(b, _cargoc.names_s[_local_cargo_id_ctype[cid]]);
-			if (cmask > 1) b = strecpy(b, ", ", lastof(_userstring));
-		}
-	}
-
-	/* Terminate and display the completed string */
-	*b = '\0';
-	return DrawStringMultiLine(x, y, STR_SPEC_USERSTRING, w);
-}
-
-
-// if the sorting criteria had the same value, sort vehicle by unitnumber
-#define VEHICLEUNITNUMBERSORTER(r, a, b) {if (r == 0) {r = a->unitnumber - b->unitnumber;}}
-
-static int CDECL VehicleNumberSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->unitnumber - vb->unitnumber;
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleNameSorter(const void *a, const void *b)
-{
-	static const Vehicle *last_vehicle[2] = { NULL, NULL };
-	static char           last_name[2][64] = { "", "" };
-
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r;
-
-	if (va != last_vehicle[0]) {
-		last_vehicle[0] = va;
-		if (IsCustomName(va->string_id)) {
-			GetString(last_name[0], va->string_id, lastof(last_name[0]));
-		} else {
-			last_name[0][0] = '\0';
-		}
-	}
-
-	if (vb != last_vehicle[1]) {
-		last_vehicle[1] = vb;
-		if (IsCustomName(vb->string_id)) {
-			GetString(last_name[1], vb->string_id, lastof(last_name[1]));
-		} else {
-			last_name[1][0] = '\0';
-		}
-	}
-
-	r = strcmp(last_name[0], last_name[1]); // sort by name
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleAgeSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->age - vb->age;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleProfitThisYearSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->profit_this_year - vb->profit_this_year;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleProfitLastYearSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->profit_last_year - vb->profit_last_year;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleCargoSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	const Vehicle* v;
-	AcceptedCargo cargoa;
-	AcceptedCargo cargob;
-	int r = 0;
-	int i;
-
-	memset(cargoa, 0, sizeof(cargoa));
-	memset(cargob, 0, sizeof(cargob));
-	for (v = va; v != NULL; v = v->next) cargoa[v->cargo_type] += v->cargo_cap;
-	for (v = vb; v != NULL; v = v->next) cargob[v->cargo_type] += v->cargo_cap;
-
-	for (i = 0; i < NUM_CARGO; i++) {
-		r = cargoa[i] - cargob[i];
-		if (r != 0) break;
-	}
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleReliabilitySorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->reliability - vb->reliability;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleMaxSpeedSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int max_speed_a = 0xFFFF, max_speed_b = 0xFFFF;
-	int r;
-	const Vehicle *ua = va, *ub = vb;
-
-	if (va->type == VEH_Train && vb->type == VEH_Train) {
-		do {
-			if (RailVehInfo(ua->engine_type)->max_speed != 0)
-				max_speed_a = min(max_speed_a, RailVehInfo(ua->engine_type)->max_speed);
-		} while ((ua = ua->next) != NULL);
-
-		do {
-			if (RailVehInfo(ub->engine_type)->max_speed != 0)
-				max_speed_b = min(max_speed_b, RailVehInfo(ub->engine_type)->max_speed);
-		} while ((ub = ub->next) != NULL);
-
-		r = max_speed_a - max_speed_b;
-	} else {
-		r = va->max_speed - vb->max_speed;
-	}
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleModelSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	int r = va->engine_type - vb->engine_type;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-static int CDECL VehicleValueSorter(const void *a, const void *b)
-{
-	const Vehicle* va = *(const Vehicle**)a;
-	const Vehicle* vb = *(const Vehicle**)b;
-	const Vehicle *u;
-	int valuea = 0, valueb = 0;
-	int r;
-
-	for (u = va; u != NULL; u = u->next) valuea += u->value;
-	for (u = vb; u != NULL; u = u->next) valueb += u->value;
-
-	r = valuea - valueb;
-
-	VEHICLEUNITNUMBERSORTER(r, va, vb);
-
-	return (_internal_sort_order & 1) ? -r : r;
-}
-
-// this define is to match engine.c, but engine.c keeps it to itself
-// ENGINE_AVAILABLE is used in ReplaceVehicleWndProc
-#define ENGINE_AVAILABLE ((e->flags & 1 && HASBIT(info->climates, _opt.landscape)) || HASBIT(e->player_avail, _local_player))
-
-/*  if show_outdated is selected, it do not sort psudo engines properly but it draws all engines
- * if used compined with show_cars set to false, it will work as intended. Replace window do it like that
- *  this was a big hack even before show_outdated was added. Stupid newgrf :p
- */
-static void train_engine_drawing_loop(int *x, int *y, int *pos, int *sel, EngineID *selected_id, RailType railtype,
-	uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated, bool show_compatible)
-{
-	EngineID j;
-	byte colour;
-	const Player *p = GetPlayer(_local_player);
-
-	for (j = 0; j < NUM_TRAIN_ENGINES; j++) {
-		EngineID i = GetRailVehAtPosition(j);
-		const Engine *e = GetEngine(i);
-		const RailVehicleInfo *rvi = RailVehInfo(i);
-		const EngineInfo *info = EngInfo(i);
-
-		if (!EngineHasReplacementForPlayer(p, i) && p->num_engines[i] == 0 && show_outdated) continue;
-
-		if ((rvi->power == 0 && !show_cars) || (rvi->power != 0 && show_cars))  // show wagons or engines (works since wagons do not have power)
-			continue;
-
-		if (*sel == 0) *selected_id = j;
-
-
-		colour = *sel == 0 ? 0xC : 0x10;
-		if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && IsCompatibleRail(e->railtype, railtype))) {
-			if ((!IsCompatibleRail(e->railtype, railtype) && show_compatible)
-				|| (e->railtype != railtype && !show_compatible)
-				|| !(rvi->flags & RVI_WAGON) != is_engine ||
-				!HASBIT(e->player_avail, _local_player))
-				continue;
-#if 0
-		} else {
-			// TODO find a nice red colour for vehicles being replaced
-			if ( _autoreplace_array[i] != i )
-				colour = *sel == 0 ? 0x44 : 0x45;
-#endif
-		}
-
-		if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) {
-			DrawString(*x + 59, *y + 2, GetCustomEngineName(i),
-				colour);
-			// show_outdated is true only for left side, which is where we show old replacements
-			DrawTrainEngine(*x + 29, *y + 6, i, (p->num_engines[i] == 0 && show_outdated) ?
-				PALETTE_CRASH : GetEnginePalette(i, _local_player));
-			if ( show_outdated ) {
-				SetDParam(0, p->num_engines[i]);
-				DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0);
-			}
-			*y += 14;
-		}
-		--*sel;
-	}
-}
-
-
-static void SetupScrollStuffForReplaceWindow(Window *w)
-{
-	EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE };
-	const Player* p = GetPlayer(_local_player);
-	uint sel[2];
-	uint count = 0;
-	uint count2 = 0;
-	EngineID i;
-
-	sel[0] = WP(w,replaceveh_d).sel_index[0];
-	sel[1] = WP(w,replaceveh_d).sel_index[1];
-
-	switch (WP(w,replaceveh_d).vehicletype) {
-		case VEH_Train: {
-			RailType railtype = _railtype_selected_in_replace_gui;
-
-			w->widget[13].color = _player_colors[_local_player]; // sets the colour of that art thing
-			w->widget[16].color = _player_colors[_local_player]; // sets the colour of that art thing
-
-			for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
-				EngineID eid = GetRailVehAtPosition(i);
-				const Engine* e = GetEngine(eid);
-				const EngineInfo* info = EngInfo(eid);
-
-				// left window contains compatible engines while right window only contains engines of the selected type
-				if (ENGINE_AVAILABLE &&
-						(RailVehInfo(eid)->power != 0) == (WP(w, replaceveh_d).wagon_btnstate != 0)) {
-					if (IsCompatibleRail(e->railtype, railtype) && (p->num_engines[eid] > 0 || EngineHasReplacementForPlayer(p, eid))) {
-						if (sel[0] == count) selected_id[0] = eid;
-						count++;
-					}
-					if (e->railtype == railtype && HASBIT(e->player_avail, _local_player)) {
-						if (sel[1] == count2) selected_id[1] = eid;
-						count2++;
-					}
-				}
-			}
-			break;
-		}
-
-		case VEH_Road: {
-			for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) {
-				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
-					if (sel[0] == count) selected_id[0] = i;
-					count++;
-				}
-			}
-
-			if (selected_id[0] != INVALID_ENGINE) { // only draw right array if we have anything in the left one
-				CargoID cargo = RoadVehInfo(selected_id[0])->cargo_type;
-
-				for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) {
-					if (cargo == RoadVehInfo(i)->cargo_type &&
-							HASBIT(GetEngine(i)->player_avail, _local_player)) {
-						if (sel[1] == count2) selected_id[1] = i;
-						count2++;
-					}
-				}
-			}
-			break;
-		}
-
-		case VEH_Ship: {
-			for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) {
-				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
-					if (sel[0] == count) selected_id[0] = i;
-					count++;
-				}
-			}
-
-			if (selected_id[0] != INVALID_ENGINE) {
-				const ShipVehicleInfo* svi = ShipVehInfo(selected_id[0]);
-				CargoID cargo = svi->cargo_type;
-				byte refittable = svi->refittable;
-
-				for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) {
-					if (HASBIT(GetEngine(i)->player_avail, _local_player) && (
-								ShipVehInfo(i)->cargo_type == cargo ||
-								ShipVehInfo(i)->refittable & refittable
-							)) {
-						if (sel[1] == count2) selected_id[1] = i;
-						count2++;
-					}
-				}
-			}
-			break;
-		}
-
-		case VEH_Aircraft: {
-			for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
-				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
-					if (sel[0] == count) selected_id[0] = i;
-					count++;
-				}
-			}
-
-			if (selected_id[0] != INVALID_ENGINE) {
-				byte subtype = AircraftVehInfo(selected_id[0])->subtype;
-
-				for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
-					if (HASBIT(GetEngine(i)->player_avail, _local_player) &&
-							(subtype & AIR_CTOL) == (AircraftVehInfo(i)->subtype & AIR_CTOL)) {
-						if (sel[1] == count2) selected_id[1] = i;
-						count2++;
-					}
-				}
-			}
-			break;
-		}
-	}
-	// sets up the number of items in each list
-	SetVScrollCount(w, count);
-	SetVScroll2Count(w, count2);
-	WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
-	WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
-
-	WP(w,replaceveh_d).count[0] = count;
-	WP(w,replaceveh_d).count[1] = count2;
-	return;
-}
-
-
-static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int y2, int pos, int pos2,
-	int sel1, int sel2, EngineID selected_id1, EngineID selected_id2)
-{
-	int sel[2];
-	EngineID selected_id[2];
-	const Player *p = GetPlayer(_local_player);
-
-	sel[0] = sel1;
-	sel[1] = sel2;
-
-	selected_id[0] = selected_id1;
-	selected_id[1] = selected_id2;
-
-	switch (WP(w,replaceveh_d).vehicletype) {
-		case VEH_Train: {
-			RailType railtype = _railtype_selected_in_replace_gui;
-			DrawString(157, w->widget[14].top + 1, _rail_types_list[railtype], 0x10);
-			/* draw sorting criteria string */
-
-			/* Ensure that custom engines which substituted wagons
-			 * are sorted correctly.
-			 * XXX - DO NOT EVER DO THIS EVER AGAIN! GRRR hacking in wagons as
-			 * engines to get more types.. Stays here until we have our own format
-			 * then it is exit!!! */
-			if (WP(w,replaceveh_d).wagon_btnstate) {
-				train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, true, false, true, true); // True engines
-				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, true, false, false, false); // True engines
-				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, false, false, false); // Feeble wagons
-			} else {
-				train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, false, true, true, true);
-				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, true, false, true);
-			}
-			break;
-		}
-
-		case VEH_Road: {
-			int num = NUM_ROAD_ENGINES;
-			const Engine* e = GetEngine(ROAD_ENGINES_INDEX);
-			EngineID engine_id = ROAD_ENGINES_INDEX;
-
-			do {
-				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
-					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
-						DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
-						DrawRoadVehEngine(x+29, y+6, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
-						SetDParam(0, p->num_engines[engine_id]);
-						DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0);
-						y += 14;
-					}
-				sel[0]--;
-				}
-
-				if (selected_id[0] != INVALID_ENGINE) {
-					byte cargo = RoadVehInfo(selected_id[0])->cargo_type;
-
-					if (RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player)) {
-						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) {
-							DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
-							DrawRoadVehEngine(x2+29, y2+6, engine_id, GetEnginePalette(engine_id, _local_player));
-							y2 += 14;
-						}
-						sel[1]--;
-					}
-				}
-			} while (++engine_id, ++e,--num);
-			break;
-		}
-
-		case VEH_Ship: {
-			int num = NUM_SHIP_ENGINES;
-			const Engine* e = GetEngine(SHIP_ENGINES_INDEX);
-			EngineID engine_id = SHIP_ENGINES_INDEX;
-
-			do {
-				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
-					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
-						DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
-						DrawShipEngine(x+35, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
-						SetDParam(0, p->num_engines[engine_id]);
-						DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
-						y += 24;
-					}
-					sel[0]--;
-				}
-
-				if (selected_id[0] != INVALID_ENGINE) {
-					CargoID cargo = ShipVehInfo(selected_id[0])->cargo_type;
-					bool refittable = ShipVehInfo(selected_id[0])->refittable;
-
-					if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
-						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
-							DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
-							DrawShipEngine(x2+35, y2+10, engine_id, GetEnginePalette(engine_id, _local_player));
-							y2 += 24;
-						}
-						sel[1]--;
-					}
-				}
-			} while (++engine_id, ++e, --num);
-			break;
-		}   //end of ship
-
-		case VEH_Aircraft: {
-			int num = NUM_AIRCRAFT_ENGINES;
-			const Engine* e = GetEngine(AIRCRAFT_ENGINES_INDEX);
-			EngineID engine_id = AIRCRAFT_ENGINES_INDEX;
-
-			do {
-				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
-					if (sel[0] == 0) selected_id[0] = engine_id;
-					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
-						DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
-						DrawAircraftEngine(x+29, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
-						SetDParam(0, p->num_engines[engine_id]);
-						DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
-						y += 24;
-					}
-					sel[0]--;
-				}
-
-				if (selected_id[0] != INVALID_ENGINE) {
-					byte subtype = AircraftVehInfo(selected_id[0])->subtype;
-
-					if ((subtype & AIR_CTOL) == (AircraftVehInfo(engine_id)->subtype & AIR_CTOL) &&
-							HASBIT(e->player_avail, _local_player)) {
-						if (sel[1] == 0) selected_id[1] = engine_id;
-						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
-							DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
-							DrawAircraftEngine(x2+29, y2+10, engine_id, GetEnginePalette(engine_id, _local_player));
-							y2 += 24;
-						}
-						sel[1]--;
-					}
-				}
-			} while (++engine_id, ++e,--num);
-			break;
-		}   // end of aircraft
-	}
-}
-
-static void DrawVehiclePurchaseInfo(const int x, const int y, uint w, const EngineID engine_number)
-{
-	switch (GetEngine(engine_number)->type) {
-		case VEH_Train:
-			if ((RailVehInfo(engine_number)->flags & RVI_WAGON) == 0) {
-				DrawTrainEnginePurchaseInfo(x, y, w, engine_number);
-			} else {
-				DrawTrainWagonPurchaseInfo(x, y, w, engine_number);
-			}
-			break;
-
-		case VEH_Road: DrawRoadVehPurchaseInfo(x, y, w, engine_number);      break;
-		case VEH_Ship: DrawShipPurchaseInfo(x, y, w, engine_number);         break;
-		case VEH_Aircraft: DrawAircraftPurchaseInfo(x, y, w, engine_number); break;
-		default: NOT_REACHED();
-	}
-}
-
-static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
-{
-	static const StringID _vehicle_type_names[] = {
-		STR_019F_TRAIN,
-		STR_019C_ROAD_VEHICLE,
-		STR_019E_SHIP,
-		STR_019D_AIRCRAFT
-	};
-
-	switch (e->event) {
-		case WE_PAINT: {
-				Player *p = GetPlayer(_local_player);
-				int pos = w->vscroll.pos;
-				EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE };
-				int x = 1;
-				int y = 15;
-				int pos2 = w->vscroll2.pos;
-				int x2 = 1 + 228;
-				int y2 = 15;
-				int sel[2];
-				byte i;
-				sel[0] = WP(w,replaceveh_d).sel_index[0];
-				sel[1] = WP(w,replaceveh_d).sel_index[1];
-
-				SetupScrollStuffForReplaceWindow(w);
-
-				selected_id[0] = WP(w,replaceveh_d).sel_engine[0];
-				selected_id[1] = WP(w,replaceveh_d).sel_engine[1];
-
-				// Disable the "Start Replacing" button if:
-				//    Either list is empty
-				// or Both lists have the same vehicle selected
-				// or The selected replacement engine has a replacement (to prevent loops)
-				// or The right list (new replacement) has the existing replacement vehicle selected
-				SetWindowWidgetDisabledState(w, 4,
-						selected_id[0] == INVALID_ENGINE ||
-						selected_id[1] == INVALID_ENGINE ||
-						selected_id[0] == selected_id[1] ||
-						EngineReplacementForPlayer(p, selected_id[1]) != INVALID_ENGINE ||
-						EngineReplacementForPlayer(p, selected_id[0]) == selected_id[1]);
-
-				// Disable the "Stop Replacing" button if:
-				//    The left list (existing vehicle) is empty
-				// or The selected vehicle has no replacement set up
-				SetWindowWidgetDisabledState(w, 6,
-						selected_id[0] == INVALID_ENGINE ||
-						!EngineHasReplacementForPlayer(p, selected_id[0]));
-
-				// now the actual drawing of the window itself takes place
-				SetDParam(0, _vehicle_type_names[WP(w, replaceveh_d).vehicletype - VEH_Train]);
-
-				if (WP(w, replaceveh_d).vehicletype == VEH_Train) {
-					// set on/off for renew_keep_length
-					SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
-
-					// set wagon/engine button
-					SetDParam(2, WP(w, replaceveh_d).wagon_btnstate ? STR_ENGINES : STR_WAGONS);
-				}
-
-				DrawWindowWidgets(w);
-
-				// sets up the string for the vehicle that is being replaced to
-				if (selected_id[0] != INVALID_ENGINE) {
-					if (!EngineHasReplacementForPlayer(p, selected_id[0])) {
-						SetDParam(0, STR_NOT_REPLACING);
-					} else {
-						SetDParam(0, GetCustomEngineName(EngineReplacementForPlayer(p, selected_id[0])));
-					}
-				} else {
-					SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
-				}
-
-				DrawString(145, w->widget[5].top + 1, STR_02BD, 0x10);
-
-				/* now we draw the two arrays according to what we just counted */
-				DrawEngineArrayInReplaceWindow(w, x, y, x2, y2, pos, pos2, sel[0], sel[1], selected_id[0], selected_id[1]);
-
-				WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
-				WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
-				/* now we draw the info about the vehicles we selected */
-				for (i = 0 ; i < 2 ; i++) {
-					if (selected_id[i] != INVALID_ENGINE) {
-						const Widget *wi = &w->widget[i == 0 ? 3 : 11];
-						DrawVehiclePurchaseInfo(wi->left + 2 , wi->top + 1, wi->right - wi->left - 2, selected_id[i]);
-					}
-				}
-			} break;   // end of paint
-
-		case WE_CLICK: {
-			// these 3 variables is used if any of the lists is clicked
-			uint16 click_scroll_pos = w->vscroll2.pos;
-			uint16 click_scroll_cap = w->vscroll2.cap;
-			byte click_side = 1;
-
-			switch (e->we.click.widget) {
-				case 12:
-					WP(w, replaceveh_d).wagon_btnstate = !(WP(w, replaceveh_d).wagon_btnstate);
-					SetWindowDirty(w);
-					break;
-
-				case 14:
-				case 15: /* Railtype selection dropdown menu */
-					ShowDropDownMenu(w, _rail_types_list, _railtype_selected_in_replace_gui, 15, 0, ~GetPlayer(_local_player)->avail_railtypes);
-					break;
-
-				case 17: /* toggle renew_keep_length */
-					DoCommandP(0, 5, GetPlayer(_local_player)->renew_keep_length ? 0 : 1, NULL, CMD_SET_AUTOREPLACE);
-					break;
-
-				case 4: { /* Start replacing */
-					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
-					EngineID veh_to = WP(w, replaceveh_d).sel_engine[1];
-					DoCommandP(0, 3, veh_from + (veh_to << 16), NULL, CMD_SET_AUTOREPLACE);
-					break;
-				}
-
-				case 6: { /* Stop replacing */
-					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
-					DoCommandP(0, 3, veh_from + (INVALID_ENGINE << 16), NULL, CMD_SET_AUTOREPLACE);
-					break;
-				}
-
-				case 7:
-					// sets up that the left one was clicked. The default values are for the right one (9)
-					// this way, the code for 9 handles both sides
-					click_scroll_pos = w->vscroll.pos;
-					click_scroll_cap = w->vscroll.cap;
-					click_side = 0;
-					/* FALL THROUGH */
-
-				case 9: {
-					uint i = (e->we.click.pt.y - 14) / w->resize.step_height;
-					if (i < click_scroll_cap) {
-						WP(w,replaceveh_d).sel_index[click_side] = i + click_scroll_pos;
-						SetWindowDirty(w);
-					}
-					break;
-				}
-			}
-			break;
-		}
-
-		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-			_railtype_selected_in_replace_gui = e->we.dropdown.index;
-			/* Reset scrollbar positions */
-			w->vscroll.pos  = 0;
-			w->vscroll2.pos = 0;
-			SetWindowDirty(w);
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap  += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->vscroll2.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-
-			w->widget[7].data = (w->vscroll.cap  << 8) + 1;
-			w->widget[9].data = (w->vscroll2.cap << 8) + 1;
-			break;
-	}
-}
-
-static const Widget _replace_rail_vehicle_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,       STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,       STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   126,   227, 0x0,            STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   240,   251, STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,   139,   316,   228,   239, 0x0,            STR_REPLACE_HELP_REPLACE_INFO_TAB},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   240,   251, STR_REPLACE_VEHICLES_STOP,  STR_REPLACE_HELP_STOP_BUTTON},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   125, 0x801,          STR_REPLACE_HELP_LEFT_ARRAY},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   125, STR_NULL,       STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   125, 0x801,          STR_REPLACE_HELP_RIGHT_ARRAY},
-{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   125, STR_NULL,       STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   126,   227, 0x0,            STR_NULL},
-// train specific stuff
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   228,   239, STR_REPLACE_ENGINE_WAGON_SELECT,       STR_REPLACE_ENGINE_WAGON_SELECT_HELP},  // widget 12
-{      WWT_PANEL,     RESIZE_TB,    14,   139,   153,   240,   251, 0x0,            STR_NULL},
-{      WWT_PANEL,     RESIZE_TB,    14,   154,   277,   240,   251, 0x0,            STR_REPLACE_HELP_RAILTYPE},
-{    WWT_TEXTBTN,     RESIZE_TB,    14,   278,   289,   240,   251, STR_0225,       STR_REPLACE_HELP_RAILTYPE},
-{      WWT_PANEL,     RESIZE_TB,    14,   290,   305,   240,   251, 0x0,            STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   317,   455,   228,   239, STR_REPLACE_REMOVE_WAGON,       STR_REPLACE_REMOVE_WAGON_HELP},
-// end of train specific stuff
-{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   240,   251, STR_NULL,       STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const Widget _replace_road_vehicle_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,  STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,                    STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   126,   217, 0x0,                         STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   218,   229, STR_REPLACE_VEHICLES_START,  STR_REPLACE_HELP_START_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,   139,   305,   218,   229, 0x0,                         STR_REPLACE_HELP_REPLACE_INFO_TAB},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   218,   229, STR_REPLACE_VEHICLES_STOP,   STR_REPLACE_HELP_STOP_BUTTON},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   125, 0x801,                       STR_REPLACE_HELP_LEFT_ARRAY},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   125, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   125, 0x801,                       STR_REPLACE_HELP_RIGHT_ARRAY},
-{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   125, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   126,   217, 0x0,                         STR_NULL},
-{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   218,   229, STR_NULL,                    STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const Widget _replace_ship_aircraft_vehicle_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,  STR_018C_WINDOW_TITLE_DRAG_THIS},
-{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,                    STR_STICKY_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   110,   201, 0x0,                         STR_NULL},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   202,   213, STR_REPLACE_VEHICLES_START,  STR_REPLACE_HELP_START_BUTTON},
-{      WWT_PANEL,     RESIZE_TB,    14,   139,   305,   202,   213, 0x0,                         STR_REPLACE_HELP_REPLACE_INFO_TAB},
-{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   202,   213, STR_REPLACE_VEHICLES_STOP,   STR_REPLACE_HELP_STOP_BUTTON},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   109, 0x401,                       STR_REPLACE_HELP_LEFT_ARRAY},
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   109, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   109, 0x401,                       STR_REPLACE_HELP_RIGHT_ARRAY},
-{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   109, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   110,   201, 0x0,                         STR_NULL},
-{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   202,   213, STR_NULL,                    STR_RESIZE_BUTTON},
-{   WIDGETS_END},
-};
-
-static const WindowDesc _replace_rail_vehicle_desc = {
-	WDP_AUTO, WDP_AUTO, 456, 252,
-	WC_REPLACE_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_replace_rail_vehicle_widgets,
-	ReplaceVehicleWndProc
-};
-
-static const WindowDesc _replace_road_vehicle_desc = {
-	WDP_AUTO, WDP_AUTO, 456, 230,
-	WC_REPLACE_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_replace_road_vehicle_widgets,
-	ReplaceVehicleWndProc
-};
-
-static const WindowDesc _replace_ship_aircraft_vehicle_desc = {
-	WDP_AUTO, WDP_AUTO, 456, 214,
-	WC_REPLACE_VEHICLE,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_replace_ship_aircraft_vehicle_widgets,
-	ReplaceVehicleWndProc
-};
-
-
-static void ShowReplaceVehicleWindow(byte vehicletype)
-{
-	Window *w;
-
-	DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype);
-
-	switch (vehicletype) {
-		case VEH_Train:
-			w = AllocateWindowDescFront(&_replace_rail_vehicle_desc, vehicletype);
-			w->vscroll.cap  = 8;
-			w->resize.step_height = 14;
-			WP(w, replaceveh_d).wagon_btnstate = true;
-			break;
-		case VEH_Road:
-			w = AllocateWindowDescFront(&_replace_road_vehicle_desc, vehicletype);
-			w->vscroll.cap  = 8;
-			w->resize.step_height = 14;
-			break;
-		case VEH_Ship:
-		case VEH_Aircraft:
-			w = AllocateWindowDescFront(&_replace_ship_aircraft_vehicle_desc, vehicletype);
-			w->vscroll.cap  = 4;
-			w->resize.step_height = 24;
-			break;
-		default: return;
-	}
-
-	w->caption_color = _local_player;
-	WP(w, replaceveh_d).vehicletype = vehicletype;
-	w->vscroll2.cap = w->vscroll.cap;   // these two are always the same
-}
-
-void InitializeGUI(void)
-{
-	memset(&_sorting, 0, sizeof(_sorting));
-}
-
-/** Assigns an already open vehicle window to a new vehicle.
- * Assigns an already open vehicle window to a new vehicle. If the vehicle got
- * any sub window open (orders and so on) it will change owner too.
- * @param *from_v the current owner of the window
- * @param *to_v the new owner of the window
- */
-void ChangeVehicleViewWindow(const Vehicle *from_v, const Vehicle *to_v)
-{
-	Window *w;
-
-	w = FindWindowById(WC_VEHICLE_VIEW, from_v->index);
-	if (w != NULL) {
-		w->window_number = to_v->index;
-		WP(w, vp_d).follow_vehicle = to_v->index;
-		SetWindowDirty(w);
-
-		w = FindWindowById(WC_VEHICLE_ORDERS, from_v->index);
-		if (w != NULL) {
-			w->window_number = to_v->index;
-			SetWindowDirty(w);
-		}
-
-		w = FindWindowById(WC_VEHICLE_REFIT, from_v->index);
-		if (w != NULL) {
-			w->window_number = to_v->index;
-			SetWindowDirty(w);
-		}
-
-		w = FindWindowById(WC_VEHICLE_DETAILS, from_v->index);
-		if (w != NULL) {
-			w->window_number = to_v->index;
-			SetWindowDirty(w);
-		}
-	}
-}
-
-/*
- * Start of functions regarding vehicle list windows
- */
-
-enum {
-	PLY_WND_PRC__OFFSET_TOP_WIDGET = 26,
-	PLY_WND_PRC__SIZE_OF_ROW_SMALL = 26,
-	PLY_WND_PRC__SIZE_OF_ROW_BIG   = 36,
-};
-
-enum VehicleListWindowWidgets {
-	VLW_WIDGET_CLOSEBOX = 0,
-	VLW_WIDGET_CAPTION,
-	VLW_WIDGET_STICKY,
-	VLW_WIDGET_SORT_ORDER,
-	VLW_WIDGET_SORT_BY_TEXT,
-	VLW_WIDGET_SORT_BY_PULLDOWN,
-	VLW_WIDGET_EMPTY_TOP_RIGHT,
-	VLW_WIDGET_LIST,
-	VLW_WIDGET_SCROLLBAR,
-	VLW_WIDGET_OTHER_PLAYER_FILLER,
-	VLW_WIDGET_NEW_VEHICLES,
-	VLW_WIDGET_MANAGE_VEHICLES,
-	VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
-	VLW_WIDGET_STOP_ALL,
-	VLW_WIDGET_START_ALL,
-	VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
-	VLW_WIDGET_RESIZE,
-};
-
-static const Widget _vehicle_list_widgets[] = {
-	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,             STR_018B_CLOSE_WINDOW},
-	{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   247,     0,    13, 0x0,                  STR_018C_WINDOW_TITLE_DRAG_THIS},
-	{  WWT_STICKYBOX,     RESIZE_LR,    14,   248,   259,     0,    13, 0x0,                  STR_STICKY_BUTTON},
-	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,          STR_SORT_ORDER_TIP},
-	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   235,    14,    25, 0x0,                  STR_SORT_CRITERIA_TIP},
-	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   236,   247,    14,    25, STR_0225,             STR_SORT_CRITERIA_TIP},
-	{      WWT_PANEL,  RESIZE_RIGHT,    14,   248,   259,    14,    25, 0x0,                  STR_NULL},
-	{     WWT_MATRIX,     RESIZE_RB,    14,     0,   247,    26,   169, 0x0,                  STR_NULL},
-	{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   248,   259,    26,   169, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
-	/* Widget to be shown for other players hiding the following 6 widgets */
-	{      WWT_PANEL,    RESIZE_RTB,    14,     0,   247,   170,   181, 0x0,                  STR_NULL},
-
-	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   105,   170,   181, 0x0,                  STR_AVAILABLE_ENGINES_TIP},
-	{    WWT_TEXTBTN,     RESIZE_TB,    14,   106,   211,   170,   181, STR_MANAGE_LIST,      STR_MANAGE_LIST_TIP},
-	{    WWT_TEXTBTN,     RESIZE_TB,    14,   212,   223,   170,   181, STR_0225,             STR_MANAGE_LIST_TIP},
-
-	{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,   224,   235,   170,   181, SPR_FLAG_VEH_STOPPED, STR_MASS_STOP_LIST_TIP},
-	{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,   236,   247,   170,   181, SPR_FLAG_VEH_RUNNING, STR_MASS_START_LIST_TIP},
-	{      WWT_PANEL,    RESIZE_RTB,    14,   248,   247,   170,   181, 0x0,                  STR_NULL},
-	{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   248,   259,   170,   181, 0x0,                  STR_RESIZE_BUTTON},
-	{   WIDGETS_END},
-};
-
-static void CreateVehicleListWindow(Window *w)
-{
-	vehiclelist_d *vl = &WP(w, vehiclelist_d);
-	uint16 window_type = w->window_number & VLW_MASK;
-	PlayerID player = GB(w->window_number, 0, 8);
-
-	vl->vehicle_type = GB(w->window_number, 11, 5);
-	vl->length_of_sort_list = 0;
-	vl->sort_list = NULL;
-	w->caption_color = player;
-
-	/* Hide the widgets that we will not use in this window
-	 * Some windows contains actions only fit for the owner */
-	if (player == _local_player) {
-		HideWindowWidget(w, VLW_WIDGET_OTHER_PLAYER_FILLER);
-		SetWindowWidgetDisabledState(w, VLW_WIDGET_NEW_VEHICLES, window_type != VLW_STANDARD);
-	} else {
-		SetWindowWidgetsHiddenState(w, true,
-			VLW_WIDGET_NEW_VEHICLES,
-			VLW_WIDGET_MANAGE_VEHICLES,
-			VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
-			VLW_WIDGET_STOP_ALL,
-			VLW_WIDGET_START_ALL,
-			VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
-			WIDGET_LIST_END);
-	}
-
-	/* Set up the window widgets */
-	switch (vl->vehicle_type) {
-		case VEH_Train:
-			w->widget[VLW_WIDGET_LIST].tooltips          = STR_883D_TRAINS_CLICK_ON_TRAIN_FOR;
-			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_8815_NEW_VEHICLES;
-			break;
-
-		case VEH_Road:
-			w->widget[VLW_WIDGET_LIST].tooltips          = STR_901A_ROAD_VEHICLES_CLICK_ON;
-			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_9004_NEW_VEHICLES;
-			break;
-
-		case VEH_Ship:
-			w->widget[VLW_WIDGET_LIST].tooltips          = STR_9823_SHIPS_CLICK_ON_SHIP_FOR;
-			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_9804_NEW_SHIPS;
-			break;
-
-		case VEH_Aircraft:
-			w->widget[VLW_WIDGET_LIST].tooltips          = STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT;
-			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_A003_NEW_AIRCRAFT;
-			break;
-
-		default: NOT_REACHED();
-	}
-
-	switch (window_type) {
-		case VLW_SHARED_ORDERS:
-			w->widget[VLW_WIDGET_CAPTION].data  = STR_VEH_WITH_SHARED_ORDERS_LIST;
-			break;
-		case VLW_STANDARD: /* Company Name - standard widget setup */
-			switch (vl->vehicle_type) {
-				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_881B_TRAINS;        break;
-				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_9001_ROAD_VEHICLES; break;
-				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_9805_SHIPS;         break;
-				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_A009_AIRCRAFT;      break;
-				default: NOT_REACHED(); break;
-			}
-			break;
-		case VLW_STATION_LIST: /* Station Name */
-			switch (vl->vehicle_type) {
-				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_TRAINS;        break;
-				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_ROAD_VEHICLES; break;
-				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_SHIPS;         break;
-				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_AIRCRAFT;      break;
-				default: NOT_REACHED(); break;
-			}
-			break;
-
-		case VLW_DEPOT_LIST:
-			switch (vl->vehicle_type) {
-				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_TRAIN_DEPOT;    break;
-				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_ROADVEH_DEPOT;  break;
-				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_SHIP_DEPOT;     break;
-				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_AIRCRAFT_DEPOT; break;
-				default: NOT_REACHED(); break;
-			}
-			break;
-		default: NOT_REACHED(); break;
-	}
-
-	switch (vl->vehicle_type) {
-		case VEH_Train:
-			w->resize.step_width = 1;
-			/* Fallthrough */
-		case VEH_Road:
-			w->vscroll.cap = 7;
-			w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_SMALL;
-			w->resize.height = 220 - (PLY_WND_PRC__SIZE_OF_ROW_SMALL * 3); // Minimum of 4 vehicles
-			break;
-		case VEH_Ship:
-		case VEH_Aircraft:
-			w->vscroll.cap = 4;
-			w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_BIG;
-			break;
-		default: NOT_REACHED();
-	}
-
-	w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-
-	/* Set up sorting. Make the window-specific _sorting variable
-		* point to the correct global _sorting struct so we are freed
-		* from having conditionals during window operation */
-	switch (vl->vehicle_type) {
-		case VEH_Train:    vl->_sorting = &_sorting.train; break;
-		case VEH_Road:     vl->_sorting = &_sorting.roadveh; break;
-		case VEH_Ship:     vl->_sorting = &_sorting.ship; break;
-		case VEH_Aircraft: vl->_sorting = &_sorting.aircraft; break;
-		default: NOT_REACHED(); break;
-	}
-
-	vl->l.flags = VL_REBUILD | (vl->_sorting->order << (VL_DESC - 1));
-	vl->l.sort_type = vl->_sorting->criteria;
-	vl->sort_list = NULL;
-	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;	// Set up resort timer
-}
-
-static void DrawSmallOrderList(const Vehicle *v, int x, int y)
-{
-	const Order *order;
-	int sel, i = 0;
-
-	sel = v->cur_order_index;
-
-	FOR_VEHICLE_ORDERS(v, order) {
-		if (sel == 0) DrawString(x - 6, y, STR_SMALL_RIGHT_ARROW, 16);
-		sel--;
-
-		if (order->type == OT_GOTO_STATION) {
-			if (v->type == VEH_Ship && IsBuoy(GetStation(order->dest))) continue;
-
-			SetDParam(0, order->dest);
-			DrawString(x, y, STR_A036, 0);
-
-			y += 6;
-			if (++i == 4) break;
-		}
-	}
-}
-
-static void DrawVehicleListWindow(Window *w)
-{
-	vehiclelist_d *vl = &WP(w, vehiclelist_d);
-	int x = 2;
-	int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
-	int max;
-	int i;
-	const PlayerID owner = (PlayerID)w->caption_color;
-	const Player *p = GetPlayer(owner);
-	const uint16 window_type = w->window_number & VLW_MASK;
-	const StationID station          = (window_type == VLW_STATION_LIST)  ? GB(w->window_number, 16, 16) : INVALID_STATION;
-	const OrderID order              = (window_type == VLW_SHARED_ORDERS) ? GB(w->window_number, 16, 16) : INVALID_ORDER;
-	const uint16 depot_airport_index = (window_type == VLW_DEPOT_LIST)    ? GB(w->window_number, 16, 16) : INVALID_STATION;
-
-	BuildVehicleList(vl, owner, station, order, depot_airport_index, window_type);
-	SortVehicleList(vl);
-	SetVScrollCount(w, vl->l.list_length);
-
-	/* draw the widgets */
-	switch (window_type) {
-		case VLW_SHARED_ORDERS: /* Shared Orders */
-			if (vl->l.list_length == 0) {
-				/* We can't open this window without vehicles using this order
-				 * and we should close the window when deleting the order      */
-				NOT_REACHED();
-			}
-			SetDParam(0, w->vscroll.count);
-			break;
-
-		case VLW_STANDARD: /* Company Name */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
-			break;
-
-		case VLW_STATION_LIST: /* Station Name */
-			SetDParam(0, station);
-			SetDParam(1, w->vscroll.count);
-			break;
-
-		case VLW_DEPOT_LIST:
-			switch (vl->vehicle_type) {
-				case VEH_Train:    SetDParam(0, STR_8800_TRAIN_DEPOT);        break;
-				case VEH_Road:     SetDParam(0, STR_9003_ROAD_VEHICLE_DEPOT); break;
-				case VEH_Ship:     SetDParam(0, STR_9803_SHIP_DEPOT);         break;
-				case VEH_Aircraft: SetDParam(0, STR_A002_AIRCRAFT_HANGAR);    break;
-				default: NOT_REACHED(); break;
-			}
-			if (vl->vehicle_type == VEH_Aircraft) {
-				SetDParam(1, depot_airport_index); // Airport name
-			} else {
-				SetDParam(1, GetDepot(depot_airport_index)->town_index);
-			}
-			SetDParam(2, w->vscroll.count);
-			break;
-		default: NOT_REACHED(); break;
-	}
-
-	SetWindowWidgetsDisabledState(w, vl->l.list_length == 0,
-		VLW_WIDGET_MANAGE_VEHICLES,
-		VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
-		VLW_WIDGET_STOP_ALL,
-		VLW_WIDGET_START_ALL,
-		WIDGET_LIST_END);
-
-	DrawWindowWidgets(w);
-
-	/* draw sorting criteria string */
-	DrawString(85, 15, _vehicle_sort_listing[vl->l.sort_type], 0x10);
-	/* draw arrow pointing up/down for ascending/descending sorting */
-	DoDrawString(vl->l.flags & VL_DESC ? DOWNARROW : UPARROW, 69, 15, 0x10);
-
-	max = min(w->vscroll.pos + w->vscroll.cap, vl->l.list_length);
-	for (i = w->vscroll.pos; i < max; ++i) {
-		const Vehicle *v = vl->sort_list[i];
-		StringID str;
-
-		SetDParam(0, v->profit_this_year);
-		SetDParam(1, v->profit_last_year);
-
-		DrawVehicleImage(v, x + 19, y + 6, w->widget[VLW_WIDGET_LIST].right - w->widget[VLW_WIDGET_LIST].left - 20, 0, INVALID_VEHICLE);
-		DrawString(x + 19, y + w->resize.step_height - 8, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
-
-		if ((v->type == VEH_Train    && v->string_id != STR_SV_TRAIN_NAME)   ||
-			(v->type == VEH_Road     && v->string_id != STR_SV_ROADVEH_NAME) ||
-			(v->type == VEH_Ship     && v->string_id != STR_SV_SHIP_NAME)    ||
-			(v->type == VEH_Aircraft && v->string_id != STR_SV_AIRCRAFT_NAME)) {
-
-			/* The vehicle got a name so we will print it */
-			SetDParam(0, v->string_id);
-			DrawString(x + 19, y, STR_01AB, 0);
-		}
-
-		if (w->resize.step_height == PLY_WND_PRC__SIZE_OF_ROW_BIG) DrawSmallOrderList(v, x + 138, y);
-
-		if (IsVehicleInDepot(v)) {
-			str = STR_021F;
-		} else {
-			str = (v->age > v->max_age - 366) ? STR_00E3 : STR_00E2;
-		}
-
-		SetDParam(0, v->unitnumber);
-		DrawString(x, y + 2, str, 0);
-
-		DrawVehicleProfitButton(v, x, y + 13);
-
-		y += w->resize.step_height;
-	}
-}
-
-/*
- * bitmask for w->window_number
- * 0-7 PlayerID (owner)
- * 8-10 window type (use flags in vehicle_gui.h)
- * 11-15 vehicle type (using VEH_, but can be compressed to fewer bytes if needed)
- * 16-31 StationID or OrderID depending on window type (bit 8-10)
- **/
-void PlayerVehWndProc(Window *w, WindowEvent *e)
-{
-	vehiclelist_d *vl = &WP(w, vehiclelist_d);
-
-	switch (e->event) {
-		case WE_CREATE:
-			CreateVehicleListWindow(w);
-			break;
-
-		case WE_PAINT:
-			DrawVehicleListWindow(w);
-			break;
-
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				case VLW_WIDGET_SORT_ORDER: /* Flip sorting method ascending/descending */
-					vl->l.flags ^= VL_DESC;
-					vl->l.flags |= VL_RESORT;
-
-					vl->_sorting->order = !!(vl->l.flags & VL_DESC);
-					SetWindowDirty(w);
-					break;
-				case VLW_WIDGET_SORT_BY_TEXT: case VLW_WIDGET_SORT_BY_PULLDOWN:/* Select sorting criteria dropdown menu */
-					ShowDropDownMenu(w, _vehicle_sort_listing, vl->l.sort_type, VLW_WIDGET_SORT_BY_PULLDOWN, 0, 0);
-					return;
-				case VLW_WIDGET_LIST: { /* Matrix to show vehicles */
-					uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / w->resize.step_height;
-					const Vehicle *v;
-
-					if (id_v >= w->vscroll.cap) return; // click out of bounds
-
-					id_v += w->vscroll.pos;
-
-					if (id_v >= vl->l.list_length) return; // click out of list bound
-
-					v = vl->sort_list[id_v];
-
-					switch (vl->vehicle_type) {
-						case VEH_Train: ShowTrainViewWindow(v); break;
-						case VEH_Road: ShowRoadVehViewWindow(v); break;
-						case VEH_Ship: ShowShipViewWindow(v); break;
-						case VEH_Aircraft: ShowAircraftViewWindow(v); break;
-						default: NOT_REACHED(); break;
-					}
-				} break;
-
-				case VLW_WIDGET_NEW_VEHICLES:
-					switch (vl->vehicle_type) {
-						case VEH_Train: ShowBuildTrainWindow(0); break;
-						case VEH_Road:  ShowBuildRoadVehWindow(0); break;
-						case VEH_Ship:  ShowBuildShipWindow(0); break;
-						case VEH_Aircraft: ShowBuildVehicleWindow(0, vl->vehicle_type); break;
-					}
-					break;
-
-				case VLW_WIDGET_MANAGE_VEHICLES:
-				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN: {
-					static StringID action_str[] = {
-						STR_REPLACE_VEHICLES,
-						STR_SEND_FOR_SERVICING,
-						STR_NULL,
-						INVALID_STRING_ID
-					};
-
-					static const StringID depot_name[] = {
-						STR_SEND_TRAIN_TO_DEPOT,
-						STR_SEND_ROAD_VEHICLE_TO_DEPOT,
-						STR_SEND_SHIP_TO_DEPOT,
-						STR_SEND_AIRCRAFT_TO_HANGAR
-					};
-
-					/* XXX - Substite string since the dropdown cannot handle dynamic strings */
-					action_str[2] = depot_name[vl->vehicle_type - VEH_Train];
-					ShowDropDownMenu(w, action_str, 0, VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN, 0, 0);
-					break;
-				}
-
-				case VLW_WIDGET_STOP_ALL:
-				case VLW_WIDGET_START_ALL:
-					DoCommandP(0, GB(w->window_number, 16, 16), (w->window_number & VLW_MASK) | (1 << 6) | (e->we.click.widget == VLW_WIDGET_START_ALL ? (1 << 5) : 0) | vl->vehicle_type, NULL, CMD_MASS_START_STOP);
-					break;
-			}
-		}	break;
-
-		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-			switch (e->we.dropdown.button) {
-				case VLW_WIDGET_SORT_BY_PULLDOWN:
-					if (vl->l.sort_type != e->we.dropdown.index) {
-						// value has changed -> resort
-						vl->l.flags |= VL_RESORT;
-						vl->l.sort_type = e->we.dropdown.index;
-						vl->_sorting->criteria = vl->l.sort_type;
-					}
-					break;
-				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
-					assert(vl->l.list_length != 0);
-
-					switch (e->we.dropdown.index) {
-						case 0: /* Replace window */
-							ShowReplaceVehicleWindow(vl->vehicle_type);
-							break;
-						case 1: /* Send for servicing */
-							DoCommandP(0, GB(w->window_number, 16, 16) /* StationID or OrderID (depending on VLW) */,
-								(w->window_number & VLW_MASK) | DEPOT_MASS_SEND | DEPOT_SERVICE,
-								NULL,
-								CMD_SEND_TO_DEPOT(vl->vehicle_type));
-							break;
-						case 2: /* Send to Depots */
-							DoCommandP(0, GB(w->window_number, 16, 16) /* StationID or OrderID (depending on VLW) */,
-								(w->window_number & VLW_MASK) | DEPOT_MASS_SEND,
-								NULL,
-								CMD_SEND_TO_DEPOT(vl->vehicle_type));
-							break;
-
-						default: NOT_REACHED();
-					}
-					break;
-				default: NOT_REACHED();
-			}
-			SetWindowDirty(w);
-			break;
-
-		case WE_DESTROY:
-			free((void*)vl->sort_list);
-			break;
-
-		case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
-			if (--vl->l.resort_timer == 0) {
-				StationID station = ((w->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(w->window_number, 16, 16) : INVALID_STATION;
-				PlayerID owner = (PlayerID)w->caption_color;
-
-				DEBUG(misc, 3, "Periodic resort %d list player %d at station %d", vl->vehicle_type, owner, station);
-				vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
-				vl->l.flags |= VL_RESORT;
-				SetWindowDirty(w);
-			}
-			break;
-
-		case WE_RESIZE: /* Update the scroll + matrix */
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-			break;
-	}
-}
-
-static const WindowDesc _player_vehicle_list_train_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 182,
-	WC_TRAINS_LIST, 0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_vehicle_list_widgets,
-	PlayerVehWndProc
-};
-
-static const WindowDesc _player_vehicle_list_road_veh_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 182,
-	WC_ROADVEH_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_vehicle_list_widgets,
-	PlayerVehWndProc
-};
-
-static const WindowDesc _player_vehicle_list_ship_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 182,
-	WC_SHIPS_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_vehicle_list_widgets,
-	PlayerVehWndProc
-};
-
-static const WindowDesc _player_vehicle_list_aircraft_desc = {
-	WDP_AUTO, WDP_AUTO, 260, 182,
-	WC_AIRCRAFT_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
-	_vehicle_list_widgets,
-	PlayerVehWndProc
-};
-
-static void ShowVehicleListWindowLocal(PlayerID player, byte vehicle_type, StationID station, OrderID order, uint16 depot_airport_index)
-{
-	Window *w;
-	WindowNumber num;
-
-	if (!IsValidPlayer(player)) return;
-
-	num = (vehicle_type << 11) | player;
-	if (order != INVALID_ORDER) {
-		num |= (order << 16) | VLW_SHARED_ORDERS;
-	} else if (depot_airport_index != INVALID_STATION) {
-		num |= (depot_airport_index << 16) | VLW_DEPOT_LIST;
-	} else if (station == INVALID_STATION) {
-		num |= VLW_STANDARD;
-	} else {
-		num |= (station << 16) | VLW_STATION_LIST;
-	}
-
-	/* The vehicle list windows have been unified. Just some strings need
-	 * to be changed which happens in the WE_CREATE event and resizing
-	 * some of the windows to the correct size */
-	switch (vehicle_type) {
-		default: NOT_REACHED();
-		case VEH_Train:
-			w = AllocateWindowDescFront(&_player_vehicle_list_train_desc, num);
-			if (w != NULL) ResizeWindow(w, 65, 38);
-			break;
-		case VEH_Road:
-			w = AllocateWindowDescFront(&_player_vehicle_list_road_veh_desc, num);
-			if (w != NULL) ResizeWindow(w, 0, 38);
-			break;
-		case VEH_Ship:
-			w = AllocateWindowDescFront(&_player_vehicle_list_ship_desc, num);
-			break;
-		case VEH_Aircraft:
-			w = AllocateWindowDescFront(&_player_vehicle_list_aircraft_desc, num);
-			break;
-	}
-
-	if (w != NULL) {
-		/* Set the minimum window size to the current window size */
-		w->resize.width = w->width;
-		w->resize.height = w->height;
-	}
-}
-
-void ShowVehicleListWindow(PlayerID player, StationID station, byte vehicle_type)
-{
-	ShowVehicleListWindowLocal(player, vehicle_type, station, INVALID_ORDER, INVALID_STATION);
-}
-
-void ShowVehWithSharedOrders(Vehicle *v, byte vehicle_type)
-{
-	if (v->orders == NULL) return; // no shared list to show
-	ShowVehicleListWindowLocal(v->owner, vehicle_type, INVALID_STATION, v->orders->index, INVALID_STATION);
-}
-
-void ShowVehDepotOrders(PlayerID player, byte vehicle_type, TileIndex depot_tile)
-{
-	uint16 depot_airport_index;
-
-	if (vehicle_type == VEH_Aircraft) {
-		depot_airport_index = GetStationIndex(depot_tile);
-	} else {
-		Depot *depot = GetDepotByTile(depot_tile);
-		if (depot == NULL) return; // no depot to show
-		depot_airport_index = depot->index;
-	}
-	ShowVehicleListWindowLocal(player, vehicle_type, INVALID_STATION, INVALID_ORDER, depot_airport_index);
-}
new file mode 100644
--- /dev/null
+++ b/src/vehicle_gui.cpp
@@ -0,0 +1,1945 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "player.h"
+#include "station.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "vehicle.h"
+#include "window.h"
+#include "engine.h"
+#include "gui.h"
+#include "command.h"
+#include "gfx.h"
+#include "variables.h"
+#include "vehicle_gui.h"
+#include "viewport.h"
+#include "train.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_text.h"
+#include "date.h"
+#include "ship.h"
+#include "aircraft.h"
+#include "roadveh.h"
+#include "depot.h"
+
+typedef struct Sorting {
+	Listing aircraft;
+	Listing roadveh;
+	Listing ship;
+	Listing train;
+} Sorting;
+
+static Sorting _sorting;
+
+typedef struct vehiclelist_d {
+	const Vehicle** sort_list;  // List of vehicles (sorted)
+	Listing *_sorting;          // pointer to the appropiate subcategory of _sorting
+	uint16 length_of_sort_list; // Keeps track of how many vehicle pointers sort list got space for
+	byte vehicle_type;          // The vehicle type that is sorted
+	list_d l;                   // General list struct
+} vehiclelist_d;
+assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehiclelist_d));
+
+static bool   _internal_sort_order;     // descending/ascending
+
+static RailType _railtype_selected_in_replace_gui;
+
+
+typedef int CDECL VehicleSortListingTypeFunction(const void*, const void*);
+
+static VehicleSortListingTypeFunction VehicleNumberSorter;
+static VehicleSortListingTypeFunction VehicleNameSorter;
+static VehicleSortListingTypeFunction VehicleAgeSorter;
+static VehicleSortListingTypeFunction VehicleProfitThisYearSorter;
+static VehicleSortListingTypeFunction VehicleProfitLastYearSorter;
+static VehicleSortListingTypeFunction VehicleCargoSorter;
+static VehicleSortListingTypeFunction VehicleReliabilitySorter;
+static VehicleSortListingTypeFunction VehicleMaxSpeedSorter;
+static VehicleSortListingTypeFunction VehicleModelSorter;
+static VehicleSortListingTypeFunction VehicleValueSorter;
+
+static VehicleSortListingTypeFunction* const _vehicle_sorter[] = {
+	&VehicleNumberSorter,
+	&VehicleNameSorter,
+	&VehicleAgeSorter,
+	&VehicleProfitThisYearSorter,
+	&VehicleProfitLastYearSorter,
+	&VehicleCargoSorter,
+	&VehicleReliabilitySorter,
+	&VehicleMaxSpeedSorter,
+	&VehicleModelSorter,
+	&VehicleValueSorter,
+};
+
+static const StringID _vehicle_sort_listing[] = {
+	STR_SORT_BY_NUMBER,
+	STR_SORT_BY_DROPDOWN_NAME,
+	STR_SORT_BY_AGE,
+	STR_SORT_BY_PROFIT_THIS_YEAR,
+	STR_SORT_BY_PROFIT_LAST_YEAR,
+	STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
+	STR_SORT_BY_RELIABILITY,
+	STR_SORT_BY_MAX_SPEED,
+	STR_SORT_BY_MODEL,
+	STR_SORT_BY_VALUE,
+	INVALID_STRING_ID
+};
+
+static const StringID _rail_types_list[] = {
+	STR_RAIL_VEHICLES,
+	STR_ELRAIL_VEHICLES,
+	STR_MONORAIL_VEHICLES,
+	STR_MAGLEV_VEHICLES,
+	INVALID_STRING_ID
+};
+
+void RebuildVehicleLists(void)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+
+		switch (w->window_class) {
+			case WC_TRAINS_LIST:
+			case WC_ROADVEH_LIST:
+			case WC_SHIPS_LIST:
+			case WC_AIRCRAFT_LIST:
+				WP(w, vehiclelist_d).l.flags |= VL_REBUILD;
+				SetWindowDirty(w);
+				break;
+		}
+	}
+}
+
+void ResortVehicleLists(void)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+
+		switch (w->window_class) {
+			case WC_TRAINS_LIST:
+			case WC_ROADVEH_LIST:
+			case WC_SHIPS_LIST:
+			case WC_AIRCRAFT_LIST:
+				WP(w, vehiclelist_d).l.flags |= VL_RESORT;
+				SetWindowDirty(w);
+				break;
+		}
+	}
+}
+
+static void BuildVehicleList(vehiclelist_d* vl, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type)
+{
+	if (!(vl->l.flags & VL_REBUILD)) return;
+
+	DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, station);
+
+	vl->l.list_length = GenerateVehicleSortList(&vl->sort_list, &vl->length_of_sort_list, vl->vehicle_type, owner, station, order, depot_airport_index, window_type);
+
+	vl->l.flags &= ~VL_REBUILD;
+	vl->l.flags |= VL_RESORT;
+}
+
+static void SortVehicleList(vehiclelist_d *vl)
+{
+	if (!(vl->l.flags & VL_RESORT)) return;
+
+	_internal_sort_order = vl->l.flags & VL_DESC;
+	qsort((void*)vl->sort_list, vl->l.list_length, sizeof(vl->sort_list[0]),
+		_vehicle_sorter[vl->l.sort_type]);
+
+	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+	vl->l.flags &= ~VL_RESORT;
+}
+
+void DepotSortList(Vehicle **v, uint16 length)
+{
+	_internal_sort_order = 0;
+	qsort((void*)v, length, sizeof(v[0]), _vehicle_sorter[0]);
+}
+
+/* General Vehicle GUI based procedures that are independent of vehicle types */
+void InitializeVehiclesGuiList(void)
+{
+	_railtype_selected_in_replace_gui = RAILTYPE_RAIL;
+}
+
+// draw the vehicle profit button in the vehicle list window.
+void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
+{
+	uint32 ormod;
+
+	// draw profit-based colored icons
+	if (v->age <= 365 * 2) {
+		ormod = PALETTE_TO_GREY;
+	} else if (v->profit_last_year < 0) {
+		ormod = PALETTE_TO_RED;
+	} else if (v->profit_last_year < 10000) {
+		ormod = PALETTE_TO_YELLOW;
+	} else {
+		ormod = PALETTE_TO_GREEN;
+	}
+	DrawSprite(SPR_BLOT | ormod, x, y);
+}
+
+typedef struct RefitOption {
+	CargoID cargo;
+	byte subtype;
+	uint16 value;
+	EngineID engine;
+} RefitOption;
+
+typedef struct RefitList {
+	uint num_lines;
+	RefitOption *items;
+} RefitList;
+
+static RefitList *BuildRefitList(const Vehicle *v)
+{
+	uint max_lines = 256;
+	RefitOption *refit = calloc(max_lines, sizeof(*refit));
+	RefitList *list = calloc(1, sizeof(*list));
+	Vehicle *u = (Vehicle*)v;
+	uint num_lines = 0;
+	uint i;
+
+	do {
+		CargoID cid;
+		uint32 cmask = EngInfo(u->engine_type)->refit_mask;
+		byte callbackmask = EngInfo(u->engine_type)->callbackmask;
+
+		/* Skip this engine if it has no capacity */
+		if (u->cargo_cap == 0) continue;
+
+		/* Loop through all cargos in the refit mask */
+		for (cid = 0; cmask != 0 && num_lines < max_lines; cmask >>= 1, cid++) {
+			CargoID lcid;
+
+			/* Skip cargo type if it's not listed */
+			if (!HASBIT(cmask, 0)) continue;
+
+			lcid = _local_cargo_id_ctype[cid];
+			if (lcid == CT_INVALID) continue;
+
+			/* Check the vehicle's callback mask for cargo suffixes */
+			if (HASBIT(callbackmask, CBM_CARGO_SUFFIX)) {
+				/* Make a note of the original cargo type. It has to be
+				 * changed to test the cargo & subtype... */
+				CargoID temp_cargo = u->cargo_type;
+				byte temp_subtype  = u->cargo_subtype;
+				byte refit_cyc;
+
+				u->cargo_type = lcid;
+
+				for (refit_cyc = 0; refit_cyc < 16 && num_lines < max_lines; refit_cyc++) {
+					bool duplicate = false;
+					uint16 callback;
+
+					u->cargo_subtype = refit_cyc;
+					callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u);
+
+					if (callback == 0xFF) callback = CALLBACK_FAILED;
+					if (refit_cyc != 0 && callback == CALLBACK_FAILED) break;
+
+					/* Check if this cargo and subtype combination are listed */
+					for (i = 0; i < num_lines && !duplicate; i++) {
+						if (refit[i].cargo == lcid && refit[i].value == callback) duplicate = true;
+					}
+
+					if (duplicate) continue;
+
+					refit[num_lines].cargo   = lcid;
+					refit[num_lines].subtype = refit_cyc;
+					refit[num_lines].value   = callback;
+					refit[num_lines].engine  = u->engine_type;
+					num_lines++;
+				}
+
+				/* Reset the vehicle's cargo type */
+				u->cargo_type    = temp_cargo;
+				u->cargo_subtype = temp_subtype;
+			} else {
+				/* No cargo suffix callback -- use no subtype */
+				bool duplicate = false;
+
+				for (i = 0; i < num_lines && !duplicate; i++) {
+					if (refit[i].cargo == lcid && refit[i].value == CALLBACK_FAILED) duplicate = true;
+				}
+
+				if (!duplicate) {
+					refit[num_lines].cargo   = lcid;
+					refit[num_lines].subtype = 0;
+					refit[num_lines].value   = CALLBACK_FAILED;
+					refit[num_lines].engine  = INVALID_ENGINE;
+					num_lines++;
+				}
+			}
+		}
+	} while (v->type == VEH_Train && (u = u->next) != NULL && num_lines < max_lines);
+
+	list->num_lines = num_lines;
+	list->items = refit;
+
+	return list;
+}
+
+/** Draw the list of available refit options for a consist.
+ * Draw the list and highlight the selected refit option (if any)
+ * @param *v first vehicle in consist to get the refit-options of
+ * @param sel selected refit cargo-type in the window
+ * @return the refit option that is hightlighted, NULL if none
+ */
+static RefitOption *DrawVehicleRefitWindow(const RefitList *list, int sel, uint pos, uint rows, uint delta)
+{
+	RefitOption *refit = list->items;
+	RefitOption *selected = NULL;
+	uint num_lines = list->num_lines;
+	uint y = 31;
+	uint i;
+
+	/* Draw the list, and find the selected cargo (by its position in list) */
+	for (i = 0; i < num_lines; i++) {
+		byte colour = 16;
+		if (sel == 0) {
+			selected = &refit[i];
+			colour = 12;
+		}
+
+		if (i >= pos && i < pos + rows) {
+			/* Draw the cargo name */
+			int last_x = DrawString(2, y, _cargoc.names_s[refit[i].cargo], colour);
+
+			/* If the callback succeeded, draw the cargo suffix */
+			if (refit[i].value != CALLBACK_FAILED) {
+				DrawString(last_x + 1, y, GetGRFStringID(GetEngineGRFID(refit[i].engine), 0xD000 + refit[i].value), colour);
+			}
+			y += delta;
+		}
+
+		sel--;
+	}
+
+	return selected;
+}
+
+static void VehicleRefitWndProc(Window *w, WindowEvent *e)
+{
+	switch (e->event) {
+		case WE_PAINT: {
+			Vehicle *v = GetVehicle(w->window_number);
+
+			if (v->type == VEH_Train) {
+				uint length = CountVehiclesInChain(v);
+
+				if (length != WP(w, refit_d).length) {
+					/* Consist length has changed, so rebuild the refit list */
+					free(WP(w, refit_d).list->items);
+					free(WP(w, refit_d).list);
+					WP(w, refit_d).list = BuildRefitList(v);
+					WP(w, refit_d).length = length;
+				}
+			}
+
+			SetVScrollCount(w, WP(w, refit_d).list->num_lines);
+
+			SetDParam(0, v->string_id);
+			SetDParam(1, v->unitnumber);
+			DrawWindowWidgets(w);
+
+			WP(w,refit_d).cargo = DrawVehicleRefitWindow(WP(w, refit_d).list, WP(w, refit_d).sel, w->vscroll.pos, w->vscroll.cap, w->resize.step_height);
+
+			if (WP(w,refit_d).cargo != NULL) {
+				int32 cost = 0;
+				switch (GetVehicle(w->window_number)->type) {
+					case VEH_Train:    cost = CMD_REFIT_RAIL_VEHICLE; break;
+					case VEH_Road:     cost = CMD_REFIT_ROAD_VEH;     break;
+					case VEH_Ship:     cost = CMD_REFIT_SHIP;         break;
+					case VEH_Aircraft: cost = CMD_REFIT_AIRCRAFT;     break;
+				}
+
+				cost = DoCommand(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8, DC_QUERY_COST, cost);
+				if (!CmdFailed(cost)) {
+					SetDParam(0, WP(w,refit_d).cargo->cargo);
+					SetDParam(1, _returned_refit_capacity);
+					SetDParam(2, cost);
+					DrawString(2, w->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
+				}
+			}
+		}	break;
+
+		case WE_CLICK:
+			switch (e->we.click.widget) {
+				case 3: { // listbox
+					int y = e->we.click.pt.y - w->widget[3].top;
+					if (y >= 0) {
+						WP(w,refit_d).sel = (y / (int)w->resize.step_height) + w->vscroll.pos;
+						SetWindowDirty(w);
+					}
+				} break;
+				case 6: // refit button
+					if (WP(w,refit_d).cargo != NULL) {
+						const Vehicle *v = GetVehicle(w->window_number);
+
+						if (WP(w, refit_d).order == INVALID_VEH_ORDER_ID) {
+							int command = 0;
+
+							switch (v->type) {
+								case VEH_Train:    command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE);  break;
+								case VEH_Road:     command = CMD_REFIT_ROAD_VEH     | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T);  break;
+								case VEH_Ship:     command = CMD_REFIT_SHIP         | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP);     break;
+								case VEH_Aircraft: command = CMD_REFIT_AIRCRAFT     | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
+							}
+							if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8, NULL, command)) DeleteWindow(w);
+						} else {
+							if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo->cargo | WP(w,refit_d).cargo->subtype << 8 | WP(w, refit_d).order << 16, NULL, CMD_ORDER_REFIT)) DeleteWindow(w);
+						}
+					}
+					break;
+			}
+			break;
+
+		case WE_RESIZE:
+			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
+			w->widget[3].data = (w->vscroll.cap << 8) + 1;
+			break;
+
+		case WE_DESTROY:
+			free(WP(w, refit_d).list->items);
+			free(WP(w, refit_d).list);
+			break;
+	}
+}
+
+
+static const Widget _vehicle_refit_widgets[] = {
+	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                            STR_018B_CLOSE_WINDOW},
+	{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   239,     0,    13, STR_983B_REFIT,                      STR_018C_WINDOW_TITLE_DRAG_THIS},
+	{    WWT_TEXTBTN,   RESIZE_NONE,    14,     0,   239,    14,    27, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, STR_983D_SELECT_TYPE_OF_CARGO_FOR},
+	{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   227,    28,   139, 0x801,                               STR_EMPTY},
+	{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   228,   239,    28,   139, 0x0,                                 STR_0190_SCROLL_BAR_SCROLLS_LIST},
+	{      WWT_PANEL,     RESIZE_TB,    14,     0,   239,   140,   161, 0x0,                                 STR_NULL},
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   227,   162,   173, 0x0,                                 STR_NULL},
+	{  WWT_RESIZEBOX,     RESIZE_TB,    14,   228,   239,   162,   173, 0x0,                                 STR_RESIZE_BUTTON},
+	{   WIDGETS_END},
+};
+
+static const WindowDesc _vehicle_refit_desc = {
+	WDP_AUTO, WDP_AUTO, 240, 174,
+	WC_VEHICLE_REFIT,WC_VEHICLE_VIEW,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
+	_vehicle_refit_widgets,
+	VehicleRefitWndProc,
+};
+
+/** Show the refit window for a vehicle
+* @param *v The vehicle to show the refit window for
+*/
+void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order)
+{
+	Window *w;
+
+	DeleteWindowById(WC_VEHICLE_REFIT, v->index);
+
+	w = AllocateWindowDescFront(&_vehicle_refit_desc, v->index);
+	WP(w, refit_d).order = order;
+
+	if (w != NULL) {
+		w->caption_color = v->owner;
+		w->vscroll.cap = 8;
+		w->resize.step_height = 14;
+		WP(w, refit_d).sel  = -1;
+		WP(w, refit_d).list = BuildRefitList(v);
+		if (v->type == VEH_Train) WP(w, refit_d).length = CountVehiclesInChain(v);
+		SetVScrollCount(w, WP(w, refit_d).list->num_lines);
+
+		switch (v->type) {
+			case VEH_Train:
+				w->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
+				w->widget[6].data     = STR_RAIL_REFIT_VEHICLE;
+				w->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
+				break;
+			case VEH_Road:
+				w->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
+				w->widget[6].data     = STR_REFIT_ROAD_VEHICLE;
+				w->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
+				break;
+			case VEH_Ship:
+				w->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
+				w->widget[6].data     = STR_983C_REFIT_SHIP;
+				w->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
+				break;
+			case VEH_Aircraft:
+				w->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
+				w->widget[6].data     = STR_A03D_REFIT_AIRCRAFT;
+				w->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
+				break;
+			default: NOT_REACHED();
+		}
+	}
+}
+
+/* Display additional text from NewGRF in the purchase information window */
+uint ShowAdditionalText(int x, int y, uint w, EngineID engine)
+{
+	uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
+	if (callback == CALLBACK_FAILED) return 0;
+
+	// STR_02BD is used to start the string with {BLACK}
+	SetDParam(0, GetGRFStringID(GetEngineGRFID(engine), 0xD000 + callback));
+	return DrawStringMultiLine(x, y, STR_02BD, w);
+}
+
+/* Count the number of bits that are set in a mask */
+static uint CountBits(uint32 mask)
+{
+	uint c = 0;
+	for (; mask != 0; mask >>= 1) if (HASBIT(mask, 0)) c++;
+	return c;
+}
+
+/* Display list of cargo types of the engine, for the purchase information window */
+uint ShowRefitOptionsList(int x, int y, uint w, EngineID engine)
+{
+	/* List of cargo types of this engine */
+	uint32 cmask = EngInfo(engine)->refit_mask;
+	/* List of cargo types available in this climate */
+	uint32 lmask = _landscape_global_cargo_mask[_opt.landscape];
+	char *b = _userstring;
+
+	/* Draw nothing if the engine is not refittable */
+	if (CountBits(cmask) <= 1) return 0;
+
+	b = InlineString(b, STR_PURCHASE_INFO_REFITTABLE_TO);
+
+	if (cmask == lmask) {
+		/* Engine can be refitted to all types in this climate */
+		b = InlineString(b, STR_PURCHASE_INFO_ALL_TYPES);
+	} else {
+		CargoID cid;
+
+		/* Check if we are able to refit to more cargo types and unable to. If
+		 * so, invert the cargo types to list those that we can't refit to. */
+		if (CountBits(cmask ^ lmask) < CountBits(cmask)) {
+			cmask ^= lmask;
+			b = InlineString(b, STR_PURCHASE_INFO_ALL_BUT);
+		}
+
+		/* Add each cargo type to the list */
+		for (cid = 0; cmask != 0; cmask >>= 1, cid++) {
+			if (!HASBIT(cmask, 0)) continue;
+
+			b = InlineString(b, _cargoc.names_s[_local_cargo_id_ctype[cid]]);
+			if (cmask > 1) b = strecpy(b, ", ", lastof(_userstring));
+		}
+	}
+
+	/* Terminate and display the completed string */
+	*b = '\0';
+	return DrawStringMultiLine(x, y, STR_SPEC_USERSTRING, w);
+}
+
+
+// if the sorting criteria had the same value, sort vehicle by unitnumber
+#define VEHICLEUNITNUMBERSORTER(r, a, b) {if (r == 0) {r = a->unitnumber - b->unitnumber;}}
+
+static int CDECL VehicleNumberSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->unitnumber - vb->unitnumber;
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleNameSorter(const void *a, const void *b)
+{
+	static const Vehicle *last_vehicle[2] = { NULL, NULL };
+	static char           last_name[2][64] = { "", "" };
+
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r;
+
+	if (va != last_vehicle[0]) {
+		last_vehicle[0] = va;
+		if (IsCustomName(va->string_id)) {
+			GetString(last_name[0], va->string_id, lastof(last_name[0]));
+		} else {
+			last_name[0][0] = '\0';
+		}
+	}
+
+	if (vb != last_vehicle[1]) {
+		last_vehicle[1] = vb;
+		if (IsCustomName(vb->string_id)) {
+			GetString(last_name[1], vb->string_id, lastof(last_name[1]));
+		} else {
+			last_name[1][0] = '\0';
+		}
+	}
+
+	r = strcmp(last_name[0], last_name[1]); // sort by name
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleAgeSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->age - vb->age;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleProfitThisYearSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->profit_this_year - vb->profit_this_year;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleProfitLastYearSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->profit_last_year - vb->profit_last_year;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleCargoSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	const Vehicle* v;
+	AcceptedCargo cargoa;
+	AcceptedCargo cargob;
+	int r = 0;
+	int i;
+
+	memset(cargoa, 0, sizeof(cargoa));
+	memset(cargob, 0, sizeof(cargob));
+	for (v = va; v != NULL; v = v->next) cargoa[v->cargo_type] += v->cargo_cap;
+	for (v = vb; v != NULL; v = v->next) cargob[v->cargo_type] += v->cargo_cap;
+
+	for (i = 0; i < NUM_CARGO; i++) {
+		r = cargoa[i] - cargob[i];
+		if (r != 0) break;
+	}
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleReliabilitySorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->reliability - vb->reliability;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleMaxSpeedSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int max_speed_a = 0xFFFF, max_speed_b = 0xFFFF;
+	int r;
+	const Vehicle *ua = va, *ub = vb;
+
+	if (va->type == VEH_Train && vb->type == VEH_Train) {
+		do {
+			if (RailVehInfo(ua->engine_type)->max_speed != 0)
+				max_speed_a = min(max_speed_a, RailVehInfo(ua->engine_type)->max_speed);
+		} while ((ua = ua->next) != NULL);
+
+		do {
+			if (RailVehInfo(ub->engine_type)->max_speed != 0)
+				max_speed_b = min(max_speed_b, RailVehInfo(ub->engine_type)->max_speed);
+		} while ((ub = ub->next) != NULL);
+
+		r = max_speed_a - max_speed_b;
+	} else {
+		r = va->max_speed - vb->max_speed;
+	}
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleModelSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	int r = va->engine_type - vb->engine_type;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+static int CDECL VehicleValueSorter(const void *a, const void *b)
+{
+	const Vehicle* va = *(const Vehicle**)a;
+	const Vehicle* vb = *(const Vehicle**)b;
+	const Vehicle *u;
+	int valuea = 0, valueb = 0;
+	int r;
+
+	for (u = va; u != NULL; u = u->next) valuea += u->value;
+	for (u = vb; u != NULL; u = u->next) valueb += u->value;
+
+	r = valuea - valueb;
+
+	VEHICLEUNITNUMBERSORTER(r, va, vb);
+
+	return (_internal_sort_order & 1) ? -r : r;
+}
+
+// this define is to match engine.c, but engine.c keeps it to itself
+// ENGINE_AVAILABLE is used in ReplaceVehicleWndProc
+#define ENGINE_AVAILABLE ((e->flags & 1 && HASBIT(info->climates, _opt.landscape)) || HASBIT(e->player_avail, _local_player))
+
+/*  if show_outdated is selected, it do not sort psudo engines properly but it draws all engines
+ * if used compined with show_cars set to false, it will work as intended. Replace window do it like that
+ *  this was a big hack even before show_outdated was added. Stupid newgrf :p
+ */
+static void train_engine_drawing_loop(int *x, int *y, int *pos, int *sel, EngineID *selected_id, RailType railtype,
+	uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated, bool show_compatible)
+{
+	EngineID j;
+	byte colour;
+	const Player *p = GetPlayer(_local_player);
+
+	for (j = 0; j < NUM_TRAIN_ENGINES; j++) {
+		EngineID i = GetRailVehAtPosition(j);
+		const Engine *e = GetEngine(i);
+		const RailVehicleInfo *rvi = RailVehInfo(i);
+		const EngineInfo *info = EngInfo(i);
+
+		if (!EngineHasReplacementForPlayer(p, i) && p->num_engines[i] == 0 && show_outdated) continue;
+
+		if ((rvi->power == 0 && !show_cars) || (rvi->power != 0 && show_cars))  // show wagons or engines (works since wagons do not have power)
+			continue;
+
+		if (*sel == 0) *selected_id = j;
+
+
+		colour = *sel == 0 ? 0xC : 0x10;
+		if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && IsCompatibleRail(e->railtype, railtype))) {
+			if ((!IsCompatibleRail(e->railtype, railtype) && show_compatible)
+				|| (e->railtype != railtype && !show_compatible)
+				|| !(rvi->flags & RVI_WAGON) != is_engine ||
+				!HASBIT(e->player_avail, _local_player))
+				continue;
+#if 0
+		} else {
+			// TODO find a nice red colour for vehicles being replaced
+			if ( _autoreplace_array[i] != i )
+				colour = *sel == 0 ? 0x44 : 0x45;
+#endif
+		}
+
+		if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) {
+			DrawString(*x + 59, *y + 2, GetCustomEngineName(i),
+				colour);
+			// show_outdated is true only for left side, which is where we show old replacements
+			DrawTrainEngine(*x + 29, *y + 6, i, (p->num_engines[i] == 0 && show_outdated) ?
+				PALETTE_CRASH : GetEnginePalette(i, _local_player));
+			if ( show_outdated ) {
+				SetDParam(0, p->num_engines[i]);
+				DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0);
+			}
+			*y += 14;
+		}
+		--*sel;
+	}
+}
+
+
+static void SetupScrollStuffForReplaceWindow(Window *w)
+{
+	EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE };
+	const Player* p = GetPlayer(_local_player);
+	uint sel[2];
+	uint count = 0;
+	uint count2 = 0;
+	EngineID i;
+
+	sel[0] = WP(w,replaceveh_d).sel_index[0];
+	sel[1] = WP(w,replaceveh_d).sel_index[1];
+
+	switch (WP(w,replaceveh_d).vehicletype) {
+		case VEH_Train: {
+			RailType railtype = _railtype_selected_in_replace_gui;
+
+			w->widget[13].color = _player_colors[_local_player]; // sets the colour of that art thing
+			w->widget[16].color = _player_colors[_local_player]; // sets the colour of that art thing
+
+			for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
+				EngineID eid = GetRailVehAtPosition(i);
+				const Engine* e = GetEngine(eid);
+				const EngineInfo* info = EngInfo(eid);
+
+				// left window contains compatible engines while right window only contains engines of the selected type
+				if (ENGINE_AVAILABLE &&
+						(RailVehInfo(eid)->power != 0) == (WP(w, replaceveh_d).wagon_btnstate != 0)) {
+					if (IsCompatibleRail(e->railtype, railtype) && (p->num_engines[eid] > 0 || EngineHasReplacementForPlayer(p, eid))) {
+						if (sel[0] == count) selected_id[0] = eid;
+						count++;
+					}
+					if (e->railtype == railtype && HASBIT(e->player_avail, _local_player)) {
+						if (sel[1] == count2) selected_id[1] = eid;
+						count2++;
+					}
+				}
+			}
+			break;
+		}
+
+		case VEH_Road: {
+			for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) {
+				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
+					if (sel[0] == count) selected_id[0] = i;
+					count++;
+				}
+			}
+
+			if (selected_id[0] != INVALID_ENGINE) { // only draw right array if we have anything in the left one
+				CargoID cargo = RoadVehInfo(selected_id[0])->cargo_type;
+
+				for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) {
+					if (cargo == RoadVehInfo(i)->cargo_type &&
+							HASBIT(GetEngine(i)->player_avail, _local_player)) {
+						if (sel[1] == count2) selected_id[1] = i;
+						count2++;
+					}
+				}
+			}
+			break;
+		}
+
+		case VEH_Ship: {
+			for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) {
+				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
+					if (sel[0] == count) selected_id[0] = i;
+					count++;
+				}
+			}
+
+			if (selected_id[0] != INVALID_ENGINE) {
+				const ShipVehicleInfo* svi = ShipVehInfo(selected_id[0]);
+				CargoID cargo = svi->cargo_type;
+				byte refittable = svi->refittable;
+
+				for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) {
+					if (HASBIT(GetEngine(i)->player_avail, _local_player) && (
+								ShipVehInfo(i)->cargo_type == cargo ||
+								ShipVehInfo(i)->refittable & refittable
+							)) {
+						if (sel[1] == count2) selected_id[1] = i;
+						count2++;
+					}
+				}
+			}
+			break;
+		}
+
+		case VEH_Aircraft: {
+			for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
+				if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) {
+					if (sel[0] == count) selected_id[0] = i;
+					count++;
+				}
+			}
+
+			if (selected_id[0] != INVALID_ENGINE) {
+				byte subtype = AircraftVehInfo(selected_id[0])->subtype;
+
+				for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) {
+					if (HASBIT(GetEngine(i)->player_avail, _local_player) &&
+							(subtype & AIR_CTOL) == (AircraftVehInfo(i)->subtype & AIR_CTOL)) {
+						if (sel[1] == count2) selected_id[1] = i;
+						count2++;
+					}
+				}
+			}
+			break;
+		}
+	}
+	// sets up the number of items in each list
+	SetVScrollCount(w, count);
+	SetVScroll2Count(w, count2);
+	WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
+	WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
+
+	WP(w,replaceveh_d).count[0] = count;
+	WP(w,replaceveh_d).count[1] = count2;
+	return;
+}
+
+
+static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int y2, int pos, int pos2,
+	int sel1, int sel2, EngineID selected_id1, EngineID selected_id2)
+{
+	int sel[2];
+	EngineID selected_id[2];
+	const Player *p = GetPlayer(_local_player);
+
+	sel[0] = sel1;
+	sel[1] = sel2;
+
+	selected_id[0] = selected_id1;
+	selected_id[1] = selected_id2;
+
+	switch (WP(w,replaceveh_d).vehicletype) {
+		case VEH_Train: {
+			RailType railtype = _railtype_selected_in_replace_gui;
+			DrawString(157, w->widget[14].top + 1, _rail_types_list[railtype], 0x10);
+			/* draw sorting criteria string */
+
+			/* Ensure that custom engines which substituted wagons
+			 * are sorted correctly.
+			 * XXX - DO NOT EVER DO THIS EVER AGAIN! GRRR hacking in wagons as
+			 * engines to get more types.. Stays here until we have our own format
+			 * then it is exit!!! */
+			if (WP(w,replaceveh_d).wagon_btnstate) {
+				train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, true, false, true, true); // True engines
+				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, true, false, false, false); // True engines
+				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, false, false, false); // Feeble wagons
+			} else {
+				train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, false, true, true, true);
+				train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, true, false, true);
+			}
+			break;
+		}
+
+		case VEH_Road: {
+			int num = NUM_ROAD_ENGINES;
+			const Engine* e = GetEngine(ROAD_ENGINES_INDEX);
+			EngineID engine_id = ROAD_ENGINES_INDEX;
+
+			do {
+				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
+					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
+						DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
+						DrawRoadVehEngine(x+29, y+6, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
+						SetDParam(0, p->num_engines[engine_id]);
+						DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0);
+						y += 14;
+					}
+				sel[0]--;
+				}
+
+				if (selected_id[0] != INVALID_ENGINE) {
+					byte cargo = RoadVehInfo(selected_id[0])->cargo_type;
+
+					if (RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player)) {
+						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) {
+							DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
+							DrawRoadVehEngine(x2+29, y2+6, engine_id, GetEnginePalette(engine_id, _local_player));
+							y2 += 14;
+						}
+						sel[1]--;
+					}
+				}
+			} while (++engine_id, ++e,--num);
+			break;
+		}
+
+		case VEH_Ship: {
+			int num = NUM_SHIP_ENGINES;
+			const Engine* e = GetEngine(SHIP_ENGINES_INDEX);
+			EngineID engine_id = SHIP_ENGINES_INDEX;
+
+			do {
+				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
+					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
+						DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
+						DrawShipEngine(x+35, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
+						SetDParam(0, p->num_engines[engine_id]);
+						DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
+						y += 24;
+					}
+					sel[0]--;
+				}
+
+				if (selected_id[0] != INVALID_ENGINE) {
+					CargoID cargo = ShipVehInfo(selected_id[0])->cargo_type;
+					bool refittable = ShipVehInfo(selected_id[0])->refittable;
+
+					if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
+						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
+							DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
+							DrawShipEngine(x2+35, y2+10, engine_id, GetEnginePalette(engine_id, _local_player));
+							y2 += 24;
+						}
+						sel[1]--;
+					}
+				}
+			} while (++engine_id, ++e, --num);
+			break;
+		}   //end of ship
+
+		case VEH_Aircraft: {
+			int num = NUM_AIRCRAFT_ENGINES;
+			const Engine* e = GetEngine(AIRCRAFT_ENGINES_INDEX);
+			EngineID engine_id = AIRCRAFT_ENGINES_INDEX;
+
+			do {
+				if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
+					if (sel[0] == 0) selected_id[0] = engine_id;
+					if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
+						DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
+						DrawAircraftEngine(x+29, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH);
+						SetDParam(0, p->num_engines[engine_id]);
+						DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
+						y += 24;
+					}
+					sel[0]--;
+				}
+
+				if (selected_id[0] != INVALID_ENGINE) {
+					byte subtype = AircraftVehInfo(selected_id[0])->subtype;
+
+					if ((subtype & AIR_CTOL) == (AircraftVehInfo(engine_id)->subtype & AIR_CTOL) &&
+							HASBIT(e->player_avail, _local_player)) {
+						if (sel[1] == 0) selected_id[1] = engine_id;
+						if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
+							DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
+							DrawAircraftEngine(x2+29, y2+10, engine_id, GetEnginePalette(engine_id, _local_player));
+							y2 += 24;
+						}
+						sel[1]--;
+					}
+				}
+			} while (++engine_id, ++e,--num);
+			break;
+		}   // end of aircraft
+	}
+}
+
+static void DrawVehiclePurchaseInfo(const int x, const int y, uint w, const EngineID engine_number)
+{
+	switch (GetEngine(engine_number)->type) {
+		case VEH_Train:
+			if ((RailVehInfo(engine_number)->flags & RVI_WAGON) == 0) {
+				DrawTrainEnginePurchaseInfo(x, y, w, engine_number);
+			} else {
+				DrawTrainWagonPurchaseInfo(x, y, w, engine_number);
+			}
+			break;
+
+		case VEH_Road: DrawRoadVehPurchaseInfo(x, y, w, engine_number);      break;
+		case VEH_Ship: DrawShipPurchaseInfo(x, y, w, engine_number);         break;
+		case VEH_Aircraft: DrawAircraftPurchaseInfo(x, y, w, engine_number); break;
+		default: NOT_REACHED();
+	}
+}
+
+static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
+{
+	static const StringID _vehicle_type_names[] = {
+		STR_019F_TRAIN,
+		STR_019C_ROAD_VEHICLE,
+		STR_019E_SHIP,
+		STR_019D_AIRCRAFT
+	};
+
+	switch (e->event) {
+		case WE_PAINT: {
+				Player *p = GetPlayer(_local_player);
+				int pos = w->vscroll.pos;
+				EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE };
+				int x = 1;
+				int y = 15;
+				int pos2 = w->vscroll2.pos;
+				int x2 = 1 + 228;
+				int y2 = 15;
+				int sel[2];
+				byte i;
+				sel[0] = WP(w,replaceveh_d).sel_index[0];
+				sel[1] = WP(w,replaceveh_d).sel_index[1];
+
+				SetupScrollStuffForReplaceWindow(w);
+
+				selected_id[0] = WP(w,replaceveh_d).sel_engine[0];
+				selected_id[1] = WP(w,replaceveh_d).sel_engine[1];
+
+				// Disable the "Start Replacing" button if:
+				//    Either list is empty
+				// or Both lists have the same vehicle selected
+				// or The selected replacement engine has a replacement (to prevent loops)
+				// or The right list (new replacement) has the existing replacement vehicle selected
+				SetWindowWidgetDisabledState(w, 4,
+						selected_id[0] == INVALID_ENGINE ||
+						selected_id[1] == INVALID_ENGINE ||
+						selected_id[0] == selected_id[1] ||
+						EngineReplacementForPlayer(p, selected_id[1]) != INVALID_ENGINE ||
+						EngineReplacementForPlayer(p, selected_id[0]) == selected_id[1]);
+
+				// Disable the "Stop Replacing" button if:
+				//    The left list (existing vehicle) is empty
+				// or The selected vehicle has no replacement set up
+				SetWindowWidgetDisabledState(w, 6,
+						selected_id[0] == INVALID_ENGINE ||
+						!EngineHasReplacementForPlayer(p, selected_id[0]));
+
+				// now the actual drawing of the window itself takes place
+				SetDParam(0, _vehicle_type_names[WP(w, replaceveh_d).vehicletype - VEH_Train]);
+
+				if (WP(w, replaceveh_d).vehicletype == VEH_Train) {
+					// set on/off for renew_keep_length
+					SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+
+					// set wagon/engine button
+					SetDParam(2, WP(w, replaceveh_d).wagon_btnstate ? STR_ENGINES : STR_WAGONS);
+				}
+
+				DrawWindowWidgets(w);
+
+				// sets up the string for the vehicle that is being replaced to
+				if (selected_id[0] != INVALID_ENGINE) {
+					if (!EngineHasReplacementForPlayer(p, selected_id[0])) {
+						SetDParam(0, STR_NOT_REPLACING);
+					} else {
+						SetDParam(0, GetCustomEngineName(EngineReplacementForPlayer(p, selected_id[0])));
+					}
+				} else {
+					SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
+				}
+
+				DrawString(145, w->widget[5].top + 1, STR_02BD, 0x10);
+
+				/* now we draw the two arrays according to what we just counted */
+				DrawEngineArrayInReplaceWindow(w, x, y, x2, y2, pos, pos2, sel[0], sel[1], selected_id[0], selected_id[1]);
+
+				WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
+				WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
+				/* now we draw the info about the vehicles we selected */
+				for (i = 0 ; i < 2 ; i++) {
+					if (selected_id[i] != INVALID_ENGINE) {
+						const Widget *wi = &w->widget[i == 0 ? 3 : 11];
+						DrawVehiclePurchaseInfo(wi->left + 2 , wi->top + 1, wi->right - wi->left - 2, selected_id[i]);
+					}
+				}
+			} break;   // end of paint
+
+		case WE_CLICK: {
+			// these 3 variables is used if any of the lists is clicked
+			uint16 click_scroll_pos = w->vscroll2.pos;
+			uint16 click_scroll_cap = w->vscroll2.cap;
+			byte click_side = 1;
+
+			switch (e->we.click.widget) {
+				case 12:
+					WP(w, replaceveh_d).wagon_btnstate = !(WP(w, replaceveh_d).wagon_btnstate);
+					SetWindowDirty(w);
+					break;
+
+				case 14:
+				case 15: /* Railtype selection dropdown menu */
+					ShowDropDownMenu(w, _rail_types_list, _railtype_selected_in_replace_gui, 15, 0, ~GetPlayer(_local_player)->avail_railtypes);
+					break;
+
+				case 17: /* toggle renew_keep_length */
+					DoCommandP(0, 5, GetPlayer(_local_player)->renew_keep_length ? 0 : 1, NULL, CMD_SET_AUTOREPLACE);
+					break;
+
+				case 4: { /* Start replacing */
+					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
+					EngineID veh_to = WP(w, replaceveh_d).sel_engine[1];
+					DoCommandP(0, 3, veh_from + (veh_to << 16), NULL, CMD_SET_AUTOREPLACE);
+					break;
+				}
+
+				case 6: { /* Stop replacing */
+					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
+					DoCommandP(0, 3, veh_from + (INVALID_ENGINE << 16), NULL, CMD_SET_AUTOREPLACE);
+					break;
+				}
+
+				case 7:
+					// sets up that the left one was clicked. The default values are for the right one (9)
+					// this way, the code for 9 handles both sides
+					click_scroll_pos = w->vscroll.pos;
+					click_scroll_cap = w->vscroll.cap;
+					click_side = 0;
+					/* FALL THROUGH */
+
+				case 9: {
+					uint i = (e->we.click.pt.y - 14) / w->resize.step_height;
+					if (i < click_scroll_cap) {
+						WP(w,replaceveh_d).sel_index[click_side] = i + click_scroll_pos;
+						SetWindowDirty(w);
+					}
+					break;
+				}
+			}
+			break;
+		}
+
+		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+			_railtype_selected_in_replace_gui = e->we.dropdown.index;
+			/* Reset scrollbar positions */
+			w->vscroll.pos  = 0;
+			w->vscroll2.pos = 0;
+			SetWindowDirty(w);
+			break;
+
+		case WE_RESIZE:
+			w->vscroll.cap  += e->we.sizing.diff.y / (int)w->resize.step_height;
+			w->vscroll2.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
+
+			w->widget[7].data = (w->vscroll.cap  << 8) + 1;
+			w->widget[9].data = (w->vscroll2.cap << 8) + 1;
+			break;
+	}
+}
+
+static const Widget _replace_rail_vehicle_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,       STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   126,   227, 0x0,            STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   240,   251, STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,   139,   316,   228,   239, 0x0,            STR_REPLACE_HELP_REPLACE_INFO_TAB},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   240,   251, STR_REPLACE_VEHICLES_STOP,  STR_REPLACE_HELP_STOP_BUTTON},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   125, 0x801,          STR_REPLACE_HELP_LEFT_ARRAY},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   125, STR_NULL,       STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   125, 0x801,          STR_REPLACE_HELP_RIGHT_ARRAY},
+{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   125, STR_NULL,       STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   126,   227, 0x0,            STR_NULL},
+// train specific stuff
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   228,   239, STR_REPLACE_ENGINE_WAGON_SELECT,       STR_REPLACE_ENGINE_WAGON_SELECT_HELP},  // widget 12
+{      WWT_PANEL,     RESIZE_TB,    14,   139,   153,   240,   251, 0x0,            STR_NULL},
+{      WWT_PANEL,     RESIZE_TB,    14,   154,   277,   240,   251, 0x0,            STR_REPLACE_HELP_RAILTYPE},
+{    WWT_TEXTBTN,     RESIZE_TB,    14,   278,   289,   240,   251, STR_0225,       STR_REPLACE_HELP_RAILTYPE},
+{      WWT_PANEL,     RESIZE_TB,    14,   290,   305,   240,   251, 0x0,            STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   317,   455,   228,   239, STR_REPLACE_REMOVE_WAGON,       STR_REPLACE_REMOVE_WAGON_HELP},
+// end of train specific stuff
+{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   240,   251, STR_NULL,       STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const Widget _replace_road_vehicle_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,  STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,                    STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   126,   217, 0x0,                         STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   218,   229, STR_REPLACE_VEHICLES_START,  STR_REPLACE_HELP_START_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,   139,   305,   218,   229, 0x0,                         STR_REPLACE_HELP_REPLACE_INFO_TAB},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   218,   229, STR_REPLACE_VEHICLES_STOP,   STR_REPLACE_HELP_STOP_BUTTON},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   125, 0x801,                       STR_REPLACE_HELP_LEFT_ARRAY},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   125, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   125, 0x801,                       STR_REPLACE_HELP_RIGHT_ARRAY},
+{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   125, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   126,   217, 0x0,                         STR_NULL},
+{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   218,   229, STR_NULL,                    STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const Widget _replace_ship_aircraft_vehicle_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                    STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,  STR_018C_WINDOW_TITLE_DRAG_THIS},
+{  WWT_STICKYBOX,   RESIZE_NONE,    14,   444,   455,     0,    13, STR_NULL,                    STR_STICKY_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,     0,   227,   110,   201, 0x0,                         STR_NULL},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   138,   202,   213, STR_REPLACE_VEHICLES_START,  STR_REPLACE_HELP_START_BUTTON},
+{      WWT_PANEL,     RESIZE_TB,    14,   139,   305,   202,   213, 0x0,                         STR_REPLACE_HELP_REPLACE_INFO_TAB},
+{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   306,   443,   202,   213, STR_REPLACE_VEHICLES_STOP,   STR_REPLACE_HELP_STOP_BUTTON},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,     0,   215,    14,   109, 0x401,                       STR_REPLACE_HELP_LEFT_ARRAY},
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,    14,   216,   227,    14,   109, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{     WWT_MATRIX, RESIZE_BOTTOM,    14,   228,   443,    14,   109, 0x401,                       STR_REPLACE_HELP_RIGHT_ARRAY},
+{ WWT_SCROLL2BAR, RESIZE_BOTTOM,    14,   444,   455,    14,   109, STR_NULL,                    STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_PANEL,     RESIZE_TB,    14,   228,   455,   110,   201, 0x0,                         STR_NULL},
+{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   202,   213, STR_NULL,                    STR_RESIZE_BUTTON},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _replace_rail_vehicle_desc = {
+	WDP_AUTO, WDP_AUTO, 456, 252,
+	WC_REPLACE_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_replace_rail_vehicle_widgets,
+	ReplaceVehicleWndProc
+};
+
+static const WindowDesc _replace_road_vehicle_desc = {
+	WDP_AUTO, WDP_AUTO, 456, 230,
+	WC_REPLACE_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_replace_road_vehicle_widgets,
+	ReplaceVehicleWndProc
+};
+
+static const WindowDesc _replace_ship_aircraft_vehicle_desc = {
+	WDP_AUTO, WDP_AUTO, 456, 214,
+	WC_REPLACE_VEHICLE,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_replace_ship_aircraft_vehicle_widgets,
+	ReplaceVehicleWndProc
+};
+
+
+static void ShowReplaceVehicleWindow(byte vehicletype)
+{
+	Window *w;
+
+	DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype);
+
+	switch (vehicletype) {
+		case VEH_Train:
+			w = AllocateWindowDescFront(&_replace_rail_vehicle_desc, vehicletype);
+			w->vscroll.cap  = 8;
+			w->resize.step_height = 14;
+			WP(w, replaceveh_d).wagon_btnstate = true;
+			break;
+		case VEH_Road:
+			w = AllocateWindowDescFront(&_replace_road_vehicle_desc, vehicletype);
+			w->vscroll.cap  = 8;
+			w->resize.step_height = 14;
+			break;
+		case VEH_Ship:
+		case VEH_Aircraft:
+			w = AllocateWindowDescFront(&_replace_ship_aircraft_vehicle_desc, vehicletype);
+			w->vscroll.cap  = 4;
+			w->resize.step_height = 24;
+			break;
+		default: return;
+	}
+
+	w->caption_color = _local_player;
+	WP(w, replaceveh_d).vehicletype = vehicletype;
+	w->vscroll2.cap = w->vscroll.cap;   // these two are always the same
+}
+
+void InitializeGUI(void)
+{
+	memset(&_sorting, 0, sizeof(_sorting));
+}
+
+/** Assigns an already open vehicle window to a new vehicle.
+ * Assigns an already open vehicle window to a new vehicle. If the vehicle got
+ * any sub window open (orders and so on) it will change owner too.
+ * @param *from_v the current owner of the window
+ * @param *to_v the new owner of the window
+ */
+void ChangeVehicleViewWindow(const Vehicle *from_v, const Vehicle *to_v)
+{
+	Window *w;
+
+	w = FindWindowById(WC_VEHICLE_VIEW, from_v->index);
+	if (w != NULL) {
+		w->window_number = to_v->index;
+		WP(w, vp_d).follow_vehicle = to_v->index;
+		SetWindowDirty(w);
+
+		w = FindWindowById(WC_VEHICLE_ORDERS, from_v->index);
+		if (w != NULL) {
+			w->window_number = to_v->index;
+			SetWindowDirty(w);
+		}
+
+		w = FindWindowById(WC_VEHICLE_REFIT, from_v->index);
+		if (w != NULL) {
+			w->window_number = to_v->index;
+			SetWindowDirty(w);
+		}
+
+		w = FindWindowById(WC_VEHICLE_DETAILS, from_v->index);
+		if (w != NULL) {
+			w->window_number = to_v->index;
+			SetWindowDirty(w);
+		}
+	}
+}
+
+/*
+ * Start of functions regarding vehicle list windows
+ */
+
+enum {
+	PLY_WND_PRC__OFFSET_TOP_WIDGET = 26,
+	PLY_WND_PRC__SIZE_OF_ROW_SMALL = 26,
+	PLY_WND_PRC__SIZE_OF_ROW_BIG   = 36,
+};
+
+enum VehicleListWindowWidgets {
+	VLW_WIDGET_CLOSEBOX = 0,
+	VLW_WIDGET_CAPTION,
+	VLW_WIDGET_STICKY,
+	VLW_WIDGET_SORT_ORDER,
+	VLW_WIDGET_SORT_BY_TEXT,
+	VLW_WIDGET_SORT_BY_PULLDOWN,
+	VLW_WIDGET_EMPTY_TOP_RIGHT,
+	VLW_WIDGET_LIST,
+	VLW_WIDGET_SCROLLBAR,
+	VLW_WIDGET_OTHER_PLAYER_FILLER,
+	VLW_WIDGET_NEW_VEHICLES,
+	VLW_WIDGET_MANAGE_VEHICLES,
+	VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
+	VLW_WIDGET_STOP_ALL,
+	VLW_WIDGET_START_ALL,
+	VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
+	VLW_WIDGET_RESIZE,
+};
+
+static const Widget _vehicle_list_widgets[] = {
+	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,             STR_018B_CLOSE_WINDOW},
+	{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   247,     0,    13, 0x0,                  STR_018C_WINDOW_TITLE_DRAG_THIS},
+	{  WWT_STICKYBOX,     RESIZE_LR,    14,   248,   259,     0,    13, 0x0,                  STR_STICKY_BUTTON},
+	{ WWT_PUSHTXTBTN,   RESIZE_NONE,    14,     0,    80,    14,    25, STR_SORT_BY,          STR_SORT_ORDER_TIP},
+	{      WWT_PANEL,   RESIZE_NONE,    14,    81,   235,    14,    25, 0x0,                  STR_SORT_CRITERIA_TIP},
+	{    WWT_TEXTBTN,   RESIZE_NONE,    14,   236,   247,    14,    25, STR_0225,             STR_SORT_CRITERIA_TIP},
+	{      WWT_PANEL,  RESIZE_RIGHT,    14,   248,   259,    14,    25, 0x0,                  STR_NULL},
+	{     WWT_MATRIX,     RESIZE_RB,    14,     0,   247,    26,   169, 0x0,                  STR_NULL},
+	{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   248,   259,    26,   169, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},
+	/* Widget to be shown for other players hiding the following 6 widgets */
+	{      WWT_PANEL,    RESIZE_RTB,    14,     0,   247,   170,   181, 0x0,                  STR_NULL},
+
+	{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,     0,   105,   170,   181, 0x0,                  STR_AVAILABLE_ENGINES_TIP},
+	{    WWT_TEXTBTN,     RESIZE_TB,    14,   106,   211,   170,   181, STR_MANAGE_LIST,      STR_MANAGE_LIST_TIP},
+	{    WWT_TEXTBTN,     RESIZE_TB,    14,   212,   223,   170,   181, STR_0225,             STR_MANAGE_LIST_TIP},
+
+	{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,   224,   235,   170,   181, SPR_FLAG_VEH_STOPPED, STR_MASS_STOP_LIST_TIP},
+	{ WWT_PUSHIMGBTN,     RESIZE_TB,    14,   236,   247,   170,   181, SPR_FLAG_VEH_RUNNING, STR_MASS_START_LIST_TIP},
+	{      WWT_PANEL,    RESIZE_RTB,    14,   248,   247,   170,   181, 0x0,                  STR_NULL},
+	{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   248,   259,   170,   181, 0x0,                  STR_RESIZE_BUTTON},
+	{   WIDGETS_END},
+};
+
+static void CreateVehicleListWindow(Window *w)
+{
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+	uint16 window_type = w->window_number & VLW_MASK;
+	PlayerID player = GB(w->window_number, 0, 8);
+
+	vl->vehicle_type = GB(w->window_number, 11, 5);
+	vl->length_of_sort_list = 0;
+	vl->sort_list = NULL;
+	w->caption_color = player;
+
+	/* Hide the widgets that we will not use in this window
+	 * Some windows contains actions only fit for the owner */
+	if (player == _local_player) {
+		HideWindowWidget(w, VLW_WIDGET_OTHER_PLAYER_FILLER);
+		SetWindowWidgetDisabledState(w, VLW_WIDGET_NEW_VEHICLES, window_type != VLW_STANDARD);
+	} else {
+		SetWindowWidgetsHiddenState(w, true,
+			VLW_WIDGET_NEW_VEHICLES,
+			VLW_WIDGET_MANAGE_VEHICLES,
+			VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
+			VLW_WIDGET_STOP_ALL,
+			VLW_WIDGET_START_ALL,
+			VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
+			WIDGET_LIST_END);
+	}
+
+	/* Set up the window widgets */
+	switch (vl->vehicle_type) {
+		case VEH_Train:
+			w->widget[VLW_WIDGET_LIST].tooltips          = STR_883D_TRAINS_CLICK_ON_TRAIN_FOR;
+			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_8815_NEW_VEHICLES;
+			break;
+
+		case VEH_Road:
+			w->widget[VLW_WIDGET_LIST].tooltips          = STR_901A_ROAD_VEHICLES_CLICK_ON;
+			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_9004_NEW_VEHICLES;
+			break;
+
+		case VEH_Ship:
+			w->widget[VLW_WIDGET_LIST].tooltips          = STR_9823_SHIPS_CLICK_ON_SHIP_FOR;
+			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_9804_NEW_SHIPS;
+			break;
+
+		case VEH_Aircraft:
+			w->widget[VLW_WIDGET_LIST].tooltips          = STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT;
+			w->widget[VLW_WIDGET_NEW_VEHICLES].data = STR_A003_NEW_AIRCRAFT;
+			break;
+
+		default: NOT_REACHED();
+	}
+
+	switch (window_type) {
+		case VLW_SHARED_ORDERS:
+			w->widget[VLW_WIDGET_CAPTION].data  = STR_VEH_WITH_SHARED_ORDERS_LIST;
+			break;
+		case VLW_STANDARD: /* Company Name - standard widget setup */
+			switch (vl->vehicle_type) {
+				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_881B_TRAINS;        break;
+				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_9001_ROAD_VEHICLES; break;
+				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_9805_SHIPS;         break;
+				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_A009_AIRCRAFT;      break;
+				default: NOT_REACHED(); break;
+			}
+			break;
+		case VLW_STATION_LIST: /* Station Name */
+			switch (vl->vehicle_type) {
+				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_TRAINS;        break;
+				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_ROAD_VEHICLES; break;
+				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_SHIPS;         break;
+				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_AIRCRAFT;      break;
+				default: NOT_REACHED(); break;
+			}
+			break;
+
+		case VLW_DEPOT_LIST:
+			switch (vl->vehicle_type) {
+				case VEH_Train:    w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_TRAIN_DEPOT;    break;
+				case VEH_Road:     w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_ROADVEH_DEPOT;  break;
+				case VEH_Ship:     w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_SHIP_DEPOT;     break;
+				case VEH_Aircraft: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_AIRCRAFT_DEPOT; break;
+				default: NOT_REACHED(); break;
+			}
+			break;
+		default: NOT_REACHED(); break;
+	}
+
+	switch (vl->vehicle_type) {
+		case VEH_Train:
+			w->resize.step_width = 1;
+			/* Fallthrough */
+		case VEH_Road:
+			w->vscroll.cap = 7;
+			w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_SMALL;
+			w->resize.height = 220 - (PLY_WND_PRC__SIZE_OF_ROW_SMALL * 3); // Minimum of 4 vehicles
+			break;
+		case VEH_Ship:
+		case VEH_Aircraft:
+			w->vscroll.cap = 4;
+			w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_BIG;
+			break;
+		default: NOT_REACHED();
+	}
+
+	w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+
+	/* Set up sorting. Make the window-specific _sorting variable
+		* point to the correct global _sorting struct so we are freed
+		* from having conditionals during window operation */
+	switch (vl->vehicle_type) {
+		case VEH_Train:    vl->_sorting = &_sorting.train; break;
+		case VEH_Road:     vl->_sorting = &_sorting.roadveh; break;
+		case VEH_Ship:     vl->_sorting = &_sorting.ship; break;
+		case VEH_Aircraft: vl->_sorting = &_sorting.aircraft; break;
+		default: NOT_REACHED(); break;
+	}
+
+	vl->l.flags = VL_REBUILD | (vl->_sorting->order << (VL_DESC - 1));
+	vl->l.sort_type = vl->_sorting->criteria;
+	vl->sort_list = NULL;
+	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;	// Set up resort timer
+}
+
+static void DrawSmallOrderList(const Vehicle *v, int x, int y)
+{
+	const Order *order;
+	int sel, i = 0;
+
+	sel = v->cur_order_index;
+
+	FOR_VEHICLE_ORDERS(v, order) {
+		if (sel == 0) DrawString(x - 6, y, STR_SMALL_RIGHT_ARROW, 16);
+		sel--;
+
+		if (order->type == OT_GOTO_STATION) {
+			if (v->type == VEH_Ship && IsBuoy(GetStation(order->dest))) continue;
+
+			SetDParam(0, order->dest);
+			DrawString(x, y, STR_A036, 0);
+
+			y += 6;
+			if (++i == 4) break;
+		}
+	}
+}
+
+static void DrawVehicleListWindow(Window *w)
+{
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+	int x = 2;
+	int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
+	int max;
+	int i;
+	const PlayerID owner = (PlayerID)w->caption_color;
+	const Player *p = GetPlayer(owner);
+	const uint16 window_type = w->window_number & VLW_MASK;
+	const StationID station          = (window_type == VLW_STATION_LIST)  ? GB(w->window_number, 16, 16) : INVALID_STATION;
+	const OrderID order              = (window_type == VLW_SHARED_ORDERS) ? GB(w->window_number, 16, 16) : INVALID_ORDER;
+	const uint16 depot_airport_index = (window_type == VLW_DEPOT_LIST)    ? GB(w->window_number, 16, 16) : INVALID_STATION;
+
+	BuildVehicleList(vl, owner, station, order, depot_airport_index, window_type);
+	SortVehicleList(vl);
+	SetVScrollCount(w, vl->l.list_length);
+
+	/* draw the widgets */
+	switch (window_type) {
+		case VLW_SHARED_ORDERS: /* Shared Orders */
+			if (vl->l.list_length == 0) {
+				/* We can't open this window without vehicles using this order
+				 * and we should close the window when deleting the order      */
+				NOT_REACHED();
+			}
+			SetDParam(0, w->vscroll.count);
+			break;
+
+		case VLW_STANDARD: /* Company Name */
+			SetDParam(0, p->name_1);
+			SetDParam(1, p->name_2);
+			SetDParam(2, w->vscroll.count);
+			break;
+
+		case VLW_STATION_LIST: /* Station Name */
+			SetDParam(0, station);
+			SetDParam(1, w->vscroll.count);
+			break;
+
+		case VLW_DEPOT_LIST:
+			switch (vl->vehicle_type) {
+				case VEH_Train:    SetDParam(0, STR_8800_TRAIN_DEPOT);        break;
+				case VEH_Road:     SetDParam(0, STR_9003_ROAD_VEHICLE_DEPOT); break;
+				case VEH_Ship:     SetDParam(0, STR_9803_SHIP_DEPOT);         break;
+				case VEH_Aircraft: SetDParam(0, STR_A002_AIRCRAFT_HANGAR);    break;
+				default: NOT_REACHED(); break;
+			}
+			if (vl->vehicle_type == VEH_Aircraft) {
+				SetDParam(1, depot_airport_index); // Airport name
+			} else {
+				SetDParam(1, GetDepot(depot_airport_index)->town_index);
+			}
+			SetDParam(2, w->vscroll.count);
+			break;
+		default: NOT_REACHED(); break;
+	}
+
+	SetWindowWidgetsDisabledState(w, vl->l.list_length == 0,
+		VLW_WIDGET_MANAGE_VEHICLES,
+		VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
+		VLW_WIDGET_STOP_ALL,
+		VLW_WIDGET_START_ALL,
+		WIDGET_LIST_END);
+
+	DrawWindowWidgets(w);
+
+	/* draw sorting criteria string */
+	DrawString(85, 15, _vehicle_sort_listing[vl->l.sort_type], 0x10);
+	/* draw arrow pointing up/down for ascending/descending sorting */
+	DoDrawString(vl->l.flags & VL_DESC ? DOWNARROW : UPARROW, 69, 15, 0x10);
+
+	max = min(w->vscroll.pos + w->vscroll.cap, vl->l.list_length);
+	for (i = w->vscroll.pos; i < max; ++i) {
+		const Vehicle *v = vl->sort_list[i];
+		StringID str;
+
+		SetDParam(0, v->profit_this_year);
+		SetDParam(1, v->profit_last_year);
+
+		DrawVehicleImage(v, x + 19, y + 6, w->widget[VLW_WIDGET_LIST].right - w->widget[VLW_WIDGET_LIST].left - 20, 0, INVALID_VEHICLE);
+		DrawString(x + 19, y + w->resize.step_height - 8, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+		if ((v->type == VEH_Train    && v->string_id != STR_SV_TRAIN_NAME)   ||
+			(v->type == VEH_Road     && v->string_id != STR_SV_ROADVEH_NAME) ||
+			(v->type == VEH_Ship     && v->string_id != STR_SV_SHIP_NAME)    ||
+			(v->type == VEH_Aircraft && v->string_id != STR_SV_AIRCRAFT_NAME)) {
+
+			/* The vehicle got a name so we will print it */
+			SetDParam(0, v->string_id);
+			DrawString(x + 19, y, STR_01AB, 0);
+		}
+
+		if (w->resize.step_height == PLY_WND_PRC__SIZE_OF_ROW_BIG) DrawSmallOrderList(v, x + 138, y);
+
+		if (IsVehicleInDepot(v)) {
+			str = STR_021F;
+		} else {
+			str = (v->age > v->max_age - 366) ? STR_00E3 : STR_00E2;
+		}
+
+		SetDParam(0, v->unitnumber);
+		DrawString(x, y + 2, str, 0);
+
+		DrawVehicleProfitButton(v, x, y + 13);
+
+		y += w->resize.step_height;
+	}
+}
+
+/*
+ * bitmask for w->window_number
+ * 0-7 PlayerID (owner)
+ * 8-10 window type (use flags in vehicle_gui.h)
+ * 11-15 vehicle type (using VEH_, but can be compressed to fewer bytes if needed)
+ * 16-31 StationID or OrderID depending on window type (bit 8-10)
+ **/
+void PlayerVehWndProc(Window *w, WindowEvent *e)
+{
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+
+	switch (e->event) {
+		case WE_CREATE:
+			CreateVehicleListWindow(w);
+			break;
+
+		case WE_PAINT:
+			DrawVehicleListWindow(w);
+			break;
+
+		case WE_CLICK: {
+			switch (e->we.click.widget) {
+				case VLW_WIDGET_SORT_ORDER: /* Flip sorting method ascending/descending */
+					vl->l.flags ^= VL_DESC;
+					vl->l.flags |= VL_RESORT;
+
+					vl->_sorting->order = !!(vl->l.flags & VL_DESC);
+					SetWindowDirty(w);
+					break;
+				case VLW_WIDGET_SORT_BY_TEXT: case VLW_WIDGET_SORT_BY_PULLDOWN:/* Select sorting criteria dropdown menu */
+					ShowDropDownMenu(w, _vehicle_sort_listing, vl->l.sort_type, VLW_WIDGET_SORT_BY_PULLDOWN, 0, 0);
+					return;
+				case VLW_WIDGET_LIST: { /* Matrix to show vehicles */
+					uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / w->resize.step_height;
+					const Vehicle *v;
+
+					if (id_v >= w->vscroll.cap) return; // click out of bounds
+
+					id_v += w->vscroll.pos;
+
+					if (id_v >= vl->l.list_length) return; // click out of list bound
+
+					v = vl->sort_list[id_v];
+
+					switch (vl->vehicle_type) {
+						case VEH_Train: ShowTrainViewWindow(v); break;
+						case VEH_Road: ShowRoadVehViewWindow(v); break;
+						case VEH_Ship: ShowShipViewWindow(v); break;
+						case VEH_Aircraft: ShowAircraftViewWindow(v); break;
+						default: NOT_REACHED(); break;
+					}
+				} break;
+
+				case VLW_WIDGET_NEW_VEHICLES:
+					switch (vl->vehicle_type) {
+						case VEH_Train: ShowBuildTrainWindow(0); break;
+						case VEH_Road:  ShowBuildRoadVehWindow(0); break;
+						case VEH_Ship:  ShowBuildShipWindow(0); break;
+						case VEH_Aircraft: ShowBuildVehicleWindow(0, vl->vehicle_type); break;
+					}
+					break;
+
+				case VLW_WIDGET_MANAGE_VEHICLES:
+				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN: {
+					static StringID action_str[] = {
+						STR_REPLACE_VEHICLES,
+						STR_SEND_FOR_SERVICING,
+						STR_NULL,
+						INVALID_STRING_ID
+					};
+
+					static const StringID depot_name[] = {
+						STR_SEND_TRAIN_TO_DEPOT,
+						STR_SEND_ROAD_VEHICLE_TO_DEPOT,
+						STR_SEND_SHIP_TO_DEPOT,
+						STR_SEND_AIRCRAFT_TO_HANGAR
+					};
+
+					/* XXX - Substite string since the dropdown cannot handle dynamic strings */
+					action_str[2] = depot_name[vl->vehicle_type - VEH_Train];
+					ShowDropDownMenu(w, action_str, 0, VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN, 0, 0);
+					break;
+				}
+
+				case VLW_WIDGET_STOP_ALL:
+				case VLW_WIDGET_START_ALL:
+					DoCommandP(0, GB(w->window_number, 16, 16), (w->window_number & VLW_MASK) | (1 << 6) | (e->we.click.widget == VLW_WIDGET_START_ALL ? (1 << 5) : 0) | vl->vehicle_type, NULL, CMD_MASS_START_STOP);
+					break;
+			}
+		}	break;
+
+		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+			switch (e->we.dropdown.button) {
+				case VLW_WIDGET_SORT_BY_PULLDOWN:
+					if (vl->l.sort_type != e->we.dropdown.index) {
+						// value has changed -> resort
+						vl->l.flags |= VL_RESORT;
+						vl->l.sort_type = e->we.dropdown.index;
+						vl->_sorting->criteria = vl->l.sort_type;
+					}
+					break;
+				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
+					assert(vl->l.list_length != 0);
+
+					switch (e->we.dropdown.index) {
+						case 0: /* Replace window */
+							ShowReplaceVehicleWindow(vl->vehicle_type);
+							break;
+						case 1: /* Send for servicing */
+							DoCommandP(0, GB(w->window_number, 16, 16) /* StationID or OrderID (depending on VLW) */,
+								(w->window_number & VLW_MASK) | DEPOT_MASS_SEND | DEPOT_SERVICE,
+								NULL,
+								CMD_SEND_TO_DEPOT(vl->vehicle_type));
+							break;
+						case 2: /* Send to Depots */
+							DoCommandP(0, GB(w->window_number, 16, 16) /* StationID or OrderID (depending on VLW) */,
+								(w->window_number & VLW_MASK) | DEPOT_MASS_SEND,
+								NULL,
+								CMD_SEND_TO_DEPOT(vl->vehicle_type));
+							break;
+
+						default: NOT_REACHED();
+					}
+					break;
+				default: NOT_REACHED();
+			}
+			SetWindowDirty(w);
+			break;
+
+		case WE_DESTROY:
+			free((void*)vl->sort_list);
+			break;
+
+		case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
+			if (--vl->l.resort_timer == 0) {
+				StationID station = ((w->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(w->window_number, 16, 16) : INVALID_STATION;
+				PlayerID owner = (PlayerID)w->caption_color;
+
+				DEBUG(misc, 3, "Periodic resort %d list player %d at station %d", vl->vehicle_type, owner, station);
+				vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+				vl->l.flags |= VL_RESORT;
+				SetWindowDirty(w);
+			}
+			break;
+
+		case WE_RESIZE: /* Update the scroll + matrix */
+			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
+			w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
+			break;
+	}
+}
+
+static const WindowDesc _player_vehicle_list_train_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 182,
+	WC_TRAINS_LIST, 0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_vehicle_list_widgets,
+	PlayerVehWndProc
+};
+
+static const WindowDesc _player_vehicle_list_road_veh_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 182,
+	WC_ROADVEH_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_vehicle_list_widgets,
+	PlayerVehWndProc
+};
+
+static const WindowDesc _player_vehicle_list_ship_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 182,
+	WC_SHIPS_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_vehicle_list_widgets,
+	PlayerVehWndProc
+};
+
+static const WindowDesc _player_vehicle_list_aircraft_desc = {
+	WDP_AUTO, WDP_AUTO, 260, 182,
+	WC_AIRCRAFT_LIST,0,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
+	_vehicle_list_widgets,
+	PlayerVehWndProc
+};
+
+static void ShowVehicleListWindowLocal(PlayerID player, byte vehicle_type, StationID station, OrderID order, uint16 depot_airport_index)
+{
+	Window *w;
+	WindowNumber num;
+
+	if (!IsValidPlayer(player)) return;
+
+	num = (vehicle_type << 11) | player;
+	if (order != INVALID_ORDER) {
+		num |= (order << 16) | VLW_SHARED_ORDERS;
+	} else if (depot_airport_index != INVALID_STATION) {
+		num |= (depot_airport_index << 16) | VLW_DEPOT_LIST;
+	} else if (station == INVALID_STATION) {
+		num |= VLW_STANDARD;
+	} else {
+		num |= (station << 16) | VLW_STATION_LIST;
+	}
+
+	/* The vehicle list windows have been unified. Just some strings need
+	 * to be changed which happens in the WE_CREATE event and resizing
+	 * some of the windows to the correct size */
+	switch (vehicle_type) {
+		default: NOT_REACHED();
+		case VEH_Train:
+			w = AllocateWindowDescFront(&_player_vehicle_list_train_desc, num);
+			if (w != NULL) ResizeWindow(w, 65, 38);
+			break;
+		case VEH_Road:
+			w = AllocateWindowDescFront(&_player_vehicle_list_road_veh_desc, num);
+			if (w != NULL) ResizeWindow(w, 0, 38);
+			break;
+		case VEH_Ship:
+			w = AllocateWindowDescFront(&_player_vehicle_list_ship_desc, num);
+			break;
+		case VEH_Aircraft:
+			w = AllocateWindowDescFront(&_player_vehicle_list_aircraft_desc, num);
+			break;
+	}
+
+	if (w != NULL) {
+		/* Set the minimum window size to the current window size */
+		w->resize.width = w->width;
+		w->resize.height = w->height;
+	}
+}
+
+void ShowVehicleListWindow(PlayerID player, StationID station, byte vehicle_type)
+{
+	ShowVehicleListWindowLocal(player, vehicle_type, station, INVALID_ORDER, INVALID_STATION);
+}
+
+void ShowVehWithSharedOrders(Vehicle *v, byte vehicle_type)
+{
+	if (v->orders == NULL) return; // no shared list to show
+	ShowVehicleListWindowLocal(v->owner, vehicle_type, INVALID_STATION, v->orders->index, INVALID_STATION);
+}
+
+void ShowVehDepotOrders(PlayerID player, byte vehicle_type, TileIndex depot_tile)
+{
+	uint16 depot_airport_index;
+
+	if (vehicle_type == VEH_Aircraft) {
+		depot_airport_index = GetStationIndex(depot_tile);
+	} else {
+		Depot *depot = GetDepotByTile(depot_tile);
+		if (depot == NULL) return; // no depot to show
+		depot_airport_index = depot->index;
+	}
+	ShowVehicleListWindowLocal(player, vehicle_type, INVALID_STATION, INVALID_ORDER, depot_airport_index);
+}
deleted file mode 100644
--- a/src/video/dedicated_v.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-
-#ifdef ENABLE_NETWORK
-
-#include "../openttd.h"
-#include "../debug.h"
-#include "../functions.h"
-#include "../gfx.h"
-#include "../network/network.h"
-#include "../window.h"
-#include "../console.h"
-#include "../variables.h"
-#include "../genworld.h"
-#include "dedicated_v.h"
-
-#ifdef BEOS_NET_SERVER
-#include <net/socket.h>
-#endif
-
-#ifdef __OS2__
-#	include <sys/time.h> /* gettimeofday */
-#	include <sys/types.h>
-#	include <unistd.h>
-#	include <conio.h>
-
-#	define INCL_DOS
-#	include <os2.h>
-
-#	define STDIN 0  /* file descriptor for standard input */
-
-/**
- * Switches OpenTTD to a console app at run-time, instead of a PM app
- * Necessary to see stdout, etc. */
-static void OS2_SwitchToConsoleMode(void)
-{
-	PPIB pib;
-	PTIB tib;
-
-	DosGetInfoBlocks(&tib, &pib);
-
-	// Change flag from PM to VIO
-	pib->pib_ultype = 3;
-}
-#endif
-
-#ifdef UNIX
-#	include <sys/time.h> /* gettimeofday */
-#	include <sys/types.h>
-#	include <unistd.h>
-#	include <signal.h>
-#	define STDIN 0  /* file descriptor for standard input */
-
-/* Signal handlers */
-static void DedicatedSignalHandler(int sig)
-{
-	_exit_game = true;
-	signal(sig, DedicatedSignalHandler);
-}
-#endif
-
-#ifdef WIN32
-#include <windows.h> /* GetTickCount */
-#include <conio.h>
-#include <time.h>
-#include <tchar.h>
-static HANDLE _hInputReady, _hWaitForInputHandling;
-static HANDLE _hThread; // Thread to close
-static char _win_console_thread_buffer[200];
-
-/* Windows Console thread. Just loop and signal when input has been received */
-static void WINAPI CheckForConsoleInput(void)
-{
-	while (true) {
-		fgets(_win_console_thread_buffer, lengthof(_win_console_thread_buffer), stdin);
-		/* Signal input waiting that input is read and wait for it being handled
-		 * SignalObjectAndWait() should be used here, but it's unsupported in Win98< */
-		SetEvent(_hInputReady);
-		WaitForSingleObject(_hWaitForInputHandling, INFINITE);
-	}
-}
-
-static void CreateWindowsConsoleThread(void)
-{
-	DWORD dwThreadId;
-	/* Create event to signal when console input is ready */
-	_hInputReady = CreateEvent(NULL, false, false, NULL);
-	_hWaitForInputHandling = CreateEvent(NULL, false, false, NULL);
-	if (_hInputReady == NULL || _hWaitForInputHandling == NULL) error("Cannot create console event!");
-
-	_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, NULL, 0, &dwThreadId);
-	if (_hThread == NULL) error("Cannot create console thread!");
-
-	DEBUG(driver, 2, "Windows console thread started");
-}
-
-static void CloseWindowsConsoleThread(void)
-{
-	CloseHandle(_hThread);
-	CloseHandle(_hInputReady);
-	CloseHandle(_hWaitForInputHandling);
-	DEBUG(driver, 2, "Windows console thread shut down");
-}
-
-#endif
-
-
-static void *_dedicated_video_mem;
-
-extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
-extern void SwitchMode(int new_mode);
-
-
-static const char *DedicatedVideoStart(const char * const *parm)
-{
-	_screen.width = _screen.pitch = _cur_resolution[0];
-	_screen.height = _cur_resolution[1];
-	_dedicated_video_mem = malloc(_cur_resolution[0]*_cur_resolution[1]);
-
-	SetDebugString("net=6");
-
-#ifdef WIN32
-	// For win32 we need to allocate a console (debug mode does the same)
-	CreateConsole();
-	CreateWindowsConsoleThread();
-	SetConsoleTitle(_T("OpenTTD Dedicated Server"));
-#endif
-
-#ifdef __OS2__
-	// For OS/2 we also need to switch to console mode instead of PM mode
-	OS2_SwitchToConsoleMode();
-#endif
-
-	DEBUG(driver, 1, "Loading dedicated server");
-	return NULL;
-}
-
-static void DedicatedVideoStop(void)
-{
-#ifdef WIN32
-	CloseWindowsConsoleThread();
-#endif
-	free(_dedicated_video_mem);
-}
-
-static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
-static bool DedicatedVideoChangeRes(int w, int h) { return false; }
-static void DedicatedVideoFullScreen(bool fs) {}
-
-#if defined(UNIX) || defined(__OS2__)
-static bool InputWaiting(void)
-{
-	struct timeval tv;
-	fd_set readfds;
-
-	tv.tv_sec = 0;
-	tv.tv_usec = 1;
-
-	FD_ZERO(&readfds);
-	FD_SET(STDIN, &readfds);
-
-	/* don't care about writefds and exceptfds: */
-	return select(STDIN + 1, &readfds, NULL, NULL, &tv) > 0;
-}
-
-static uint32 GetTime(void)
-{
-	struct timeval tim;
-
-	gettimeofday(&tim, NULL);
-	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
-}
-
-#else
-
-static bool InputWaiting(void)
-{
-	return WaitForSingleObject(_hInputReady, 1) == WAIT_OBJECT_0;
-}
-
-static uint32 GetTime(void)
-{
-	return GetTickCount();
-}
-
-#endif
-
-static void DedicatedHandleKeyInput(void)
-{
-	static char input_line[200] = "";
-
-	if (!InputWaiting()) return;
-
-	if (_exit_game) return;
-
-#if defined(UNIX) || defined(__OS2__)
-	if (fgets(input_line, lengthof(input_line), stdin) == NULL) return;
-#else
-	/* Handle console input, and singal console thread, it can accept input again */
-	strncpy(input_line, _win_console_thread_buffer, lengthof(input_line));
-	SetEvent(_hWaitForInputHandling);
-#endif
-
-	/* XXX - strtok() does not 'forget' \n\r if it is the first character! */
-	strtok(input_line, "\r\n"); // Forget about the final \n (or \r)
-	{ /* Remove any special control characters */
-		uint i;
-		for (i = 0; i < lengthof(input_line); i++) {
-			if (input_line[i] == '\n' || input_line[i] == '\r') // cut missed beginning '\0'
-				input_line[i] = '\0';
-
-			if (input_line[i] == '\0')
-				break;
-
-			if (!IS_INT_INSIDE(input_line[i], ' ', 256))
-				input_line[i] = ' ';
-		}
-	}
-
-	IConsoleCmdExec(input_line); // execute command
-}
-
-static void DedicatedVideoMainLoop(void)
-{
-	uint32 cur_ticks = GetTime();
-	uint32 next_tick = cur_ticks + 30;
-
-	/* Signal handlers */
-#ifdef UNIX
-	signal(SIGTERM, DedicatedSignalHandler);
-	signal(SIGINT, DedicatedSignalHandler);
-	signal(SIGQUIT, DedicatedSignalHandler);
-#endif
-
-	// Load the dedicated server stuff
-	_is_network_server = true;
-	_network_dedicated = true;
-	_network_playas = PLAYER_SPECTATOR;
-	_local_player = PLAYER_SPECTATOR;
-
-	/* If SwitchMode is SM_LOAD, it means that the user used the '-g' options */
-	if (_switch_mode != SM_LOAD) {
-		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
-		SwitchMode(_switch_mode);
-		_switch_mode = SM_NONE;
-	} else {
-		_switch_mode = SM_NONE;
-		/* First we need to test if the savegame can be loaded, else we will end up playing the
-		 *  intro game... */
-		if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
-			/* Loading failed, pop out.. */
-			DEBUG(net, 0, "Loading requested map failed, aborting");
-			_networking = false;
-		} else {
-			/* We can load this game, so go ahead */
-			SwitchMode(SM_LOAD);
-		}
-	}
-
-	// Done loading, start game!
-
-	if (!_networking) {
-		DEBUG(net, 0, "Dedicated server could not be started, aborting");
-		return;
-	}
-
-	while (!_exit_game) {
-		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
-		InteractiveRandom(); // randomness
-
-		if (!_dedicated_forks)
-			DedicatedHandleKeyInput();
-
-		cur_ticks = GetTime();
-		if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks) {
-			next_tick = cur_ticks + 30;
-
-			GameLoop();
-			_screen.dst_ptr = _dedicated_video_mem;
-			UpdateWindows();
-		}
-		CSleep(1);
-	}
-}
-
-const HalVideoDriver _dedicated_video_driver = {
-	DedicatedVideoStart,
-	DedicatedVideoStop,
-	DedicatedVideoMakeDirty,
-	DedicatedVideoMainLoop,
-	DedicatedVideoChangeRes,
-	DedicatedVideoFullScreen,
-};
-
-#endif /* ENABLE_NETWORK */
new file mode 100644
--- /dev/null
+++ b/src/video/dedicated_v.cpp
@@ -0,0 +1,296 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+
+#ifdef ENABLE_NETWORK
+
+#include "../openttd.h"
+#include "../debug.h"
+#include "../functions.h"
+#include "../gfx.h"
+#include "../network/network.h"
+#include "../window.h"
+#include "../console.h"
+#include "../variables.h"
+#include "../genworld.h"
+#include "dedicated_v.h"
+
+#ifdef BEOS_NET_SERVER
+#include <net/socket.h>
+#endif
+
+#ifdef __OS2__
+#	include <sys/time.h> /* gettimeofday */
+#	include <sys/types.h>
+#	include <unistd.h>
+#	include <conio.h>
+
+#	define INCL_DOS
+#	include <os2.h>
+
+#	define STDIN 0  /* file descriptor for standard input */
+
+/**
+ * Switches OpenTTD to a console app at run-time, instead of a PM app
+ * Necessary to see stdout, etc. */
+static void OS2_SwitchToConsoleMode(void)
+{
+	PPIB pib;
+	PTIB tib;
+
+	DosGetInfoBlocks(&tib, &pib);
+
+	// Change flag from PM to VIO
+	pib->pib_ultype = 3;
+}
+#endif
+
+#ifdef UNIX
+#	include <sys/time.h> /* gettimeofday */
+#	include <sys/types.h>
+#	include <unistd.h>
+#	include <signal.h>
+#	define STDIN 0  /* file descriptor for standard input */
+
+/* Signal handlers */
+static void DedicatedSignalHandler(int sig)
+{
+	_exit_game = true;
+	signal(sig, DedicatedSignalHandler);
+}
+#endif
+
+#ifdef WIN32
+#include <windows.h> /* GetTickCount */
+#include <conio.h>
+#include <time.h>
+#include <tchar.h>
+static HANDLE _hInputReady, _hWaitForInputHandling;
+static HANDLE _hThread; // Thread to close
+static char _win_console_thread_buffer[200];
+
+/* Windows Console thread. Just loop and signal when input has been received */
+static void WINAPI CheckForConsoleInput(void)
+{
+	while (true) {
+		fgets(_win_console_thread_buffer, lengthof(_win_console_thread_buffer), stdin);
+		/* Signal input waiting that input is read and wait for it being handled
+		 * SignalObjectAndWait() should be used here, but it's unsupported in Win98< */
+		SetEvent(_hInputReady);
+		WaitForSingleObject(_hWaitForInputHandling, INFINITE);
+	}
+}
+
+static void CreateWindowsConsoleThread(void)
+{
+	DWORD dwThreadId;
+	/* Create event to signal when console input is ready */
+	_hInputReady = CreateEvent(NULL, false, false, NULL);
+	_hWaitForInputHandling = CreateEvent(NULL, false, false, NULL);
+	if (_hInputReady == NULL || _hWaitForInputHandling == NULL) error("Cannot create console event!");
+
+	_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, NULL, 0, &dwThreadId);
+	if (_hThread == NULL) error("Cannot create console thread!");
+
+	DEBUG(driver, 2, "Windows console thread started");
+}
+
+static void CloseWindowsConsoleThread(void)
+{
+	CloseHandle(_hThread);
+	CloseHandle(_hInputReady);
+	CloseHandle(_hWaitForInputHandling);
+	DEBUG(driver, 2, "Windows console thread shut down");
+}
+
+#endif
+
+
+static void *_dedicated_video_mem;
+
+extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
+extern void SwitchMode(int new_mode);
+
+
+static const char *DedicatedVideoStart(const char * const *parm)
+{
+	_screen.width = _screen.pitch = _cur_resolution[0];
+	_screen.height = _cur_resolution[1];
+	_dedicated_video_mem = malloc(_cur_resolution[0]*_cur_resolution[1]);
+
+	SetDebugString("net=6");
+
+#ifdef WIN32
+	// For win32 we need to allocate a console (debug mode does the same)
+	CreateConsole();
+	CreateWindowsConsoleThread();
+	SetConsoleTitle(_T("OpenTTD Dedicated Server"));
+#endif
+
+#ifdef __OS2__
+	// For OS/2 we also need to switch to console mode instead of PM mode
+	OS2_SwitchToConsoleMode();
+#endif
+
+	DEBUG(driver, 1, "Loading dedicated server");
+	return NULL;
+}
+
+static void DedicatedVideoStop(void)
+{
+#ifdef WIN32
+	CloseWindowsConsoleThread();
+#endif
+	free(_dedicated_video_mem);
+}
+
+static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
+static bool DedicatedVideoChangeRes(int w, int h) { return false; }
+static void DedicatedVideoFullScreen(bool fs) {}
+
+#if defined(UNIX) || defined(__OS2__)
+static bool InputWaiting(void)
+{
+	struct timeval tv;
+	fd_set readfds;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 1;
+
+	FD_ZERO(&readfds);
+	FD_SET(STDIN, &readfds);
+
+	/* don't care about writefds and exceptfds: */
+	return select(STDIN + 1, &readfds, NULL, NULL, &tv) > 0;
+}
+
+static uint32 GetTime(void)
+{
+	struct timeval tim;
+
+	gettimeofday(&tim, NULL);
+	return tim.tv_usec / 1000 + tim.tv_sec * 1000;
+}
+
+#else
+
+static bool InputWaiting(void)
+{
+	return WaitForSingleObject(_hInputReady, 1) == WAIT_OBJECT_0;
+}
+
+static uint32 GetTime(void)
+{
+	return GetTickCount();
+}
+
+#endif
+
+static void DedicatedHandleKeyInput(void)
+{
+	static char input_line[200] = "";
+
+	if (!InputWaiting()) return;
+
+	if (_exit_game) return;
+
+#if defined(UNIX) || defined(__OS2__)
+	if (fgets(input_line, lengthof(input_line), stdin) == NULL) return;
+#else
+	/* Handle console input, and singal console thread, it can accept input again */
+	strncpy(input_line, _win_console_thread_buffer, lengthof(input_line));
+	SetEvent(_hWaitForInputHandling);
+#endif
+
+	/* XXX - strtok() does not 'forget' \n\r if it is the first character! */
+	strtok(input_line, "\r\n"); // Forget about the final \n (or \r)
+	{ /* Remove any special control characters */
+		uint i;
+		for (i = 0; i < lengthof(input_line); i++) {
+			if (input_line[i] == '\n' || input_line[i] == '\r') // cut missed beginning '\0'
+				input_line[i] = '\0';
+
+			if (input_line[i] == '\0')
+				break;
+
+			if (!IS_INT_INSIDE(input_line[i], ' ', 256))
+				input_line[i] = ' ';
+		}
+	}
+
+	IConsoleCmdExec(input_line); // execute command
+}
+
+static void DedicatedVideoMainLoop(void)
+{
+	uint32 cur_ticks = GetTime();
+	uint32 next_tick = cur_ticks + 30;
+
+	/* Signal handlers */
+#ifdef UNIX
+	signal(SIGTERM, DedicatedSignalHandler);
+	signal(SIGINT, DedicatedSignalHandler);
+	signal(SIGQUIT, DedicatedSignalHandler);
+#endif
+
+	// Load the dedicated server stuff
+	_is_network_server = true;
+	_network_dedicated = true;
+	_network_playas = PLAYER_SPECTATOR;
+	_local_player = PLAYER_SPECTATOR;
+
+	/* If SwitchMode is SM_LOAD, it means that the user used the '-g' options */
+	if (_switch_mode != SM_LOAD) {
+		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
+		SwitchMode(_switch_mode);
+		_switch_mode = SM_NONE;
+	} else {
+		_switch_mode = SM_NONE;
+		/* First we need to test if the savegame can be loaded, else we will end up playing the
+		 *  intro game... */
+		if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
+			/* Loading failed, pop out.. */
+			DEBUG(net, 0, "Loading requested map failed, aborting");
+			_networking = false;
+		} else {
+			/* We can load this game, so go ahead */
+			SwitchMode(SM_LOAD);
+		}
+	}
+
+	// Done loading, start game!
+
+	if (!_networking) {
+		DEBUG(net, 0, "Dedicated server could not be started, aborting");
+		return;
+	}
+
+	while (!_exit_game) {
+		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
+		InteractiveRandom(); // randomness
+
+		if (!_dedicated_forks)
+			DedicatedHandleKeyInput();
+
+		cur_ticks = GetTime();
+		if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks) {
+			next_tick = cur_ticks + 30;
+
+			GameLoop();
+			_screen.dst_ptr = _dedicated_video_mem;
+			UpdateWindows();
+		}
+		CSleep(1);
+	}
+}
+
+const HalVideoDriver _dedicated_video_driver = {
+	DedicatedVideoStart,
+	DedicatedVideoStop,
+	DedicatedVideoMakeDirty,
+	DedicatedVideoMainLoop,
+	DedicatedVideoChangeRes,
+	DedicatedVideoFullScreen,
+};
+
+#endif /* ENABLE_NETWORK */
deleted file mode 100644
--- a/src/video/null_v.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../gfx.h"
-#include "../variables.h"
-#include "../window.h"
-#include "null_v.h"
-
-static void* _null_video_mem = NULL;
-
-static const char* NullVideoStart(const char* const* parm)
-{
-	_screen.width = _screen.pitch = _cur_resolution[0];
-	_screen.height = _cur_resolution[1];
-	_null_video_mem = malloc(_cur_resolution[0] * _cur_resolution[1]);
-	return NULL;
-}
-
-static void NullVideoStop(void) { free(_null_video_mem); }
-
-static void NullVideoMakeDirty(int left, int top, int width, int height) {}
-
-static void NullVideoMainLoop(void)
-{
-	uint i;
-
-	for (i = 0; i < 1000; i++) {
-		GameLoop();
-		_screen.dst_ptr = _null_video_mem;
-		UpdateWindows();
-	}
-}
-
-static bool NullVideoChangeRes(int w, int h) { return false; }
-static void NullVideoFullScreen(bool fs) {}
-
-const HalVideoDriver _null_video_driver = {
-	NullVideoStart,
-	NullVideoStop,
-	NullVideoMakeDirty,
-	NullVideoMainLoop,
-	NullVideoChangeRes,
-	NullVideoFullScreen,
-};
new file mode 100644
--- /dev/null
+++ b/src/video/null_v.cpp
@@ -0,0 +1,45 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../gfx.h"
+#include "../variables.h"
+#include "../window.h"
+#include "null_v.h"
+
+static void* _null_video_mem = NULL;
+
+static const char* NullVideoStart(const char* const* parm)
+{
+	_screen.width = _screen.pitch = _cur_resolution[0];
+	_screen.height = _cur_resolution[1];
+	_null_video_mem = malloc(_cur_resolution[0] * _cur_resolution[1]);
+	return NULL;
+}
+
+static void NullVideoStop(void) { free(_null_video_mem); }
+
+static void NullVideoMakeDirty(int left, int top, int width, int height) {}
+
+static void NullVideoMainLoop(void)
+{
+	uint i;
+
+	for (i = 0; i < 1000; i++) {
+		GameLoop();
+		_screen.dst_ptr = _null_video_mem;
+		UpdateWindows();
+	}
+}
+
+static bool NullVideoChangeRes(int w, int h) { return false; }
+static void NullVideoFullScreen(bool fs) {}
+
+const HalVideoDriver _null_video_driver = {
+	NullVideoStart,
+	NullVideoStop,
+	NullVideoMakeDirty,
+	NullVideoMainLoop,
+	NullVideoChangeRes,
+	NullVideoFullScreen,
+};
deleted file mode 100644
--- a/src/video/sdl_v.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-
-#ifdef WITH_SDL
-
-#include "../openttd.h"
-#include "../debug.h"
-#include "../functions.h"
-#include "../gfx.h"
-#include "../macros.h"
-#include "../sdl.h"
-#include "../window.h"
-#include "../network/network.h"
-#include "../variables.h"
-#include "sdl_v.h"
-#include <SDL.h>
-
-static SDL_Surface *_sdl_screen;
-static bool _all_modes;
-
-#define MAX_DIRTY_RECTS 100
-static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
-static int _num_dirty_rects;
-
-static void SdlVideoMakeDirty(int left, int top, int width, int height)
-{
-	if (_num_dirty_rects < MAX_DIRTY_RECTS) {
-		_dirty_rects[_num_dirty_rects].x = left;
-		_dirty_rects[_num_dirty_rects].y = top;
-		_dirty_rects[_num_dirty_rects].w = width;
-		_dirty_rects[_num_dirty_rects].h = height;
-	}
-	_num_dirty_rects++;
-}
-
-static void UpdatePalette(uint start, uint count)
-{
-	SDL_Color pal[256];
-	uint i;
-
-	for (i = 0; i != count; i++) {
-		pal[i].r = _cur_palette[start + i].r;
-		pal[i].g = _cur_palette[start + i].g;
-		pal[i].b = _cur_palette[start + i].b;
-		pal[i].unused = 0;
-	}
-
-	SDL_CALL SDL_SetColors(_sdl_screen, pal, start, count);
-}
-
-static void InitPalette(void)
-{
-	UpdatePalette(0, 256);
-}
-
-static void CheckPaletteAnim(void)
-{
-	if (_pal_last_dirty != -1) {
-		UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
-		_pal_last_dirty = -1;
-	}
-}
-
-static void DrawSurfaceToScreen(void)
-{
-	int n = _num_dirty_rects;
-	if (n != 0) {
-		_num_dirty_rects = 0;
-		if (n > MAX_DIRTY_RECTS)
-			SDL_CALL SDL_UpdateRect(_sdl_screen, 0, 0, 0, 0);
-		else
-			SDL_CALL SDL_UpdateRects(_sdl_screen, n, _dirty_rects);
-	}
-}
-
-static const uint16 default_resolutions[][2] = {
-	{ 640,  480},
-	{ 800,  600},
-	{1024,  768},
-	{1152,  864},
-	{1280,  800},
-	{1280,  960},
-	{1280, 1024},
-	{1400, 1050},
-	{1600, 1200},
-	{1680, 1050},
-	{1920, 1200}
-};
-
-static void GetVideoModes(void)
-{
-	int i;
-	SDL_Rect **modes;
-
-	modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE + (_fullscreen ? SDL_FULLSCREEN : 0));
-
-	if (modes == NULL)
-		error("sdl: no modes available");
-
-	_all_modes = (modes == (void*)-1);
-
-	if (_all_modes) {
-		// all modes available, put some default ones here
-		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
-		_num_resolutions = lengthof(default_resolutions);
-	} else {
-		int n = 0;
-		for (i = 0; modes[i]; i++) {
-			int w = modes[i]->w;
-			int h = modes[i]->h;
-			if (IS_INT_INSIDE(w, 640, MAX_SCREEN_WIDTH + 1) &&
-					IS_INT_INSIDE(h, 480, MAX_SCREEN_HEIGHT + 1)) {
-				int j;
-				for (j = 0; j < n; j++) {
-					if (_resolutions[j][0] == w && _resolutions[j][1] == h) break;
-				}
-
-				if (j == n) {
-					_resolutions[j][0] = w;
-					_resolutions[j][1] = h;
-					if (++n == lengthof(_resolutions)) break;
-				}
-			}
-		}
-		_num_resolutions = n;
-		SortResolutions(_num_resolutions);
-	}
-}
-
-static void GetAvailableVideoMode(int *w, int *h)
-{
-	int i;
-	int best;
-	uint delta;
-
-	// all modes available?
-	if (_all_modes) return;
-
-	// is the wanted mode among the available modes?
-	for (i = 0; i != _num_resolutions; i++) {
-		if (*w == _resolutions[i][0] && *h == _resolutions[i][1]) return;
-	}
-
-	// use the closest possible resolution
-	best = 0;
-	delta = abs((_resolutions[0][0] - *w) * (_resolutions[0][1] - *h));
-	for (i = 1; i != _num_resolutions; ++i) {
-		uint newdelta = abs((_resolutions[i][0] - *w) * (_resolutions[i][1] - *h));
-		if (newdelta < delta) {
-			best = i;
-			delta = newdelta;
-		}
-	}
-	*w = _resolutions[best][0];
-	*h = _resolutions[best][1];
-}
-
-#ifndef ICON_DIR
-#define ICON_DIR "media"
-#endif
-
-#ifdef WIN32
-/* Let's redefine the LoadBMP macro with because we are dynamically
- * loading SDL and need to 'SDL_CALL' all functions */
-#undef SDL_LoadBMP
-#define SDL_LoadBMP(file)	SDL_LoadBMP_RW(SDL_CALL SDL_RWFromFile(file, "rb"), 1)
-#endif
-
-static bool CreateMainSurface(int w, int h)
-{
-	extern const char _openttd_revision[];
-	SDL_Surface *newscreen, *icon;
-	char caption[50];
-
-	GetAvailableVideoMode(&w, &h);
-
-	DEBUG(driver, 1, "SDL: using mode %dx%d", w, h);
-
-	/* Give the application an icon */
-	icon = SDL_CALL SDL_LoadBMP(ICON_DIR PATHSEP "openttd.32.bmp");
-	if (icon != NULL) {
-		/* Get the colourkey, which will be magenta */
-		uint32 rgbmap = SDL_CALL SDL_MapRGB(icon->format, 255, 0, 255);
-
-		SDL_CALL SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap);
-		SDL_CALL SDL_WM_SetIcon(icon, NULL);
-		SDL_CALL SDL_FreeSurface(icon);
-	}
-
-	// DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK
-	newscreen = SDL_CALL SDL_SetVideoMode(w, h, 8, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE));
-	if (newscreen == NULL)
-		return false;
-
-	_screen.width = newscreen->w;
-	_screen.height = newscreen->h;
-	_screen.pitch = newscreen->pitch;
-
-	_sdl_screen = newscreen;
-	InitPalette();
-
-	snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
-	SDL_CALL SDL_WM_SetCaption(caption, caption);
-	SDL_CALL SDL_ShowCursor(0);
-
-	GameSizeChanged();
-
-	return true;
-}
-
-typedef struct VkMapping {
-	uint16 vk_from;
-	byte vk_count;
-	byte map_to;
-} VkMapping;
-
-#define AS(x, z) {x, 0, z}
-#define AM(x, y, z, w) {x, y - x, z}
-
-static const VkMapping _vk_mapping[] = {
-	// Pageup stuff + up/down
-	AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),
-	AS(SDLK_UP,     WKC_UP),
-	AS(SDLK_DOWN,   WKC_DOWN),
-	AS(SDLK_LEFT,   WKC_LEFT),
-	AS(SDLK_RIGHT,  WKC_RIGHT),
-
-	AS(SDLK_HOME,   WKC_HOME),
-	AS(SDLK_END,    WKC_END),
-
-	AS(SDLK_INSERT, WKC_INSERT),
-	AS(SDLK_DELETE, WKC_DELETE),
-
-	// Map letters & digits
-	AM(SDLK_a, SDLK_z, 'A', 'Z'),
-	AM(SDLK_0, SDLK_9, '0', '9'),
-
-	AS(SDLK_ESCAPE,    WKC_ESC),
-	AS(SDLK_PAUSE,     WKC_PAUSE),
-	AS(SDLK_BACKSPACE, WKC_BACKSPACE),
-
-	AS(SDLK_SPACE,     WKC_SPACE),
-	AS(SDLK_RETURN,    WKC_RETURN),
-	AS(SDLK_TAB,       WKC_TAB),
-
-	// Function keys
-	AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12),
-
-	// Numeric part.
-	// What is the virtual keycode for numeric enter??
-	AM(SDLK_KP0, SDLK_KP9, WKC_NUM_0, WKC_NUM_9),
-	AS(SDLK_KP_DIVIDE,   WKC_NUM_DIV),
-	AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL),
-	AS(SDLK_KP_MINUS,    WKC_NUM_MINUS),
-	AS(SDLK_KP_PLUS,     WKC_NUM_PLUS),
-	AS(SDLK_KP_ENTER,    WKC_NUM_ENTER),
-	AS(SDLK_KP_PERIOD,   WKC_NUM_DECIMAL)
-};
-
-static uint32 ConvertSdlKeyIntoMy(SDL_keysym *sym)
-{
-	const VkMapping *map;
-	uint key = 0;
-
-	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
-		if ((uint)(sym->sym - map->vk_from) <= map->vk_count) {
-			key = sym->sym - map->vk_from + map->map_to;
-			break;
-		}
-	}
-
-	// check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards)
-#if defined(WIN32) || defined(__OS2__)
-	if (sym->scancode == 41) key = WKC_BACKQUOTE;
-#elif defined(__APPLE__)
-	if (sym->scancode == 10) key = WKC_BACKQUOTE;
-#elif defined(__MORPHOS__)
-	if (sym->scancode == 0)  key = WKC_BACKQUOTE;  // yes, that key is code '0' under MorphOS :)
-#elif defined(__BEOS__)
-	if (sym->scancode == 17) key = WKC_BACKQUOTE;
-#elif defined(__SVR4) && defined(__sun)
-	if (sym->scancode == 60) key = WKC_BACKQUOTE;
-	if (sym->scancode == 49) key = WKC_BACKSPACE;
-#elif defined(__sgi__)
-	if (sym->scancode == 22) key = WKC_BACKQUOTE;
-#else
-	if (sym->scancode == 49) key = WKC_BACKQUOTE;
-#endif
-
-	// META are the command keys on mac
-	if (sym->mod & KMOD_META)  key |= WKC_META;
-	if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT;
-	if (sym->mod & KMOD_CTRL)  key |= WKC_CTRL;
-	if (sym->mod & KMOD_ALT)   key |= WKC_ALT;
-	// these two lines really help porting hotkey combos. Uncomment to use -- Bjarni
-#if 0
-	DEBUG(driver, 0, "Scancode character pressed %u", sym->scancode);
-	DEBUG(driver, 0, "Unicode character pressed %u", sym->unicode);
-#endif
-	return (key << 16) + sym->unicode;
-}
-
-static int PollEvent(void)
-{
-	SDL_Event ev;
-
-	if (!SDL_CALL SDL_PollEvent(&ev)) return -2;
-
-	switch (ev.type) {
-		case SDL_MOUSEMOTION:
-			if (_cursor.fix_at) {
-				int dx = ev.motion.x - _cursor.pos.x;
-				int dy = ev.motion.y - _cursor.pos.y;
-				if (dx != 0 || dy != 0) {
-					_cursor.delta.x += dx;
-					_cursor.delta.y += dy;
-					SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y);
-				}
-			} else {
-				_cursor.delta.x = ev.motion.x - _cursor.pos.x;
-				_cursor.delta.y = ev.motion.y - _cursor.pos.y;
-				_cursor.pos.x = ev.motion.x;
-				_cursor.pos.y = ev.motion.y;
-				_cursor.dirty = true;
-			}
-			HandleMouseEvents();
-			break;
-
-		case SDL_MOUSEBUTTONDOWN:
-			if (_rightclick_emulate && SDL_CALL SDL_GetModState() & KMOD_CTRL) {
-				ev.button.button = SDL_BUTTON_RIGHT;
-			}
-
-			switch (ev.button.button) {
-				case SDL_BUTTON_LEFT:
-					_left_button_down = true;
-					break;
-
-				case SDL_BUTTON_RIGHT:
-					_right_button_down = true;
-					_right_button_clicked = true;
-					break;
-
-				case SDL_BUTTON_WHEELUP:   _cursor.wheel--; break;
-				case SDL_BUTTON_WHEELDOWN: _cursor.wheel++; break;
-
-				default: break;
-			}
-			HandleMouseEvents();
-			break;
-
-		case SDL_MOUSEBUTTONUP:
-			if (_rightclick_emulate) {
-				_right_button_down = false;
-				_left_button_down = false;
-				_left_button_clicked = false;
-			} else if (ev.button.button == SDL_BUTTON_LEFT) {
-				_left_button_down = false;
-				_left_button_clicked = false;
-			} else if (ev.button.button == SDL_BUTTON_RIGHT) {
-				_right_button_down = false;
-			}
-			HandleMouseEvents();
-			break;
-
-		case SDL_ACTIVEEVENT:
-			if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break;
-
-			if (ev.active.gain) { // mouse entered the window, enable cursor
-				_cursor.in_window = true;
-			} else {
-				UndrawMouseCursor(); // mouse left the window, undraw cursor
-				_cursor.in_window = false;
-			}
-			break;
-
-		case SDL_QUIT: HandleExitGameRequest(); break;
-
-		case SDL_KEYDOWN: /* Toggle full-screen on ALT + ENTER/F */
-			if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) &&
-					(ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
-				ToggleFullScreen(!_fullscreen);
-			} else {
-				HandleKeypress(ConvertSdlKeyIntoMy(&ev.key.keysym));
-			}
-			break;
-
-		case SDL_VIDEORESIZE: {
-			int w = clamp(ev.resize.w, 64, MAX_SCREEN_WIDTH);
-			int h = clamp(ev.resize.h, 64, MAX_SCREEN_HEIGHT);
-			ChangeResInGame(w, h);
-			break;
-		}
-	}
-	return -1;
-}
-
-static const char *SdlVideoStart(const char * const *parm)
-{
-	char buf[30];
-
-	const char *s = SdlOpen(SDL_INIT_VIDEO);
-	if (s != NULL) return s;
-
-	SDL_CALL SDL_VideoDriverName(buf, 30);
-	DEBUG(driver, 1, "SDL: using driver '%s'", buf);
-
-	GetVideoModes();
-	CreateMainSurface(_cur_resolution[0], _cur_resolution[1]);
-	MarkWholeScreenDirty();
-
-	SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
-	SDL_CALL SDL_EnableUNICODE(1);
-	return NULL;
-}
-
-static void SdlVideoStop(void)
-{
-	SdlClose(SDL_INIT_VIDEO);
-}
-
-static void SdlVideoMainLoop(void)
-{
-	uint32 cur_ticks = SDL_CALL SDL_GetTicks();
-	uint32 next_tick = cur_ticks + 30;
-	uint32 pal_tick = 0;
-	uint32 mod;
-	int numkeys;
-	Uint8 *keys;
-
-	for (;;) {
-		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
-		InteractiveRandom(); // randomness
-
-		while (PollEvent() == -1) {}
-		if (_exit_game) return;
-
-		mod = SDL_CALL SDL_GetModState();
-		keys = SDL_CALL SDL_GetKeyState(&numkeys);
-#if defined(_DEBUG)
-		if (_shift_pressed)
-#else
-		/* Speedup when pressing tab, except when using ALT+TAB
-		 * to switch to another application */
-		if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0)
-#endif
-		{
-			if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
-		} else if (_fast_forward & 2) {
-			_fast_forward = 0;
-		}
-
-		cur_ticks = SDL_CALL SDL_GetTicks();
-		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
-			next_tick = cur_ticks + 30;
-
-			_ctrl_pressed  = !!(mod & KMOD_CTRL);
-			_shift_pressed = !!(mod & KMOD_SHIFT);
-#ifdef _DEBUG
-			_dbg_screen_rect = !!(mod & KMOD_CAPS);
-#endif
-
-			// determine which directional keys are down
-			_dirkeys =
-				(keys[SDLK_LEFT]  ? 1 : 0) |
-				(keys[SDLK_UP]    ? 2 : 0) |
-				(keys[SDLK_RIGHT] ? 4 : 0) |
-				(keys[SDLK_DOWN]  ? 8 : 0);
-			GameLoop();
-
-			_screen.dst_ptr = _sdl_screen->pixels;
-			UpdateWindows();
-			if (++pal_tick > 4) {
-				CheckPaletteAnim();
-				pal_tick = 1;
-			}
-			DrawSurfaceToScreen();
-		} else {
-			SDL_CALL SDL_Delay(1);
-			_screen.dst_ptr = _sdl_screen->pixels;
-			DrawTextMessage();
-			DrawMouseCursor();
-			DrawSurfaceToScreen();
-		}
-	}
-}
-
-static bool SdlVideoChangeRes(int w, int h)
-{
-	return CreateMainSurface(w, h);
-}
-
-static void SdlVideoFullScreen(bool full_screen)
-{
-	_fullscreen = full_screen;
-	GetVideoModes(); // get the list of available video modes
-	if (_num_resolutions == 0 || !_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1])) {
-		// switching resolution failed, put back full_screen to original status
-		_fullscreen ^= true;
-	}
-}
-
-const HalVideoDriver _sdl_video_driver = {
-	SdlVideoStart,
-	SdlVideoStop,
-	SdlVideoMakeDirty,
-	SdlVideoMainLoop,
-	SdlVideoChangeRes,
-	SdlVideoFullScreen,
-};
-
-#endif
new file mode 100644
--- /dev/null
+++ b/src/video/sdl_v.cpp
@@ -0,0 +1,513 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+
+#ifdef WITH_SDL
+
+#include "../openttd.h"
+#include "../debug.h"
+#include "../functions.h"
+#include "../gfx.h"
+#include "../macros.h"
+#include "../sdl.h"
+#include "../window.h"
+#include "../network/network.h"
+#include "../variables.h"
+#include "sdl_v.h"
+#include <SDL.h>
+
+static SDL_Surface *_sdl_screen;
+static bool _all_modes;
+
+#define MAX_DIRTY_RECTS 100
+static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
+static int _num_dirty_rects;
+
+static void SdlVideoMakeDirty(int left, int top, int width, int height)
+{
+	if (_num_dirty_rects < MAX_DIRTY_RECTS) {
+		_dirty_rects[_num_dirty_rects].x = left;
+		_dirty_rects[_num_dirty_rects].y = top;
+		_dirty_rects[_num_dirty_rects].w = width;
+		_dirty_rects[_num_dirty_rects].h = height;
+	}
+	_num_dirty_rects++;
+}
+
+static void UpdatePalette(uint start, uint count)
+{
+	SDL_Color pal[256];
+	uint i;
+
+	for (i = 0; i != count; i++) {
+		pal[i].r = _cur_palette[start + i].r;
+		pal[i].g = _cur_palette[start + i].g;
+		pal[i].b = _cur_palette[start + i].b;
+		pal[i].unused = 0;
+	}
+
+	SDL_CALL SDL_SetColors(_sdl_screen, pal, start, count);
+}
+
+static void InitPalette(void)
+{
+	UpdatePalette(0, 256);
+}
+
+static void CheckPaletteAnim(void)
+{
+	if (_pal_last_dirty != -1) {
+		UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
+		_pal_last_dirty = -1;
+	}
+}
+
+static void DrawSurfaceToScreen(void)
+{
+	int n = _num_dirty_rects;
+	if (n != 0) {
+		_num_dirty_rects = 0;
+		if (n > MAX_DIRTY_RECTS)
+			SDL_CALL SDL_UpdateRect(_sdl_screen, 0, 0, 0, 0);
+		else
+			SDL_CALL SDL_UpdateRects(_sdl_screen, n, _dirty_rects);
+	}
+}
+
+static const uint16 default_resolutions[][2] = {
+	{ 640,  480},
+	{ 800,  600},
+	{1024,  768},
+	{1152,  864},
+	{1280,  800},
+	{1280,  960},
+	{1280, 1024},
+	{1400, 1050},
+	{1600, 1200},
+	{1680, 1050},
+	{1920, 1200}
+};
+
+static void GetVideoModes(void)
+{
+	int i;
+	SDL_Rect **modes;
+
+	modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE + (_fullscreen ? SDL_FULLSCREEN : 0));
+
+	if (modes == NULL)
+		error("sdl: no modes available");
+
+	_all_modes = (modes == (void*)-1);
+
+	if (_all_modes) {
+		// all modes available, put some default ones here
+		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
+		_num_resolutions = lengthof(default_resolutions);
+	} else {
+		int n = 0;
+		for (i = 0; modes[i]; i++) {
+			int w = modes[i]->w;
+			int h = modes[i]->h;
+			if (IS_INT_INSIDE(w, 640, MAX_SCREEN_WIDTH + 1) &&
+					IS_INT_INSIDE(h, 480, MAX_SCREEN_HEIGHT + 1)) {
+				int j;
+				for (j = 0; j < n; j++) {
+					if (_resolutions[j][0] == w && _resolutions[j][1] == h) break;
+				}
+
+				if (j == n) {
+					_resolutions[j][0] = w;
+					_resolutions[j][1] = h;
+					if (++n == lengthof(_resolutions)) break;
+				}
+			}
+		}
+		_num_resolutions = n;
+		SortResolutions(_num_resolutions);
+	}
+}
+
+static void GetAvailableVideoMode(int *w, int *h)
+{
+	int i;
+	int best;
+	uint delta;
+
+	// all modes available?
+	if (_all_modes) return;
+
+	// is the wanted mode among the available modes?
+	for (i = 0; i != _num_resolutions; i++) {
+		if (*w == _resolutions[i][0] && *h == _resolutions[i][1]) return;
+	}
+
+	// use the closest possible resolution
+	best = 0;
+	delta = abs((_resolutions[0][0] - *w) * (_resolutions[0][1] - *h));
+	for (i = 1; i != _num_resolutions; ++i) {
+		uint newdelta = abs((_resolutions[i][0] - *w) * (_resolutions[i][1] - *h));
+		if (newdelta < delta) {
+			best = i;
+			delta = newdelta;
+		}
+	}
+	*w = _resolutions[best][0];
+	*h = _resolutions[best][1];
+}
+
+#ifndef ICON_DIR
+#define ICON_DIR "media"
+#endif
+
+#ifdef WIN32
+/* Let's redefine the LoadBMP macro with because we are dynamically
+ * loading SDL and need to 'SDL_CALL' all functions */
+#undef SDL_LoadBMP
+#define SDL_LoadBMP(file)	SDL_LoadBMP_RW(SDL_CALL SDL_RWFromFile(file, "rb"), 1)
+#endif
+
+static bool CreateMainSurface(int w, int h)
+{
+	extern const char _openttd_revision[];
+	SDL_Surface *newscreen, *icon;
+	char caption[50];
+
+	GetAvailableVideoMode(&w, &h);
+
+	DEBUG(driver, 1, "SDL: using mode %dx%d", w, h);
+
+	/* Give the application an icon */
+	icon = SDL_CALL SDL_LoadBMP(ICON_DIR PATHSEP "openttd.32.bmp");
+	if (icon != NULL) {
+		/* Get the colourkey, which will be magenta */
+		uint32 rgbmap = SDL_CALL SDL_MapRGB(icon->format, 255, 0, 255);
+
+		SDL_CALL SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap);
+		SDL_CALL SDL_WM_SetIcon(icon, NULL);
+		SDL_CALL SDL_FreeSurface(icon);
+	}
+
+	// DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK
+	newscreen = SDL_CALL SDL_SetVideoMode(w, h, 8, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE));
+	if (newscreen == NULL)
+		return false;
+
+	_screen.width = newscreen->w;
+	_screen.height = newscreen->h;
+	_screen.pitch = newscreen->pitch;
+
+	_sdl_screen = newscreen;
+	InitPalette();
+
+	snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
+	SDL_CALL SDL_WM_SetCaption(caption, caption);
+	SDL_CALL SDL_ShowCursor(0);
+
+	GameSizeChanged();
+
+	return true;
+}
+
+typedef struct VkMapping {
+	uint16 vk_from;
+	byte vk_count;
+	byte map_to;
+} VkMapping;
+
+#define AS(x, z) {x, 0, z}
+#define AM(x, y, z, w) {x, y - x, z}
+
+static const VkMapping _vk_mapping[] = {
+	// Pageup stuff + up/down
+	AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),
+	AS(SDLK_UP,     WKC_UP),
+	AS(SDLK_DOWN,   WKC_DOWN),
+	AS(SDLK_LEFT,   WKC_LEFT),
+	AS(SDLK_RIGHT,  WKC_RIGHT),
+
+	AS(SDLK_HOME,   WKC_HOME),
+	AS(SDLK_END,    WKC_END),
+
+	AS(SDLK_INSERT, WKC_INSERT),
+	AS(SDLK_DELETE, WKC_DELETE),
+
+	// Map letters & digits
+	AM(SDLK_a, SDLK_z, 'A', 'Z'),
+	AM(SDLK_0, SDLK_9, '0', '9'),
+
+	AS(SDLK_ESCAPE,    WKC_ESC),
+	AS(SDLK_PAUSE,     WKC_PAUSE),
+	AS(SDLK_BACKSPACE, WKC_BACKSPACE),
+
+	AS(SDLK_SPACE,     WKC_SPACE),
+	AS(SDLK_RETURN,    WKC_RETURN),
+	AS(SDLK_TAB,       WKC_TAB),
+
+	// Function keys
+	AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12),
+
+	// Numeric part.
+	// What is the virtual keycode for numeric enter??
+	AM(SDLK_KP0, SDLK_KP9, WKC_NUM_0, WKC_NUM_9),
+	AS(SDLK_KP_DIVIDE,   WKC_NUM_DIV),
+	AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL),
+	AS(SDLK_KP_MINUS,    WKC_NUM_MINUS),
+	AS(SDLK_KP_PLUS,     WKC_NUM_PLUS),
+	AS(SDLK_KP_ENTER,    WKC_NUM_ENTER),
+	AS(SDLK_KP_PERIOD,   WKC_NUM_DECIMAL)
+};
+
+static uint32 ConvertSdlKeyIntoMy(SDL_keysym *sym)
+{
+	const VkMapping *map;
+	uint key = 0;
+
+	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
+		if ((uint)(sym->sym - map->vk_from) <= map->vk_count) {
+			key = sym->sym - map->vk_from + map->map_to;
+			break;
+		}
+	}
+
+	// check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards)
+#if defined(WIN32) || defined(__OS2__)
+	if (sym->scancode == 41) key = WKC_BACKQUOTE;
+#elif defined(__APPLE__)
+	if (sym->scancode == 10) key = WKC_BACKQUOTE;
+#elif defined(__MORPHOS__)
+	if (sym->scancode == 0)  key = WKC_BACKQUOTE;  // yes, that key is code '0' under MorphOS :)
+#elif defined(__BEOS__)
+	if (sym->scancode == 17) key = WKC_BACKQUOTE;
+#elif defined(__SVR4) && defined(__sun)
+	if (sym->scancode == 60) key = WKC_BACKQUOTE;
+	if (sym->scancode == 49) key = WKC_BACKSPACE;
+#elif defined(__sgi__)
+	if (sym->scancode == 22) key = WKC_BACKQUOTE;
+#else
+	if (sym->scancode == 49) key = WKC_BACKQUOTE;
+#endif
+
+	// META are the command keys on mac
+	if (sym->mod & KMOD_META)  key |= WKC_META;
+	if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT;
+	if (sym->mod & KMOD_CTRL)  key |= WKC_CTRL;
+	if (sym->mod & KMOD_ALT)   key |= WKC_ALT;
+	// these two lines really help porting hotkey combos. Uncomment to use -- Bjarni
+#if 0
+	DEBUG(driver, 0, "Scancode character pressed %u", sym->scancode);
+	DEBUG(driver, 0, "Unicode character pressed %u", sym->unicode);
+#endif
+	return (key << 16) + sym->unicode;
+}
+
+static int PollEvent(void)
+{
+	SDL_Event ev;
+
+	if (!SDL_CALL SDL_PollEvent(&ev)) return -2;
+
+	switch (ev.type) {
+		case SDL_MOUSEMOTION:
+			if (_cursor.fix_at) {
+				int dx = ev.motion.x - _cursor.pos.x;
+				int dy = ev.motion.y - _cursor.pos.y;
+				if (dx != 0 || dy != 0) {
+					_cursor.delta.x += dx;
+					_cursor.delta.y += dy;
+					SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y);
+				}
+			} else {
+				_cursor.delta.x = ev.motion.x - _cursor.pos.x;
+				_cursor.delta.y = ev.motion.y - _cursor.pos.y;
+				_cursor.pos.x = ev.motion.x;
+				_cursor.pos.y = ev.motion.y;
+				_cursor.dirty = true;
+			}
+			HandleMouseEvents();
+			break;
+
+		case SDL_MOUSEBUTTONDOWN:
+			if (_rightclick_emulate && SDL_CALL SDL_GetModState() & KMOD_CTRL) {
+				ev.button.button = SDL_BUTTON_RIGHT;
+			}
+
+			switch (ev.button.button) {
+				case SDL_BUTTON_LEFT:
+					_left_button_down = true;
+					break;
+
+				case SDL_BUTTON_RIGHT:
+					_right_button_down = true;
+					_right_button_clicked = true;
+					break;
+
+				case SDL_BUTTON_WHEELUP:   _cursor.wheel--; break;
+				case SDL_BUTTON_WHEELDOWN: _cursor.wheel++; break;
+
+				default: break;
+			}
+			HandleMouseEvents();
+			break;
+
+		case SDL_MOUSEBUTTONUP:
+			if (_rightclick_emulate) {
+				_right_button_down = false;
+				_left_button_down = false;
+				_left_button_clicked = false;
+			} else if (ev.button.button == SDL_BUTTON_LEFT) {
+				_left_button_down = false;
+				_left_button_clicked = false;
+			} else if (ev.button.button == SDL_BUTTON_RIGHT) {
+				_right_button_down = false;
+			}
+			HandleMouseEvents();
+			break;
+
+		case SDL_ACTIVEEVENT:
+			if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break;
+
+			if (ev.active.gain) { // mouse entered the window, enable cursor
+				_cursor.in_window = true;
+			} else {
+				UndrawMouseCursor(); // mouse left the window, undraw cursor
+				_cursor.in_window = false;
+			}
+			break;
+
+		case SDL_QUIT: HandleExitGameRequest(); break;
+
+		case SDL_KEYDOWN: /* Toggle full-screen on ALT + ENTER/F */
+			if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) &&
+					(ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
+				ToggleFullScreen(!_fullscreen);
+			} else {
+				HandleKeypress(ConvertSdlKeyIntoMy(&ev.key.keysym));
+			}
+			break;
+
+		case SDL_VIDEORESIZE: {
+			int w = clamp(ev.resize.w, 64, MAX_SCREEN_WIDTH);
+			int h = clamp(ev.resize.h, 64, MAX_SCREEN_HEIGHT);
+			ChangeResInGame(w, h);
+			break;
+		}
+	}
+	return -1;
+}
+
+static const char *SdlVideoStart(const char * const *parm)
+{
+	char buf[30];
+
+	const char *s = SdlOpen(SDL_INIT_VIDEO);
+	if (s != NULL) return s;
+
+	SDL_CALL SDL_VideoDriverName(buf, 30);
+	DEBUG(driver, 1, "SDL: using driver '%s'", buf);
+
+	GetVideoModes();
+	CreateMainSurface(_cur_resolution[0], _cur_resolution[1]);
+	MarkWholeScreenDirty();
+
+	SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+	SDL_CALL SDL_EnableUNICODE(1);
+	return NULL;
+}
+
+static void SdlVideoStop(void)
+{
+	SdlClose(SDL_INIT_VIDEO);
+}
+
+static void SdlVideoMainLoop(void)
+{
+	uint32 cur_ticks = SDL_CALL SDL_GetTicks();
+	uint32 next_tick = cur_ticks + 30;
+	uint32 pal_tick = 0;
+	uint32 mod;
+	int numkeys;
+	Uint8 *keys;
+
+	for (;;) {
+		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
+		InteractiveRandom(); // randomness
+
+		while (PollEvent() == -1) {}
+		if (_exit_game) return;
+
+		mod = SDL_CALL SDL_GetModState();
+		keys = SDL_CALL SDL_GetKeyState(&numkeys);
+#if defined(_DEBUG)
+		if (_shift_pressed)
+#else
+		/* Speedup when pressing tab, except when using ALT+TAB
+		 * to switch to another application */
+		if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0)
+#endif
+		{
+			if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
+		} else if (_fast_forward & 2) {
+			_fast_forward = 0;
+		}
+
+		cur_ticks = SDL_CALL SDL_GetTicks();
+		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
+			next_tick = cur_ticks + 30;
+
+			_ctrl_pressed  = !!(mod & KMOD_CTRL);
+			_shift_pressed = !!(mod & KMOD_SHIFT);
+#ifdef _DEBUG
+			_dbg_screen_rect = !!(mod & KMOD_CAPS);
+#endif
+
+			// determine which directional keys are down
+			_dirkeys =
+				(keys[SDLK_LEFT]  ? 1 : 0) |
+				(keys[SDLK_UP]    ? 2 : 0) |
+				(keys[SDLK_RIGHT] ? 4 : 0) |
+				(keys[SDLK_DOWN]  ? 8 : 0);
+			GameLoop();
+
+			_screen.dst_ptr = _sdl_screen->pixels;
+			UpdateWindows();
+			if (++pal_tick > 4) {
+				CheckPaletteAnim();
+				pal_tick = 1;
+			}
+			DrawSurfaceToScreen();
+		} else {
+			SDL_CALL SDL_Delay(1);
+			_screen.dst_ptr = _sdl_screen->pixels;
+			DrawTextMessage();
+			DrawMouseCursor();
+			DrawSurfaceToScreen();
+		}
+	}
+}
+
+static bool SdlVideoChangeRes(int w, int h)
+{
+	return CreateMainSurface(w, h);
+}
+
+static void SdlVideoFullScreen(bool full_screen)
+{
+	_fullscreen = full_screen;
+	GetVideoModes(); // get the list of available video modes
+	if (_num_resolutions == 0 || !_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1])) {
+		// switching resolution failed, put back full_screen to original status
+		_fullscreen ^= true;
+	}
+}
+
+const HalVideoDriver _sdl_video_driver = {
+	SdlVideoStart,
+	SdlVideoStop,
+	SdlVideoMakeDirty,
+	SdlVideoMainLoop,
+	SdlVideoChangeRes,
+	SdlVideoFullScreen,
+};
+
+#endif
deleted file mode 100644
--- a/src/video/win32_v.c
+++ /dev/null
@@ -1,876 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../functions.h"
-#include "../gfx.h"
-#include "../macros.h"
-#include "../network/network.h"
-#include "../variables.h"
-#include "../win32.h"
-#include "../window.h"
-#include "win32_v.h"
-#include <windows.h>
-#include <tchar.h>
-
-static struct {
-	HWND main_wnd;
-	HBITMAP dib_sect;
-	Pixel *bitmap_bits;
-	Pixel *buffer_bits;
-	Pixel *alloced_bits;
-	HPALETTE gdi_palette;
-	int width;
-	int height;
-	int width_org;
-	int height_org;
-	bool fullscreen;
-	bool double_size;
-	bool has_focus;
-	bool running;
-} _wnd;
-
-bool _force_full_redraw;
-bool _double_size;
-bool _window_maximize;
-uint _display_hz;
-uint _fullscreen_bpp;
-static uint16 _bck_resolution[2];
-
-static void MakePalette(void)
-{
-	LOGPALETTE *pal;
-	uint i;
-
-	pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY));
-
-	pal->palVersion = 0x300;
-	pal->palNumEntries = 256;
-
-	for (i = 0; i != 256; i++) {
-		pal->palPalEntry[i].peRed   = _cur_palette[i].r;
-		pal->palPalEntry[i].peGreen = _cur_palette[i].g;
-		pal->palPalEntry[i].peBlue  = _cur_palette[i].b;
-		pal->palPalEntry[i].peFlags = 0;
-
-	}
-	_wnd.gdi_palette = CreatePalette(pal);
-	if (_wnd.gdi_palette == NULL) error("CreatePalette failed!\n");
-}
-
-static void UpdatePalette(HDC dc, uint start, uint count)
-{
-	RGBQUAD rgb[256];
-	uint i;
-
-	for (i = 0; i != count; i++) {
-		rgb[i].rgbRed   = _cur_palette[start + i].r;
-		rgb[i].rgbGreen = _cur_palette[start + i].g;
-		rgb[i].rgbBlue  = _cur_palette[start + i].b;
-		rgb[i].rgbReserved = 0;
-	}
-
-	SetDIBColorTable(dc, start, count, rgb);
-}
-
-typedef struct {
-	byte vk_from;
-	byte vk_count;
-	byte map_to;
-} VkMapping;
-
-#define AS(x, z) {x, 0, z}
-#define AM(x, y, z, w) {x, y - x, z}
-
-static const VkMapping _vk_mapping[] = {
-	// Pageup stuff + up/down
-	AM(VK_PRIOR,VK_DOWN, WKC_PAGEUP, WKC_DOWN),
-	// Map letters & digits
-	AM('A','Z','A','Z'),
-	AM('0','9','0','9'),
-
-	AS(VK_ESCAPE,   WKC_ESC),
-	AS(VK_PAUSE,    WKC_PAUSE),
-	AS(VK_BACK,     WKC_BACKSPACE),
-	AM(VK_INSERT,   VK_DELETE, WKC_INSERT, WKC_DELETE),
-
-	AS(VK_SPACE,    WKC_SPACE),
-	AS(VK_RETURN,   WKC_RETURN),
-	AS(VK_TAB,      WKC_TAB),
-
-	// Function keys
-	AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
-
-	// Numeric part.
-	// What is the virtual keycode for numeric enter??
-	AM(VK_NUMPAD0, VK_NUMPAD9, WKC_NUM_0, WKC_NUM_9),
-	AS(VK_DIVIDE,   WKC_NUM_DIV),
-	AS(VK_MULTIPLY, WKC_NUM_MUL),
-	AS(VK_SUBTRACT, WKC_NUM_MINUS),
-	AS(VK_ADD,      WKC_NUM_PLUS),
-	AS(VK_DECIMAL,  WKC_NUM_DECIMAL)
-};
-
-static uint MapWindowsKey(uint sym)
-{
-	const VkMapping *map;
-	uint key = 0;
-
-	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
-		if ((uint)(sym - map->vk_from) <= map->vk_count) {
-			key = sym - map->vk_from + map->map_to;
-			break;
-		}
-	}
-
-	if (GetAsyncKeyState(VK_SHIFT)   < 0) key |= WKC_SHIFT;
-	if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
-	if (GetAsyncKeyState(VK_MENU)    < 0) key |= WKC_ALT;
-	return key;
-}
-
-static bool AllocateDibSection(int w, int h);
-
-static void ClientSizeChanged(int w, int h)
-{
-	if (_wnd.double_size) {
-		w /= 2;
-		h /= 2;
-	}
-
-	// allocate new dib section of the new size
-	if (AllocateDibSection(w, h)) {
-		// mark all palette colors dirty
-		_pal_first_dirty = 0;
-		_pal_last_dirty = 255;
-		GameSizeChanged();
-
-		// redraw screen
-		if (_wnd.running) {
-			_screen.dst_ptr = _wnd.buffer_bits;
-			UpdateWindows();
-		}
-	}
-}
-
-#ifdef _DEBUG
-// Keep this function here..
-// It allows you to redraw the screen from within the MSVC debugger
-int RedrawScreenDebug(void)
-{
-	HDC dc,dc2;
-	static int _fooctr;
-	HBITMAP old_bmp;
-	HPALETTE old_palette;
-
-	_screen.dst_ptr = _wnd.buffer_bits;
-	UpdateWindows();
-
-	dc = GetDC(_wnd.main_wnd);
-	dc2 = CreateCompatibleDC(dc);
-
-	old_bmp = SelectObject(dc2, _wnd.dib_sect);
-	old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
-	BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
-	SelectPalette(dc, old_palette, TRUE);
-	SelectObject(dc2, old_bmp);
-	DeleteDC(dc2);
-	ReleaseDC(_wnd.main_wnd, dc);
-
-	return _fooctr++;
-}
-#endif
-
-/* Windows 95 will not have a WM_MOUSELEAVE message, so define it if needed */
-#if !defined(WM_MOUSELEAVE)
-#define WM_MOUSELEAVE 0x02A3
-#endif
-#define TID_POLLMOUSE 1
-#define MOUSE_POLL_DELAY 75
-
-static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT event, DWORD time)
-{
-	RECT rc;
-	POINT pt;
-
-	/* Get the rectangle of our window and translate it to screen coordinates.
-	 * Compare this with the current screen coordinates of the mouse and if it
-	 * falls outside of the area or our window we have left the window. */
-	GetClientRect(hwnd, &rc);
-	MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)(LPRECT)&rc, 2);
-	GetCursorPos(&pt);
-
-	if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) {
-		KillTimer(hwnd, event);
-		PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
-	}
-}
-
-static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-	switch (msg) {
-		case WM_CREATE:
-			SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
-			break;
-
-		case WM_PAINT: {
-			PAINTSTRUCT ps;
-			HDC dc,dc2;
-			HBITMAP old_bmp;
-			HPALETTE old_palette;
-
-			BeginPaint(hwnd, &ps);
-			dc = ps.hdc;
-			dc2 = CreateCompatibleDC(dc);
-			old_bmp = SelectObject(dc2, _wnd.dib_sect);
-			old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
-
-			if (_pal_last_dirty != -1) {
-				UpdatePalette(dc2, _pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
-				_pal_last_dirty = -1;
-			}
-
-			BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
-			SelectPalette(dc, old_palette, TRUE);
-			SelectObject(dc2, old_bmp);
-			DeleteDC(dc2);
-			EndPaint(hwnd, &ps);
-			return 0;
-		}
-
-		case WM_PALETTECHANGED:
-			if ((HWND)wParam == hwnd) return 0;
-			/* FALLTHROUGH */
-
-		case WM_QUERYNEWPALETTE: {
-			HDC hDC = GetWindowDC(hwnd);
-			HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
-			UINT nChanged = RealizePalette(hDC);
-
-			SelectPalette(hDC, hOldPalette, TRUE);
-			ReleaseDC(hwnd, hDC);
-			if (nChanged) InvalidateRect(hwnd, NULL, FALSE);
-			return 0;
-		}
-
-		case WM_CLOSE:
-			HandleExitGameRequest();
-			return 0;
-
-		case WM_DESTROY:
-			if (_window_maximize) {
-				_cur_resolution[0] = _bck_resolution[0];
-				_cur_resolution[1] = _bck_resolution[1];
-			}
-			return 0;
-
-		case WM_LBUTTONDOWN:
-			SetCapture(hwnd);
-			_left_button_down = true;
-			HandleMouseEvents();
-			return 0;
-
-		case WM_LBUTTONUP:
-			ReleaseCapture();
-			_left_button_down = false;
-			_left_button_clicked = false;
-			HandleMouseEvents();
-			return 0;
-
-		case WM_RBUTTONDOWN:
-			SetCapture(hwnd);
-			_right_button_down = true;
-			_right_button_clicked = true;
-			HandleMouseEvents();
-			return 0;
-
-		case WM_RBUTTONUP:
-			ReleaseCapture();
-			_right_button_down = false;
-			HandleMouseEvents();
-			return 0;
-
-		case WM_MOUSELEAVE:
-			UndrawMouseCursor();
-			_cursor.in_window = false;
-
-			if (!_left_button_down && !_right_button_down) MyShowCursor(true);
-			HandleMouseEvents();
-			return 0;
-
-		case WM_MOUSEMOVE: {
-			int x = (int16)LOWORD(lParam);
-			int y = (int16)HIWORD(lParam);
-			POINT pt;
-
-			/* If the mouse was not in the window and it has moved it means it has
-			 * come into the window, so start drawing the mouse. Also start
-			 * tracking the mouse for exiting the window */
-			if (!_cursor.in_window) {
-				_cursor.in_window = true;
-				SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
-
-				DrawMouseCursor();
-			}
-
-			if (_wnd.double_size) {
-				x /= 2;
-				y /= 2;
-			}
-
-			if (_cursor.fix_at) {
-				int dx = x - _cursor.pos.x;
-				int dy = y - _cursor.pos.y;
-				if (dx != 0 || dy != 0) {
-					_cursor.delta.x += dx;
-					_cursor.delta.y += dy;
-
-					pt.x = _cursor.pos.x;
-					pt.y = _cursor.pos.y;
-
-					if (_wnd.double_size) {
-						pt.x *= 2;
-						pt.y *= 2;
-					}
-					ClientToScreen(hwnd, &pt);
-					SetCursorPos(pt.x, pt.y);
-				}
-			} else {
-				_cursor.delta.x += x - _cursor.pos.x;
-				_cursor.delta.y += y - _cursor.pos.y;
-				_cursor.pos.x = x;
-				_cursor.pos.y = y;
-				_cursor.dirty = true;
-			}
-			MyShowCursor(false);
-			HandleMouseEvents();
-			return 0;
-		}
-
-		case WM_KEYDOWN: {
-			// this is the rewritten ascii input function
-			// it disables windows deadkey handling --> more linux like :D
-			wchar_t w = 0;
-			byte ks[256];
-			uint scancode;
-			uint32 pressed_key;
-
-			GetKeyboardState(ks);
-			if (ToUnicode(wParam, 0, ks, &w, 1, 0) != 1) {
-				/* On win9x ToUnicode always fails, so fall back to ToAscii */
-				if (ToAscii(wParam, 0, ks, &w, 0) != 1) w = 0; // no translation was possible
-			}
-
-			pressed_key = w | MapWindowsKey(wParam) << 16;
-
-			scancode = GB(lParam, 16, 8);
-			if (scancode == 41) pressed_key = w | WKC_BACKQUOTE << 16;
-
-			if (GB(pressed_key, 16, 16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) {
-				_double_size ^= 1;
-				_wnd.double_size = _double_size;
-				ClientSizeChanged(_wnd.width, _wnd.height);
-				MarkWholeScreenDirty();
-			}
-			HandleKeypress(pressed_key);
-			break;
-		}
-
-		case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
-			switch (wParam) {
-				case VK_RETURN:
-				case 'F': /* Full Screen on ALT + ENTER/F */
-					ToggleFullScreen(!_wnd.fullscreen);
-					return 0;
-
-				case VK_MENU: /* Just ALT */
-					return 0; // do nothing
-
-				case VK_F10: /* F10, ignore activation of menu */
-					HandleKeypress(MapWindowsKey(wParam) << 16);
-					return 0;
-
-				default: /* ALT in combination with something else */
-					HandleKeypress(MapWindowsKey(wParam) << 16);
-					break;
-			}
-			break;
-
-		case WM_SIZE:
-			if (wParam != SIZE_MINIMIZED) {
-				/* Set maximized flag when we maximize (obviously), but also when we
-				 * switched to fullscreen from a maximized state */
-				_window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
-				if (_window_maximize) {
-					_bck_resolution[0] = _cur_resolution[0];
-					_bck_resolution[1] = _cur_resolution[1];
-				}
-				ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
-			}
-			return 0;
-
-		case WM_SIZING: {
-			RECT* r = (RECT*)lParam;
-			RECT r2;
-			int w, h;
-
-			SetRect(&r2, 0, 0, 0, 0);
-			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
-
-			w = r->right - r->left - (r2.right - r2.left);
-			h = r->bottom - r->top - (r2.bottom - r2.top);
-			if (_wnd.double_size) {
-				w /= 2;
-				h /= 2;
-			}
-			w = clamp(w, 64, MAX_SCREEN_WIDTH);
-			h = clamp(h, 64, MAX_SCREEN_HEIGHT);
-			if (_wnd.double_size) {
-				w *= 2;
-				h *= 2;
-			}
-			SetRect(&r2, 0, 0, w, h);
-
-			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
-			w = r2.right - r2.left;
-			h = r2.bottom - r2.top;
-
-			switch (wParam) {
-				case WMSZ_BOTTOM:
-					r->bottom = r->top + h;
-					break;
-
-				case WMSZ_BOTTOMLEFT:
-					r->bottom = r->top + h;
-					r->left = r->right - w;
-					break;
-
-				case WMSZ_BOTTOMRIGHT:
-					r->bottom = r->top + h;
-					r->right = r->left + w;
-					break;
-
-				case WMSZ_LEFT:
-					r->left = r->right - w;
-					break;
-
-				case WMSZ_RIGHT:
-					r->right = r->left + w;
-					break;
-
-				case WMSZ_TOP:
-					r->top = r->bottom - h;
-					break;
-
-				case WMSZ_TOPLEFT:
-					r->top = r->bottom - h;
-					r->left = r->right - w;
-					break;
-
-				case WMSZ_TOPRIGHT:
-					r->top = r->bottom - h;
-					r->right = r->left + w;
-					break;
-			}
-			return TRUE;
-		}
-
-// needed for wheel
-#if !defined(WM_MOUSEWHEEL)
-# define WM_MOUSEWHEEL 0x020A
-#endif  //WM_MOUSEWHEEL
-#if !defined(GET_WHEEL_DELTA_WPARAM)
-# define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
-#endif  //GET_WHEEL_DELTA_WPARAM
-
-		case WM_MOUSEWHEEL: {
-			int delta = GET_WHEEL_DELTA_WPARAM(wParam);
-
-			if (delta < 0) {
-				_cursor.wheel++;
-			} else if (delta > 0) {
-				_cursor.wheel--;
-			}
-			HandleMouseEvents();
-			return 0;
-		}
-
-		case WM_ACTIVATEAPP:
-			_wnd.has_focus = (bool)wParam;
-			break;
-	}
-	return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-static void RegisterWndClass(void)
-{
-	static bool registered = false;
-
-	if (!registered) {
-		HINSTANCE hinst = GetModuleHandle(NULL);
-		WNDCLASS wnd = {
-			0,
-			WndProcGdi,
-			0,
-			0,
-			hinst,
-			LoadIcon(hinst, MAKEINTRESOURCE(100)),
-			LoadCursor(NULL, IDC_ARROW),
-			0,
-			0,
-			_T("OTTD")
-		};
-
-		registered = true;
-		if (!RegisterClass(&wnd)) error("RegisterClass failed");
-	}
-}
-
-static void MakeWindow(bool full_screen)
-{
-	_fullscreen = full_screen;
-
-	_wnd.double_size = _double_size && !full_screen;
-
-	// recreate window?
-	if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
-		DestroyWindow(_wnd.main_wnd);
-		_wnd.main_wnd = 0;
-	}
-
-	if (full_screen) {
-		DEVMODE settings;
-
-		memset(&settings, 0, sizeof(settings));
-		settings.dmSize = sizeof(settings);
-		settings.dmFields =
-			(_fullscreen_bpp != 0 ? DM_BITSPERPEL : 0) |
-			DM_PELSWIDTH |
-			DM_PELSHEIGHT |
-			(_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
-		settings.dmBitsPerPel = _fullscreen_bpp;
-		settings.dmPelsWidth  = _wnd.width_org;
-		settings.dmPelsHeight = _wnd.height_org;
-		settings.dmDisplayFrequency = _display_hz;
-
-		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
-			MakeWindow(false);
-			return;
-		}
-	} else if (_wnd.fullscreen) {
-		// restore display?
-		ChangeDisplaySettings(NULL, 0);
-	}
-
-	{
-		RECT r;
-		DWORD style, showstyle;
-		int x, y, w, h;
-
-		showstyle = SW_SHOWNORMAL;
-		_wnd.fullscreen = full_screen;
-		if (_wnd.fullscreen) {
-			style = WS_POPUP;
-			SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
-		} else {
-			style = WS_OVERLAPPEDWINDOW;
-			/* On window creation, check if we were in maximize mode before */
-			if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
-			SetRect(&r, 0, 0, _wnd.width, _wnd.height);
-		}
-
-		AdjustWindowRect(&r, style, FALSE);
-		w = r.right - r.left;
-		h = r.bottom - r.top;
-		x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
-		y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
-
-		if (_wnd.main_wnd) {
-			ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); // remove maximize-flag
-			SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
-		} else {
-			extern const char _openttd_revision[];
-			TCHAR Windowtitle[50];
-
-			_sntprintf(Windowtitle, sizeof(Windowtitle), _T("OpenTTD %s"), MB_TO_WIDE(_openttd_revision));
-
-			_wnd.main_wnd = CreateWindow(_T("OTTD"), Windowtitle, style, x, y, w, h, 0, 0, GetModuleHandle(NULL), 0);
-			if (_wnd.main_wnd == NULL) error("CreateWindow failed");
-			ShowWindow(_wnd.main_wnd, showstyle);
-		}
-	}
-	GameSizeChanged(); // invalidate all windows, force redraw
-}
-
-static bool AllocateDibSection(int w, int h)
-{
-	BITMAPINFO *bi;
-	HDC dc;
-
-	w = clamp(w, 64, MAX_SCREEN_WIDTH);
-	h = clamp(h, 64, MAX_SCREEN_HEIGHT);
-
-	if (w == _screen.width && h == _screen.height)
-		return false;
-
-	_screen.width = w;
-	_screen.pitch = ALIGN(w, 4);
-	_screen.height = h;
-
-	if (_wnd.alloced_bits) {
-		free(_wnd.alloced_bits);
-		_wnd.alloced_bits = NULL;
-	}
-
-	bi = alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
-	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
-	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-
-	if (_wnd.double_size) {
-		w = ALIGN(w, 4);
-		_wnd.alloced_bits = _wnd.buffer_bits = malloc(w * h);
-		w *= 2;
-		h *= 2;
-	}
-
-	bi->bmiHeader.biWidth = _wnd.width = w;
-	bi->bmiHeader.biHeight = -(_wnd.height = h);
-
-	bi->bmiHeader.biPlanes = 1;
-	bi->bmiHeader.biBitCount = 8;
-	bi->bmiHeader.biCompression = BI_RGB;
-
-	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
-
-	dc = GetDC(0);
-	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.bitmap_bits, NULL, 0);
-	if (_wnd.dib_sect == NULL) error("CreateDIBSection failed");
-	ReleaseDC(0, dc);
-
-	if (!_wnd.double_size) _wnd.buffer_bits = _wnd.bitmap_bits;
-
-	return true;
-}
-
-static const uint16 default_resolutions[][2] = {
-	{  640,  480 },
-	{  800,  600 },
-	{ 1024,  768 },
-	{ 1152,  864 },
-	{ 1280,  800 },
-	{ 1280,  960 },
-	{ 1280, 1024 },
-	{ 1400, 1050 },
-	{ 1600, 1200 },
-	{ 1680, 1050 },
-	{ 1920, 1200 }
-};
-
-static void FindResolutions(void)
-{
-	uint n = 0;
-	uint i;
-	DEVMODEA dm;
-
-	/* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95
-	 * Doesn't really matter since we don't pass a string anyways, but still
-	 * a letdown */
-	for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) {
-		if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
-				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) {
-			uint j;
-
-			for (j = 0; j < n; j++) {
-				if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break;
-			}
-
-			/* In the previous loop we have checked already existing/added resolutions if
-			 * they are the same as the new ones. If this is not the case (j == n); we have
-			 * looped all and found none, add the new one to the list. If we have reached the
-			 * maximum amount of resolutions, then quit querying the display */
-			if (j == n) {
-				_resolutions[j][0] = dm.dmPelsWidth;
-				_resolutions[j][1] = dm.dmPelsHeight;
-				if (++n == lengthof(_resolutions)) break;
-			}
-		}
-	}
-
-	/* We have found no resolutions, show the default list */
-	if (n == 0) {
-		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
-		n = lengthof(default_resolutions);
-	}
-
-	_num_resolutions = n;
-	SortResolutions(_num_resolutions);
-}
-
-
-static const char *Win32GdiStart(const char * const *parm)
-{
-	memset(&_wnd, 0, sizeof(_wnd));
-
-	RegisterWndClass();
-
-	MakePalette();
-
-	FindResolutions();
-
-	// fullscreen uses those
-	_wnd.width_org = _cur_resolution[0];
-	_wnd.height_org = _cur_resolution[1];
-
-	AllocateDibSection(_cur_resolution[0], _cur_resolution[1]);
-	MarkWholeScreenDirty();
-
-	MakeWindow(_fullscreen);
-
-	return NULL;
-}
-
-static void Win32GdiStop(void)
-{
-	DeleteObject(_wnd.gdi_palette);
-	DeleteObject(_wnd.dib_sect);
-	DestroyWindow(_wnd.main_wnd);
-
-	if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0);
-	if (_double_size) {
-		_cur_resolution[0] *= 2;
-		_cur_resolution[1] *= 2;
-	}
-
-	MyShowCursor(true);
-}
-
-// simple upscaler by 2
-static void filter(int left, int top, int width, int height)
-{
-	uint p = _screen.pitch;
-	const Pixel *s = _wnd.buffer_bits + top * p + left;
-	Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2;
-
-	for (; height > 0; height--) {
-		int i;
-
-		for (i = 0; i != width; i++) {
-			d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i];
-		}
-		s += p;
-		d += p * 4;
-	}
-}
-
-static void Win32GdiMakeDirty(int left, int top, int width, int height)
-{
-	RECT r = { left, top, left + width, top + height };
-
-	if (_wnd.double_size) {
-		filter(left, top, width, height);
-		r.left *= 2;
-		r.top *= 2;
-		r.right *= 2;
-		r.bottom *= 2;
-	}
-	InvalidateRect(_wnd.main_wnd, &r, FALSE);
-}
-
-static void CheckPaletteAnim(void)
-{
-	if (_pal_last_dirty == -1)
-		return;
-	InvalidateRect(_wnd.main_wnd, NULL, FALSE);
-}
-
-static void Win32GdiMainLoop(void)
-{
-	MSG mesg;
-	uint32 cur_ticks = GetTickCount();
-	uint32 next_tick = cur_ticks + 30;
-
-	_wnd.running = true;
-
-	for (;;) {
-		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
-
-		while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) {
-			InteractiveRandom(); // randomness
-			DispatchMessage(&mesg);
-		}
-		if (_exit_game) return;
-
-#if defined(_DEBUG)
-		if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
-#else
-		/* Speed up using TAB, but disable for ALT+TAB of course */
-		if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 &&
-#endif
-			  !_networking && _game_mode != GM_MENU) {
-			_fast_forward |= 2;
-		} else if (_fast_forward & 2) {
-			_fast_forward = 0;
-		}
-
-		cur_ticks = GetTickCount();
-		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
-			next_tick = cur_ticks + 30;
-			_ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
-			_shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0;
-#ifdef _DEBUG
-			_dbg_screen_rect = _wnd.has_focus && GetAsyncKeyState(VK_CAPITAL)<0;
-#endif
-
-			// determine which directional keys are down
-			if (_wnd.has_focus) {
-				_dirkeys =
-					(GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
-					(GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
-					(GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
-					(GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
-			} else {
-				_dirkeys = 0;
-			}
-
-			GameLoop();
-			_cursor.delta.x = _cursor.delta.y = 0;
-
-			if (_force_full_redraw) MarkWholeScreenDirty();
-
-			GdiFlush();
-			_screen.dst_ptr = _wnd.buffer_bits;
-			UpdateWindows();
-			CheckPaletteAnim();
-		} else {
-			Sleep(1);
-			GdiFlush();
-			_screen.dst_ptr = _wnd.buffer_bits;
-			DrawTextMessage();
-			DrawMouseCursor();
-		}
-	}
-}
-
-static bool Win32GdiChangeRes(int w, int h)
-{
-	_wnd.width = _wnd.width_org = w;
-	_wnd.height = _wnd.height_org = h;
-
-	MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
-
-	return true;
-}
-
-static void Win32GdiFullScreen(bool full_screen)
-{
-	MakeWindow(full_screen);
-}
-
-const HalVideoDriver _win32_video_driver = {
-	Win32GdiStart,
-	Win32GdiStop,
-	Win32GdiMakeDirty,
-	Win32GdiMainLoop,
-	Win32GdiChangeRes,
-	Win32GdiFullScreen,
-};
new file mode 100644
--- /dev/null
+++ b/src/video/win32_v.cpp
@@ -0,0 +1,876 @@
+/* $Id$ */
+
+#include "../stdafx.h"
+#include "../openttd.h"
+#include "../functions.h"
+#include "../gfx.h"
+#include "../macros.h"
+#include "../network/network.h"
+#include "../variables.h"
+#include "../win32.h"
+#include "../window.h"
+#include "win32_v.h"
+#include <windows.h>
+#include <tchar.h>
+
+static struct {
+	HWND main_wnd;
+	HBITMAP dib_sect;
+	Pixel *bitmap_bits;
+	Pixel *buffer_bits;
+	Pixel *alloced_bits;
+	HPALETTE gdi_palette;
+	int width;
+	int height;
+	int width_org;
+	int height_org;
+	bool fullscreen;
+	bool double_size;
+	bool has_focus;
+	bool running;
+} _wnd;
+
+bool _force_full_redraw;
+bool _double_size;
+bool _window_maximize;
+uint _display_hz;
+uint _fullscreen_bpp;
+static uint16 _bck_resolution[2];
+
+static void MakePalette(void)
+{
+	LOGPALETTE *pal;
+	uint i;
+
+	pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY));
+
+	pal->palVersion = 0x300;
+	pal->palNumEntries = 256;
+
+	for (i = 0; i != 256; i++) {
+		pal->palPalEntry[i].peRed   = _cur_palette[i].r;
+		pal->palPalEntry[i].peGreen = _cur_palette[i].g;
+		pal->palPalEntry[i].peBlue  = _cur_palette[i].b;
+		pal->palPalEntry[i].peFlags = 0;
+
+	}
+	_wnd.gdi_palette = CreatePalette(pal);
+	if (_wnd.gdi_palette == NULL) error("CreatePalette failed!\n");
+}
+
+static void UpdatePalette(HDC dc, uint start, uint count)
+{
+	RGBQUAD rgb[256];
+	uint i;
+
+	for (i = 0; i != count; i++) {
+		rgb[i].rgbRed   = _cur_palette[start + i].r;
+		rgb[i].rgbGreen = _cur_palette[start + i].g;
+		rgb[i].rgbBlue  = _cur_palette[start + i].b;
+		rgb[i].rgbReserved = 0;
+	}
+
+	SetDIBColorTable(dc, start, count, rgb);
+}
+
+typedef struct {
+	byte vk_from;
+	byte vk_count;
+	byte map_to;
+} VkMapping;
+
+#define AS(x, z) {x, 0, z}
+#define AM(x, y, z, w) {x, y - x, z}
+
+static const VkMapping _vk_mapping[] = {
+	// Pageup stuff + up/down
+	AM(VK_PRIOR,VK_DOWN, WKC_PAGEUP, WKC_DOWN),
+	// Map letters & digits
+	AM('A','Z','A','Z'),
+	AM('0','9','0','9'),
+
+	AS(VK_ESCAPE,   WKC_ESC),
+	AS(VK_PAUSE,    WKC_PAUSE),
+	AS(VK_BACK,     WKC_BACKSPACE),
+	AM(VK_INSERT,   VK_DELETE, WKC_INSERT, WKC_DELETE),
+
+	AS(VK_SPACE,    WKC_SPACE),
+	AS(VK_RETURN,   WKC_RETURN),
+	AS(VK_TAB,      WKC_TAB),
+
+	// Function keys
+	AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
+
+	// Numeric part.
+	// What is the virtual keycode for numeric enter??
+	AM(VK_NUMPAD0, VK_NUMPAD9, WKC_NUM_0, WKC_NUM_9),
+	AS(VK_DIVIDE,   WKC_NUM_DIV),
+	AS(VK_MULTIPLY, WKC_NUM_MUL),
+	AS(VK_SUBTRACT, WKC_NUM_MINUS),
+	AS(VK_ADD,      WKC_NUM_PLUS),
+	AS(VK_DECIMAL,  WKC_NUM_DECIMAL)
+};
+
+static uint MapWindowsKey(uint sym)
+{
+	const VkMapping *map;
+	uint key = 0;
+
+	for (map = _vk_mapping; map != endof(_vk_mapping); ++map) {
+		if ((uint)(sym - map->vk_from) <= map->vk_count) {
+			key = sym - map->vk_from + map->map_to;
+			break;
+		}
+	}
+
+	if (GetAsyncKeyState(VK_SHIFT)   < 0) key |= WKC_SHIFT;
+	if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
+	if (GetAsyncKeyState(VK_MENU)    < 0) key |= WKC_ALT;
+	return key;
+}
+
+static bool AllocateDibSection(int w, int h);
+
+static void ClientSizeChanged(int w, int h)
+{
+	if (_wnd.double_size) {
+		w /= 2;
+		h /= 2;
+	}
+
+	// allocate new dib section of the new size
+	if (AllocateDibSection(w, h)) {
+		// mark all palette colors dirty
+		_pal_first_dirty = 0;
+		_pal_last_dirty = 255;
+		GameSizeChanged();
+
+		// redraw screen
+		if (_wnd.running) {
+			_screen.dst_ptr = _wnd.buffer_bits;
+			UpdateWindows();
+		}
+	}
+}
+
+#ifdef _DEBUG
+// Keep this function here..
+// It allows you to redraw the screen from within the MSVC debugger
+int RedrawScreenDebug(void)
+{
+	HDC dc,dc2;
+	static int _fooctr;
+	HBITMAP old_bmp;
+	HPALETTE old_palette;
+
+	_screen.dst_ptr = _wnd.buffer_bits;
+	UpdateWindows();
+
+	dc = GetDC(_wnd.main_wnd);
+	dc2 = CreateCompatibleDC(dc);
+
+	old_bmp = SelectObject(dc2, _wnd.dib_sect);
+	old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
+	BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
+	SelectPalette(dc, old_palette, TRUE);
+	SelectObject(dc2, old_bmp);
+	DeleteDC(dc2);
+	ReleaseDC(_wnd.main_wnd, dc);
+
+	return _fooctr++;
+}
+#endif
+
+/* Windows 95 will not have a WM_MOUSELEAVE message, so define it if needed */
+#if !defined(WM_MOUSELEAVE)
+#define WM_MOUSELEAVE 0x02A3
+#endif
+#define TID_POLLMOUSE 1
+#define MOUSE_POLL_DELAY 75
+
+static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT event, DWORD time)
+{
+	RECT rc;
+	POINT pt;
+
+	/* Get the rectangle of our window and translate it to screen coordinates.
+	 * Compare this with the current screen coordinates of the mouse and if it
+	 * falls outside of the area or our window we have left the window. */
+	GetClientRect(hwnd, &rc);
+	MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)(LPRECT)&rc, 2);
+	GetCursorPos(&pt);
+
+	if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) {
+		KillTimer(hwnd, event);
+		PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
+	}
+}
+
+static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	switch (msg) {
+		case WM_CREATE:
+			SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
+			break;
+
+		case WM_PAINT: {
+			PAINTSTRUCT ps;
+			HDC dc,dc2;
+			HBITMAP old_bmp;
+			HPALETTE old_palette;
+
+			BeginPaint(hwnd, &ps);
+			dc = ps.hdc;
+			dc2 = CreateCompatibleDC(dc);
+			old_bmp = SelectObject(dc2, _wnd.dib_sect);
+			old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
+
+			if (_pal_last_dirty != -1) {
+				UpdatePalette(dc2, _pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1);
+				_pal_last_dirty = -1;
+			}
+
+			BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
+			SelectPalette(dc, old_palette, TRUE);
+			SelectObject(dc2, old_bmp);
+			DeleteDC(dc2);
+			EndPaint(hwnd, &ps);
+			return 0;
+		}
+
+		case WM_PALETTECHANGED:
+			if ((HWND)wParam == hwnd) return 0;
+			/* FALLTHROUGH */
+
+		case WM_QUERYNEWPALETTE: {
+			HDC hDC = GetWindowDC(hwnd);
+			HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
+			UINT nChanged = RealizePalette(hDC);
+
+			SelectPalette(hDC, hOldPalette, TRUE);
+			ReleaseDC(hwnd, hDC);
+			if (nChanged) InvalidateRect(hwnd, NULL, FALSE);
+			return 0;
+		}
+
+		case WM_CLOSE:
+			HandleExitGameRequest();
+			return 0;
+
+		case WM_DESTROY:
+			if (_window_maximize) {
+				_cur_resolution[0] = _bck_resolution[0];
+				_cur_resolution[1] = _bck_resolution[1];
+			}
+			return 0;
+
+		case WM_LBUTTONDOWN:
+			SetCapture(hwnd);
+			_left_button_down = true;
+			HandleMouseEvents();
+			return 0;
+
+		case WM_LBUTTONUP:
+			ReleaseCapture();
+			_left_button_down = false;
+			_left_button_clicked = false;
+			HandleMouseEvents();
+			return 0;
+
+		case WM_RBUTTONDOWN:
+			SetCapture(hwnd);
+			_right_button_down = true;
+			_right_button_clicked = true;
+			HandleMouseEvents();
+			return 0;
+
+		case WM_RBUTTONUP:
+			ReleaseCapture();
+			_right_button_down = false;
+			HandleMouseEvents();
+			return 0;
+
+		case WM_MOUSELEAVE:
+			UndrawMouseCursor();
+			_cursor.in_window = false;
+
+			if (!_left_button_down && !_right_button_down) MyShowCursor(true);
+			HandleMouseEvents();
+			return 0;
+
+		case WM_MOUSEMOVE: {
+			int x = (int16)LOWORD(lParam);
+			int y = (int16)HIWORD(lParam);
+			POINT pt;
+
+			/* If the mouse was not in the window and it has moved it means it has
+			 * come into the window, so start drawing the mouse. Also start
+			 * tracking the mouse for exiting the window */
+			if (!_cursor.in_window) {
+				_cursor.in_window = true;
+				SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
+
+				DrawMouseCursor();
+			}
+
+			if (_wnd.double_size) {
+				x /= 2;
+				y /= 2;
+			}
+
+			if (_cursor.fix_at) {
+				int dx = x - _cursor.pos.x;
+				int dy = y - _cursor.pos.y;
+				if (dx != 0 || dy != 0) {
+					_cursor.delta.x += dx;
+					_cursor.delta.y += dy;
+
+					pt.x = _cursor.pos.x;
+					pt.y = _cursor.pos.y;
+
+					if (_wnd.double_size) {
+						pt.x *= 2;
+						pt.y *= 2;
+					}
+					ClientToScreen(hwnd, &pt);
+					SetCursorPos(pt.x, pt.y);
+				}
+			} else {
+				_cursor.delta.x += x - _cursor.pos.x;
+				_cursor.delta.y += y - _cursor.pos.y;
+				_cursor.pos.x = x;
+				_cursor.pos.y = y;
+				_cursor.dirty = true;
+			}
+			MyShowCursor(false);
+			HandleMouseEvents();
+			return 0;
+		}
+
+		case WM_KEYDOWN: {
+			// this is the rewritten ascii input function
+			// it disables windows deadkey handling --> more linux like :D
+			wchar_t w = 0;
+			byte ks[256];
+			uint scancode;
+			uint32 pressed_key;
+
+			GetKeyboardState(ks);
+			if (ToUnicode(wParam, 0, ks, &w, 1, 0) != 1) {
+				/* On win9x ToUnicode always fails, so fall back to ToAscii */
+				if (ToAscii(wParam, 0, ks, &w, 0) != 1) w = 0; // no translation was possible
+			}
+
+			pressed_key = w | MapWindowsKey(wParam) << 16;
+
+			scancode = GB(lParam, 16, 8);
+			if (scancode == 41) pressed_key = w | WKC_BACKQUOTE << 16;
+
+			if (GB(pressed_key, 16, 16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) {
+				_double_size ^= 1;
+				_wnd.double_size = _double_size;
+				ClientSizeChanged(_wnd.width, _wnd.height);
+				MarkWholeScreenDirty();
+			}
+			HandleKeypress(pressed_key);
+			break;
+		}
+
+		case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
+			switch (wParam) {
+				case VK_RETURN:
+				case 'F': /* Full Screen on ALT + ENTER/F */
+					ToggleFullScreen(!_wnd.fullscreen);
+					return 0;
+
+				case VK_MENU: /* Just ALT */
+					return 0; // do nothing
+
+				case VK_F10: /* F10, ignore activation of menu */
+					HandleKeypress(MapWindowsKey(wParam) << 16);
+					return 0;
+
+				default: /* ALT in combination with something else */
+					HandleKeypress(MapWindowsKey(wParam) << 16);
+					break;
+			}
+			break;
+
+		case WM_SIZE:
+			if (wParam != SIZE_MINIMIZED) {
+				/* Set maximized flag when we maximize (obviously), but also when we
+				 * switched to fullscreen from a maximized state */
+				_window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
+				if (_window_maximize) {
+					_bck_resolution[0] = _cur_resolution[0];
+					_bck_resolution[1] = _cur_resolution[1];
+				}
+				ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
+			}
+			return 0;
+
+		case WM_SIZING: {
+			RECT* r = (RECT*)lParam;
+			RECT r2;
+			int w, h;
+
+			SetRect(&r2, 0, 0, 0, 0);
+			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
+
+			w = r->right - r->left - (r2.right - r2.left);
+			h = r->bottom - r->top - (r2.bottom - r2.top);
+			if (_wnd.double_size) {
+				w /= 2;
+				h /= 2;
+			}
+			w = clamp(w, 64, MAX_SCREEN_WIDTH);
+			h = clamp(h, 64, MAX_SCREEN_HEIGHT);
+			if (_wnd.double_size) {
+				w *= 2;
+				h *= 2;
+			}
+			SetRect(&r2, 0, 0, w, h);
+
+			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
+			w = r2.right - r2.left;
+			h = r2.bottom - r2.top;
+
+			switch (wParam) {
+				case WMSZ_BOTTOM:
+					r->bottom = r->top + h;
+					break;
+
+				case WMSZ_BOTTOMLEFT:
+					r->bottom = r->top + h;
+					r->left = r->right - w;
+					break;
+
+				case WMSZ_BOTTOMRIGHT:
+					r->bottom = r->top + h;
+					r->right = r->left + w;
+					break;
+
+				case WMSZ_LEFT:
+					r->left = r->right - w;
+					break;
+
+				case WMSZ_RIGHT:
+					r->right = r->left + w;
+					break;
+
+				case WMSZ_TOP:
+					r->top = r->bottom - h;
+					break;
+
+				case WMSZ_TOPLEFT:
+					r->top = r->bottom - h;
+					r->left = r->right - w;
+					break;
+
+				case WMSZ_TOPRIGHT:
+					r->top = r->bottom - h;
+					r->right = r->left + w;
+					break;
+			}
+			return TRUE;
+		}
+
+// needed for wheel
+#if !defined(WM_MOUSEWHEEL)
+# define WM_MOUSEWHEEL 0x020A
+#endif  //WM_MOUSEWHEEL
+#if !defined(GET_WHEEL_DELTA_WPARAM)
+# define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
+#endif  //GET_WHEEL_DELTA_WPARAM
+
+		case WM_MOUSEWHEEL: {
+			int delta = GET_WHEEL_DELTA_WPARAM(wParam);
+
+			if (delta < 0) {
+				_cursor.wheel++;
+			} else if (delta > 0) {
+				_cursor.wheel--;
+			}
+			HandleMouseEvents();
+			return 0;
+		}
+
+		case WM_ACTIVATEAPP:
+			_wnd.has_focus = (bool)wParam;
+			break;
+	}
+	return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static void RegisterWndClass(void)
+{
+	static bool registered = false;
+
+	if (!registered) {
+		HINSTANCE hinst = GetModuleHandle(NULL);
+		WNDCLASS wnd = {
+			0,
+			WndProcGdi,
+			0,
+			0,
+			hinst,
+			LoadIcon(hinst, MAKEINTRESOURCE(100)),
+			LoadCursor(NULL, IDC_ARROW),
+			0,
+			0,
+			_T("OTTD")
+		};
+
+		registered = true;
+		if (!RegisterClass(&wnd)) error("RegisterClass failed");
+	}
+}
+
+static void MakeWindow(bool full_screen)
+{
+	_fullscreen = full_screen;
+
+	_wnd.double_size = _double_size && !full_screen;
+
+	// recreate window?
+	if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
+		DestroyWindow(_wnd.main_wnd);
+		_wnd.main_wnd = 0;
+	}
+
+	if (full_screen) {
+		DEVMODE settings;
+
+		memset(&settings, 0, sizeof(settings));
+		settings.dmSize = sizeof(settings);
+		settings.dmFields =
+			(_fullscreen_bpp != 0 ? DM_BITSPERPEL : 0) |
+			DM_PELSWIDTH |
+			DM_PELSHEIGHT |
+			(_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
+		settings.dmBitsPerPel = _fullscreen_bpp;
+		settings.dmPelsWidth  = _wnd.width_org;
+		settings.dmPelsHeight = _wnd.height_org;
+		settings.dmDisplayFrequency = _display_hz;
+
+		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
+			MakeWindow(false);
+			return;
+		}
+	} else if (_wnd.fullscreen) {
+		// restore display?
+		ChangeDisplaySettings(NULL, 0);
+	}
+
+	{
+		RECT r;
+		DWORD style, showstyle;
+		int x, y, w, h;
+
+		showstyle = SW_SHOWNORMAL;
+		_wnd.fullscreen = full_screen;
+		if (_wnd.fullscreen) {
+			style = WS_POPUP;
+			SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
+		} else {
+			style = WS_OVERLAPPEDWINDOW;
+			/* On window creation, check if we were in maximize mode before */
+			if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
+			SetRect(&r, 0, 0, _wnd.width, _wnd.height);
+		}
+
+		AdjustWindowRect(&r, style, FALSE);
+		w = r.right - r.left;
+		h = r.bottom - r.top;
+		x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
+		y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
+
+		if (_wnd.main_wnd) {
+			ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); // remove maximize-flag
+			SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
+		} else {
+			extern const char _openttd_revision[];
+			TCHAR Windowtitle[50];
+
+			_sntprintf(Windowtitle, sizeof(Windowtitle), _T("OpenTTD %s"), MB_TO_WIDE(_openttd_revision));
+
+			_wnd.main_wnd = CreateWindow(_T("OTTD"), Windowtitle, style, x, y, w, h, 0, 0, GetModuleHandle(NULL), 0);
+			if (_wnd.main_wnd == NULL) error("CreateWindow failed");
+			ShowWindow(_wnd.main_wnd, showstyle);
+		}
+	}
+	GameSizeChanged(); // invalidate all windows, force redraw
+}
+
+static bool AllocateDibSection(int w, int h)
+{
+	BITMAPINFO *bi;
+	HDC dc;
+
+	w = clamp(w, 64, MAX_SCREEN_WIDTH);
+	h = clamp(h, 64, MAX_SCREEN_HEIGHT);
+
+	if (w == _screen.width && h == _screen.height)
+		return false;
+
+	_screen.width = w;
+	_screen.pitch = ALIGN(w, 4);
+	_screen.height = h;
+
+	if (_wnd.alloced_bits) {
+		free(_wnd.alloced_bits);
+		_wnd.alloced_bits = NULL;
+	}
+
+	bi = alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
+	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
+	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+	if (_wnd.double_size) {
+		w = ALIGN(w, 4);
+		_wnd.alloced_bits = _wnd.buffer_bits = malloc(w * h);
+		w *= 2;
+		h *= 2;
+	}
+
+	bi->bmiHeader.biWidth = _wnd.width = w;
+	bi->bmiHeader.biHeight = -(_wnd.height = h);
+
+	bi->bmiHeader.biPlanes = 1;
+	bi->bmiHeader.biBitCount = 8;
+	bi->bmiHeader.biCompression = BI_RGB;
+
+	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
+
+	dc = GetDC(0);
+	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.bitmap_bits, NULL, 0);
+	if (_wnd.dib_sect == NULL) error("CreateDIBSection failed");
+	ReleaseDC(0, dc);
+
+	if (!_wnd.double_size) _wnd.buffer_bits = _wnd.bitmap_bits;
+
+	return true;
+}
+
+static const uint16 default_resolutions[][2] = {
+	{  640,  480 },
+	{  800,  600 },
+	{ 1024,  768 },
+	{ 1152,  864 },
+	{ 1280,  800 },
+	{ 1280,  960 },
+	{ 1280, 1024 },
+	{ 1400, 1050 },
+	{ 1600, 1200 },
+	{ 1680, 1050 },
+	{ 1920, 1200 }
+};
+
+static void FindResolutions(void)
+{
+	uint n = 0;
+	uint i;
+	DEVMODEA dm;
+
+	/* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95
+	 * Doesn't really matter since we don't pass a string anyways, but still
+	 * a letdown */
+	for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) {
+		if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
+				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) {
+			uint j;
+
+			for (j = 0; j < n; j++) {
+				if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break;
+			}
+
+			/* In the previous loop we have checked already existing/added resolutions if
+			 * they are the same as the new ones. If this is not the case (j == n); we have
+			 * looped all and found none, add the new one to the list. If we have reached the
+			 * maximum amount of resolutions, then quit querying the display */
+			if (j == n) {
+				_resolutions[j][0] = dm.dmPelsWidth;
+				_resolutions[j][1] = dm.dmPelsHeight;
+				if (++n == lengthof(_resolutions)) break;
+			}
+		}
+	}
+
+	/* We have found no resolutions, show the default list */
+	if (n == 0) {
+		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
+		n = lengthof(default_resolutions);
+	}
+
+	_num_resolutions = n;
+	SortResolutions(_num_resolutions);
+}
+
+
+static const char *Win32GdiStart(const char * const *parm)
+{
+	memset(&_wnd, 0, sizeof(_wnd));
+
+	RegisterWndClass();
+
+	MakePalette();
+
+	FindResolutions();
+
+	// fullscreen uses those
+	_wnd.width_org = _cur_resolution[0];
+	_wnd.height_org = _cur_resolution[1];
+
+	AllocateDibSection(_cur_resolution[0], _cur_resolution[1]);
+	MarkWholeScreenDirty();
+
+	MakeWindow(_fullscreen);
+
+	return NULL;
+}
+
+static void Win32GdiStop(void)
+{
+	DeleteObject(_wnd.gdi_palette);
+	DeleteObject(_wnd.dib_sect);
+	DestroyWindow(_wnd.main_wnd);
+
+	if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0);
+	if (_double_size) {
+		_cur_resolution[0] *= 2;
+		_cur_resolution[1] *= 2;
+	}
+
+	MyShowCursor(true);
+}
+
+// simple upscaler by 2
+static void filter(int left, int top, int width, int height)
+{
+	uint p = _screen.pitch;
+	const Pixel *s = _wnd.buffer_bits + top * p + left;
+	Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2;
+
+	for (; height > 0; height--) {
+		int i;
+
+		for (i = 0; i != width; i++) {
+			d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i];
+		}
+		s += p;
+		d += p * 4;
+	}
+}
+
+static void Win32GdiMakeDirty(int left, int top, int width, int height)
+{
+	RECT r = { left, top, left + width, top + height };
+
+	if (_wnd.double_size) {
+		filter(left, top, width, height);
+		r.left *= 2;
+		r.top *= 2;
+		r.right *= 2;
+		r.bottom *= 2;
+	}
+	InvalidateRect(_wnd.main_wnd, &r, FALSE);
+}
+
+static void CheckPaletteAnim(void)
+{
+	if (_pal_last_dirty == -1)
+		return;
+	InvalidateRect(_wnd.main_wnd, NULL, FALSE);
+}
+
+static void Win32GdiMainLoop(void)
+{
+	MSG mesg;
+	uint32 cur_ticks = GetTickCount();
+	uint32 next_tick = cur_ticks + 30;
+
+	_wnd.running = true;
+
+	for (;;) {
+		uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
+
+		while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) {
+			InteractiveRandom(); // randomness
+			DispatchMessage(&mesg);
+		}
+		if (_exit_game) return;
+
+#if defined(_DEBUG)
+		if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
+#else
+		/* Speed up using TAB, but disable for ALT+TAB of course */
+		if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 &&
+#endif
+			  !_networking && _game_mode != GM_MENU) {
+			_fast_forward |= 2;
+		} else if (_fast_forward & 2) {
+			_fast_forward = 0;
+		}
+
+		cur_ticks = GetTickCount();
+		if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) {
+			next_tick = cur_ticks + 30;
+			_ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
+			_shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0;
+#ifdef _DEBUG
+			_dbg_screen_rect = _wnd.has_focus && GetAsyncKeyState(VK_CAPITAL)<0;
+#endif
+
+			// determine which directional keys are down
+			if (_wnd.has_focus) {
+				_dirkeys =
+					(GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
+					(GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
+					(GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
+					(GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
+			} else {
+				_dirkeys = 0;
+			}
+
+			GameLoop();
+			_cursor.delta.x = _cursor.delta.y = 0;
+
+			if (_force_full_redraw) MarkWholeScreenDirty();
+
+			GdiFlush();
+			_screen.dst_ptr = _wnd.buffer_bits;
+			UpdateWindows();
+			CheckPaletteAnim();
+		} else {
+			Sleep(1);
+			GdiFlush();
+			_screen.dst_ptr = _wnd.buffer_bits;
+			DrawTextMessage();
+			DrawMouseCursor();
+		}
+	}
+}
+
+static bool Win32GdiChangeRes(int w, int h)
+{
+	_wnd.width = _wnd.width_org = w;
+	_wnd.height = _wnd.height_org = h;
+
+	MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
+
+	return true;
+}
+
+static void Win32GdiFullScreen(bool full_screen)
+{
+	MakeWindow(full_screen);
+}
+
+const HalVideoDriver _win32_video_driver = {
+	Win32GdiStart,
+	Win32GdiStop,
+	Win32GdiMakeDirty,
+	Win32GdiMainLoop,
+	Win32GdiChangeRes,
+	Win32GdiFullScreen,
+};
deleted file mode 100644
--- a/src/viewport.c
+++ /dev/null
@@ -1,2462 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "gui.h"
-#include "spritecache.h"
-#include "strings.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "map.h"
-#include "viewport.h"
-#include "window.h"
-#include "vehicle.h"
-#include "station.h"
-#include "gfx.h"
-#include "town.h"
-#include "signs.h"
-#include "waypoint.h"
-#include "variables.h"
-#include "train.h"
-
-#define VIEWPORT_DRAW_MEM (65536 * 2)
-
-/* viewport.c */
-// XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar)
-static ViewPort _viewports[25 - 2];
-static uint32 _active_viewports;    ///< bitmasked variable where each bit signifies if a viewport is in use or not
-assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8);
-
-static bool _added_tile_sprite;
-static bool _offset_ground_sprites;
-
-/* The in-game coordiante system looks like this *
- *                                               *
- *                    ^ Z                        *
- *                    |                          *
- *                    |                          *
- *                    |                          *
- *                    |                          *
- *                 /     \                       *
- *              /           \                    *
- *           /                 \                 *
- *        /                       \              *
- *   X <                             > Y         *
- */
-
-typedef struct StringSpriteToDraw {
-	uint16 string;
-	uint16 color;
-	struct StringSpriteToDraw *next;
-	int32 x;
-	int32 y;
-	uint32 params[2];
-	uint16 width;
-} StringSpriteToDraw;
-
-typedef struct TileSpriteToDraw {
-	uint32 image;
-	struct TileSpriteToDraw *next;
-	int32 x;
-	int32 y;
-	byte z;
-} TileSpriteToDraw;
-
-typedef struct ChildScreenSpriteToDraw {
-	uint32 image;
-	int32 x;
-	int32 y;
-	struct ChildScreenSpriteToDraw *next;
-} ChildScreenSpriteToDraw;
-
-typedef struct ParentSpriteToDraw {
-	uint32 image;
-	int32 left;
-	int32 top;
-	int32 right;
-	int32 bottom;
-	int32 xmin;
-	int32 ymin;
-	int32 xmax;
-	int32 ymax;
-	ChildScreenSpriteToDraw *child;
-	byte unk16;
-	byte zmin;
-	byte zmax;
-} ParentSpriteToDraw;
-
-// Quick hack to know how much memory to reserve when allocating from the spritelist
-// to prevent a buffer overflow.
-#define LARGEST_SPRITELIST_STRUCT ParentSpriteToDraw
-
-typedef struct ViewportDrawer {
-	DrawPixelInfo dpi;
-
-	byte *spritelist_mem;
-	const byte *eof_spritelist_mem;
-
-	StringSpriteToDraw **last_string, *first_string;
-	TileSpriteToDraw **last_tile, *first_tile;
-
-	ChildScreenSpriteToDraw **last_child;
-
-	ParentSpriteToDraw **parent_list;
-	ParentSpriteToDraw * const *eof_parent_list;
-
-	byte combine_sprites;
-
-	int offs_x, offs_y; // used when drawing ground sprites relative
-} ViewportDrawer;
-
-static ViewportDrawer *_cur_vd;
-
-TileHighlightData _thd;
-static TileInfo *_cur_ti;
-
-extern void SmallMapCenterOnCurrentPos(Window *w);
-
-static Point MapXYZToViewport(const ViewPort *vp, uint x, uint y, uint z)
-{
-	Point p = RemapCoords(x, y, z);
-	p.x -= vp->virtual_width / 2;
-	p.y -= vp->virtual_height / 2;
-	return p;
-}
-
-void InitViewports(void) {
-	memset(_viewports, 0, sizeof(_viewports));
-	_active_viewports = 0;
-}
-
-void DeleteWindowViewport(Window *w)
-{
-	CLRBIT(_active_viewports, w->viewport - _viewports);
-	w->viewport->width = 0;
-	w->viewport = NULL;
-}
-
-void AssignWindowViewport(Window *w, int x, int y,
-	int width, int height, uint32 follow_flags, byte zoom)
-{
-	ViewPort *vp;
-	Point pt;
-	uint32 bit;
-
-	for (vp = _viewports, bit = 0; ; vp++, bit++) {
-		assert(vp != endof(_viewports));
-		if (vp->width == 0) break;
-	}
-	SETBIT(_active_viewports, bit);
-
-	vp->left = x + w->left;
-	vp->top = y + w->top;
-	vp->width = width;
-	vp->height = height;
-
-	vp->zoom = zoom;
-
-	vp->virtual_width = width << zoom;
-	vp->virtual_height = height << zoom;
-
-	if (follow_flags & 0x80000000) {
-		const Vehicle *veh;
-
-		WP(w, vp_d).follow_vehicle = (VehicleID)(follow_flags & 0xFFFF);
-		veh = GetVehicle(WP(w, vp_d).follow_vehicle);
-		pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
-	} else {
-		uint x = TileX(follow_flags) * TILE_SIZE;
-		uint y = TileY(follow_flags) * TILE_SIZE;
-
-		WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
-		pt = MapXYZToViewport(vp, x, y, GetSlopeZ(x, y));
-	}
-
-	WP(w, vp_d).scrollpos_x = pt.x;
-	WP(w, vp_d).scrollpos_y = pt.y;
-	w->viewport = vp;
-	vp->virtual_left = 0;//pt.x;
-	vp->virtual_top = 0;//pt.y;
-}
-
-static Point _vp_move_offs;
-
-static void DoSetViewportPosition(Window* const *wz, int left, int top, int width, int height)
-{
-
-	for (; wz != _last_z_window; wz++) {
-		const Window *w = *wz;
-
-		if (left + width > w->left &&
-				w->left + w->width > left &&
-				top + height > w->top &&
-				w->top + w->height > top) {
-
-			if (left < w->left) {
-				DoSetViewportPosition(wz, left, top, w->left - left, height);
-				DoSetViewportPosition(wz, left + (w->left - left), top, width - (w->left - left), height);
-				return;
-			}
-
-			if (left + width > w->left + w->width) {
-				DoSetViewportPosition(wz, left, top, (w->left + w->width - left), height);
-				DoSetViewportPosition(wz, left + (w->left + w->width - left), top, width - (w->left + w->width - left) , height);
-				return;
-			}
-
-			if (top < w->top) {
-				DoSetViewportPosition(wz, left, top, width, (w->top - top));
-				DoSetViewportPosition(wz, left, top + (w->top - top), width, height - (w->top - top));
-				return;
-			}
-
-			if (top + height > w->top + w->height) {
-				DoSetViewportPosition(wz, left, top, width, (w->top + w->height - top));
-				DoSetViewportPosition(wz, left, top + (w->top + w->height - top), width , height - (w->top + w->height - top));
-				return;
-			}
-
-			return;
-		}
-	}
-
-	{
-		int xo = _vp_move_offs.x;
-		int yo = _vp_move_offs.y;
-
-		if (abs(xo) >= width || abs(yo) >= height) {
-			/* fully_outside */
-			RedrawScreenRect(left, top, left + width, top + height);
-			return;
-		}
-
-		GfxScroll(left, top, width, height, xo, yo);
-
-		if (xo > 0) {
-			RedrawScreenRect(left, top, xo + left, top + height);
-			left += xo;
-			width -= xo;
-		} else if (xo < 0) {
-			RedrawScreenRect(left+width+xo, top, left+width, top + height);
-			width += xo;
-		}
-
-		if (yo > 0) {
-			RedrawScreenRect(left, top, width+left, top + yo);
-		} else if (yo < 0) {
-			RedrawScreenRect(left, top + height + yo, width+left, top + height);
-		}
-	}
-}
-
-static void SetViewportPosition(Window *w, int x, int y)
-{
-	ViewPort *vp = w->viewport;
-	int old_left = vp->virtual_left;
-	int old_top = vp->virtual_top;
-	int i;
-	int left, top, width, height;
-
-	vp->virtual_left = x;
-	vp->virtual_top = y;
-
-	old_left >>= vp->zoom;
-	old_top >>= vp->zoom;
-	x >>= vp->zoom;
-	y >>= vp->zoom;
-
-	old_left -= x;
-	old_top -= y;
-
-	if (old_top == 0 && old_left == 0) return;
-
-	_vp_move_offs.x = old_left;
-	_vp_move_offs.y = old_top;
-
-	left = vp->left;
-	top = vp->top;
-	width = vp->width;
-	height = vp->height;
-
-	if (left < 0) {
-		width += left;
-		left = 0;
-	}
-
-	i = left + width - _screen.width;
-	if (i >= 0) width -= i;
-
-	if (width > 0) {
-		if (top < 0) {
-			height += top;
-			top = 0;
-		}
-
-		i = top + height - _screen.height;
-		if (i >= 0) height -= i;
-
-		if (height > 0) DoSetViewportPosition(FindWindowZPosition(w) + 1, left, top, width, height);
-	}
-}
-
-
-ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
-{
-	ViewPort *vp = w->viewport;
-
-	if (vp != NULL &&
-	    IS_INT_INSIDE(x, vp->left, vp->left + vp->width) &&
-			IS_INT_INSIDE(y, vp->top, vp->top + vp->height))
-		return vp;
-
-	return NULL;
-}
-
-static Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y)
-{
-	Point pt;
-	int a,b;
-	uint z;
-
-	if ( (uint)(x -= vp->left) >= (uint)vp->width ||
-				(uint)(y -= vp->top) >= (uint)vp->height) {
-				Point pt = {-1, -1};
-				return pt;
-	}
-
-	x = ((x << vp->zoom) + vp->virtual_left) >> 2;
-	y = ((y << vp->zoom) + vp->virtual_top) >> 1;
-
-	a = y-x;
-	b = y+x;
-
-	/* we need to move variables in to the valid range, as the
-	 * GetTileZoomCenterWindow() function can call here with invalid x and/or y,
-	 * when the user tries to zoom out along the sides of the map */
-	a = clamp(a, 0, (int)(MapMaxX() * TILE_SIZE) - 1);
-	b = clamp(b, 0, (int)(MapMaxY() * TILE_SIZE) - 1);
-
-	z = GetSlopeZ(a,     b    ) / 2;
-	z = GetSlopeZ(a + z, b + z) / 2;
-	z = GetSlopeZ(a + z, b + z) / 2;
-	z = GetSlopeZ(a + z, b + z) / 2;
-	z = GetSlopeZ(a + z, b + z) / 2;
-
-	pt.x = a + z;
-	pt.y = b + z;
-
-	return pt;
-}
-
-/* When used for zooming, check area below current coordinates (x,y)
- * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
- * when you just want the tile, make x = zoom_x and y = zoom_y */
-static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
-{
-	Window *w;
-	ViewPort *vp;
-	Point pt;
-
-	if ( (w = FindWindowFromPt(x, y)) != NULL &&
-			 (vp = IsPtInWindowViewport(w, x, y)) != NULL)
-				return TranslateXYToTileCoord(vp, zoom_x, zoom_y);
-
-	pt.y = pt.x = -1;
-	return pt;
-}
-
-Point GetTileBelowCursor(void)
-{
-	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
-}
-
-
-Point GetTileZoomCenterWindow(bool in, Window * w)
-{
-	int x, y;
-	ViewPort * vp;
-
-	vp = w->viewport;
-
-	if (in) {
-		x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
-		y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2);
-	} else {
-		x = vp->width - (_cursor.pos.x - vp->left);
-		y = vp->height - (_cursor.pos.y - vp->top);
-	}
-	/* Get the tile below the cursor and center on the zoomed-out center */
-	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
-}
-
-/** Update the status of the zoom-buttons according to the zoom-level
- * of the viewport. This will update their status and invalidate accordingly
- * @param window pointer to the window that has the zoom buttons
- * @param vp pointer to the viewport whose zoom-level the buttons represent
- * @param widget_zoom_in widget index for window with zoom-in button
- * @param widget_zoom_out widget index for window with zoom-out button */
-void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
-{
-	SetWindowWidgetDisabledState(w, widget_zoom_in, vp->zoom == 0);
-	InvalidateWidget(w, widget_zoom_in);
-
-	SetWindowWidgetDisabledState(w, widget_zoom_out, vp->zoom == 2);
-	InvalidateWidget(w, widget_zoom_out);
-}
-
-void DrawGroundSpriteAt(uint32 image, int32 x, int32 y, byte z)
-{
-	ViewportDrawer *vd = _cur_vd;
-	TileSpriteToDraw *ts;
-
-	assert((image & SPRITE_MASK) < MAX_SPRITES);
-
-	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
-		DEBUG(sprite, 0, "Out of sprite memory");
-		return;
-	}
-	ts = (TileSpriteToDraw*)vd->spritelist_mem;
-
-	vd->spritelist_mem += sizeof(TileSpriteToDraw);
-
-	ts->image = image;
-	ts->next = NULL;
-	ts->x = x;
-	ts->y = y;
-	ts->z = z;
-	*vd->last_tile = ts;
-	vd->last_tile = &ts->next;
-}
-
-void DrawGroundSprite(uint32 image)
-{
-	if (_offset_ground_sprites) {
-		// offset ground sprite because of foundation?
-		AddChildSpriteScreen(image, _cur_vd->offs_x, _cur_vd->offs_y);
-	} else {
-		_added_tile_sprite = true;
-		DrawGroundSpriteAt(image, _cur_ti->x, _cur_ti->y, _cur_ti->z);
-	}
-}
-
-
-void OffsetGroundSprite(int x, int y)
-{
-	_cur_vd->offs_x = x;
-	_cur_vd->offs_y = y;
-	_offset_ground_sprites = true;
-}
-
-static void AddCombinedSprite(uint32 image, int x, int y, byte z)
-{
-	const ViewportDrawer *vd = _cur_vd;
-	Point pt = RemapCoords(x, y, z);
-	const Sprite* spr = GetSprite(image & SPRITE_MASK);
-
-	if (pt.x + spr->x_offs >= vd->dpi.left + vd->dpi.width ||
-			pt.x + spr->x_offs + spr->width <= vd->dpi.left ||
-			pt.y + spr->y_offs >= vd->dpi.top + vd->dpi.height ||
-			pt.y + spr->y_offs + spr->height <= vd->dpi.top)
-		return;
-
-	AddChildSpriteScreen(image, pt.x - vd->parent_list[-1]->left, pt.y - vd->parent_list[-1]->top);
-}
-
-
-void AddSortableSpriteToDraw(uint32 image, int x, int y, int w, int h, byte dz, byte z)
-{
-	ViewportDrawer *vd = _cur_vd;
-	ParentSpriteToDraw *ps;
-	const Sprite *spr;
-	Point pt;
-
-	assert((image & SPRITE_MASK) < MAX_SPRITES);
-
-	if (vd->combine_sprites == 2) {
-		AddCombinedSprite(image, x, y, z);
-		return;
-	}
-
-	vd->last_child = NULL;
-
-	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
-		DEBUG(sprite, 0, "Out of sprite memory");
-		return;
-	}
-	ps = (ParentSpriteToDraw*)vd->spritelist_mem;
-
-	if (vd->parent_list >= vd->eof_parent_list) {
-		// This can happen rarely, mostly when you zoom out completely
-		//  and have a lot of stuff that moves (and is added to the
-		//  sort-list, this function). To solve it, increase
-		//  parent_list somewhere below to a higher number.
-		// This can not really hurt you, it just gives some black
-		//  spots on the screen ;)
-		DEBUG(sprite, 0, "Out of sprite memory (parent_list)");
-		return;
-	}
-
-	pt = RemapCoords(x, y, z);
-	spr = GetSprite(image & SPRITE_MASK);
-	if ((ps->left   = (pt.x += spr->x_offs)) >= vd->dpi.left + vd->dpi.width ||
-			(ps->right  = (pt.x +  spr->width )) <= vd->dpi.left ||
-			(ps->top    = (pt.y += spr->y_offs)) >= vd->dpi.top + vd->dpi.height ||
-			(ps->bottom = (pt.y +  spr->height)) <= vd->dpi.top) {
-		return;
-	}
-
-	vd->spritelist_mem += sizeof(ParentSpriteToDraw);
-
-	ps->image = image;
-	ps->xmin = x;
-	ps->xmax = x + w - 1;
-
-	ps->ymin = y;
-	ps->ymax = y + h - 1;
-
-	ps->zmin = z;
-	ps->zmax = z + dz - 1;
-
-	ps->unk16 = 0;
-	ps->child = NULL;
-	vd->last_child = &ps->child;
-
-	*vd->parent_list++ = ps;
-
-	if (vd->combine_sprites == 1) vd->combine_sprites = 2;
-}
-
-void StartSpriteCombine(void)
-{
-	_cur_vd->combine_sprites = 1;
-}
-
-void EndSpriteCombine(void)
-{
-	_cur_vd->combine_sprites = 0;
-}
-
-void AddChildSpriteScreen(uint32 image, int x, int y)
-{
-	ViewportDrawer *vd = _cur_vd;
-	ChildScreenSpriteToDraw *cs;
-
-	assert((image & SPRITE_MASK) < MAX_SPRITES);
-
-	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
-		DEBUG(sprite, 0, "Out of sprite memory");
-		return;
-	}
-	cs = (ChildScreenSpriteToDraw*)vd->spritelist_mem;
-
-	if (vd->last_child == NULL) return;
-
-	vd->spritelist_mem += sizeof(ChildScreenSpriteToDraw);
-
-	*vd->last_child = cs;
-	vd->last_child = &cs->next;
-
-	cs->image = image;
-	cs->x = x;
-	cs->y = y;
-	cs->next = NULL;
-}
-
-/* Returns a StringSpriteToDraw */
-void *AddStringToDraw(int x, int y, StringID string, uint32 params_1, uint32 params_2)
-{
-	ViewportDrawer *vd = _cur_vd;
-	StringSpriteToDraw *ss;
-
-	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
-		DEBUG(sprite, 0, "Out of sprite memory");
-		return NULL;
-	}
-	ss = (StringSpriteToDraw*)vd->spritelist_mem;
-
-	vd->spritelist_mem += sizeof(StringSpriteToDraw);
-
-	ss->string = string;
-	ss->next = NULL;
-	ss->x = x;
-	ss->y = y;
-	ss->params[0] = params_1;
-	ss->params[1] = params_2;
-	ss->width = 0;
-
-	*vd->last_string = ss;
-	vd->last_string = &ss->next;
-
-	return ss;
-}
-
-
-static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
-{
-	if (_added_tile_sprite && !(_thd.drawstyle & HT_LINE)) { // draw on real ground
-		DrawGroundSpriteAt(image, ti->x, ti->y, ti->z + 7);
-	} else { // draw on top of foundation
-		AddSortableSpriteToDraw(image, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
-	}
-}
-
-static bool IsPartOfAutoLine(int px, int py)
-{
-	px -= _thd.selstart.x;
-	py -= _thd.selstart.y;
-
-	switch (_thd.drawstyle) {
-	case HT_LINE | HT_DIR_X:  return py == 0; // x direction
-	case HT_LINE | HT_DIR_Y:  return px == 0; // y direction
-	case HT_LINE | HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
-	case HT_LINE | HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
-	case HT_LINE | HT_DIR_VL: return px == py || px == py + 16; // vertival left
-	case HT_LINE | HT_DIR_VR: return px == py || px == py - 16; // vertical right
-	default:
-		NOT_REACHED();
-	}
-
-	/* useless, but avoids compiler warning this way */
-	return 0;
-}
-
-// [direction][side]
-static const int _AutorailType[6][2] = {
-	{ HT_DIR_X,  HT_DIR_X },
-	{ HT_DIR_Y,  HT_DIR_Y },
-	{ HT_DIR_HU, HT_DIR_HL },
-	{ HT_DIR_HL, HT_DIR_HU },
-	{ HT_DIR_VL, HT_DIR_VR },
-	{ HT_DIR_VR, HT_DIR_VL }
-};
-
-#include "table/autorail.h"
-
-static void DrawTileSelection(const TileInfo *ti)
-{
-	uint32 image;
-
-	// Draw a red error square?
-	if (_thd.redsq != 0 && _thd.redsq == ti->tile) {
-		DrawSelectionSprite(PALETTE_TILE_RED_PULSATING | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
-		return;
-	}
-
-	// no selection active?
-	if (_thd.drawstyle == 0) return;
-
-	// Inside the inner area?
-	if (IS_INSIDE_1D(ti->x, _thd.pos.x, _thd.size.x) &&
-			IS_INSIDE_1D(ti->y, _thd.pos.y, _thd.size.y)) {
-		if (_thd.drawstyle & HT_RECT) {
-			image = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh];
-			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
-			DrawSelectionSprite(image, ti);
-		} else if (_thd.drawstyle & HT_POINT) {
-			// Figure out the Z coordinate for the single dot.
-			byte z = ti->z;
-			if (ti->tileh & SLOPE_N) {
-				z += TILE_HEIGHT;
-				if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT;
-			}
-			DrawGroundSpriteAt(_cur_dpi->zoom != 2 ? SPR_DOT : SPR_DOT_SMALL, ti->x, ti->y, z);
-		} else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) {
-			// autorail highlight piece under cursor
-			uint type = _thd.drawstyle & 0xF;
-			assert(type <= 5);
-			image = SPR_AUTORAIL_BASE + _AutorailTilehSprite[ti->tileh][_AutorailType[type][0]];
-
-			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
-			DrawSelectionSprite(image, ti);
-
-		} else if (IsPartOfAutoLine(ti->x, ti->y)) {
-			// autorail highlighting long line
-			int dir = _thd.drawstyle & ~0xF0;
-			uint side;
-
-			if (dir < 2) {
-				side = 0;
-			} else {
-				TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
-				int diffx = myabs(TileX(start) - TileX(ti->tile));
-				int diffy = myabs(TileY(start) - TileY(ti->tile));
-				side = myabs(diffx - diffy);
-			}
-
-			image = SPR_AUTORAIL_BASE + _AutorailTilehSprite[ti->tileh][_AutorailType[dir][side]];
-
-			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
-			DrawSelectionSprite(image, ti);
-		}
-		return;
-	}
-
-	// Check if it's inside the outer area?
-	if (_thd.outersize.x &&
-			_thd.size.x < _thd.size.x + _thd.outersize.x &&
-			IS_INSIDE_1D(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
-			IS_INSIDE_1D(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
-		// Draw a blue rect.
-		DrawSelectionSprite(PALETTE_SEL_TILE_BLUE | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
-		return;
-	}
-}
-
-static void ViewportAddLandscape(void)
-{
-	ViewportDrawer *vd = _cur_vd;
-	int x, y, width, height;
-	TileInfo ti;
-	bool direction;
-
-	_cur_ti = &ti;
-
-	// Transform into tile coordinates and round to closest full tile
-	x = ((vd->dpi.top >> 1) - (vd->dpi.left >> 2)) & ~0xF;
-	y = ((vd->dpi.top >> 1) + (vd->dpi.left >> 2) - 0x10) & ~0xF;
-
-	// determine size of area
-	{
-		Point pt = RemapCoords(x, y, 241);
-		width = (vd->dpi.left + vd->dpi.width - pt.x + 95) >> 6;
-		height = (vd->dpi.top + vd->dpi.height - pt.y) >> 5 << 1;
-	}
-
-	assert(width > 0);
-	assert(height > 0);
-
-	direction = false;
-
-	do {
-		int width_cur = width;
-		int x_cur = x;
-		int y_cur = y;
-
-		do {
-			TileType tt;
-
-			ti.x = x_cur;
-			ti.y = y_cur;
-			if (0 <= x_cur && x_cur < (int)MapMaxX() * TILE_SIZE &&
-					0 <= y_cur && y_cur < (int)MapMaxY() * TILE_SIZE) {
-				TileIndex tile = TileVirtXY(x_cur, y_cur);
-
-				ti.tile = tile;
-				ti.tileh = GetTileSlope(tile, &ti.z);
-				tt = GetTileType(tile);
-			} else {
-				ti.tileh = SLOPE_FLAT;
-				ti.tile = 0;
-				ti.z = 0;
-				tt = MP_VOID;
-			}
-
-			y_cur += 0x10;
-			x_cur -= 0x10;
-
-			_added_tile_sprite = false;
-			_offset_ground_sprites = false;
-
-			_tile_type_procs[tt]->draw_tile_proc(&ti);
-			DrawTileSelection(&ti);
-		} while (--width_cur);
-
-		if ((direction ^= 1) != 0) {
-			y += 0x10;
-		} else {
-			x += 0x10;
-		}
-	} while (--height);
-}
-
-
-static void ViewportAddTownNames(DrawPixelInfo *dpi)
-{
-	Town *t;
-	int left, top, right, bottom;
-
-	if (!(_display_opt & DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU)
-		return;
-
-	left = dpi->left;
-	top = dpi->top;
-	right = left + dpi->width;
-	bottom = top + dpi->height;
-
-	switch (dpi->zoom) {
-		case 0:
-			FOR_ALL_TOWNS(t) {
-				if (bottom > t->sign.top &&
-						top    < t->sign.top + 12 &&
-						right  > t->sign.left &&
-						left   < t->sign.left + t->sign.width_1) {
-					AddStringToDraw(t->sign.left + 1, t->sign.top + 1,
-						_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL,
-						t->index, t->population);
-				}
-			}
-			break;
-
-		case 1:
-			right += 2;
-			bottom += 2;
-
-			FOR_ALL_TOWNS(t) {
-				if (bottom > t->sign.top &&
-						top    < t->sign.top + 24 &&
-						right  > t->sign.left &&
-						left   < t->sign.left + t->sign.width_1*2) {
-					AddStringToDraw(t->sign.left + 1, t->sign.top + 1,
-						_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL,
-						t->index, t->population);
-				}
-			}
-			break;
-
-		default: NOT_REACHED();
-		case 2:
-			right += 4;
-			bottom += 5;
-
-			FOR_ALL_TOWNS(t) {
-				if (bottom > t->sign.top &&
-						top    < t->sign.top + 24 &&
-						right  > t->sign.left &&
-						left   < t->sign.left + t->sign.width_2*4) {
-					AddStringToDraw(t->sign.left + 5, t->sign.top + 1, STR_TOWN_LABEL_TINY_BLACK, t->index, 0);
-					AddStringToDraw(t->sign.left + 1, t->sign.top - 3, STR_TOWN_LABEL_TINY_WHITE, t->index, 0);
-				}
-			}
-			break;
-	}
-}
-
-
-static void AddStation(const Station *st, StringID str, uint16 width)
-{
-	StringSpriteToDraw *sstd;
-
-	sstd = AddStringToDraw(st->sign.left + 1, st->sign.top + 1, str, st->index, st->facilities);
-	if (sstd != NULL) {
-		sstd->color = (st->owner == OWNER_NONE || st->facilities == 0) ? 0xE : _player_colors[st->owner];
-		sstd->width = width;
-	}
-}
-
-
-static void ViewportAddStationNames(DrawPixelInfo *dpi)
-{
-	int left, top, right, bottom;
-	const Station *st;
-
-	if (!(_display_opt & DO_SHOW_STATION_NAMES) || _game_mode == GM_MENU)
-		return;
-
-	left = dpi->left;
-	top = dpi->top;
-	right = left + dpi->width;
-	bottom = top + dpi->height;
-
-	switch (dpi->zoom) {
-		case 0:
-			FOR_ALL_STATIONS(st) {
-				if (bottom > st->sign.top &&
-						top    < st->sign.top + 12 &&
-						right  > st->sign.left &&
-						left   < st->sign.left + st->sign.width_1) {
-					AddStation(st, STR_305C_0, st->sign.width_1);
-				}
-			}
-			break;
-
-		case 1:
-			right += 2;
-			bottom += 2;
-			FOR_ALL_STATIONS(st) {
-				if (bottom > st->sign.top &&
-						top    < st->sign.top + 24 &&
-						right  > st->sign.left &&
-						left   < st->sign.left + st->sign.width_1*2) {
-					AddStation(st, STR_305C_0, st->sign.width_1);
-				}
-			}
-			break;
-
-		default: NOT_REACHED();
-		case 2:
-			right += 4;
-			bottom += 5;
-			FOR_ALL_STATIONS(st) {
-				if (bottom > st->sign.top &&
-						top    < st->sign.top + 24 &&
-						right  > st->sign.left &&
-						left   < st->sign.left + st->sign.width_2*4) {
-					AddStation(st, STR_STATION_SIGN_TINY, st->sign.width_2 | 0x8000);
-				}
-			}
-			break;
-	}
-}
-
-
-static void AddSign(const Sign *si, StringID str, uint16 width)
-{
-	StringSpriteToDraw *sstd;
-
-	sstd = AddStringToDraw(si->sign.left + 1, si->sign.top + 1, str, si->str, 0);
-	if (sstd != NULL) {
-		sstd->color = (si->owner == OWNER_NONE) ? 14 : _player_colors[si->owner];
-		sstd->width = width;
-	}
-}
-
-
-static void ViewportAddSigns(DrawPixelInfo *dpi)
-{
-	const Sign *si;
-	int left, top, right, bottom;
-
-	if (!(_display_opt & DO_SHOW_SIGNS))
-		return;
-
-	left = dpi->left;
-	top = dpi->top;
-	right = left + dpi->width;
-	bottom = top + dpi->height;
-
-	switch (dpi->zoom) {
-		case 0:
-			FOR_ALL_SIGNS(si) {
-				if (bottom > si->sign.top &&
-						top    < si->sign.top + 12 &&
-						right  > si->sign.left &&
-						left   < si->sign.left + si->sign.width_1) {
-					AddSign(si, STR_2806, si->sign.width_1);
-				}
-			}
-			break;
-
-		case 1:
-			right += 2;
-			bottom += 2;
-			FOR_ALL_SIGNS(si) {
-				if (bottom > si->sign.top &&
-						top    < si->sign.top + 24 &&
-						right  > si->sign.left &&
-						left   < si->sign.left + si->sign.width_1 * 2) {
-					AddSign(si, STR_2806, si->sign.width_1);
-				}
-			}
-			break;
-
-		default: NOT_REACHED();
-		case 2:
-			right += 4;
-			bottom += 5;
-			FOR_ALL_SIGNS(si) {
-				if (bottom > si->sign.top &&
-						top    < si->sign.top + 24 &&
-						right  > si->sign.left &&
-						left   < si->sign.left + si->sign.width_2 * 4) {
-					AddSign(si, STR_2002, si->sign.width_2 | 0x8000);
-				}
-			}
-			break;
-	}
-}
-
-
-static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width)
-{
-	StringSpriteToDraw *sstd;
-
-	sstd = AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0);
-	if (sstd != NULL) {
-		sstd->color = (wp->deleted ? 0xE : 11);
-		sstd->width = width;
-	}
-}
-
-
-static void ViewportAddWaypoints(DrawPixelInfo *dpi)
-{
-	const Waypoint *wp;
-	int left, top, right, bottom;
-
-	if (!(_display_opt & DO_WAYPOINTS))
-		return;
-
-	left = dpi->left;
-	top = dpi->top;
-	right = left + dpi->width;
-	bottom = top + dpi->height;
-
-	switch (dpi->zoom) {
-		case 0:
-			FOR_ALL_WAYPOINTS(wp) {
-				if (bottom > wp->sign.top &&
-						top    < wp->sign.top + 12 &&
-						right  > wp->sign.left &&
-						left   < wp->sign.left + wp->sign.width_1) {
-					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
-				}
-			}
-			break;
-
-		case 1:
-			right += 2;
-			bottom += 2;
-			FOR_ALL_WAYPOINTS(wp) {
-				if (bottom > wp->sign.top &&
-						top    < wp->sign.top + 24 &&
-						right  > wp->sign.left &&
-						left   < wp->sign.left + wp->sign.width_1*2) {
-					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
-				}
-			}
-			break;
-
-		default: NOT_REACHED();
-		case 2:
-			right += 4;
-			bottom += 5;
-			FOR_ALL_WAYPOINTS(wp) {
-				if (bottom > wp->sign.top &&
-						top    < wp->sign.top + 24 &&
-						right  > wp->sign.left &&
-						left   < wp->sign.left + wp->sign.width_2*4) {
-					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT_TINY, wp->sign.width_2 | 0x8000);
-				}
-			}
-			break;
-	}
-}
-
-void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str)
-{
-	char buffer[128];
-	uint w;
-
-	sign->top = top;
-
-	GetString(buffer, str, lastof(buffer));
-	w = GetStringBoundingBox(buffer).width + 3;
-	sign->width_1 = w;
-	sign->left = left - w / 2;
-
-	/* zoomed out version */
-	_cur_fontsize = FS_SMALL;
-	w = GetStringBoundingBox(buffer).width + 3;
-	_cur_fontsize = FS_NORMAL;
-	sign->width_2 = w;
-}
-
-
-static void ViewportDrawTileSprites(TileSpriteToDraw *ts)
-{
-	do {
-		Point pt = RemapCoords(ts->x, ts->y, ts->z);
-		DrawSprite(ts->image, pt.x, pt.y);
-		ts = ts->next;
-	} while (ts != NULL);
-}
-
-static void ViewportSortParentSprites(ParentSpriteToDraw *psd[])
-{
-	while (*psd != NULL) {
-		ParentSpriteToDraw* ps = *psd;
-
-		if (!(ps->unk16 & 1)) {
-			ParentSpriteToDraw** psd2 = psd;
-
-			ps->unk16 |= 1;
-
-			while (*++psd2 != NULL) {
-				ParentSpriteToDraw* ps2 = *psd2;
-				ParentSpriteToDraw** psd3;
-
-				if (ps2->unk16 & 1) continue;
-
-				/* Decide which comparator to use, based on whether the bounding
-				 * boxes overlap
-				 */
-				if (ps->xmax > ps2->xmin && ps->xmin < ps2->xmax && // overlap in X?
-						ps->ymax > ps2->ymin && ps->ymin < ps2->ymax && // overlap in Y?
-						ps->zmax > ps2->zmin && ps->zmin < ps2->zmax) { // overlap in Z?
-					/* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
-					 * the screen and with higher Z elevation, are drawn in front.
-					 * Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
-					 * i.e. X=(left+right)/2, etc.
-					 * However, since we only care about order, don't actually divide / 2
-					 */
-					if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
-							ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
-						continue;
-					}
-				} else {
-					if (ps->xmax < ps2->xmin ||
-							ps->ymax < ps2->ymin ||
-							ps->zmax < ps2->zmin || (
-								ps->xmin < ps2->xmax &&
-								ps->ymin < ps2->ymax &&
-								ps->zmin < ps2->zmax
-							)) {
-						continue;
-					}
-				}
-
-				// Swap the two sprites ps and ps2 using bubble-sort algorithm.
-				psd3 = psd;
-				do {
-					ParentSpriteToDraw* temp = *psd3;
-					*psd3 = ps2;
-					ps2 = temp;
-
-					psd3++;
-				} while (psd3 <= psd2);
-			}
-		} else {
-			psd++;
-		}
-	}
-}
-
-static void ViewportDrawParentSprites(ParentSpriteToDraw *psd[])
-{
-	for (; *psd != NULL; psd++) {
-		const ParentSpriteToDraw* ps = *psd;
-		Point pt = RemapCoords(ps->xmin, ps->ymin, ps->zmin);
-		const ChildScreenSpriteToDraw* cs;
-
-		DrawSprite(ps->image, pt.x, pt.y);
-
-		for (cs = ps->child; cs != NULL; cs = cs->next) {
-			DrawSprite(cs->image, ps->left + cs->x, ps->top + cs->y);
-		}
-	}
-}
-
-static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDraw *ss)
-{
-	DrawPixelInfo dp;
-	byte zoom;
-
-	_cur_dpi = &dp;
-	dp = *dpi;
-
-	zoom = dp.zoom;
-	dp.zoom = 0;
-
-	dp.left >>= zoom;
-	dp.top >>= zoom;
-	dp.width >>= zoom;
-	dp.height >>= zoom;
-
-	do {
-		uint16 colour;
-
-		if (ss->width != 0) {
-			int x = (ss->x >> zoom) - 1;
-			int y = (ss->y >> zoom) - 1;
-			int bottom = y + 11;
-			int w = ss->width;
-
-			if (w & 0x8000) {
-				w &= ~0x8000;
-				y--;
-				bottom -= 6;
-				w -= 3;
-			}
-
-		/* Draw the rectangle if 'tranparent station signs' is off,
-		 * or if we are drawing a general text sign (STR_2806) */
-			if (!(_display_opt & DO_TRANS_SIGNS) || ss->string == STR_2806)
-				DrawFrameRect(
-					x, y, x + w, bottom, ss->color,
-					(_display_opt & DO_TRANS_BUILDINGS) ? FR_TRANSPARENT : 0
-				);
-		}
-
-		SetDParam(0, ss->params[0]);
-		SetDParam(1, ss->params[1]);
-		/* if we didn't draw a rectangle, or if transparant building is on,
-		 * draw the text in the color the rectangle would have */
-		if ((
-					(_display_opt & DO_TRANS_BUILDINGS) ||
-					(_display_opt & DO_TRANS_SIGNS && ss->string != STR_2806)
-				) && ss->width != 0) {
-			/* Real colors need the IS_PALETTE_COLOR flag
-			 * otherwise colors from _string_colormap are assumed. */
-			colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR;
-		} else {
-			colour = 16;
-		}
-		DrawString(
-			ss->x >> zoom, (ss->y >> zoom) - (ss->width & 0x8000 ? 2 : 0),
-			ss->string, colour
-		);
-
-		ss = ss->next;
-	} while (ss != NULL);
-}
-
-void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
-{
-	ViewportDrawer vd;
-	int mask;
-	int x;
-	int y;
-	DrawPixelInfo *old_dpi;
-
-	byte mem[VIEWPORT_DRAW_MEM];
-	ParentSpriteToDraw *parent_list[6144];
-
-	_cur_vd = &vd;
-
-	old_dpi = _cur_dpi;
-	_cur_dpi = &vd.dpi;
-
-	vd.dpi.zoom = vp->zoom;
-	mask = (-1) << vp->zoom;
-
-	vd.combine_sprites = 0;
-
-	vd.dpi.width = (right - left) & mask;
-	vd.dpi.height = (bottom - top) & mask;
-	vd.dpi.left = left & mask;
-	vd.dpi.top = top & mask;
-	vd.dpi.pitch = old_dpi->pitch;
-
-	x = ((vd.dpi.left - (vp->virtual_left&mask)) >> vp->zoom) + vp->left;
-	y = ((vd.dpi.top - (vp->virtual_top&mask)) >> vp->zoom) + vp->top;
-
-	vd.dpi.dst_ptr = old_dpi->dst_ptr + x - old_dpi->left + (y - old_dpi->top) * old_dpi->pitch;
-
-	vd.parent_list = parent_list;
-	vd.eof_parent_list = endof(parent_list);
-	vd.spritelist_mem = mem;
-	vd.eof_spritelist_mem = endof(mem) - sizeof(LARGEST_SPRITELIST_STRUCT);
-	vd.last_string = &vd.first_string;
-	vd.first_string = NULL;
-	vd.last_tile = &vd.first_tile;
-	vd.first_tile = NULL;
-
-	ViewportAddLandscape();
-	ViewportAddVehicles(&vd.dpi);
-	DrawTextEffects(&vd.dpi);
-
-	ViewportAddTownNames(&vd.dpi);
-	ViewportAddStationNames(&vd.dpi);
-	ViewportAddSigns(&vd.dpi);
-	ViewportAddWaypoints(&vd.dpi);
-
-	// This assert should never happen (because the length of the parent_list
-	//  is checked)
-	assert(vd.parent_list <= endof(parent_list));
-
-	if (vd.first_tile != NULL) ViewportDrawTileSprites(vd.first_tile);
-
-	/* null terminate parent sprite list */
-	*vd.parent_list = NULL;
-
-	ViewportSortParentSprites(parent_list);
-	ViewportDrawParentSprites(parent_list);
-
-	if (vd.first_string != NULL) ViewportDrawStrings(&vd.dpi, vd.first_string);
-
-	_cur_dpi = old_dpi;
-}
-
-// Make sure we don't draw a too big area at a time.
-// If we do, the sprite memory will overflow.
-static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
-{
-	if (((bottom - top) * (right - left) << vp->zoom) > 180000) {
-		if ((bottom - top) > (right - left)) {
-			int t = (top + bottom) >> 1;
-			ViewportDrawChk(vp, left, top, right, t);
-			ViewportDrawChk(vp, left, t, right, bottom);
-		} else {
-			int t = (left + right) >> 1;
-			ViewportDrawChk(vp, left, top, t, bottom);
-			ViewportDrawChk(vp, t, top, right, bottom);
-		}
-	} else {
-		ViewportDoDraw(vp,
-			((left - vp->left) << vp->zoom) + vp->virtual_left,
-			((top - vp->top) << vp->zoom) + vp->virtual_top,
-			((right - vp->left) << vp->zoom) + vp->virtual_left,
-			((bottom - vp->top) << vp->zoom) + vp->virtual_top
-		);
-	}
-}
-
-static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
-{
-	if (right <= vp->left || bottom <= vp->top) return;
-
-	if (left >= vp->left + vp->width) return;
-
-	if (left < vp->left) left = vp->left;
-	if (right > vp->left + vp->width) right = vp->left + vp->width;
-
-	if (top >= vp->top + vp->height) return;
-
-	if (top < vp->top) top = vp->top;
-	if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
-
-	ViewportDrawChk(vp, left, top, right, bottom);
-}
-
-void DrawWindowViewport(const Window *w)
-{
-	DrawPixelInfo *dpi = _cur_dpi;
-
-	dpi->left += w->left;
-	dpi->top += w->top;
-
-	ViewportDraw(w->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
-
-	dpi->left -= w->left;
-	dpi->top -= w->top;
-}
-
-void UpdateViewportPosition(Window *w)
-{
-	const ViewPort *vp = w->viewport;
-
-	if (WP(w, vp_d).follow_vehicle != INVALID_VEHICLE) {
-		const Vehicle* veh = GetVehicle(WP(w,vp_d).follow_vehicle);
-		Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
-
-		SetViewportPosition(w, pt.x, pt.y);
-	} else {
-		int x;
-		int y;
-		int vx;
-		int vy;
-
-		// Center of the viewport is hot spot
-		x = WP(w,vp_d).scrollpos_x + vp->virtual_width / 2;
-		y = WP(w,vp_d).scrollpos_y + vp->virtual_height / 2;
-		// Convert viewport coordinates to map coordinates
-		// Calculation is scaled by 4 to avoid rounding errors
-		vx = -x + y * 2;
-		vy =  x + y * 2;
-		// clamp to size of map
-		vx = clamp(vx, 0 * 4, MapMaxX() * TILE_SIZE * 4);
-		vy = clamp(vy, 0 * 4, MapMaxY() * TILE_SIZE * 4);
-		// Convert map coordinates to viewport coordinates
-		x = (-vx + vy) / 2;
-		y = ( vx + vy) / 4;
-		// Set position
-		WP(w, vp_d).scrollpos_x = x - vp->virtual_width / 2;
-		WP(w, vp_d).scrollpos_y = y - vp->virtual_height / 2;
-
-		SetViewportPosition(w, WP(w, vp_d).scrollpos_x, WP(w, vp_d).scrollpos_y);
-	}
-}
-
-static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
-{
-	right -= vp->virtual_left;
-	if (right <= 0) return;
-
-	bottom -= vp->virtual_top;
-	if (bottom <= 0) return;
-
-	left = max(0, left - vp->virtual_left);
-
-	if (left >= vp->virtual_width) return;
-
-	top = max(0, top - vp->virtual_top);
-
-	if (top >= vp->virtual_height) return;
-
-	SetDirtyBlocks(
-		(left >> vp->zoom) + vp->left,
-		(top >> vp->zoom) + vp->top,
-		(right >> vp->zoom) + vp->left,
-		(bottom >> vp->zoom) + vp->top
-	);
-}
-
-void MarkAllViewportsDirty(int left, int top, int right, int bottom)
-{
-	const ViewPort *vp = _viewports;
-	uint32 act = _active_viewports;
-	do {
-		if (act & 1) {
-			assert(vp->width != 0);
-			MarkViewportDirty(vp, left, top, right, bottom);
-		}
-	} while (vp++,act>>=1);
-}
-
-void MarkTileDirtyByTile(TileIndex tile)
-{
-	Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, GetTileZ(tile));
-	MarkAllViewportsDirty(
-		pt.x - 31,
-		pt.y - 122,
-		pt.x - 31 + 67,
-		pt.y - 122 + 154
-	);
-}
-
-void MarkTileDirty(int x, int y)
-{
-	uint z = 0;
-	Point pt;
-
-	if (IS_INT_INSIDE(x, 0, MapSizeX() * TILE_SIZE) &&
-			IS_INT_INSIDE(y, 0, MapSizeY() * TILE_SIZE))
-		z = GetTileZ(TileVirtXY(x, y));
-	pt = RemapCoords(x, y, z);
-
-	MarkAllViewportsDirty(
-		pt.x - 31,
-		pt.y - 122,
-		pt.x - 31 + 67,
-		pt.y - 122 + 154
-	);
-}
-
-static void SetSelectionTilesDirty(void)
-{
-	int y_size, x_size;
-	int x = _thd.pos.x;
-	int y = _thd.pos.y;
-
-	x_size = _thd.size.x;
-	y_size = _thd.size.y;
-
-	if (_thd.outersize.x) {
-		x_size += _thd.outersize.x;
-		x += _thd.offs.x;
-		y_size += _thd.outersize.y;
-		y += _thd.offs.y;
-	}
-
-	assert(x_size > 0);
-	assert(y_size > 0);
-
-	x_size += x;
-	y_size += y;
-
-	do {
-		int y_bk = y;
-		do {
-			MarkTileDirty(x, y);
-		} while ( (y += TILE_SIZE) != y_size);
-		y = y_bk;
-	} while ( (x += TILE_SIZE) != x_size);
-}
-
-
-void SetSelectionRed(bool b)
-{
-	_thd.make_square_red = b;
-	SetSelectionTilesDirty();
-}
-
-
-static bool CheckClickOnTown(const ViewPort *vp, int x, int y)
-{
-	const Town *t;
-
-	if (!(_display_opt & DO_SHOW_TOWN_NAMES)) return false;
-
-	switch (vp->zoom) {
-		case 0:
-			x = x - vp->left + vp->virtual_left;
-			y = y - vp->top  + vp->virtual_top;
-			FOR_ALL_TOWNS(t) {
-				if (y >= t->sign.top &&
-						y < t->sign.top + 12 &&
-						x >= t->sign.left &&
-						x < t->sign.left + t->sign.width_1) {
-					ShowTownViewWindow(t->index);
-					return true;
-				}
-			}
-			break;
-
-		case 1:
-			x = (x - vp->left + 1) * 2 + vp->virtual_left;
-			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
-			FOR_ALL_TOWNS(t) {
-				if (y >= t->sign.top &&
-						y < t->sign.top + 24 &&
-						x >= t->sign.left &&
-						x < t->sign.left + t->sign.width_1 * 2) {
-					ShowTownViewWindow(t->index);
-					return true;
-				}
-			}
-			break;
-
-		default:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
-			FOR_ALL_TOWNS(t) {
-				if (y >= t->sign.top &&
-						y < t->sign.top + 24 &&
-						x >= t->sign.left &&
-						x < t->sign.left + t->sign.width_2 * 4) {
-					ShowTownViewWindow(t->index);
-					return true;
-				}
-			}
-			break;
-	}
-
-	return false;
-}
-
-
-static bool CheckClickOnStation(const ViewPort *vp, int x, int y)
-{
-	const Station *st;
-
-	if (!(_display_opt & DO_SHOW_STATION_NAMES)) return false;
-
-	switch (vp->zoom) {
-		case 0:
-			x = x - vp->left + vp->virtual_left;
-			y = y - vp->top  + vp->virtual_top;
-			FOR_ALL_STATIONS(st) {
-				if (y >= st->sign.top &&
-						y < st->sign.top + 12 &&
-						x >= st->sign.left &&
-						x < st->sign.left + st->sign.width_1) {
-					ShowStationViewWindow(st->index);
-					return true;
-				}
-			}
-			break;
-
-		case 1:
-			x = (x - vp->left + 1) * 2 + vp->virtual_left;
-			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
-			FOR_ALL_STATIONS(st) {
-				if (y >= st->sign.top &&
-						y < st->sign.top + 24 &&
-						x >= st->sign.left &&
-						x < st->sign.left + st->sign.width_1 * 2) {
-					ShowStationViewWindow(st->index);
-					return true;
-				}
-			}
-			break;
-
-		default:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
-			FOR_ALL_STATIONS(st) {
-				if (y >= st->sign.top &&
-						y < st->sign.top + 24 &&
-						x >= st->sign.left &&
-						x < st->sign.left + st->sign.width_2 * 4) {
-					ShowStationViewWindow(st->index);
-					return true;
-				}
-			}
-			break;
-	}
-
-	return false;
-}
-
-
-static bool CheckClickOnSign(const ViewPort *vp, int x, int y)
-{
-	const Sign *si;
-
-	if (!(_display_opt & DO_SHOW_SIGNS)) return false;
-
-	switch (vp->zoom) {
-		case 0:
-			x = x - vp->left + vp->virtual_left;
-			y = y - vp->top  + vp->virtual_top;
-			FOR_ALL_SIGNS(si) {
-				if (y >= si->sign.top &&
-						y <  si->sign.top + 12 &&
-						x >= si->sign.left &&
-						x <  si->sign.left + si->sign.width_1) {
-					ShowRenameSignWindow(si);
-					return true;
-				}
-			}
-			break;
-
-		case 1:
-			x = (x - vp->left + 1) * 2 + vp->virtual_left;
-			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
-			FOR_ALL_SIGNS(si) {
-				if (y >= si->sign.top &&
-						y <  si->sign.top + 24 &&
-						x >= si->sign.left &&
-						x <  si->sign.left + si->sign.width_1 * 2) {
-					ShowRenameSignWindow(si);
-					return true;
-				}
-			}
-			break;
-
-		default:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
-			FOR_ALL_SIGNS(si) {
-				if (y >= si->sign.top &&
-						y <  si->sign.top + 24 &&
-						x >= si->sign.left &&
-						x <  si->sign.left + si->sign.width_2 * 4) {
-					ShowRenameSignWindow(si);
-					return true;
-				}
-			}
-			break;
-	}
-
-	return false;
-}
-
-
-static bool CheckClickOnWaypoint(const ViewPort *vp, int x, int y)
-{
-	const Waypoint *wp;
-
-	if (!(_display_opt & DO_WAYPOINTS)) return false;
-
-	switch (vp->zoom) {
-		case 0:
-			x = x - vp->left + vp->virtual_left;
-			y = y - vp->top  + vp->virtual_top;
-			FOR_ALL_WAYPOINTS(wp) {
-				if (y >= wp->sign.top &&
-						y < wp->sign.top + 12 &&
-						x >= wp->sign.left &&
-						x < wp->sign.left + wp->sign.width_1) {
-					ShowRenameWaypointWindow(wp);
-					return true;
-				}
-			}
-			break;
-
-		case 1:
-			x = (x - vp->left + 1) * 2 + vp->virtual_left;
-			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
-			FOR_ALL_WAYPOINTS(wp) {
-				if (y >= wp->sign.top &&
-						y < wp->sign.top + 24 &&
-						x >= wp->sign.left &&
-						x < wp->sign.left + wp->sign.width_1 * 2) {
-					ShowRenameWaypointWindow(wp);
-					return true;
-				}
-			}
-			break;
-
-		default:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
-			FOR_ALL_WAYPOINTS(wp) {
-				if (y >= wp->sign.top &&
-						y < wp->sign.top + 24 &&
-						x >= wp->sign.left &&
-						x < wp->sign.left + wp->sign.width_2 * 4) {
-					ShowRenameWaypointWindow(wp);
-					return true;
-				}
-			}
-			break;
-	}
-
-	return false;
-}
-
-
-static void CheckClickOnLandscape(const ViewPort *vp, int x, int y)
-{
-	Point pt = TranslateXYToTileCoord(vp, x, y);
-
-	if (pt.x != -1) ClickTile(TileVirtXY(pt.x, pt.y));
-}
-
-
-static void SafeShowTrainViewWindow(const Vehicle* v)
-{
-	if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
-	ShowTrainViewWindow(v);
-}
-
-static void Nop(const Vehicle *v) {}
-
-typedef void OnVehicleClickProc(const Vehicle *v);
-static OnVehicleClickProc* const _on_vehicle_click_proc[] = {
-	SafeShowTrainViewWindow,
-	ShowRoadVehViewWindow,
-	ShowShipViewWindow,
-	ShowAircraftViewWindow,
-	Nop, // Special vehicles
-	Nop  // Disaster vehicles
-};
-
-void HandleViewportClicked(const ViewPort *vp, int x, int y)
-{
-	const Vehicle *v;
-
-	if (CheckClickOnTown(vp, x, y)) return;
-	if (CheckClickOnStation(vp, x, y)) return;
-	if (CheckClickOnSign(vp, x, y)) return;
-	if (CheckClickOnWaypoint(vp, x, y)) return;
-	CheckClickOnLandscape(vp, x, y);
-
-	v = CheckClickOnVehicle(vp, x, y);
-	if (v != NULL) {
-		DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v);
-		_on_vehicle_click_proc[v->type - 0x10](v);
-	}
-}
-
-Vehicle *CheckMouseOverVehicle(void)
-{
-	const Window *w;
-	const ViewPort *vp;
-
-	int x = _cursor.pos.x;
-	int y = _cursor.pos.y;
-
-	w = FindWindowFromPt(x, y);
-	if (w == NULL) return NULL;
-
-	vp = IsPtInWindowViewport(w, x, y);
-	return (vp != NULL) ? CheckClickOnVehicle(vp, x, y) : NULL;
-}
-
-
-
-void PlaceObject(void)
-{
-	Point pt;
-	Window *w;
-
-	pt = GetTileBelowCursor();
-	if (pt.x == -1) return;
-
-	if (_thd.place_mode == VHM_POINT) {
-		pt.x += 8;
-		pt.y += 8;
-	}
-
-	_tile_fract_coords.x = pt.x & 0xF;
-	_tile_fract_coords.y = pt.y & 0xF;
-
-	w = GetCallbackWnd();
-	if (w != NULL) {
-		WindowEvent e;
-
-		e.event = WE_PLACE_OBJ;
-		e.we.place.pt = pt;
-		e.we.place.tile = TileVirtXY(pt.x, pt.y);
-		w->wndproc(w, &e);
-	}
-}
-
-
-/* scrolls the viewport in a window to a given location */
-bool ScrollWindowTo(int x , int y, Window *w)
-{
-	Point pt;
-
-	pt = MapXYZToViewport(w->viewport, x, y, GetSlopeZ(x, y));
-	WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
-
-	if (WP(w, vp_d).scrollpos_x == pt.x && WP(w, vp_d).scrollpos_y == pt.y)
-		return false;
-
-	WP(w, vp_d).scrollpos_x = pt.x;
-	WP(w, vp_d).scrollpos_y = pt.y;
-	return true;
-}
-
-
-bool ScrollMainWindowTo(int x, int y)
-{
-	Window *w;
-	bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0));
-
-	/* If a user scrolls to a tile (via what way what so ever) and already is on
-	 *  that tile (e.g.: pressed twice), move the smallmap to that location,
-	 *  so you directly see where you are on the smallmap. */
-
-	if (res) return res;
-
-	w = FindWindowById(WC_SMALLMAP, 0);
-	if (w == NULL) return res;
-
-	SmallMapCenterOnCurrentPos(w);
-
-	return res;
-}
-
-
-bool ScrollMainWindowToTile(TileIndex tile)
-{
-	return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2);
-}
-
-void SetRedErrorSquare(TileIndex tile)
-{
-	TileIndex old;
-
-	old = _thd.redsq;
-	_thd.redsq = tile;
-
-	if (tile != old) {
-		if (tile != 0) MarkTileDirtyByTile(tile);
-		if (old  != 0) MarkTileDirtyByTile(old);
-	}
-}
-
-void SetTileSelectSize(int w, int h)
-{
-	_thd.new_size.x = w * TILE_SIZE;
-	_thd.new_size.y = h * TILE_SIZE;
-	_thd.new_outersize.x = 0;
-	_thd.new_outersize.y = 0;
-}
-
-void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
-{
-	_thd.offs.x = ox * TILE_SIZE;
-	_thd.offs.y = oy * TILE_SIZE;
-	_thd.new_outersize.x = sx * TILE_SIZE;
-	_thd.new_outersize.y = sy * TILE_SIZE;
-}
-
-/* returns the best autorail highlight type from map coordinates */
-static byte GetAutorailHT(int x, int y)
-{
-	return HT_RAIL | _AutorailPiece[x & 0xF][y & 0xF];
-}
-
-// called regular to update tile highlighting in all cases
-void UpdateTileSelection(void)
-{
-	int x1;
-	int y1;
-
-	_thd.new_drawstyle = 0;
-
-	if (_thd.place_mode == VHM_SPECIAL) {
-		x1 = _thd.selend.x;
-		y1 = _thd.selend.y;
-		if (x1 != -1) {
-			int x2 = _thd.selstart.x;
-			int y2 = _thd.selstart.y;
-			x1 &= ~0xF;
-			y1 &= ~0xF;
-
-			if (x1 >= x2) intswap(x1,x2);
-			if (y1 >= y2) intswap(y1,y2);
-			_thd.new_pos.x = x1;
-			_thd.new_pos.y = y1;
-			_thd.new_size.x = x2 - x1 + TILE_SIZE;
-			_thd.new_size.y = y2 - y1 + TILE_SIZE;
-			_thd.new_drawstyle = _thd.next_drawstyle;
-		}
-	} else if (_thd.place_mode != VHM_NONE) {
-		Point pt = GetTileBelowCursor();
-		x1 = pt.x;
-		y1 = pt.y;
-		if (x1 != -1) {
-			switch (_thd.place_mode) {
-				case VHM_RECT:
-					_thd.new_drawstyle = HT_RECT;
-					break;
-				case VHM_POINT:
-					_thd.new_drawstyle = HT_POINT;
-					x1 += 8;
-					y1 += 8;
-					break;
-				case VHM_RAIL:
-					_thd.new_drawstyle = GetAutorailHT(pt.x, pt.y); // draw one highlighted tile
-			}
-			_thd.new_pos.x = x1 & ~0xF;
-			_thd.new_pos.y = y1 & ~0xF;
-		}
-	}
-
-	// redraw selection
-	if (_thd.drawstyle != _thd.new_drawstyle ||
-			_thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
-			_thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
-	    _thd.outersize.x != _thd.new_outersize.x ||
-	    _thd.outersize.y != _thd.new_outersize.y) {
-		// clear the old selection?
-		if (_thd.drawstyle) SetSelectionTilesDirty();
-
-		_thd.drawstyle = _thd.new_drawstyle;
-		_thd.pos = _thd.new_pos;
-		_thd.size = _thd.new_size;
-		_thd.outersize = _thd.new_outersize;
-		_thd.dirty = 0xff;
-
-		// draw the new selection?
-		if (_thd.new_drawstyle) SetSelectionTilesDirty();
-	}
-}
-
-// highlighting tiles while only going over them with the mouse
-void VpStartPlaceSizing(TileIndex tile, int user)
-{
-	_thd.userdata = user;
-	_thd.selend.x = TileX(tile) * TILE_SIZE;
-	_thd.selstart.x = TileX(tile) * TILE_SIZE;
-	_thd.selend.y = TileY(tile) * TILE_SIZE;
-	_thd.selstart.y = TileY(tile) * TILE_SIZE;
-	if (_thd.place_mode == VHM_RECT) {
-		_thd.place_mode = VHM_SPECIAL;
-		_thd.next_drawstyle = HT_RECT;
-	} else if (_thd.place_mode == VHM_RAIL) { // autorail one piece
-		_thd.place_mode = VHM_SPECIAL;
-		_thd.next_drawstyle = _thd.drawstyle;
-	} else {
-		_thd.place_mode = VHM_SPECIAL;
-		_thd.next_drawstyle = HT_POINT;
-	}
-	_special_mouse_mode = WSM_SIZING;
-}
-
-void VpSetPlaceSizingLimit(int limit)
-{
-	_thd.sizelimit = limit;
-}
-
-/**
-* Highlights all tiles between a set of two tiles. Used in dock and tunnel placement
-* @param from TileIndex of the first tile to highlight
-* @param to TileIndex of the last tile to highlight */
-void VpSetPresizeRange(TileIndex from, TileIndex to)
-{
-	uint distance = DistanceManhattan(from, to) + 1;
-
-	_thd.selend.x = TileX(to) * TILE_SIZE;
-	_thd.selend.y = TileY(to) * TILE_SIZE;
-	_thd.selstart.x = TileX(from) * TILE_SIZE;
-	_thd.selstart.y = TileY(from) * TILE_SIZE;
-	_thd.next_drawstyle = HT_RECT;
-
-	/* show measurement only if there is any length to speak of */
-	if (distance > 1) GuiShowTooltipsWithArgs(STR_MEASURE_LENGTH, 1, &distance);
-}
-
-static void VpStartPreSizing(void)
-{
-	_thd.selend.x = -1;
-	_special_mouse_mode = WSM_PRESIZE;
-}
-
-/* returns information about the 2x1 piece to be build.
- * The lower bits (0-3) are the track type. */
-static byte Check2x1AutoRail(int mode)
-{
-	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
-	int sxpy = (_thd.selend.x & 0xF) + (_thd.selend.y & 0xF);
-	int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
-	int sxmy = (_thd.selend.x & 0xF) - (_thd.selend.y & 0xF);
-
-	switch (mode) {
-	case 0: // end piece is lower right
-		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
-		if (fxmy < -3 && sxmy > 3) {/* DoRailroadTrack(0); */return 5; }
-		return 1;
-
-	case 1:
-		if (fxmy > 3 && sxmy < -3) { /*SwapSelection(); DoRailroadTrack(0); */return 4; }
-		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
-		return 1;
-
-	case 2:
-		if (fxmy > 3 && sxmy < -3) { /*DoRailroadTrack(3);*/ return 4; }
-		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
-		return 0;
-
-	case 3:
-		if (fxmy < -3 && sxmy > 3) { /*SwapSelection(); DoRailroadTrack(3);*/ return 5; }
-		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
-		return 0;
-	}
-
-	return 0; // avoids compiler warnings
-}
-
-/** Check if the direction of start and end tile should be swapped based on
- * the dragging-style. Default directions are:
- * in the case of a line (HT_RAIL, HT_LINE):  DIR_NE, DIR_NW, DIR_N, DIR_E
- * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E
- * For example dragging a rectangle area from south to north should be swapped to
- * north-south (DIR_S) to obtain the same results with less code. This is what
- * the return value signifies.
- * @param style HighLightStyle dragging style
- * @param start_tile, end_tile start and end tile of drag
- * @param boolean value which when true means start/end should be swapped */
-static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
-{
-	uint start_x = TileX(start_tile);
-	uint start_y = TileY(start_tile);
-	uint end_x = TileX(end_tile);
-	uint end_y = TileY(end_tile);
-
-	switch (style & HT_DRAG_MASK) {
-		case HT_RAIL:
-		case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
-
-		case HT_RECT:
-		case HT_POINT: return (end_x != start_x && end_y < start_y);
-		default: NOT_REACHED();
-	}
-
-	return false;
-}
-
-/** Calculates height difference between one tile and another
-* Multiplies the result to suit the standard given by minimap - 50 meters high
-* To correctly get the height difference we need the direction we are dragging
-* in, as well as with what kind of tool we are dragging. For example a horizontal
-* autorail tool that starts in bottom and ends at the top of a tile will need the
-* maximum of SW,S and SE,N corners respectively. This is handled by the lookup table below
-* See _tileoffs_by_dir in map.c for the direction enums if you can't figure out
-* the values yourself.
-* @param style HightlightStyle of drag. This includes direction and style (autorail, rect, etc.)
-* @param distance amount of tiles dragged, important for horizontal/vertical drags
-*        ignored for others
-* @param start_tile, end_tile start and end tile of drag operation
-* @return height difference between two tiles. Tile measurement tool utilizes
-* this value in its tooltips */
-static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
-{
-	bool swap = SwapDirection(style, start_tile, end_tile);
-	byte style_t;
-	uint h0, h1, ht; // start heigth, end height, and temp variable
-
-	if (start_tile == end_tile) return 0;
-	if (swap) swap_tile(&start_tile, &end_tile);
-
-	switch (style & HT_DRAG_MASK) {
-		case HT_RECT: {
-			static const TileIndexDiffC heightdiff_area_by_dir[] = {
-				/* Start */ {1, 0}, /* Dragging east */ {0, 0}, /* Dragging south */
-				/* End   */ {0, 1}, /* Dragging east */ {1, 1}  /* Dragging south */
-			};
-
-			/* In the case of an area we can determine whether we were dragging south or
-			 * east by checking the X-coordinates of the tiles */
-			style_t = (byte)(TileX(end_tile) > TileX(start_tile));
-			start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t]));
-			end_tile   = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t]));
-		}
-		/* Fallthrough */
-		case HT_POINT:
-			h0 = TileHeight(start_tile);
-			h1 = TileHeight(end_tile);
-			break;
-		default: { /* All other types, this is mostly only line/autorail */
-			static const HighLightStyle flip_style_direction[] = {
-				HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL
-			};
-			static const TileIndexDiffC heightdiff_line_by_dir[] = {
-				/* Start */ {1, 0}, {1, 1}, /* HT_DIR_X  */ {0, 1}, {1, 1}, /* HT_DIR_Y  */
-				/* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, /* HT_DIR_HL */
-				/* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, /* HT_DIR_VR */
-
-				/* Start */ {0, 1}, {0, 0}, /* HT_DIR_X  */ {1, 0}, {0, 0}, /* HT_DIR_Y  */
-				/* End   */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, /* HT_DIR_HL */
-				/* End   */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, /* HT_DIR_VR */
-			};
-
-			distance %= 2; // we're only interested if the distance is even or uneven
-			style &= HT_DIR_MASK;
-
-			/* To handle autorail, we do some magic to be able to use a lookup table.
-			 * Firstly if we drag the other way around, we switch start&end, and if needed
-			 * also flip the drag-position. Eg if it was on the left, and the distance is even
-			 * that means the end, which is now the start is on the right */
-			if (swap && distance == 0) style = flip_style_direction[style];
-
-			/* Use lookup table for start-tile based on HighLightStyle direction */
-			style_t = style * 2;
-			assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
-			h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t])));
-			ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1])));
-			h0 = maxu(h0, ht);
-
-			/* Use lookup table for end-tile based on HighLightStyle direction
-			 * flip around side (lower/upper, left/right) based on distance */
-			if (distance == 0) style_t = flip_style_direction[style] * 2;
-			assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
-			h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t])));
-			ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1])));
-			h1 = maxu(h1, ht);
-		} break;
-	}
-
-	if (swap) swap_uint32(&h0, &h1);
-	/* Minimap shows height in intervals of 50 meters, let's do the same */
-	return (int)(h1 - h0) * 50;
-}
-
-static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
-
-// while dragging
-static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method)
-{
-	HighLightStyle b;
-	uint w, h;
-
-	int dx = thd->selstart.x - (thd->selend.x & ~0xF);
-	int dy = thd->selstart.y - (thd->selend.y & ~0xF);
-	w = myabs(dx) + 16;
-	h = myabs(dy) + 16;
-
-	if (TileVirtXY(thd->selstart.x, thd->selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile
-		if (method == VPM_RAILDIRS) {
-			b = GetAutorailHT(x, y);
-		} else { // rect for autosignals on one tile
-			b = HT_RECT;
-		}
-	} else if (h == 16) { // Is this in X direction?
-		if (dx == 16) { // 2x1 special handling
-			b = (Check2x1AutoRail(3)) | HT_LINE;
-		} else if (dx == -16) {
-			b = (Check2x1AutoRail(2)) | HT_LINE;
-		} else {
-			b = HT_LINE | HT_DIR_X;
-		}
-		y = thd->selstart.y;
-	} else if (w == 16) { // Or Y direction?
-		if (dy == 16) { // 2x1 special handling
-			b = (Check2x1AutoRail(1)) | HT_LINE;
-		} else if (dy == -16) { // 2x1 other direction
-			b = (Check2x1AutoRail(0)) | HT_LINE;
-		} else {
-			b = HT_LINE | HT_DIR_Y;
-		}
-		x = thd->selstart.x;
-	} else if (w > h * 2) { // still count as x dir?
-		b = HT_LINE | HT_DIR_X;
-		y = thd->selstart.y;
-	} else if (h > w * 2) { // still count as y dir?
-		b = HT_LINE | HT_DIR_Y;
-		x = thd->selstart.x;
-	} else { // complicated direction
-		int d = w - h;
-		thd->selend.x = thd->selend.x & ~0xF;
-		thd->selend.y = thd->selend.y & ~0xF;
-
-		// four cases.
-		if (x > thd->selstart.x) {
-			if (y > thd->selstart.y) {
-				// south
-				if (d == 0) {
-					b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
-				} else if (d >= 0) {
-					x = thd->selstart.x + h;
-					b = HT_LINE | HT_DIR_VL;
-					// return px == py || px == py + 16;
-				} else {
-					y = thd->selstart.y + w;
-					b = HT_LINE | HT_DIR_VR;
-				} // return px == py || px == py - 16;
-			} else {
-				// west
-				if (d == 0) {
-					b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
-				} else if (d >= 0) {
-					x = thd->selstart.x + h;
-					b = HT_LINE | HT_DIR_HL;
-				} else {
-					y = thd->selstart.y - w;
-					b = HT_LINE | HT_DIR_HU;
-				}
-			}
-		} else {
-			if (y > thd->selstart.y) {
-				// east
-				if (d == 0) {
-					b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
-				} else if (d >= 0) {
-					x = thd->selstart.x - h;
-					b = HT_LINE | HT_DIR_HU;
-					// return px == -py || px == -py - 16;
-				} else {
-					y = thd->selstart.y + w;
-					b = HT_LINE | HT_DIR_HL;
-				} // return px == -py || px == -py + 16;
-			} else {
-				// north
-				if (d == 0) {
-					b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
-				} else if (d >= 0) {
-					x = thd->selstart.x - h;
-					b = HT_LINE | HT_DIR_VR;
-					// return px == py || px == py - 16;
-				} else {
-					y = thd->selstart.y - w;
-					b = HT_LINE | HT_DIR_VL;
-				} //return px == py || px == py + 16;
-			}
-		}
-	}
-
-	if (_patches.measure_tooltip) {
-		TileIndex t0 = TileVirtXY(thd->selstart.x, thd->selstart.y);
-		TileIndex t1 = TileVirtXY(x, y);
-		uint distance = DistanceManhattan(t0, t1) + 1;
-		byte index = 0;
-		uint params[2];
-
-		if (distance != 1) {
-			int heightdiff = CalcHeightdiff(b, distance, t0, t1);
-			/* If we are showing a tooltip for horizontal or vertical drags,
-			 * 2 tiles have a length of 1. To bias towards the ceiling we add
-			 * one before division. It feels more natural to count 3 lengths as 2 */
-			if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
-				distance = (distance + 1) / 2;
-			}
-
-			params[index++] = distance;
-			if (heightdiff != 0) params[index++] = heightdiff;
-		}
-
-		GuiShowTooltipsWithArgs(measure_strings_length[index], index, params);
-	}
-
-	thd->selend.x = x;
-	thd->selend.y = y;
-	thd->next_drawstyle = b;
-}
-
-/**
- * Selects tiles while dragging
- * @param x X coordinate of end of selection
- * @param y Y coordinate of end of selection
- * @param method modifies the way tiles are selected. Possible
- * methods are VPM_* in viewport.h */
-void VpSelectTilesWithMethod(int x, int y, int method)
-{
-	int sx, sy;
-	HighLightStyle style;
-
-	if (x == -1) {
-		_thd.selend.x = -1;
-		return;
-	}
-
-	/* Special handling of drag in any (8-way) direction */
-	if (method == VPM_RAILDIRS || method == VPM_SIGNALDIRS) {
-		_thd.selend.x = x;
-		_thd.selend.y = y;
-		CalcRaildirsDrawstyle(&_thd, x, y, method);
-		return;
-	}
-
-	if (_thd.next_drawstyle == HT_POINT) {
-		x += TILE_SIZE / 2;
-		y += TILE_SIZE / 2;
-	}
-
-	sx = _thd.selstart.x;
-	sy = _thd.selstart.y;
-
-	switch (method) {
-		case VPM_X_OR_Y: /* drag in X or Y direction */
-			if (myabs(sy - y) < myabs(sx - x)) {
-				y = sy;
-				style = HT_DIR_X;
-			} else {
-				x = sx;
-				style = HT_DIR_Y;
-			}
-			goto calc_heightdiff_single_direction;
-		case VPM_FIX_X: /* drag in Y direction */
-			x = sx;
-			style = HT_DIR_Y;
-			goto calc_heightdiff_single_direction;
-		case VPM_FIX_Y: /* drag in X direction */
-			y = sy;
-			style = HT_DIR_X;
-
-calc_heightdiff_single_direction:;
-			if (_patches.measure_tooltip) {
-				TileIndex t0 = TileVirtXY(sx, sy);
-				TileIndex t1 = TileVirtXY(x, y);
-				uint distance = DistanceManhattan(t0, t1) + 1;
-				byte index = 0;
-				uint params[2];
-
-				if (distance != 1) {
-					/* With current code passing a HT_LINE style to calculate the height
-					 * difference is enough. However if/when a point-tool is created
-					 * with this method, function should be called with new_style (below)
-					 * instead of HT_LINE | style case HT_POINT is handled specially
-					 * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
-					int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1);
-
-					params[index++] = distance;
-					if (heightdiff != 0) params[index++] = heightdiff;
-				}
-
-				GuiShowTooltipsWithArgs(measure_strings_length[index], index, params);
-			} break;
-
-		case VPM_X_AND_Y_LIMITED: { /* drag an X by Y constrained rect area */
-			int limit = (_thd.sizelimit - 1) * TILE_SIZE;
-			x = sx + clamp(x - sx, -limit, limit);
-			y = sy + clamp(y - sy, -limit, limit);
-			/* Fallthrough */
-		case VPM_X_AND_Y: /* drag an X by Y area */
-			if (_patches.measure_tooltip) {
-				static const StringID measure_strings_area[] = {
-					STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
-				};
-
-				TileIndex t0 = TileVirtXY(sx, sy);
-				TileIndex t1 = TileVirtXY(x, y);
-				uint dx = abs(TileX(t0) - TileX(t1)) + 1;
-				uint dy = abs(TileY(t0) - TileY(t1)) + 1;
-				byte index = 0;
-				uint params[3];
-
-				/* If dragging an area (eg dynamite tool) and it is actually a single
-				 * row/column, change the type to 'line' to get proper calculation for height */
-				style = _thd.next_drawstyle;
-				if (style & HT_RECT) {
-					if (dx == 1) {
-						style = HT_LINE | HT_DIR_Y;
-					} else if (dy == 1) {
-						style = HT_LINE | HT_DIR_X;
-					}
-				}
-
-				if (dx != 1 || dy != 1) {
-					int heightdiff = CalcHeightdiff(style, 0, t0, t1);
-
-					params[index++] = dx;
-					params[index++] = dy;
-					if (heightdiff != 0) params[index++] = heightdiff;
-				}
-
-				GuiShowTooltipsWithArgs(measure_strings_area[index], index, params);
-			}
-		break;
-
-		}
-		default: NOT_REACHED();
-	}
-
-	_thd.selend.x = x;
-	_thd.selend.y = y;
-}
-
-// while dragging
-bool VpHandlePlaceSizingDrag(void)
-{
-	Window *w;
-	WindowEvent e;
-
-	if (_special_mouse_mode != WSM_SIZING) return true;
-
-	e.we.place.userdata = _thd.userdata;
-
-	// stop drag mode if the window has been closed
-	w = FindWindowById(_thd.window_class,_thd.window_number);
-	if (w == NULL) {
-		ResetObjectToPlace();
-		return false;
-	}
-
-	// while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() )
-	if (_left_button_down) {
-		e.event = WE_PLACE_DRAG;
-		e.we.place.pt = GetTileBelowCursor();
-		w->wndproc(w, &e);
-		return false;
-	}
-
-	// mouse button released..
-	// keep the selected tool, but reset it to the original mode.
-	_special_mouse_mode = WSM_NONE;
-	if (_thd.next_drawstyle == HT_RECT) {
-		_thd.place_mode = VHM_RECT;
-	} else if ((e.we.place.userdata & 0xF) == VPM_SIGNALDIRS) { // some might call this a hack... -- Dominik
-		_thd.place_mode = VHM_RECT;
-	} else if (_thd.next_drawstyle & HT_LINE) {
-		_thd.place_mode = VHM_RAIL;
-	} else if (_thd.next_drawstyle & HT_RAIL) {
-		_thd.place_mode = VHM_RAIL;
-	} else {
-		_thd.place_mode = VHM_POINT;
-	}
-	SetTileSelectSize(1, 1);
-
-	// and call the mouseup event.
-	e.event = WE_PLACE_MOUSEUP;
-	e.we.place.pt = _thd.selend;
-	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
-	e.we.place.starttile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
-	w->wndproc(w, &e);
-
-	return false;
-}
-
-void SetObjectToPlaceWnd(CursorID icon, byte mode, Window *w)
-{
-	SetObjectToPlace(icon, mode, w->window_class, w->window_number);
-}
-
-#include "table/animcursors.h"
-
-void SetObjectToPlace(CursorID icon, byte mode, WindowClass window_class, WindowNumber window_num)
-{
-	Window *w;
-
-	// undo clicking on button
-	if (_thd.place_mode != 0) {
-		_thd.place_mode = 0;
-		w = FindWindowById(_thd.window_class, _thd.window_number);
-		if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ);
-	}
-
-	SetTileSelectSize(1, 1);
-
-	_thd.make_square_red = false;
-
-	if (mode == VHM_DRAG) { // mode 4 is for dragdropping trains in the depot window
-		mode = 0;
-		_special_mouse_mode = WSM_DRAGDROP;
-	} else {
-		_special_mouse_mode = WSM_NONE;
-	}
-
-	_thd.place_mode = mode;
-	_thd.window_class = window_class;
-	_thd.window_number = window_num;
-
-	if (mode == VHM_SPECIAL) // special tools, like tunnels or docks start with presizing mode
-		VpStartPreSizing();
-
-	if ( (int)icon < 0)
-		SetAnimatedMouseCursor(_animcursors[~icon]);
-	else
-		SetMouseCursor(icon);
-}
-
-void ResetObjectToPlace(void)
-{
-	SetObjectToPlace(SPR_CURSOR_MOUSE, VHM_NONE, 0, 0);
-}
new file mode 100644
--- /dev/null
+++ b/src/viewport.cpp
@@ -0,0 +1,2462 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "gui.h"
+#include "spritecache.h"
+#include "strings.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "map.h"
+#include "viewport.h"
+#include "window.h"
+#include "vehicle.h"
+#include "station.h"
+#include "gfx.h"
+#include "town.h"
+#include "signs.h"
+#include "waypoint.h"
+#include "variables.h"
+#include "train.h"
+
+#define VIEWPORT_DRAW_MEM (65536 * 2)
+
+/* viewport.c */
+// XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar)
+static ViewPort _viewports[25 - 2];
+static uint32 _active_viewports;    ///< bitmasked variable where each bit signifies if a viewport is in use or not
+assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8);
+
+static bool _added_tile_sprite;
+static bool _offset_ground_sprites;
+
+/* The in-game coordiante system looks like this *
+ *                                               *
+ *                    ^ Z                        *
+ *                    |                          *
+ *                    |                          *
+ *                    |                          *
+ *                    |                          *
+ *                 /     \                       *
+ *              /           \                    *
+ *           /                 \                 *
+ *        /                       \              *
+ *   X <                             > Y         *
+ */
+
+typedef struct StringSpriteToDraw {
+	uint16 string;
+	uint16 color;
+	struct StringSpriteToDraw *next;
+	int32 x;
+	int32 y;
+	uint32 params[2];
+	uint16 width;
+} StringSpriteToDraw;
+
+typedef struct TileSpriteToDraw {
+	uint32 image;
+	struct TileSpriteToDraw *next;
+	int32 x;
+	int32 y;
+	byte z;
+} TileSpriteToDraw;
+
+typedef struct ChildScreenSpriteToDraw {
+	uint32 image;
+	int32 x;
+	int32 y;
+	struct ChildScreenSpriteToDraw *next;
+} ChildScreenSpriteToDraw;
+
+typedef struct ParentSpriteToDraw {
+	uint32 image;
+	int32 left;
+	int32 top;
+	int32 right;
+	int32 bottom;
+	int32 xmin;
+	int32 ymin;
+	int32 xmax;
+	int32 ymax;
+	ChildScreenSpriteToDraw *child;
+	byte unk16;
+	byte zmin;
+	byte zmax;
+} ParentSpriteToDraw;
+
+// Quick hack to know how much memory to reserve when allocating from the spritelist
+// to prevent a buffer overflow.
+#define LARGEST_SPRITELIST_STRUCT ParentSpriteToDraw
+
+typedef struct ViewportDrawer {
+	DrawPixelInfo dpi;
+
+	byte *spritelist_mem;
+	const byte *eof_spritelist_mem;
+
+	StringSpriteToDraw **last_string, *first_string;
+	TileSpriteToDraw **last_tile, *first_tile;
+
+	ChildScreenSpriteToDraw **last_child;
+
+	ParentSpriteToDraw **parent_list;
+	ParentSpriteToDraw * const *eof_parent_list;
+
+	byte combine_sprites;
+
+	int offs_x, offs_y; // used when drawing ground sprites relative
+} ViewportDrawer;
+
+static ViewportDrawer *_cur_vd;
+
+TileHighlightData _thd;
+static TileInfo *_cur_ti;
+
+extern void SmallMapCenterOnCurrentPos(Window *w);
+
+static Point MapXYZToViewport(const ViewPort *vp, uint x, uint y, uint z)
+{
+	Point p = RemapCoords(x, y, z);
+	p.x -= vp->virtual_width / 2;
+	p.y -= vp->virtual_height / 2;
+	return p;
+}
+
+void InitViewports(void) {
+	memset(_viewports, 0, sizeof(_viewports));
+	_active_viewports = 0;
+}
+
+void DeleteWindowViewport(Window *w)
+{
+	CLRBIT(_active_viewports, w->viewport - _viewports);
+	w->viewport->width = 0;
+	w->viewport = NULL;
+}
+
+void AssignWindowViewport(Window *w, int x, int y,
+	int width, int height, uint32 follow_flags, byte zoom)
+{
+	ViewPort *vp;
+	Point pt;
+	uint32 bit;
+
+	for (vp = _viewports, bit = 0; ; vp++, bit++) {
+		assert(vp != endof(_viewports));
+		if (vp->width == 0) break;
+	}
+	SETBIT(_active_viewports, bit);
+
+	vp->left = x + w->left;
+	vp->top = y + w->top;
+	vp->width = width;
+	vp->height = height;
+
+	vp->zoom = zoom;
+
+	vp->virtual_width = width << zoom;
+	vp->virtual_height = height << zoom;
+
+	if (follow_flags & 0x80000000) {
+		const Vehicle *veh;
+
+		WP(w, vp_d).follow_vehicle = (VehicleID)(follow_flags & 0xFFFF);
+		veh = GetVehicle(WP(w, vp_d).follow_vehicle);
+		pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
+	} else {
+		uint x = TileX(follow_flags) * TILE_SIZE;
+		uint y = TileY(follow_flags) * TILE_SIZE;
+
+		WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
+		pt = MapXYZToViewport(vp, x, y, GetSlopeZ(x, y));
+	}
+
+	WP(w, vp_d).scrollpos_x = pt.x;
+	WP(w, vp_d).scrollpos_y = pt.y;
+	w->viewport = vp;
+	vp->virtual_left = 0;//pt.x;
+	vp->virtual_top = 0;//pt.y;
+}
+
+static Point _vp_move_offs;
+
+static void DoSetViewportPosition(Window* const *wz, int left, int top, int width, int height)
+{
+
+	for (; wz != _last_z_window; wz++) {
+		const Window *w = *wz;
+
+		if (left + width > w->left &&
+				w->left + w->width > left &&
+				top + height > w->top &&
+				w->top + w->height > top) {
+
+			if (left < w->left) {
+				DoSetViewportPosition(wz, left, top, w->left - left, height);
+				DoSetViewportPosition(wz, left + (w->left - left), top, width - (w->left - left), height);
+				return;
+			}
+
+			if (left + width > w->left + w->width) {
+				DoSetViewportPosition(wz, left, top, (w->left + w->width - left), height);
+				DoSetViewportPosition(wz, left + (w->left + w->width - left), top, width - (w->left + w->width - left) , height);
+				return;
+			}
+
+			if (top < w->top) {
+				DoSetViewportPosition(wz, left, top, width, (w->top - top));
+				DoSetViewportPosition(wz, left, top + (w->top - top), width, height - (w->top - top));
+				return;
+			}
+
+			if (top + height > w->top + w->height) {
+				DoSetViewportPosition(wz, left, top, width, (w->top + w->height - top));
+				DoSetViewportPosition(wz, left, top + (w->top + w->height - top), width , height - (w->top + w->height - top));
+				return;
+			}
+
+			return;
+		}
+	}
+
+	{
+		int xo = _vp_move_offs.x;
+		int yo = _vp_move_offs.y;
+
+		if (abs(xo) >= width || abs(yo) >= height) {
+			/* fully_outside */
+			RedrawScreenRect(left, top, left + width, top + height);
+			return;
+		}
+
+		GfxScroll(left, top, width, height, xo, yo);
+
+		if (xo > 0) {
+			RedrawScreenRect(left, top, xo + left, top + height);
+			left += xo;
+			width -= xo;
+		} else if (xo < 0) {
+			RedrawScreenRect(left+width+xo, top, left+width, top + height);
+			width += xo;
+		}
+
+		if (yo > 0) {
+			RedrawScreenRect(left, top, width+left, top + yo);
+		} else if (yo < 0) {
+			RedrawScreenRect(left, top + height + yo, width+left, top + height);
+		}
+	}
+}
+
+static void SetViewportPosition(Window *w, int x, int y)
+{
+	ViewPort *vp = w->viewport;
+	int old_left = vp->virtual_left;
+	int old_top = vp->virtual_top;
+	int i;
+	int left, top, width, height;
+
+	vp->virtual_left = x;
+	vp->virtual_top = y;
+
+	old_left >>= vp->zoom;
+	old_top >>= vp->zoom;
+	x >>= vp->zoom;
+	y >>= vp->zoom;
+
+	old_left -= x;
+	old_top -= y;
+
+	if (old_top == 0 && old_left == 0) return;
+
+	_vp_move_offs.x = old_left;
+	_vp_move_offs.y = old_top;
+
+	left = vp->left;
+	top = vp->top;
+	width = vp->width;
+	height = vp->height;
+
+	if (left < 0) {
+		width += left;
+		left = 0;
+	}
+
+	i = left + width - _screen.width;
+	if (i >= 0) width -= i;
+
+	if (width > 0) {
+		if (top < 0) {
+			height += top;
+			top = 0;
+		}
+
+		i = top + height - _screen.height;
+		if (i >= 0) height -= i;
+
+		if (height > 0) DoSetViewportPosition(FindWindowZPosition(w) + 1, left, top, width, height);
+	}
+}
+
+
+ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
+{
+	ViewPort *vp = w->viewport;
+
+	if (vp != NULL &&
+	    IS_INT_INSIDE(x, vp->left, vp->left + vp->width) &&
+			IS_INT_INSIDE(y, vp->top, vp->top + vp->height))
+		return vp;
+
+	return NULL;
+}
+
+static Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y)
+{
+	Point pt;
+	int a,b;
+	uint z;
+
+	if ( (uint)(x -= vp->left) >= (uint)vp->width ||
+				(uint)(y -= vp->top) >= (uint)vp->height) {
+				Point pt = {-1, -1};
+				return pt;
+	}
+
+	x = ((x << vp->zoom) + vp->virtual_left) >> 2;
+	y = ((y << vp->zoom) + vp->virtual_top) >> 1;
+
+	a = y-x;
+	b = y+x;
+
+	/* we need to move variables in to the valid range, as the
+	 * GetTileZoomCenterWindow() function can call here with invalid x and/or y,
+	 * when the user tries to zoom out along the sides of the map */
+	a = clamp(a, 0, (int)(MapMaxX() * TILE_SIZE) - 1);
+	b = clamp(b, 0, (int)(MapMaxY() * TILE_SIZE) - 1);
+
+	z = GetSlopeZ(a,     b    ) / 2;
+	z = GetSlopeZ(a + z, b + z) / 2;
+	z = GetSlopeZ(a + z, b + z) / 2;
+	z = GetSlopeZ(a + z, b + z) / 2;
+	z = GetSlopeZ(a + z, b + z) / 2;
+
+	pt.x = a + z;
+	pt.y = b + z;
+
+	return pt;
+}
+
+/* When used for zooming, check area below current coordinates (x,y)
+ * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
+ * when you just want the tile, make x = zoom_x and y = zoom_y */
+static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
+{
+	Window *w;
+	ViewPort *vp;
+	Point pt;
+
+	if ( (w = FindWindowFromPt(x, y)) != NULL &&
+			 (vp = IsPtInWindowViewport(w, x, y)) != NULL)
+				return TranslateXYToTileCoord(vp, zoom_x, zoom_y);
+
+	pt.y = pt.x = -1;
+	return pt;
+}
+
+Point GetTileBelowCursor(void)
+{
+	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
+}
+
+
+Point GetTileZoomCenterWindow(bool in, Window * w)
+{
+	int x, y;
+	ViewPort * vp;
+
+	vp = w->viewport;
+
+	if (in) {
+		x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
+		y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2);
+	} else {
+		x = vp->width - (_cursor.pos.x - vp->left);
+		y = vp->height - (_cursor.pos.y - vp->top);
+	}
+	/* Get the tile below the cursor and center on the zoomed-out center */
+	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
+}
+
+/** Update the status of the zoom-buttons according to the zoom-level
+ * of the viewport. This will update their status and invalidate accordingly
+ * @param window pointer to the window that has the zoom buttons
+ * @param vp pointer to the viewport whose zoom-level the buttons represent
+ * @param widget_zoom_in widget index for window with zoom-in button
+ * @param widget_zoom_out widget index for window with zoom-out button */
+void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
+{
+	SetWindowWidgetDisabledState(w, widget_zoom_in, vp->zoom == 0);
+	InvalidateWidget(w, widget_zoom_in);
+
+	SetWindowWidgetDisabledState(w, widget_zoom_out, vp->zoom == 2);
+	InvalidateWidget(w, widget_zoom_out);
+}
+
+void DrawGroundSpriteAt(uint32 image, int32 x, int32 y, byte z)
+{
+	ViewportDrawer *vd = _cur_vd;
+	TileSpriteToDraw *ts;
+
+	assert((image & SPRITE_MASK) < MAX_SPRITES);
+
+	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
+		DEBUG(sprite, 0, "Out of sprite memory");
+		return;
+	}
+	ts = (TileSpriteToDraw*)vd->spritelist_mem;
+
+	vd->spritelist_mem += sizeof(TileSpriteToDraw);
+
+	ts->image = image;
+	ts->next = NULL;
+	ts->x = x;
+	ts->y = y;
+	ts->z = z;
+	*vd->last_tile = ts;
+	vd->last_tile = &ts->next;
+}
+
+void DrawGroundSprite(uint32 image)
+{
+	if (_offset_ground_sprites) {
+		// offset ground sprite because of foundation?
+		AddChildSpriteScreen(image, _cur_vd->offs_x, _cur_vd->offs_y);
+	} else {
+		_added_tile_sprite = true;
+		DrawGroundSpriteAt(image, _cur_ti->x, _cur_ti->y, _cur_ti->z);
+	}
+}
+
+
+void OffsetGroundSprite(int x, int y)
+{
+	_cur_vd->offs_x = x;
+	_cur_vd->offs_y = y;
+	_offset_ground_sprites = true;
+}
+
+static void AddCombinedSprite(uint32 image, int x, int y, byte z)
+{
+	const ViewportDrawer *vd = _cur_vd;
+	Point pt = RemapCoords(x, y, z);
+	const Sprite* spr = GetSprite(image & SPRITE_MASK);
+
+	if (pt.x + spr->x_offs >= vd->dpi.left + vd->dpi.width ||
+			pt.x + spr->x_offs + spr->width <= vd->dpi.left ||
+			pt.y + spr->y_offs >= vd->dpi.top + vd->dpi.height ||
+			pt.y + spr->y_offs + spr->height <= vd->dpi.top)
+		return;
+
+	AddChildSpriteScreen(image, pt.x - vd->parent_list[-1]->left, pt.y - vd->parent_list[-1]->top);
+}
+
+
+void AddSortableSpriteToDraw(uint32 image, int x, int y, int w, int h, byte dz, byte z)
+{
+	ViewportDrawer *vd = _cur_vd;
+	ParentSpriteToDraw *ps;
+	const Sprite *spr;
+	Point pt;
+
+	assert((image & SPRITE_MASK) < MAX_SPRITES);
+
+	if (vd->combine_sprites == 2) {
+		AddCombinedSprite(image, x, y, z);
+		return;
+	}
+
+	vd->last_child = NULL;
+
+	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
+		DEBUG(sprite, 0, "Out of sprite memory");
+		return;
+	}
+	ps = (ParentSpriteToDraw*)vd->spritelist_mem;
+
+	if (vd->parent_list >= vd->eof_parent_list) {
+		// This can happen rarely, mostly when you zoom out completely
+		//  and have a lot of stuff that moves (and is added to the
+		//  sort-list, this function). To solve it, increase
+		//  parent_list somewhere below to a higher number.
+		// This can not really hurt you, it just gives some black
+		//  spots on the screen ;)
+		DEBUG(sprite, 0, "Out of sprite memory (parent_list)");
+		return;
+	}
+
+	pt = RemapCoords(x, y, z);
+	spr = GetSprite(image & SPRITE_MASK);
+	if ((ps->left   = (pt.x += spr->x_offs)) >= vd->dpi.left + vd->dpi.width ||
+			(ps->right  = (pt.x +  spr->width )) <= vd->dpi.left ||
+			(ps->top    = (pt.y += spr->y_offs)) >= vd->dpi.top + vd->dpi.height ||
+			(ps->bottom = (pt.y +  spr->height)) <= vd->dpi.top) {
+		return;
+	}
+
+	vd->spritelist_mem += sizeof(ParentSpriteToDraw);
+
+	ps->image = image;
+	ps->xmin = x;
+	ps->xmax = x + w - 1;
+
+	ps->ymin = y;
+	ps->ymax = y + h - 1;
+
+	ps->zmin = z;
+	ps->zmax = z + dz - 1;
+
+	ps->unk16 = 0;
+	ps->child = NULL;
+	vd->last_child = &ps->child;
+
+	*vd->parent_list++ = ps;
+
+	if (vd->combine_sprites == 1) vd->combine_sprites = 2;
+}
+
+void StartSpriteCombine(void)
+{
+	_cur_vd->combine_sprites = 1;
+}
+
+void EndSpriteCombine(void)
+{
+	_cur_vd->combine_sprites = 0;
+}
+
+void AddChildSpriteScreen(uint32 image, int x, int y)
+{
+	ViewportDrawer *vd = _cur_vd;
+	ChildScreenSpriteToDraw *cs;
+
+	assert((image & SPRITE_MASK) < MAX_SPRITES);
+
+	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
+		DEBUG(sprite, 0, "Out of sprite memory");
+		return;
+	}
+	cs = (ChildScreenSpriteToDraw*)vd->spritelist_mem;
+
+	if (vd->last_child == NULL) return;
+
+	vd->spritelist_mem += sizeof(ChildScreenSpriteToDraw);
+
+	*vd->last_child = cs;
+	vd->last_child = &cs->next;
+
+	cs->image = image;
+	cs->x = x;
+	cs->y = y;
+	cs->next = NULL;
+}
+
+/* Returns a StringSpriteToDraw */
+void *AddStringToDraw(int x, int y, StringID string, uint32 params_1, uint32 params_2)
+{
+	ViewportDrawer *vd = _cur_vd;
+	StringSpriteToDraw *ss;
+
+	if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
+		DEBUG(sprite, 0, "Out of sprite memory");
+		return NULL;
+	}
+	ss = (StringSpriteToDraw*)vd->spritelist_mem;
+
+	vd->spritelist_mem += sizeof(StringSpriteToDraw);
+
+	ss->string = string;
+	ss->next = NULL;
+	ss->x = x;
+	ss->y = y;
+	ss->params[0] = params_1;
+	ss->params[1] = params_2;
+	ss->width = 0;
+
+	*vd->last_string = ss;
+	vd->last_string = &ss->next;
+
+	return ss;
+}
+
+
+static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
+{
+	if (_added_tile_sprite && !(_thd.drawstyle & HT_LINE)) { // draw on real ground
+		DrawGroundSpriteAt(image, ti->x, ti->y, ti->z + 7);
+	} else { // draw on top of foundation
+		AddSortableSpriteToDraw(image, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
+	}
+}
+
+static bool IsPartOfAutoLine(int px, int py)
+{
+	px -= _thd.selstart.x;
+	py -= _thd.selstart.y;
+
+	switch (_thd.drawstyle) {
+	case HT_LINE | HT_DIR_X:  return py == 0; // x direction
+	case HT_LINE | HT_DIR_Y:  return px == 0; // y direction
+	case HT_LINE | HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
+	case HT_LINE | HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
+	case HT_LINE | HT_DIR_VL: return px == py || px == py + 16; // vertival left
+	case HT_LINE | HT_DIR_VR: return px == py || px == py - 16; // vertical right
+	default:
+		NOT_REACHED();
+	}
+
+	/* useless, but avoids compiler warning this way */
+	return 0;
+}
+
+// [direction][side]
+static const int _AutorailType[6][2] = {
+	{ HT_DIR_X,  HT_DIR_X },
+	{ HT_DIR_Y,  HT_DIR_Y },
+	{ HT_DIR_HU, HT_DIR_HL },
+	{ HT_DIR_HL, HT_DIR_HU },
+	{ HT_DIR_VL, HT_DIR_VR },
+	{ HT_DIR_VR, HT_DIR_VL }
+};
+
+#include "table/autorail.h"
+
+static void DrawTileSelection(const TileInfo *ti)
+{
+	uint32 image;
+
+	// Draw a red error square?
+	if (_thd.redsq != 0 && _thd.redsq == ti->tile) {
+		DrawSelectionSprite(PALETTE_TILE_RED_PULSATING | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
+		return;
+	}
+
+	// no selection active?
+	if (_thd.drawstyle == 0) return;
+
+	// Inside the inner area?
+	if (IS_INSIDE_1D(ti->x, _thd.pos.x, _thd.size.x) &&
+			IS_INSIDE_1D(ti->y, _thd.pos.y, _thd.size.y)) {
+		if (_thd.drawstyle & HT_RECT) {
+			image = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh];
+			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
+			DrawSelectionSprite(image, ti);
+		} else if (_thd.drawstyle & HT_POINT) {
+			// Figure out the Z coordinate for the single dot.
+			byte z = ti->z;
+			if (ti->tileh & SLOPE_N) {
+				z += TILE_HEIGHT;
+				if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT;
+			}
+			DrawGroundSpriteAt(_cur_dpi->zoom != 2 ? SPR_DOT : SPR_DOT_SMALL, ti->x, ti->y, z);
+		} else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) {
+			// autorail highlight piece under cursor
+			uint type = _thd.drawstyle & 0xF;
+			assert(type <= 5);
+			image = SPR_AUTORAIL_BASE + _AutorailTilehSprite[ti->tileh][_AutorailType[type][0]];
+
+			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
+			DrawSelectionSprite(image, ti);
+
+		} else if (IsPartOfAutoLine(ti->x, ti->y)) {
+			// autorail highlighting long line
+			int dir = _thd.drawstyle & ~0xF0;
+			uint side;
+
+			if (dir < 2) {
+				side = 0;
+			} else {
+				TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
+				int diffx = myabs(TileX(start) - TileX(ti->tile));
+				int diffy = myabs(TileY(start) - TileY(ti->tile));
+				side = myabs(diffx - diffy);
+			}
+
+			image = SPR_AUTORAIL_BASE + _AutorailTilehSprite[ti->tileh][_AutorailType[dir][side]];
+
+			if (_thd.make_square_red) image |= PALETTE_SEL_TILE_RED;
+			DrawSelectionSprite(image, ti);
+		}
+		return;
+	}
+
+	// Check if it's inside the outer area?
+	if (_thd.outersize.x &&
+			_thd.size.x < _thd.size.x + _thd.outersize.x &&
+			IS_INSIDE_1D(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
+			IS_INSIDE_1D(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
+		// Draw a blue rect.
+		DrawSelectionSprite(PALETTE_SEL_TILE_BLUE | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
+		return;
+	}
+}
+
+static void ViewportAddLandscape(void)
+{
+	ViewportDrawer *vd = _cur_vd;
+	int x, y, width, height;
+	TileInfo ti;
+	bool direction;
+
+	_cur_ti = &ti;
+
+	// Transform into tile coordinates and round to closest full tile
+	x = ((vd->dpi.top >> 1) - (vd->dpi.left >> 2)) & ~0xF;
+	y = ((vd->dpi.top >> 1) + (vd->dpi.left >> 2) - 0x10) & ~0xF;
+
+	// determine size of area
+	{
+		Point pt = RemapCoords(x, y, 241);
+		width = (vd->dpi.left + vd->dpi.width - pt.x + 95) >> 6;
+		height = (vd->dpi.top + vd->dpi.height - pt.y) >> 5 << 1;
+	}
+
+	assert(width > 0);
+	assert(height > 0);
+
+	direction = false;
+
+	do {
+		int width_cur = width;
+		int x_cur = x;
+		int y_cur = y;
+
+		do {
+			TileType tt;
+
+			ti.x = x_cur;
+			ti.y = y_cur;
+			if (0 <= x_cur && x_cur < (int)MapMaxX() * TILE_SIZE &&
+					0 <= y_cur && y_cur < (int)MapMaxY() * TILE_SIZE) {
+				TileIndex tile = TileVirtXY(x_cur, y_cur);
+
+				ti.tile = tile;
+				ti.tileh = GetTileSlope(tile, &ti.z);
+				tt = GetTileType(tile);
+			} else {
+				ti.tileh = SLOPE_FLAT;
+				ti.tile = 0;
+				ti.z = 0;
+				tt = MP_VOID;
+			}
+
+			y_cur += 0x10;
+			x_cur -= 0x10;
+
+			_added_tile_sprite = false;
+			_offset_ground_sprites = false;
+
+			_tile_type_procs[tt]->draw_tile_proc(&ti);
+			DrawTileSelection(&ti);
+		} while (--width_cur);
+
+		if ((direction ^= 1) != 0) {
+			y += 0x10;
+		} else {
+			x += 0x10;
+		}
+	} while (--height);
+}
+
+
+static void ViewportAddTownNames(DrawPixelInfo *dpi)
+{
+	Town *t;
+	int left, top, right, bottom;
+
+	if (!(_display_opt & DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU)
+		return;
+
+	left = dpi->left;
+	top = dpi->top;
+	right = left + dpi->width;
+	bottom = top + dpi->height;
+
+	switch (dpi->zoom) {
+		case 0:
+			FOR_ALL_TOWNS(t) {
+				if (bottom > t->sign.top &&
+						top    < t->sign.top + 12 &&
+						right  > t->sign.left &&
+						left   < t->sign.left + t->sign.width_1) {
+					AddStringToDraw(t->sign.left + 1, t->sign.top + 1,
+						_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL,
+						t->index, t->population);
+				}
+			}
+			break;
+
+		case 1:
+			right += 2;
+			bottom += 2;
+
+			FOR_ALL_TOWNS(t) {
+				if (bottom > t->sign.top &&
+						top    < t->sign.top + 24 &&
+						right  > t->sign.left &&
+						left   < t->sign.left + t->sign.width_1*2) {
+					AddStringToDraw(t->sign.left + 1, t->sign.top + 1,
+						_patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL,
+						t->index, t->population);
+				}
+			}
+			break;
+
+		default: NOT_REACHED();
+		case 2:
+			right += 4;
+			bottom += 5;
+
+			FOR_ALL_TOWNS(t) {
+				if (bottom > t->sign.top &&
+						top    < t->sign.top + 24 &&
+						right  > t->sign.left &&
+						left   < t->sign.left + t->sign.width_2*4) {
+					AddStringToDraw(t->sign.left + 5, t->sign.top + 1, STR_TOWN_LABEL_TINY_BLACK, t->index, 0);
+					AddStringToDraw(t->sign.left + 1, t->sign.top - 3, STR_TOWN_LABEL_TINY_WHITE, t->index, 0);
+				}
+			}
+			break;
+	}
+}
+
+
+static void AddStation(const Station *st, StringID str, uint16 width)
+{
+	StringSpriteToDraw *sstd;
+
+	sstd = AddStringToDraw(st->sign.left + 1, st->sign.top + 1, str, st->index, st->facilities);
+	if (sstd != NULL) {
+		sstd->color = (st->owner == OWNER_NONE || st->facilities == 0) ? 0xE : _player_colors[st->owner];
+		sstd->width = width;
+	}
+}
+
+
+static void ViewportAddStationNames(DrawPixelInfo *dpi)
+{
+	int left, top, right, bottom;
+	const Station *st;
+
+	if (!(_display_opt & DO_SHOW_STATION_NAMES) || _game_mode == GM_MENU)
+		return;
+
+	left = dpi->left;
+	top = dpi->top;
+	right = left + dpi->width;
+	bottom = top + dpi->height;
+
+	switch (dpi->zoom) {
+		case 0:
+			FOR_ALL_STATIONS(st) {
+				if (bottom > st->sign.top &&
+						top    < st->sign.top + 12 &&
+						right  > st->sign.left &&
+						left   < st->sign.left + st->sign.width_1) {
+					AddStation(st, STR_305C_0, st->sign.width_1);
+				}
+			}
+			break;
+
+		case 1:
+			right += 2;
+			bottom += 2;
+			FOR_ALL_STATIONS(st) {
+				if (bottom > st->sign.top &&
+						top    < st->sign.top + 24 &&
+						right  > st->sign.left &&
+						left   < st->sign.left + st->sign.width_1*2) {
+					AddStation(st, STR_305C_0, st->sign.width_1);
+				}
+			}
+			break;
+
+		default: NOT_REACHED();
+		case 2:
+			right += 4;
+			bottom += 5;
+			FOR_ALL_STATIONS(st) {
+				if (bottom > st->sign.top &&
+						top    < st->sign.top + 24 &&
+						right  > st->sign.left &&
+						left   < st->sign.left + st->sign.width_2*4) {
+					AddStation(st, STR_STATION_SIGN_TINY, st->sign.width_2 | 0x8000);
+				}
+			}
+			break;
+	}
+}
+
+
+static void AddSign(const Sign *si, StringID str, uint16 width)
+{
+	StringSpriteToDraw *sstd;
+
+	sstd = AddStringToDraw(si->sign.left + 1, si->sign.top + 1, str, si->str, 0);
+	if (sstd != NULL) {
+		sstd->color = (si->owner == OWNER_NONE) ? 14 : _player_colors[si->owner];
+		sstd->width = width;
+	}
+}
+
+
+static void ViewportAddSigns(DrawPixelInfo *dpi)
+{
+	const Sign *si;
+	int left, top, right, bottom;
+
+	if (!(_display_opt & DO_SHOW_SIGNS))
+		return;
+
+	left = dpi->left;
+	top = dpi->top;
+	right = left + dpi->width;
+	bottom = top + dpi->height;
+
+	switch (dpi->zoom) {
+		case 0:
+			FOR_ALL_SIGNS(si) {
+				if (bottom > si->sign.top &&
+						top    < si->sign.top + 12 &&
+						right  > si->sign.left &&
+						left   < si->sign.left + si->sign.width_1) {
+					AddSign(si, STR_2806, si->sign.width_1);
+				}
+			}
+			break;
+
+		case 1:
+			right += 2;
+			bottom += 2;
+			FOR_ALL_SIGNS(si) {
+				if (bottom > si->sign.top &&
+						top    < si->sign.top + 24 &&
+						right  > si->sign.left &&
+						left   < si->sign.left + si->sign.width_1 * 2) {
+					AddSign(si, STR_2806, si->sign.width_1);
+				}
+			}
+			break;
+
+		default: NOT_REACHED();
+		case 2:
+			right += 4;
+			bottom += 5;
+			FOR_ALL_SIGNS(si) {
+				if (bottom > si->sign.top &&
+						top    < si->sign.top + 24 &&
+						right  > si->sign.left &&
+						left   < si->sign.left + si->sign.width_2 * 4) {
+					AddSign(si, STR_2002, si->sign.width_2 | 0x8000);
+				}
+			}
+			break;
+	}
+}
+
+
+static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width)
+{
+	StringSpriteToDraw *sstd;
+
+	sstd = AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0);
+	if (sstd != NULL) {
+		sstd->color = (wp->deleted ? 0xE : 11);
+		sstd->width = width;
+	}
+}
+
+
+static void ViewportAddWaypoints(DrawPixelInfo *dpi)
+{
+	const Waypoint *wp;
+	int left, top, right, bottom;
+
+	if (!(_display_opt & DO_WAYPOINTS))
+		return;
+
+	left = dpi->left;
+	top = dpi->top;
+	right = left + dpi->width;
+	bottom = top + dpi->height;
+
+	switch (dpi->zoom) {
+		case 0:
+			FOR_ALL_WAYPOINTS(wp) {
+				if (bottom > wp->sign.top &&
+						top    < wp->sign.top + 12 &&
+						right  > wp->sign.left &&
+						left   < wp->sign.left + wp->sign.width_1) {
+					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
+				}
+			}
+			break;
+
+		case 1:
+			right += 2;
+			bottom += 2;
+			FOR_ALL_WAYPOINTS(wp) {
+				if (bottom > wp->sign.top &&
+						top    < wp->sign.top + 24 &&
+						right  > wp->sign.left &&
+						left   < wp->sign.left + wp->sign.width_1*2) {
+					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
+				}
+			}
+			break;
+
+		default: NOT_REACHED();
+		case 2:
+			right += 4;
+			bottom += 5;
+			FOR_ALL_WAYPOINTS(wp) {
+				if (bottom > wp->sign.top &&
+						top    < wp->sign.top + 24 &&
+						right  > wp->sign.left &&
+						left   < wp->sign.left + wp->sign.width_2*4) {
+					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT_TINY, wp->sign.width_2 | 0x8000);
+				}
+			}
+			break;
+	}
+}
+
+void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str)
+{
+	char buffer[128];
+	uint w;
+
+	sign->top = top;
+
+	GetString(buffer, str, lastof(buffer));
+	w = GetStringBoundingBox(buffer).width + 3;
+	sign->width_1 = w;
+	sign->left = left - w / 2;
+
+	/* zoomed out version */
+	_cur_fontsize = FS_SMALL;
+	w = GetStringBoundingBox(buffer).width + 3;
+	_cur_fontsize = FS_NORMAL;
+	sign->width_2 = w;
+}
+
+
+static void ViewportDrawTileSprites(TileSpriteToDraw *ts)
+{
+	do {
+		Point pt = RemapCoords(ts->x, ts->y, ts->z);
+		DrawSprite(ts->image, pt.x, pt.y);
+		ts = ts->next;
+	} while (ts != NULL);
+}
+
+static void ViewportSortParentSprites(ParentSpriteToDraw *psd[])
+{
+	while (*psd != NULL) {
+		ParentSpriteToDraw* ps = *psd;
+
+		if (!(ps->unk16 & 1)) {
+			ParentSpriteToDraw** psd2 = psd;
+
+			ps->unk16 |= 1;
+
+			while (*++psd2 != NULL) {
+				ParentSpriteToDraw* ps2 = *psd2;
+				ParentSpriteToDraw** psd3;
+
+				if (ps2->unk16 & 1) continue;
+
+				/* Decide which comparator to use, based on whether the bounding
+				 * boxes overlap
+				 */
+				if (ps->xmax > ps2->xmin && ps->xmin < ps2->xmax && // overlap in X?
+						ps->ymax > ps2->ymin && ps->ymin < ps2->ymax && // overlap in Y?
+						ps->zmax > ps2->zmin && ps->zmin < ps2->zmax) { // overlap in Z?
+					/* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
+					 * the screen and with higher Z elevation, are drawn in front.
+					 * Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
+					 * i.e. X=(left+right)/2, etc.
+					 * However, since we only care about order, don't actually divide / 2
+					 */
+					if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
+							ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
+						continue;
+					}
+				} else {
+					if (ps->xmax < ps2->xmin ||
+							ps->ymax < ps2->ymin ||
+							ps->zmax < ps2->zmin || (
+								ps->xmin < ps2->xmax &&
+								ps->ymin < ps2->ymax &&
+								ps->zmin < ps2->zmax
+							)) {
+						continue;
+					}
+				}
+
+				// Swap the two sprites ps and ps2 using bubble-sort algorithm.
+				psd3 = psd;
+				do {
+					ParentSpriteToDraw* temp = *psd3;
+					*psd3 = ps2;
+					ps2 = temp;
+
+					psd3++;
+				} while (psd3 <= psd2);
+			}
+		} else {
+			psd++;
+		}
+	}
+}
+
+static void ViewportDrawParentSprites(ParentSpriteToDraw *psd[])
+{
+	for (; *psd != NULL; psd++) {
+		const ParentSpriteToDraw* ps = *psd;
+		Point pt = RemapCoords(ps->xmin, ps->ymin, ps->zmin);
+		const ChildScreenSpriteToDraw* cs;
+
+		DrawSprite(ps->image, pt.x, pt.y);
+
+		for (cs = ps->child; cs != NULL; cs = cs->next) {
+			DrawSprite(cs->image, ps->left + cs->x, ps->top + cs->y);
+		}
+	}
+}
+
+static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDraw *ss)
+{
+	DrawPixelInfo dp;
+	byte zoom;
+
+	_cur_dpi = &dp;
+	dp = *dpi;
+
+	zoom = dp.zoom;
+	dp.zoom = 0;
+
+	dp.left >>= zoom;
+	dp.top >>= zoom;
+	dp.width >>= zoom;
+	dp.height >>= zoom;
+
+	do {
+		uint16 colour;
+
+		if (ss->width != 0) {
+			int x = (ss->x >> zoom) - 1;
+			int y = (ss->y >> zoom) - 1;
+			int bottom = y + 11;
+			int w = ss->width;
+
+			if (w & 0x8000) {
+				w &= ~0x8000;
+				y--;
+				bottom -= 6;
+				w -= 3;
+			}
+
+		/* Draw the rectangle if 'tranparent station signs' is off,
+		 * or if we are drawing a general text sign (STR_2806) */
+			if (!(_display_opt & DO_TRANS_SIGNS) || ss->string == STR_2806)
+				DrawFrameRect(
+					x, y, x + w, bottom, ss->color,
+					(_display_opt & DO_TRANS_BUILDINGS) ? FR_TRANSPARENT : 0
+				);
+		}
+
+		SetDParam(0, ss->params[0]);
+		SetDParam(1, ss->params[1]);
+		/* if we didn't draw a rectangle, or if transparant building is on,
+		 * draw the text in the color the rectangle would have */
+		if ((
+					(_display_opt & DO_TRANS_BUILDINGS) ||
+					(_display_opt & DO_TRANS_SIGNS && ss->string != STR_2806)
+				) && ss->width != 0) {
+			/* Real colors need the IS_PALETTE_COLOR flag
+			 * otherwise colors from _string_colormap are assumed. */
+			colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR;
+		} else {
+			colour = 16;
+		}
+		DrawString(
+			ss->x >> zoom, (ss->y >> zoom) - (ss->width & 0x8000 ? 2 : 0),
+			ss->string, colour
+		);
+
+		ss = ss->next;
+	} while (ss != NULL);
+}
+
+void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
+{
+	ViewportDrawer vd;
+	int mask;
+	int x;
+	int y;
+	DrawPixelInfo *old_dpi;
+
+	byte mem[VIEWPORT_DRAW_MEM];
+	ParentSpriteToDraw *parent_list[6144];
+
+	_cur_vd = &vd;
+
+	old_dpi = _cur_dpi;
+	_cur_dpi = &vd.dpi;
+
+	vd.dpi.zoom = vp->zoom;
+	mask = (-1) << vp->zoom;
+
+	vd.combine_sprites = 0;
+
+	vd.dpi.width = (right - left) & mask;
+	vd.dpi.height = (bottom - top) & mask;
+	vd.dpi.left = left & mask;
+	vd.dpi.top = top & mask;
+	vd.dpi.pitch = old_dpi->pitch;
+
+	x = ((vd.dpi.left - (vp->virtual_left&mask)) >> vp->zoom) + vp->left;
+	y = ((vd.dpi.top - (vp->virtual_top&mask)) >> vp->zoom) + vp->top;
+
+	vd.dpi.dst_ptr = old_dpi->dst_ptr + x - old_dpi->left + (y - old_dpi->top) * old_dpi->pitch;
+
+	vd.parent_list = parent_list;
+	vd.eof_parent_list = endof(parent_list);
+	vd.spritelist_mem = mem;
+	vd.eof_spritelist_mem = endof(mem) - sizeof(LARGEST_SPRITELIST_STRUCT);
+	vd.last_string = &vd.first_string;
+	vd.first_string = NULL;
+	vd.last_tile = &vd.first_tile;
+	vd.first_tile = NULL;
+
+	ViewportAddLandscape();
+	ViewportAddVehicles(&vd.dpi);
+	DrawTextEffects(&vd.dpi);
+
+	ViewportAddTownNames(&vd.dpi);
+	ViewportAddStationNames(&vd.dpi);
+	ViewportAddSigns(&vd.dpi);
+	ViewportAddWaypoints(&vd.dpi);
+
+	// This assert should never happen (because the length of the parent_list
+	//  is checked)
+	assert(vd.parent_list <= endof(parent_list));
+
+	if (vd.first_tile != NULL) ViewportDrawTileSprites(vd.first_tile);
+
+	/* null terminate parent sprite list */
+	*vd.parent_list = NULL;
+
+	ViewportSortParentSprites(parent_list);
+	ViewportDrawParentSprites(parent_list);
+
+	if (vd.first_string != NULL) ViewportDrawStrings(&vd.dpi, vd.first_string);
+
+	_cur_dpi = old_dpi;
+}
+
+// Make sure we don't draw a too big area at a time.
+// If we do, the sprite memory will overflow.
+static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
+{
+	if (((bottom - top) * (right - left) << vp->zoom) > 180000) {
+		if ((bottom - top) > (right - left)) {
+			int t = (top + bottom) >> 1;
+			ViewportDrawChk(vp, left, top, right, t);
+			ViewportDrawChk(vp, left, t, right, bottom);
+		} else {
+			int t = (left + right) >> 1;
+			ViewportDrawChk(vp, left, top, t, bottom);
+			ViewportDrawChk(vp, t, top, right, bottom);
+		}
+	} else {
+		ViewportDoDraw(vp,
+			((left - vp->left) << vp->zoom) + vp->virtual_left,
+			((top - vp->top) << vp->zoom) + vp->virtual_top,
+			((right - vp->left) << vp->zoom) + vp->virtual_left,
+			((bottom - vp->top) << vp->zoom) + vp->virtual_top
+		);
+	}
+}
+
+static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
+{
+	if (right <= vp->left || bottom <= vp->top) return;
+
+	if (left >= vp->left + vp->width) return;
+
+	if (left < vp->left) left = vp->left;
+	if (right > vp->left + vp->width) right = vp->left + vp->width;
+
+	if (top >= vp->top + vp->height) return;
+
+	if (top < vp->top) top = vp->top;
+	if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
+
+	ViewportDrawChk(vp, left, top, right, bottom);
+}
+
+void DrawWindowViewport(const Window *w)
+{
+	DrawPixelInfo *dpi = _cur_dpi;
+
+	dpi->left += w->left;
+	dpi->top += w->top;
+
+	ViewportDraw(w->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
+
+	dpi->left -= w->left;
+	dpi->top -= w->top;
+}
+
+void UpdateViewportPosition(Window *w)
+{
+	const ViewPort *vp = w->viewport;
+
+	if (WP(w, vp_d).follow_vehicle != INVALID_VEHICLE) {
+		const Vehicle* veh = GetVehicle(WP(w,vp_d).follow_vehicle);
+		Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
+
+		SetViewportPosition(w, pt.x, pt.y);
+	} else {
+		int x;
+		int y;
+		int vx;
+		int vy;
+
+		// Center of the viewport is hot spot
+		x = WP(w,vp_d).scrollpos_x + vp->virtual_width / 2;
+		y = WP(w,vp_d).scrollpos_y + vp->virtual_height / 2;
+		// Convert viewport coordinates to map coordinates
+		// Calculation is scaled by 4 to avoid rounding errors
+		vx = -x + y * 2;
+		vy =  x + y * 2;
+		// clamp to size of map
+		vx = clamp(vx, 0 * 4, MapMaxX() * TILE_SIZE * 4);
+		vy = clamp(vy, 0 * 4, MapMaxY() * TILE_SIZE * 4);
+		// Convert map coordinates to viewport coordinates
+		x = (-vx + vy) / 2;
+		y = ( vx + vy) / 4;
+		// Set position
+		WP(w, vp_d).scrollpos_x = x - vp->virtual_width / 2;
+		WP(w, vp_d).scrollpos_y = y - vp->virtual_height / 2;
+
+		SetViewportPosition(w, WP(w, vp_d).scrollpos_x, WP(w, vp_d).scrollpos_y);
+	}
+}
+
+static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
+{
+	right -= vp->virtual_left;
+	if (right <= 0) return;
+
+	bottom -= vp->virtual_top;
+	if (bottom <= 0) return;
+
+	left = max(0, left - vp->virtual_left);
+
+	if (left >= vp->virtual_width) return;
+
+	top = max(0, top - vp->virtual_top);
+
+	if (top >= vp->virtual_height) return;
+
+	SetDirtyBlocks(
+		(left >> vp->zoom) + vp->left,
+		(top >> vp->zoom) + vp->top,
+		(right >> vp->zoom) + vp->left,
+		(bottom >> vp->zoom) + vp->top
+	);
+}
+
+void MarkAllViewportsDirty(int left, int top, int right, int bottom)
+{
+	const ViewPort *vp = _viewports;
+	uint32 act = _active_viewports;
+	do {
+		if (act & 1) {
+			assert(vp->width != 0);
+			MarkViewportDirty(vp, left, top, right, bottom);
+		}
+	} while (vp++,act>>=1);
+}
+
+void MarkTileDirtyByTile(TileIndex tile)
+{
+	Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, GetTileZ(tile));
+	MarkAllViewportsDirty(
+		pt.x - 31,
+		pt.y - 122,
+		pt.x - 31 + 67,
+		pt.y - 122 + 154
+	);
+}
+
+void MarkTileDirty(int x, int y)
+{
+	uint z = 0;
+	Point pt;
+
+	if (IS_INT_INSIDE(x, 0, MapSizeX() * TILE_SIZE) &&
+			IS_INT_INSIDE(y, 0, MapSizeY() * TILE_SIZE))
+		z = GetTileZ(TileVirtXY(x, y));
+	pt = RemapCoords(x, y, z);
+
+	MarkAllViewportsDirty(
+		pt.x - 31,
+		pt.y - 122,
+		pt.x - 31 + 67,
+		pt.y - 122 + 154
+	);
+}
+
+static void SetSelectionTilesDirty(void)
+{
+	int y_size, x_size;
+	int x = _thd.pos.x;
+	int y = _thd.pos.y;
+
+	x_size = _thd.size.x;
+	y_size = _thd.size.y;
+
+	if (_thd.outersize.x) {
+		x_size += _thd.outersize.x;
+		x += _thd.offs.x;
+		y_size += _thd.outersize.y;
+		y += _thd.offs.y;
+	}
+
+	assert(x_size > 0);
+	assert(y_size > 0);
+
+	x_size += x;
+	y_size += y;
+
+	do {
+		int y_bk = y;
+		do {
+			MarkTileDirty(x, y);
+		} while ( (y += TILE_SIZE) != y_size);
+		y = y_bk;
+	} while ( (x += TILE_SIZE) != x_size);
+}
+
+
+void SetSelectionRed(bool b)
+{
+	_thd.make_square_red = b;
+	SetSelectionTilesDirty();
+}
+
+
+static bool CheckClickOnTown(const ViewPort *vp, int x, int y)
+{
+	const Town *t;
+
+	if (!(_display_opt & DO_SHOW_TOWN_NAMES)) return false;
+
+	switch (vp->zoom) {
+		case 0:
+			x = x - vp->left + vp->virtual_left;
+			y = y - vp->top  + vp->virtual_top;
+			FOR_ALL_TOWNS(t) {
+				if (y >= t->sign.top &&
+						y < t->sign.top + 12 &&
+						x >= t->sign.left &&
+						x < t->sign.left + t->sign.width_1) {
+					ShowTownViewWindow(t->index);
+					return true;
+				}
+			}
+			break;
+
+		case 1:
+			x = (x - vp->left + 1) * 2 + vp->virtual_left;
+			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
+			FOR_ALL_TOWNS(t) {
+				if (y >= t->sign.top &&
+						y < t->sign.top + 24 &&
+						x >= t->sign.left &&
+						x < t->sign.left + t->sign.width_1 * 2) {
+					ShowTownViewWindow(t->index);
+					return true;
+				}
+			}
+			break;
+
+		default:
+			x = (x - vp->left + 3) * 4 + vp->virtual_left;
+			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+			FOR_ALL_TOWNS(t) {
+				if (y >= t->sign.top &&
+						y < t->sign.top + 24 &&
+						x >= t->sign.left &&
+						x < t->sign.left + t->sign.width_2 * 4) {
+					ShowTownViewWindow(t->index);
+					return true;
+				}
+			}
+			break;
+	}
+
+	return false;
+}
+
+
+static bool CheckClickOnStation(const ViewPort *vp, int x, int y)
+{
+	const Station *st;
+
+	if (!(_display_opt & DO_SHOW_STATION_NAMES)) return false;
+
+	switch (vp->zoom) {
+		case 0:
+			x = x - vp->left + vp->virtual_left;
+			y = y - vp->top  + vp->virtual_top;
+			FOR_ALL_STATIONS(st) {
+				if (y >= st->sign.top &&
+						y < st->sign.top + 12 &&
+						x >= st->sign.left &&
+						x < st->sign.left + st->sign.width_1) {
+					ShowStationViewWindow(st->index);
+					return true;
+				}
+			}
+			break;
+
+		case 1:
+			x = (x - vp->left + 1) * 2 + vp->virtual_left;
+			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
+			FOR_ALL_STATIONS(st) {
+				if (y >= st->sign.top &&
+						y < st->sign.top + 24 &&
+						x >= st->sign.left &&
+						x < st->sign.left + st->sign.width_1 * 2) {
+					ShowStationViewWindow(st->index);
+					return true;
+				}
+			}
+			break;
+
+		default:
+			x = (x - vp->left + 3) * 4 + vp->virtual_left;
+			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+			FOR_ALL_STATIONS(st) {
+				if (y >= st->sign.top &&
+						y < st->sign.top + 24 &&
+						x >= st->sign.left &&
+						x < st->sign.left + st->sign.width_2 * 4) {
+					ShowStationViewWindow(st->index);
+					return true;
+				}
+			}
+			break;
+	}
+
+	return false;
+}
+
+
+static bool CheckClickOnSign(const ViewPort *vp, int x, int y)
+{
+	const Sign *si;
+
+	if (!(_display_opt & DO_SHOW_SIGNS)) return false;
+
+	switch (vp->zoom) {
+		case 0:
+			x = x - vp->left + vp->virtual_left;
+			y = y - vp->top  + vp->virtual_top;
+			FOR_ALL_SIGNS(si) {
+				if (y >= si->sign.top &&
+						y <  si->sign.top + 12 &&
+						x >= si->sign.left &&
+						x <  si->sign.left + si->sign.width_1) {
+					ShowRenameSignWindow(si);
+					return true;
+				}
+			}
+			break;
+
+		case 1:
+			x = (x - vp->left + 1) * 2 + vp->virtual_left;
+			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
+			FOR_ALL_SIGNS(si) {
+				if (y >= si->sign.top &&
+						y <  si->sign.top + 24 &&
+						x >= si->sign.left &&
+						x <  si->sign.left + si->sign.width_1 * 2) {
+					ShowRenameSignWindow(si);
+					return true;
+				}
+			}
+			break;
+
+		default:
+			x = (x - vp->left + 3) * 4 + vp->virtual_left;
+			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+			FOR_ALL_SIGNS(si) {
+				if (y >= si->sign.top &&
+						y <  si->sign.top + 24 &&
+						x >= si->sign.left &&
+						x <  si->sign.left + si->sign.width_2 * 4) {
+					ShowRenameSignWindow(si);
+					return true;
+				}
+			}
+			break;
+	}
+
+	return false;
+}
+
+
+static bool CheckClickOnWaypoint(const ViewPort *vp, int x, int y)
+{
+	const Waypoint *wp;
+
+	if (!(_display_opt & DO_WAYPOINTS)) return false;
+
+	switch (vp->zoom) {
+		case 0:
+			x = x - vp->left + vp->virtual_left;
+			y = y - vp->top  + vp->virtual_top;
+			FOR_ALL_WAYPOINTS(wp) {
+				if (y >= wp->sign.top &&
+						y < wp->sign.top + 12 &&
+						x >= wp->sign.left &&
+						x < wp->sign.left + wp->sign.width_1) {
+					ShowRenameWaypointWindow(wp);
+					return true;
+				}
+			}
+			break;
+
+		case 1:
+			x = (x - vp->left + 1) * 2 + vp->virtual_left;
+			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
+			FOR_ALL_WAYPOINTS(wp) {
+				if (y >= wp->sign.top &&
+						y < wp->sign.top + 24 &&
+						x >= wp->sign.left &&
+						x < wp->sign.left + wp->sign.width_1 * 2) {
+					ShowRenameWaypointWindow(wp);
+					return true;
+				}
+			}
+			break;
+
+		default:
+			x = (x - vp->left + 3) * 4 + vp->virtual_left;
+			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+			FOR_ALL_WAYPOINTS(wp) {
+				if (y >= wp->sign.top &&
+						y < wp->sign.top + 24 &&
+						x >= wp->sign.left &&
+						x < wp->sign.left + wp->sign.width_2 * 4) {
+					ShowRenameWaypointWindow(wp);
+					return true;
+				}
+			}
+			break;
+	}
+
+	return false;
+}
+
+
+static void CheckClickOnLandscape(const ViewPort *vp, int x, int y)
+{
+	Point pt = TranslateXYToTileCoord(vp, x, y);
+
+	if (pt.x != -1) ClickTile(TileVirtXY(pt.x, pt.y));
+}
+
+
+static void SafeShowTrainViewWindow(const Vehicle* v)
+{
+	if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
+	ShowTrainViewWindow(v);
+}
+
+static void Nop(const Vehicle *v) {}
+
+typedef void OnVehicleClickProc(const Vehicle *v);
+static OnVehicleClickProc* const _on_vehicle_click_proc[] = {
+	SafeShowTrainViewWindow,
+	ShowRoadVehViewWindow,
+	ShowShipViewWindow,
+	ShowAircraftViewWindow,
+	Nop, // Special vehicles
+	Nop  // Disaster vehicles
+};
+
+void HandleViewportClicked(const ViewPort *vp, int x, int y)
+{
+	const Vehicle *v;
+
+	if (CheckClickOnTown(vp, x, y)) return;
+	if (CheckClickOnStation(vp, x, y)) return;
+	if (CheckClickOnSign(vp, x, y)) return;
+	if (CheckClickOnWaypoint(vp, x, y)) return;
+	CheckClickOnLandscape(vp, x, y);
+
+	v = CheckClickOnVehicle(vp, x, y);
+	if (v != NULL) {
+		DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v);
+		_on_vehicle_click_proc[v->type - 0x10](v);
+	}
+}
+
+Vehicle *CheckMouseOverVehicle(void)
+{
+	const Window *w;
+	const ViewPort *vp;
+
+	int x = _cursor.pos.x;
+	int y = _cursor.pos.y;
+
+	w = FindWindowFromPt(x, y);
+	if (w == NULL) return NULL;
+
+	vp = IsPtInWindowViewport(w, x, y);
+	return (vp != NULL) ? CheckClickOnVehicle(vp, x, y) : NULL;
+}
+
+
+
+void PlaceObject(void)
+{
+	Point pt;
+	Window *w;
+
+	pt = GetTileBelowCursor();
+	if (pt.x == -1) return;
+
+	if (_thd.place_mode == VHM_POINT) {
+		pt.x += 8;
+		pt.y += 8;
+	}
+
+	_tile_fract_coords.x = pt.x & 0xF;
+	_tile_fract_coords.y = pt.y & 0xF;
+
+	w = GetCallbackWnd();
+	if (w != NULL) {
+		WindowEvent e;
+
+		e.event = WE_PLACE_OBJ;
+		e.we.place.pt = pt;
+		e.we.place.tile = TileVirtXY(pt.x, pt.y);
+		w->wndproc(w, &e);
+	}
+}
+
+
+/* scrolls the viewport in a window to a given location */
+bool ScrollWindowTo(int x , int y, Window *w)
+{
+	Point pt;
+
+	pt = MapXYZToViewport(w->viewport, x, y, GetSlopeZ(x, y));
+	WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
+
+	if (WP(w, vp_d).scrollpos_x == pt.x && WP(w, vp_d).scrollpos_y == pt.y)
+		return false;
+
+	WP(w, vp_d).scrollpos_x = pt.x;
+	WP(w, vp_d).scrollpos_y = pt.y;
+	return true;
+}
+
+
+bool ScrollMainWindowTo(int x, int y)
+{
+	Window *w;
+	bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0));
+
+	/* If a user scrolls to a tile (via what way what so ever) and already is on
+	 *  that tile (e.g.: pressed twice), move the smallmap to that location,
+	 *  so you directly see where you are on the smallmap. */
+
+	if (res) return res;
+
+	w = FindWindowById(WC_SMALLMAP, 0);
+	if (w == NULL) return res;
+
+	SmallMapCenterOnCurrentPos(w);
+
+	return res;
+}
+
+
+bool ScrollMainWindowToTile(TileIndex tile)
+{
+	return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2);
+}
+
+void SetRedErrorSquare(TileIndex tile)
+{
+	TileIndex old;
+
+	old = _thd.redsq;
+	_thd.redsq = tile;
+
+	if (tile != old) {
+		if (tile != 0) MarkTileDirtyByTile(tile);
+		if (old  != 0) MarkTileDirtyByTile(old);
+	}
+}
+
+void SetTileSelectSize(int w, int h)
+{
+	_thd.new_size.x = w * TILE_SIZE;
+	_thd.new_size.y = h * TILE_SIZE;
+	_thd.new_outersize.x = 0;
+	_thd.new_outersize.y = 0;
+}
+
+void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
+{
+	_thd.offs.x = ox * TILE_SIZE;
+	_thd.offs.y = oy * TILE_SIZE;
+	_thd.new_outersize.x = sx * TILE_SIZE;
+	_thd.new_outersize.y = sy * TILE_SIZE;
+}
+
+/* returns the best autorail highlight type from map coordinates */
+static byte GetAutorailHT(int x, int y)
+{
+	return HT_RAIL | _AutorailPiece[x & 0xF][y & 0xF];
+}
+
+// called regular to update tile highlighting in all cases
+void UpdateTileSelection(void)
+{
+	int x1;
+	int y1;
+
+	_thd.new_drawstyle = 0;
+
+	if (_thd.place_mode == VHM_SPECIAL) {
+		x1 = _thd.selend.x;
+		y1 = _thd.selend.y;
+		if (x1 != -1) {
+			int x2 = _thd.selstart.x;
+			int y2 = _thd.selstart.y;
+			x1 &= ~0xF;
+			y1 &= ~0xF;
+
+			if (x1 >= x2) intswap(x1,x2);
+			if (y1 >= y2) intswap(y1,y2);
+			_thd.new_pos.x = x1;
+			_thd.new_pos.y = y1;
+			_thd.new_size.x = x2 - x1 + TILE_SIZE;
+			_thd.new_size.y = y2 - y1 + TILE_SIZE;
+			_thd.new_drawstyle = _thd.next_drawstyle;
+		}
+	} else if (_thd.place_mode != VHM_NONE) {
+		Point pt = GetTileBelowCursor();
+		x1 = pt.x;
+		y1 = pt.y;
+		if (x1 != -1) {
+			switch (_thd.place_mode) {
+				case VHM_RECT:
+					_thd.new_drawstyle = HT_RECT;
+					break;
+				case VHM_POINT:
+					_thd.new_drawstyle = HT_POINT;
+					x1 += 8;
+					y1 += 8;
+					break;
+				case VHM_RAIL:
+					_thd.new_drawstyle = GetAutorailHT(pt.x, pt.y); // draw one highlighted tile
+			}
+			_thd.new_pos.x = x1 & ~0xF;
+			_thd.new_pos.y = y1 & ~0xF;
+		}
+	}
+
+	// redraw selection
+	if (_thd.drawstyle != _thd.new_drawstyle ||
+			_thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
+			_thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
+	    _thd.outersize.x != _thd.new_outersize.x ||
+	    _thd.outersize.y != _thd.new_outersize.y) {
+		// clear the old selection?
+		if (_thd.drawstyle) SetSelectionTilesDirty();
+
+		_thd.drawstyle = _thd.new_drawstyle;
+		_thd.pos = _thd.new_pos;
+		_thd.size = _thd.new_size;
+		_thd.outersize = _thd.new_outersize;
+		_thd.dirty = 0xff;
+
+		// draw the new selection?
+		if (_thd.new_drawstyle) SetSelectionTilesDirty();
+	}
+}
+
+// highlighting tiles while only going over them with the mouse
+void VpStartPlaceSizing(TileIndex tile, int user)
+{
+	_thd.userdata = user;
+	_thd.selend.x = TileX(tile) * TILE_SIZE;
+	_thd.selstart.x = TileX(tile) * TILE_SIZE;
+	_thd.selend.y = TileY(tile) * TILE_SIZE;
+	_thd.selstart.y = TileY(tile) * TILE_SIZE;
+	if (_thd.place_mode == VHM_RECT) {
+		_thd.place_mode = VHM_SPECIAL;
+		_thd.next_drawstyle = HT_RECT;
+	} else if (_thd.place_mode == VHM_RAIL) { // autorail one piece
+		_thd.place_mode = VHM_SPECIAL;
+		_thd.next_drawstyle = _thd.drawstyle;
+	} else {
+		_thd.place_mode = VHM_SPECIAL;
+		_thd.next_drawstyle = HT_POINT;
+	}
+	_special_mouse_mode = WSM_SIZING;
+}
+
+void VpSetPlaceSizingLimit(int limit)
+{
+	_thd.sizelimit = limit;
+}
+
+/**
+* Highlights all tiles between a set of two tiles. Used in dock and tunnel placement
+* @param from TileIndex of the first tile to highlight
+* @param to TileIndex of the last tile to highlight */
+void VpSetPresizeRange(TileIndex from, TileIndex to)
+{
+	uint distance = DistanceManhattan(from, to) + 1;
+
+	_thd.selend.x = TileX(to) * TILE_SIZE;
+	_thd.selend.y = TileY(to) * TILE_SIZE;
+	_thd.selstart.x = TileX(from) * TILE_SIZE;
+	_thd.selstart.y = TileY(from) * TILE_SIZE;
+	_thd.next_drawstyle = HT_RECT;
+
+	/* show measurement only if there is any length to speak of */
+	if (distance > 1) GuiShowTooltipsWithArgs(STR_MEASURE_LENGTH, 1, &distance);
+}
+
+static void VpStartPreSizing(void)
+{
+	_thd.selend.x = -1;
+	_special_mouse_mode = WSM_PRESIZE;
+}
+
+/* returns information about the 2x1 piece to be build.
+ * The lower bits (0-3) are the track type. */
+static byte Check2x1AutoRail(int mode)
+{
+	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
+	int sxpy = (_thd.selend.x & 0xF) + (_thd.selend.y & 0xF);
+	int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
+	int sxmy = (_thd.selend.x & 0xF) - (_thd.selend.y & 0xF);
+
+	switch (mode) {
+	case 0: // end piece is lower right
+		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
+		if (fxmy < -3 && sxmy > 3) {/* DoRailroadTrack(0); */return 5; }
+		return 1;
+
+	case 1:
+		if (fxmy > 3 && sxmy < -3) { /*SwapSelection(); DoRailroadTrack(0); */return 4; }
+		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
+		return 1;
+
+	case 2:
+		if (fxmy > 3 && sxmy < -3) { /*DoRailroadTrack(3);*/ return 4; }
+		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
+		return 0;
+
+	case 3:
+		if (fxmy < -3 && sxmy > 3) { /*SwapSelection(); DoRailroadTrack(3);*/ return 5; }
+		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
+		return 0;
+	}
+
+	return 0; // avoids compiler warnings
+}
+
+/** Check if the direction of start and end tile should be swapped based on
+ * the dragging-style. Default directions are:
+ * in the case of a line (HT_RAIL, HT_LINE):  DIR_NE, DIR_NW, DIR_N, DIR_E
+ * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E
+ * For example dragging a rectangle area from south to north should be swapped to
+ * north-south (DIR_S) to obtain the same results with less code. This is what
+ * the return value signifies.
+ * @param style HighLightStyle dragging style
+ * @param start_tile, end_tile start and end tile of drag
+ * @param boolean value which when true means start/end should be swapped */
+static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
+{
+	uint start_x = TileX(start_tile);
+	uint start_y = TileY(start_tile);
+	uint end_x = TileX(end_tile);
+	uint end_y = TileY(end_tile);
+
+	switch (style & HT_DRAG_MASK) {
+		case HT_RAIL:
+		case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
+
+		case HT_RECT:
+		case HT_POINT: return (end_x != start_x && end_y < start_y);
+		default: NOT_REACHED();
+	}
+
+	return false;
+}
+
+/** Calculates height difference between one tile and another
+* Multiplies the result to suit the standard given by minimap - 50 meters high
+* To correctly get the height difference we need the direction we are dragging
+* in, as well as with what kind of tool we are dragging. For example a horizontal
+* autorail tool that starts in bottom and ends at the top of a tile will need the
+* maximum of SW,S and SE,N corners respectively. This is handled by the lookup table below
+* See _tileoffs_by_dir in map.c for the direction enums if you can't figure out
+* the values yourself.
+* @param style HightlightStyle of drag. This includes direction and style (autorail, rect, etc.)
+* @param distance amount of tiles dragged, important for horizontal/vertical drags
+*        ignored for others
+* @param start_tile, end_tile start and end tile of drag operation
+* @return height difference between two tiles. Tile measurement tool utilizes
+* this value in its tooltips */
+static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
+{
+	bool swap = SwapDirection(style, start_tile, end_tile);
+	byte style_t;
+	uint h0, h1, ht; // start heigth, end height, and temp variable
+
+	if (start_tile == end_tile) return 0;
+	if (swap) swap_tile(&start_tile, &end_tile);
+
+	switch (style & HT_DRAG_MASK) {
+		case HT_RECT: {
+			static const TileIndexDiffC heightdiff_area_by_dir[] = {
+				/* Start */ {1, 0}, /* Dragging east */ {0, 0}, /* Dragging south */
+				/* End   */ {0, 1}, /* Dragging east */ {1, 1}  /* Dragging south */
+			};
+
+			/* In the case of an area we can determine whether we were dragging south or
+			 * east by checking the X-coordinates of the tiles */
+			style_t = (byte)(TileX(end_tile) > TileX(start_tile));
+			start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t]));
+			end_tile   = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t]));
+		}
+		/* Fallthrough */
+		case HT_POINT:
+			h0 = TileHeight(start_tile);
+			h1 = TileHeight(end_tile);
+			break;
+		default: { /* All other types, this is mostly only line/autorail */
+			static const HighLightStyle flip_style_direction[] = {
+				HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL
+			};
+			static const TileIndexDiffC heightdiff_line_by_dir[] = {
+				/* Start */ {1, 0}, {1, 1}, /* HT_DIR_X  */ {0, 1}, {1, 1}, /* HT_DIR_Y  */
+				/* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, /* HT_DIR_HL */
+				/* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, /* HT_DIR_VR */
+
+				/* Start */ {0, 1}, {0, 0}, /* HT_DIR_X  */ {1, 0}, {0, 0}, /* HT_DIR_Y  */
+				/* End   */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, /* HT_DIR_HL */
+				/* End   */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, /* HT_DIR_VR */
+			};
+
+			distance %= 2; // we're only interested if the distance is even or uneven
+			style &= HT_DIR_MASK;
+
+			/* To handle autorail, we do some magic to be able to use a lookup table.
+			 * Firstly if we drag the other way around, we switch start&end, and if needed
+			 * also flip the drag-position. Eg if it was on the left, and the distance is even
+			 * that means the end, which is now the start is on the right */
+			if (swap && distance == 0) style = flip_style_direction[style];
+
+			/* Use lookup table for start-tile based on HighLightStyle direction */
+			style_t = style * 2;
+			assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
+			h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t])));
+			ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1])));
+			h0 = maxu(h0, ht);
+
+			/* Use lookup table for end-tile based on HighLightStyle direction
+			 * flip around side (lower/upper, left/right) based on distance */
+			if (distance == 0) style_t = flip_style_direction[style] * 2;
+			assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
+			h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t])));
+			ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1])));
+			h1 = maxu(h1, ht);
+		} break;
+	}
+
+	if (swap) swap_uint32(&h0, &h1);
+	/* Minimap shows height in intervals of 50 meters, let's do the same */
+	return (int)(h1 - h0) * 50;
+}
+
+static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
+
+// while dragging
+static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method)
+{
+	HighLightStyle b;
+	uint w, h;
+
+	int dx = thd->selstart.x - (thd->selend.x & ~0xF);
+	int dy = thd->selstart.y - (thd->selend.y & ~0xF);
+	w = myabs(dx) + 16;
+	h = myabs(dy) + 16;
+
+	if (TileVirtXY(thd->selstart.x, thd->selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile
+		if (method == VPM_RAILDIRS) {
+			b = GetAutorailHT(x, y);
+		} else { // rect for autosignals on one tile
+			b = HT_RECT;
+		}
+	} else if (h == 16) { // Is this in X direction?
+		if (dx == 16) { // 2x1 special handling
+			b = (Check2x1AutoRail(3)) | HT_LINE;
+		} else if (dx == -16) {
+			b = (Check2x1AutoRail(2)) | HT_LINE;
+		} else {
+			b = HT_LINE | HT_DIR_X;
+		}
+		y = thd->selstart.y;
+	} else if (w == 16) { // Or Y direction?
+		if (dy == 16) { // 2x1 special handling
+			b = (Check2x1AutoRail(1)) | HT_LINE;
+		} else if (dy == -16) { // 2x1 other direction
+			b = (Check2x1AutoRail(0)) | HT_LINE;
+		} else {
+			b = HT_LINE | HT_DIR_Y;
+		}
+		x = thd->selstart.x;
+	} else if (w > h * 2) { // still count as x dir?
+		b = HT_LINE | HT_DIR_X;
+		y = thd->selstart.y;
+	} else if (h > w * 2) { // still count as y dir?
+		b = HT_LINE | HT_DIR_Y;
+		x = thd->selstart.x;
+	} else { // complicated direction
+		int d = w - h;
+		thd->selend.x = thd->selend.x & ~0xF;
+		thd->selend.y = thd->selend.y & ~0xF;
+
+		// four cases.
+		if (x > thd->selstart.x) {
+			if (y > thd->selstart.y) {
+				// south
+				if (d == 0) {
+					b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
+				} else if (d >= 0) {
+					x = thd->selstart.x + h;
+					b = HT_LINE | HT_DIR_VL;
+					// return px == py || px == py + 16;
+				} else {
+					y = thd->selstart.y + w;
+					b = HT_LINE | HT_DIR_VR;
+				} // return px == py || px == py - 16;
+			} else {
+				// west
+				if (d == 0) {
+					b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
+				} else if (d >= 0) {
+					x = thd->selstart.x + h;
+					b = HT_LINE | HT_DIR_HL;
+				} else {
+					y = thd->selstart.y - w;
+					b = HT_LINE | HT_DIR_HU;
+				}
+			}
+		} else {
+			if (y > thd->selstart.y) {
+				// east
+				if (d == 0) {
+					b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
+				} else if (d >= 0) {
+					x = thd->selstart.x - h;
+					b = HT_LINE | HT_DIR_HU;
+					// return px == -py || px == -py - 16;
+				} else {
+					y = thd->selstart.y + w;
+					b = HT_LINE | HT_DIR_HL;
+				} // return px == -py || px == -py + 16;
+			} else {
+				// north
+				if (d == 0) {
+					b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
+				} else if (d >= 0) {
+					x = thd->selstart.x - h;
+					b = HT_LINE | HT_DIR_VR;
+					// return px == py || px == py - 16;
+				} else {
+					y = thd->selstart.y - w;
+					b = HT_LINE | HT_DIR_VL;
+				} //return px == py || px == py + 16;
+			}
+		}
+	}
+
+	if (_patches.measure_tooltip) {
+		TileIndex t0 = TileVirtXY(thd->selstart.x, thd->selstart.y);
+		TileIndex t1 = TileVirtXY(x, y);
+		uint distance = DistanceManhattan(t0, t1) + 1;
+		byte index = 0;
+		uint params[2];
+
+		if (distance != 1) {
+			int heightdiff = CalcHeightdiff(b, distance, t0, t1);
+			/* If we are showing a tooltip for horizontal or vertical drags,
+			 * 2 tiles have a length of 1. To bias towards the ceiling we add
+			 * one before division. It feels more natural to count 3 lengths as 2 */
+			if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
+				distance = (distance + 1) / 2;
+			}
+
+			params[index++] = distance;
+			if (heightdiff != 0) params[index++] = heightdiff;
+		}
+
+		GuiShowTooltipsWithArgs(measure_strings_length[index], index, params);
+	}
+
+	thd->selend.x = x;
+	thd->selend.y = y;
+	thd->next_drawstyle = b;
+}
+
+/**
+ * Selects tiles while dragging
+ * @param x X coordinate of end of selection
+ * @param y Y coordinate of end of selection
+ * @param method modifies the way tiles are selected. Possible
+ * methods are VPM_* in viewport.h */
+void VpSelectTilesWithMethod(int x, int y, int method)
+{
+	int sx, sy;
+	HighLightStyle style;
+
+	if (x == -1) {
+		_thd.selend.x = -1;
+		return;
+	}
+
+	/* Special handling of drag in any (8-way) direction */
+	if (method == VPM_RAILDIRS || method == VPM_SIGNALDIRS) {
+		_thd.selend.x = x;
+		_thd.selend.y = y;
+		CalcRaildirsDrawstyle(&_thd, x, y, method);
+		return;
+	}
+
+	if (_thd.next_drawstyle == HT_POINT) {
+		x += TILE_SIZE / 2;
+		y += TILE_SIZE / 2;
+	}
+
+	sx = _thd.selstart.x;
+	sy = _thd.selstart.y;
+
+	switch (method) {
+		case VPM_X_OR_Y: /* drag in X or Y direction */
+			if (myabs(sy - y) < myabs(sx - x)) {
+				y = sy;
+				style = HT_DIR_X;
+			} else {
+				x = sx;
+				style = HT_DIR_Y;
+			}
+			goto calc_heightdiff_single_direction;
+		case VPM_FIX_X: /* drag in Y direction */
+			x = sx;
+			style = HT_DIR_Y;
+			goto calc_heightdiff_single_direction;
+		case VPM_FIX_Y: /* drag in X direction */
+			y = sy;
+			style = HT_DIR_X;
+
+calc_heightdiff_single_direction:;
+			if (_patches.measure_tooltip) {
+				TileIndex t0 = TileVirtXY(sx, sy);
+				TileIndex t1 = TileVirtXY(x, y);
+				uint distance = DistanceManhattan(t0, t1) + 1;
+				byte index = 0;
+				uint params[2];
+
+				if (distance != 1) {
+					/* With current code passing a HT_LINE style to calculate the height
+					 * difference is enough. However if/when a point-tool is created
+					 * with this method, function should be called with new_style (below)
+					 * instead of HT_LINE | style case HT_POINT is handled specially
+					 * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
+					int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1);
+
+					params[index++] = distance;
+					if (heightdiff != 0) params[index++] = heightdiff;
+				}
+
+				GuiShowTooltipsWithArgs(measure_strings_length[index], index, params);
+			} break;
+
+		case VPM_X_AND_Y_LIMITED: { /* drag an X by Y constrained rect area */
+			int limit = (_thd.sizelimit - 1) * TILE_SIZE;
+			x = sx + clamp(x - sx, -limit, limit);
+			y = sy + clamp(y - sy, -limit, limit);
+			/* Fallthrough */
+		case VPM_X_AND_Y: /* drag an X by Y area */
+			if (_patches.measure_tooltip) {
+				static const StringID measure_strings_area[] = {
+					STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
+				};
+
+				TileIndex t0 = TileVirtXY(sx, sy);
+				TileIndex t1 = TileVirtXY(x, y);
+				uint dx = abs(TileX(t0) - TileX(t1)) + 1;
+				uint dy = abs(TileY(t0) - TileY(t1)) + 1;
+				byte index = 0;
+				uint params[3];
+
+				/* If dragging an area (eg dynamite tool) and it is actually a single
+				 * row/column, change the type to 'line' to get proper calculation for height */
+				style = _thd.next_drawstyle;
+				if (style & HT_RECT) {
+					if (dx == 1) {
+						style = HT_LINE | HT_DIR_Y;
+					} else if (dy == 1) {
+						style = HT_LINE | HT_DIR_X;
+					}
+				}
+
+				if (dx != 1 || dy != 1) {
+					int heightdiff = CalcHeightdiff(style, 0, t0, t1);
+
+					params[index++] = dx;
+					params[index++] = dy;
+					if (heightdiff != 0) params[index++] = heightdiff;
+				}
+
+				GuiShowTooltipsWithArgs(measure_strings_area[index], index, params);
+			}
+		break;
+
+		}
+		default: NOT_REACHED();
+	}
+
+	_thd.selend.x = x;
+	_thd.selend.y = y;
+}
+
+// while dragging
+bool VpHandlePlaceSizingDrag(void)
+{
+	Window *w;
+	WindowEvent e;
+
+	if (_special_mouse_mode != WSM_SIZING) return true;
+
+	e.we.place.userdata = _thd.userdata;
+
+	// stop drag mode if the window has been closed
+	w = FindWindowById(_thd.window_class,_thd.window_number);
+	if (w == NULL) {
+		ResetObjectToPlace();
+		return false;
+	}
+
+	// while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() )
+	if (_left_button_down) {
+		e.event = WE_PLACE_DRAG;
+		e.we.place.pt = GetTileBelowCursor();
+		w->wndproc(w, &e);
+		return false;
+	}
+
+	// mouse button released..
+	// keep the selected tool, but reset it to the original mode.
+	_special_mouse_mode = WSM_NONE;
+	if (_thd.next_drawstyle == HT_RECT) {
+		_thd.place_mode = VHM_RECT;
+	} else if ((e.we.place.userdata & 0xF) == VPM_SIGNALDIRS) { // some might call this a hack... -- Dominik
+		_thd.place_mode = VHM_RECT;
+	} else if (_thd.next_drawstyle & HT_LINE) {
+		_thd.place_mode = VHM_RAIL;
+	} else if (_thd.next_drawstyle & HT_RAIL) {
+		_thd.place_mode = VHM_RAIL;
+	} else {
+		_thd.place_mode = VHM_POINT;
+	}
+	SetTileSelectSize(1, 1);
+
+	// and call the mouseup event.
+	e.event = WE_PLACE_MOUSEUP;
+	e.we.place.pt = _thd.selend;
+	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
+	e.we.place.starttile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
+	w->wndproc(w, &e);
+
+	return false;
+}
+
+void SetObjectToPlaceWnd(CursorID icon, byte mode, Window *w)
+{
+	SetObjectToPlace(icon, mode, w->window_class, w->window_number);
+}
+
+#include "table/animcursors.h"
+
+void SetObjectToPlace(CursorID icon, byte mode, WindowClass window_class, WindowNumber window_num)
+{
+	Window *w;
+
+	// undo clicking on button
+	if (_thd.place_mode != 0) {
+		_thd.place_mode = 0;
+		w = FindWindowById(_thd.window_class, _thd.window_number);
+		if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ);
+	}
+
+	SetTileSelectSize(1, 1);
+
+	_thd.make_square_red = false;
+
+	if (mode == VHM_DRAG) { // mode 4 is for dragdropping trains in the depot window
+		mode = 0;
+		_special_mouse_mode = WSM_DRAGDROP;
+	} else {
+		_special_mouse_mode = WSM_NONE;
+	}
+
+	_thd.place_mode = mode;
+	_thd.window_class = window_class;
+	_thd.window_number = window_num;
+
+	if (mode == VHM_SPECIAL) // special tools, like tunnels or docks start with presizing mode
+		VpStartPreSizing();
+
+	if ( (int)icon < 0)
+		SetAnimatedMouseCursor(_animcursors[~icon]);
+	else
+		SetMouseCursor(icon);
+}
+
+void ResetObjectToPlace(void)
+{
+	SetObjectToPlace(SPR_CURSOR_MOUSE, VHM_NONE, 0, 0);
+}
deleted file mode 100644
--- a/src/water_cmd.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "bridge_map.h"
-#include "station_map.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
-#include "town.h"
-#include "news.h"
-#include "sound.h"
-#include "depot.h"
-#include "vehicle_gui.h"
-#include "train.h"
-#include "water_map.h"
-#include "newgrf.h"
-
-static const SpriteID _water_shore_sprites[] = {
-	0,
-	SPR_SHORE_TILEH_1,
-	SPR_SHORE_TILEH_2,
-	SPR_SHORE_TILEH_3,
-	SPR_SHORE_TILEH_4,
-	0,
-	SPR_SHORE_TILEH_6,
-	0,
-	SPR_SHORE_TILEH_8,
-	SPR_SHORE_TILEH_9,
-	0,
-	0,
-	SPR_SHORE_TILEH_12,
-	0,
-	0
-};
-
-
-static void FloodVehicle(Vehicle *v);
-
-/** Build a ship depot.
- * @param tile tile where ship depot is built
- * @param p1 depot direction (0 == X or 1 == Y)
- * @param p2 unused
- */
-int32 CmdBuildShipDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	TileIndex tile2;
-
-	int32 cost, ret;
-	Depot *depot;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (p1 > 1) return CMD_ERROR;
-
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	tile2 = tile + (p1 ? TileDiffXY(0, 1) : TileDiffXY(1, 0));
-	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
-
-	if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2))
-		return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
-
-	if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-	ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-
-	// pretend that we're not making land from the water even though we actually are.
-	cost = 0;
-
-	depot = AllocateDepot();
-	if (depot == NULL) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		depot->xy = tile;
-		depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
-
-		MakeShipDepot(tile,_current_player, DEPOT_NORTH, p1);
-		MakeShipDepot(tile2,_current_player, DEPOT_SOUTH, p1);
-		MarkTileDirtyByTile(tile);
-		MarkTileDirtyByTile(tile2);
-	}
-
-	return cost + _price.build_ship_depot;
-}
-
-static int32 RemoveShipDepot(TileIndex tile, uint32 flags)
-{
-	TileIndex tile2;
-
-	if (!IsShipDepot(tile)) return CMD_ERROR;
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	tile2 = GetOtherShipDepotTile(tile);
-
-	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		/* Kill the depot, which is registered at the northernmost tile. Use that one */
-		DeleteDepot(GetDepotByTile(tile2 < tile ? tile2 : tile));
-
-		MakeWater(tile);
-		MakeWater(tile2);
-		MarkTileDirtyByTile(tile);
-		MarkTileDirtyByTile(tile2);
-	}
-
-	return _price.remove_ship_depot;
-}
-
-// build a shiplift
-static int32 DoBuildShiplift(TileIndex tile, DiagDirection dir, uint32 flags)
-{
-	int32 ret;
-	int delta;
-
-	// middle tile
-	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-
-	delta = TileOffsByDiagDir(dir);
-	// lower tile
-	ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-	if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
-		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	}
-
-	// upper tile
-	ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-	if (CmdFailed(ret)) return CMD_ERROR;
-	if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
-		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	}
-
-	if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
-	    (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
-	    (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
-		return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-	}
-
-	if (flags & DC_EXEC) {
-		MakeLock(tile, _current_player, dir);
-		MarkTileDirtyByTile(tile);
-		MarkTileDirtyByTile(tile - delta);
-		MarkTileDirtyByTile(tile + delta);
-	}
-
-	return _price.clear_water * 22 >> 3;
-}
-
-static int32 RemoveShiplift(TileIndex tile, uint32 flags)
-{
-	TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
-
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-	// make sure no vehicle is on the tile.
-	if (!EnsureNoVehicle(tile) || !EnsureNoVehicle(tile + delta) || !EnsureNoVehicle(tile - delta))
-		return CMD_ERROR;
-
-	if (flags & DC_EXEC) {
-		DoClearSquare(tile);
-		DoClearSquare(tile + delta);
-		DoClearSquare(tile - delta);
-	}
-
-	return _price.clear_water * 2;
-}
-
-static void MarkTilesAroundDirty(TileIndex tile)
-{
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, 1));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, -1));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 1, 0));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0));
-}
-
-/** Builds a lock (ship-lift)
- * @param tile tile where to place the lock
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	DiagDirection dir;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	switch (GetTileSlope(tile, NULL)) {
-		case SLOPE_SW: dir = DIAGDIR_SW; break;
-		case SLOPE_SE: dir = DIAGDIR_SE; break;
-		case SLOPE_NW: dir = DIAGDIR_NW; break;
-		case SLOPE_NE: dir = DIAGDIR_NE; break;
-		default: return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	}
-	return DoBuildShiplift(tile, dir, flags);
-}
-
-/** Build a piece of canal.
- * @param tile end tile of stretch-dragging
- * @param p1 start tile of stretch-dragging
- * @param p2 ctrl pressed - toggles ocean / canals at sealevel
- */
-int32 CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	int32 cost;
-	int size_x, size_y;
-	int x;
-	int y;
-	int sx, sy;
-
-	if (p1 >= MapSize()) return CMD_ERROR;
-
-	x = TileX(tile);
-	y = TileY(tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (x < sx) intswap(x, sx);
-	if (y < sy) intswap(y, sy);
-	size_x = (x - sx) + 1;
-	size_y = (y - sy) + 1;
-
-	/* Outside the editor you can only drag canals, and not areas */
-	if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
-
-	cost = 0;
-	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
-		int32 ret;
-
-		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) {
-			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-		}
-
-		// can't make water of water!
-		if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) continue;
-
-		ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-		if (CmdFailed(ret)) return ret;
-		cost += ret;
-
-		if (flags & DC_EXEC) {
-			if (TileHeight(tile) == 0 && HASBIT(p2, 0)) {
-				MakeWater(tile);
-			} else {
-				MakeCanal(tile, _current_player);
-			}
-			MarkTileDirtyByTile(tile);
-			MarkTilesAroundDirty(tile);
-		}
-
-		cost += _price.clear_water;
-	} END_TILE_LOOP(tile, size_x, size_y, 0);
-
-	if (cost == 0) {
-		return_cmd_error(STR_1007_ALREADY_BUILT);
-	} else {
-		return cost;
-	}
-}
-
-static int32 ClearTile_Water(TileIndex tile, byte flags)
-{
-	switch (GetWaterTileType(tile)) {
-		case WATER_CLEAR:
-			if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
-
-			// Make sure no vehicle is on the tile
-			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-			// Make sure it's not an edge tile.
-			if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) ||
-					!IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) {
-				return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
-			}
-
-			if (GetTileOwner(tile) != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
-
-			if (flags & DC_EXEC) DoClearSquare(tile);
-			return _price.clear_water;
-
-		case WATER_COAST: {
-			Slope slope = GetTileSlope(tile, NULL);
-
-			// Make sure no vehicle is on the tile
-			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-			// Make sure it's not an edge tile.
-			if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) ||
-					!IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) {
-				return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
-			}
-
-			if (flags & DC_EXEC) DoClearSquare(tile);
-			if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) {
-				return _price.clear_water;
-			} else {
-				return _price.purchase_land;
-			}
-		}
-
-		case WATER_LOCK: {
-			static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
-				{ 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
-				{-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
-				{ 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
-			};
-
-			if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
-			if (_current_player == OWNER_WATER) return CMD_ERROR;
-			// move to the middle tile..
-			return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
-		}
-
-		case WATER_DEPOT:
-			if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
-			return RemoveShipDepot(tile, flags);
-
-		default:
-			NOT_REACHED();
-			return 0;
-	}
-
-	return 0; // useless but silences warning
-}
-
-// return true if a tile is a water tile.
-static bool IsWateredTile(TileIndex tile)
-{
-	switch (GetTileType(tile)) {
-		case MP_WATER:
-			if (!IsCoast(tile)) return true;
-
-			switch (GetTileSlope(tile, NULL)) {
-				case SLOPE_W:
-				case SLOPE_S:
-				case SLOPE_E:
-				case SLOPE_N:
-					return true;
-
-				default:
-					return false;
-			}
-
-		case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
-		default:         return false;
-	}
-}
-
-// draw a canal styled water tile with dikes around
-void DrawCanalWater(TileIndex tile)
-{
-	uint wa;
-
-	// determine the edges around with water.
-	wa = IsWateredTile(TILE_ADDXY(tile, -1, 0)) << 0;
-	wa += IsWateredTile(TILE_ADDXY(tile, 0, 1)) << 1;
-	wa += IsWateredTile(TILE_ADDXY(tile, 1, 0)) << 2;
-	wa += IsWateredTile(TILE_ADDXY(tile, 0, -1)) << 3;
-
-	if (!(wa & 1)) DrawGroundSprite(SPR_CANALS_BASE + 57);
-	if (!(wa & 2)) DrawGroundSprite(SPR_CANALS_BASE + 58);
-	if (!(wa & 4)) DrawGroundSprite(SPR_CANALS_BASE + 59);
-	if (!(wa & 8)) DrawGroundSprite(SPR_CANALS_BASE + 60);
-
-	// right corner
-	switch (wa & 0x03) {
-		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 4); break;
-		case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 8); break;
-	}
-
-	// bottom corner
-	switch (wa & 0x06) {
-		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 5); break;
-		case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 9); break;
-	}
-
-	// left corner
-	switch (wa & 0x0C) {
-		case  0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 6); break;
-		case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 10); break;
-	}
-
-	// upper corner
-	switch (wa & 0x09) {
-		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 7); break;
-		case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 11); break;
-	}
-}
-
-typedef struct LocksDrawTileStruct {
-	int8 delta_x, delta_y, delta_z;
-	byte width, height, depth;
-	SpriteID image;
-} LocksDrawTileStruct;
-
-#include "table/water_land.h"
-
-static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
-	uint32 palette, uint base
-)
-{
-	DrawGroundSprite(wdts++->image);
-
-	for (; wdts->delta_x != 0x80; wdts++) {
-		uint32 image = wdts->image + base;
-		if (_display_opt & DO_TRANS_BUILDINGS) {
-			MAKE_TRANSPARENT(image);
-		} else {
-			image |= palette;
-		}
-		AddSortableSpriteToDraw(image, ti->x + wdts->delta_x, ti->y + wdts->delta_y, wdts->width, wdts->height, wdts->unk, ti->z + wdts->delta_z);
-	}
-}
-
-static void DrawTile_Water(TileInfo *ti)
-{
-	switch (GetWaterTileType(ti->tile)) {
-		case WATER_CLEAR:
-			DrawGroundSprite(SPR_FLAT_WATER_TILE);
-			if (ti->z != 0 || !IsTileOwner(ti->tile, OWNER_WATER)) DrawCanalWater(ti->tile);
-			DrawBridgeMiddle(ti);
-			break;
-
-		case WATER_COAST:
-			assert(!IsSteepSlope(ti->tileh));
-			if (_coast_base != 0) {
-				DrawGroundSprite(_coast_base + ti->tileh);
-			} else {
-				DrawGroundSprite(_water_shore_sprites[ti->tileh]);
-			}
-			DrawBridgeMiddle(ti);
-			break;
-
-		case WATER_LOCK: {
-			const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
-			DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0);
-		} break;
-
-		case WATER_DEPOT:
-			DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)), 0);
-			break;
-	}
-}
-
-void DrawShipDepotSprite(int x, int y, int image)
-{
-	const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
-
-	DrawSprite(wdts++->image, x, y);
-
-	for (; wdts->delta_x != 0x80; wdts++) {
-		Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
-		DrawSprite(wdts->image + PLAYER_SPRITE_COLOR(_local_player), x + pt.x, y + pt.y);
-	}
-}
-
-
-static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
-{
-	uint z;
-	uint tileh = GetTileSlope(tile, &z);
-
-	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
-}
-
-static Slope GetSlopeTileh_Water(TileIndex tile, Slope tileh)
-{
-	return tileh;
-}
-
-static void GetAcceptedCargo_Water(TileIndex tile, AcceptedCargo ac)
-{
-	/* not used */
-}
-
-static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
-{
-	switch (GetWaterTileType(tile)) {
-		case WATER_CLEAR:
-			if (TilePixelHeight(tile) == 0 || IsTileOwner(tile, OWNER_WATER)) {
-				td->str = STR_3804_WATER;
-			} else {
-				td->str = STR_LANDINFO_CANAL;
-			}
-			break;
-		case WATER_COAST: td->str = STR_3805_COAST_OR_RIVERBANK; break;
-		case WATER_LOCK : td->str = STR_LANDINFO_LOCK; break;
-		case WATER_DEPOT: td->str = STR_3806_SHIP_DEPOT; break;
-		default: assert(0); break;
-	}
-
-	td->owner = GetTileOwner(tile);
-}
-
-static void AnimateTile_Water(TileIndex tile)
-{
-	/* not used */
-}
-
-static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs)
-{
-	TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0]));
-
-	// type of this tile mustn't be water already.
-	if (IsTileType(target, MP_WATER)) return;
-
-	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 ||
-			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) {
-		return;
-	}
-
-	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 ||
-			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) {
-		// make coast..
-		switch (GetTileType(target)) {
-			case MP_RAILWAY: {
-				TrackBits tracks;
-				Slope slope;
-
-				if (!IsPlainRailTile(target)) break;
-
-				tracks = GetTrackBits(target);
-				slope = GetTileSlope(target, NULL);
-				if (!(
-							(slope == SLOPE_W && tracks == TRACK_BIT_RIGHT) ||
-							(slope == SLOPE_S && tracks == TRACK_BIT_UPPER) ||
-							(slope == SLOPE_E && tracks == TRACK_BIT_LEFT)  ||
-							(slope == SLOPE_N && tracks == TRACK_BIT_LOWER)
-						)) {
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-
-			case MP_CLEAR:
-			case MP_TREES:
-				_current_player = OWNER_WATER;
-				if (!CmdFailed(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
-					MakeShore(target);
-					MarkTileDirtyByTile(target);
-				}
-				break;
-
-			default:
-				break;
-		}
-	} else {
-		_current_player = OWNER_WATER;
-		{
-			Vehicle *v = FindVehicleOnTileZ(target, 0);
-			if (v != NULL) FloodVehicle(v);
-		}
-
-		if (!CmdFailed(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
-			MakeWater(target);
-			MarkTileDirtyByTile(target);
-		}
-	}
-}
-
-static void FloodVehicle(Vehicle *v)
-{
-	if (!(v->vehstatus & VS_CRASHED)) {
-		uint16 pass = 0;
-
-		if (v->type == VEH_Road) { // flood bus/truck
-			pass = 1; // driver
-			if (v->cargo_type == CT_PASSENGERS)
-				pass += v->cargo_count;
-
-			v->vehstatus |= VS_CRASHED;
-			v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
-			RebuildVehicleLists();
-		} else if (v->type == VEH_Train) {
-			Vehicle *u;
-
-			v = GetFirstVehicleInChain(v);
-			u = v;
-			if (IsFrontEngine(v)) pass = 4; // driver
-
-			// crash all wagons, and count passangers
-			BEGIN_ENUM_WAGONS(v)
-				if (v->cargo_type == CT_PASSENGERS) pass += v->cargo_count;
-				v->vehstatus |= VS_CRASHED;
-			END_ENUM_WAGONS(v)
-
-			v = u;
-			v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
-			RebuildVehicleLists();
-		} else {
-			return;
-		}
-
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-
-		SetDParam(0, pass);
-		AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
-			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
-			v->index,
-			0);
-		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
-		SndPlayVehicleFx(SND_12_EXPLOSION, v);
-	}
-}
-
-// called from tunnelbridge_cmd, and by TileLoop_Industry()
-void TileLoop_Water(TileIndex tile)
-{
-	static const TileIndexDiffC _tile_loop_offs_array[][5] = {
-		// tile to mod              shore?    shore?
-		{{-1,  0}, {0, 0}, {0, 1}, {-1,  0}, {-1,  1}},
-		{{ 0,  1}, {0, 1}, {1, 1}, { 0,  2}, { 1,  2}},
-		{{ 1,  0}, {1, 0}, {1, 1}, { 2,  0}, { 2,  1}},
-		{{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}}
-	};
-
-	/* Ensure sea-level canals do not flood */
-	if ((IsTileType(tile, MP_WATER) || IsTileType(tile, MP_TUNNELBRIDGE)) &&
-			!IsTileOwner(tile, OWNER_WATER)) return;
-
-	if (IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1) &&
-			IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) {
-		uint i;
-
-		for (i = 0; i != lengthof(_tile_loop_offs_array); i++) {
-			TileLoopWaterHelper(tile, _tile_loop_offs_array[i]);
-		}
-	}
-	// _current_player can be changed by TileLoopWaterHelper.. reset it back
-	//   here
-	_current_player = OWNER_NONE;
-
-	// edges
-	if (TileX(tile) == 0 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[2]);
-	}
-
-	if (TileX(tile) == MapSizeX() - 2 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[0]);
-	}
-
-	if (TileY(tile) == 0 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[1]);
-	}
-
-	if (TileY(tile) == MapSizeY() - 2 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[3]);
-	}
-}
-
-static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode)
-{
-	static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
-
-	TrackBits ts;
-
-	if (mode != TRANSPORT_WATER) return 0;
-
-	switch (GetWaterTileType(tile)) {
-		case WATER_CLEAR: ts = TRACK_BIT_ALL; break;
-		case WATER_COAST: ts = coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
-		case WATER_LOCK:  ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
-		case WATER_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
-		default: return 0;
-	}
-	if (TileX(tile) == 0) {
-		// NE border: remove tracks that connects NE tile edge
-		ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
-	}
-	if (TileY(tile) == 0) {
-		// NW border: remove tracks that connects NW tile edge
-		ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
-	}
-	return ts * 0x101;
-}
-
-static void ClickTile_Water(TileIndex tile)
-{
-	if (GetWaterTileType(tile) == WATER_DEPOT) {
-		TileIndex tile2 = GetOtherShipDepotTile(tile);
-
-		ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_Ship);
-	}
-}
-
-static void ChangeTileOwner_Water(TileIndex tile, PlayerID old_player, PlayerID new_player)
-{
-	if (!IsTileOwner(tile, old_player)) return;
-
-	if (new_player != PLAYER_SPECTATOR) {
-		SetTileOwner(tile, new_player);
-	} else {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
-	}
-}
-
-static uint32 VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
-{
-	return 0;
-}
-
-
-const TileTypeProcs _tile_type_water_procs = {
-	DrawTile_Water,           /* draw_tile_proc */
-	GetSlopeZ_Water,          /* get_slope_z_proc */
-	ClearTile_Water,          /* clear_tile_proc */
-	GetAcceptedCargo_Water,   /* get_accepted_cargo_proc */
-	GetTileDesc_Water,        /* get_tile_desc_proc */
-	GetTileTrackStatus_Water, /* get_tile_track_status_proc */
-	ClickTile_Water,          /* click_tile_proc */
-	AnimateTile_Water,        /* animate_tile_proc */
-	TileLoop_Water,           /* tile_loop_clear */
-	ChangeTileOwner_Water,    /* change_tile_owner_clear */
-	NULL,                     /* get_produced_cargo_proc */
-	VehicleEnter_Water,       /* vehicle_enter_tile_proc */
-	GetSlopeTileh_Water,      /* get_slope_tileh_proc */
-};
new file mode 100644
--- /dev/null
+++ b/src/water_cmd.cpp
@@ -0,0 +1,731 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "bridge_map.h"
+#include "station_map.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "functions.h"
+#include "map.h"
+#include "tile.h"
+#include "vehicle.h"
+#include "viewport.h"
+#include "command.h"
+#include "town.h"
+#include "news.h"
+#include "sound.h"
+#include "depot.h"
+#include "vehicle_gui.h"
+#include "train.h"
+#include "water_map.h"
+#include "newgrf.h"
+
+static const SpriteID _water_shore_sprites[] = {
+	0,
+	SPR_SHORE_TILEH_1,
+	SPR_SHORE_TILEH_2,
+	SPR_SHORE_TILEH_3,
+	SPR_SHORE_TILEH_4,
+	0,
+	SPR_SHORE_TILEH_6,
+	0,
+	SPR_SHORE_TILEH_8,
+	SPR_SHORE_TILEH_9,
+	0,
+	0,
+	SPR_SHORE_TILEH_12,
+	0,
+	0
+};
+
+
+static void FloodVehicle(Vehicle *v);
+
+/** Build a ship depot.
+ * @param tile tile where ship depot is built
+ * @param p1 depot direction (0 == X or 1 == Y)
+ * @param p2 unused
+ */
+int32 CmdBuildShipDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	TileIndex tile2;
+
+	int32 cost, ret;
+	Depot *depot;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (p1 > 1) return CMD_ERROR;
+
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	tile2 = tile + (p1 ? TileDiffXY(0, 1) : TileDiffXY(1, 0));
+	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
+
+	if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2))
+		return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
+
+	if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
+	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+	ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+
+	// pretend that we're not making land from the water even though we actually are.
+	cost = 0;
+
+	depot = AllocateDepot();
+	if (depot == NULL) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		depot->xy = tile;
+		depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
+
+		MakeShipDepot(tile,_current_player, DEPOT_NORTH, p1);
+		MakeShipDepot(tile2,_current_player, DEPOT_SOUTH, p1);
+		MarkTileDirtyByTile(tile);
+		MarkTileDirtyByTile(tile2);
+	}
+
+	return cost + _price.build_ship_depot;
+}
+
+static int32 RemoveShipDepot(TileIndex tile, uint32 flags)
+{
+	TileIndex tile2;
+
+	if (!IsShipDepot(tile)) return CMD_ERROR;
+	if (!CheckTileOwnership(tile)) return CMD_ERROR;
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	tile2 = GetOtherShipDepotTile(tile);
+
+	if (!EnsureNoVehicle(tile2)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		/* Kill the depot, which is registered at the northernmost tile. Use that one */
+		DeleteDepot(GetDepotByTile(tile2 < tile ? tile2 : tile));
+
+		MakeWater(tile);
+		MakeWater(tile2);
+		MarkTileDirtyByTile(tile);
+		MarkTileDirtyByTile(tile2);
+	}
+
+	return _price.remove_ship_depot;
+}
+
+// build a shiplift
+static int32 DoBuildShiplift(TileIndex tile, DiagDirection dir, uint32 flags)
+{
+	int32 ret;
+	int delta;
+
+	// middle tile
+	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+
+	delta = TileOffsByDiagDir(dir);
+	// lower tile
+	ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+	if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
+		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	}
+
+	// upper tile
+	ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	if (CmdFailed(ret)) return CMD_ERROR;
+	if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
+		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	}
+
+	if ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
+	    (MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
+	    (MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
+		return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+	}
+
+	if (flags & DC_EXEC) {
+		MakeLock(tile, _current_player, dir);
+		MarkTileDirtyByTile(tile);
+		MarkTileDirtyByTile(tile - delta);
+		MarkTileDirtyByTile(tile + delta);
+	}
+
+	return _price.clear_water * 22 >> 3;
+}
+
+static int32 RemoveShiplift(TileIndex tile, uint32 flags)
+{
+	TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile));
+
+	if (!CheckTileOwnership(tile)) return CMD_ERROR;
+
+	// make sure no vehicle is on the tile.
+	if (!EnsureNoVehicle(tile) || !EnsureNoVehicle(tile + delta) || !EnsureNoVehicle(tile - delta))
+		return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		DoClearSquare(tile);
+		DoClearSquare(tile + delta);
+		DoClearSquare(tile - delta);
+	}
+
+	return _price.clear_water * 2;
+}
+
+static void MarkTilesAroundDirty(TileIndex tile)
+{
+	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, 1));
+	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, -1));
+	MarkTileDirtyByTile(TILE_ADDXY(tile, 1, 0));
+	MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0));
+}
+
+/** Builds a lock (ship-lift)
+ * @param tile tile where to place the lock
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	DiagDirection dir;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	switch (GetTileSlope(tile, NULL)) {
+		case SLOPE_SW: dir = DIAGDIR_SW; break;
+		case SLOPE_SE: dir = DIAGDIR_SE; break;
+		case SLOPE_NW: dir = DIAGDIR_NW; break;
+		case SLOPE_NE: dir = DIAGDIR_NE; break;
+		default: return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	}
+	return DoBuildShiplift(tile, dir, flags);
+}
+
+/** Build a piece of canal.
+ * @param tile end tile of stretch-dragging
+ * @param p1 start tile of stretch-dragging
+ * @param p2 ctrl pressed - toggles ocean / canals at sealevel
+ */
+int32 CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	int32 cost;
+	int size_x, size_y;
+	int x;
+	int y;
+	int sx, sy;
+
+	if (p1 >= MapSize()) return CMD_ERROR;
+
+	x = TileX(tile);
+	y = TileY(tile);
+	sx = TileX(p1);
+	sy = TileY(p1);
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	if (x < sx) intswap(x, sx);
+	if (y < sy) intswap(y, sy);
+	size_x = (x - sx) + 1;
+	size_y = (y - sy) + 1;
+
+	/* Outside the editor you can only drag canals, and not areas */
+	if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR;
+
+	cost = 0;
+	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+		int32 ret;
+
+		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) {
+			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+		}
+
+		// can't make water of water!
+		if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) continue;
+
+		ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+		if (CmdFailed(ret)) return ret;
+		cost += ret;
+
+		if (flags & DC_EXEC) {
+			if (TileHeight(tile) == 0 && HASBIT(p2, 0)) {
+				MakeWater(tile);
+			} else {
+				MakeCanal(tile, _current_player);
+			}
+			MarkTileDirtyByTile(tile);
+			MarkTilesAroundDirty(tile);
+		}
+
+		cost += _price.clear_water;
+	} END_TILE_LOOP(tile, size_x, size_y, 0);
+
+	if (cost == 0) {
+		return_cmd_error(STR_1007_ALREADY_BUILT);
+	} else {
+		return cost;
+	}
+}
+
+static int32 ClearTile_Water(TileIndex tile, byte flags)
+{
+	switch (GetWaterTileType(tile)) {
+		case WATER_CLEAR:
+			if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
+
+			// Make sure no vehicle is on the tile
+			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+			// Make sure it's not an edge tile.
+			if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) ||
+					!IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) {
+				return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
+			}
+
+			if (GetTileOwner(tile) != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
+
+			if (flags & DC_EXEC) DoClearSquare(tile);
+			return _price.clear_water;
+
+		case WATER_COAST: {
+			Slope slope = GetTileSlope(tile, NULL);
+
+			// Make sure no vehicle is on the tile
+			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+			// Make sure it's not an edge tile.
+			if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) ||
+					!IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) {
+				return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
+			}
+
+			if (flags & DC_EXEC) DoClearSquare(tile);
+			if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) {
+				return _price.clear_water;
+			} else {
+				return _price.purchase_land;
+			}
+		}
+
+		case WATER_LOCK: {
+			static const TileIndexDiffC _shiplift_tomiddle_offs[] = {
+				{ 0,  0}, {0,  0}, { 0, 0}, {0,  0}, // middle
+				{-1,  0}, {0,  1}, { 1, 0}, {0, -1}, // lower
+				{ 1,  0}, {0, -1}, {-1, 0}, {0,  1}, // upper
+			};
+
+			if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+			if (_current_player == OWNER_WATER) return CMD_ERROR;
+			// move to the middle tile..
+			return RemoveShiplift(tile + ToTileIndexDiff(_shiplift_tomiddle_offs[GetSection(tile)]), flags);
+		}
+
+		case WATER_DEPOT:
+			if (flags & DC_AUTO) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
+			return RemoveShipDepot(tile, flags);
+
+		default:
+			NOT_REACHED();
+			return 0;
+	}
+
+	return 0; // useless but silences warning
+}
+
+// return true if a tile is a water tile.
+static bool IsWateredTile(TileIndex tile)
+{
+	switch (GetTileType(tile)) {
+		case MP_WATER:
+			if (!IsCoast(tile)) return true;
+
+			switch (GetTileSlope(tile, NULL)) {
+				case SLOPE_W:
+				case SLOPE_S:
+				case SLOPE_E:
+				case SLOPE_N:
+					return true;
+
+				default:
+					return false;
+			}
+
+		case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
+		default:         return false;
+	}
+}
+
+// draw a canal styled water tile with dikes around
+void DrawCanalWater(TileIndex tile)
+{
+	uint wa;
+
+	// determine the edges around with water.
+	wa = IsWateredTile(TILE_ADDXY(tile, -1, 0)) << 0;
+	wa += IsWateredTile(TILE_ADDXY(tile, 0, 1)) << 1;
+	wa += IsWateredTile(TILE_ADDXY(tile, 1, 0)) << 2;
+	wa += IsWateredTile(TILE_ADDXY(tile, 0, -1)) << 3;
+
+	if (!(wa & 1)) DrawGroundSprite(SPR_CANALS_BASE + 57);
+	if (!(wa & 2)) DrawGroundSprite(SPR_CANALS_BASE + 58);
+	if (!(wa & 4)) DrawGroundSprite(SPR_CANALS_BASE + 59);
+	if (!(wa & 8)) DrawGroundSprite(SPR_CANALS_BASE + 60);
+
+	// right corner
+	switch (wa & 0x03) {
+		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 4); break;
+		case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 8); break;
+	}
+
+	// bottom corner
+	switch (wa & 0x06) {
+		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 5); break;
+		case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 9); break;
+	}
+
+	// left corner
+	switch (wa & 0x0C) {
+		case  0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 6); break;
+		case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 10); break;
+	}
+
+	// upper corner
+	switch (wa & 0x09) {
+		case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 7); break;
+		case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 11); break;
+	}
+}
+
+typedef struct LocksDrawTileStruct {
+	int8 delta_x, delta_y, delta_z;
+	byte width, height, depth;
+	SpriteID image;
+} LocksDrawTileStruct;
+
+#include "table/water_land.h"
+
+static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts,
+	uint32 palette, uint base
+)
+{
+	DrawGroundSprite(wdts++->image);
+
+	for (; wdts->delta_x != 0x80; wdts++) {
+		uint32 image = wdts->image + base;
+		if (_display_opt & DO_TRANS_BUILDINGS) {
+			MAKE_TRANSPARENT(image);
+		} else {
+			image |= palette;
+		}
+		AddSortableSpriteToDraw(image, ti->x + wdts->delta_x, ti->y + wdts->delta_y, wdts->width, wdts->height, wdts->unk, ti->z + wdts->delta_z);
+	}
+}
+
+static void DrawTile_Water(TileInfo *ti)
+{
+	switch (GetWaterTileType(ti->tile)) {
+		case WATER_CLEAR:
+			DrawGroundSprite(SPR_FLAT_WATER_TILE);
+			if (ti->z != 0 || !IsTileOwner(ti->tile, OWNER_WATER)) DrawCanalWater(ti->tile);
+			DrawBridgeMiddle(ti);
+			break;
+
+		case WATER_COAST:
+			assert(!IsSteepSlope(ti->tileh));
+			if (_coast_base != 0) {
+				DrawGroundSprite(_coast_base + ti->tileh);
+			} else {
+				DrawGroundSprite(_water_shore_sprites[ti->tileh]);
+			}
+			DrawBridgeMiddle(ti);
+			break;
+
+		case WATER_LOCK: {
+			const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)];
+			DrawWaterStuff(ti, t, 0, ti->z > t[3].delta_y ? 24 : 0);
+		} break;
+
+		case WATER_DEPOT:
+			DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)), 0);
+			break;
+	}
+}
+
+void DrawShipDepotSprite(int x, int y, int image)
+{
+	const WaterDrawTileStruct *wdts = _shipdepot_display_seq[image];
+
+	DrawSprite(wdts++->image, x, y);
+
+	for (; wdts->delta_x != 0x80; wdts++) {
+		Point pt = RemapCoords(wdts->delta_x, wdts->delta_y, wdts->delta_z);
+		DrawSprite(wdts->image + PLAYER_SPRITE_COLOR(_local_player), x + pt.x, y + pt.y);
+	}
+}
+
+
+static uint GetSlopeZ_Water(TileIndex tile, uint x, uint y)
+{
+	uint z;
+	uint tileh = GetTileSlope(tile, &z);
+
+	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
+}
+
+static Slope GetSlopeTileh_Water(TileIndex tile, Slope tileh)
+{
+	return tileh;
+}
+
+static void GetAcceptedCargo_Water(TileIndex tile, AcceptedCargo ac)
+{
+	/* not used */
+}
+
+static void GetTileDesc_Water(TileIndex tile, TileDesc *td)
+{
+	switch (GetWaterTileType(tile)) {
+		case WATER_CLEAR:
+			if (TilePixelHeight(tile) == 0 || IsTileOwner(tile, OWNER_WATER)) {
+				td->str = STR_3804_WATER;
+			} else {
+				td->str = STR_LANDINFO_CANAL;
+			}
+			break;
+		case WATER_COAST: td->str = STR_3805_COAST_OR_RIVERBANK; break;
+		case WATER_LOCK : td->str = STR_LANDINFO_LOCK; break;
+		case WATER_DEPOT: td->str = STR_3806_SHIP_DEPOT; break;
+		default: assert(0); break;
+	}
+
+	td->owner = GetTileOwner(tile);
+}
+
+static void AnimateTile_Water(TileIndex tile)
+{
+	/* not used */
+}
+
+static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs)
+{
+	TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0]));
+
+	// type of this tile mustn't be water already.
+	if (IsTileType(target, MP_WATER)) return;
+
+	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 ||
+			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) {
+		return;
+	}
+
+	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 ||
+			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) {
+		// make coast..
+		switch (GetTileType(target)) {
+			case MP_RAILWAY: {
+				TrackBits tracks;
+				Slope slope;
+
+				if (!IsPlainRailTile(target)) break;
+
+				tracks = GetTrackBits(target);
+				slope = GetTileSlope(target, NULL);
+				if (!(
+							(slope == SLOPE_W && tracks == TRACK_BIT_RIGHT) ||
+							(slope == SLOPE_S && tracks == TRACK_BIT_UPPER) ||
+							(slope == SLOPE_E && tracks == TRACK_BIT_LEFT)  ||
+							(slope == SLOPE_N && tracks == TRACK_BIT_LOWER)
+						)) {
+					break;
+				}
+			}
+			/* FALLTHROUGH */
+
+			case MP_CLEAR:
+			case MP_TREES:
+				_current_player = OWNER_WATER;
+				if (!CmdFailed(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
+					MakeShore(target);
+					MarkTileDirtyByTile(target);
+				}
+				break;
+
+			default:
+				break;
+		}
+	} else {
+		_current_player = OWNER_WATER;
+		{
+			Vehicle *v = FindVehicleOnTileZ(target, 0);
+			if (v != NULL) FloodVehicle(v);
+		}
+
+		if (!CmdFailed(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
+			MakeWater(target);
+			MarkTileDirtyByTile(target);
+		}
+	}
+}
+
+static void FloodVehicle(Vehicle *v)
+{
+	if (!(v->vehstatus & VS_CRASHED)) {
+		uint16 pass = 0;
+
+		if (v->type == VEH_Road) { // flood bus/truck
+			pass = 1; // driver
+			if (v->cargo_type == CT_PASSENGERS)
+				pass += v->cargo_count;
+
+			v->vehstatus |= VS_CRASHED;
+			v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
+			RebuildVehicleLists();
+		} else if (v->type == VEH_Train) {
+			Vehicle *u;
+
+			v = GetFirstVehicleInChain(v);
+			u = v;
+			if (IsFrontEngine(v)) pass = 4; // driver
+
+			// crash all wagons, and count passangers
+			BEGIN_ENUM_WAGONS(v)
+				if (v->cargo_type == CT_PASSENGERS) pass += v->cargo_count;
+				v->vehstatus |= VS_CRASHED;
+			END_ENUM_WAGONS(v)
+
+			v = u;
+			v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
+			RebuildVehicleLists();
+		} else {
+			return;
+		}
+
+		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+
+		SetDParam(0, pass);
+		AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
+			NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
+			v->index,
+			0);
+		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
+		SndPlayVehicleFx(SND_12_EXPLOSION, v);
+	}
+}
+
+// called from tunnelbridge_cmd, and by TileLoop_Industry()
+void TileLoop_Water(TileIndex tile)
+{
+	static const TileIndexDiffC _tile_loop_offs_array[][5] = {
+		// tile to mod              shore?    shore?
+		{{-1,  0}, {0, 0}, {0, 1}, {-1,  0}, {-1,  1}},
+		{{ 0,  1}, {0, 1}, {1, 1}, { 0,  2}, { 1,  2}},
+		{{ 1,  0}, {1, 0}, {1, 1}, { 2,  0}, { 2,  1}},
+		{{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}}
+	};
+
+	/* Ensure sea-level canals do not flood */
+	if ((IsTileType(tile, MP_WATER) || IsTileType(tile, MP_TUNNELBRIDGE)) &&
+			!IsTileOwner(tile, OWNER_WATER)) return;
+
+	if (IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1) &&
+			IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) {
+		uint i;
+
+		for (i = 0; i != lengthof(_tile_loop_offs_array); i++) {
+			TileLoopWaterHelper(tile, _tile_loop_offs_array[i]);
+		}
+	}
+	// _current_player can be changed by TileLoopWaterHelper.. reset it back
+	//   here
+	_current_player = OWNER_NONE;
+
+	// edges
+	if (TileX(tile) == 0 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE
+		TileLoopWaterHelper(tile, _tile_loop_offs_array[2]);
+	}
+
+	if (TileX(tile) == MapSizeX() - 2 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW
+		TileLoopWaterHelper(tile, _tile_loop_offs_array[0]);
+	}
+
+	if (TileY(tile) == 0 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW
+		TileLoopWaterHelper(tile, _tile_loop_offs_array[1]);
+	}
+
+	if (TileY(tile) == MapSizeY() - 2 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE
+		TileLoopWaterHelper(tile, _tile_loop_offs_array[3]);
+	}
+}
+
+static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode)
+{
+	static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0};
+
+	TrackBits ts;
+
+	if (mode != TRANSPORT_WATER) return 0;
+
+	switch (GetWaterTileType(tile)) {
+		case WATER_CLEAR: ts = TRACK_BIT_ALL; break;
+		case WATER_COAST: ts = coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
+		case WATER_LOCK:  ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
+		case WATER_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
+		default: return 0;
+	}
+	if (TileX(tile) == 0) {
+		// NE border: remove tracks that connects NE tile edge
+		ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
+	}
+	if (TileY(tile) == 0) {
+		// NW border: remove tracks that connects NW tile edge
+		ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
+	}
+	return ts * 0x101;
+}
+
+static void ClickTile_Water(TileIndex tile)
+{
+	if (GetWaterTileType(tile) == WATER_DEPOT) {
+		TileIndex tile2 = GetOtherShipDepotTile(tile);
+
+		ShowDepotWindow(tile < tile2 ? tile : tile2, VEH_Ship);
+	}
+}
+
+static void ChangeTileOwner_Water(TileIndex tile, PlayerID old_player, PlayerID new_player)
+{
+	if (!IsTileOwner(tile, old_player)) return;
+
+	if (new_player != PLAYER_SPECTATOR) {
+		SetTileOwner(tile, new_player);
+	} else {
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	}
+}
+
+static uint32 VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y)
+{
+	return 0;
+}
+
+
+const TileTypeProcs _tile_type_water_procs = {
+	DrawTile_Water,           /* draw_tile_proc */
+	GetSlopeZ_Water,          /* get_slope_z_proc */
+	ClearTile_Water,          /* clear_tile_proc */
+	GetAcceptedCargo_Water,   /* get_accepted_cargo_proc */
+	GetTileDesc_Water,        /* get_tile_desc_proc */
+	GetTileTrackStatus_Water, /* get_tile_track_status_proc */
+	ClickTile_Water,          /* click_tile_proc */
+	AnimateTile_Water,        /* animate_tile_proc */
+	TileLoop_Water,           /* tile_loop_clear */
+	ChangeTileOwner_Water,    /* change_tile_owner_clear */
+	NULL,                     /* get_produced_cargo_proc */
+	VehicleEnter_Water,       /* vehicle_enter_tile_proc */
+	GetSlopeTileh_Water,      /* get_slope_tileh_proc */
+};
deleted file mode 100644
--- a/src/waypoint.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-
-#include "command.h"
-#include "functions.h"
-#include "gfx.h"
-#include "map.h"
-#include "order.h"
-#include "rail_map.h"
-#include "bridge_map.h"
-#include "saveload.h"
-#include "station.h"
-#include "tile.h"
-#include "town.h"
-#include "waypoint.h"
-#include "variables.h"
-#include "table/strings.h"
-#include "vehicle.h"
-#include "yapf/yapf.h"
-#include "date.h"
-
-enum {
-	MAX_WAYPOINTS_PER_TOWN = 64,
-};
-
-/**
- * Called if a new block is added to the waypoint-pool
- */
-static void WaypointPoolNewBlock(uint start_item)
-{
-	Waypoint *wp;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (wp = GetWaypoint(start_item); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) wp->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Waypoint, Waypoint, WaypointPoolNewBlock, NULL)
-
-/* Create a new waypoint */
-static Waypoint* AllocateWaypoint(void)
-{
-	Waypoint *wp;
-
-	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
-	 * TODO - This is just a temporary stage, this will be removed. */
-	for (wp = GetWaypoint(0); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) {
-		if (!IsValidWaypoint(wp)) {
-			uint index = wp->index;
-
-			memset(wp, 0, sizeof(*wp));
-			wp->index = index;
-
-			return wp;
-		}
-	}
-
-	/* Check if we can add a block to the pool */
-	if (AddBlockToPool(&_Waypoint_pool)) return AllocateWaypoint();
-
-	return NULL;
-}
-
-/* Update the sign for the waypoint */
-static void UpdateWaypointSign(Waypoint* wp)
-{
-	Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
-	SetDParam(0, wp->index);
-	UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
-}
-
-/* Redraw the sign of a waypoint */
-static void RedrawWaypointSign(const Waypoint* wp)
-{
-	MarkAllViewportsDirty(
-		wp->sign.left - 6,
-		wp->sign.top,
-		wp->sign.left + (wp->sign.width_1 << 2) + 12,
-		wp->sign.top + 48);
-}
-
-/* Update all signs */
-void UpdateAllWaypointSigns(void)
-{
-	Waypoint *wp;
-
-	FOR_ALL_WAYPOINTS(wp) {
-		UpdateWaypointSign(wp);
-	}
-}
-
-/* Internal handler to delete a waypoint */
-void DestroyWaypoint(Waypoint *wp)
-{
-	RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, wp->index);
-
-	if (wp->string != STR_NULL) DeleteName(wp->string);
-
-	RedrawWaypointSign(wp);
-}
-
-/* Set the default name for a waypoint */
-static void MakeDefaultWaypointName(Waypoint* wp)
-{
-	Waypoint *local_wp;
-	bool used_waypoint[MAX_WAYPOINTS_PER_TOWN];
-	int i;
-
-	wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
-
-	memset(used_waypoint, 0, sizeof(used_waypoint));
-
-	/* Find an unused waypoint number belonging to this town */
-	FOR_ALL_WAYPOINTS(local_wp) {
-		if (wp == local_wp) continue;
-
-		if (local_wp->xy && local_wp->string == STR_NULL && local_wp->town_index == wp->town_index)
-			used_waypoint[local_wp->town_cn] = true;
-	}
-
-	/* Find an empty spot */
-	for (i = 0; used_waypoint[i] && i < MAX_WAYPOINTS_PER_TOWN; i++) {}
-
-	wp->string = STR_NULL;
-	wp->town_cn = i;
-}
-
-/* Find a deleted waypoint close to a tile. */
-static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
-{
-	Waypoint *wp, *best = NULL;
-	uint thres = 8;
-
-	FOR_ALL_WAYPOINTS(wp) {
-		if (wp->deleted) {
-			uint cur_dist = DistanceManhattan(tile, wp->xy);
-
-			if (cur_dist < thres) {
-				thres = cur_dist;
-				best = wp;
-			}
-		}
-	}
-
-	return best;
-}
-
-/**
- * Update waypoint graphics id against saved GRFID/localidx.
- * This is to ensure the chosen graphics are correct if GRF files are changed.
- */
-void AfterLoadWaypoints(void)
-{
-	Waypoint *wp;
-
-	FOR_ALL_WAYPOINTS(wp) {
-		uint i;
-
-		if (wp->grfid == 0) continue;
-
-		for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
-			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
-			if (statspec != NULL && statspec->grfid == wp->grfid && statspec->localidx == wp->localidx) {
-				wp->stat_id = i;
-				break;
-			}
-		}
-	}
-}
-
-/** Convert existing rail to waypoint. Eg build a waypoint station over
- * piece of rail
- * @param tile tile where waypoint will be built
- * @param p1 graphics for waypoint type, 0 indicates standard graphics
- * @param p2 unused
- *
- * @todo When checking for the tile slope,
- * distingush between "Flat land required" and "land sloped in wrong direction"
- */
-int32 CmdBuildTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Waypoint *wp;
-	Slope tileh;
-	Axis axis;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	/* if custom gfx are used, make sure it is within bounds */
-	if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
-
-	if (!IsTileType(tile, MP_RAILWAY) ||
-			GetRailTileType(tile) != RAIL_TILE_NORMAL || (
-				(axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
-				(axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
-			)) {
-		return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
-	}
-
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	tileh = GetTileSlope(tile, NULL);
-	if (tileh != SLOPE_FLAT &&
-			(!_patches.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
-		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
-	}
-
-	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
-	wp = FindDeletedWaypointCloseTo(tile);
-	if (wp == NULL) {
-		wp = AllocateWaypoint();
-		if (wp == NULL) return CMD_ERROR;
-
-		wp->town_index = 0;
-		wp->string = STR_NULL;
-		wp->town_cn = 0;
-	}
-
-	if (flags & DC_EXEC) {
-		const StationSpec* statspec;
-
-		MakeRailWaypoint(tile, GetTileOwner(tile), axis, GetRailType(tile), wp->index);
-		MarkTileDirtyByTile(tile);
-
-		statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);
-
-		if (statspec != NULL) {
-			wp->stat_id = p1;
-			wp->grfid = statspec->grfid;
-			wp->localidx = statspec->localidx;
-		} else {
-			// Specified custom graphics do not exist, so use default.
-			wp->stat_id = 0;
-			wp->grfid = 0;
-			wp->localidx = 0;
-		}
-
-		wp->deleted = 0;
-		wp->xy = tile;
-		wp->build_date = _date;
-
-		if (wp->town_index == 0) MakeDefaultWaypointName(wp);
-
-		UpdateWaypointSign(wp);
-		RedrawWaypointSign(wp);
-		YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
-	}
-
-	return _price.build_train_depot;
-}
-
-/* Daily loop for waypoints */
-void WaypointsDailyLoop(void)
-{
-	Waypoint *wp;
-
-	/* Check if we need to delete a waypoint */
-	FOR_ALL_WAYPOINTS(wp) {
-		if (wp->deleted != 0 && --wp->deleted == 0) DeleteWaypoint(wp);
-	}
-}
-
-/* Remove a waypoint */
-int32 RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove)
-{
-	Waypoint *wp;
-
-	/* Make sure it's a waypoint */
-	if (!IsTileType(tile, MP_RAILWAY) ||
-			!IsRailWaypoint(tile) ||
-			(!CheckTileOwnership(tile) && _current_player != OWNER_WATER) ||
-			!EnsureNoVehicle(tile)) {
-		return CMD_ERROR;
-	}
-
-	if (flags & DC_EXEC) {
-		Track track = GetRailWaypointTrack(tile);
-		wp = GetWaypointByTile(tile);
-
-		wp->deleted = 30; // let it live for this many days before we do the actual deletion.
-		RedrawWaypointSign(wp);
-
-		if (justremove) {
-			MakeRailNormal(tile, GetTileOwner(tile), GetRailWaypointBits(tile), GetRailType(tile));
-			MarkTileDirtyByTile(tile);
-		} else {
-			DoClearSquare(tile);
-			SetSignalsOnBothDir(tile, track);
-		}
-		YapfNotifyTrackLayoutChange(tile, track);
-	}
-
-	return _price.remove_train_depot;
-}
-
-/** Delete a waypoint
- * @param tile tile where waypoint is to be deleted
- * @param p1 unused
- * @param p2 unused
- */
-int32 CmdRemoveTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-	return RemoveTrainWaypoint(tile, flags, true);
-}
-
-/** Rename a waypoint.
- * @param tile unused
- * @param p1 id of waypoint
- * @param p2 unused
- */
-int32 CmdRenameWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	Waypoint *wp;
-
-	if (!IsValidWaypointID(p1)) return CMD_ERROR;
-
-	if (_cmd_text[0] != '\0') {
-		StringID str = AllocateNameUnique(_cmd_text, 0);
-
-		if (str == 0) return CMD_ERROR;
-
-		if (flags & DC_EXEC) {
-			wp = GetWaypoint(p1);
-			if (wp->string != STR_NULL) DeleteName(wp->string);
-
-			wp->string = str;
-			wp->town_cn = 0;
-
-			UpdateWaypointSign(wp);
-			MarkWholeScreenDirty();
-		} else {
-			DeleteName(str);
-		}
-	} else {
-		if (flags & DC_EXEC) {
-			wp = GetWaypoint(p1);
-			if (wp->string != STR_NULL) DeleteName(wp->string);
-
-			MakeDefaultWaypointName(wp);
-			UpdateWaypointSign(wp);
-			MarkWholeScreenDirty();
-		}
-	}
-	return 0;
-}
-
-/* This hacks together some dummy one-shot Station structure for a waypoint. */
-Station *ComposeWaypointStation(TileIndex tile)
-{
-	Waypoint *wp = GetWaypointByTile(tile);
-	static Station stat;
-
-	stat.train_tile = stat.xy = wp->xy;
-	stat.town = GetTown(wp->town_index);
-	stat.string_id = wp->string == STR_NULL ? /* FIXME? */ 0 : wp->string;
-	stat.build_date = wp->build_date;
-
-	return &stat;
-}
-
-/* Draw a waypoint */
-void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
-{
-	x += 33;
-	y += 17;
-
-	if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) {
-		DrawDefaultWaypointSprite(x, y, railtype);
-	}
-}
-
-/* Fix savegames which stored waypoints in their old format */
-void FixOldWaypoints(void)
-{
-	Waypoint *wp;
-
-	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
-	FOR_ALL_WAYPOINTS(wp) {
-		wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
-		wp->town_cn = 0;
-		if (wp->string & 0xC000) {
-			wp->town_cn = wp->string & 0x3F;
-			wp->string = STR_NULL;
-		}
-	}
-}
-
-void InitializeWaypoints(void)
-{
-	CleanPool(&_Waypoint_pool);
-	AddBlockToPool(&_Waypoint_pool);
-}
-
-static const SaveLoad _waypoint_desc[] = {
-	SLE_CONDVAR(Waypoint, xy,         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
-	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
-	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
-	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT8,                  12, SL_MAX_VERSION),
-	    SLE_VAR(Waypoint, string,     SLE_UINT16),
-	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
-
-	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
-	SLE_CONDVAR(Waypoint, build_date, SLE_INT32,                  31, SL_MAX_VERSION),
-	SLE_CONDVAR(Waypoint, localidx,   SLE_UINT8,                   3, SL_MAX_VERSION),
-	SLE_CONDVAR(Waypoint, grfid,      SLE_UINT32,                 17, SL_MAX_VERSION),
-
-	SLE_END()
-};
-
-static void Save_WAYP(void)
-{
-	Waypoint *wp;
-
-	FOR_ALL_WAYPOINTS(wp) {
-		SlSetArrayIndex(wp->index);
-		SlObject(wp, _waypoint_desc);
-	}
-}
-
-static void Load_WAYP(void)
-{
-	int index;
-
-	while ((index = SlIterateArray()) != -1) {
-		Waypoint *wp;
-
-		if (!AddBlockIfNeeded(&_Waypoint_pool, index))
-			error("Waypoints: failed loading savegame: too many waypoints");
-
-		wp = GetWaypoint(index);
-		SlObject(wp, _waypoint_desc);
-	}
-}
-
-const ChunkHandler _waypoint_chunk_handlers[] = {
-	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
-};
new file mode 100644
--- /dev/null
+++ b/src/waypoint.cpp
@@ -0,0 +1,442 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+
+#include "command.h"
+#include "functions.h"
+#include "gfx.h"
+#include "map.h"
+#include "order.h"
+#include "rail_map.h"
+#include "bridge_map.h"
+#include "saveload.h"
+#include "station.h"
+#include "tile.h"
+#include "town.h"
+#include "waypoint.h"
+#include "variables.h"
+#include "table/strings.h"
+#include "vehicle.h"
+#include "yapf/yapf.h"
+#include "date.h"
+
+enum {
+	MAX_WAYPOINTS_PER_TOWN = 64,
+};
+
+/**
+ * Called if a new block is added to the waypoint-pool
+ */
+static void WaypointPoolNewBlock(uint start_item)
+{
+	Waypoint *wp;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (wp = GetWaypoint(start_item); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) wp->index = start_item++;
+}
+
+DEFINE_OLD_POOL(Waypoint, Waypoint, WaypointPoolNewBlock, NULL)
+
+/* Create a new waypoint */
+static Waypoint* AllocateWaypoint(void)
+{
+	Waypoint *wp;
+
+	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
+	 * TODO - This is just a temporary stage, this will be removed. */
+	for (wp = GetWaypoint(0); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) {
+		if (!IsValidWaypoint(wp)) {
+			uint index = wp->index;
+
+			memset(wp, 0, sizeof(*wp));
+			wp->index = index;
+
+			return wp;
+		}
+	}
+
+	/* Check if we can add a block to the pool */
+	if (AddBlockToPool(&_Waypoint_pool)) return AllocateWaypoint();
+
+	return NULL;
+}
+
+/* Update the sign for the waypoint */
+static void UpdateWaypointSign(Waypoint* wp)
+{
+	Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
+	SetDParam(0, wp->index);
+	UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
+}
+
+/* Redraw the sign of a waypoint */
+static void RedrawWaypointSign(const Waypoint* wp)
+{
+	MarkAllViewportsDirty(
+		wp->sign.left - 6,
+		wp->sign.top,
+		wp->sign.left + (wp->sign.width_1 << 2) + 12,
+		wp->sign.top + 48);
+}
+
+/* Update all signs */
+void UpdateAllWaypointSigns(void)
+{
+	Waypoint *wp;
+
+	FOR_ALL_WAYPOINTS(wp) {
+		UpdateWaypointSign(wp);
+	}
+}
+
+/* Internal handler to delete a waypoint */
+void DestroyWaypoint(Waypoint *wp)
+{
+	RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, wp->index);
+
+	if (wp->string != STR_NULL) DeleteName(wp->string);
+
+	RedrawWaypointSign(wp);
+}
+
+/* Set the default name for a waypoint */
+static void MakeDefaultWaypointName(Waypoint* wp)
+{
+	Waypoint *local_wp;
+	bool used_waypoint[MAX_WAYPOINTS_PER_TOWN];
+	int i;
+
+	wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
+
+	memset(used_waypoint, 0, sizeof(used_waypoint));
+
+	/* Find an unused waypoint number belonging to this town */
+	FOR_ALL_WAYPOINTS(local_wp) {
+		if (wp == local_wp) continue;
+
+		if (local_wp->xy && local_wp->string == STR_NULL && local_wp->town_index == wp->town_index)
+			used_waypoint[local_wp->town_cn] = true;
+	}
+
+	/* Find an empty spot */
+	for (i = 0; used_waypoint[i] && i < MAX_WAYPOINTS_PER_TOWN; i++) {}
+
+	wp->string = STR_NULL;
+	wp->town_cn = i;
+}
+
+/* Find a deleted waypoint close to a tile. */
+static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
+{
+	Waypoint *wp, *best = NULL;
+	uint thres = 8;
+
+	FOR_ALL_WAYPOINTS(wp) {
+		if (wp->deleted) {
+			uint cur_dist = DistanceManhattan(tile, wp->xy);
+
+			if (cur_dist < thres) {
+				thres = cur_dist;
+				best = wp;
+			}
+		}
+	}
+
+	return best;
+}
+
+/**
+ * Update waypoint graphics id against saved GRFID/localidx.
+ * This is to ensure the chosen graphics are correct if GRF files are changed.
+ */
+void AfterLoadWaypoints(void)
+{
+	Waypoint *wp;
+
+	FOR_ALL_WAYPOINTS(wp) {
+		uint i;
+
+		if (wp->grfid == 0) continue;
+
+		for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
+			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
+			if (statspec != NULL && statspec->grfid == wp->grfid && statspec->localidx == wp->localidx) {
+				wp->stat_id = i;
+				break;
+			}
+		}
+	}
+}
+
+/** Convert existing rail to waypoint. Eg build a waypoint station over
+ * piece of rail
+ * @param tile tile where waypoint will be built
+ * @param p1 graphics for waypoint type, 0 indicates standard graphics
+ * @param p2 unused
+ *
+ * @todo When checking for the tile slope,
+ * distingush between "Flat land required" and "land sloped in wrong direction"
+ */
+int32 CmdBuildTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Waypoint *wp;
+	Slope tileh;
+	Axis axis;
+
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	/* if custom gfx are used, make sure it is within bounds */
+	if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
+
+	if (!IsTileType(tile, MP_RAILWAY) ||
+			GetRailTileType(tile) != RAIL_TILE_NORMAL || (
+				(axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
+				(axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
+			)) {
+		return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
+	}
+
+	if (!CheckTileOwnership(tile)) return CMD_ERROR;
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
+
+	tileh = GetTileSlope(tile, NULL);
+	if (tileh != SLOPE_FLAT &&
+			(!_patches.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
+		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+	}
+
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
+	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
+	wp = FindDeletedWaypointCloseTo(tile);
+	if (wp == NULL) {
+		wp = AllocateWaypoint();
+		if (wp == NULL) return CMD_ERROR;
+
+		wp->town_index = 0;
+		wp->string = STR_NULL;
+		wp->town_cn = 0;
+	}
+
+	if (flags & DC_EXEC) {
+		const StationSpec* statspec;
+
+		MakeRailWaypoint(tile, GetTileOwner(tile), axis, GetRailType(tile), wp->index);
+		MarkTileDirtyByTile(tile);
+
+		statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);
+
+		if (statspec != NULL) {
+			wp->stat_id = p1;
+			wp->grfid = statspec->grfid;
+			wp->localidx = statspec->localidx;
+		} else {
+			// Specified custom graphics do not exist, so use default.
+			wp->stat_id = 0;
+			wp->grfid = 0;
+			wp->localidx = 0;
+		}
+
+		wp->deleted = 0;
+		wp->xy = tile;
+		wp->build_date = _date;
+
+		if (wp->town_index == 0) MakeDefaultWaypointName(wp);
+
+		UpdateWaypointSign(wp);
+		RedrawWaypointSign(wp);
+		YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
+	}
+
+	return _price.build_train_depot;
+}
+
+/* Daily loop for waypoints */
+void WaypointsDailyLoop(void)
+{
+	Waypoint *wp;
+
+	/* Check if we need to delete a waypoint */
+	FOR_ALL_WAYPOINTS(wp) {
+		if (wp->deleted != 0 && --wp->deleted == 0) DeleteWaypoint(wp);
+	}
+}
+
+/* Remove a waypoint */
+int32 RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove)
+{
+	Waypoint *wp;
+
+	/* Make sure it's a waypoint */
+	if (!IsTileType(tile, MP_RAILWAY) ||
+			!IsRailWaypoint(tile) ||
+			(!CheckTileOwnership(tile) && _current_player != OWNER_WATER) ||
+			!EnsureNoVehicle(tile)) {
+		return CMD_ERROR;
+	}
+
+	if (flags & DC_EXEC) {
+		Track track = GetRailWaypointTrack(tile);
+		wp = GetWaypointByTile(tile);
+
+		wp->deleted = 30; // let it live for this many days before we do the actual deletion.
+		RedrawWaypointSign(wp);
+
+		if (justremove) {
+			MakeRailNormal(tile, GetTileOwner(tile), GetRailWaypointBits(tile), GetRailType(tile));
+			MarkTileDirtyByTile(tile);
+		} else {
+			DoClearSquare(tile);
+			SetSignalsOnBothDir(tile, track);
+		}
+		YapfNotifyTrackLayoutChange(tile, track);
+	}
+
+	return _price.remove_train_depot;
+}
+
+/** Delete a waypoint
+ * @param tile tile where waypoint is to be deleted
+ * @param p1 unused
+ * @param p2 unused
+ */
+int32 CmdRemoveTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+	return RemoveTrainWaypoint(tile, flags, true);
+}
+
+/** Rename a waypoint.
+ * @param tile unused
+ * @param p1 id of waypoint
+ * @param p2 unused
+ */
+int32 CmdRenameWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	Waypoint *wp;
+
+	if (!IsValidWaypointID(p1)) return CMD_ERROR;
+
+	if (_cmd_text[0] != '\0') {
+		StringID str = AllocateNameUnique(_cmd_text, 0);
+
+		if (str == 0) return CMD_ERROR;
+
+		if (flags & DC_EXEC) {
+			wp = GetWaypoint(p1);
+			if (wp->string != STR_NULL) DeleteName(wp->string);
+
+			wp->string = str;
+			wp->town_cn = 0;
+
+			UpdateWaypointSign(wp);
+			MarkWholeScreenDirty();
+		} else {
+			DeleteName(str);
+		}
+	} else {
+		if (flags & DC_EXEC) {
+			wp = GetWaypoint(p1);
+			if (wp->string != STR_NULL) DeleteName(wp->string);
+
+			MakeDefaultWaypointName(wp);
+			UpdateWaypointSign(wp);
+			MarkWholeScreenDirty();
+		}
+	}
+	return 0;
+}
+
+/* This hacks together some dummy one-shot Station structure for a waypoint. */
+Station *ComposeWaypointStation(TileIndex tile)
+{
+	Waypoint *wp = GetWaypointByTile(tile);
+	static Station stat;
+
+	stat.train_tile = stat.xy = wp->xy;
+	stat.town = GetTown(wp->town_index);
+	stat.string_id = wp->string == STR_NULL ? /* FIXME? */ 0 : wp->string;
+	stat.build_date = wp->build_date;
+
+	return &stat;
+}
+
+/* Draw a waypoint */
+void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
+{
+	x += 33;
+	y += 17;
+
+	if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) {
+		DrawDefaultWaypointSprite(x, y, railtype);
+	}
+}
+
+/* Fix savegames which stored waypoints in their old format */
+void FixOldWaypoints(void)
+{
+	Waypoint *wp;
+
+	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
+	FOR_ALL_WAYPOINTS(wp) {
+		wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
+		wp->town_cn = 0;
+		if (wp->string & 0xC000) {
+			wp->town_cn = wp->string & 0x3F;
+			wp->string = STR_NULL;
+		}
+	}
+}
+
+void InitializeWaypoints(void)
+{
+	CleanPool(&_Waypoint_pool);
+	AddBlockToPool(&_Waypoint_pool);
+}
+
+static const SaveLoad _waypoint_desc[] = {
+	SLE_CONDVAR(Waypoint, xy,         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
+	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
+	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
+	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT8,                  12, SL_MAX_VERSION),
+	    SLE_VAR(Waypoint, string,     SLE_UINT16),
+	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
+
+	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
+	SLE_CONDVAR(Waypoint, build_date, SLE_INT32,                  31, SL_MAX_VERSION),
+	SLE_CONDVAR(Waypoint, localidx,   SLE_UINT8,                   3, SL_MAX_VERSION),
+	SLE_CONDVAR(Waypoint, grfid,      SLE_UINT32,                 17, SL_MAX_VERSION),
+
+	SLE_END()
+};
+
+static void Save_WAYP(void)
+{
+	Waypoint *wp;
+
+	FOR_ALL_WAYPOINTS(wp) {
+		SlSetArrayIndex(wp->index);
+		SlObject(wp, _waypoint_desc);
+	}
+}
+
+static void Load_WAYP(void)
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		Waypoint *wp;
+
+		if (!AddBlockIfNeeded(&_Waypoint_pool, index))
+			error("Waypoints: failed loading savegame: too many waypoints");
+
+		wp = GetWaypoint(index);
+		SlObject(wp, _waypoint_desc);
+	}
+}
+
+const ChunkHandler _waypoint_chunk_handlers[] = {
+	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
+};
deleted file mode 100644
--- a/src/widget.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "functions.h"
-#include "player.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "window.h"
-#include "gfx.h"
-#include "viewport.h"
-
-static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom)
-{
-	Point pt;
-	int height, count, pos, cap;
-
-	top += 10;
-	bottom -= 9;
-
-	height = (bottom - top);
-
-	pos = sb->pos;
-	count = sb->count;
-	cap = sb->cap;
-
-	if (count != 0) top += height * pos / count;
-
-	if (cap > count) cap = count;
-	if (count != 0) bottom -= (count - pos - cap) * height / count;
-
-	pt.x = top;
-	pt.y = bottom - 1;
-	return pt;
-}
-
-/*****************************************************
- * Special handling for the scrollbar widget type.
- * Handles the special scrolling buttons and other
- * scrolling.
- * Parameters:
- *   w   - Window.
- *   wi  - Pointer to the scrollbar widget.
- *   x   - The X coordinate of the mouse click.
- *   y   - The Y coordinate of the mouse click.
- */
-
-void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y)
-{
-	int mi, ma, pos;
-	Scrollbar *sb;
-
-	switch (wi->type) {
-		case WWT_SCROLLBAR: {
-			// vertical scroller
-			w->flags4 &= ~WF_HSCROLL;
-			w->flags4 &= ~WF_SCROLL2;
-			mi = wi->top;
-			ma = wi->bottom;
-			pos = y;
-			sb = &w->vscroll;
-			break;
-		}
-		case WWT_SCROLL2BAR: {
-			// 2nd vertical scroller
-			w->flags4 &= ~WF_HSCROLL;
-			w->flags4 |= WF_SCROLL2;
-			mi = wi->top;
-			ma = wi->bottom;
-			pos = y;
-			sb = &w->vscroll2;
-			break;
-		}
-		case  WWT_HSCROLLBAR: {
-			// horizontal scroller
-			w->flags4 &= ~WF_SCROLL2;
-			w->flags4 |= WF_HSCROLL;
-			mi = wi->left;
-			ma = wi->right;
-			pos = x;
-			sb = &w->hscroll;
-			break;
-		}
-		default: return; //this should never happen
-	}
-	if (pos <= mi+9) {
-		// Pressing the upper button?
-		w->flags4 |= WF_SCROLL_UP;
-		if (_scroller_click_timeout == 0) {
-			_scroller_click_timeout = 6;
-			if (sb->pos != 0) sb->pos--;
-		}
-		_left_button_clicked = false;
-	} else if (pos >= ma-10) {
-		// Pressing the lower button?
-		w->flags4 |= WF_SCROLL_DOWN;
-
-		if (_scroller_click_timeout == 0) {
-			_scroller_click_timeout = 6;
-			if ((byte)(sb->pos + sb->cap) < sb->count)
-				sb->pos++;
-		}
-		_left_button_clicked = false;
-	} else {
-		//
-		Point pt = HandleScrollbarHittest(sb, mi, ma);
-
-		if (pos < pt.x) {
-			sb->pos = max(sb->pos - sb->cap, 0);
-		} else if (pos > pt.y) {
-			sb->pos = min(
-				sb->pos + sb->cap,
-				max(sb->count - sb->cap, 0)
-			);
-		} else {
-			_scrollbar_start_pos = pt.x - mi - 9;
-			_scrollbar_size = ma - mi - 23;
-			w->flags4 |= WF_SCROLL_MIDDLE;
-			_scrolling_scrollbar = true;
-			_cursorpos_drag_start = _cursor.pos;
-		}
-	}
-
-	SetWindowDirty(w);
-}
-
-/** Returns the index for the widget located at the given position
- * relative to the window. It includes all widget-corner pixels as well.
- * @param *w Window to look inside
- * @param  x,y Window client coordinates
- * @return A widget index, or -1 if no widget was found.
- */
-int GetWidgetFromPos(const Window *w, int x, int y)
-{
-	uint index;
-	int found_index = -1;
-
-	// Go through the widgets and check if we find the widget that the coordinate is
-	// inside.
-	for (index = 0; index < w->widget_count; index++) {
-		const Widget *wi = &w->widget[index];
-		if (wi->type == WWT_EMPTY || wi->type == WWT_FRAME) continue;
-
-		if (x >= wi->left && x <= wi->right && y >= wi->top &&  y <= wi->bottom &&
-				!IsWindowWidgetHidden(w, index)) {
-			found_index = index;
-		}
-	}
-
-	return found_index;
-}
-
-
-void DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags)
-{
-	uint dark         = _colour_gradient[ctab][3];
-	uint medium_dark  = _colour_gradient[ctab][5];
-	uint medium_light = _colour_gradient[ctab][6];
-	uint light        = _colour_gradient[ctab][7];
-
-	if (flags & FR_TRANSPARENT) {
-		GfxFillRect(left, top, right, bottom, 0x322 | USE_COLORTABLE);
-	} else {
-		uint interior;
-
-		if (flags & FR_LOWERED) {
-			GfxFillRect(left,     top,     left,  bottom,     dark);
-			GfxFillRect(left + 1, top,     right, top,        dark);
-			GfxFillRect(right,    top + 1, right, bottom - 1, light);
-			GfxFillRect(left + 1, bottom,  right, bottom,     light);
-			interior = (flags & FR_DARKENED ? medium_dark : medium_light);
-		} else {
-			GfxFillRect(left,     top,    left,      bottom - 1, light);
-			GfxFillRect(left + 1, top,    right - 1, top,        light);
-			GfxFillRect(right,    top,    right,     bottom - 1, dark);
-			GfxFillRect(left,     bottom, right,     bottom,     dark);
-			interior = medium_dark;
-		}
-		if (!(flags & FR_BORDERONLY)) {
-			GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior);
-		}
-	}
-}
-
-
-void DrawWindowWidgets(const Window *w)
-{
-	const DrawPixelInfo* dpi = _cur_dpi;
-	Rect r;
-	uint i;
-
-	for (i = 0; i < w->widget_count; i++) {
-		const Widget *wi = &w->widget[i];
-		bool clicked = IsWindowWidgetLowered(w, i);
-
-		if (dpi->left > (r.right=/*w->left + */wi->right) ||
-				dpi->left + dpi->width <= (r.left=wi->left/* + w->left*/) ||
-				dpi->top > (r.bottom=/*w->top +*/ wi->bottom) ||
-				dpi->top + dpi->height <= (r.top = /*w->top +*/ wi->top) ||
-				IsWindowWidgetHidden(w, i)) {
-			continue;
-		}
-
-		switch (wi->type & WWT_MASK) {
-		case WWT_IMGBTN:
-		case WWT_IMGBTN_2: {
-			int img = wi->data;
-			assert(img != 0);
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-
-			/* show different image when clicked for WWT_IMGBTN_2 */
-			if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++;
-			DrawSprite(img, r.left + 1 + clicked, r.top + 1 + clicked);
-			goto draw_default;
-		}
-
-		case WWT_PANEL: {
-			assert(wi->data == 0);
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			goto draw_default;
-		}
-
-		case WWT_TEXTBTN:
-		case WWT_TEXTBTN_2: {
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			}
-		/* fall through */
-
-		case WWT_LABEL: {
-			StringID str = wi->data;
-
-			if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++;
-
-			DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, 0);
-			goto draw_default;
-		}
-
-		case WWT_INSET: {
-			StringID str = wi->data;
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED);
-
-			if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, 0, r.right - r.left - 10);
-			goto draw_default;
-		}
-
-		case WWT_MATRIX: {
-			int c, d, ctr;
-			int x, amt1, amt2;
-			int color;
-
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-
-			c = GB(wi->data, 0, 8);
-			amt1 = (wi->right - wi->left + 1) / c;
-
-			d = GB(wi->data, 8, 8);
-			amt2 = (wi->bottom - wi->top + 1) / d;
-
-			color = _colour_gradient[wi->color & 0xF][6];
-
-			x = r.left;
-			for (ctr = c; ctr > 1; ctr--) {
-				x += amt1;
-				GfxFillRect(x, r.top + 1, x, r.bottom - 1, color);
-			}
-
-			x = r.top;
-			for (ctr = d; ctr > 1; ctr--) {
-				x += amt2;
-				GfxFillRect(r.left + 1, x, r.right - 1, x, color);
-			}
-
-			color = _colour_gradient[wi->color&0xF][4];
-
-			x = r.left - 1;
-			for (ctr = c; ctr > 1; ctr--) {
-				x += amt1;
-				GfxFillRect(x, r.top + 1, x, r.bottom - 1, color);
-			}
-
-			x = r.top - 1;
-			for (ctr = d; ctr > 1; ctr--) {
-				x += amt2;
-				GfxFillRect(r.left+1, x, r.right-1, x, color);
-			}
-
-			goto draw_default;
-		}
-
-		// vertical scrollbar
-		case WWT_SCROLLBAR: {
-			Point pt;
-			int c1,c2;
-
-			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
-
-			// draw up/down buttons
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
-			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0);
-			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10);
-
-			clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
-			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10);
-
-			c1 = _colour_gradient[wi->color&0xF][3];
-			c2 = _colour_gradient[wi->color&0xF][7];
-
-			// draw "shaded" background
-			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2);
-			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT);
-
-			// draw shaded lines
-			GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1);
-			GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2);
-			GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1);
-			GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
-
-			pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom);
-			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : 0);
-			break;
-		}
-		case WWT_SCROLL2BAR: {
-			Point pt;
-			int c1,c2;
-
-			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
-
-			// draw up/down buttons
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
-			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color,  (clicked) ? FR_LOWERED : 0);
-			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10);
-
-			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
-			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color,  (clicked) ? FR_LOWERED : 0);
-			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10);
-
-			c1 = _colour_gradient[wi->color&0xF][3];
-			c2 = _colour_gradient[wi->color&0xF][7];
-
-			// draw "shaded" background
-			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2);
-			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT);
-
-			// draw shaded lines
-			GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1);
-			GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2);
-			GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1);
-			GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
-
-			pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom);
-			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : 0);
-			break;
-		}
-
-		// horizontal scrollbar
-		case WWT_HSCROLLBAR: {
-			Point pt;
-			int c1,c2;
-
-			assert(r.bottom - r.top == 11); // XXX - to ensure the same sizes are used everywhere!
-
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
-			DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			DrawSprite(SPR_ARROW_LEFT, r.left + 1 + clicked, r.top + 1 + clicked);
-
-			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
-			DrawFrameRect(r.right-9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			DrawSprite(SPR_ARROW_RIGHT, r.right - 8 + clicked, r.top + 1 + clicked);
-
-			c1 = _colour_gradient[wi->color&0xF][3];
-			c2 = _colour_gradient[wi->color&0xF][7];
-
-			// draw "shaded" background
-			GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c2);
-			GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c1 | PALETTE_MODIFIER_GREYOUT);
-
-			// draw shaded lines
-			GfxFillRect(r.left+10, r.top+2, r.right-10, r.top+2, c1);
-			GfxFillRect(r.left+10, r.top+3, r.right-10, r.top+3, c2);
-			GfxFillRect(r.left+10, r.top+7, r.right-10, r.top+7, c1);
-			GfxFillRect(r.left+10, r.top+8, r.right-10, r.top+8, c2);
-
-			// draw actual scrollbar
-			pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right);
-			DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : 0);
-
-			break;
-		}
-
-		case WWT_FRAME: {
-			int c1,c2;
-			int x2 = r.left; // by default the left side is the left side of the widget
-
-			if (wi->data != 0) x2 = DrawString(r.left + 6, r.top, wi->data, 0);
-
-			c1 = _colour_gradient[wi->color][3];
-			c2 = _colour_gradient[wi->color][7];
-
-			//Line from upper left corner to start of text
-			GfxFillRect(r.left, r.top+4, r.left+4,r.top+4, c1);
-			GfxFillRect(r.left+1, r.top+5, r.left+4,r.top+5, c2);
-
-			// Line from end of text to upper right corner
-			GfxFillRect(x2, r.top+4, r.right-1,r.top+4,c1);
-			GfxFillRect(x2, r.top+5, r.right-2,r.top+5,c2);
-
-			// Line from upper left corner to bottom left corner
-			GfxFillRect(r.left, r.top+5, r.left, r.bottom-1, c1);
-			GfxFillRect(r.left+1, r.top+6, r.left+1, r.bottom-2, c2);
-
-			//Line from upper right corner to bottom right corner
-			GfxFillRect(r.right-1, r.top+5, r.right-1, r.bottom-2, c1);
-			GfxFillRect(r.right, r.top+4, r.right, r.bottom-1, c2);
-
-			GfxFillRect(r.left+1, r.bottom-1, r.right-1, r.bottom-1, c1);
-			GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2);
-
-			goto draw_default;
-		}
-
-		case WWT_STICKYBOX: {
-			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
-
-			clicked = !!(w->flags4 & WF_STICKY);
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, r.left + 2 + clicked, r.top + 3 + clicked);
-			break;
-		}
-
-		case WWT_RESIZEBOX: {
-			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
-
-			clicked = !!(w->flags4 & WF_SIZING);
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
-			DrawSprite(SPR_WINDOW_RESIZE, r.left + 3 + clicked, r.top + 3 + clicked);
-			break;
-		}
-
-		case WWT_CLOSEBOX: {
-			assert(r.right - r.left == 10); // ensure the same sizes are used everywhere
-
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, 0);
-			DrawString(r.left + 2, r.top + 2, STR_00C5, 0);
-			break;
-		}
-
-		case WWT_CAPTION: {
-			assert(r.bottom - r.top == 13); // XXX - to ensure the same sizes are used everywhere!
-			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY);
-			DrawFrameRect(r.left+1, r.top+1, r.right-1, r.bottom-1, wi->color, (w->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
-
-			if (w->caption_color != 0xFF) {
-				GfxFillRect(r.left+2, r.top+2, r.right-2, r.bottom-2, _colour_gradient[_player_colors[w->caption_color]][4]);
-			}
-
-			DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top+2, wi->data, 0x84);
-draw_default:;
-			if (IsWindowWidgetDisabled(w, i)) {
-				GfxFillRect(r.left+1, r.top+1, r.right-1, r.bottom-1, _colour_gradient[wi->color&0xF][2] | PALETTE_MODIFIER_GREYOUT);
-			}
-		}
-		}
-	}
-
-
-	if (w->flags4 & WF_WHITE_BORDER_MASK) {
-		//DrawFrameRect(w->left, w->top, w->left + w->width-1, w->top+w->height-1, 0xF, 0x10);
-		DrawFrameRect(0, 0, w->width-1, w->height-1, 0xF, FR_BORDERONLY);
-	}
-
-}
-
-static const Widget _dropdown_menu_widgets[] = {
-{      WWT_PANEL,   RESIZE_NONE,     0,     0, 0,     0, 0, 0x0, STR_NULL},
-{  WWT_SCROLLBAR,   RESIZE_NONE,     0,     0, 0,     0, 0, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
-static int GetDropdownItem(const Window *w)
-{
-	byte item, counter;
-	int y;
-
-	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
-		return -1;
-
-	y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10;
-
-	if (y < 0)
-		return - 1;
-
-	item = y / 10;
-	if (item >= WP(w,dropdown_d).num_items || (HASBIT(WP(w,dropdown_d).disabled_state, item) && !HASBIT(WP(w,dropdown_d).hidden_state, item)) || WP(w,dropdown_d).items[item] == 0)
-		return - 1;
-
-	// Skip hidden items -- +1 for each hidden item before the clicked item.
-	for (counter = 0; item >= counter; ++counter)
-		if (HASBIT(WP(w,dropdown_d).hidden_state, counter)) item++;
-
-	return item;
-}
-
-static void DropdownMenuWndProc(Window *w, WindowEvent *e)
-{
-	int item;
-
-	switch (e->event) {
-		case WE_PAINT: {
-			int x,y,i,sel;
-			int width, height;
-
-			DrawWindowWidgets(w);
-
-			x = 1;
-			y = 2 - w->vscroll.pos * 10;
-
-			sel    = WP(w,dropdown_d).selected_index;
-			width  = w->widget[0].right - 3;
-			height = w->widget[0].bottom - 3;
-
-			for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++, sel--) {
-				if (HASBIT(WP(w,dropdown_d).hidden_state, i)) continue;
-
-				if (y >= 0 && y <= height) {
-					if (WP(w,dropdown_d).items[i] != STR_NULL) {
-						if (sel == 0) GfxFillRect(x + 1, y, x + width, y + 9, 0);
-						DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, x + width);
-
-						if (HASBIT(WP(w,dropdown_d).disabled_state, i)) {
-							GfxFillRect(x, y, x + width, y + 9,
-								PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5]
-							);
-						}
-					} else {
-						int c1 = _colour_gradient[_dropdown_menu_widgets[0].color][3];
-						int c2 = _colour_gradient[_dropdown_menu_widgets[0].color][7];
-
-						GfxFillRect(x + 1, y + 3, x + w->width - 5, y + 3, c1);
-						GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2);
-					}
-				}
-				y += 10;
-			}
-		} break;
-
-		case WE_CLICK: {
-			if (e->we.click.widget != 0) break;
-			item = GetDropdownItem(w);
-			if (item >= 0) {
-				WP(w,dropdown_d).click_delay = 4;
-				WP(w,dropdown_d).selected_index = item;
-				SetWindowDirty(w);
-			}
-		} break;
-
-		case WE_MOUSELOOP: {
-			Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num);
-			if (w2 == NULL) {
-				DeleteWindow(w);
-				return;
-			}
-
-			if (WP(w,dropdown_d).click_delay != 0 && --WP(w,dropdown_d).click_delay == 0) {
-				WindowEvent e;
-				e.event = WE_DROPDOWN_SELECT;
-				e.we.dropdown.button = WP(w,dropdown_d).parent_button;
-				e.we.dropdown.index  = WP(w,dropdown_d).selected_index;
-				w2->wndproc(w2, &e);
-				DeleteWindow(w);
-				return;
-			}
-
-			if (WP(w,dropdown_d).drag_mode) {
-				item = GetDropdownItem(w);
-
-				if (!_left_button_clicked) {
-					WP(w,dropdown_d).drag_mode = false;
-					if (item < 0) return;
-					WP(w,dropdown_d).click_delay = 2;
-				} else {
-					if (item < 0) return;
-				}
-
-				WP(w,dropdown_d).selected_index = item;
-				SetWindowDirty(w);
-			}
-		} break;
-
-		case WE_DESTROY: {
-			Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num);
-			if (w2 != NULL) {
-				RaiseWindowWidget(w2, WP(w,dropdown_d).parent_button);
-				InvalidateWidget(w2, WP(w,dropdown_d).parent_button);
-			}
-		} break;
-	}
-}
-
-void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask)
-{
-	int i;
-	const Widget *wi;
-	Window *w2;
-	const Window *w3;
-	bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button);
-	int top, height;
-	int screen_top, screen_bottom;
-	bool scroll = false;
-
-	DeleteWindowById(WC_DROPDOWN_MENU, 0);
-
-	if (is_dropdown_menu_shown) return;
-
-	LowerWindowWidget(w, button);
-
-	InvalidateWidget(w, button);
-
-	for (i = 0; strings[i] != INVALID_STRING_ID; i++) {}
-	if (i == 0) return;
-
-	wi = &w->widget[button];
-
-	if (hidden_mask != 0) {
-		uint j;
-
-		for (j = 0; strings[j] != INVALID_STRING_ID; j++) {
-			if (HASBIT(hidden_mask, j)) i--;
-		}
-	}
-
-	/* The preferred position is just below the dropdown calling widget */
-	top = w->top + wi->bottom + 2;
-	height = i * 10 + 4;
-
-	w3 = FindWindowById(WC_STATUS_BAR, 0);
-	screen_bottom = w3 == NULL ? _screen.height : w3->top;
-
-	/* Check if the dropdown will fully fit below the widget */
-	if (top + height >= screen_bottom) {
-		w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
-		screen_top = w3 == NULL ? 0 : w3->top + w3->height;
-
-		/* If not, check if it will fit above the widget */
-		if (w->top + wi->top - height - 1 > screen_top) {
-			top = w->top + wi->top - height - 1;
-		} else {
-			/* ... and lastly if it won't, enable the scroll bar and fit the
-			 * list in below the widget */
-			int rows = (screen_bottom - 4 - top) / 10;
-			height = rows * 10 + 4;
-			scroll = true;
-		}
-	}
-
-	w2 = AllocateWindow(
-		w->left + wi[-1].left + 1,
-		top,
-		wi->right - wi[-1].left + 1,
-		height,
-		DropdownMenuWndProc,
-		WC_DROPDOWN_MENU,
-		_dropdown_menu_widgets);
-
-	w2->widget[0].color = wi->color;
-	w2->widget[0].right = wi->right - wi[-1].left;
-	w2->widget[0].bottom = height - 1;
-
-	SetWindowWidgetHiddenState(w2, 1, !scroll);
-
-	if (scroll) {
-		/* We're scrolling, so enable the scroll bar and shrink the list by
-		 * the scrollbar's width */
-		w2->widget[1].color  = wi->color;
-		w2->widget[1].right  = w2->widget[0].right;
-		w2->widget[1].left   = w2->widget[1].right - 11;
-		w2->widget[1].bottom = height - 1;
-		w2->widget[0].right -= 12;
-
-		w2->vscroll.cap   = (height - 4) / 10;
-		w2->vscroll.count = i;
-	}
-
-	w2->desc_flags = WDF_DEF_WIDGET;
-	w2->flags4 &= ~WF_WHITE_BORDER_MASK;
-
-	WP(w2,dropdown_d).disabled_state = disabled_mask;
-	WP(w2,dropdown_d).hidden_state = hidden_mask;
-
-	WP(w2,dropdown_d).parent_wnd_class = w->window_class;
-	WP(w2,dropdown_d).parent_wnd_num = w->window_number;
-	WP(w2,dropdown_d).parent_button = button;
-
-	WP(w2,dropdown_d).num_items = i;
-	WP(w2,dropdown_d).selected_index = selected;
-	WP(w2,dropdown_d).items = strings;
-
-	WP(w2,dropdown_d).click_delay = 0;
-	WP(w2,dropdown_d).drag_mode = true;
-}
new file mode 100644
--- /dev/null
+++ b/src/widget.cpp
@@ -0,0 +1,700 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "functions.h"
+#include "player.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+#include "window.h"
+#include "gfx.h"
+#include "viewport.h"
+
+static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom)
+{
+	Point pt;
+	int height, count, pos, cap;
+
+	top += 10;
+	bottom -= 9;
+
+	height = (bottom - top);
+
+	pos = sb->pos;
+	count = sb->count;
+	cap = sb->cap;
+
+	if (count != 0) top += height * pos / count;
+
+	if (cap > count) cap = count;
+	if (count != 0) bottom -= (count - pos - cap) * height / count;
+
+	pt.x = top;
+	pt.y = bottom - 1;
+	return pt;
+}
+
+/*****************************************************
+ * Special handling for the scrollbar widget type.
+ * Handles the special scrolling buttons and other
+ * scrolling.
+ * Parameters:
+ *   w   - Window.
+ *   wi  - Pointer to the scrollbar widget.
+ *   x   - The X coordinate of the mouse click.
+ *   y   - The Y coordinate of the mouse click.
+ */
+
+void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y)
+{
+	int mi, ma, pos;
+	Scrollbar *sb;
+
+	switch (wi->type) {
+		case WWT_SCROLLBAR: {
+			// vertical scroller
+			w->flags4 &= ~WF_HSCROLL;
+			w->flags4 &= ~WF_SCROLL2;
+			mi = wi->top;
+			ma = wi->bottom;
+			pos = y;
+			sb = &w->vscroll;
+			break;
+		}
+		case WWT_SCROLL2BAR: {
+			// 2nd vertical scroller
+			w->flags4 &= ~WF_HSCROLL;
+			w->flags4 |= WF_SCROLL2;
+			mi = wi->top;
+			ma = wi->bottom;
+			pos = y;
+			sb = &w->vscroll2;
+			break;
+		}
+		case  WWT_HSCROLLBAR: {
+			// horizontal scroller
+			w->flags4 &= ~WF_SCROLL2;
+			w->flags4 |= WF_HSCROLL;
+			mi = wi->left;
+			ma = wi->right;
+			pos = x;
+			sb = &w->hscroll;
+			break;
+		}
+		default: return; //this should never happen
+	}
+	if (pos <= mi+9) {
+		// Pressing the upper button?
+		w->flags4 |= WF_SCROLL_UP;
+		if (_scroller_click_timeout == 0) {
+			_scroller_click_timeout = 6;
+			if (sb->pos != 0) sb->pos--;
+		}
+		_left_button_clicked = false;
+	} else if (pos >= ma-10) {
+		// Pressing the lower button?
+		w->flags4 |= WF_SCROLL_DOWN;
+
+		if (_scroller_click_timeout == 0) {
+			_scroller_click_timeout = 6;
+			if ((byte)(sb->pos + sb->cap) < sb->count)
+				sb->pos++;
+		}
+		_left_button_clicked = false;
+	} else {
+		//
+		Point pt = HandleScrollbarHittest(sb, mi, ma);
+
+		if (pos < pt.x) {
+			sb->pos = max(sb->pos - sb->cap, 0);
+		} else if (pos > pt.y) {
+			sb->pos = min(
+				sb->pos + sb->cap,
+				max(sb->count - sb->cap, 0)
+			);
+		} else {
+			_scrollbar_start_pos = pt.x - mi - 9;
+			_scrollbar_size = ma - mi - 23;
+			w->flags4 |= WF_SCROLL_MIDDLE;
+			_scrolling_scrollbar = true;
+			_cursorpos_drag_start = _cursor.pos;
+		}
+	}
+
+	SetWindowDirty(w);
+}
+
+/** Returns the index for the widget located at the given position
+ * relative to the window. It includes all widget-corner pixels as well.
+ * @param *w Window to look inside
+ * @param  x,y Window client coordinates
+ * @return A widget index, or -1 if no widget was found.
+ */
+int GetWidgetFromPos(const Window *w, int x, int y)
+{
+	uint index;
+	int found_index = -1;
+
+	// Go through the widgets and check if we find the widget that the coordinate is
+	// inside.
+	for (index = 0; index < w->widget_count; index++) {
+		const Widget *wi = &w->widget[index];
+		if (wi->type == WWT_EMPTY || wi->type == WWT_FRAME) continue;
+
+		if (x >= wi->left && x <= wi->right && y >= wi->top &&  y <= wi->bottom &&
+				!IsWindowWidgetHidden(w, index)) {
+			found_index = index;
+		}
+	}
+
+	return found_index;
+}
+
+
+void DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags)
+{
+	uint dark         = _colour_gradient[ctab][3];
+	uint medium_dark  = _colour_gradient[ctab][5];
+	uint medium_light = _colour_gradient[ctab][6];
+	uint light        = _colour_gradient[ctab][7];
+
+	if (flags & FR_TRANSPARENT) {
+		GfxFillRect(left, top, right, bottom, 0x322 | USE_COLORTABLE);
+	} else {
+		uint interior;
+
+		if (flags & FR_LOWERED) {
+			GfxFillRect(left,     top,     left,  bottom,     dark);
+			GfxFillRect(left + 1, top,     right, top,        dark);
+			GfxFillRect(right,    top + 1, right, bottom - 1, light);
+			GfxFillRect(left + 1, bottom,  right, bottom,     light);
+			interior = (flags & FR_DARKENED ? medium_dark : medium_light);
+		} else {
+			GfxFillRect(left,     top,    left,      bottom - 1, light);
+			GfxFillRect(left + 1, top,    right - 1, top,        light);
+			GfxFillRect(right,    top,    right,     bottom - 1, dark);
+			GfxFillRect(left,     bottom, right,     bottom,     dark);
+			interior = medium_dark;
+		}
+		if (!(flags & FR_BORDERONLY)) {
+			GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior);
+		}
+	}
+}
+
+
+void DrawWindowWidgets(const Window *w)
+{
+	const DrawPixelInfo* dpi = _cur_dpi;
+	Rect r;
+	uint i;
+
+	for (i = 0; i < w->widget_count; i++) {
+		const Widget *wi = &w->widget[i];
+		bool clicked = IsWindowWidgetLowered(w, i);
+
+		if (dpi->left > (r.right=/*w->left + */wi->right) ||
+				dpi->left + dpi->width <= (r.left=wi->left/* + w->left*/) ||
+				dpi->top > (r.bottom=/*w->top +*/ wi->bottom) ||
+				dpi->top + dpi->height <= (r.top = /*w->top +*/ wi->top) ||
+				IsWindowWidgetHidden(w, i)) {
+			continue;
+		}
+
+		switch (wi->type & WWT_MASK) {
+		case WWT_IMGBTN:
+		case WWT_IMGBTN_2: {
+			int img = wi->data;
+			assert(img != 0);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+
+			/* show different image when clicked for WWT_IMGBTN_2 */
+			if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++;
+			DrawSprite(img, r.left + 1 + clicked, r.top + 1 + clicked);
+			goto draw_default;
+		}
+
+		case WWT_PANEL: {
+			assert(wi->data == 0);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			goto draw_default;
+		}
+
+		case WWT_TEXTBTN:
+		case WWT_TEXTBTN_2: {
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			}
+		/* fall through */
+
+		case WWT_LABEL: {
+			StringID str = wi->data;
+
+			if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++;
+
+			DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, 0);
+			goto draw_default;
+		}
+
+		case WWT_INSET: {
+			StringID str = wi->data;
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED);
+
+			if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, 0, r.right - r.left - 10);
+			goto draw_default;
+		}
+
+		case WWT_MATRIX: {
+			int c, d, ctr;
+			int x, amt1, amt2;
+			int color;
+
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+
+			c = GB(wi->data, 0, 8);
+			amt1 = (wi->right - wi->left + 1) / c;
+
+			d = GB(wi->data, 8, 8);
+			amt2 = (wi->bottom - wi->top + 1) / d;
+
+			color = _colour_gradient[wi->color & 0xF][6];
+
+			x = r.left;
+			for (ctr = c; ctr > 1; ctr--) {
+				x += amt1;
+				GfxFillRect(x, r.top + 1, x, r.bottom - 1, color);
+			}
+
+			x = r.top;
+			for (ctr = d; ctr > 1; ctr--) {
+				x += amt2;
+				GfxFillRect(r.left + 1, x, r.right - 1, x, color);
+			}
+
+			color = _colour_gradient[wi->color&0xF][4];
+
+			x = r.left - 1;
+			for (ctr = c; ctr > 1; ctr--) {
+				x += amt1;
+				GfxFillRect(x, r.top + 1, x, r.bottom - 1, color);
+			}
+
+			x = r.top - 1;
+			for (ctr = d; ctr > 1; ctr--) {
+				x += amt2;
+				GfxFillRect(r.left+1, x, r.right-1, x, color);
+			}
+
+			goto draw_default;
+		}
+
+		// vertical scrollbar
+		case WWT_SCROLLBAR: {
+			Point pt;
+			int c1,c2;
+
+			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
+
+			// draw up/down buttons
+			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
+			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0);
+			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10);
+
+			clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
+			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10);
+
+			c1 = _colour_gradient[wi->color&0xF][3];
+			c2 = _colour_gradient[wi->color&0xF][7];
+
+			// draw "shaded" background
+			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2);
+			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT);
+
+			// draw shaded lines
+			GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1);
+			GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2);
+			GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1);
+			GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
+
+			pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom);
+			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : 0);
+			break;
+		}
+		case WWT_SCROLL2BAR: {
+			Point pt;
+			int c1,c2;
+
+			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
+
+			// draw up/down buttons
+			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
+			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color,  (clicked) ? FR_LOWERED : 0);
+			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10);
+
+			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
+			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color,  (clicked) ? FR_LOWERED : 0);
+			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10);
+
+			c1 = _colour_gradient[wi->color&0xF][3];
+			c2 = _colour_gradient[wi->color&0xF][7];
+
+			// draw "shaded" background
+			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2);
+			GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT);
+
+			// draw shaded lines
+			GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1);
+			GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2);
+			GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1);
+			GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
+
+			pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom);
+			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : 0);
+			break;
+		}
+
+		// horizontal scrollbar
+		case WWT_HSCROLLBAR: {
+			Point pt;
+			int c1,c2;
+
+			assert(r.bottom - r.top == 11); // XXX - to ensure the same sizes are used everywhere!
+
+			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
+			DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			DrawSprite(SPR_ARROW_LEFT, r.left + 1 + clicked, r.top + 1 + clicked);
+
+			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
+			DrawFrameRect(r.right-9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			DrawSprite(SPR_ARROW_RIGHT, r.right - 8 + clicked, r.top + 1 + clicked);
+
+			c1 = _colour_gradient[wi->color&0xF][3];
+			c2 = _colour_gradient[wi->color&0xF][7];
+
+			// draw "shaded" background
+			GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c2);
+			GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c1 | PALETTE_MODIFIER_GREYOUT);
+
+			// draw shaded lines
+			GfxFillRect(r.left+10, r.top+2, r.right-10, r.top+2, c1);
+			GfxFillRect(r.left+10, r.top+3, r.right-10, r.top+3, c2);
+			GfxFillRect(r.left+10, r.top+7, r.right-10, r.top+7, c1);
+			GfxFillRect(r.left+10, r.top+8, r.right-10, r.top+8, c2);
+
+			// draw actual scrollbar
+			pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right);
+			DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : 0);
+
+			break;
+		}
+
+		case WWT_FRAME: {
+			int c1,c2;
+			int x2 = r.left; // by default the left side is the left side of the widget
+
+			if (wi->data != 0) x2 = DrawString(r.left + 6, r.top, wi->data, 0);
+
+			c1 = _colour_gradient[wi->color][3];
+			c2 = _colour_gradient[wi->color][7];
+
+			//Line from upper left corner to start of text
+			GfxFillRect(r.left, r.top+4, r.left+4,r.top+4, c1);
+			GfxFillRect(r.left+1, r.top+5, r.left+4,r.top+5, c2);
+
+			// Line from end of text to upper right corner
+			GfxFillRect(x2, r.top+4, r.right-1,r.top+4,c1);
+			GfxFillRect(x2, r.top+5, r.right-2,r.top+5,c2);
+
+			// Line from upper left corner to bottom left corner
+			GfxFillRect(r.left, r.top+5, r.left, r.bottom-1, c1);
+			GfxFillRect(r.left+1, r.top+6, r.left+1, r.bottom-2, c2);
+
+			//Line from upper right corner to bottom right corner
+			GfxFillRect(r.right-1, r.top+5, r.right-1, r.bottom-2, c1);
+			GfxFillRect(r.right, r.top+4, r.right, r.bottom-1, c2);
+
+			GfxFillRect(r.left+1, r.bottom-1, r.right-1, r.bottom-1, c1);
+			GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2);
+
+			goto draw_default;
+		}
+
+		case WWT_STICKYBOX: {
+			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
+
+			clicked = !!(w->flags4 & WF_STICKY);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, r.left + 2 + clicked, r.top + 3 + clicked);
+			break;
+		}
+
+		case WWT_RESIZEBOX: {
+			assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere!
+
+			clicked = !!(w->flags4 & WF_SIZING);
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0);
+			DrawSprite(SPR_WINDOW_RESIZE, r.left + 3 + clicked, r.top + 3 + clicked);
+			break;
+		}
+
+		case WWT_CLOSEBOX: {
+			assert(r.right - r.left == 10); // ensure the same sizes are used everywhere
+
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, 0);
+			DrawString(r.left + 2, r.top + 2, STR_00C5, 0);
+			break;
+		}
+
+		case WWT_CAPTION: {
+			assert(r.bottom - r.top == 13); // XXX - to ensure the same sizes are used everywhere!
+			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY);
+			DrawFrameRect(r.left+1, r.top+1, r.right-1, r.bottom-1, wi->color, (w->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
+
+			if (w->caption_color != 0xFF) {
+				GfxFillRect(r.left+2, r.top+2, r.right-2, r.bottom-2, _colour_gradient[_player_colors[w->caption_color]][4]);
+			}
+
+			DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top+2, wi->data, 0x84);
+draw_default:;
+			if (IsWindowWidgetDisabled(w, i)) {
+				GfxFillRect(r.left+1, r.top+1, r.right-1, r.bottom-1, _colour_gradient[wi->color&0xF][2] | PALETTE_MODIFIER_GREYOUT);
+			}
+		}
+		}
+	}
+
+
+	if (w->flags4 & WF_WHITE_BORDER_MASK) {
+		//DrawFrameRect(w->left, w->top, w->left + w->width-1, w->top+w->height-1, 0xF, 0x10);
+		DrawFrameRect(0, 0, w->width-1, w->height-1, 0xF, FR_BORDERONLY);
+	}
+
+}
+
+static const Widget _dropdown_menu_widgets[] = {
+{      WWT_PANEL,   RESIZE_NONE,     0,     0, 0,     0, 0, 0x0, STR_NULL},
+{  WWT_SCROLLBAR,   RESIZE_NONE,     0,     0, 0,     0, 0, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
+
+static int GetDropdownItem(const Window *w)
+{
+	byte item, counter;
+	int y;
+
+	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
+		return -1;
+
+	y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10;
+
+	if (y < 0)
+		return - 1;
+
+	item = y / 10;
+	if (item >= WP(w,dropdown_d).num_items || (HASBIT(WP(w,dropdown_d).disabled_state, item) && !HASBIT(WP(w,dropdown_d).hidden_state, item)) || WP(w,dropdown_d).items[item] == 0)
+		return - 1;
+
+	// Skip hidden items -- +1 for each hidden item before the clicked item.
+	for (counter = 0; item >= counter; ++counter)
+		if (HASBIT(WP(w,dropdown_d).hidden_state, counter)) item++;
+
+	return item;
+}
+
+static void DropdownMenuWndProc(Window *w, WindowEvent *e)
+{
+	int item;
+
+	switch (e->event) {
+		case WE_PAINT: {
+			int x,y,i,sel;
+			int width, height;
+
+			DrawWindowWidgets(w);
+
+			x = 1;
+			y = 2 - w->vscroll.pos * 10;
+
+			sel    = WP(w,dropdown_d).selected_index;
+			width  = w->widget[0].right - 3;
+			height = w->widget[0].bottom - 3;
+
+			for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++, sel--) {
+				if (HASBIT(WP(w,dropdown_d).hidden_state, i)) continue;
+
+				if (y >= 0 && y <= height) {
+					if (WP(w,dropdown_d).items[i] != STR_NULL) {
+						if (sel == 0) GfxFillRect(x + 1, y, x + width, y + 9, 0);
+						DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, x + width);
+
+						if (HASBIT(WP(w,dropdown_d).disabled_state, i)) {
+							GfxFillRect(x, y, x + width, y + 9,
+								PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5]
+							);
+						}
+					} else {
+						int c1 = _colour_gradient[_dropdown_menu_widgets[0].color][3];
+						int c2 = _colour_gradient[_dropdown_menu_widgets[0].color][7];
+
+						GfxFillRect(x + 1, y + 3, x + w->width - 5, y + 3, c1);
+						GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2);
+					}
+				}
+				y += 10;
+			}
+		} break;
+
+		case WE_CLICK: {
+			if (e->we.click.widget != 0) break;
+			item = GetDropdownItem(w);
+			if (item >= 0) {
+				WP(w,dropdown_d).click_delay = 4;
+				WP(w,dropdown_d).selected_index = item;
+				SetWindowDirty(w);
+			}
+		} break;
+
+		case WE_MOUSELOOP: {
+			Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num);
+			if (w2 == NULL) {
+				DeleteWindow(w);
+				return;
+			}
+
+			if (WP(w,dropdown_d).click_delay != 0 && --WP(w,dropdown_d).click_delay == 0) {
+				WindowEvent e;
+				e.event = WE_DROPDOWN_SELECT;
+				e.we.dropdown.button = WP(w,dropdown_d).parent_button;
+				e.we.dropdown.index  = WP(w,dropdown_d).selected_index;
+				w2->wndproc(w2, &e);
+				DeleteWindow(w);
+				return;
+			}
+
+			if (WP(w,dropdown_d).drag_mode) {
+				item = GetDropdownItem(w);
+
+				if (!_left_button_clicked) {
+					WP(w,dropdown_d).drag_mode = false;
+					if (item < 0) return;
+					WP(w,dropdown_d).click_delay = 2;
+				} else {
+					if (item < 0) return;
+				}
+
+				WP(w,dropdown_d).selected_index = item;
+				SetWindowDirty(w);
+			}
+		} break;
+
+		case WE_DESTROY: {
+			Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num);
+			if (w2 != NULL) {
+				RaiseWindowWidget(w2, WP(w,dropdown_d).parent_button);
+				InvalidateWidget(w2, WP(w,dropdown_d).parent_button);
+			}
+		} break;
+	}
+}
+
+void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask)
+{
+	int i;
+	const Widget *wi;
+	Window *w2;
+	const Window *w3;
+	bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button);
+	int top, height;
+	int screen_top, screen_bottom;
+	bool scroll = false;
+
+	DeleteWindowById(WC_DROPDOWN_MENU, 0);
+
+	if (is_dropdown_menu_shown) return;
+
+	LowerWindowWidget(w, button);
+
+	InvalidateWidget(w, button);
+
+	for (i = 0; strings[i] != INVALID_STRING_ID; i++) {}
+	if (i == 0) return;
+
+	wi = &w->widget[button];
+
+	if (hidden_mask != 0) {
+		uint j;
+
+		for (j = 0; strings[j] != INVALID_STRING_ID; j++) {
+			if (HASBIT(hidden_mask, j)) i--;
+		}
+	}
+
+	/* The preferred position is just below the dropdown calling widget */
+	top = w->top + wi->bottom + 2;
+	height = i * 10 + 4;
+
+	w3 = FindWindowById(WC_STATUS_BAR, 0);
+	screen_bottom = w3 == NULL ? _screen.height : w3->top;
+
+	/* Check if the dropdown will fully fit below the widget */
+	if (top + height >= screen_bottom) {
+		w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		screen_top = w3 == NULL ? 0 : w3->top + w3->height;
+
+		/* If not, check if it will fit above the widget */
+		if (w->top + wi->top - height - 1 > screen_top) {
+			top = w->top + wi->top - height - 1;
+		} else {
+			/* ... and lastly if it won't, enable the scroll bar and fit the
+			 * list in below the widget */
+			int rows = (screen_bottom - 4 - top) / 10;
+			height = rows * 10 + 4;
+			scroll = true;
+		}
+	}
+
+	w2 = AllocateWindow(
+		w->left + wi[-1].left + 1,
+		top,
+		wi->right - wi[-1].left + 1,
+		height,
+		DropdownMenuWndProc,
+		WC_DROPDOWN_MENU,
+		_dropdown_menu_widgets);
+
+	w2->widget[0].color = wi->color;
+	w2->widget[0].right = wi->right - wi[-1].left;
+	w2->widget[0].bottom = height - 1;
+
+	SetWindowWidgetHiddenState(w2, 1, !scroll);
+
+	if (scroll) {
+		/* We're scrolling, so enable the scroll bar and shrink the list by
+		 * the scrollbar's width */
+		w2->widget[1].color  = wi->color;
+		w2->widget[1].right  = w2->widget[0].right;
+		w2->widget[1].left   = w2->widget[1].right - 11;
+		w2->widget[1].bottom = height - 1;
+		w2->widget[0].right -= 12;
+
+		w2->vscroll.cap   = (height - 4) / 10;
+		w2->vscroll.count = i;
+	}
+
+	w2->desc_flags = WDF_DEF_WIDGET;
+	w2->flags4 &= ~WF_WHITE_BORDER_MASK;
+
+	WP(w2,dropdown_d).disabled_state = disabled_mask;
+	WP(w2,dropdown_d).hidden_state = hidden_mask;
+
+	WP(w2,dropdown_d).parent_wnd_class = w->window_class;
+	WP(w2,dropdown_d).parent_wnd_num = w->window_number;
+	WP(w2,dropdown_d).parent_button = button;
+
+	WP(w2,dropdown_d).num_items = i;
+	WP(w2,dropdown_d).selected_index = selected;
+	WP(w2,dropdown_d).items = strings;
+
+	WP(w2,dropdown_d).click_delay = 0;
+	WP(w2,dropdown_d).drag_mode = true;
+}
deleted file mode 100644
--- a/src/win32.c
+++ /dev/null
@@ -1,1140 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "macros.h"
-#include "saveload.h"
-#include "string.h"
-#include "gfx.h"
-#include "window.h"
-#include <windows.h>
-#include <winnt.h>
-#include <wininet.h>
-#include <io.h>
-#include <fcntl.h>
-#include <shlobj.h> // SHGetFolderPath
-#include "variables.h"
-#include "win32.h"
-#include "fios.h" // opendir/readdir/closedir
-#include <ctype.h>
-#include <tchar.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-static bool _has_console;
-
-#if defined(__MINGW32__)
-	#include <stdint.h>
-#endif
-
-static bool cursor_visible = true;
-
-bool MyShowCursor(bool show)
-{
-	if (cursor_visible == show) return show;
-
-	cursor_visible = show;
-	ShowCursor(show);
-
-	return !show;
-}
-
-/** Helper function needed by dynamically loading libraries
- * XXX: Hurray for MS only having an ANSI GetProcAddress function
- * on normal windows and no Wide version except for in Windows Mobile/CE */
-bool LoadLibraryList(Function proc[], const char *dll)
-{
-	while (*dll != '\0') {
-		HMODULE lib;
-		lib = LoadLibrary(MB_TO_WIDE(dll));
-
-		if (lib == NULL) return false;
-		for (;;) {
-			FARPROC p;
-
-			while (*dll++ != '\0');
-			if (*dll == '\0') break;
-#if defined(WINCE)
-			p = GetProcAddress(lib, MB_TO_WIDE(dll);
-#else
-			p = GetProcAddress(lib, dll);
-#endif
-			if (p == NULL) return false;
-			*proc++ = (Function)p;
-		}
-		dll++;
-	}
-	return true;
-}
-
-#ifdef _MSC_VER
-static const char *_exception_string = NULL;
-#endif
-
-void ShowOSErrorBox(const char *buf)
-{
-	MyShowCursor(true);
-	MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP);
-
-// if exception tracker is enabled, we crash here to let the exception handler handle it.
-#if defined(WIN32_EXCEPTION_TRACKER) && !defined(_DEBUG)
-	if (*buf == '!') {
-		_exception_string = buf;
-		*(byte*)0 = 0;
-	}
-#endif
-}
-
-#ifdef _MSC_VER
-
-static void *_safe_esp;
-static char *_crash_msg;
-static bool _expanded;
-static bool _did_emerg_save;
-static int _ident;
-
-typedef struct DebugFileInfo {
-	uint32 size;
-	uint32 crc32;
-	SYSTEMTIME file_time;
-} DebugFileInfo;
-
-static uint32 *_crc_table;
-
-static void MakeCRCTable(uint32 *table) {
-	uint32 crc, poly = 0xEDB88320L;
-	int i;
-	int j;
-
-	_crc_table = table;
-
-	for (i = 0; i != 256; i++) {
-		crc = i;
-		for (j = 8; j != 0; j--) {
-			crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1);
-		}
-		table[i] = crc;
-	}
-}
-
-static uint32 CalcCRC(byte *data, uint size, uint32 crc) {
-	for (; size > 0; size--) {
-		crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF];
-	}
-	return crc;
-}
-
-static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename)
-{
-	HANDLE file;
-	memset(dfi, 0, sizeof(dfi));
-
-	file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
-	if (file != INVALID_HANDLE_VALUE) {
-		byte buffer[1024];
-		DWORD numread;
-		uint32 filesize = 0;
-		FILETIME write_time;
-		uint32 crc = (uint32)-1;
-
-		for (;;) {
-			if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread == 0)
-				break;
-			filesize += numread;
-			crc = CalcCRC(buffer, numread, crc);
-		}
-		dfi->size = filesize;
-		dfi->crc32 = crc ^ (uint32)-1;
-
-		if (GetFileTime(file, NULL, NULL, &write_time)) {
-			FileTimeToSystemTime(&write_time, &dfi->file_time);
-		}
-		CloseHandle(file);
-	}
-}
-
-
-static char *PrintModuleInfo(char *output, HMODULE mod)
-{
-	TCHAR buffer[MAX_PATH];
-	DebugFileInfo dfi;
-
-	GetModuleFileName(mod, buffer, MAX_PATH);
-	GetFileInfo(&dfi, buffer);
-	output += sprintf(output, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n",
-		WIDE_TO_MB(buffer),
-		mod,
-		dfi.size,
-		dfi.crc32,
-		dfi.file_time.wYear,
-		dfi.file_time.wMonth,
-		dfi.file_time.wDay,
-		dfi.file_time.wHour,
-		dfi.file_time.wMinute,
-		dfi.file_time.wSecond
-	);
-	return output;
-}
-
-static char *PrintModuleList(char *output)
-{
-	BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD);
-
-	if (LoadLibraryList((Function*)&EnumProcessModules, "psapi.dll\0EnumProcessModules\0\0")) {
-		HMODULE modules[100];
-		DWORD needed;
-		BOOL res;
-		int count, i;
-
-		HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
-		if (proc != NULL) {
-			res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
-			CloseHandle(proc);
-			if (res) {
-				count = min(needed / sizeof(HMODULE), lengthof(modules));
-
-				for (i = 0; i != count; i++) output = PrintModuleInfo(output, modules[i]);
-				return output;
-			}
-		}
-	}
-	output = PrintModuleInfo(output, NULL);
-	return output;
-}
-
-static const TCHAR _crash_desc[] =
-	_T("A serious fault condition occured in the game. The game will shut down.\n")
-	_T("Please send the crash information and the crash.dmp file (if any) to the developers.\n")
-	_T("This will greatly help debugging. The correct place to do this is http://bugs.openttd.org. ")
-	_T("The information contained in the report is displayed below.\n")
-	_T("Press \"Emergency save\" to attempt saving the game.");
-
-static const TCHAR _save_succeeded[] =
-	_T("Emergency save succeeded.\n")
-	_T("Be aware that critical parts of the internal game state may have become ")
-	_T("corrupted. The saved game is not guaranteed to work.");
-
-static bool EmergencySave(void)
-{
-	SaveOrLoad("crash.sav", SL_SAVE);
-	return true;
-}
-
-/* Disable the crash-save submit code as it's not used */
-#if 0
-
-typedef struct {
-	HINTERNET (WINAPI *InternetOpen)(LPCTSTR,DWORD, LPCTSTR, LPCTSTR, DWORD);
-	HINTERNET (WINAPI *InternetConnect)(HINTERNET, LPCTSTR, INTERNET_PORT, LPCTSTR, LPCTSTR, DWORD, DWORD, DWORD);
-	HINTERNET (WINAPI *HttpOpenRequest)(HINTERNET, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR *, DWORD, DWORD);
-	BOOL (WINAPI *HttpSendRequest)(HINTERNET, LPCTSTR, DWORD, LPVOID, DWORD);
-	BOOL (WINAPI *InternetCloseHandle)(HINTERNET);
-	BOOL (WINAPI *HttpQueryInfo)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
-} WinInetProcs;
-
-#define M(x) x "\0"
-#if defined(UNICODE)
-# define W(x) x "W"
-#else
-# define W(x) x "A"
-#endif
-static const char wininet_files[] =
-	M("wininet.dll")
-	M(W("InternetOpen"))
-	M(W("InternetConnect"))
-	M(W("HttpOpenRequest"))
-	M(W("HttpSendRequest"))
-	M("InternetCloseHandle")
-	M(W("HttpQueryInfo"))
-	M("");
-#undef W
-#undef M
-
-static WinInetProcs _wininet;
-
-static const TCHAR *SubmitCrashReport(HWND wnd, void *msg, size_t msglen, const TCHAR *arg)
-{
-	HINTERNET inet, conn, http;
-	const TCHAR *err = NULL;
-	DWORD code, len;
-	static TCHAR buf[100];
-	TCHAR buff[100];
-
-	if (_wininet.InternetOpen == NULL && !LoadLibraryList((Function*)&_wininet, wininet_files)) return _T("can't load wininet.dll");
-
-	inet = _wininet.InternetOpen(_T("OTTD"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
-	if (inet == NULL) { err = _T("internetopen failed"); goto error1; }
-
-	conn = _wininet.InternetConnect(inet, _T("www.openttd.org"), INTERNET_DEFAULT_HTTP_PORT, _T(""), _T(""), INTERNET_SERVICE_HTTP, 0, 0);
-	if (conn == NULL) { err = _T("internetconnect failed"); goto error2; }
-
-	_sntprintf(buff, lengthof(buff), _T("/crash.php?file=%s&ident=%d"), arg, _ident);
-
-	http = _wininet.HttpOpenRequest(conn, _T("POST"), buff, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE , 0);
-	if (http == NULL) { err = _T("httpopenrequest failed"); goto error3; }
-
-	if (!_wininet.HttpSendRequest(http, _T("Content-type: application/binary"), -1, msg, (DWORD)msglen)) { err = _T("httpsendrequest failed"); goto error4; }
-
-	len = sizeof(code);
-	if (!_wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &code, &len, 0)) { err = _T("httpqueryinfo failed"); goto error4; }
-
-	if (code != 200) {
-		int l = _sntprintf(buf, lengthof(buf), _T("Server said: %d "), code);
-		len = sizeof(buf) - l;
-		_wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_TEXT, buf + l, &len, 0);
-		err = buf;
-	}
-
-error4:
-	_wininet.InternetCloseHandle(http);
-error3:
-	_wininet.InternetCloseHandle(conn);
-error2:
-	_wininet.InternetCloseHandle(inet);
-error1:
-	return err;
-}
-
-static void SubmitFile(HWND wnd, const TCHAR *file)
-{
-	HANDLE h;
-	unsigned long size;
-	unsigned long read;
-	void *mem;
-
-	h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
-	if (h == NULL) return;
-
-	size = GetFileSize(h, NULL);
-	if (size > 500000) goto error1;
-
-	mem = malloc(size);
-	if (mem == NULL) goto error1;
-
-	if (!ReadFile(h, mem, size, &read, NULL) || read != size) goto error2;
-
-	SubmitCrashReport(wnd, mem, size, file);
-
-error2:
-	free(mem);
-error1:
-	CloseHandle(h);
-}
-
-#endif /* Disabled crash-submit procedures */
-
-static const TCHAR * const _expand_texts[] = {_T("S&how report >>"), _T("&Hide report <<") };
-
-static void SetWndSize(HWND wnd, int mode)
-{
-	RECT r,r2;
-	int offs;
-
-	GetWindowRect(wnd, &r);
-
-	SetDlgItemText(wnd, 15, _expand_texts[mode == 1]);
-
-	if (mode >= 0) {
-		GetWindowRect(GetDlgItem(wnd, 11), &r2);
-		offs = r2.bottom - r2.top + 10;
-		if (!mode) offs = -offs;
-		SetWindowPos(wnd, HWND_TOPMOST, 0, 0,
-			r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER);
-	} else {
-		SetWindowPos(wnd, HWND_TOPMOST,
-			(GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2,
-			(GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2,
-			0, 0, SWP_NOSIZE);
-	}
-}
-
-static bool DoEmergencySave(HWND wnd)
-{
-	bool b = false;
-
-	EnableWindow(GetDlgItem(wnd, 13), FALSE);
-	_did_emerg_save = true;
-	__try {
-		b = EmergencySave();
-	} __except (1) {}
-	return b;
-}
-
-static INT_PTR CALLBACK CrashDialogFunc(HWND wnd,UINT msg,WPARAM wParam,LPARAM lParam)
-{
-	switch (msg) {
-		case WM_INITDIALOG: {
-#if defined(UNICODE)
-			/* We need to put the crash-log in a seperate buffer because the default
-			 * buffer in MB_TO_WIDE is not large enough (256 chars) */
-			wchar_t crash_msgW[8096];
-#endif
-			SetDlgItemText(wnd, 10, _crash_desc);
-			SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(_crash_msg, crash_msgW, lengthof(crash_msgW)));
-			SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
-			SetWndSize(wnd, -1);
-		} return TRUE;
-		case WM_COMMAND:
-			switch (wParam) {
-				case 12: /* Close */
-					ExitProcess(0);
-				case 13: /* Emergency save */
-					if (DoEmergencySave(wnd)) {
-						MessageBox(wnd, _save_succeeded, _T("Save successful"), MB_ICONINFORMATION);
-					} else {
-						MessageBox(wnd, _T("Save failed"), _T("Save failed"), MB_ICONINFORMATION);
-					}
-					break;
-/* Disable the crash-save submit code as it's not used */
-#if 0
-				case 14: { /* Submit crash report */
-					const TCHAR *s;
-
-					SetCursor(LoadCursor(NULL, IDC_WAIT));
-
-					s = SubmitCrashReport(wnd, _crash_msg, strlen(_crash_msg), _T(""));
-					if (s != NULL) {
-						MessageBox(wnd, s, _T("Error"), MB_ICONSTOP);
-						break;
-					}
-
-					// try to submit emergency savegame
-					if (_did_emerg_save || DoEmergencySave(wnd)) SubmitFile(wnd, _T("crash.sav"));
-
-					// try to submit the autosaved game
-					if (_opt.autosave) {
-						TCHAR buf[40];
-						_sntprintf(buf, lengthof(buf), _T("autosave%d.sav"), (_autosave_ctr - 1) & 3);
-						SubmitFile(wnd, buf);
-					}
-					EnableWindow(GetDlgItem(wnd, 14), FALSE);
-					SetCursor(LoadCursor(NULL, IDC_ARROW));
-					MessageBox(wnd, _T("Crash report submitted. Thank you."), _T("Crash Report"), MB_ICONINFORMATION);
-				}	break;
-#endif /* Disabled crash-submit procedures */
-				case 15: /* Expand window to show crash-message */
-					_expanded ^= 1;
-					SetWndSize(wnd, _expanded);
-					break;
-			}
-			return TRUE;
-		case WM_CLOSE: ExitProcess(0);
-	}
-
-	return FALSE;
-}
-
-static void Handler2(void)
-{
-	ShowCursor(TRUE);
-	ShowWindow(GetActiveWindow(), FALSE);
-	DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, CrashDialogFunc);
-}
-
-extern bool CloseConsoleLogIfActive(void);
-
-static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
-{
-	extern const char _openttd_revision[];
-	char *output;
-	static bool had_exception = false;
-
-	if (had_exception) ExitProcess(0);
-	had_exception = true;
-
-	_ident = GetTickCount(); // something pretty unique
-
-	MakeCRCTable(alloca(256 * sizeof(uint32)));
-	_crash_msg = output = LocalAlloc(LMEM_FIXED, 8192);
-
-	{
-		SYSTEMTIME time;
-		GetLocalTime(&time);
-		output += sprintf(output,
-			"*** OpenTTD Crash Report ***\r\n"
-			"Date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n"
-			"Build: %s built on " __DATE__ " " __TIME__ "\r\n",
-			time.wYear,
-			time.wMonth,
-			time.wDay,
-			time.wHour,
-			time.wMinute,
-			time.wSecond,
-			_openttd_revision
-		);
-	}
-
-	if (_exception_string)
-		output += sprintf(output, "Reason: %s\r\n", _exception_string);
-
-#ifdef _M_AMD64
-	output += sprintf(output, "Exception %.8X at %.16IX\r\n"
-		"Registers:\r\n"
-		"RAX: %.16llX RBX: %.16llX RCX: %.16llX RDX: %.16llX\r\n"
-		"RSI: %.16llX RDI: %.16llX RBP: %.16llX RSP: %.16llX\r\n"
-		"R8:  %.16llX R9:  %.16llX R10: %.16llX R11: %.16llX\r\n"
-		"R12: %.16llX R13: %.16llX R14: %.16llX R15: %.16llX\r\n"
-		"RIP: %.16llX EFLAGS: %.8X\r\n"
-		"\r\nBytes at CS:RIP:\r\n",
-		ep->ExceptionRecord->ExceptionCode,
-		ep->ExceptionRecord->ExceptionAddress,
-		ep->ContextRecord->Rax,
-		ep->ContextRecord->Rbx,
-		ep->ContextRecord->Rcx,
-		ep->ContextRecord->Rdx,
-		ep->ContextRecord->Rsi,
-		ep->ContextRecord->Rdi,
-		ep->ContextRecord->Rbp,
-		ep->ContextRecord->Rsp,
-		ep->ContextRecord->R8,
-		ep->ContextRecord->R9,
-		ep->ContextRecord->R10,
-		ep->ContextRecord->R11,
-		ep->ContextRecord->R12,
-		ep->ContextRecord->R13,
-		ep->ContextRecord->R14,
-		ep->ContextRecord->R15,
-		ep->ContextRecord->Rip,
-		ep->ContextRecord->EFlags
-	);
-#else
-	output += sprintf(output, "Exception %.8X at %.8X\r\n"
-		"Registers:\r\n"
-		" EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\r\n"
-		" ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\r\n"
-		" EIP: %.8X EFLAGS: %.8X\r\n"
-		"\r\nBytes at CS:EIP:\r\n",
-		ep->ExceptionRecord->ExceptionCode,
-		ep->ExceptionRecord->ExceptionAddress,
-		ep->ContextRecord->Eax,
-		ep->ContextRecord->Ebx,
-		ep->ContextRecord->Ecx,
-		ep->ContextRecord->Edx,
-		ep->ContextRecord->Esi,
-		ep->ContextRecord->Edi,
-		ep->ContextRecord->Ebp,
-		ep->ContextRecord->Esp,
-		ep->ContextRecord->Eip,
-		ep->ContextRecord->EFlags
-	);
-#endif
-
-	{
-#ifdef _M_AMD64
-		byte *b = (byte*)ep->ContextRecord->Rip;
-#else
-		byte *b = (byte*)ep->ContextRecord->Eip;
-#endif
-		int i;
-		for (i = 0; i != 24; i++) {
-			if (IsBadReadPtr(b, 1)) {
-				output += sprintf(output, " ??"); // OCR: WAS: , 0);
-			} else {
-				output += sprintf(output, " %.2X", *b);
-			}
-			b++;
-		}
-		output += sprintf(output,
-			"\r\n"
-			"\r\nStack trace: \r\n"
-		);
-	}
-
-	{
-		int i,j;
-#ifdef _M_AMD64
-		uint32 *b = (uint32*)ep->ContextRecord->Rsp;
-#else
-		uint32 *b = (uint32*)ep->ContextRecord->Esp;
-#endif
-		for (j = 0; j != 24; j++) {
-			for (i = 0; i != 8; i++) {
-				if (IsBadReadPtr(b,sizeof(uint32))) {
-					output += sprintf(output, " ????????"); //OCR: WAS - , 0);
-				} else {
-					output += sprintf(output, " %.8X", *b);
-				}
-				b++;
-			}
-			output += sprintf(output, "\r\n");
-		}
-	}
-
-	output += sprintf(output, "\r\nModule information:\r\n");
-	output = PrintModuleList(output);
-
-	{
-		OSVERSIONINFO os;
-		os.dwOSVersionInfoSize = sizeof(os);
-		GetVersionEx(&os);
-		output += sprintf(output, "\r\nSystem information:\r\n"
-			" Windows version %d.%d %d %s\r\n",
-			os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion);
-	}
-
-	{
-		HANDLE file = CreateFile(_T("crash.log"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
-		DWORD num_written;
-		if (file != INVALID_HANDLE_VALUE) {
-			WriteFile(file, _crash_msg, output - _crash_msg, &num_written, NULL);
-			CloseHandle(file);
-		}
-	}
-
-	/* Close any possible log files */
-	CloseConsoleLogIfActive();
-
-	if (_safe_esp) {
-#ifdef _M_AMD64
-		ep->ContextRecord->Rip = (DWORD64)Handler2;
-		ep->ContextRecord->Rsp = (DWORD64)_safe_esp;
-#else
-		ep->ContextRecord->Eip = (DWORD)Handler2;
-		ep->ContextRecord->Esp = (DWORD)_safe_esp;
-#endif
-		return EXCEPTION_CONTINUE_EXECUTION;
-	}
-
-
-	return EXCEPTION_EXECUTE_HANDLER;
-}
-
-static void Win32InitializeExceptions(void)
-{
-#ifdef _M_AMD64
-	extern void *_get_save_esp(void);
-	_safe_esp = _get_save_esp();
-#else
-	_asm {
-		mov _safe_esp, esp
-	}
-#endif
-
-	SetUnhandledExceptionFilter(ExceptionHandler);
-}
-#endif /* _MSC_VER */
-
-/* Code below for windows version of opendir/readdir/closedir copied and
- * modified from Jan Wassenberg's GPL implementation posted over at
- * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1&#2398903 */
-
-/* suballocator - satisfies most requests with a reusable static instance.
- * this avoids hundreds of alloc/free which would fragment the heap.
- * To guarantee reentrancy, we fall back to malloc if the instance is
- * already in use (it's important to avoid suprises since this is such a
- * low-level routine). */
-static DIR _global_dir;
-static bool _global_dir_is_in_use = false;
-
-static inline DIR *dir_calloc(void)
-{
-	DIR *d;
-
-	if (_global_dir_is_in_use) {
-		d = calloc(1, sizeof(*d));
-	} else {
-		_global_dir_is_in_use = true;
-		d = &_global_dir;
-		memset(d, 0, sizeof(*d));
-	}
-	return d;
-}
-
-static inline void dir_free(DIR *d)
-{
-	if (d == &_global_dir) {
-		_global_dir_is_in_use = false;
-	} else {
-		free(d);
-	}
-}
-
-DIR *opendir(const char *path)
-{
-	DIR *d;
-	UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
-	DWORD fa = GetFileAttributesW(OTTD2FS(path));
-
-	if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
-		d = dir_calloc();
-		if (d != NULL) {
-			char search_path[MAX_PATH];
-			/* build search path for FindFirstFile */
-			snprintf(search_path, lengthof(search_path), "%s" PATHSEP "*", path);
-			d->hFind = FindFirstFileW(OTTD2FS(search_path), &d->fd);
-
-			if (d->hFind != INVALID_HANDLE_VALUE ||
-					GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty
-				d->ent.dir = d;
-				d->at_first_entry = true;
-			} else {
-				dir_free(d);
-				d = NULL;
-			}
-		} else {
-			errno = ENOMEM;
-		}
-	} else {
-		/* path not found or not a directory */
-		d = NULL;
-		errno = ENOENT;
-	}
-
-	SetErrorMode(sem); // restore previous setting
-	return d;
-}
-
-struct dirent *readdir(DIR *d)
-{
-	DWORD prev_err = GetLastError(); // avoid polluting last error
-
-	if (d->at_first_entry) {
-		/* the directory was empty when opened */
-		if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
-		d->at_first_entry = false;
-	} else if (!FindNextFileW(d->hFind, &d->fd)) { // determine cause and bail
-		if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
-		return NULL;
-	}
-
-	/* This entry has passed all checks; return information about it.
-	 * (note: d_name is a pointer; see struct dirent definition) */
-	d->ent.d_name = d->fd.cFileName;
-	return &d->ent;
-}
-
-int closedir(DIR *d)
-{
-	FindClose(d->hFind);
-	dir_free(d);
-	return 0;
-}
-
-bool FiosIsRoot(const char *file)
-{
-	return file[3] == '\0'; // C:\...
-}
-
-void FiosGetDrives(void)
-{
-	TCHAR drives[256];
-	const TCHAR *s;
-
-	GetLogicalDriveStrings(sizeof(drives), drives);
-	for (s = drives; *s != '\0';) {
-		FiosItem *fios = FiosAlloc();
-		fios->type = FIOS_TYPE_DRIVE;
-		fios->mtime = 0;
-		snprintf(fios->name, lengthof(fios->name),  "%c:", s[0] & 0xFF);
-		ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
-		while (*s++ != '\0');
-	}
-}
-
-bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
-{
-	// hectonanoseconds between Windows and POSIX epoch
-	static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
-	const WIN32_FIND_DATAW *fd = &ent->dir->fd;
-	if (fd->dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) return false;
-
-	sb->st_size  = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
-	/* UTC FILETIME to seconds-since-1970 UTC
-	 * we just have to subtract POSIX epoch and scale down to units of seconds.
-	 * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1&#1860504
-	 * XXX - not entirely correct, since filetimes on FAT aren't UTC but local,
-	 * this won't entirely be correct, but we use the time only for comparsion. */
-	sb->st_mtime = (time_t)((*(uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
-	sb->st_mode  = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
-
-	return true;
-}
-
-bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
-{
-	UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);  // disable 'no-disk' message box
-	bool retval = false;
-	TCHAR root[4];
-	DWORD spc, bps, nfc, tnc;
-
-	_sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]);
-	if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
-		*tot = ((spc * bps) * (uint64)nfc) >> 20;
-		retval = true;
-	}
-
-	SetErrorMode(sem); // reset previous setting
-	return retval;
-}
-
-static int ParseCommandLine(char *line, char **argv, int max_argc)
-{
-	int n = 0;
-
-	do {
-		// skip whitespace
-		while (*line == ' ' || *line == '\t') line++;
-
-		// end?
-		if (*line == '\0') break;
-
-		// special handling when quoted
-		if (*line == '"') {
-			argv[n++] = ++line;
-			while (*line != '"') {
-				if (*line == '\0') return n;
-				line++;
-			}
-		} else {
-			argv[n++] = line;
-			while (*line != ' ' && *line != '\t') {
-				if (*line == '\0') return n;
-				line++;
-			}
-		}
-		*line++ = '\0';
-	} while (n != max_argc);
-
-	return n;
-}
-
-void CreateConsole(void)
-{
-	HANDLE hand;
-	CONSOLE_SCREEN_BUFFER_INFO coninfo;
-
-	if (_has_console) return;
-	_has_console = true;
-
-	AllocConsole();
-
-	hand = GetStdHandle(STD_OUTPUT_HANDLE);
-	GetConsoleScreenBufferInfo(hand, &coninfo);
-	coninfo.dwSize.Y = 500;
-	SetConsoleScreenBufferSize(hand, coninfo.dwSize);
-
-	// redirect unbuffered STDIN, STDOUT, STDERR to the console
-#if !defined(__CYGWIN__)
-	*stdout = *_fdopen( _open_osfhandle((intptr_t)hand, _O_TEXT), "w" );
-	*stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" );
-	*stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" );
-#else
-	// open_osfhandle is not in cygwin
-	*stdout = *fdopen(1, "w" );
-	*stdin = *fdopen(0, "r" );
-	*stderr = *fdopen(2, "w" );
-#endif
-
-	setvbuf(stdin, NULL, _IONBF, 0);
-	setvbuf(stdout, NULL, _IONBF, 0);
-	setvbuf(stderr, NULL, _IONBF, 0);
-}
-
-void ShowInfo(const char *str)
-{
-	if (_has_console) {
-		fprintf(stderr, str);
-	} else {
-		bool old;
-
-		ReleaseCapture();
-		_left_button_clicked =_left_button_down = false;
-
-		old = MyShowCursor(true);
-		if (MessageBox(GetActiveWindow(), MB_TO_WIDE(str), _T("OpenTTD"), MB_ICONINFORMATION | MB_OKCANCEL) == IDCANCEL) {
-			CreateConsole();
-		}
-		MyShowCursor(old);
-	}
-}
-
-#ifdef __MINGW32__
-	/* _set_error_mode() constants&function (do not exist in mingw headers) */
-	#define _OUT_TO_DEFAULT      0
-	#define _OUT_TO_STDERR       1
-	#define _OUT_TO_MSGBOX       2
-	#define _REPORT_ERRMODE      3
-	int _set_error_mode(int);
-#endif
-
-int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
-	LPTSTR lpCmdLine, int nCmdShow)
-{
-	int argc;
-	char *argv[64]; // max 64 command line arguments
-	char *cmdline;
-
-#if defined(UNICODE)
-	/* For UNICODE we need to convert the commandline to char* _AND_
-	 * save it because argv[] points into this buffer and thus needs to
-	 * be available between subsequent calls to FS2OTTD() */
-	char cmdlinebuf[MAX_PATH];
-#endif
-
-	cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf));
-
-#if defined(_DEBUG)
-	CreateConsole();
-#endif
-
-	_set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox
-
-	/* setup random seed to something quite random */
-	_random_seeds[1][0] = _random_seeds[0][0] = GetTickCount();
-	_random_seeds[1][1] = _random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
-	SeedMT(_random_seeds[0][0]);
-
-	argc = ParseCommandLine(cmdline, argv, lengthof(argv));
-
-#if defined(WIN32_EXCEPTION_TRACKER)
-	Win32InitializeExceptions();
-#endif
-
-#if defined(WIN32_EXCEPTION_TRACKER_DEBUG)
-	_try {
-		LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep);
-#endif
-		ttd_main(argc, argv);
-
-#if defined(WIN32_EXCEPTION_TRACKER_DEBUG)
-	} _except (ExceptionHandler(_exception_info())) {}
-#endif
-
-	return 0;
-}
-
-void DeterminePaths(void)
-{
-	char *s, *cfg;
-	wchar_t path[MAX_PATH];
-
-	_paths.personal_dir = _paths.game_data_dir = cfg = malloc(MAX_PATH);
-	GetCurrentDirectoryW(MAX_PATH - 1, path);
-	convert_from_fs(path, cfg, MAX_PATH);
-
-	cfg[0] = toupper(cfg[0]);
-	s = strchr(cfg, '\0');
-	if (s[-1] != '\\') strcpy(s, "\\");
-
-	_paths.save_dir = str_fmt("%ssave", cfg);
-	_paths.autosave_dir = str_fmt("%s\\autosave", _paths.save_dir);
-	_paths.scenario_dir = str_fmt("%sscenario", cfg);
-	_paths.heightmap_dir = str_fmt("%sscenario\\heightmap", cfg);
-	_paths.gm_dir = str_fmt("%sgm\\", cfg);
-	_paths.data_dir = str_fmt("%sdata\\", cfg);
-	_paths.lang_dir = str_fmt("%slang\\", cfg);
-
-	if (_config_file == NULL)
-		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
-
-	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
-	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
-
-	// make (auto)save and scenario folder
-	CreateDirectoryW(OTTD2FS(_paths.save_dir), NULL);
-	CreateDirectoryW(OTTD2FS(_paths.autosave_dir), NULL);
-	CreateDirectoryW(OTTD2FS(_paths.scenario_dir), NULL);
-	CreateDirectoryW(OTTD2FS(_paths.heightmap_dir), NULL);
-}
-
-/**
- * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard
- * and append this up to the maximum length (either absolute or screenlength). If maxlength
- * is zero, we don't care about the screenlength but only about the physical length of the string
- * @param tb @Textbuf type to be changed
- * @return Return true on successfull change of Textbuf, or false otherwise
- */
-bool InsertTextBufferClipboard(Textbuf *tb)
-{
-	HGLOBAL cbuf;
-	char utf8_buf[512];
-	const char *ptr;
-
-	WChar c;
-	uint16 width, length;
-
-	if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
-		const char *ret;
-
-		OpenClipboard(NULL);
-		cbuf = GetClipboardData(CF_UNICODETEXT);
-
-		ptr = GlobalLock(cbuf);
-		ret = convert_from_fs((wchar_t*)ptr, utf8_buf, lengthof(utf8_buf));
-		GlobalUnlock(cbuf);
-		CloseClipboard();
-
-		if (*ret == '\0') return false;
-	} else if (IsClipboardFormatAvailable(CF_TEXT)) {
-		OpenClipboard(NULL);
-		cbuf = GetClipboardData(CF_TEXT);
-
-		ptr = GlobalLock(cbuf);
-		ttd_strlcpy(utf8_buf, ptr, lengthof(utf8_buf));
-		GlobalUnlock(cbuf);
-		CloseClipboard();
-	} else {
-		return false;
-	}
-
-	width = length = 0;
-
-	for (ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
-		byte charwidth;
-
-		if (!IsPrintable(c)) break;
-		if (tb->length + length >= tb->maxlength - 1) break;
-		charwidth = GetCharacterWidth(FS_NORMAL, c);
-
-		if (tb->maxwidth != 0 && width + tb->width + charwidth > tb->maxwidth) break;
-
-		width += charwidth;
-		length += Utf8CharLen(c);
-	}
-
-	if (length == 0) return false;
-
-	memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
-	memcpy(tb->buf + tb->caretpos, utf8_buf, length);
-	tb->width += width;
-	tb->caretxoffs += width;
-
-	tb->length += length;
-	tb->caretpos += length;
-	tb->buf[tb->length] = '\0'; // terminating zero
-
-	return true;
-}
-
-
-void CSleep(int milliseconds)
-{
-	Sleep(milliseconds);
-}
-
-
-// Utility function to get the current timestamp in milliseconds
-// Useful for profiling
-int64 GetTS(void)
-{
-	static double freq;
-	__int64 value;
-	if (!freq) {
-		QueryPerformanceFrequency((LARGE_INTEGER*)&value);
-		freq = (double)1000000 / value;
-	}
-	QueryPerformanceCounter((LARGE_INTEGER*)&value);
-	return (__int64)(value * freq);
-}
-
-/** Convert from OpenTTD's encoding to that of the local environment in
- * UNICODE. OpenTTD encoding is UTF8, local is wide-char
- * @param name pointer to a valid string that will be converted
- * @param utf16_buf pointer to a valid wide-char buffer that will receive the
- * converted string
- * @param buflen length in wide characters of the receiving buffer
- * @return pointer to utf16_buf. If conversion fails the string is of zero-length */
-wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
-{
-	int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, buflen);
-	if (len == 0) {
-		DEBUG(misc, 0, "[utf8] error converting '%s'. Errno %d", name, GetLastError());
-		utf16_buf[0] = '\0';
-	}
-
-	return utf16_buf;
-}
-
-/** Convert from OpenTTD's encoding to that of the local environment in
- * UNICODE. OpenTTD encoding is UTF8, local is wide-char.
- * The returned value's contents can only be guaranteed until the next call to
- * this function. So if the value is needed for anything else, use convert_from_fs
- * @param name pointer to a valid string that will be converted
- * @return pointer to the converted string; if failed string is of zero-length */
-const wchar_t *OTTD2FS(const char *name)
-{
-	static wchar_t utf16_buf[512];
-	return convert_to_fs(name, utf16_buf, lengthof(utf16_buf));
-}
-
-
-/** Convert to OpenTTD's encoding from that of the local environment in
- * UNICODE. OpenTTD encoding is UTF8, local is wide-char
- * @param name pointer to a valid string that will be converted
- * @param utf8_buf pointer to a valid buffer that will receive the converted string
- * @param buflen length in characters of the receiving buffer
- * @return pointer to utf8_buf. If conversion fails the string is of zero-length */
-char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
-{
-	int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, buflen, NULL, NULL);
-	if (len == 0) {
-		DEBUG(misc, 0, "[utf8] error converting wide-string. Errno %d", GetLastError());
-		utf8_buf[0] = '\0';
-	}
-
-	return utf8_buf;
-}
-
-/** Convert to OpenTTD's encoding from that of the local environment in
- * UNICODE. OpenTTD encoding is UTF8, local is wide-char.
- * The returned value's contents can only be guaranteed until the next call to
- * this function. So if the value is needed for anything else, use convert_from_fs
- * @param name pointer to a valid string that will be converted
- * @return pointer to the converted string; if failed string is of zero-length */
-const char *FS2OTTD(const wchar_t *name)
-{
-	static char utf8_buf[512];
-	return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
-}
-
-/** Our very own SHGetFolderPath function for support of windows operating
- * systems that don't have this function (eg Win9x, etc.). We try using the
- * native function, and if that doesn't exist we will try a more crude approach
- * of environment variables and hope for the best */
-HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
-{
-	static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
-	static bool first_time = true;
-
-	/* We only try to load the library one time; if it fails, it fails */
-	if (first_time) {
-#if defined(UNICODE)
-# define W(x) x "W"
-#else
-# define W(x) x "A"
-#endif
-		if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) {
-			DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from SHFolder.dll");
-		}
-#undef W
-		first_time = false;
-	}
-
-	if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
-
-	/* SHGetFolderPath doesn't exist, try a more conservative approach,
-	 * eg environment variables. This is only included for legacy modes
-	 * MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of
-	 * length MAX_PATH which will receive the path" so let's assume that
-	 * Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0,
-	 * Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0,
-	 * Windows NT 4.0 with Service Pack 4 (SP4) */
-	{
-		DWORD ret;
-		switch (csidl) {
-			case CSIDL_FONTS: /* Get the system font path, eg %WINDIR%\Fonts */
-				ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH);
-				if (ret == 0) break;
-				_tcsncat(pszPath, _T("\\Fonts"), MAX_PATH);
-
-				return (HRESULT)0;
-				break;
-			/* XXX - other types to go here when needed... */
-		}
-	}
-
-	return E_INVALIDARG;
-}
new file mode 100644
--- /dev/null
+++ b/src/win32.cpp
@@ -0,0 +1,1140 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "macros.h"
+#include "saveload.h"
+#include "string.h"
+#include "gfx.h"
+#include "window.h"
+#include <windows.h>
+#include <winnt.h>
+#include <wininet.h>
+#include <io.h>
+#include <fcntl.h>
+#include <shlobj.h> // SHGetFolderPath
+#include "variables.h"
+#include "win32.h"
+#include "fios.h" // opendir/readdir/closedir
+#include <ctype.h>
+#include <tchar.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static bool _has_console;
+
+#if defined(__MINGW32__)
+	#include <stdint.h>
+#endif
+
+static bool cursor_visible = true;
+
+bool MyShowCursor(bool show)
+{
+	if (cursor_visible == show) return show;
+
+	cursor_visible = show;
+	ShowCursor(show);
+
+	return !show;
+}
+
+/** Helper function needed by dynamically loading libraries
+ * XXX: Hurray for MS only having an ANSI GetProcAddress function
+ * on normal windows and no Wide version except for in Windows Mobile/CE */
+bool LoadLibraryList(Function proc[], const char *dll)
+{
+	while (*dll != '\0') {
+		HMODULE lib;
+		lib = LoadLibrary(MB_TO_WIDE(dll));
+
+		if (lib == NULL) return false;
+		for (;;) {
+			FARPROC p;
+
+			while (*dll++ != '\0');
+			if (*dll == '\0') break;
+#if defined(WINCE)
+			p = GetProcAddress(lib, MB_TO_WIDE(dll);
+#else
+			p = GetProcAddress(lib, dll);
+#endif
+			if (p == NULL) return false;
+			*proc++ = (Function)p;
+		}
+		dll++;
+	}
+	return true;
+}
+
+#ifdef _MSC_VER
+static const char *_exception_string = NULL;
+#endif
+
+void ShowOSErrorBox(const char *buf)
+{
+	MyShowCursor(true);
+	MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP);
+
+// if exception tracker is enabled, we crash here to let the exception handler handle it.
+#if defined(WIN32_EXCEPTION_TRACKER) && !defined(_DEBUG)
+	if (*buf == '!') {
+		_exception_string = buf;
+		*(byte*)0 = 0;
+	}
+#endif
+}
+
+#ifdef _MSC_VER
+
+static void *_safe_esp;
+static char *_crash_msg;
+static bool _expanded;
+static bool _did_emerg_save;
+static int _ident;
+
+typedef struct DebugFileInfo {
+	uint32 size;
+	uint32 crc32;
+	SYSTEMTIME file_time;
+} DebugFileInfo;
+
+static uint32 *_crc_table;
+
+static void MakeCRCTable(uint32 *table) {
+	uint32 crc, poly = 0xEDB88320L;
+	int i;
+	int j;
+
+	_crc_table = table;
+
+	for (i = 0; i != 256; i++) {
+		crc = i;
+		for (j = 8; j != 0; j--) {
+			crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1);
+		}
+		table[i] = crc;
+	}
+}
+
+static uint32 CalcCRC(byte *data, uint size, uint32 crc) {
+	for (; size > 0; size--) {
+		crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF];
+	}
+	return crc;
+}
+
+static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename)
+{
+	HANDLE file;
+	memset(dfi, 0, sizeof(dfi));
+
+	file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+	if (file != INVALID_HANDLE_VALUE) {
+		byte buffer[1024];
+		DWORD numread;
+		uint32 filesize = 0;
+		FILETIME write_time;
+		uint32 crc = (uint32)-1;
+
+		for (;;) {
+			if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread == 0)
+				break;
+			filesize += numread;
+			crc = CalcCRC(buffer, numread, crc);
+		}
+		dfi->size = filesize;
+		dfi->crc32 = crc ^ (uint32)-1;
+
+		if (GetFileTime(file, NULL, NULL, &write_time)) {
+			FileTimeToSystemTime(&write_time, &dfi->file_time);
+		}
+		CloseHandle(file);
+	}
+}
+
+
+static char *PrintModuleInfo(char *output, HMODULE mod)
+{
+	TCHAR buffer[MAX_PATH];
+	DebugFileInfo dfi;
+
+	GetModuleFileName(mod, buffer, MAX_PATH);
+	GetFileInfo(&dfi, buffer);
+	output += sprintf(output, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n",
+		WIDE_TO_MB(buffer),
+		mod,
+		dfi.size,
+		dfi.crc32,
+		dfi.file_time.wYear,
+		dfi.file_time.wMonth,
+		dfi.file_time.wDay,
+		dfi.file_time.wHour,
+		dfi.file_time.wMinute,
+		dfi.file_time.wSecond
+	);
+	return output;
+}
+
+static char *PrintModuleList(char *output)
+{
+	BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD);
+
+	if (LoadLibraryList((Function*)&EnumProcessModules, "psapi.dll\0EnumProcessModules\0\0")) {
+		HMODULE modules[100];
+		DWORD needed;
+		BOOL res;
+		int count, i;
+
+		HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
+		if (proc != NULL) {
+			res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
+			CloseHandle(proc);
+			if (res) {
+				count = min(needed / sizeof(HMODULE), lengthof(modules));
+
+				for (i = 0; i != count; i++) output = PrintModuleInfo(output, modules[i]);
+				return output;
+			}
+		}
+	}
+	output = PrintModuleInfo(output, NULL);
+	return output;
+}
+
+static const TCHAR _crash_desc[] =
+	_T("A serious fault condition occured in the game. The game will shut down.\n")
+	_T("Please send the crash information and the crash.dmp file (if any) to the developers.\n")
+	_T("This will greatly help debugging. The correct place to do this is http://bugs.openttd.org. ")
+	_T("The information contained in the report is displayed below.\n")
+	_T("Press \"Emergency save\" to attempt saving the game.");
+
+static const TCHAR _save_succeeded[] =
+	_T("Emergency save succeeded.\n")
+	_T("Be aware that critical parts of the internal game state may have become ")
+	_T("corrupted. The saved game is not guaranteed to work.");
+
+static bool EmergencySave(void)
+{
+	SaveOrLoad("crash.sav", SL_SAVE);
+	return true;
+}
+
+/* Disable the crash-save submit code as it's not used */
+#if 0
+
+typedef struct {
+	HINTERNET (WINAPI *InternetOpen)(LPCTSTR,DWORD, LPCTSTR, LPCTSTR, DWORD);
+	HINTERNET (WINAPI *InternetConnect)(HINTERNET, LPCTSTR, INTERNET_PORT, LPCTSTR, LPCTSTR, DWORD, DWORD, DWORD);
+	HINTERNET (WINAPI *HttpOpenRequest)(HINTERNET, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR *, DWORD, DWORD);
+	BOOL (WINAPI *HttpSendRequest)(HINTERNET, LPCTSTR, DWORD, LPVOID, DWORD);
+	BOOL (WINAPI *InternetCloseHandle)(HINTERNET);
+	BOOL (WINAPI *HttpQueryInfo)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
+} WinInetProcs;
+
+#define M(x) x "\0"
+#if defined(UNICODE)
+# define W(x) x "W"
+#else
+# define W(x) x "A"
+#endif
+static const char wininet_files[] =
+	M("wininet.dll")
+	M(W("InternetOpen"))
+	M(W("InternetConnect"))
+	M(W("HttpOpenRequest"))
+	M(W("HttpSendRequest"))
+	M("InternetCloseHandle")
+	M(W("HttpQueryInfo"))
+	M("");
+#undef W
+#undef M
+
+static WinInetProcs _wininet;
+
+static const TCHAR *SubmitCrashReport(HWND wnd, void *msg, size_t msglen, const TCHAR *arg)
+{
+	HINTERNET inet, conn, http;
+	const TCHAR *err = NULL;
+	DWORD code, len;
+	static TCHAR buf[100];
+	TCHAR buff[100];
+
+	if (_wininet.InternetOpen == NULL && !LoadLibraryList((Function*)&_wininet, wininet_files)) return _T("can't load wininet.dll");
+
+	inet = _wininet.InternetOpen(_T("OTTD"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
+	if (inet == NULL) { err = _T("internetopen failed"); goto error1; }
+
+	conn = _wininet.InternetConnect(inet, _T("www.openttd.org"), INTERNET_DEFAULT_HTTP_PORT, _T(""), _T(""), INTERNET_SERVICE_HTTP, 0, 0);
+	if (conn == NULL) { err = _T("internetconnect failed"); goto error2; }
+
+	_sntprintf(buff, lengthof(buff), _T("/crash.php?file=%s&ident=%d"), arg, _ident);
+
+	http = _wininet.HttpOpenRequest(conn, _T("POST"), buff, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE , 0);
+	if (http == NULL) { err = _T("httpopenrequest failed"); goto error3; }
+
+	if (!_wininet.HttpSendRequest(http, _T("Content-type: application/binary"), -1, msg, (DWORD)msglen)) { err = _T("httpsendrequest failed"); goto error4; }
+
+	len = sizeof(code);
+	if (!_wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &code, &len, 0)) { err = _T("httpqueryinfo failed"); goto error4; }
+
+	if (code != 200) {
+		int l = _sntprintf(buf, lengthof(buf), _T("Server said: %d "), code);
+		len = sizeof(buf) - l;
+		_wininet.HttpQueryInfo(http, HTTP_QUERY_STATUS_TEXT, buf + l, &len, 0);
+		err = buf;
+	}
+
+error4:
+	_wininet.InternetCloseHandle(http);
+error3:
+	_wininet.InternetCloseHandle(conn);
+error2:
+	_wininet.InternetCloseHandle(inet);
+error1:
+	return err;
+}
+
+static void SubmitFile(HWND wnd, const TCHAR *file)
+{
+	HANDLE h;
+	unsigned long size;
+	unsigned long read;
+	void *mem;
+
+	h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+	if (h == NULL) return;
+
+	size = GetFileSize(h, NULL);
+	if (size > 500000) goto error1;
+
+	mem = malloc(size);
+	if (mem == NULL) goto error1;
+
+	if (!ReadFile(h, mem, size, &read, NULL) || read != size) goto error2;
+
+	SubmitCrashReport(wnd, mem, size, file);
+
+error2:
+	free(mem);
+error1:
+	CloseHandle(h);
+}
+
+#endif /* Disabled crash-submit procedures */
+
+static const TCHAR * const _expand_texts[] = {_T("S&how report >>"), _T("&Hide report <<") };
+
+static void SetWndSize(HWND wnd, int mode)
+{
+	RECT r,r2;
+	int offs;
+
+	GetWindowRect(wnd, &r);
+
+	SetDlgItemText(wnd, 15, _expand_texts[mode == 1]);
+
+	if (mode >= 0) {
+		GetWindowRect(GetDlgItem(wnd, 11), &r2);
+		offs = r2.bottom - r2.top + 10;
+		if (!mode) offs = -offs;
+		SetWindowPos(wnd, HWND_TOPMOST, 0, 0,
+			r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER);
+	} else {
+		SetWindowPos(wnd, HWND_TOPMOST,
+			(GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2,
+			(GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2,
+			0, 0, SWP_NOSIZE);
+	}
+}
+
+static bool DoEmergencySave(HWND wnd)
+{
+	bool b = false;
+
+	EnableWindow(GetDlgItem(wnd, 13), FALSE);
+	_did_emerg_save = true;
+	__try {
+		b = EmergencySave();
+	} __except (1) {}
+	return b;
+}
+
+static INT_PTR CALLBACK CrashDialogFunc(HWND wnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+	switch (msg) {
+		case WM_INITDIALOG: {
+#if defined(UNICODE)
+			/* We need to put the crash-log in a seperate buffer because the default
+			 * buffer in MB_TO_WIDE is not large enough (256 chars) */
+			wchar_t crash_msgW[8096];
+#endif
+			SetDlgItemText(wnd, 10, _crash_desc);
+			SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(_crash_msg, crash_msgW, lengthof(crash_msgW)));
+			SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
+			SetWndSize(wnd, -1);
+		} return TRUE;
+		case WM_COMMAND:
+			switch (wParam) {
+				case 12: /* Close */
+					ExitProcess(0);
+				case 13: /* Emergency save */
+					if (DoEmergencySave(wnd)) {
+						MessageBox(wnd, _save_succeeded, _T("Save successful"), MB_ICONINFORMATION);
+					} else {
+						MessageBox(wnd, _T("Save failed"), _T("Save failed"), MB_ICONINFORMATION);
+					}
+					break;
+/* Disable the crash-save submit code as it's not used */
+#if 0
+				case 14: { /* Submit crash report */
+					const TCHAR *s;
+
+					SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+					s = SubmitCrashReport(wnd, _crash_msg, strlen(_crash_msg), _T(""));
+					if (s != NULL) {
+						MessageBox(wnd, s, _T("Error"), MB_ICONSTOP);
+						break;
+					}
+
+					// try to submit emergency savegame
+					if (_did_emerg_save || DoEmergencySave(wnd)) SubmitFile(wnd, _T("crash.sav"));
+
+					// try to submit the autosaved game
+					if (_opt.autosave) {
+						TCHAR buf[40];
+						_sntprintf(buf, lengthof(buf), _T("autosave%d.sav"), (_autosave_ctr - 1) & 3);
+						SubmitFile(wnd, buf);
+					}
+					EnableWindow(GetDlgItem(wnd, 14), FALSE);
+					SetCursor(LoadCursor(NULL, IDC_ARROW));
+					MessageBox(wnd, _T("Crash report submitted. Thank you."), _T("Crash Report"), MB_ICONINFORMATION);
+				}	break;
+#endif /* Disabled crash-submit procedures */
+				case 15: /* Expand window to show crash-message */
+					_expanded ^= 1;
+					SetWndSize(wnd, _expanded);
+					break;
+			}
+			return TRUE;
+		case WM_CLOSE: ExitProcess(0);
+	}
+
+	return FALSE;
+}
+
+static void Handler2(void)
+{
+	ShowCursor(TRUE);
+	ShowWindow(GetActiveWindow(), FALSE);
+	DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, CrashDialogFunc);
+}
+
+extern bool CloseConsoleLogIfActive(void);
+
+static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
+{
+	extern const char _openttd_revision[];
+	char *output;
+	static bool had_exception = false;
+
+	if (had_exception) ExitProcess(0);
+	had_exception = true;
+
+	_ident = GetTickCount(); // something pretty unique
+
+	MakeCRCTable(alloca(256 * sizeof(uint32)));
+	_crash_msg = output = LocalAlloc(LMEM_FIXED, 8192);
+
+	{
+		SYSTEMTIME time;
+		GetLocalTime(&time);
+		output += sprintf(output,
+			"*** OpenTTD Crash Report ***\r\n"
+			"Date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n"
+			"Build: %s built on " __DATE__ " " __TIME__ "\r\n",
+			time.wYear,
+			time.wMonth,
+			time.wDay,
+			time.wHour,
+			time.wMinute,
+			time.wSecond,
+			_openttd_revision
+		);
+	}
+
+	if (_exception_string)
+		output += sprintf(output, "Reason: %s\r\n", _exception_string);
+
+#ifdef _M_AMD64
+	output += sprintf(output, "Exception %.8X at %.16IX\r\n"
+		"Registers:\r\n"
+		"RAX: %.16llX RBX: %.16llX RCX: %.16llX RDX: %.16llX\r\n"
+		"RSI: %.16llX RDI: %.16llX RBP: %.16llX RSP: %.16llX\r\n"
+		"R8:  %.16llX R9:  %.16llX R10: %.16llX R11: %.16llX\r\n"
+		"R12: %.16llX R13: %.16llX R14: %.16llX R15: %.16llX\r\n"
+		"RIP: %.16llX EFLAGS: %.8X\r\n"
+		"\r\nBytes at CS:RIP:\r\n",
+		ep->ExceptionRecord->ExceptionCode,
+		ep->ExceptionRecord->ExceptionAddress,
+		ep->ContextRecord->Rax,
+		ep->ContextRecord->Rbx,
+		ep->ContextRecord->Rcx,
+		ep->ContextRecord->Rdx,
+		ep->ContextRecord->Rsi,
+		ep->ContextRecord->Rdi,
+		ep->ContextRecord->Rbp,
+		ep->ContextRecord->Rsp,
+		ep->ContextRecord->R8,
+		ep->ContextRecord->R9,
+		ep->ContextRecord->R10,
+		ep->ContextRecord->R11,
+		ep->ContextRecord->R12,
+		ep->ContextRecord->R13,
+		ep->ContextRecord->R14,
+		ep->ContextRecord->R15,
+		ep->ContextRecord->Rip,
+		ep->ContextRecord->EFlags
+	);
+#else
+	output += sprintf(output, "Exception %.8X at %.8X\r\n"
+		"Registers:\r\n"
+		" EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\r\n"
+		" ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\r\n"
+		" EIP: %.8X EFLAGS: %.8X\r\n"
+		"\r\nBytes at CS:EIP:\r\n",
+		ep->ExceptionRecord->ExceptionCode,
+		ep->ExceptionRecord->ExceptionAddress,
+		ep->ContextRecord->Eax,
+		ep->ContextRecord->Ebx,
+		ep->ContextRecord->Ecx,
+		ep->ContextRecord->Edx,
+		ep->ContextRecord->Esi,
+		ep->ContextRecord->Edi,
+		ep->ContextRecord->Ebp,
+		ep->ContextRecord->Esp,
+		ep->ContextRecord->Eip,
+		ep->ContextRecord->EFlags
+	);
+#endif
+
+	{
+#ifdef _M_AMD64
+		byte *b = (byte*)ep->ContextRecord->Rip;
+#else
+		byte *b = (byte*)ep->ContextRecord->Eip;
+#endif
+		int i;
+		for (i = 0; i != 24; i++) {
+			if (IsBadReadPtr(b, 1)) {
+				output += sprintf(output, " ??"); // OCR: WAS: , 0);
+			} else {
+				output += sprintf(output, " %.2X", *b);
+			}
+			b++;
+		}
+		output += sprintf(output,
+			"\r\n"
+			"\r\nStack trace: \r\n"
+		);
+	}
+
+	{
+		int i,j;
+#ifdef _M_AMD64
+		uint32 *b = (uint32*)ep->ContextRecord->Rsp;
+#else
+		uint32 *b = (uint32*)ep->ContextRecord->Esp;
+#endif
+		for (j = 0; j != 24; j++) {
+			for (i = 0; i != 8; i++) {
+				if (IsBadReadPtr(b,sizeof(uint32))) {
+					output += sprintf(output, " ????????"); //OCR: WAS - , 0);
+				} else {
+					output += sprintf(output, " %.8X", *b);
+				}
+				b++;
+			}
+			output += sprintf(output, "\r\n");
+		}
+	}
+
+	output += sprintf(output, "\r\nModule information:\r\n");
+	output = PrintModuleList(output);
+
+	{
+		OSVERSIONINFO os;
+		os.dwOSVersionInfoSize = sizeof(os);
+		GetVersionEx(&os);
+		output += sprintf(output, "\r\nSystem information:\r\n"
+			" Windows version %d.%d %d %s\r\n",
+			os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion);
+	}
+
+	{
+		HANDLE file = CreateFile(_T("crash.log"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+		DWORD num_written;
+		if (file != INVALID_HANDLE_VALUE) {
+			WriteFile(file, _crash_msg, output - _crash_msg, &num_written, NULL);
+			CloseHandle(file);
+		}
+	}
+
+	/* Close any possible log files */
+	CloseConsoleLogIfActive();
+
+	if (_safe_esp) {
+#ifdef _M_AMD64
+		ep->ContextRecord->Rip = (DWORD64)Handler2;
+		ep->ContextRecord->Rsp = (DWORD64)_safe_esp;
+#else
+		ep->ContextRecord->Eip = (DWORD)Handler2;
+		ep->ContextRecord->Esp = (DWORD)_safe_esp;
+#endif
+		return EXCEPTION_CONTINUE_EXECUTION;
+	}
+
+
+	return EXCEPTION_EXECUTE_HANDLER;
+}
+
+static void Win32InitializeExceptions(void)
+{
+#ifdef _M_AMD64
+	extern void *_get_save_esp(void);
+	_safe_esp = _get_save_esp();
+#else
+	_asm {
+		mov _safe_esp, esp
+	}
+#endif
+
+	SetUnhandledExceptionFilter(ExceptionHandler);
+}
+#endif /* _MSC_VER */
+
+/* Code below for windows version of opendir/readdir/closedir copied and
+ * modified from Jan Wassenberg's GPL implementation posted over at
+ * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1&#2398903 */
+
+/* suballocator - satisfies most requests with a reusable static instance.
+ * this avoids hundreds of alloc/free which would fragment the heap.
+ * To guarantee reentrancy, we fall back to malloc if the instance is
+ * already in use (it's important to avoid suprises since this is such a
+ * low-level routine). */
+static DIR _global_dir;
+static bool _global_dir_is_in_use = false;
+
+static inline DIR *dir_calloc(void)
+{
+	DIR *d;
+
+	if (_global_dir_is_in_use) {
+		d = calloc(1, sizeof(*d));
+	} else {
+		_global_dir_is_in_use = true;
+		d = &_global_dir;
+		memset(d, 0, sizeof(*d));
+	}
+	return d;
+}
+
+static inline void dir_free(DIR *d)
+{
+	if (d == &_global_dir) {
+		_global_dir_is_in_use = false;
+	} else {
+		free(d);
+	}
+}
+
+DIR *opendir(const char *path)
+{
+	DIR *d;
+	UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
+	DWORD fa = GetFileAttributesW(OTTD2FS(path));
+
+	if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
+		d = dir_calloc();
+		if (d != NULL) {
+			char search_path[MAX_PATH];
+			/* build search path for FindFirstFile */
+			snprintf(search_path, lengthof(search_path), "%s" PATHSEP "*", path);
+			d->hFind = FindFirstFileW(OTTD2FS(search_path), &d->fd);
+
+			if (d->hFind != INVALID_HANDLE_VALUE ||
+					GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty
+				d->ent.dir = d;
+				d->at_first_entry = true;
+			} else {
+				dir_free(d);
+				d = NULL;
+			}
+		} else {
+			errno = ENOMEM;
+		}
+	} else {
+		/* path not found or not a directory */
+		d = NULL;
+		errno = ENOENT;
+	}
+
+	SetErrorMode(sem); // restore previous setting
+	return d;
+}
+
+struct dirent *readdir(DIR *d)
+{
+	DWORD prev_err = GetLastError(); // avoid polluting last error
+
+	if (d->at_first_entry) {
+		/* the directory was empty when opened */
+		if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
+		d->at_first_entry = false;
+	} else if (!FindNextFileW(d->hFind, &d->fd)) { // determine cause and bail
+		if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
+		return NULL;
+	}
+
+	/* This entry has passed all checks; return information about it.
+	 * (note: d_name is a pointer; see struct dirent definition) */
+	d->ent.d_name = d->fd.cFileName;
+	return &d->ent;
+}
+
+int closedir(DIR *d)
+{
+	FindClose(d->hFind);
+	dir_free(d);
+	return 0;
+}
+
+bool FiosIsRoot(const char *file)
+{
+	return file[3] == '\0'; // C:\...
+}
+
+void FiosGetDrives(void)
+{
+	TCHAR drives[256];
+	const TCHAR *s;
+
+	GetLogicalDriveStrings(sizeof(drives), drives);
+	for (s = drives; *s != '\0';) {
+		FiosItem *fios = FiosAlloc();
+		fios->type = FIOS_TYPE_DRIVE;
+		fios->mtime = 0;
+		snprintf(fios->name, lengthof(fios->name),  "%c:", s[0] & 0xFF);
+		ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
+		while (*s++ != '\0');
+	}
+}
+
+bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
+{
+	// hectonanoseconds between Windows and POSIX epoch
+	static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
+	const WIN32_FIND_DATAW *fd = &ent->dir->fd;
+	if (fd->dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) return false;
+
+	sb->st_size  = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
+	/* UTC FILETIME to seconds-since-1970 UTC
+	 * we just have to subtract POSIX epoch and scale down to units of seconds.
+	 * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1&#1860504
+	 * XXX - not entirely correct, since filetimes on FAT aren't UTC but local,
+	 * this won't entirely be correct, but we use the time only for comparsion. */
+	sb->st_mtime = (time_t)((*(uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
+	sb->st_mode  = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
+
+	return true;
+}
+
+bool FiosGetDiskFreeSpace(const char *path, uint32 *tot)
+{
+	UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);  // disable 'no-disk' message box
+	bool retval = false;
+	TCHAR root[4];
+	DWORD spc, bps, nfc, tnc;
+
+	_sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]);
+	if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
+		*tot = ((spc * bps) * (uint64)nfc) >> 20;
+		retval = true;
+	}
+
+	SetErrorMode(sem); // reset previous setting
+	return retval;
+}
+
+static int ParseCommandLine(char *line, char **argv, int max_argc)
+{
+	int n = 0;
+
+	do {
+		// skip whitespace
+		while (*line == ' ' || *line == '\t') line++;
+
+		// end?
+		if (*line == '\0') break;
+
+		// special handling when quoted
+		if (*line == '"') {
+			argv[n++] = ++line;
+			while (*line != '"') {
+				if (*line == '\0') return n;
+				line++;
+			}
+		} else {
+			argv[n++] = line;
+			while (*line != ' ' && *line != '\t') {
+				if (*line == '\0') return n;
+				line++;
+			}
+		}
+		*line++ = '\0';
+	} while (n != max_argc);
+
+	return n;
+}
+
+void CreateConsole(void)
+{
+	HANDLE hand;
+	CONSOLE_SCREEN_BUFFER_INFO coninfo;
+
+	if (_has_console) return;
+	_has_console = true;
+
+	AllocConsole();
+
+	hand = GetStdHandle(STD_OUTPUT_HANDLE);
+	GetConsoleScreenBufferInfo(hand, &coninfo);
+	coninfo.dwSize.Y = 500;
+	SetConsoleScreenBufferSize(hand, coninfo.dwSize);
+
+	// redirect unbuffered STDIN, STDOUT, STDERR to the console
+#if !defined(__CYGWIN__)
+	*stdout = *_fdopen( _open_osfhandle((intptr_t)hand, _O_TEXT), "w" );
+	*stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" );
+	*stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" );
+#else
+	// open_osfhandle is not in cygwin
+	*stdout = *fdopen(1, "w" );
+	*stdin = *fdopen(0, "r" );
+	*stderr = *fdopen(2, "w" );
+#endif
+
+	setvbuf(stdin, NULL, _IONBF, 0);
+	setvbuf(stdout, NULL, _IONBF, 0);
+	setvbuf(stderr, NULL, _IONBF, 0);
+}
+
+void ShowInfo(const char *str)
+{
+	if (_has_console) {
+		fprintf(stderr, str);
+	} else {
+		bool old;
+
+		ReleaseCapture();
+		_left_button_clicked =_left_button_down = false;
+
+		old = MyShowCursor(true);
+		if (MessageBox(GetActiveWindow(), MB_TO_WIDE(str), _T("OpenTTD"), MB_ICONINFORMATION | MB_OKCANCEL) == IDCANCEL) {
+			CreateConsole();
+		}
+		MyShowCursor(old);
+	}
+}
+
+#ifdef __MINGW32__
+	/* _set_error_mode() constants&function (do not exist in mingw headers) */
+	#define _OUT_TO_DEFAULT      0
+	#define _OUT_TO_STDERR       1
+	#define _OUT_TO_MSGBOX       2
+	#define _REPORT_ERRMODE      3
+	int _set_error_mode(int);
+#endif
+
+int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+	LPTSTR lpCmdLine, int nCmdShow)
+{
+	int argc;
+	char *argv[64]; // max 64 command line arguments
+	char *cmdline;
+
+#if defined(UNICODE)
+	/* For UNICODE we need to convert the commandline to char* _AND_
+	 * save it because argv[] points into this buffer and thus needs to
+	 * be available between subsequent calls to FS2OTTD() */
+	char cmdlinebuf[MAX_PATH];
+#endif
+
+	cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf));
+
+#if defined(_DEBUG)
+	CreateConsole();
+#endif
+
+	_set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox
+
+	/* setup random seed to something quite random */
+	_random_seeds[1][0] = _random_seeds[0][0] = GetTickCount();
+	_random_seeds[1][1] = _random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
+	SeedMT(_random_seeds[0][0]);
+
+	argc = ParseCommandLine(cmdline, argv, lengthof(argv));
+
+#if defined(WIN32_EXCEPTION_TRACKER)
+	Win32InitializeExceptions();
+#endif
+
+#if defined(WIN32_EXCEPTION_TRACKER_DEBUG)
+	_try {
+		LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep);
+#endif
+		ttd_main(argc, argv);
+
+#if defined(WIN32_EXCEPTION_TRACKER_DEBUG)
+	} _except (ExceptionHandler(_exception_info())) {}
+#endif
+
+	return 0;
+}
+
+void DeterminePaths(void)
+{
+	char *s, *cfg;
+	wchar_t path[MAX_PATH];
+
+	_paths.personal_dir = _paths.game_data_dir = cfg = malloc(MAX_PATH);
+	GetCurrentDirectoryW(MAX_PATH - 1, path);
+	convert_from_fs(path, cfg, MAX_PATH);
+
+	cfg[0] = toupper(cfg[0]);
+	s = strchr(cfg, '\0');
+	if (s[-1] != '\\') strcpy(s, "\\");
+
+	_paths.save_dir = str_fmt("%ssave", cfg);
+	_paths.autosave_dir = str_fmt("%s\\autosave", _paths.save_dir);
+	_paths.scenario_dir = str_fmt("%sscenario", cfg);
+	_paths.heightmap_dir = str_fmt("%sscenario\\heightmap", cfg);
+	_paths.gm_dir = str_fmt("%sgm\\", cfg);
+	_paths.data_dir = str_fmt("%sdata\\", cfg);
+	_paths.lang_dir = str_fmt("%slang\\", cfg);
+
+	if (_config_file == NULL)
+		_config_file = str_fmt("%sopenttd.cfg", _paths.personal_dir);
+
+	_highscore_file = str_fmt("%shs.dat", _paths.personal_dir);
+	_log_file = str_fmt("%sopenttd.log", _paths.personal_dir);
+
+	// make (auto)save and scenario folder
+	CreateDirectoryW(OTTD2FS(_paths.save_dir), NULL);
+	CreateDirectoryW(OTTD2FS(_paths.autosave_dir), NULL);
+	CreateDirectoryW(OTTD2FS(_paths.scenario_dir), NULL);
+	CreateDirectoryW(OTTD2FS(_paths.heightmap_dir), NULL);
+}
+
+/**
+ * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard
+ * and append this up to the maximum length (either absolute or screenlength). If maxlength
+ * is zero, we don't care about the screenlength but only about the physical length of the string
+ * @param tb @Textbuf type to be changed
+ * @return Return true on successfull change of Textbuf, or false otherwise
+ */
+bool InsertTextBufferClipboard(Textbuf *tb)
+{
+	HGLOBAL cbuf;
+	char utf8_buf[512];
+	const char *ptr;
+
+	WChar c;
+	uint16 width, length;
+
+	if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+		const char *ret;
+
+		OpenClipboard(NULL);
+		cbuf = GetClipboardData(CF_UNICODETEXT);
+
+		ptr = GlobalLock(cbuf);
+		ret = convert_from_fs((wchar_t*)ptr, utf8_buf, lengthof(utf8_buf));
+		GlobalUnlock(cbuf);
+		CloseClipboard();
+
+		if (*ret == '\0') return false;
+	} else if (IsClipboardFormatAvailable(CF_TEXT)) {
+		OpenClipboard(NULL);
+		cbuf = GetClipboardData(CF_TEXT);
+
+		ptr = GlobalLock(cbuf);
+		ttd_strlcpy(utf8_buf, ptr, lengthof(utf8_buf));
+		GlobalUnlock(cbuf);
+		CloseClipboard();
+	} else {
+		return false;
+	}
+
+	width = length = 0;
+
+	for (ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
+		byte charwidth;
+
+		if (!IsPrintable(c)) break;
+		if (tb->length + length >= tb->maxlength - 1) break;
+		charwidth = GetCharacterWidth(FS_NORMAL, c);
+
+		if (tb->maxwidth != 0 && width + tb->width + charwidth > tb->maxwidth) break;
+
+		width += charwidth;
+		length += Utf8CharLen(c);
+	}
+
+	if (length == 0) return false;
+
+	memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
+	memcpy(tb->buf + tb->caretpos, utf8_buf, length);
+	tb->width += width;
+	tb->caretxoffs += width;
+
+	tb->length += length;
+	tb->caretpos += length;
+	tb->buf[tb->length] = '\0'; // terminating zero
+
+	return true;
+}
+
+
+void CSleep(int milliseconds)
+{
+	Sleep(milliseconds);
+}
+
+
+// Utility function to get the current timestamp in milliseconds
+// Useful for profiling
+int64 GetTS(void)
+{
+	static double freq;
+	__int64 value;
+	if (!freq) {
+		QueryPerformanceFrequency((LARGE_INTEGER*)&value);
+		freq = (double)1000000 / value;
+	}
+	QueryPerformanceCounter((LARGE_INTEGER*)&value);
+	return (__int64)(value * freq);
+}
+
+/** Convert from OpenTTD's encoding to that of the local environment in
+ * UNICODE. OpenTTD encoding is UTF8, local is wide-char
+ * @param name pointer to a valid string that will be converted
+ * @param utf16_buf pointer to a valid wide-char buffer that will receive the
+ * converted string
+ * @param buflen length in wide characters of the receiving buffer
+ * @return pointer to utf16_buf. If conversion fails the string is of zero-length */
+wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
+{
+	int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, buflen);
+	if (len == 0) {
+		DEBUG(misc, 0, "[utf8] error converting '%s'. Errno %d", name, GetLastError());
+		utf16_buf[0] = '\0';
+	}
+
+	return utf16_buf;
+}
+
+/** Convert from OpenTTD's encoding to that of the local environment in
+ * UNICODE. OpenTTD encoding is UTF8, local is wide-char.
+ * The returned value's contents can only be guaranteed until the next call to
+ * this function. So if the value is needed for anything else, use convert_from_fs
+ * @param name pointer to a valid string that will be converted
+ * @return pointer to the converted string; if failed string is of zero-length */
+const wchar_t *OTTD2FS(const char *name)
+{
+	static wchar_t utf16_buf[512];
+	return convert_to_fs(name, utf16_buf, lengthof(utf16_buf));
+}
+
+
+/** Convert to OpenTTD's encoding from that of the local environment in
+ * UNICODE. OpenTTD encoding is UTF8, local is wide-char
+ * @param name pointer to a valid string that will be converted
+ * @param utf8_buf pointer to a valid buffer that will receive the converted string
+ * @param buflen length in characters of the receiving buffer
+ * @return pointer to utf8_buf. If conversion fails the string is of zero-length */
+char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
+{
+	int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, buflen, NULL, NULL);
+	if (len == 0) {
+		DEBUG(misc, 0, "[utf8] error converting wide-string. Errno %d", GetLastError());
+		utf8_buf[0] = '\0';
+	}
+
+	return utf8_buf;
+}
+
+/** Convert to OpenTTD's encoding from that of the local environment in
+ * UNICODE. OpenTTD encoding is UTF8, local is wide-char.
+ * The returned value's contents can only be guaranteed until the next call to
+ * this function. So if the value is needed for anything else, use convert_from_fs
+ * @param name pointer to a valid string that will be converted
+ * @return pointer to the converted string; if failed string is of zero-length */
+const char *FS2OTTD(const wchar_t *name)
+{
+	static char utf8_buf[512];
+	return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
+}
+
+/** Our very own SHGetFolderPath function for support of windows operating
+ * systems that don't have this function (eg Win9x, etc.). We try using the
+ * native function, and if that doesn't exist we will try a more crude approach
+ * of environment variables and hope for the best */
+HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
+{
+	static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
+	static bool first_time = true;
+
+	/* We only try to load the library one time; if it fails, it fails */
+	if (first_time) {
+#if defined(UNICODE)
+# define W(x) x "W"
+#else
+# define W(x) x "A"
+#endif
+		if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) {
+			DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from SHFolder.dll");
+		}
+#undef W
+		first_time = false;
+	}
+
+	if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
+
+	/* SHGetFolderPath doesn't exist, try a more conservative approach,
+	 * eg environment variables. This is only included for legacy modes
+	 * MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of
+	 * length MAX_PATH which will receive the path" so let's assume that
+	 * Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0,
+	 * Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0,
+	 * Windows NT 4.0 with Service Pack 4 (SP4) */
+	{
+		DWORD ret;
+		switch (csidl) {
+			case CSIDL_FONTS: /* Get the system font path, eg %WINDIR%\Fonts */
+				ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH);
+				if (ret == 0) break;
+				_tcsncat(pszPath, _T("\\Fonts"), MAX_PATH);
+
+				return (HRESULT)0;
+				break;
+			/* XXX - other types to go here when needed... */
+		}
+	}
+
+	return E_INVALIDARG;
+}
deleted file mode 100644
--- a/src/window.c
+++ /dev/null
@@ -1,2000 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include <stdarg.h>
-#include "openttd.h"
-#include "debug.h"
-#include "functions.h"
-#include "map.h"
-#include "player.h"
-#include "window.h"
-#include "gfx.h"
-#include "viewport.h"
-#include "console.h"
-#include "variables.h"
-#include "table/sprites.h"
-#include "genworld.h"
-
-// delta between mouse cursor and upper left corner of dragged window
-static Point _drag_delta;
-
-static Window _windows[25];
-Window *_z_windows[lengthof(_windows)];
-Window **_last_z_window; ///< always points to the next free space in the z-array
-
-void CDECL SetWindowWidgetsDisabledState(Window *w, bool disab_stat, int widgets, ...)
-{
-	va_list wdg_list;
-
-	va_start(wdg_list, widgets);
-
-	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetDisabledState(w, widgets, disab_stat);
-		widgets = va_arg(wdg_list, int);
-	}
-
-	va_end(wdg_list);
-}
-
-void CDECL SetWindowWidgetsHiddenState(Window *w, bool hidden_stat, int widgets, ...)
-{
-	va_list wdg_list;
-
-	va_start(wdg_list, widgets);
-
-	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetHiddenState(w, widgets, hidden_stat);
-		widgets = va_arg(wdg_list, int);
-	}
-
-	va_end(wdg_list);
-}
-
-void CDECL SetWindowWidgetsLoweredState(Window *w, bool lowered_stat, int widgets, ...)
-{
-	va_list wdg_list;
-
-	va_start(wdg_list, widgets);
-
-	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetLoweredState(w, widgets, lowered_stat);
-		widgets = va_arg(wdg_list, int);
-	}
-
-	va_end(wdg_list);
-}
-
-void RaiseWindowButtons(Window *w)
-{
-	uint i;
-
-	for (i = 0; i < w->widget_count; i++) {
-		if (IsWindowWidgetLowered(w, i)) {
-			RaiseWindowWidget(w, i);
-			InvalidateWidget(w, i);
-		}
-	}
-}
-
-void HandleButtonClick(Window *w, byte widget)
-{
-	LowerWindowWidget(w, widget);
-	w->flags4 |= 5 << WF_TIMEOUT_SHL;
-	InvalidateWidget(w, widget);
-}
-
-
-static void StartWindowDrag(Window *w);
-static void StartWindowSizing(Window *w);
-
-static void DispatchLeftClickEvent(Window *w, int x, int y)
-{
-	WindowEvent e;
-	const Widget *wi;
-
-	e.we.click.pt.x = x;
-	e.we.click.pt.y = y;
-	e.event = WE_CLICK;
-
-	if (w->desc_flags & WDF_DEF_WIDGET) {
-		e.we.click.widget = GetWidgetFromPos(w, x, y);
-		if (e.we.click.widget < 0) return; /* exit if clicked outside of widgets */
-
-		/* don't allow any interaction if the button has been disabled */
-		if (IsWindowWidgetDisabled(w, e.we.click.widget)) return;
-
-		wi = &w->widget[e.we.click.widget];
-
-		if (wi->type & WWB_MASK) {
-			/* special widget handling for buttons*/
-			switch (wi->type) {
-				case WWT_PANEL   | WWB_PUSHBUTTON: /* WWT_PUSHBTN */
-				case WWT_IMGBTN  | WWB_PUSHBUTTON: /* WWT_PUSHIMGBTN */
-				case WWT_TEXTBTN | WWB_PUSHBUTTON: /* WWT_PUSHTXTBTN */
-					HandleButtonClick(w, e.we.click.widget);
-					break;
-			}
-		} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
-			ScrollbarClickHandler(w, wi, e.we.click.pt.x, e.we.click.pt.y);
-		}
-
-		if (w->desc_flags & WDF_STD_BTN) {
-			if (e.we.click.widget == 0) { /* 'X' */
-				DeleteWindow(w);
-				return;
-			}
-
-			if (e.we.click.widget == 1) { /* 'Title bar' */
-				StartWindowDrag(w);
-				return;
-			}
-		}
-
-		if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) {
-			StartWindowSizing(w);
-			InvalidateWidget(w, e.we.click.widget);
-			return;
-		}
-
-		if (w->desc_flags & WDF_STICKY_BUTTON && wi->type == WWT_STICKYBOX) {
-			w->flags4 ^= WF_STICKY;
-			InvalidateWidget(w, e.we.click.widget);
-			return;
-		}
-	}
-
-	w->wndproc(w, &e);
-}
-
-static void DispatchRightClickEvent(Window *w, int x, int y)
-{
-	WindowEvent e;
-
-	/* default tooltips handler? */
-	if (w->desc_flags & WDF_STD_TOOLTIPS) {
-		e.we.click.widget = GetWidgetFromPos(w, x, y);
-		if (e.we.click.widget < 0)
-			return; /* exit if clicked outside of widgets */
-
-		if (w->widget[e.we.click.widget].tooltips != 0) {
-			GuiShowTooltips(w->widget[e.we.click.widget].tooltips);
-			return;
-		}
-	}
-
-	e.event = WE_RCLICK;
-	e.we.click.pt.x = x;
-	e.we.click.pt.y = y;
-	w->wndproc(w, &e);
-}
-
-/** Dispatch the mousewheel-action to the window which will scroll any
- * compatible scrollbars if the mouse is pointed over the bar or its contents
- * @param *w Window
- * @param widget the widget where the scrollwheel was used
- * @param wheel scroll up or down
- */
-static void DispatchMouseWheelEvent(Window *w, int widget, int wheel)
-{
-	const Widget *wi1, *wi2;
-	Scrollbar *sb;
-
-	if (widget < 0) return;
-
-	wi1 = &w->widget[widget];
-	wi2 = &w->widget[widget + 1];
-
-	/* The listbox can only scroll if scrolling was done on the scrollbar itself,
-	 * or on the listbox (and the next item is (must be) the scrollbar)
-	 * XXX - should be rewritten as a widget-dependent scroller but that's
-	 * not happening until someone rewrites the whole widget-code */
-	if ((sb = &w->vscroll,  wi1->type == WWT_SCROLLBAR)  || (sb = &w->vscroll2, wi1->type == WWT_SCROLL2BAR)  ||
-			(sb = &w->vscroll2, wi2->type == WWT_SCROLL2BAR) || (sb = &w->vscroll, wi2->type == WWT_SCROLLBAR) ) {
-
-		if (sb->count > sb->cap) {
-			int pos = clamp(sb->pos + wheel, 0, sb->count - sb->cap);
-			if (pos != sb->pos) {
-				sb->pos = pos;
-				SetWindowDirty(w);
-			}
-		}
-	}
-}
-
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom);
-
-void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
-{
-	Window* const *wz;
-	DrawPixelInfo bk;
-	_cur_dpi = &bk;
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (right > w->left &&
-				bottom > w->top &&
-				left < w->left + w->width &&
-				top < w->top + w->height) {
-			DrawOverlappedWindow(wz, left, top, right, bottom);
-		}
-	}
-}
-
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom)
-{
-	Window* const *vz = wz;
-	int x;
-
-	while (++vz != _last_z_window) {
-		const Window *v = *vz;
-
-		if (right > v->left &&
-				bottom > v->top &&
-				left < v->left + v->width &&
-				top < v->top + v->height) {
-			if (left < (x=v->left)) {
-				DrawOverlappedWindow(wz, left, top, x, bottom);
-				DrawOverlappedWindow(wz, x, top, right, bottom);
-				return;
-			}
-
-			if (right > (x=v->left + v->width)) {
-				DrawOverlappedWindow(wz, left, top, x, bottom);
-				DrawOverlappedWindow(wz, x, top, right, bottom);
-				return;
-			}
-
-			if (top < (x=v->top)) {
-				DrawOverlappedWindow(wz, left, top, right, x);
-				DrawOverlappedWindow(wz, left, x, right, bottom);
-				return;
-			}
-
-			if (bottom > (x=v->top + v->height)) {
-				DrawOverlappedWindow(wz, left, top, right, x);
-				DrawOverlappedWindow(wz, left, x, right, bottom);
-				return;
-			}
-
-			return;
-		}
-	}
-
-	{
-		DrawPixelInfo *dp = _cur_dpi;
-		dp->width = right - left;
-		dp->height = bottom - top;
-		dp->left = left - (*wz)->left;
-		dp->top = top - (*wz)->top;
-		dp->pitch = _screen.pitch;
-		dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left;
-		dp->zoom = 0;
-		CallWindowEventNP(*wz, WE_PAINT);
-	}
-}
-
-void CallWindowEventNP(Window *w, int event)
-{
-	WindowEvent e;
-
-	e.event = event;
-	w->wndproc(w, &e);
-}
-
-void SetWindowDirty(const Window *w)
-{
-	if (w == NULL) return;
-	SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
-}
-
-/** Find the Window whose parent pointer points to this window
- * @parent w Window to find child of
- * @return return a Window pointer that is the child of w, or NULL otherwise */
-static Window *FindChildWindow(const Window *w)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *v = *wz;
-		if (v->parent == w) return v;
-	}
-
-	return NULL;
-}
-
-/** Find the z-value of a window. A window must already be open
- * or the behaviour is undefined but function should never fail */
-Window **FindWindowZPosition(const Window *w)
-{
-	Window **wz;
-
-	for (wz = _z_windows; wz != _last_z_window; wz++) {
-		if (*wz == w) return wz;
-	}
-
-	DEBUG(misc, 3, "Window (class %d, number %d) is not open, probably removed by recursive calls",
-		w->window_class, w->window_number);
-	return NULL;
-}
-
-void DeleteWindow(Window *w)
-{
-	Window *v;
-	Window **wz;
-	if (w == NULL) return;
-
-	/* Delete any children a window might have in a head-recursive manner */
-	v = FindChildWindow(w);
-	if (v != NULL) DeleteWindow(v);
-
-	if (_thd.place_mode != VHM_NONE &&
-			_thd.window_class == w->window_class &&
-			_thd.window_number == w->window_number) {
-		ResetObjectToPlace();
-	}
-
-	CallWindowEventNP(w, WE_DESTROY);
-	if (w->viewport != NULL) DeleteWindowViewport(w);
-
-	SetWindowDirty(w);
-	free(w->widget);
-	w->widget = NULL;
-	w->widget_count = 0;
-	w->parent = NULL;
-
-	/* Find the window in the z-array, and effectively remove it
-	 * by moving all windows after it one to the left */
-	wz = FindWindowZPosition(w);
-	if (wz == NULL) return;
-	memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
-	_last_z_window--;
-}
-
-Window *FindWindowById(WindowClass cls, WindowNumber number)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) return w;
-	}
-
-	return NULL;
-}
-
-void DeleteWindowById(WindowClass cls, WindowNumber number)
-{
-	DeleteWindow(FindWindowById(cls, number));
-}
-
-void DeleteWindowByClass(WindowClass cls)
-{
-	Window* const *wz;
-
-restart_search:
-	/* When we find the window to delete, we need to restart the search
-	 * as deleting this window could cascade in deleting (many) others
-	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == cls) {
-			DeleteWindow(w);
-			goto restart_search;
-		}
-	}
-}
-
-/** Delete all windows of a player. We identify windows of a player
- * by looking at the caption colour. If it is equal to the player ID
- * then we say the window belongs to the player and should be deleted
- * @param id PlayerID player identifier */
-void DeletePlayerWindows(PlayerID id)
-{
-	Window* const *wz;
-
-restart_search:
-	/* When we find the window to delete, we need to restart the search
-	 * as deleting this window could cascade in deleting (many) others
-	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->caption_color == id) {
-			DeleteWindow(w);
-			goto restart_search;
-		}
-	}
-
-	/* Also delete the player specific windows, that don't have a player-colour */
-	DeleteWindowById(WC_BUY_COMPANY, id);
-}
-
-/** Change the owner of all the windows one player can take over from another
- * player in the case of a company merger. Do not change ownership of windows
- * that need to be deleted once takeover is complete
- * @param old_player PlayerID of original owner of the window
- * @param new_player PlayerID of the new owner of the window */
-void ChangeWindowOwner(PlayerID old_player, PlayerID new_player)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		if (w->caption_color != old_player)      continue;
-		if (w->window_class == WC_PLAYER_COLOR)  continue;
-		if (w->window_class == WC_FINANCES)      continue;
-		if (w->window_class == WC_STATION_LIST)  continue;
-		if (w->window_class == WC_TRAINS_LIST)   continue;
-		if (w->window_class == WC_ROADVEH_LIST)  continue;
-		if (w->window_class == WC_SHIPS_LIST)    continue;
-		if (w->window_class == WC_AIRCRAFT_LIST) continue;
-		if (w->window_class == WC_BUY_COMPANY)   continue;
-		if (w->window_class == WC_COMPANY)       continue;
-
-		w->caption_color = new_player;
-	}
-}
-
-static void BringWindowToFront(const Window *w);
-
-/** Find a window and make it the top-window on the screen. The window
- * gets a white border for a brief period of time to visualize its
- * "activation"
- * @return a pointer to the window thus activated */
-Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
-{
-	Window *w = FindWindowById(cls, number);
-
-	if (w != NULL) {
-		w->flags4 |= WF_WHITE_BORDER_MASK;
-		BringWindowToFront(w);
-		SetWindowDirty(w);
-	}
-
-	return w;
-}
-
-static inline bool IsVitalWindow(const Window *w)
-{
-	WindowClass wc = w->window_class;
-	return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
-}
-
-/** On clicking on a window, make it the frontmost window of all. However
- * there are certain windows that always need to be on-top; these include
- * - Toolbar, Statusbar (always on)
- * - New window, Chatbar (only if open)
- * The window is marked dirty for a repaint if the window is actually moved
- * @param w window that is put into the foreground
- * @return pointer to the window, the same as the input pointer
- */
-static void BringWindowToFront(const Window *w)
-{
-	Window *tempz;
-	Window **wz = FindWindowZPosition(w);
-	Window **vz = _last_z_window;
-
-	/* Bring the window just below the vital windows */
-	do {
-		if (--vz < _z_windows) return;
-	} while (IsVitalWindow(*vz));
-
-	if (wz == vz) return; // window is already in the right position
-	assert(wz < vz);
-
-	tempz = *wz;
-	memmove(wz, wz + 1, (byte*)vz - (byte*)wz);
-	*vz = tempz;
-
-	SetWindowDirty(w);
-}
-
-/** We have run out of windows, so find a suitable candidate for replacement.
- * Keep all important windows intact. These are
- * - Main window (gamefield), Toolbar, Statusbar (always on)
- * - News window, Chatbar (when on)
- * - Any sticked windows since we wanted to keep these
- * @return w pointer to the window that is going to be deleted
- */
-static Window *FindDeletableWindow(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
-			return w;
-		}
-	}
-	return NULL;
-}
-
-/** A window must be freed, and all are marked as important windows. Ease the
- * restriction a bit by allowing to delete sticky windows. Keep important/vital
- * windows intact (Main window, Toolbar, Statusbar, News Window, Chatbar)
- * Start finding an appropiate candidate from the lowest z-values (bottom)
- * @see FindDeletableWindow()
- * @return w Pointer to the window that is being deleted
- */
-static Window *ForceFindDeletableWindow(void)
-{
-	Window* const *wz;
-
-	for (wz = _z_windows;; wz++) {
-		Window *w = *wz;
-		assert(wz < _last_z_window);
-		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
-	}
-}
-
-bool IsWindowOfPrototype(const Window *w, const Widget *widget)
-{
-	return (w->original_widget == widget);
-}
-
-/* Copies 'widget' to 'w->widget' to allow for resizable windows */
-void AssignWidgetToWindow(Window *w, const Widget *widget)
-{
-	w->original_widget = widget;
-
-	if (widget != NULL) {
-		uint index = 1;
-		const Widget *wi;
-
-		for (wi = widget; wi->type != WWT_LAST; wi++) index++;
-
-		w->widget = realloc(w->widget, sizeof(*w->widget) * index);
-		memcpy(w->widget, widget, sizeof(*w->widget) * index);
-		w->widget_count = index - 1;
-	} else {
-		w->widget = NULL;
-		w->widget_count = 0;
-	}
-}
-
-static Window *FindFreeWindow(void)
-{
-	Window *w;
-
-	for (w = _windows; w < endof(_windows); w++) {
-		Window* const *wz;
-		bool window_in_use = false;
-
-		FOR_ALL_WINDOWS(wz) {
-			if (*wz == w) {
-				window_in_use = true;
-				break;
-			}
-		}
-
-		if (!window_in_use) return w;
-	}
-
-	assert(_last_z_window == endof(_z_windows));
-	return NULL;
-}
-
-/* Open a new window.
- * This function is called from AllocateWindow() or AllocateWindowDesc()
- * See descriptions for those functions for usage
- * See AllocateWindow() for description of arguments.
- * Only addition here is window_number, which is the window_number being assigned to the new window
- */
-static Window *LocalAllocateWindow(
-							int x, int y, int width, int height,
-							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
-{
-	Window *w = FindFreeWindow();
-
-	/* We have run out of windows, close one and use that as the place for our new one */
-	if (w == NULL) {
-		w = FindDeletableWindow();
-		if (w == NULL) w = ForceFindDeletableWindow();
-		DeleteWindow(w);
-	}
-
-	// Set up window properties
-	memset(w, 0, sizeof(*w));
-	w->window_class = cls;
-	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
-	w->caption_color = 0xFF;
-	w->left = x;
-	w->top = y;
-	w->width = width;
-	w->height = height;
-	w->wndproc = proc;
-	AssignWidgetToWindow(w, widget);
-	w->resize.width = width;
-	w->resize.height = height;
-	w->resize.step_width = 1;
-	w->resize.step_height = 1;
-	w->window_number = window_number;
-
-	{
-		Window **wz = _last_z_window;
-
-		/* Hacky way of specifying always-on-top windows. These windows are
-		 * always above other windows because they are moved below them.
-		 * status-bar is above news-window because it has been created earlier.
-		 * Also, as the chat-window is excluded from this, it will always be
-		 * the last window, thus always on top.
-		 * XXX - Yes, ugly, probably needs something like w->always_on_top flag
-		 * to implement correctly, but even then you need some kind of distinction
-		 * between on-top of chat/news and status windows, because these conflict */
-		if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
-			if (FindWindowById(WC_MAIN_TOOLBAR, 0)     != NULL) wz--;
-			if (FindWindowById(WC_STATUS_BAR, 0)       != NULL) wz--;
-			if (FindWindowById(WC_NEWS_WINDOW, 0)      != NULL) wz--;
-			if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
-
-			assert(wz >= _z_windows);
-			if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
-		}
-
-		*wz = w;
-		_last_z_window++;
-	}
-
-	SetWindowDirty(w);
-	CallWindowEventNP(w, WE_CREATE);
-
-	return w;
-}
-
-/**
- * Open a new window. If there is no space for a new window, close an open
- * window. Try to avoid stickied windows, but if there is no else, close one of
- * those as well. Then make sure all created windows are below some always-on-top
- * ones. Finally set all variables and call the WE_CREATE event
- * @param x offset in pixels from the left of the screen
- * @param y offset in pixels from the top of the screen
- * @param width width in pixels of the window
- * @param height height in pixels of the window
- * @param *proc @see WindowProc function to call when any messages/updates happen to the window
- * @param cls @see WindowClass class of the window, used for identification and grouping
- * @param *widget @see Widget pointer to the window layout and various elements
- * @return @see Window pointer of the newly created window
- */
-Window *AllocateWindow(
-							int x, int y, int width, int height,
-							WindowProc *proc, WindowClass cls, const Widget *widget)
-{
-	return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
-}
-
-typedef struct SizeRect {
-	int left,top,width,height;
-} SizeRect;
-
-
-static SizeRect _awap_r;
-
-static bool IsGoodAutoPlace1(int left, int top)
-{
-	int right,bottom;
-	Window* const *wz;
-
-	_awap_r.left= left;
-	_awap_r.top = top;
-	right = _awap_r.width + left;
-	bottom = _awap_r.height + top;
-
-	if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height)
-		return false;
-
-	// Make sure it is not obscured by any window.
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == WC_MAIN_WINDOW) continue;
-
-		if (right > w->left &&
-				w->left + w->width > left &&
-				bottom > w->top &&
-				w->top + w->height > top) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static bool IsGoodAutoPlace2(int left, int top)
-{
-	int width,height;
-	Window* const *wz;
-
-	_awap_r.left= left;
-	_awap_r.top = top;
-	width = _awap_r.width;
-	height = _awap_r.height;
-
-	if (left < -(width>>2) || left > _screen.width - (width>>1)) return false;
-	if (top < 22 || top > _screen.height - (height>>2)) return false;
-
-	// Make sure it is not obscured by any window.
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == WC_MAIN_WINDOW) continue;
-
-		if (left + width > w->left &&
-				w->left + w->width > left &&
-				top + height > w->top &&
-				w->top + w->height > top) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static Point GetAutoPlacePosition(int width, int height)
-{
-	Window* const *wz;
-	Point pt;
-
-	_awap_r.width = width;
-	_awap_r.height = height;
-
-	if (IsGoodAutoPlace1(0, 24)) goto ok_pos;
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == WC_MAIN_WINDOW) continue;
-
-		if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left-   width-2,w->top)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left,w->top+w->height+2)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left,w->top-   height-2)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left+w->width+2,w->top+w->height-height)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left-   width-2,w->top+w->height-height)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left+w->width-width,w->top+w->height+2)) goto ok_pos;
-		if (IsGoodAutoPlace1(w->left+w->width-width,w->top-   height-2)) goto ok_pos;
-	}
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == WC_MAIN_WINDOW) continue;
-
-		if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos;
-		if (IsGoodAutoPlace2(w->left-   width-2,w->top)) goto ok_pos;
-		if (IsGoodAutoPlace2(w->left,w->top+w->height+2)) goto ok_pos;
-		if (IsGoodAutoPlace2(w->left,w->top-   height-2)) goto ok_pos;
-	}
-
-	{
-		int left=0,top=24;
-
-restart:;
-		FOR_ALL_WINDOWS(wz) {
-			const Window *w = *wz;
-
-			if (w->left == left && w->top == top) {
-				left += 5;
-				top += 5;
-				goto restart;
-			}
-		}
-
-		pt.x = left;
-		pt.y = top;
-		return pt;
-	}
-
-ok_pos:;
-	pt.x = _awap_r.left;
-	pt.y = _awap_r.top;
-	return pt;
-}
-
-static Window *LocalAllocateWindowDesc(const WindowDesc *desc, int window_number)
-{
-	Point pt;
-	Window *w;
-
-	/* By default position a child window at an offset of 10/10 of its parent.
-	 * However if it falls too extremely outside window positions, reposition
-	 * it to an automatic place */
-	if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ &&
-			(w = FindWindowById(desc->parent_cls, window_number)) != NULL &&
-			w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) {
-
-		pt.x = w->left + 10;
-		if (pt.x > _screen.width + 10 - desc->width) {
-			pt.x = (_screen.width + 10 - desc->width) - 20;
-		}
-		pt.y = w->top + 10;
-	} else {
-		switch (desc->left) {
-			case WDP_ALIGN_TBR: { /* Align the right side with the top toolbar */
-				w = FindWindowById(WC_MAIN_TOOLBAR, 0);
-				pt.x = (w->left + w->width) - desc->width;
-			}	break;
-			case WDP_ALIGN_TBL: /* Align the left side with the top toolbar */
-				pt.x = FindWindowById(WC_MAIN_TOOLBAR, 0)->left;
-				break;
-			case WDP_AUTO: /* Find a good automatic position for the window */
-				pt = GetAutoPlacePosition(desc->width, desc->height);
-				goto allocate_window;
-			case WDP_CENTER: /* Centre the window horizontally */
-				pt.x = (_screen.width - desc->width) / 2;
-				break;
-			default:
-				pt.x = desc->left;
-				if (pt.x < 0) pt.x += _screen.width; // negative is from right of the screen
-		}
-
-		switch (desc->top) {
-			case WDP_CENTER: /* Centre the window vertically */
-				pt.y = (_screen.height - desc->height) / 2;
-				break;
-			/* WDP_AUTO sets the position at once and is controlled by desc->left.
-			 * Both left and top must be set to WDP_AUTO */
-			case WDP_AUTO:
-				NOT_REACHED();
-				assert(desc->left == WDP_AUTO && desc->top != WDP_AUTO);
-				/* fallthrough */
-			default:
-				pt.y = desc->top;
-				if (pt.y < 0) pt.y += _screen.height; // negative is from bottom of the screen
-				break;
-		}
-	}
-
-allocate_window:
-	w = LocalAllocateWindow(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
-	w->desc_flags = desc->flags;
-	return w;
-}
-
-/**
- * Open a new window.
- * @param *desc The pointer to the WindowDesc to be created
- * @return @see Window pointer of the newly created window
- */
-Window *AllocateWindowDesc(const WindowDesc *desc)
-{
-	return LocalAllocateWindowDesc(desc, 0);
-}
-
-/**
- * Open a new window.
- * @param *desc The pointer to the WindowDesc to be created
- * @param window_number the window number of the new window
- * @return @see Window pointer of the newly created window
- */
-Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
-{
-	Window *w;
-
-	if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
-	w = LocalAllocateWindowDesc(desc, window_number);
-	return w;
-}
-
-/** Do a search for a window at specific coordinates. For this we start
- * at the topmost window, obviously and work our way down to the bottom
- * @return a pointer to the found window if any, NULL otherwise */
-Window *FindWindowFromPt(int x, int y)
-{
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
-		if (IS_INSIDE_1D(x, w->left, w->width) && IS_INSIDE_1D(y, w->top, w->height)) {
-			return w;
-		}
-	}
-
-	return NULL;
-}
-
-void InitWindowSystem(void)
-{
-	IConsoleClose();
-
-	memset(&_windows, 0, sizeof(_windows));
-	_last_z_window = _z_windows;
-	InitViewports();
-	_no_scroll = 0;
-}
-
-void UnInitWindowSystem(void)
-{
-	Window **wz;
-	/* Delete all malloced widgets, and reset z-array */
-	FOR_ALL_WINDOWS(wz) {
-		free((*wz)->widget);
-		(*wz)->widget = NULL;
-		(*wz)->widget_count = 0;
-		*wz = NULL;
-	}
-	_last_z_window = _z_windows;
-}
-
-void ResetWindowSystem(void)
-{
-	UnInitWindowSystem();
-	InitWindowSystem();
-	_thd.pos.x = 0;
-	_thd.pos.y = 0;
-	_thd.new_pos.x = 0;
-	_thd.new_pos.y = 0;
-}
-
-static void DecreaseWindowCounters(void)
-{
-	Window *w;
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		w = *--wz;
-		// Unclick scrollbar buttons if they are pressed.
-		if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
-			w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
-			SetWindowDirty(w);
-		}
-		CallWindowEventNP(w, WE_MOUSELOOP);
-	}
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		w = *--wz;
-
-		if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) {
-			CallWindowEventNP(w, WE_TIMEOUT);
-			if (w->desc_flags & WDF_UNCLICK_BUTTONS) RaiseWindowButtons(w);
-		}
-	}
-}
-
-Window *GetCallbackWnd(void)
-{
-	return FindWindowById(_thd.window_class, _thd.window_number);
-}
-
-static void HandlePlacePresize(void)
-{
-	Window *w;
-	WindowEvent e;
-
-	if (_special_mouse_mode != WSM_PRESIZE) return;
-
-	w = GetCallbackWnd();
-	if (w == NULL) return;
-
-	e.we.place.pt = GetTileBelowCursor();
-	if (e.we.place.pt.x == -1) {
-		_thd.selend.x = -1;
-		return;
-	}
-	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
-	e.event = WE_PLACE_PRESIZE;
-	w->wndproc(w, &e);
-}
-
-static bool HandleDragDrop(void)
-{
-	Window *w;
-	WindowEvent e;
-
-	if (_special_mouse_mode != WSM_DRAGDROP) return true;
-
-	if (_left_button_down) return false;
-
-	w = GetCallbackWnd();
-
-	ResetObjectToPlace();
-
-	if (w != NULL) {
-		// send an event in client coordinates.
-		e.event = WE_DRAGDROP;
-		e.we.dragdrop.pt.x = _cursor.pos.x - w->left;
-		e.we.dragdrop.pt.y = _cursor.pos.y - w->top;
-		e.we.dragdrop.widget = GetWidgetFromPos(w, e.we.dragdrop.pt.x, e.we.dragdrop.pt.y);
-		w->wndproc(w, &e);
-	}
-	return false;
-}
-
-static bool HandlePopupMenu(void)
-{
-	Window *w;
-	WindowEvent e;
-
-	if (!_popup_menu_active) return true;
-
-	w = FindWindowById(WC_TOOLBAR_MENU, 0);
-	if (w == NULL) {
-		_popup_menu_active = false;
-		return false;
-	}
-
-	if (_left_button_down) {
-		e.event = WE_POPUPMENU_OVER;
-		e.we.popupmenu.pt = _cursor.pos;
-	} else {
-		_popup_menu_active = false;
-		e.event = WE_POPUPMENU_SELECT;
-		e.we.popupmenu.pt = _cursor.pos;
-	}
-
-	w->wndproc(w, &e);
-
-	return false;
-}
-
-static bool HandleMouseOver(void)
-{
-	Window *w;
-	WindowEvent e;
-	static Window *last_w = NULL;
-
-	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
-
-	// We changed window, put a MOUSEOVER event to the last window
-	if (last_w != NULL && last_w != w) {
-		e.event = WE_MOUSEOVER;
-		e.we.mouseover.pt.x = -1;
-		e.we.mouseover.pt.y = -1;
-		if (last_w->wndproc) last_w->wndproc(last_w, &e);
-	}
-	last_w = w;
-
-	if (w != NULL) {
-		// send an event in client coordinates.
-		e.event = WE_MOUSEOVER;
-		e.we.mouseover.pt.x = _cursor.pos.x - w->left;
-		e.we.mouseover.pt.y = _cursor.pos.y - w->top;
-		if (w->widget != NULL) {
-			e.we.mouseover.widget = GetWidgetFromPos(w, e.we.mouseover.pt.x, e.we.mouseover.pt.y);
-		}
-		w->wndproc(w, &e);
-	}
-
-	// Mouseover never stops execution
-	return true;
-}
-
-/** Update all the widgets of a window based on their resize flags
- * Both the areas of the old window and the new sized window are set dirty
- * ensuring proper redrawal.
- * @param w Window to resize
- * @param x delta x-size of changed window (positive if larger, etc.(
- * @param y delta y-size of changed window */
-void ResizeWindow(Window *w, int x, int y)
-{
-	Widget *wi;
-	bool resize_height = false;
-	bool resize_width = false;
-
-	if (x == 0 && y == 0) return;
-
-	SetWindowDirty(w);
-	for (wi = w->widget; wi->type != WWT_LAST; wi++) {
-		/* Isolate the resizing flags */
-		byte rsizeflag = GB(wi->display_flags, 0, 4);
-
-		if (rsizeflag == RESIZE_NONE) continue;
-
-		/* Resize the widget based on its resize-flag */
-		if (rsizeflag & RESIZE_LEFT) {
-			wi->left += x;
-			resize_width = true;
-		}
-
-		if (rsizeflag & RESIZE_RIGHT) {
-			wi->right += x;
-			resize_width = true;
-		}
-
-		if (rsizeflag & RESIZE_TOP) {
-			wi->top += y;
-			resize_height = true;
-		}
-
-		if (rsizeflag & RESIZE_BOTTOM) {
-			wi->bottom += y;
-			resize_height = true;
-		}
-	}
-
-	/* We resized at least 1 widget, so let's resize the window totally */
-	if (resize_width)  w->width  += x;
-	if (resize_height) w->height += y;
-
-	SetWindowDirty(w);
-}
-
-static bool _dragging_window;
-
-static bool HandleWindowDragging(void)
-{
-	Window* const *wz;
-	// Get out immediately if no window is being dragged at all.
-	if (!_dragging_window) return true;
-
-	// Otherwise find the window...
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		if (w->flags4 & WF_DRAGGING) {
-			const Widget *t = &w->widget[1]; // the title bar ... ugh
-			const Window *v;
-			int x;
-			int y;
-			int nx;
-			int ny;
-
-			// Stop the dragging if the left mouse button was released
-			if (!_left_button_down) {
-				w->flags4 &= ~WF_DRAGGING;
-				break;
-			}
-
-			SetWindowDirty(w);
-
-			x = _cursor.pos.x + _drag_delta.x;
-			y = _cursor.pos.y + _drag_delta.y;
-			nx = x;
-			ny = y;
-
-			if (_patches.window_snap_radius != 0) {
-				Window* const *vz;
-
-				int hsnap = _patches.window_snap_radius;
-				int vsnap = _patches.window_snap_radius;
-				int delta;
-
-				FOR_ALL_WINDOWS(vz) {
-					const Window *v = *vz;
-
-					if (v == w) continue; // Don't snap at yourself
-
-					if (y + w->height > v->top && y < v->top + v->height) {
-						// Your left border <-> other right border
-						delta = abs(v->left + v->width - x);
-						if (delta <= hsnap) {
-							nx = v->left + v->width;
-							hsnap = delta;
-						}
-
-						// Your right border <-> other left border
-						delta = abs(v->left - x - w->width);
-						if (delta <= hsnap) {
-							nx = v->left - w->width;
-							hsnap = delta;
-						}
-					}
-
-					if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
-						// Your left border <-> other left border
-						delta = abs(v->left - x);
-						if (delta <= hsnap) {
-							nx = v->left;
-							hsnap = delta;
-						}
-
-						// Your right border <-> other right border
-						delta = abs(v->left + v->width - x - w->width);
-						if (delta <= hsnap) {
-							nx = v->left + v->width - w->width;
-							hsnap = delta;
-						}
-					}
-
-					if (x + w->width > v->left && x < v->left + v->width) {
-						// Your top border <-> other bottom border
-						delta = abs(v->top + v->height - y);
-						if (delta <= vsnap) {
-							ny = v->top + v->height;
-							vsnap = delta;
-						}
-
-						// Your bottom border <-> other top border
-						delta = abs(v->top - y - w->height);
-						if (delta <= vsnap) {
-							ny = v->top - w->height;
-							vsnap = delta;
-						}
-					}
-
-					if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
-						// Your top border <-> other top border
-						delta = abs(v->top - y);
-						if (delta <= vsnap) {
-							ny = v->top;
-							vsnap = delta;
-						}
-
-						// Your bottom border <-> other bottom border
-						delta = abs(v->top + v->height - y - w->height);
-						if (delta <= vsnap) {
-							ny = v->top + v->height - w->height;
-							vsnap = delta;
-						}
-					}
-				}
-			}
-
-			// Make sure the window doesn't leave the screen
-			// 13 is the height of the title bar
-			nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
-			ny = clamp(ny, 0, _screen.height - 13);
-
-			// Make sure the title bar isn't hidden by behind the main tool bar
-			v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-			if (v != NULL) {
-				int v_bottom = v->top + v->height;
-				int v_right = v->left + v->width;
-				if (ny + t->top >= v->top && ny + t->top < v_bottom) {
-					if ((v->left < 13 && nx + t->left < v->left) ||
-							(v_right > _screen.width - 13 && nx + t->right > v_right)) {
-						ny = v_bottom;
-					} else {
-						if (nx + t->left > v->left - 13 &&
-								nx + t->right < v_right + 13) {
-							if (w->top >= v_bottom) {
-								ny = v_bottom;
-							} else if (w->left < nx) {
-								nx = v->left - 13 - t->left;
-							} else {
-								nx = v_right + 13 - t->right;
-							}
-						}
-					}
-				}
-			}
-
-			if (w->viewport != NULL) {
-				w->viewport->left += nx - w->left;
-				w->viewport->top  += ny - w->top;
-			}
-			w->left = nx;
-			w->top  = ny;
-
-			SetWindowDirty(w);
-			return false;
-		} else if (w->flags4 & WF_SIZING) {
-			WindowEvent e;
-			int x, y;
-
-			/* Stop the sizing if the left mouse button was released */
-			if (!_left_button_down) {
-				w->flags4 &= ~WF_SIZING;
-				SetWindowDirty(w);
-				break;
-			}
-
-			x = _cursor.pos.x - _drag_delta.x;
-			y = _cursor.pos.y - _drag_delta.y;
-
-			/* X and Y has to go by step.. calculate it.
-			 * The cast to int is necessary else x/y are implicitly casted to
-			 * unsigned int, which won't work. */
-			if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
-
-			if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
-
-			/* Check if we don't go below the minimum set size */
-			if ((int)w->width + x < (int)w->resize.width)
-				x = w->resize.width - w->width;
-			if ((int)w->height + y < (int)w->resize.height)
-				y = w->resize.height - w->height;
-
-			/* Window already on size */
-			if (x == 0 && y == 0) return false;
-
-			/* Now find the new cursor pos.. this is NOT _cursor, because
-			    we move in steps. */
-			_drag_delta.x += x;
-			_drag_delta.y += y;
-
-			/* ResizeWindow sets both pre- and after-size to dirty for redrawal */
-			ResizeWindow(w, x, y);
-
-			e.event = WE_RESIZE;
-			e.we.sizing.size.x = x + w->width;
-			e.we.sizing.size.y = y + w->height;
-			e.we.sizing.diff.x = x;
-			e.we.sizing.diff.y = y;
-			w->wndproc(w, &e);
-			return false;
-		}
-	}
-
-	_dragging_window = false;
-	return false;
-}
-
-static void StartWindowDrag(Window *w)
-{
-	w->flags4 |= WF_DRAGGING;
-	_dragging_window = true;
-
-	_drag_delta.x = w->left - _cursor.pos.x;
-	_drag_delta.y = w->top  - _cursor.pos.y;
-
-	BringWindowToFront(w);
-	DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-static void StartWindowSizing(Window *w)
-{
-	w->flags4 |= WF_SIZING;
-	_dragging_window = true;
-
-	_drag_delta.x = _cursor.pos.x;
-	_drag_delta.y = _cursor.pos.y;
-
-	BringWindowToFront(w);
-	DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-
-static bool HandleScrollbarScrolling(void)
-{
-	Window* const *wz;
-	int i;
-	int pos;
-	Scrollbar *sb;
-
-	// Get out quickly if no item is being scrolled
-	if (!_scrolling_scrollbar) return true;
-
-	// Find the scrolling window
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		if (w->flags4 & WF_SCROLL_MIDDLE) {
-			// Abort if no button is clicked any more.
-			if (!_left_button_down) {
-				w->flags4 &= ~WF_SCROLL_MIDDLE;
-				SetWindowDirty(w);
-				break;
-			}
-
-			if (w->flags4 & WF_HSCROLL) {
-				sb = &w->hscroll;
-				i = _cursor.pos.x - _cursorpos_drag_start.x;
-			} else if (w->flags4 & WF_SCROLL2){
-				sb = &w->vscroll2;
-				i = _cursor.pos.y - _cursorpos_drag_start.y;
-			} else {
-				sb = &w->vscroll;
-				i = _cursor.pos.y - _cursorpos_drag_start.y;
-			}
-
-			// Find the item we want to move to and make sure it's inside bounds.
-			pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
-			if (pos != sb->pos) {
-				sb->pos = pos;
-				SetWindowDirty(w);
-			}
-			return false;
-		}
-	}
-
-	_scrolling_scrollbar = false;
-	return false;
-}
-
-static bool HandleViewportScroll(void)
-{
-	WindowEvent e;
-	Window *w;
-
-	if (!_scrolling_viewport) return true;
-
-	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
-
-	if (!_right_button_down || w == NULL) {
-		_cursor.fix_at = false;
-		_scrolling_viewport = false;
-		return true;
-	}
-
-	if (_patches.reverse_scroll) {
-		e.we.scroll.delta.x = -_cursor.delta.x;
-		e.we.scroll.delta.y = -_cursor.delta.y;
-	} else {
-		e.we.scroll.delta.x = _cursor.delta.x;
-		e.we.scroll.delta.y = _cursor.delta.y;
-	}
-
-	/* Create a scroll-event and send it to the window */
-	e.event = WE_SCROLL;
-	w->wndproc(w, &e);
-
-	_cursor.delta.x = 0;
-	_cursor.delta.y = 0;
-	return false;
-}
-
-/** Check if a window can be made top-most window, and if so do
- * it. If a window does not obscure any other windows, it will not
- * be brought to the foreground. Also if the only obscuring windows
- * are so-called system-windows, the window will not be moved.
- * The function will return false when a child window of this window is a
- * modal-popup; function returns a false and child window gets a white border
- * @param w Window to bring on-top
- * @return false if the window has an active modal child, true otherwise */
-static bool MaybeBringWindowToFront(const Window *w)
-{
-	bool bring_to_front = false;
-	Window* const *wz;
-	Window* const *uz;
-
-	if (w->window_class == WC_MAIN_WINDOW ||
-			IsVitalWindow(w) ||
-			w->window_class == WC_TOOLTIPS ||
-			w->window_class == WC_DROPDOWN_MENU) {
-		return true;
-	}
-
-	wz = FindWindowZPosition(w);
-	for (uz = wz; ++uz != _last_z_window;) {
-		Window *u = *uz;
-
-		/* A modal child will prevent the activation of the parent window */
-		if (u->parent == w && (u->desc_flags & WDF_MODAL)) {
-			u->flags4 |= WF_WHITE_BORDER_MASK;
-			SetWindowDirty(u);
-			return false;
-		}
-
-		if (u->window_class == WC_MAIN_WINDOW ||
-				IsVitalWindow(u) ||
-				u->window_class == WC_TOOLTIPS ||
-				u->window_class == WC_DROPDOWN_MENU) {
-			continue;
-		}
-
-		/* Window sizes don't interfere, leave z-order alone */
-		if (w->left + w->width <= u->left ||
-				u->left + u->width <= w->left ||
-				w->top  + w->height <= u->top ||
-				u->top + u->height <= w->top) {
-			continue;
-		}
-
-		bring_to_front = true;
-	}
-
-	if (bring_to_front) BringWindowToFront(w);
-	return true;
-}
-
-/** Send a message from one window to another. The receiving window is found by
- * @param w @see Window pointer pointing to the other window
- * @param msg Specifies the message to be sent
- * @param wparam Specifies additional message-specific information
- * @param lparam Specifies additional message-specific information
- */
-static void SendWindowMessageW(Window *w, uint msg, uint wparam, uint lparam)
-{
-	WindowEvent e;
-
-	e.event             = WE_MESSAGE;
-	e.we.message.msg    = msg;
-	e.we.message.wparam = wparam;
-	e.we.message.lparam = lparam;
-
-	w->wndproc(w, &e);
-}
-
-/** Send a message from one window to another. The receiving window is found by
- * @param wnd_class @see WindowClass class AND
- * @param wnd_num @see WindowNumber number, mostly 0
- * @param msg Specifies the message to be sent
- * @param wparam Specifies additional message-specific information
- * @param lparam Specifies additional message-specific information
- */
-void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, uint msg, uint wparam, uint lparam)
-{
-	Window *w = FindWindowById(wnd_class, wnd_num);
-	if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
-}
-
-/** Send a message from one window to another. The message will be sent
- * to ALL windows of the windowclass specified in the first parameter
- * @param wnd_class @see WindowClass class
- * @param msg Specifies the message to be sent
- * @param wparam Specifies additional message-specific information
- * @param lparam Specifies additional message-specific information
- */
-void SendWindowMessageClass(WindowClass wnd_class, uint msg, uint wparam, uint lparam)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam);
-	}
-}
-
-/** Handle keyboard input.
- * @param key Lower 8 bits contain the ASCII character, the higher
- * 16 bits the keycode */
-void HandleKeypress(uint32 key)
-{
-	Window* const *wz;
-	WindowEvent e;
-	/* Stores if a window with a textfield for typing is open
-	 * If this is the case, keypress events are only passed to windows with text fields and
-	 * to thein this main toolbar. */
-	bool query_open = false;
-
-	/*
-	* During the generation of the world, there might be
-	* another thread that is currently building for example
-	* a road. To not interfere with those tasks, we should
-	* NOT change the _current_player here.
-	*
-	* This is not necessary either, as the only events that
-	* can be handled are the 'close application' events
-	*/
-	if (!IsGeneratingWorld()) _current_player = _local_player;
-
-	// Setup event
-	e.event = WE_KEYPRESS;
-	e.we.keypress.key     = GB(key,  0, 16);
-	e.we.keypress.keycode = GB(key, 16, 16);
-	e.we.keypress.cont = true;
-
-	// check if we have a query string window open before allowing hotkeys
-	if (FindWindowById(WC_QUERY_STRING,       0) != NULL ||
-			FindWindowById(WC_SEND_NETWORK_MSG,   0) != NULL ||
-			FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
-			FindWindowById(WC_CONSOLE,            0) != NULL ||
-			FindWindowById(WC_SAVELOAD,           0) != NULL) {
-		query_open = true;
-	}
-
-	// Call the event, start with the uppermost window.
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
-
-		// if a query window is open, only call the event for certain window types
-		if (query_open &&
-				w->window_class != WC_QUERY_STRING &&
-				w->window_class != WC_SEND_NETWORK_MSG &&
-				w->window_class != WC_GENERATE_LANDSCAPE &&
-				w->window_class != WC_CONSOLE &&
-				w->window_class != WC_SAVELOAD) {
-			continue;
-		}
-		w->wndproc(w, &e);
-		if (!e.we.keypress.cont) break;
-	}
-
-	if (e.we.keypress.cont) {
-		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
-		// When there is no toolbar w is null, check for that
-		if (w != NULL) w->wndproc(w, &e);
-	}
-}
-
-extern void UpdateTileSelection(void);
-extern bool VpHandlePlaceSizingDrag(void);
-
-static int _input_events_this_tick = 0;
-
-static void HandleAutoscroll(void)
-{
-	Window *w;
-	ViewPort *vp;
-	int x = _cursor.pos.x;
-	int y = _cursor.pos.y;
-
-	if (_input_events_this_tick != 0) {
-		/* HandleAutoscroll is called only once per GameLoop() - so we can clear the counter here */
-		_input_events_this_tick = 0;
-		/* there were some inputs this tick, don't scroll ??? */
-		return;
-	}
-
-	if (_patches.autoscroll && _game_mode != GM_MENU && !IsGeneratingWorld()) {
-		w = FindWindowFromPt(x, y);
-		if (w == NULL || w->flags4 & WF_DISABLE_VP_SCROLL) return;
-		vp = IsPtInWindowViewport(w, x, y);
-		if (vp != NULL) {
-			x -= vp->left;
-			y -= vp->top;
-			//here allows scrolling in both x and y axis
-#define scrollspeed 3
-			if (x - 15 < 0) {
-				WP(w, vp_d).scrollpos_x += (x - 15) * scrollspeed << vp->zoom;
-			} else if (15 - (vp->width - x) > 0) {
-				WP(w, vp_d).scrollpos_x += (15 - (vp->width - x)) * scrollspeed << vp->zoom;
-			}
-			if (y - 15 < 0) {
-				WP(w, vp_d).scrollpos_y += (y - 15) * scrollspeed << vp->zoom;
-			} else if (15 - (vp->height - y) > 0) {
-				WP(w,vp_d).scrollpos_y += (15 - (vp->height - y)) * scrollspeed << vp->zoom;
-			}
-#undef scrollspeed
-		}
-	}
-}
-
-void MouseLoop(int click, int mousewheel)
-{
-	int x,y;
-	Window *w;
-	ViewPort *vp;
-
-	DecreaseWindowCounters();
-	HandlePlacePresize();
-	UpdateTileSelection();
-	if (!VpHandlePlaceSizingDrag())  return;
-	if (!HandleDragDrop())           return;
-	if (!HandlePopupMenu())          return;
-	if (!HandleWindowDragging())     return;
-	if (!HandleScrollbarScrolling()) return;
-	if (!HandleViewportScroll())     return;
-	if (!HandleMouseOver())          return;
-
-	x = _cursor.pos.x;
-	y = _cursor.pos.y;
-
-	if (click == 0 && mousewheel == 0) return;
-
-	w = FindWindowFromPt(x, y);
-	if (w == NULL) return;
-	if (!MaybeBringWindowToFront(w)) return;
-	vp = IsPtInWindowViewport(w, x, y);
-
-	/* Don't allow any action in a viewport if either in menu of in generating world */
-	if (vp != NULL && (_game_mode == GM_MENU || IsGeneratingWorld())) return;
-
-	if (mousewheel != 0) {
-		WindowEvent e;
-
-		/* Send WE_MOUSEWHEEL event to window */
-		e.event = WE_MOUSEWHEEL;
-		e.we.wheel.wheel = mousewheel;
-		w->wndproc(w, &e);
-
-		/* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
-		if (vp == NULL) DispatchMouseWheelEvent(w, GetWidgetFromPos(w, x - w->left, y - w->top), mousewheel);
-	}
-
-	if (vp != NULL) {
-		switch (click) {
-			case 1:
-				DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
-				if (_thd.place_mode != 0 &&
-						// query button and place sign button work in pause mode
-						_cursor.sprite != SPR_CURSOR_QUERY &&
-						_cursor.sprite != SPR_CURSOR_SIGN &&
-						_pause != 0 &&
-						!_cheats.build_in_pause.value) {
-					return;
-				}
-
-				if (_thd.place_mode == 0) {
-					HandleViewportClicked(vp, x, y);
-				} else {
-					PlaceObject();
-				}
-				break;
-
-			case 2:
-				if (!(w->flags4 & WF_DISABLE_VP_SCROLL)) {
-					_scrolling_viewport = true;
-					_cursor.fix_at = true;
-				}
-				break;
-		}
-	} else {
-		switch (click) {
-			case 1: DispatchLeftClickEvent(w, x - w->left, y - w->top);  break;
-			case 2: DispatchRightClickEvent(w, x - w->left, y - w->top); break;
-		}
-	}
-}
-
-void HandleMouseEvents(void)
-{
-	int click;
-	int mousewheel;
-
-	/*
-	 * During the generation of the world, there might be
-	 * another thread that is currently building for example
-	 * a road. To not interfere with those tasks, we should
-	 * NOT change the _current_player here.
-	 *
-	 * This is not necessary either, as the only events that
-	 * can be handled are the 'close application' events
-	 */
-	if (!IsGeneratingWorld()) _current_player = _local_player;
-
-	// Mouse event?
-	click = 0;
-	if (_left_button_down && !_left_button_clicked) {
-		_left_button_clicked = true;
-		click = 1;
-		_input_events_this_tick++;
-	} else if (_right_button_clicked) {
-		_right_button_clicked = false;
-		click = 2;
-		_input_events_this_tick++;
-	}
-
-	mousewheel = 0;
-	if (_cursor.wheel) {
-		mousewheel = _cursor.wheel;
-		_cursor.wheel = 0;
-		_input_events_this_tick++;
-	}
-
-	MouseLoop(click, mousewheel);
-}
-
-void InputLoop(void)
-{
-	HandleMouseEvents();
-	HandleAutoscroll();
-}
-
-void UpdateWindows(void)
-{
-	Window* const *wz;
-	static int we4_timer = 0;
-	int t = we4_timer + 1;
-
-	if (t >= 100) {
-		for (wz = _last_z_window; wz != _z_windows;) {
-			CallWindowEventNP(*--wz, WE_4);
-		}
-		t = 0;
-	}
-	we4_timer = t;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
-		if (w->flags4 & WF_WHITE_BORDER_MASK) {
-			w->flags4 -= WF_WHITE_BORDER_ONE;
-
-			if (!(w->flags4 & WF_WHITE_BORDER_MASK)) SetWindowDirty(w);
-		}
-	}
-
-	DrawDirtyBlocks();
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
-	}
-	DrawTextMessage();
-	// Redraw mouse cursor in case it was hidden
-	DrawMouseCursor();
-}
-
-
-int GetMenuItemIndex(const Window *w, int x, int y)
-{
-	if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) {
-		y /= 10;
-
-		if (y < WP(w, const menu_d).item_count &&
-				!HASBIT(WP(w, const menu_d).disabled_items, y)) {
-			return y;
-		}
-	}
-	return -1;
-}
-
-void InvalidateWindow(WindowClass cls, WindowNumber number)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) SetWindowDirty(w);
-	}
-}
-
-void InvalidateWidget(const Window *w, byte widget_index)
-{
-	const Widget *wi = &w->widget[widget_index];
-
-	/* Don't redraw the window if the widget is invisible or of no-type */
-	if (wi->type == WWT_EMPTY || IsWindowWidgetHidden(w, widget_index)) return;
-
-	SetDirtyBlocks(w->left + wi->left, w->top + wi->top, w->left + wi->right + 1, w->top + wi->bottom + 1);
-}
-
-void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) {
-			InvalidateWidget(w, widget_index);
-		}
-	}
-}
-
-void InvalidateWindowClasses(WindowClass cls)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == cls) SetWindowDirty(*wz);
-	}
-}
-
-void InvalidateThisWindowData(Window *w)
-{
-	CallWindowEventNP(w, WE_INVALIDATE_DATA);
-	SetWindowDirty(w);
-}
-
-void InvalidateWindowData(WindowClass cls, WindowNumber number)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w);
-	}
-}
-
-void InvalidateWindowClassesData(WindowClass cls)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz);
-	}
-}
-
-void CallWindowTickEvent(void)
-{
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		CallWindowEventNP(*--wz, WE_TICK);
-	}
-}
-
-void DeleteNonVitalWindows(void)
-{
-	Window* const *wz;
-
-restart_search:
-	/* When we find the window to delete, we need to restart the search
-	 * as deleting this window could cascade in deleting (many) others
-	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class != WC_MAIN_WINDOW &&
-				w->window_class != WC_SELECT_GAME &&
-				w->window_class != WC_MAIN_TOOLBAR &&
-				w->window_class != WC_STATUS_BAR &&
-				w->window_class != WC_TOOLBAR_MENU &&
-				w->window_class != WC_TOOLTIPS &&
-				(w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned'
-
-			DeleteWindow(w);
-			goto restart_search;
-		}
-	}
-}
-
-/* It is possible that a stickied window gets to a position where the
- * 'close' button is outside the gaming area. You cannot close it then; except
- * with this function. It closes all windows calling the standard function,
- * then, does a little hacked loop of closing all stickied windows. Note
- * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
-void DeleteAllNonVitalWindows(void)
-{
-	Window* const *wz;
-
-	/* Delete every window except for stickied ones, then sticky ones as well */
-	DeleteNonVitalWindows();
-
-restart_search:
-	/* When we find the window to delete, we need to restart the search
-	 * as deleting this window could cascade in deleting (many) others
-	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->flags4 & WF_STICKY) {
-			DeleteWindow(*wz);
-			goto restart_search;
-		}
-	}
-}
-
-/* Delete all always on-top windows to get an empty screen */
-void HideVitalWindows(void)
-{
-	DeleteWindowById(WC_MAIN_TOOLBAR, 0);
-	DeleteWindowById(WC_STATUS_BAR, 0);
-}
-
-int PositionMainToolbar(Window *w)
-{
-	DEBUG(misc, 5, "Repositioning Main Toolbar...");
-
-	if (w == NULL || w->window_class != WC_MAIN_TOOLBAR) {
-		w = FindWindowById(WC_MAIN_TOOLBAR, 0);
-	}
-
-	switch (_patches.toolbar_pos) {
-		case 1:  w->left = (_screen.width - w->width) / 2; break;
-		case 2:  w->left = _screen.width - w->width; break;
-		default: w->left = 0;
-	}
-	SetDirtyBlocks(0, 0, _screen.width, w->height); // invalidate the whole top part
-	return w->left;
-}
-
-void RelocateAllWindows(int neww, int newh)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		int left, top;
-
-		if (w->window_class == WC_MAIN_WINDOW) {
-			ViewPort *vp = w->viewport;
-			vp->width = w->width = neww;
-			vp->height = w->height = newh;
-			vp->virtual_width = neww << vp->zoom;
-			vp->virtual_height = newh << vp->zoom;
-			continue; // don't modify top,left
-		}
-
-		/* XXX - this probably needs something more sane. For example specying
-		 * in a 'backup'-desc that the window should always be centred. */
-		switch (w->window_class) {
-			case WC_MAIN_TOOLBAR:
-				top = w->top;
-				left = PositionMainToolbar(w); // changes toolbar orientation
-				break;
-
-			case WC_SELECT_GAME:
-			case WC_GAME_OPTIONS:
-			case WC_NETWORK_WINDOW:
-				top = (newh - w->height) >> 1;
-				left = (neww - w->width) >> 1;
-				break;
-
-			case WC_NEWS_WINDOW:
-				top = newh - w->height;
-				left = (neww - w->width) >> 1;
-				break;
-
-			case WC_STATUS_BAR:
-				top = newh - w->height;
-				left = (neww - w->width) >> 1;
-				break;
-
-			case WC_SEND_NETWORK_MSG:
-				top = (newh - 26); // 26 = height of status bar + height of chat bar
-				left = (neww - w->width) >> 1;
-				break;
-
-			case WC_CONSOLE:
-				IConsoleResize(w);
-				continue;
-
-			default:
-				left = w->left;
-				if (left + (w->width >> 1) >= neww) left = neww - w->width;
-				top = w->top;
-				if (top + (w->height >> 1) >= newh) top = newh - w->height;
-				break;
-		}
-
-		if (w->viewport != NULL) {
-			w->viewport->left += left - w->left;
-			w->viewport->top += top - w->top;
-		}
-
-		w->left = left;
-		w->top = top;
-	}
-}
new file mode 100644
--- /dev/null
+++ b/src/window.cpp
@@ -0,0 +1,2000 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include <stdarg.h>
+#include "openttd.h"
+#include "debug.h"
+#include "functions.h"
+#include "map.h"
+#include "player.h"
+#include "window.h"
+#include "gfx.h"
+#include "viewport.h"
+#include "console.h"
+#include "variables.h"
+#include "table/sprites.h"
+#include "genworld.h"
+
+// delta between mouse cursor and upper left corner of dragged window
+static Point _drag_delta;
+
+static Window _windows[25];
+Window *_z_windows[lengthof(_windows)];
+Window **_last_z_window; ///< always points to the next free space in the z-array
+
+void CDECL SetWindowWidgetsDisabledState(Window *w, bool disab_stat, int widgets, ...)
+{
+	va_list wdg_list;
+
+	va_start(wdg_list, widgets);
+
+	while (widgets != WIDGET_LIST_END) {
+		SetWindowWidgetDisabledState(w, widgets, disab_stat);
+		widgets = va_arg(wdg_list, int);
+	}
+
+	va_end(wdg_list);
+}
+
+void CDECL SetWindowWidgetsHiddenState(Window *w, bool hidden_stat, int widgets, ...)
+{
+	va_list wdg_list;
+
+	va_start(wdg_list, widgets);
+
+	while (widgets != WIDGET_LIST_END) {
+		SetWindowWidgetHiddenState(w, widgets, hidden_stat);
+		widgets = va_arg(wdg_list, int);
+	}
+
+	va_end(wdg_list);
+}
+
+void CDECL SetWindowWidgetsLoweredState(Window *w, bool lowered_stat, int widgets, ...)
+{
+	va_list wdg_list;
+
+	va_start(wdg_list, widgets);
+
+	while (widgets != WIDGET_LIST_END) {
+		SetWindowWidgetLoweredState(w, widgets, lowered_stat);
+		widgets = va_arg(wdg_list, int);
+	}
+
+	va_end(wdg_list);
+}
+
+void RaiseWindowButtons(Window *w)
+{
+	uint i;
+
+	for (i = 0; i < w->widget_count; i++) {
+		if (IsWindowWidgetLowered(w, i)) {
+			RaiseWindowWidget(w, i);
+			InvalidateWidget(w, i);
+		}
+	}
+}
+
+void HandleButtonClick(Window *w, byte widget)
+{
+	LowerWindowWidget(w, widget);
+	w->flags4 |= 5 << WF_TIMEOUT_SHL;
+	InvalidateWidget(w, widget);
+}
+
+
+static void StartWindowDrag(Window *w);
+static void StartWindowSizing(Window *w);
+
+static void DispatchLeftClickEvent(Window *w, int x, int y)
+{
+	WindowEvent e;
+	const Widget *wi;
+
+	e.we.click.pt.x = x;
+	e.we.click.pt.y = y;
+	e.event = WE_CLICK;
+
+	if (w->desc_flags & WDF_DEF_WIDGET) {
+		e.we.click.widget = GetWidgetFromPos(w, x, y);
+		if (e.we.click.widget < 0) return; /* exit if clicked outside of widgets */
+
+		/* don't allow any interaction if the button has been disabled */
+		if (IsWindowWidgetDisabled(w, e.we.click.widget)) return;
+
+		wi = &w->widget[e.we.click.widget];
+
+		if (wi->type & WWB_MASK) {
+			/* special widget handling for buttons*/
+			switch (wi->type) {
+				case WWT_PANEL   | WWB_PUSHBUTTON: /* WWT_PUSHBTN */
+				case WWT_IMGBTN  | WWB_PUSHBUTTON: /* WWT_PUSHIMGBTN */
+				case WWT_TEXTBTN | WWB_PUSHBUTTON: /* WWT_PUSHTXTBTN */
+					HandleButtonClick(w, e.we.click.widget);
+					break;
+			}
+		} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
+			ScrollbarClickHandler(w, wi, e.we.click.pt.x, e.we.click.pt.y);
+		}
+
+		if (w->desc_flags & WDF_STD_BTN) {
+			if (e.we.click.widget == 0) { /* 'X' */
+				DeleteWindow(w);
+				return;
+			}
+
+			if (e.we.click.widget == 1) { /* 'Title bar' */
+				StartWindowDrag(w);
+				return;
+			}
+		}
+
+		if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) {
+			StartWindowSizing(w);
+			InvalidateWidget(w, e.we.click.widget);
+			return;
+		}
+
+		if (w->desc_flags & WDF_STICKY_BUTTON && wi->type == WWT_STICKYBOX) {
+			w->flags4 ^= WF_STICKY;
+			InvalidateWidget(w, e.we.click.widget);
+			return;
+		}
+	}
+
+	w->wndproc(w, &e);
+}
+
+static void DispatchRightClickEvent(Window *w, int x, int y)
+{
+	WindowEvent e;
+
+	/* default tooltips handler? */
+	if (w->desc_flags & WDF_STD_TOOLTIPS) {
+		e.we.click.widget = GetWidgetFromPos(w, x, y);
+		if (e.we.click.widget < 0)
+			return; /* exit if clicked outside of widgets */
+
+		if (w->widget[e.we.click.widget].tooltips != 0) {
+			GuiShowTooltips(w->widget[e.we.click.widget].tooltips);
+			return;
+		}
+	}
+
+	e.event = WE_RCLICK;
+	e.we.click.pt.x = x;
+	e.we.click.pt.y = y;
+	w->wndproc(w, &e);
+}
+
+/** Dispatch the mousewheel-action to the window which will scroll any
+ * compatible scrollbars if the mouse is pointed over the bar or its contents
+ * @param *w Window
+ * @param widget the widget where the scrollwheel was used
+ * @param wheel scroll up or down
+ */
+static void DispatchMouseWheelEvent(Window *w, int widget, int wheel)
+{
+	const Widget *wi1, *wi2;
+	Scrollbar *sb;
+
+	if (widget < 0) return;
+
+	wi1 = &w->widget[widget];
+	wi2 = &w->widget[widget + 1];
+
+	/* The listbox can only scroll if scrolling was done on the scrollbar itself,
+	 * or on the listbox (and the next item is (must be) the scrollbar)
+	 * XXX - should be rewritten as a widget-dependent scroller but that's
+	 * not happening until someone rewrites the whole widget-code */
+	if ((sb = &w->vscroll,  wi1->type == WWT_SCROLLBAR)  || (sb = &w->vscroll2, wi1->type == WWT_SCROLL2BAR)  ||
+			(sb = &w->vscroll2, wi2->type == WWT_SCROLL2BAR) || (sb = &w->vscroll, wi2->type == WWT_SCROLLBAR) ) {
+
+		if (sb->count > sb->cap) {
+			int pos = clamp(sb->pos + wheel, 0, sb->count - sb->cap);
+			if (pos != sb->pos) {
+				sb->pos = pos;
+				SetWindowDirty(w);
+			}
+		}
+	}
+}
+
+static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom);
+
+void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
+{
+	Window* const *wz;
+	DrawPixelInfo bk;
+	_cur_dpi = &bk;
+
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (right > w->left &&
+				bottom > w->top &&
+				left < w->left + w->width &&
+				top < w->top + w->height) {
+			DrawOverlappedWindow(wz, left, top, right, bottom);
+		}
+	}
+}
+
+static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom)
+{
+	Window* const *vz = wz;
+	int x;
+
+	while (++vz != _last_z_window) {
+		const Window *v = *vz;
+
+		if (right > v->left &&
+				bottom > v->top &&
+				left < v->left + v->width &&
+				top < v->top + v->height) {
+			if (left < (x=v->left)) {
+				DrawOverlappedWindow(wz, left, top, x, bottom);
+				DrawOverlappedWindow(wz, x, top, right, bottom);
+				return;
+			}
+
+			if (right > (x=v->left + v->width)) {
+				DrawOverlappedWindow(wz, left, top, x, bottom);
+				DrawOverlappedWindow(wz, x, top, right, bottom);
+				return;
+			}
+
+			if (top < (x=v->top)) {
+				DrawOverlappedWindow(wz, left, top, right, x);
+				DrawOverlappedWindow(wz, left, x, right, bottom);
+				return;
+			}
+
+			if (bottom > (x=v->top + v->height)) {
+				DrawOverlappedWindow(wz, left, top, right, x);
+				DrawOverlappedWindow(wz, left, x, right, bottom);
+				return;
+			}
+
+			return;
+		}
+	}
+
+	{
+		DrawPixelInfo *dp = _cur_dpi;
+		dp->width = right - left;
+		dp->height = bottom - top;
+		dp->left = left - (*wz)->left;
+		dp->top = top - (*wz)->top;
+		dp->pitch = _screen.pitch;
+		dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left;
+		dp->zoom = 0;
+		CallWindowEventNP(*wz, WE_PAINT);
+	}
+}
+
+void CallWindowEventNP(Window *w, int event)
+{
+	WindowEvent e;
+
+	e.event = event;
+	w->wndproc(w, &e);
+}
+
+void SetWindowDirty(const Window *w)
+{
+	if (w == NULL) return;
+	SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
+}
+
+/** Find the Window whose parent pointer points to this window
+ * @parent w Window to find child of
+ * @return return a Window pointer that is the child of w, or NULL otherwise */
+static Window *FindChildWindow(const Window *w)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *v = *wz;
+		if (v->parent == w) return v;
+	}
+
+	return NULL;
+}
+
+/** Find the z-value of a window. A window must already be open
+ * or the behaviour is undefined but function should never fail */
+Window **FindWindowZPosition(const Window *w)
+{
+	Window **wz;
+
+	for (wz = _z_windows; wz != _last_z_window; wz++) {
+		if (*wz == w) return wz;
+	}
+
+	DEBUG(misc, 3, "Window (class %d, number %d) is not open, probably removed by recursive calls",
+		w->window_class, w->window_number);
+	return NULL;
+}
+
+void DeleteWindow(Window *w)
+{
+	Window *v;
+	Window **wz;
+	if (w == NULL) return;
+
+	/* Delete any children a window might have in a head-recursive manner */
+	v = FindChildWindow(w);
+	if (v != NULL) DeleteWindow(v);
+
+	if (_thd.place_mode != VHM_NONE &&
+			_thd.window_class == w->window_class &&
+			_thd.window_number == w->window_number) {
+		ResetObjectToPlace();
+	}
+
+	CallWindowEventNP(w, WE_DESTROY);
+	if (w->viewport != NULL) DeleteWindowViewport(w);
+
+	SetWindowDirty(w);
+	free(w->widget);
+	w->widget = NULL;
+	w->widget_count = 0;
+	w->parent = NULL;
+
+	/* Find the window in the z-array, and effectively remove it
+	 * by moving all windows after it one to the left */
+	wz = FindWindowZPosition(w);
+	if (wz == NULL) return;
+	memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
+	_last_z_window--;
+}
+
+Window *FindWindowById(WindowClass cls, WindowNumber number)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class == cls && w->window_number == number) return w;
+	}
+
+	return NULL;
+}
+
+void DeleteWindowById(WindowClass cls, WindowNumber number)
+{
+	DeleteWindow(FindWindowById(cls, number));
+}
+
+void DeleteWindowByClass(WindowClass cls)
+{
+	Window* const *wz;
+
+restart_search:
+	/* When we find the window to delete, we need to restart the search
+	 * as deleting this window could cascade in deleting (many) others
+	 * anywhere in the z-array */
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class == cls) {
+			DeleteWindow(w);
+			goto restart_search;
+		}
+	}
+}
+
+/** Delete all windows of a player. We identify windows of a player
+ * by looking at the caption colour. If it is equal to the player ID
+ * then we say the window belongs to the player and should be deleted
+ * @param id PlayerID player identifier */
+void DeletePlayerWindows(PlayerID id)
+{
+	Window* const *wz;
+
+restart_search:
+	/* When we find the window to delete, we need to restart the search
+	 * as deleting this window could cascade in deleting (many) others
+	 * anywhere in the z-array */
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->caption_color == id) {
+			DeleteWindow(w);
+			goto restart_search;
+		}
+	}
+
+	/* Also delete the player specific windows, that don't have a player-colour */
+	DeleteWindowById(WC_BUY_COMPANY, id);
+}
+
+/** Change the owner of all the windows one player can take over from another
+ * player in the case of a company merger. Do not change ownership of windows
+ * that need to be deleted once takeover is complete
+ * @param old_player PlayerID of original owner of the window
+ * @param new_player PlayerID of the new owner of the window */
+void ChangeWindowOwner(PlayerID old_player, PlayerID new_player)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+
+		if (w->caption_color != old_player)      continue;
+		if (w->window_class == WC_PLAYER_COLOR)  continue;
+		if (w->window_class == WC_FINANCES)      continue;
+		if (w->window_class == WC_STATION_LIST)  continue;
+		if (w->window_class == WC_TRAINS_LIST)   continue;
+		if (w->window_class == WC_ROADVEH_LIST)  continue;
+		if (w->window_class == WC_SHIPS_LIST)    continue;
+		if (w->window_class == WC_AIRCRAFT_LIST) continue;
+		if (w->window_class == WC_BUY_COMPANY)   continue;
+		if (w->window_class == WC_COMPANY)       continue;
+
+		w->caption_color = new_player;
+	}
+}
+
+static void BringWindowToFront(const Window *w);
+
+/** Find a window and make it the top-window on the screen. The window
+ * gets a white border for a brief period of time to visualize its
+ * "activation"
+ * @return a pointer to the window thus activated */
+Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
+{
+	Window *w = FindWindowById(cls, number);
+
+	if (w != NULL) {
+		w->flags4 |= WF_WHITE_BORDER_MASK;
+		BringWindowToFront(w);
+		SetWindowDirty(w);
+	}
+
+	return w;
+}
+
+static inline bool IsVitalWindow(const Window *w)
+{
+	WindowClass wc = w->window_class;
+	return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
+}
+
+/** On clicking on a window, make it the frontmost window of all. However
+ * there are certain windows that always need to be on-top; these include
+ * - Toolbar, Statusbar (always on)
+ * - New window, Chatbar (only if open)
+ * The window is marked dirty for a repaint if the window is actually moved
+ * @param w window that is put into the foreground
+ * @return pointer to the window, the same as the input pointer
+ */
+static void BringWindowToFront(const Window *w)
+{
+	Window *tempz;
+	Window **wz = FindWindowZPosition(w);
+	Window **vz = _last_z_window;
+
+	/* Bring the window just below the vital windows */
+	do {
+		if (--vz < _z_windows) return;
+	} while (IsVitalWindow(*vz));
+
+	if (wz == vz) return; // window is already in the right position
+	assert(wz < vz);
+
+	tempz = *wz;
+	memmove(wz, wz + 1, (byte*)vz - (byte*)wz);
+	*vz = tempz;
+
+	SetWindowDirty(w);
+}
+
+/** We have run out of windows, so find a suitable candidate for replacement.
+ * Keep all important windows intact. These are
+ * - Main window (gamefield), Toolbar, Statusbar (always on)
+ * - News window, Chatbar (when on)
+ * - Any sticked windows since we wanted to keep these
+ * @return w pointer to the window that is going to be deleted
+ */
+static Window *FindDeletableWindow(void)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
+			return w;
+		}
+	}
+	return NULL;
+}
+
+/** A window must be freed, and all are marked as important windows. Ease the
+ * restriction a bit by allowing to delete sticky windows. Keep important/vital
+ * windows intact (Main window, Toolbar, Statusbar, News Window, Chatbar)
+ * Start finding an appropiate candidate from the lowest z-values (bottom)
+ * @see FindDeletableWindow()
+ * @return w Pointer to the window that is being deleted
+ */
+static Window *ForceFindDeletableWindow(void)
+{
+	Window* const *wz;
+
+	for (wz = _z_windows;; wz++) {
+		Window *w = *wz;
+		assert(wz < _last_z_window);
+		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
+	}
+}
+
+bool IsWindowOfPrototype(const Window *w, const Widget *widget)
+{
+	return (w->original_widget == widget);
+}
+
+/* Copies 'widget' to 'w->widget' to allow for resizable windows */
+void AssignWidgetToWindow(Window *w, const Widget *widget)
+{
+	w->original_widget = widget;
+
+	if (widget != NULL) {
+		uint index = 1;
+		const Widget *wi;
+
+		for (wi = widget; wi->type != WWT_LAST; wi++) index++;
+
+		w->widget = realloc(w->widget, sizeof(*w->widget) * index);
+		memcpy(w->widget, widget, sizeof(*w->widget) * index);
+		w->widget_count = index - 1;
+	} else {
+		w->widget = NULL;
+		w->widget_count = 0;
+	}
+}
+
+static Window *FindFreeWindow(void)
+{
+	Window *w;
+
+	for (w = _windows; w < endof(_windows); w++) {
+		Window* const *wz;
+		bool window_in_use = false;
+
+		FOR_ALL_WINDOWS(wz) {
+			if (*wz == w) {
+				window_in_use = true;
+				break;
+			}
+		}
+
+		if (!window_in_use) return w;
+	}
+
+	assert(_last_z_window == endof(_z_windows));
+	return NULL;
+}
+
+/* Open a new window.
+ * This function is called from AllocateWindow() or AllocateWindowDesc()
+ * See descriptions for those functions for usage
+ * See AllocateWindow() for description of arguments.
+ * Only addition here is window_number, which is the window_number being assigned to the new window
+ */
+static Window *LocalAllocateWindow(
+							int x, int y, int width, int height,
+							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
+{
+	Window *w = FindFreeWindow();
+
+	/* We have run out of windows, close one and use that as the place for our new one */
+	if (w == NULL) {
+		w = FindDeletableWindow();
+		if (w == NULL) w = ForceFindDeletableWindow();
+		DeleteWindow(w);
+	}
+
+	// Set up window properties
+	memset(w, 0, sizeof(*w));
+	w->window_class = cls;
+	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
+	w->caption_color = 0xFF;
+	w->left = x;
+	w->top = y;
+	w->width = width;
+	w->height = height;
+	w->wndproc = proc;
+	AssignWidgetToWindow(w, widget);
+	w->resize.width = width;
+	w->resize.height = height;
+	w->resize.step_width = 1;
+	w->resize.step_height = 1;
+	w->window_number = window_number;
+
+	{
+		Window **wz = _last_z_window;
+
+		/* Hacky way of specifying always-on-top windows. These windows are
+		 * always above other windows because they are moved below them.
+		 * status-bar is above news-window because it has been created earlier.
+		 * Also, as the chat-window is excluded from this, it will always be
+		 * the last window, thus always on top.
+		 * XXX - Yes, ugly, probably needs something like w->always_on_top flag
+		 * to implement correctly, but even then you need some kind of distinction
+		 * between on-top of chat/news and status windows, because these conflict */
+		if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
+			if (FindWindowById(WC_MAIN_TOOLBAR, 0)     != NULL) wz--;
+			if (FindWindowById(WC_STATUS_BAR, 0)       != NULL) wz--;
+			if (FindWindowById(WC_NEWS_WINDOW, 0)      != NULL) wz--;
+			if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
+
+			assert(wz >= _z_windows);
+			if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
+		}
+
+		*wz = w;
+		_last_z_window++;
+	}
+
+	SetWindowDirty(w);
+	CallWindowEventNP(w, WE_CREATE);
+
+	return w;
+}
+
+/**
+ * Open a new window. If there is no space for a new window, close an open
+ * window. Try to avoid stickied windows, but if there is no else, close one of
+ * those as well. Then make sure all created windows are below some always-on-top
+ * ones. Finally set all variables and call the WE_CREATE event
+ * @param x offset in pixels from the left of the screen
+ * @param y offset in pixels from the top of the screen
+ * @param width width in pixels of the window
+ * @param height height in pixels of the window
+ * @param *proc @see WindowProc function to call when any messages/updates happen to the window
+ * @param cls @see WindowClass class of the window, used for identification and grouping
+ * @param *widget @see Widget pointer to the window layout and various elements
+ * @return @see Window pointer of the newly created window
+ */
+Window *AllocateWindow(
+							int x, int y, int width, int height,
+							WindowProc *proc, WindowClass cls, const Widget *widget)
+{
+	return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
+}
+
+typedef struct SizeRect {
+	int left,top,width,height;
+} SizeRect;
+
+
+static SizeRect _awap_r;
+
+static bool IsGoodAutoPlace1(int left, int top)
+{
+	int right,bottom;
+	Window* const *wz;
+
+	_awap_r.left= left;
+	_awap_r.top = top;
+	right = _awap_r.width + left;
+	bottom = _awap_r.height + top;
+
+	if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height)
+		return false;
+
+	// Make sure it is not obscured by any window.
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == WC_MAIN_WINDOW) continue;
+
+		if (right > w->left &&
+				w->left + w->width > left &&
+				bottom > w->top &&
+				w->top + w->height > top) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static bool IsGoodAutoPlace2(int left, int top)
+{
+	int width,height;
+	Window* const *wz;
+
+	_awap_r.left= left;
+	_awap_r.top = top;
+	width = _awap_r.width;
+	height = _awap_r.height;
+
+	if (left < -(width>>2) || left > _screen.width - (width>>1)) return false;
+	if (top < 22 || top > _screen.height - (height>>2)) return false;
+
+	// Make sure it is not obscured by any window.
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == WC_MAIN_WINDOW) continue;
+
+		if (left + width > w->left &&
+				w->left + w->width > left &&
+				top + height > w->top &&
+				w->top + w->height > top) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static Point GetAutoPlacePosition(int width, int height)
+{
+	Window* const *wz;
+	Point pt;
+
+	_awap_r.width = width;
+	_awap_r.height = height;
+
+	if (IsGoodAutoPlace1(0, 24)) goto ok_pos;
+
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == WC_MAIN_WINDOW) continue;
+
+		if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left-   width-2,w->top)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left,w->top+w->height+2)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left,w->top-   height-2)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left+w->width+2,w->top+w->height-height)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left-   width-2,w->top+w->height-height)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left+w->width-width,w->top+w->height+2)) goto ok_pos;
+		if (IsGoodAutoPlace1(w->left+w->width-width,w->top-   height-2)) goto ok_pos;
+	}
+
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == WC_MAIN_WINDOW) continue;
+
+		if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos;
+		if (IsGoodAutoPlace2(w->left-   width-2,w->top)) goto ok_pos;
+		if (IsGoodAutoPlace2(w->left,w->top+w->height+2)) goto ok_pos;
+		if (IsGoodAutoPlace2(w->left,w->top-   height-2)) goto ok_pos;
+	}
+
+	{
+		int left=0,top=24;
+
+restart:;
+		FOR_ALL_WINDOWS(wz) {
+			const Window *w = *wz;
+
+			if (w->left == left && w->top == top) {
+				left += 5;
+				top += 5;
+				goto restart;
+			}
+		}
+
+		pt.x = left;
+		pt.y = top;
+		return pt;
+	}
+
+ok_pos:;
+	pt.x = _awap_r.left;
+	pt.y = _awap_r.top;
+	return pt;
+}
+
+static Window *LocalAllocateWindowDesc(const WindowDesc *desc, int window_number)
+{
+	Point pt;
+	Window *w;
+
+	/* By default position a child window at an offset of 10/10 of its parent.
+	 * However if it falls too extremely outside window positions, reposition
+	 * it to an automatic place */
+	if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ &&
+			(w = FindWindowById(desc->parent_cls, window_number)) != NULL &&
+			w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) {
+
+		pt.x = w->left + 10;
+		if (pt.x > _screen.width + 10 - desc->width) {
+			pt.x = (_screen.width + 10 - desc->width) - 20;
+		}
+		pt.y = w->top + 10;
+	} else {
+		switch (desc->left) {
+			case WDP_ALIGN_TBR: { /* Align the right side with the top toolbar */
+				w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+				pt.x = (w->left + w->width) - desc->width;
+			}	break;
+			case WDP_ALIGN_TBL: /* Align the left side with the top toolbar */
+				pt.x = FindWindowById(WC_MAIN_TOOLBAR, 0)->left;
+				break;
+			case WDP_AUTO: /* Find a good automatic position for the window */
+				pt = GetAutoPlacePosition(desc->width, desc->height);
+				goto allocate_window;
+			case WDP_CENTER: /* Centre the window horizontally */
+				pt.x = (_screen.width - desc->width) / 2;
+				break;
+			default:
+				pt.x = desc->left;
+				if (pt.x < 0) pt.x += _screen.width; // negative is from right of the screen
+		}
+
+		switch (desc->top) {
+			case WDP_CENTER: /* Centre the window vertically */
+				pt.y = (_screen.height - desc->height) / 2;
+				break;
+			/* WDP_AUTO sets the position at once and is controlled by desc->left.
+			 * Both left and top must be set to WDP_AUTO */
+			case WDP_AUTO:
+				NOT_REACHED();
+				assert(desc->left == WDP_AUTO && desc->top != WDP_AUTO);
+				/* fallthrough */
+			default:
+				pt.y = desc->top;
+				if (pt.y < 0) pt.y += _screen.height; // negative is from bottom of the screen
+				break;
+		}
+	}
+
+allocate_window:
+	w = LocalAllocateWindow(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
+	w->desc_flags = desc->flags;
+	return w;
+}
+
+/**
+ * Open a new window.
+ * @param *desc The pointer to the WindowDesc to be created
+ * @return @see Window pointer of the newly created window
+ */
+Window *AllocateWindowDesc(const WindowDesc *desc)
+{
+	return LocalAllocateWindowDesc(desc, 0);
+}
+
+/**
+ * Open a new window.
+ * @param *desc The pointer to the WindowDesc to be created
+ * @param window_number the window number of the new window
+ * @return @see Window pointer of the newly created window
+ */
+Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
+{
+	Window *w;
+
+	if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
+	w = LocalAllocateWindowDesc(desc, window_number);
+	return w;
+}
+
+/** Do a search for a window at specific coordinates. For this we start
+ * at the topmost window, obviously and work our way down to the bottom
+ * @return a pointer to the found window if any, NULL otherwise */
+Window *FindWindowFromPt(int x, int y)
+{
+	Window* const *wz;
+
+	for (wz = _last_z_window; wz != _z_windows;) {
+		Window *w = *--wz;
+		if (IS_INSIDE_1D(x, w->left, w->width) && IS_INSIDE_1D(y, w->top, w->height)) {
+			return w;
+		}
+	}
+
+	return NULL;
+}
+
+void InitWindowSystem(void)
+{
+	IConsoleClose();
+
+	memset(&_windows, 0, sizeof(_windows));
+	_last_z_window = _z_windows;
+	InitViewports();
+	_no_scroll = 0;
+}
+
+void UnInitWindowSystem(void)
+{
+	Window **wz;
+	/* Delete all malloced widgets, and reset z-array */
+	FOR_ALL_WINDOWS(wz) {
+		free((*wz)->widget);
+		(*wz)->widget = NULL;
+		(*wz)->widget_count = 0;
+		*wz = NULL;
+	}
+	_last_z_window = _z_windows;
+}
+
+void ResetWindowSystem(void)
+{
+	UnInitWindowSystem();
+	InitWindowSystem();
+	_thd.pos.x = 0;
+	_thd.pos.y = 0;
+	_thd.new_pos.x = 0;
+	_thd.new_pos.y = 0;
+}
+
+static void DecreaseWindowCounters(void)
+{
+	Window *w;
+	Window* const *wz;
+
+	for (wz = _last_z_window; wz != _z_windows;) {
+		w = *--wz;
+		// Unclick scrollbar buttons if they are pressed.
+		if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
+			w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
+			SetWindowDirty(w);
+		}
+		CallWindowEventNP(w, WE_MOUSELOOP);
+	}
+
+	for (wz = _last_z_window; wz != _z_windows;) {
+		w = *--wz;
+
+		if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) {
+			CallWindowEventNP(w, WE_TIMEOUT);
+			if (w->desc_flags & WDF_UNCLICK_BUTTONS) RaiseWindowButtons(w);
+		}
+	}
+}
+
+Window *GetCallbackWnd(void)
+{
+	return FindWindowById(_thd.window_class, _thd.window_number);
+}
+
+static void HandlePlacePresize(void)
+{
+	Window *w;
+	WindowEvent e;
+
+	if (_special_mouse_mode != WSM_PRESIZE) return;
+
+	w = GetCallbackWnd();
+	if (w == NULL) return;
+
+	e.we.place.pt = GetTileBelowCursor();
+	if (e.we.place.pt.x == -1) {
+		_thd.selend.x = -1;
+		return;
+	}
+	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
+	e.event = WE_PLACE_PRESIZE;
+	w->wndproc(w, &e);
+}
+
+static bool HandleDragDrop(void)
+{
+	Window *w;
+	WindowEvent e;
+
+	if (_special_mouse_mode != WSM_DRAGDROP) return true;
+
+	if (_left_button_down) return false;
+
+	w = GetCallbackWnd();
+
+	ResetObjectToPlace();
+
+	if (w != NULL) {
+		// send an event in client coordinates.
+		e.event = WE_DRAGDROP;
+		e.we.dragdrop.pt.x = _cursor.pos.x - w->left;
+		e.we.dragdrop.pt.y = _cursor.pos.y - w->top;
+		e.we.dragdrop.widget = GetWidgetFromPos(w, e.we.dragdrop.pt.x, e.we.dragdrop.pt.y);
+		w->wndproc(w, &e);
+	}
+	return false;
+}
+
+static bool HandlePopupMenu(void)
+{
+	Window *w;
+	WindowEvent e;
+
+	if (!_popup_menu_active) return true;
+
+	w = FindWindowById(WC_TOOLBAR_MENU, 0);
+	if (w == NULL) {
+		_popup_menu_active = false;
+		return false;
+	}
+
+	if (_left_button_down) {
+		e.event = WE_POPUPMENU_OVER;
+		e.we.popupmenu.pt = _cursor.pos;
+	} else {
+		_popup_menu_active = false;
+		e.event = WE_POPUPMENU_SELECT;
+		e.we.popupmenu.pt = _cursor.pos;
+	}
+
+	w->wndproc(w, &e);
+
+	return false;
+}
+
+static bool HandleMouseOver(void)
+{
+	Window *w;
+	WindowEvent e;
+	static Window *last_w = NULL;
+
+	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
+
+	// We changed window, put a MOUSEOVER event to the last window
+	if (last_w != NULL && last_w != w) {
+		e.event = WE_MOUSEOVER;
+		e.we.mouseover.pt.x = -1;
+		e.we.mouseover.pt.y = -1;
+		if (last_w->wndproc) last_w->wndproc(last_w, &e);
+	}
+	last_w = w;
+
+	if (w != NULL) {
+		// send an event in client coordinates.
+		e.event = WE_MOUSEOVER;
+		e.we.mouseover.pt.x = _cursor.pos.x - w->left;
+		e.we.mouseover.pt.y = _cursor.pos.y - w->top;
+		if (w->widget != NULL) {
+			e.we.mouseover.widget = GetWidgetFromPos(w, e.we.mouseover.pt.x, e.we.mouseover.pt.y);
+		}
+		w->wndproc(w, &e);
+	}
+
+	// Mouseover never stops execution
+	return true;
+}
+
+/** Update all the widgets of a window based on their resize flags
+ * Both the areas of the old window and the new sized window are set dirty
+ * ensuring proper redrawal.
+ * @param w Window to resize
+ * @param x delta x-size of changed window (positive if larger, etc.(
+ * @param y delta y-size of changed window */
+void ResizeWindow(Window *w, int x, int y)
+{
+	Widget *wi;
+	bool resize_height = false;
+	bool resize_width = false;
+
+	if (x == 0 && y == 0) return;
+
+	SetWindowDirty(w);
+	for (wi = w->widget; wi->type != WWT_LAST; wi++) {
+		/* Isolate the resizing flags */
+		byte rsizeflag = GB(wi->display_flags, 0, 4);
+
+		if (rsizeflag == RESIZE_NONE) continue;
+
+		/* Resize the widget based on its resize-flag */
+		if (rsizeflag & RESIZE_LEFT) {
+			wi->left += x;
+			resize_width = true;
+		}
+
+		if (rsizeflag & RESIZE_RIGHT) {
+			wi->right += x;
+			resize_width = true;
+		}
+
+		if (rsizeflag & RESIZE_TOP) {
+			wi->top += y;
+			resize_height = true;
+		}
+
+		if (rsizeflag & RESIZE_BOTTOM) {
+			wi->bottom += y;
+			resize_height = true;
+		}
+	}
+
+	/* We resized at least 1 widget, so let's resize the window totally */
+	if (resize_width)  w->width  += x;
+	if (resize_height) w->height += y;
+
+	SetWindowDirty(w);
+}
+
+static bool _dragging_window;
+
+static bool HandleWindowDragging(void)
+{
+	Window* const *wz;
+	// Get out immediately if no window is being dragged at all.
+	if (!_dragging_window) return true;
+
+	// Otherwise find the window...
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+
+		if (w->flags4 & WF_DRAGGING) {
+			const Widget *t = &w->widget[1]; // the title bar ... ugh
+			const Window *v;
+			int x;
+			int y;
+			int nx;
+			int ny;
+
+			// Stop the dragging if the left mouse button was released
+			if (!_left_button_down) {
+				w->flags4 &= ~WF_DRAGGING;
+				break;
+			}
+
+			SetWindowDirty(w);
+
+			x = _cursor.pos.x + _drag_delta.x;
+			y = _cursor.pos.y + _drag_delta.y;
+			nx = x;
+			ny = y;
+
+			if (_patches.window_snap_radius != 0) {
+				Window* const *vz;
+
+				int hsnap = _patches.window_snap_radius;
+				int vsnap = _patches.window_snap_radius;
+				int delta;
+
+				FOR_ALL_WINDOWS(vz) {
+					const Window *v = *vz;
+
+					if (v == w) continue; // Don't snap at yourself
+
+					if (y + w->height > v->top && y < v->top + v->height) {
+						// Your left border <-> other right border
+						delta = abs(v->left + v->width - x);
+						if (delta <= hsnap) {
+							nx = v->left + v->width;
+							hsnap = delta;
+						}
+
+						// Your right border <-> other left border
+						delta = abs(v->left - x - w->width);
+						if (delta <= hsnap) {
+							nx = v->left - w->width;
+							hsnap = delta;
+						}
+					}
+
+					if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
+						// Your left border <-> other left border
+						delta = abs(v->left - x);
+						if (delta <= hsnap) {
+							nx = v->left;
+							hsnap = delta;
+						}
+
+						// Your right border <-> other right border
+						delta = abs(v->left + v->width - x - w->width);
+						if (delta <= hsnap) {
+							nx = v->left + v->width - w->width;
+							hsnap = delta;
+						}
+					}
+
+					if (x + w->width > v->left && x < v->left + v->width) {
+						// Your top border <-> other bottom border
+						delta = abs(v->top + v->height - y);
+						if (delta <= vsnap) {
+							ny = v->top + v->height;
+							vsnap = delta;
+						}
+
+						// Your bottom border <-> other top border
+						delta = abs(v->top - y - w->height);
+						if (delta <= vsnap) {
+							ny = v->top - w->height;
+							vsnap = delta;
+						}
+					}
+
+					if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
+						// Your top border <-> other top border
+						delta = abs(v->top - y);
+						if (delta <= vsnap) {
+							ny = v->top;
+							vsnap = delta;
+						}
+
+						// Your bottom border <-> other bottom border
+						delta = abs(v->top + v->height - y - w->height);
+						if (delta <= vsnap) {
+							ny = v->top + v->height - w->height;
+							vsnap = delta;
+						}
+					}
+				}
+			}
+
+			// Make sure the window doesn't leave the screen
+			// 13 is the height of the title bar
+			nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
+			ny = clamp(ny, 0, _screen.height - 13);
+
+			// Make sure the title bar isn't hidden by behind the main tool bar
+			v = FindWindowById(WC_MAIN_TOOLBAR, 0);
+			if (v != NULL) {
+				int v_bottom = v->top + v->height;
+				int v_right = v->left + v->width;
+				if (ny + t->top >= v->top && ny + t->top < v_bottom) {
+					if ((v->left < 13 && nx + t->left < v->left) ||
+							(v_right > _screen.width - 13 && nx + t->right > v_right)) {
+						ny = v_bottom;
+					} else {
+						if (nx + t->left > v->left - 13 &&
+								nx + t->right < v_right + 13) {
+							if (w->top >= v_bottom) {
+								ny = v_bottom;
+							} else if (w->left < nx) {
+								nx = v->left - 13 - t->left;
+							} else {
+								nx = v_right + 13 - t->right;
+							}
+						}
+					}
+				}
+			}
+
+			if (w->viewport != NULL) {
+				w->viewport->left += nx - w->left;
+				w->viewport->top  += ny - w->top;
+			}
+			w->left = nx;
+			w->top  = ny;
+
+			SetWindowDirty(w);
+			return false;
+		} else if (w->flags4 & WF_SIZING) {
+			WindowEvent e;
+			int x, y;
+
+			/* Stop the sizing if the left mouse button was released */
+			if (!_left_button_down) {
+				w->flags4 &= ~WF_SIZING;
+				SetWindowDirty(w);
+				break;
+			}
+
+			x = _cursor.pos.x - _drag_delta.x;
+			y = _cursor.pos.y - _drag_delta.y;
+
+			/* X and Y has to go by step.. calculate it.
+			 * The cast to int is necessary else x/y are implicitly casted to
+			 * unsigned int, which won't work. */
+			if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
+
+			if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
+
+			/* Check if we don't go below the minimum set size */
+			if ((int)w->width + x < (int)w->resize.width)
+				x = w->resize.width - w->width;
+			if ((int)w->height + y < (int)w->resize.height)
+				y = w->resize.height - w->height;
+
+			/* Window already on size */
+			if (x == 0 && y == 0) return false;
+
+			/* Now find the new cursor pos.. this is NOT _cursor, because
+			    we move in steps. */
+			_drag_delta.x += x;
+			_drag_delta.y += y;
+
+			/* ResizeWindow sets both pre- and after-size to dirty for redrawal */
+			ResizeWindow(w, x, y);
+
+			e.event = WE_RESIZE;
+			e.we.sizing.size.x = x + w->width;
+			e.we.sizing.size.y = y + w->height;
+			e.we.sizing.diff.x = x;
+			e.we.sizing.diff.y = y;
+			w->wndproc(w, &e);
+			return false;
+		}
+	}
+
+	_dragging_window = false;
+	return false;
+}
+
+static void StartWindowDrag(Window *w)
+{
+	w->flags4 |= WF_DRAGGING;
+	_dragging_window = true;
+
+	_drag_delta.x = w->left - _cursor.pos.x;
+	_drag_delta.y = w->top  - _cursor.pos.y;
+
+	BringWindowToFront(w);
+	DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+static void StartWindowSizing(Window *w)
+{
+	w->flags4 |= WF_SIZING;
+	_dragging_window = true;
+
+	_drag_delta.x = _cursor.pos.x;
+	_drag_delta.y = _cursor.pos.y;
+
+	BringWindowToFront(w);
+	DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+
+static bool HandleScrollbarScrolling(void)
+{
+	Window* const *wz;
+	int i;
+	int pos;
+	Scrollbar *sb;
+
+	// Get out quickly if no item is being scrolled
+	if (!_scrolling_scrollbar) return true;
+
+	// Find the scrolling window
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+
+		if (w->flags4 & WF_SCROLL_MIDDLE) {
+			// Abort if no button is clicked any more.
+			if (!_left_button_down) {
+				w->flags4 &= ~WF_SCROLL_MIDDLE;
+				SetWindowDirty(w);
+				break;
+			}
+
+			if (w->flags4 & WF_HSCROLL) {
+				sb = &w->hscroll;
+				i = _cursor.pos.x - _cursorpos_drag_start.x;
+			} else if (w->flags4 & WF_SCROLL2){
+				sb = &w->vscroll2;
+				i = _cursor.pos.y - _cursorpos_drag_start.y;
+			} else {
+				sb = &w->vscroll;
+				i = _cursor.pos.y - _cursorpos_drag_start.y;
+			}
+
+			// Find the item we want to move to and make sure it's inside bounds.
+			pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
+			if (pos != sb->pos) {
+				sb->pos = pos;
+				SetWindowDirty(w);
+			}
+			return false;
+		}
+	}
+
+	_scrolling_scrollbar = false;
+	return false;
+}
+
+static bool HandleViewportScroll(void)
+{
+	WindowEvent e;
+	Window *w;
+
+	if (!_scrolling_viewport) return true;
+
+	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
+
+	if (!_right_button_down || w == NULL) {
+		_cursor.fix_at = false;
+		_scrolling_viewport = false;
+		return true;
+	}
+
+	if (_patches.reverse_scroll) {
+		e.we.scroll.delta.x = -_cursor.delta.x;
+		e.we.scroll.delta.y = -_cursor.delta.y;
+	} else {
+		e.we.scroll.delta.x = _cursor.delta.x;
+		e.we.scroll.delta.y = _cursor.delta.y;
+	}
+
+	/* Create a scroll-event and send it to the window */
+	e.event = WE_SCROLL;
+	w->wndproc(w, &e);
+
+	_cursor.delta.x = 0;
+	_cursor.delta.y = 0;
+	return false;
+}
+
+/** Check if a window can be made top-most window, and if so do
+ * it. If a window does not obscure any other windows, it will not
+ * be brought to the foreground. Also if the only obscuring windows
+ * are so-called system-windows, the window will not be moved.
+ * The function will return false when a child window of this window is a
+ * modal-popup; function returns a false and child window gets a white border
+ * @param w Window to bring on-top
+ * @return false if the window has an active modal child, true otherwise */
+static bool MaybeBringWindowToFront(const Window *w)
+{
+	bool bring_to_front = false;
+	Window* const *wz;
+	Window* const *uz;
+
+	if (w->window_class == WC_MAIN_WINDOW ||
+			IsVitalWindow(w) ||
+			w->window_class == WC_TOOLTIPS ||
+			w->window_class == WC_DROPDOWN_MENU) {
+		return true;
+	}
+
+	wz = FindWindowZPosition(w);
+	for (uz = wz; ++uz != _last_z_window;) {
+		Window *u = *uz;
+
+		/* A modal child will prevent the activation of the parent window */
+		if (u->parent == w && (u->desc_flags & WDF_MODAL)) {
+			u->flags4 |= WF_WHITE_BORDER_MASK;
+			SetWindowDirty(u);
+			return false;
+		}
+
+		if (u->window_class == WC_MAIN_WINDOW ||
+				IsVitalWindow(u) ||
+				u->window_class == WC_TOOLTIPS ||
+				u->window_class == WC_DROPDOWN_MENU) {
+			continue;
+		}
+
+		/* Window sizes don't interfere, leave z-order alone */
+		if (w->left + w->width <= u->left ||
+				u->left + u->width <= w->left ||
+				w->top  + w->height <= u->top ||
+				u->top + u->height <= w->top) {
+			continue;
+		}
+
+		bring_to_front = true;
+	}
+
+	if (bring_to_front) BringWindowToFront(w);
+	return true;
+}
+
+/** Send a message from one window to another. The receiving window is found by
+ * @param w @see Window pointer pointing to the other window
+ * @param msg Specifies the message to be sent
+ * @param wparam Specifies additional message-specific information
+ * @param lparam Specifies additional message-specific information
+ */
+static void SendWindowMessageW(Window *w, uint msg, uint wparam, uint lparam)
+{
+	WindowEvent e;
+
+	e.event             = WE_MESSAGE;
+	e.we.message.msg    = msg;
+	e.we.message.wparam = wparam;
+	e.we.message.lparam = lparam;
+
+	w->wndproc(w, &e);
+}
+
+/** Send a message from one window to another. The receiving window is found by
+ * @param wnd_class @see WindowClass class AND
+ * @param wnd_num @see WindowNumber number, mostly 0
+ * @param msg Specifies the message to be sent
+ * @param wparam Specifies additional message-specific information
+ * @param lparam Specifies additional message-specific information
+ */
+void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, uint msg, uint wparam, uint lparam)
+{
+	Window *w = FindWindowById(wnd_class, wnd_num);
+	if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
+}
+
+/** Send a message from one window to another. The message will be sent
+ * to ALL windows of the windowclass specified in the first parameter
+ * @param wnd_class @see WindowClass class
+ * @param msg Specifies the message to be sent
+ * @param wparam Specifies additional message-specific information
+ * @param lparam Specifies additional message-specific information
+ */
+void SendWindowMessageClass(WindowClass wnd_class, uint msg, uint wparam, uint lparam)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam);
+	}
+}
+
+/** Handle keyboard input.
+ * @param key Lower 8 bits contain the ASCII character, the higher
+ * 16 bits the keycode */
+void HandleKeypress(uint32 key)
+{
+	Window* const *wz;
+	WindowEvent e;
+	/* Stores if a window with a textfield for typing is open
+	 * If this is the case, keypress events are only passed to windows with text fields and
+	 * to thein this main toolbar. */
+	bool query_open = false;
+
+	/*
+	* During the generation of the world, there might be
+	* another thread that is currently building for example
+	* a road. To not interfere with those tasks, we should
+	* NOT change the _current_player here.
+	*
+	* This is not necessary either, as the only events that
+	* can be handled are the 'close application' events
+	*/
+	if (!IsGeneratingWorld()) _current_player = _local_player;
+
+	// Setup event
+	e.event = WE_KEYPRESS;
+	e.we.keypress.key     = GB(key,  0, 16);
+	e.we.keypress.keycode = GB(key, 16, 16);
+	e.we.keypress.cont = true;
+
+	// check if we have a query string window open before allowing hotkeys
+	if (FindWindowById(WC_QUERY_STRING,       0) != NULL ||
+			FindWindowById(WC_SEND_NETWORK_MSG,   0) != NULL ||
+			FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
+			FindWindowById(WC_CONSOLE,            0) != NULL ||
+			FindWindowById(WC_SAVELOAD,           0) != NULL) {
+		query_open = true;
+	}
+
+	// Call the event, start with the uppermost window.
+	for (wz = _last_z_window; wz != _z_windows;) {
+		Window *w = *--wz;
+
+		// if a query window is open, only call the event for certain window types
+		if (query_open &&
+				w->window_class != WC_QUERY_STRING &&
+				w->window_class != WC_SEND_NETWORK_MSG &&
+				w->window_class != WC_GENERATE_LANDSCAPE &&
+				w->window_class != WC_CONSOLE &&
+				w->window_class != WC_SAVELOAD) {
+			continue;
+		}
+		w->wndproc(w, &e);
+		if (!e.we.keypress.cont) break;
+	}
+
+	if (e.we.keypress.cont) {
+		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		// When there is no toolbar w is null, check for that
+		if (w != NULL) w->wndproc(w, &e);
+	}
+}
+
+extern void UpdateTileSelection(void);
+extern bool VpHandlePlaceSizingDrag(void);
+
+static int _input_events_this_tick = 0;
+
+static void HandleAutoscroll(void)
+{
+	Window *w;
+	ViewPort *vp;
+	int x = _cursor.pos.x;
+	int y = _cursor.pos.y;
+
+	if (_input_events_this_tick != 0) {
+		/* HandleAutoscroll is called only once per GameLoop() - so we can clear the counter here */
+		_input_events_this_tick = 0;
+		/* there were some inputs this tick, don't scroll ??? */
+		return;
+	}
+
+	if (_patches.autoscroll && _game_mode != GM_MENU && !IsGeneratingWorld()) {
+		w = FindWindowFromPt(x, y);
+		if (w == NULL || w->flags4 & WF_DISABLE_VP_SCROLL) return;
+		vp = IsPtInWindowViewport(w, x, y);
+		if (vp != NULL) {
+			x -= vp->left;
+			y -= vp->top;
+			//here allows scrolling in both x and y axis
+#define scrollspeed 3
+			if (x - 15 < 0) {
+				WP(w, vp_d).scrollpos_x += (x - 15) * scrollspeed << vp->zoom;
+			} else if (15 - (vp->width - x) > 0) {
+				WP(w, vp_d).scrollpos_x += (15 - (vp->width - x)) * scrollspeed << vp->zoom;
+			}
+			if (y - 15 < 0) {
+				WP(w, vp_d).scrollpos_y += (y - 15) * scrollspeed << vp->zoom;
+			} else if (15 - (vp->height - y) > 0) {
+				WP(w,vp_d).scrollpos_y += (15 - (vp->height - y)) * scrollspeed << vp->zoom;
+			}
+#undef scrollspeed
+		}
+	}
+}
+
+void MouseLoop(int click, int mousewheel)
+{
+	int x,y;
+	Window *w;
+	ViewPort *vp;
+
+	DecreaseWindowCounters();
+	HandlePlacePresize();
+	UpdateTileSelection();
+	if (!VpHandlePlaceSizingDrag())  return;
+	if (!HandleDragDrop())           return;
+	if (!HandlePopupMenu())          return;
+	if (!HandleWindowDragging())     return;
+	if (!HandleScrollbarScrolling()) return;
+	if (!HandleViewportScroll())     return;
+	if (!HandleMouseOver())          return;
+
+	x = _cursor.pos.x;
+	y = _cursor.pos.y;
+
+	if (click == 0 && mousewheel == 0) return;
+
+	w = FindWindowFromPt(x, y);
+	if (w == NULL) return;
+	if (!MaybeBringWindowToFront(w)) return;
+	vp = IsPtInWindowViewport(w, x, y);
+
+	/* Don't allow any action in a viewport if either in menu of in generating world */
+	if (vp != NULL && (_game_mode == GM_MENU || IsGeneratingWorld())) return;
+
+	if (mousewheel != 0) {
+		WindowEvent e;
+
+		/* Send WE_MOUSEWHEEL event to window */
+		e.event = WE_MOUSEWHEEL;
+		e.we.wheel.wheel = mousewheel;
+		w->wndproc(w, &e);
+
+		/* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
+		if (vp == NULL) DispatchMouseWheelEvent(w, GetWidgetFromPos(w, x - w->left, y - w->top), mousewheel);
+	}
+
+	if (vp != NULL) {
+		switch (click) {
+			case 1:
+				DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
+				if (_thd.place_mode != 0 &&
+						// query button and place sign button work in pause mode
+						_cursor.sprite != SPR_CURSOR_QUERY &&
+						_cursor.sprite != SPR_CURSOR_SIGN &&
+						_pause != 0 &&
+						!_cheats.build_in_pause.value) {
+					return;
+				}
+
+				if (_thd.place_mode == 0) {
+					HandleViewportClicked(vp, x, y);
+				} else {
+					PlaceObject();
+				}
+				break;
+
+			case 2:
+				if (!(w->flags4 & WF_DISABLE_VP_SCROLL)) {
+					_scrolling_viewport = true;
+					_cursor.fix_at = true;
+				}
+				break;
+		}
+	} else {
+		switch (click) {
+			case 1: DispatchLeftClickEvent(w, x - w->left, y - w->top);  break;
+			case 2: DispatchRightClickEvent(w, x - w->left, y - w->top); break;
+		}
+	}
+}
+
+void HandleMouseEvents(void)
+{
+	int click;
+	int mousewheel;
+
+	/*
+	 * During the generation of the world, there might be
+	 * another thread that is currently building for example
+	 * a road. To not interfere with those tasks, we should
+	 * NOT change the _current_player here.
+	 *
+	 * This is not necessary either, as the only events that
+	 * can be handled are the 'close application' events
+	 */
+	if (!IsGeneratingWorld()) _current_player = _local_player;
+
+	// Mouse event?
+	click = 0;
+	if (_left_button_down && !_left_button_clicked) {
+		_left_button_clicked = true;
+		click = 1;
+		_input_events_this_tick++;
+	} else if (_right_button_clicked) {
+		_right_button_clicked = false;
+		click = 2;
+		_input_events_this_tick++;
+	}
+
+	mousewheel = 0;
+	if (_cursor.wheel) {
+		mousewheel = _cursor.wheel;
+		_cursor.wheel = 0;
+		_input_events_this_tick++;
+	}
+
+	MouseLoop(click, mousewheel);
+}
+
+void InputLoop(void)
+{
+	HandleMouseEvents();
+	HandleAutoscroll();
+}
+
+void UpdateWindows(void)
+{
+	Window* const *wz;
+	static int we4_timer = 0;
+	int t = we4_timer + 1;
+
+	if (t >= 100) {
+		for (wz = _last_z_window; wz != _z_windows;) {
+			CallWindowEventNP(*--wz, WE_4);
+		}
+		t = 0;
+	}
+	we4_timer = t;
+
+	for (wz = _last_z_window; wz != _z_windows;) {
+		Window *w = *--wz;
+		if (w->flags4 & WF_WHITE_BORDER_MASK) {
+			w->flags4 -= WF_WHITE_BORDER_ONE;
+
+			if (!(w->flags4 & WF_WHITE_BORDER_MASK)) SetWindowDirty(w);
+		}
+	}
+
+	DrawDirtyBlocks();
+
+	FOR_ALL_WINDOWS(wz) {
+		if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
+	}
+	DrawTextMessage();
+	// Redraw mouse cursor in case it was hidden
+	DrawMouseCursor();
+}
+
+
+int GetMenuItemIndex(const Window *w, int x, int y)
+{
+	if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) {
+		y /= 10;
+
+		if (y < WP(w, const menu_d).item_count &&
+				!HASBIT(WP(w, const menu_d).disabled_items, y)) {
+			return y;
+		}
+	}
+	return -1;
+}
+
+void InvalidateWindow(WindowClass cls, WindowNumber number)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == cls && w->window_number == number) SetWindowDirty(w);
+	}
+}
+
+void InvalidateWidget(const Window *w, byte widget_index)
+{
+	const Widget *wi = &w->widget[widget_index];
+
+	/* Don't redraw the window if the widget is invisible or of no-type */
+	if (wi->type == WWT_EMPTY || IsWindowWidgetHidden(w, widget_index)) return;
+
+	SetDirtyBlocks(w->left + wi->left, w->top + wi->top, w->left + wi->right + 1, w->top + wi->bottom + 1);
+}
+
+void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		const Window *w = *wz;
+		if (w->window_class == cls && w->window_number == number) {
+			InvalidateWidget(w, widget_index);
+		}
+	}
+}
+
+void InvalidateWindowClasses(WindowClass cls)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		if ((*wz)->window_class == cls) SetWindowDirty(*wz);
+	}
+}
+
+void InvalidateThisWindowData(Window *w)
+{
+	CallWindowEventNP(w, WE_INVALIDATE_DATA);
+	SetWindowDirty(w);
+}
+
+void InvalidateWindowData(WindowClass cls, WindowNumber number)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w);
+	}
+}
+
+void InvalidateWindowClassesData(WindowClass cls)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz);
+	}
+}
+
+void CallWindowTickEvent(void)
+{
+	Window* const *wz;
+
+	for (wz = _last_z_window; wz != _z_windows;) {
+		CallWindowEventNP(*--wz, WE_TICK);
+	}
+}
+
+void DeleteNonVitalWindows(void)
+{
+	Window* const *wz;
+
+restart_search:
+	/* When we find the window to delete, we need to restart the search
+	 * as deleting this window could cascade in deleting (many) others
+	 * anywhere in the z-array */
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		if (w->window_class != WC_MAIN_WINDOW &&
+				w->window_class != WC_SELECT_GAME &&
+				w->window_class != WC_MAIN_TOOLBAR &&
+				w->window_class != WC_STATUS_BAR &&
+				w->window_class != WC_TOOLBAR_MENU &&
+				w->window_class != WC_TOOLTIPS &&
+				(w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned'
+
+			DeleteWindow(w);
+			goto restart_search;
+		}
+	}
+}
+
+/* It is possible that a stickied window gets to a position where the
+ * 'close' button is outside the gaming area. You cannot close it then; except
+ * with this function. It closes all windows calling the standard function,
+ * then, does a little hacked loop of closing all stickied windows. Note
+ * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
+void DeleteAllNonVitalWindows(void)
+{
+	Window* const *wz;
+
+	/* Delete every window except for stickied ones, then sticky ones as well */
+	DeleteNonVitalWindows();
+
+restart_search:
+	/* When we find the window to delete, we need to restart the search
+	 * as deleting this window could cascade in deleting (many) others
+	 * anywhere in the z-array */
+	FOR_ALL_WINDOWS(wz) {
+		if ((*wz)->flags4 & WF_STICKY) {
+			DeleteWindow(*wz);
+			goto restart_search;
+		}
+	}
+}
+
+/* Delete all always on-top windows to get an empty screen */
+void HideVitalWindows(void)
+{
+	DeleteWindowById(WC_MAIN_TOOLBAR, 0);
+	DeleteWindowById(WC_STATUS_BAR, 0);
+}
+
+int PositionMainToolbar(Window *w)
+{
+	DEBUG(misc, 5, "Repositioning Main Toolbar...");
+
+	if (w == NULL || w->window_class != WC_MAIN_TOOLBAR) {
+		w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+	}
+
+	switch (_patches.toolbar_pos) {
+		case 1:  w->left = (_screen.width - w->width) / 2; break;
+		case 2:  w->left = _screen.width - w->width; break;
+		default: w->left = 0;
+	}
+	SetDirtyBlocks(0, 0, _screen.width, w->height); // invalidate the whole top part
+	return w->left;
+}
+
+void RelocateAllWindows(int neww, int newh)
+{
+	Window* const *wz;
+
+	FOR_ALL_WINDOWS(wz) {
+		Window *w = *wz;
+		int left, top;
+
+		if (w->window_class == WC_MAIN_WINDOW) {
+			ViewPort *vp = w->viewport;
+			vp->width = w->width = neww;
+			vp->height = w->height = newh;
+			vp->virtual_width = neww << vp->zoom;
+			vp->virtual_height = newh << vp->zoom;
+			continue; // don't modify top,left
+		}
+
+		/* XXX - this probably needs something more sane. For example specying
+		 * in a 'backup'-desc that the window should always be centred. */
+		switch (w->window_class) {
+			case WC_MAIN_TOOLBAR:
+				top = w->top;
+				left = PositionMainToolbar(w); // changes toolbar orientation
+				break;
+
+			case WC_SELECT_GAME:
+			case WC_GAME_OPTIONS:
+			case WC_NETWORK_WINDOW:
+				top = (newh - w->height) >> 1;
+				left = (neww - w->width) >> 1;
+				break;
+
+			case WC_NEWS_WINDOW:
+				top = newh - w->height;
+				left = (neww - w->width) >> 1;
+				break;
+
+			case WC_STATUS_BAR:
+				top = newh - w->height;
+				left = (neww - w->width) >> 1;
+				break;
+
+			case WC_SEND_NETWORK_MSG:
+				top = (newh - 26); // 26 = height of status bar + height of chat bar
+				left = (neww - w->width) >> 1;
+				break;
+
+			case WC_CONSOLE:
+				IConsoleResize(w);
+				continue;
+
+			default:
+				left = w->left;
+				if (left + (w->width >> 1) >= neww) left = neww - w->width;
+				top = w->top;
+				if (top + (w->height >> 1) >= newh) top = newh - w->height;
+				break;
+		}
+
+		if (w->viewport != NULL) {
+			w->viewport->left += left - w->left;
+			w->viewport->top += top - w->top;
+		}
+
+		w->left = left;
+		w->top = top;
+	}
+}