diff -r e16bdc0054ce cm_changelog.txt
--- /dev/null
+++ b/cm_changelog.txt
@@ -0,0 +1,311 @@
+== ATTENTION ==
+The client circumvents the OpenTTD version checks to be able to join unpatched multiplayer games.
+Because of this, if you encounter any bug, report it to CityMania team as it may be connected to patches included.
+Unless you encouter the same bug on unpatched OpenTTD client do not report it to OpenTTD development team.
+
+
+== INSTALL ==
+Unlike Novapolis client Citymania one is shipped as a complete package, not
+just a patch, so it no longer needs vanila OpenTTD installation to work.
+But it can also be installed in the same old way described below.
+
+If you have shared OpenTTD folder, you can just unzip anywhere and launch
+If you dont use shared folder, unzip into your OpenTTD folder
+innerhighlight.grf in data folder is required, copy it to data or content_download/data folder
+
+
+== PRO INSTALL ==
+WINDOWS
+Possible situations:
+1) Installing stable release from openttd.org, install also with graphics and sound sets (only graphic are required)
+	Install the package. It will create game files in %Program Files%/OpenTTD and user files in %USER_PROFILE%/Documents/OpenTTD
+	To gain advantage of shared folder, copy all files except LANG folder and OPENTTD.EXE from %Program Files%/OpenTTD to %USER_PROFILE%/Documents/OpenTTD
+	Now if you can unzip this client anywhere and if openttd.exe stays with its lang/folder, you can launch it from any place
+	This will also you enable you to use any number or openttd versions/clients
+2) Installing stable release from zip
+	Download zip and also graphics set zip.
+	Unzip both into the same folder. Graphics set belong to BASESET or DATA folder
+	Launch the openttd.exe (if there is openttd.cfg already, delete it)
+	Quit OpenTTD. Now it created user files in your User profile
+	Copy all files except LANG folder and OPENTTD.EXE into User profile folder called OpenTTD
+	This will enable you to use any number or openttd versions/clients under condition you keep openttd.exe and its lang files in one folder (every client comes with binary and lang folder at least)
+LINUX
+CityMania does not ship linux client. Your only chance is to download source package and compile it by yourself.
+Process is easy and simple guide is at http://wiki.openttd.org/Compiling_on_(GNU/)Linux_and_*BSD
+
+
+== LOGIN SYSTEM ==
+Community Login system - login window. Atm accessible only by defining hotkey for it.
+- Please read carefully about new login system if you intend to use it
+- new login system for CityMania and also for n-ice and BTPro, login date are stored in new config file novapolis.cfg
+	- login window can be opened via landinfo dropdown mene or a hotkey can be associated with it, for example CTRL+L
+
+	- login is saved by entering text via OpenTTD forms. Remember that OpenTTD shows real letters when entering any text
+	- TODO novapolis password is stored encrypted and login string is sent via ingame chat privately to server
+		so no one can see it
+	- n-ice and BTPro uses token system. In order to retrieve the token, client has to log to their websites
+		obtain the token here and enter it in ingame chat
+		Alternatively both communities implemented a system, that one can open a dedicated webpage
+		and enter username and password there to obtain the token, which is used in n-ice and BTPro
+		patched OpenTTD client and CityMania client uses it too.
+		Once token is retrieved, it is sent via ingame chat privately to server
+		so no one can see it
+
+		!!! Be aware, that the token login webpage needs decrypted password, so this decrypted password
+		is stored in novapolis.cfg file and send decrypted via OpenTTD to their website
+		Thus do not provide novapolis.cfg file to any one!
+		N-ice and BTPro are 3rd side and Novapolis cannot guarantee safety of the login to their community
+		and should they change the login system, CityMania client login will not work for both of them
+
+
+== SCRIPTS ==
+autoexec.scr contains some predefined aliases for connecting on CityMania server
+In game press ~ (above tab key) and write "cm<number>", e.g. "cm1". This will connect you to desired server
+This is usable for any OpenTTD servers
+
+If you want to use login alias, you will have to rewrite "nick" and "password" to your actual CityMania account.
+However bear in mind, if you accidentally launch this alias on another server, you will uncover your password
+
+
+== OPENTTD.CFG ==
+In openttd.cfg.example are lines you can add to your openttd.cfg to have CityMania servers available in multiplayer menu all the time without searching for games
+This is usable for any OpenTTD servers
+
+
+== CHANGELOG ==
+
+*** 1.6.0 (2 Apr 2016) ***
+- Added active stations highlight to town zoning. Outlines stations that have been serviced in last ~50 days (as in checks for authority rating and town growth rate).
+- Fixed next counter in town window (was always showing -1 in case of custom growth rate). Also show * after GR value for a custom rate (set by GameScript or server patch).
+- Detailed station ratings tooltip (hover over rating in station window).
+- Make cargo window look better, especially in double/quad interface size.
+- Added real population to town directory, towns can be sorted by it too.
+- Added experimental "New CB border" zone in zoning tool. Meant to replace old CB borders for new game modes, but is not used anywhere just yet.
+
+*** 1.5.3 (3 Dec 2015) ***
+- Update to OpenTTD 1.5.3
+- Fixed crash when pressing Ctrl while building tramways.
+
+*** 1.5.3-RC1 (3 Nov 2015) ***
+- Update to OpenTTD 1.5.3-RC1
+
+*** 1.5.2/30 (2 Sep 2015) ***
+- Fixed fast server change buttons
+- Fixed extra data saving (crashed when opening saves).
+
+*** 1.5.1-2/29 (16 Jun 2015) ***
+- Stores most of CityMania client extra data in savegame
+	- Includes CB info (deliveries/requirements/etc.), RTM/DTM, CS/HS/HR and town growth zoning.
+	- It also means that all of these are now synchronized when you join CityMania servers.
+	- Savegame is compatible with unmodified clients (they obviously don't understand extra data, but preserve it intact).
+- Fixed OpenTTD version detection in source package.
+
+*** v28-151 (3 Jun 2015)***
+- Renamed to CityMania client as successor of Novapolis, community-related things changed accordingly.
+- Now is shipped in a complete package, similar to vanila OpenTTD, so no longer require it to be installed first.
+- Providing complete source pack instead of just diff
+- Also note that town growth mechanics is changed a bit in 1.5.1. It's now safe (no CS) to keep depots and extra roadbits in town. And previously HS cases become CS. Now HS can only happen when town is allowed to build roads and decides to build one instead of house.
+- Show houses count in towns list, towns can be sorted by it too.
+
+*** v27-150 ***
+- Land info tool works as tooltip, can also be used to mesure distances by dragging
+- land_info hotkey (no default)
+- Money and houses settings for powerfunding
+- Setting to disable "runway too short" warning
+- Some visual improvements for double/quad interface sizes and rtl languages
+
+*** v26-150rc1 ***
+Prepared by dp
+
+Update to 1.5.0-RC1
+- Regular advertisement and powerfunding (in CB window)
+- Regular funding is now smarter
+- Full tile autoroad is replaced with CB autoroad which is more like regular autoroad, but also tries to avoid half-tile dead ends and redundant roadbits
+- station_sized and station_dragdrop hotkeys to start building station directly in fixed size or drag&drop mode
+- toggle_fullscreen hotkey
+- zoning hotkeys can be global
+- Industry funding window has option to highlight tiles where industry can't be build regardless of terrain. Note that it works quite slow and can cause lags so use with caution
+- GR and next displays once again show proper values
+- Polyrail tool updated to version 10b, noticable changes:
+--- Ending line with double click no longer interferes with building quickly so setting for disabling it was removed
+--- Tool can now be started in non-snapping mode (new line) with new_polyline hotkey (CTRL+SHIFT+A)
+--- No longer shows error if no new tracks were built, only changes snap point
+
+*** v25-150b2 ***
+Update to 1.5.0-beta2
+
+*** v24-150b1 ***
+Update to 1.5.0-beta1
+
+*** v23-144 ***
+Town gui - hotkey for building statue
+Statue will be also built when doing Ctrl + click on town name
+Fixing bugs in login window
+- no crash on doubleclick
+- now working with non asci characters in login entries
+
+*** v22-144 ***
+- Community login system - read above
+- hotkeys for industry funding, adv. settings window, newgrf window and login window, by default not assigned
+- added setting to choose finishing polyrail by double click
+- cb window updated more often
+- Fund regularly button in CB window is toggled when clicked
+- Cargo commands gui in commands window are changed and one is added
+- Town window
+	-Houses under construction are hopefully diplayed properly and houses under reconstruction are showed only per month
+
+*** v21-144 ***
+Zoning tool
+ - window made smaller - removed unnecessary lines, clicking on selected button will deselect it
+ - hotkeys for all buttons, default is SHIFT+{number}
+Town window
+ - new line: Houses: UC - under construction, UR - under reconstruction (being rebuilt), DTM - demolished this month
+ - hotkeys for buttons. No default key is set. Hotkey for CB button will open CB window for any town even in single player
+CB window
+ - added more lines (from Town window)
+ - added hotkeys for small and medium advertisement (not set by default)
+ - added Fund regularly button
+Fund regularly feature
+ - Can be de/activated in CB window only
+ - Will fund buildings whenever fund buildings goes down to 0 months. Company needs money to use it
+ - any number of towns can have this activated, but it is costly
+ - !!! Use with caution as it drains money away
+
+*** v20-144 ***
+Update to 1.4.4
+Zoning gui revised. Zoning tiles are more colourful.
+Zoning hotkey (default none, recommended CTRL+Z)
+New innerhighlight.grf
+
+*** v19-143 ***
+Update to 1.4.3
+
+*** v18-142 ***
+Extended tooltips inspired by MJP's patch (http://www.tt-forums.net/viewtopic.php?f=33&t=53394)
+ - hover over industry or station to see cargos and its ratings
+ - can be disabled in gui setting
+More hotkeys
+ - close vehicle order window
+ - refit and clone vehicle from vehicle window while in depot
+ - tree hotkey switches tree window between active/inactive
+Changes
+ - local authority detail for all companies in town authority window
+ - potential population and authority detail number moved from header to town details part ot town window
+
+*** v17-141 ***
+Hotkeys for town management removed from town view window
+
+
+*** v16-140 ***
+Option for depots and road stations to automatically choose direction
+Fixed width of companies dropdown in toolbar
+Fixed client version in diff
+
+*** v15-140 ***
+Update to 1.4.0
+New autoroad tool that builds only full tile roads
+Show potential town population (including unfinished buildings) in town view window toolbar
+Hotkey for borrowing all money (no default binding)
+Double click in polyrail mode no longer finishes current line
+
+*** v14-140b5 ***
+1.4.0-beta5 client
+
+*** v13-133 ***
+Fixed 32bit binary (problem in WinXP)
+Fix crash when pressed trees hotkey in spectating mode
+Fixed gui problem with extra sprites, when too many new sprites were loaded
+Fixed login query. Input is now both '<name> <password>'
+
+*** v12-133 ***
+New town growth counters and zones (for zoning GUI) Unfinished wiki article
+Replaced "from" column in CB GUI with storage usage %
+Vehicle cloning hotkey in depot(no default), advertise hotkeys for town authority and town info windows (CTRL+V for large advertisemetn), funding hotkey for town info window(CTRL+F).
+Zoning GUI changes: new advertisement range and CB town borders zones, "town borders" renamed to "town zones" and now shows more zones.
+CB GUI fixed
+
+*** v11-133 ***
+Fix nova client extra hotkeys
+
+*** v10-133 ***
+Update to 1.3.3
+Added quick button for NS16
+Town gui new GR/next/flag calculation
+
+*** v9-132 ***
+New innerhighlight.grf file !!!
+Added goal gui button to toolbar. You can now easily access it and also see other companies goal progress (partially backported from official trunk)
+Moved watch gui to toolbar
+Added teamchat option to watch gui - when clicked on dot next to company colour, you will teamchat with that company
+Goal gui height is adjusted according to current number of goals (lines)
+Zoning gui fixes and unused parts reduction (thanks to dp for fixes)
+
+*** v8-132 ***
+Added:
+Watchgui patch by Muxy
+
+*** v7-132 ***
+New Client Version check - upon joining Novapolis server, a message will pop up if there is update available
+CB gui - When you join Novapolis City builder server, there will be a new button in town window with cargos delivered (merged from city builder client)
+       - this works only on Novapolis City builder servers
+New button in Novapolis commands gui (HELP topic 6)
+
+*** v6-132 ***
+New hotkeys, changes to hotkeys (can be altered in hotkeys.cfg)
+'R' Build new vehicle, when vehicle purchase list is active
+CTRL+'F' START/STOP all vehicles in active depot
+'B' Open Vehicle purchase list from Depot window
+'G' Open orders window when a vehicle window is active
+'Z' START/STOP vehicle when a vehicle window is active
+CTRL+'S' Build statue in active town
+CTRL+'F' Fund buildings in active town
+
+*** v5-132 ***
+64bit version package
+New hotkeys:
+'G' Open orders window when a vehicle window is active
+'X' START/STOP vehicle when a vehicle window is active
+'CTRL+X' Start all vehicles in depot
+NS8 quick connect button added
+
+*** v4-132 ***
+Update to 1.3.2
+New buttons: quick connect to NSX3, login data input, autologin (requires login data input first)
+Due to new support of Brahmic languages, some language libraries are required and binary is a little bigger.
+
+*** v3-131 ***
+new buttons to commands gui
+filter for Novapolis servers in server list
+polyline patch fix (fixes missing coverage area for dock)
+
+*** v2-131 ***
+Hotkeys for several events: defaults: N:Commands windows, CTRL+H:build HQ, CTRL+F4:goal gui, CTRL+F2:cargo table
+Updated direct server connect buttons to new IP
+
+*** v1-130 ***
+Client created
+
+Patch
+Watch Company Gui - by Muxy http://www.openttd.fr/
+Polyline patch - by adf88 http://www.tt-forums.net/viewtopic.php?f=33&t=57080&hilit=polyline
+Zoning patch - by Svip http://www.tt-forums.net/viewtopic.php?f=33&t=33701&start=40
+Orders control with alt/ctrl/shift and setting gui - by blup
+Transported cargo table - by Honza_ http://www.tt-forums.net/viewtopic.php?f=33&t=62339
+City names in different colour - by Honza_ http://www.tt-forums.net/viewtopic.php?f=33&t=63844
+Novapolis commands gui - by xi (found under question mark menu, only available when connected on Novapolis servers)
+
+Option to select old depot train length display - by The Dude
+Income and delivery graph can display data of individual cargos - by The Dude
+Industry directory filter - author unknown
+Rating in town label - by Terkhen http://www.tt-forums.net/viewtopic.php?f=33&t=42598&hilit=rating+label
+Manhatten and square distance of vehicle route in orders gui - by The Dude
+Count of cities/towns - by The Dude
+Hotkey for Goal Gui and HQ placement - by The Dude
+
+Script
+Aliases for connecting to Novapolis servers
+Aliases for login on Novapolis servers
+
+
+
+Special thanks to authors of the patched included and to OpenTTD development team for developing the game further.
diff -r e16bdc0054ce cmclient.sublime-project
--- /dev/null
+++ b/cmclient.sublime-project
@@ -0,0 +1,22 @@
+{
+	"build_systems":
+	[
+		{
+			"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
+			"name": "Anaconda Python Builder",
+			"selector": "source.python",
+			"shell_cmd": "python -u \"$file\""
+		}
+	],
+	"folders":
+	[
+		{
+			"file_exclude_patterns":
+			[
+				"*.cod"
+			],
+			"follow_symlinks": true,
+			"path": "."
+		}
+	]
+}
diff -r e16bdc0054ce projects/openttd_vs100.vcxproj
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -295,6 +295,7 @@
     <ClCompile Include="..\src\animated_tile.cpp" />
     <ClCompile Include="..\src\articulated_vehicles.cpp" />
     <ClCompile Include="..\src\autoreplace.cpp" />
+    <ClCompile Include="..\src\bitstream.cpp" />
     <ClCompile Include="..\src\bmp.cpp" />
     <ClCompile Include="..\src\cargoaction.cpp" />
     <ClCompile Include="..\src\cargomonitor.cpp" />
@@ -402,8 +403,10 @@
     <ClInclude Include="..\src\base_media_base.h" />
     <ClInclude Include="..\src\base_media_func.h" />
     <ClInclude Include="..\src\base_station_base.h" />
+    <ClInclude Include="..\src\bitstream.h" />
     <ClInclude Include="..\src\bmp.h" />
     <ClInclude Include="..\src\bridge.h" />
+    <ClInclude Include="..\src\cargo_table_gui.h" />
     <ClInclude Include="..\src\cargo_type.h" />
     <ClInclude Include="..\src\cargoaction.h" />
     <ClInclude Include="..\src\cargomonitor.h" />
@@ -647,6 +650,7 @@
     <ClInclude Include="..\src\viewport_func.h" />
     <ClInclude Include="..\src\viewport_sprite_sorter.h" />
     <ClInclude Include="..\src\viewport_type.h" />
+    <ClInclude Include="..\src\watch_gui.h" />
     <ClInclude Include="..\src\water.h" />
     <ClInclude Include="..\src\waypoint_base.h" />
     <ClInclude Include="..\src\waypoint_func.h" />
@@ -658,6 +662,7 @@
     <ClInclude Include="..\src\window_func.h" />
     <ClInclude Include="..\src\window_gui.h" />
     <ClInclude Include="..\src\window_type.h" />
+    <ClInclude Include="..\src\zoning.h" />
     <ClInclude Include="..\src\zoom_func.h" />
     <ClInclude Include="..\src\zoom_type.h" />
     <ClCompile Include="..\src\core\alloc_func.cpp" />
@@ -694,7 +699,9 @@
     <ClCompile Include="..\src\bootstrap_gui.cpp" />
     <ClCompile Include="..\src\bridge_gui.cpp" />
     <ClCompile Include="..\src\build_vehicle_gui.cpp" />
+    <ClCompile Include="..\src\cargo_table_gui.cpp" />
     <ClCompile Include="..\src\cheat_gui.cpp" />
+    <ClCompile Include="..\src\commands_gui.cpp" />
     <ClCompile Include="..\src\company_gui.cpp" />
     <ClCompile Include="..\src\console_gui.cpp" />
     <ClCompile Include="..\src\date_gui.cpp" />
@@ -743,14 +750,17 @@
     <ClCompile Include="..\src\transparency_gui.cpp" />
     <ClCompile Include="..\src\tree_gui.cpp" />
     <ClCompile Include="..\src\vehicle_gui.cpp" />
+    <ClCompile Include="..\src\watch_gui.cpp" />
     <ClCompile Include="..\src\viewport_gui.cpp" />
     <ClCompile Include="..\src\waypoint_gui.cpp" />
+    <ClCompile Include="..\src\zoning_gui.cpp" />
     <ClInclude Include="..\src\widgets\airport_widget.h" />
     <ClInclude Include="..\src\widgets\ai_widget.h" />
     <ClInclude Include="..\src\widgets\autoreplace_widget.h" />
     <ClInclude Include="..\src\widgets\bootstrap_widget.h" />
     <ClInclude Include="..\src\widgets\bridge_widget.h" />
     <ClInclude Include="..\src\widgets\build_vehicle_widget.h" />
+    <ClInclude Include="..\src\widgets\cargo_table_widget.h" />
     <ClInclude Include="..\src\widgets\cheat_widget.h" />
     <ClInclude Include="..\src\widgets\company_widget.h" />
     <ClInclude Include="..\src\widgets\console_widget.h" />
@@ -828,6 +838,7 @@
     <ClCompile Include="..\src\void_cmd.cpp" />
     <ClCompile Include="..\src\water_cmd.cpp" />
     <ClCompile Include="..\src\waypoint_cmd.cpp" />
+    <ClCompile Include="..\src\zoning_cmd.cpp" />
     <ClCompile Include="..\src\saveload\afterload.cpp" />
     <ClCompile Include="..\src\saveload\ai_sl.cpp" />
     <ClCompile Include="..\src\saveload\airport_sl.cpp" />
@@ -835,6 +846,8 @@
     <ClCompile Include="..\src\saveload\autoreplace_sl.cpp" />
     <ClCompile Include="..\src\saveload\cargomonitor_sl.cpp" />
     <ClCompile Include="..\src\saveload\cargopacket_sl.cpp" />
+    <ClCompile Include="..\src\saveload\citymania_sl.cpp" />
+    <ClInclude Include="..\src\saveload\citymania_sl.h" />
     <ClCompile Include="..\src\saveload\cheat_sl.cpp" />
     <ClCompile Include="..\src\saveload\company_sl.cpp" />
     <ClCompile Include="..\src\saveload\depot_sl.cpp" />
diff -r e16bdc0054ce projects/openttd_vs100.vcxproj.filters
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -114,6 +114,9 @@
     <ClCompile Include="..\src\autoreplace.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\bitstream.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\bmp.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -435,12 +438,18 @@
     <ClInclude Include="..\src\base_station_base.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\bitstream.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\bmp.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="..\src\bridge.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\cargo_table_gui.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\cargo_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1170,6 +1179,9 @@
     <ClInclude Include="..\src\viewport_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\watch_gui.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\water.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1203,6 +1215,9 @@
     <ClInclude Include="..\src\window_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\zoning.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\zoom_func.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1311,9 +1326,15 @@
     <ClCompile Include="..\src\build_vehicle_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\cargo_table_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\cheat_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\commands_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\company_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
@@ -1458,12 +1479,18 @@
     <ClCompile Include="..\src\vehicle_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\watch_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\viewport_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
     <ClCompile Include="..\src\waypoint_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\zoning_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClInclude Include="..\src\widgets\airport_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
@@ -1482,6 +1509,9 @@
     <ClInclude Include="..\src\widgets\build_vehicle_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\widgets\cargo_table_widget.h">
+      <Filter>Widgets</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\widgets\cheat_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
@@ -1713,6 +1743,9 @@
     <ClCompile Include="..\src\waypoint_cmd.cpp">
       <Filter>Command handlers</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\zoning_cmd.cpp">
+      <Filter>Command handlers</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\saveload\afterload.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
@@ -1734,6 +1767,12 @@
     <ClCompile Include="..\src\saveload\cargopacket_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\saveload\citymania_sl.cpp">
+      <Filter>Save/Load handlers</Filter>
+    </ClCompile>
+    <ClInclude Include="..\src\saveload\citymania_sl.h">
+      <Filter>Save/Load handlers</Filter>
+    </ClInclude>
     <ClCompile Include="..\src\saveload\cheat_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
diff -r e16bdc0054ce projects/openttd_vs140.vcxproj
--- a/projects/openttd_vs140.vcxproj
+++ b/projects/openttd_vs140.vcxproj
@@ -312,6 +312,7 @@
     <ClCompile Include="..\src\animated_tile.cpp" />
     <ClCompile Include="..\src\articulated_vehicles.cpp" />
     <ClCompile Include="..\src\autoreplace.cpp" />
+    <ClCompile Include="..\src\bitstream.cpp" />
     <ClCompile Include="..\src\bmp.cpp" />
     <ClCompile Include="..\src\cargoaction.cpp" />
     <ClCompile Include="..\src\cargomonitor.cpp" />
@@ -419,8 +420,10 @@
     <ClInclude Include="..\src\base_media_base.h" />
     <ClInclude Include="..\src\base_media_func.h" />
     <ClInclude Include="..\src\base_station_base.h" />
+    <ClInclude Include="..\src\bitstream.h" />
     <ClInclude Include="..\src\bmp.h" />
     <ClInclude Include="..\src\bridge.h" />
+    <ClInclude Include="..\src\cargo_table_gui.h" />
     <ClInclude Include="..\src\cargo_type.h" />
     <ClInclude Include="..\src\cargoaction.h" />
     <ClInclude Include="..\src\cargomonitor.h" />
@@ -664,6 +667,7 @@
     <ClInclude Include="..\src\viewport_func.h" />
     <ClInclude Include="..\src\viewport_sprite_sorter.h" />
     <ClInclude Include="..\src\viewport_type.h" />
+    <ClInclude Include="..\src\watch_gui.h" />
     <ClInclude Include="..\src\water.h" />
     <ClInclude Include="..\src\waypoint_base.h" />
     <ClInclude Include="..\src\waypoint_func.h" />
@@ -675,6 +679,7 @@
     <ClInclude Include="..\src\window_func.h" />
     <ClInclude Include="..\src\window_gui.h" />
     <ClInclude Include="..\src\window_type.h" />
+    <ClInclude Include="..\src\zoning.h" />
     <ClInclude Include="..\src\zoom_func.h" />
     <ClInclude Include="..\src\zoom_type.h" />
     <ClCompile Include="..\src\core\alloc_func.cpp" />
@@ -711,7 +716,9 @@
     <ClCompile Include="..\src\bootstrap_gui.cpp" />
     <ClCompile Include="..\src\bridge_gui.cpp" />
     <ClCompile Include="..\src\build_vehicle_gui.cpp" />
+    <ClCompile Include="..\src\cargo_table_gui.cpp" />
     <ClCompile Include="..\src\cheat_gui.cpp" />
+    <ClCompile Include="..\src\commands_gui.cpp" />
     <ClCompile Include="..\src\company_gui.cpp" />
     <ClCompile Include="..\src\console_gui.cpp" />
     <ClCompile Include="..\src\date_gui.cpp" />
@@ -760,14 +767,17 @@
     <ClCompile Include="..\src\transparency_gui.cpp" />
     <ClCompile Include="..\src\tree_gui.cpp" />
     <ClCompile Include="..\src\vehicle_gui.cpp" />
+    <ClCompile Include="..\src\watch_gui.cpp" />
     <ClCompile Include="..\src\viewport_gui.cpp" />
     <ClCompile Include="..\src\waypoint_gui.cpp" />
+    <ClCompile Include="..\src\zoning_gui.cpp" />
     <ClInclude Include="..\src\widgets\airport_widget.h" />
     <ClInclude Include="..\src\widgets\ai_widget.h" />
     <ClInclude Include="..\src\widgets\autoreplace_widget.h" />
     <ClInclude Include="..\src\widgets\bootstrap_widget.h" />
     <ClInclude Include="..\src\widgets\bridge_widget.h" />
     <ClInclude Include="..\src\widgets\build_vehicle_widget.h" />
+    <ClInclude Include="..\src\widgets\cargo_table_widget.h" />
     <ClInclude Include="..\src\widgets\cheat_widget.h" />
     <ClInclude Include="..\src\widgets\company_widget.h" />
     <ClInclude Include="..\src\widgets\console_widget.h" />
@@ -845,6 +855,7 @@
     <ClCompile Include="..\src\void_cmd.cpp" />
     <ClCompile Include="..\src\water_cmd.cpp" />
     <ClCompile Include="..\src\waypoint_cmd.cpp" />
+    <ClCompile Include="..\src\zoning_cmd.cpp" />
     <ClCompile Include="..\src\saveload\afterload.cpp" />
     <ClCompile Include="..\src\saveload\ai_sl.cpp" />
     <ClCompile Include="..\src\saveload\airport_sl.cpp" />
@@ -852,6 +863,8 @@
     <ClCompile Include="..\src\saveload\autoreplace_sl.cpp" />
     <ClCompile Include="..\src\saveload\cargomonitor_sl.cpp" />
     <ClCompile Include="..\src\saveload\cargopacket_sl.cpp" />
+    <ClCompile Include="..\src\saveload\citymania_sl.cpp" />
+    <ClInclude Include="..\src\saveload\citymania_sl.h" />
     <ClCompile Include="..\src\saveload\cheat_sl.cpp" />
     <ClCompile Include="..\src\saveload\company_sl.cpp" />
     <ClCompile Include="..\src\saveload\depot_sl.cpp" />
diff -r e16bdc0054ce projects/openttd_vs140.vcxproj.filters
--- a/projects/openttd_vs140.vcxproj.filters
+++ b/projects/openttd_vs140.vcxproj.filters
@@ -114,6 +114,9 @@
     <ClCompile Include="..\src\autoreplace.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\bitstream.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\bmp.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -435,12 +438,18 @@
     <ClInclude Include="..\src\base_station_base.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\bitstream.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\bmp.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="..\src\bridge.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\cargo_table_gui.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\cargo_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1170,6 +1179,9 @@
     <ClInclude Include="..\src\viewport_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\watch_gui.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\water.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1203,6 +1215,9 @@
     <ClInclude Include="..\src\window_type.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\zoning.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\zoom_func.h">
       <Filter>Header Files</Filter>
     </ClInclude>
@@ -1311,9 +1326,15 @@
     <ClCompile Include="..\src\build_vehicle_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\cargo_table_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\cheat_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\commands_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\company_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
@@ -1458,12 +1479,18 @@
     <ClCompile Include="..\src\vehicle_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\watch_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\viewport_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
     <ClCompile Include="..\src\waypoint_gui.cpp">
       <Filter>GUI Source Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\zoning_gui.cpp">
+      <Filter>GUI Source Code</Filter>
+    </ClCompile>
     <ClInclude Include="..\src\widgets\airport_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
@@ -1482,6 +1509,9 @@
     <ClInclude Include="..\src\widgets\build_vehicle_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\widgets\cargo_table_widget.h">
+      <Filter>Widgets</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\widgets\cheat_widget.h">
       <Filter>Widgets</Filter>
     </ClInclude>
@@ -1713,6 +1743,9 @@
     <ClCompile Include="..\src\waypoint_cmd.cpp">
       <Filter>Command handlers</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\zoning_cmd.cpp">
+      <Filter>Command handlers</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\saveload\afterload.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
@@ -1734,6 +1767,12 @@
     <ClCompile Include="..\src\saveload\cargopacket_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\saveload\citymania_sl.cpp">
+      <Filter>Save/Load handlers</Filter>
+    </ClCompile>
+    <ClInclude Include="..\src\saveload\citymania_sl.h">
+      <Filter>Save/Load handlers</Filter>
+    </ClInclude>
     <ClCompile Include="..\src\saveload\cheat_sl.cpp">
       <Filter>Save/Load handlers</Filter>
     </ClCompile>
diff -r e16bdc0054ce projects/openttd_vs80.vcproj
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -451,6 +451,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bitstream.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bmp.cpp"
 				>
 			</File>
@@ -883,6 +887,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bitstream.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bmp.h"
 				>
 			</File>
@@ -891,6 +899,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\cargo_table_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\cargo_type.h"
 				>
 			</File>
@@ -1863,6 +1875,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\watch_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\water.h"
 				>
 			</File>
@@ -1907,6 +1923,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\zoning.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\zoom_func.h"
 				>
 			</File>
@@ -2059,10 +2079,18 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\cargo_table_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\cheat_gui.cpp"
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\commands_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\company_gui.cpp"
 				>
 			</File>
@@ -2255,6 +2283,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\watch_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\viewport_gui.cpp"
 				>
 			</File>
@@ -2262,6 +2294,10 @@
 				RelativePath=".\..\src\waypoint_gui.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\..\src\zoning_gui.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Widgets"
@@ -2291,6 +2327,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\widgets\cargo_table_widget.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\widgets\cheat_widget.h"
 				>
 			</File>
@@ -2602,6 +2642,10 @@
 				RelativePath=".\..\src\waypoint_cmd.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\..\src\zoning_cmd.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Save/Load handlers"
@@ -2635,6 +2679,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\saveload\citymania_sl.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\saveload\citymania_sl.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\saveload\cheat_sl.cpp"
 				>
 			</File>
diff -r e16bdc0054ce projects/openttd_vs90.vcproj
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -448,6 +448,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bitstream.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bmp.cpp"
 				>
 			</File>
@@ -880,6 +884,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\bitstream.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\bmp.h"
 				>
 			</File>
@@ -888,6 +896,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\cargo_table_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\cargo_type.h"
 				>
 			</File>
@@ -1860,6 +1872,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\watch_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\water.h"
 				>
 			</File>
@@ -1904,6 +1920,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\zoning.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\zoom_func.h"
 				>
 			</File>
@@ -2056,10 +2076,18 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\cargo_table_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\cheat_gui.cpp"
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\commands_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\company_gui.cpp"
 				>
 			</File>
@@ -2252,6 +2280,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\watch_gui.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\viewport_gui.cpp"
 				>
 			</File>
@@ -2259,6 +2291,10 @@
 				RelativePath=".\..\src\waypoint_gui.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\..\src\zoning_gui.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Widgets"
@@ -2288,6 +2324,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\widgets\cargo_table_widget.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\widgets\cheat_widget.h"
 				>
 			</File>
@@ -2599,6 +2639,10 @@
 				RelativePath=".\..\src\waypoint_cmd.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\..\src\zoning_cmd.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Save/Load handlers"
@@ -2632,6 +2676,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\saveload\citymania_sl.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\saveload\citymania_sl.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\saveload\cheat_sl.cpp"
 				>
 			</File>
diff -r e16bdc0054ce release.zip
Binary file release.zip has changed
diff -r e16bdc0054ce source.list
--- a/source.list
+++ b/source.list
@@ -3,6 +3,7 @@
 animated_tile.cpp
 articulated_vehicles.cpp
 autoreplace.cpp
+bitstream.cpp
 bmp.cpp
 cargoaction.cpp
 cargomonitor.cpp
@@ -141,8 +142,10 @@
 base_media_base.h
 base_media_func.h
 base_station_base.h
+bitstream.h
 bmp.h
 bridge.h
+cargo_table_gui.h
 cargo_type.h
 cargoaction.h
 cargomonitor.h
@@ -386,6 +389,7 @@
 viewport_func.h
 viewport_sprite_sorter.h
 viewport_type.h
+watch_gui.h
 water.h
 waypoint_base.h
 waypoint_func.h
@@ -397,6 +401,7 @@
 window_func.h
 window_gui.h
 window_type.h
+zoning.h
 zoom_func.h
 zoom_type.h
 #if WIN32
@@ -452,7 +457,9 @@
 bootstrap_gui.cpp
 bridge_gui.cpp
 build_vehicle_gui.cpp
+cargo_table_gui.cpp
 cheat_gui.cpp
+commands_gui.cpp
 company_gui.cpp
 console_gui.cpp
 date_gui.cpp
@@ -501,8 +508,10 @@
 transparency_gui.cpp
 tree_gui.cpp
 vehicle_gui.cpp
+watch_gui.cpp
 viewport_gui.cpp
 waypoint_gui.cpp
+zoning_gui.cpp
 
 # Widgets
 widgets/airport_widget.h
@@ -511,6 +520,7 @@
 widgets/bootstrap_widget.h
 widgets/bridge_widget.h
 widgets/build_vehicle_widget.h
+widgets/cargo_table_widget.h
 widgets/cheat_widget.h
 widgets/company_widget.h
 widgets/console_widget.h
@@ -590,6 +600,7 @@
 void_cmd.cpp
 water_cmd.cpp
 waypoint_cmd.cpp
+zoning_cmd.cpp
 
 # Save/Load handlers
 saveload/afterload.cpp
@@ -599,6 +610,8 @@
 saveload/autoreplace_sl.cpp
 saveload/cargomonitor_sl.cpp
 saveload/cargopacket_sl.cpp
+saveload/citymania_sl.cpp
+saveload/citymania_sl.h
 saveload/cheat_sl.cpp
 saveload/company_sl.cpp
 saveload/depot_sl.cpp
diff -r e16bdc0054ce src/bitstream.cpp
--- /dev/null
+++ b/src/bitstream.cpp
@@ -0,0 +1,58 @@
+#include "bitstream.h"
+
+// Returns 8 higher bits of s-bit integer x
+#define FIRST8(x, s) (((x) >> ((s) - 8)) & 0xFF)
+
+void BitOStream::WriteBytes(uint32 value, int amount)
+{
+	do {
+		v = (v << 8) | FIRST8(value, amount << 3);
+		f.push_back(FIRST8(v, c + 8));
+	} while (--amount);
+}
+
+void BitOStream::WriteBytes64(uint64 value, int amount)
+{
+	do {
+		v = (v << 8) | FIRST8(value, amount << 3);
+		f.push_back(FIRST8(v, c + 8));
+	} while (--amount);
+}
+
+/**
+ * Reserves memory for encoded data. Use to avoid reallocation of vector.
+ */
+void BitOStream::Reserve(int bytes)
+{
+	f.reserve(bytes);
+}
+
+/**
+ * Returns encoded data
+ */
+const u8vector &BitOStream::GetVector()
+{
+	return f;
+}
+
+/**
+ * Size of encoded data in bytes
+ */
+uint BitOStream::GetByteSize() const
+{
+	return f.size() + (c ? 1 : 0);
+}
+
+BitIStreamUnexpectedEnd _bit_i_stream_unexpected_end;
+
+uint32 BitIStream::ReadBytes(uint amount)
+{
+	uint32 res = 0;
+	while (amount--) {
+		if (i >= f.size()) {
+			throw _bit_i_stream_unexpected_end;
+		}
+		res = (res << 8) | f[i++];
+	}
+	return res;
+}
diff -r e16bdc0054ce src/bitstream.h
--- /dev/null
+++ b/src/bitstream.h
@@ -0,0 +1,41 @@
+#ifndef BITSTREAM_H
+#define BITSTREAM_H
+
+#include "stdafx.h"
+#include <vector>
+
+typedef std::vector<uint8> u8vector;
+
+class BitOStream {
+protected:
+	u8vector f;
+	uint32 c;
+	uint32 v;
+
+public:
+	BitOStream(): c(0), v(0) {}
+	virtual ~BitOStream(){}
+	void Reserve(int bytes);
+	void WriteBytes(uint32 value, int amount);
+	void WriteBytes64(uint64 value, int amount);
+	const u8vector &GetVector();
+	uint GetByteSize() const;
+};
+
+class BitIStreamUnexpectedEnd: public std::exception {
+	virtual const char* what() const throw() {
+		return "Unexpected end of bit input stream";
+	}
+};
+
+class BitIStream {
+protected:
+	u8vector &f;
+	uint32 i;
+public:
+	BitIStream(u8vector &data): f(data), i(0) {}
+	virtual ~BitIStream(){}
+	uint32 ReadBytes(uint amount);
+};
+
+#endif
diff -r e16bdc0054ce src/bridge_gui.cpp
--- a/src/bridge_gui.cpp
+++ b/src/bridge_gui.cpp
@@ -24,6 +24,7 @@
 #include "cmd_helper.h"
 #include "tunnelbridge_map.h"
 #include "road_gui.h"
+#include "tilehighlight_func.h"
 
 #include "widgets/bridge_widget.h"
 
@@ -72,6 +73,7 @@
 		DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(p1));
 		ConnectRoadToStructure(p1, start_direction);
 	}
+	StoreRailPlacementEndpoints(p1, end_tile, (TileX(p1) == TileX(end_tile)) ? TRACK_Y : TRACK_X, false);
 }
 
 /** Window class for handling the bridge-build GUI. */
diff -r e16bdc0054ce src/build_vehicle_gui.cpp
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -34,7 +34,7 @@
 #include "autoreplace_func.h"
 
 #include "widgets/build_vehicle_widget.h"
-
+#include "hotkeys.h"
 #include "table/strings.h"
 
 #include "safeguards.h"
@@ -1481,13 +1481,28 @@
 	{
 		this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		if (this->owner != _local_company) return ES_NOT_HANDLED;
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey build_vehicle_hotkeys[] = {
+	Hotkey('R', "build_vehicle", WID_BV_BUILD),
+	HOTKEY_LIST_END
+};
+HotkeyList BuildVehicleWindow::hotkeys("build_vehicle", build_vehicle_hotkeys);
+
 static WindowDesc _build_vehicle_desc(
 	WDP_AUTO, "build_vehicle", 240, 268,
 	WC_BUILD_VEHICLE, WC_NONE,
 	WDF_CONSTRUCTION,
-	_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
+	_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets),
+	&BuildVehicleWindow::hotkeys
 );
 
 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
diff -r e16bdc0054ce src/cargo_table_gui.cpp
--- /dev/null
+++ b/src/cargo_table_gui.cpp
@@ -0,0 +1,235 @@
+/* $Id: cargo_table_gui.cpp 21909 2011-01-26 08:14:36Z TheDude $ */
+
+#include "stdafx.h"
+#include "window_gui.h"
+#include "window_func.h"
+#include "strings_func.h"
+#include "company_func.h"
+#include "company_base.h"
+#include "table/strings.h"
+#include "textbuf_gui.h"
+#include "cargotype.h"
+#include "zoom_func.h"
+#include "widgets/dropdown_type.h"
+
+#include "widgets/cargo_table_widget.h"
+
+static const uint CT_LINESPACE  = 3;      ///< Amount of vertical space for a horizontal (sub-)total line.
+static const uint CT_ICON_MARGIN = 2;     ///< Amount of space between cargo icon and text
+
+enum CargoOption {
+	WID_CT_OPTION_CARGO_TOTAL = 0,
+	WID_CT_OPTION_CARGO_MONTH,
+};
+
+static void DrawPrice(Money amount, int left, int right, int top)
+{
+	SetDParam(0, amount);
+	DrawString(left, right, top, STR_FINANCES_POSITIVE_INCOME, TC_FROMSTRING, SA_RIGHT);
+}
+
+void InvalidateCargosWindows(CompanyID cid)
+{
+	if (cid == _local_company) SetWindowDirty(WC_STATUS_BAR, 0);
+	SetWindowDirty(WC_CARGOS, cid);
+}
+
+/** Cargos window handler. */
+struct CargosWindow : Window {
+
+	CargoOption cargoPeriod;
+	CargosWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
+	{
+		this->InitNested(window_number);
+		this->owner = (Owner)this->window_number;
+		this->cargoPeriod = WID_CT_OPTION_CARGO_TOTAL;
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		if(widget != WID_CT_CAPTION) return;
+		SetDParam(0, (CompanyID)this->window_number);
+		SetDParam(1, (CompanyID)this->window_number);
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count)
+	{
+		if(widget != WID_CT_HEADER_CARGO) return;
+		this->cargoPeriod = (this->cargoPeriod == WID_CT_OPTION_CARGO_TOTAL) ? WID_CT_OPTION_CARGO_MONTH : WID_CT_OPTION_CARGO_TOTAL;
+		this->SetDirty();
+	}
+
+	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		Dimension icon_size = this->GetMaxIconSize();
+		int line_height = max(FONT_HEIGHT_NORMAL, (int)icon_size.height);
+		int icon_space = icon_size.width + ScaleGUITrad(CT_ICON_MARGIN);
+		switch(widget) {
+			case WID_CT_HEADER_AMOUNT:
+			case WID_CT_HEADER_INCOME:
+			case WID_CT_AMOUNT:
+			case WID_CT_INCOME: {
+				break;
+			}
+			case WID_CT_HEADER_CARGO:
+			case WID_CT_LIST: {
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+					size->width = max(GetStringBoundingBox(cs->name).width + icon_space, size->width);
+				}
+				size->width = max(GetStringBoundingBox(STR_TOOLBAR_CARGOS_HEADER_TOTAL_MONTH).width, size->width);
+				break;
+			}
+		}
+		switch(widget) {
+			case WID_CT_HEADER_AMOUNT:
+			case WID_CT_HEADER_INCOME:
+				size->height = FONT_HEIGHT_NORMAL;
+				break;
+			case WID_CT_HEADER_CARGO:
+				break;
+			case WID_CT_AMOUNT:
+			case WID_CT_INCOME:
+			case WID_CT_LIST: {
+				size->height = _sorted_standard_cargo_specs_size * line_height + CT_LINESPACE + FONT_HEIGHT_NORMAL;
+				break;
+			}
+		}
+	}
+
+	Dimension GetMaxIconSize() const {
+		const CargoSpec *cs;
+		Dimension size = {0, 0};
+		FOR_ALL_CARGOSPECS(cs) {
+			Dimension icon_size = GetSpriteSize(cs->GetCargoIcon());
+			size.width = max(size.width, icon_size.width);
+			size.height = max(size.height, icon_size.height);
+		}
+		return size;
+	}
+
+	void DrawWidget(const Rect &r, int widget) const
+	{
+		const Company *c = Company::Get((CompanyID)this->window_number);
+		uint32 sum_cargo_amount = 0;
+		Money sum_cargo_income = 0;
+		int y = r.top;
+		Dimension max_icon_size = this->GetMaxIconSize();
+		int line_height = max(FONT_HEIGHT_NORMAL, (int)(max_icon_size.height));
+		int icon_space = max_icon_size.width + ScaleGUITrad(CT_ICON_MARGIN);
+		int text_y_ofs = (line_height - FONT_HEIGHT_NORMAL);
+
+		switch(widget){
+			case WID_CT_HEADER_CARGO:
+				break;
+			case WID_CT_HEADER_AMOUNT:
+				DrawString(r.left, r.right, y, STR_TOOLBAR_CARGOS_HEADER_AMOUNT, TC_FROMSTRING, SA_RIGHT);
+				break;
+			case WID_CT_HEADER_INCOME:
+				DrawString(r.left, r.right, y, STR_TOOLBAR_CARGOS_HEADER_INCOME, TC_FROMSTRING, SA_RIGHT);
+				break;
+
+			case WID_CT_LIST: {
+				int rect_x = r.left + WD_FRAMERECT_LEFT;
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+					Dimension icon_size = GetSpriteSize(cs->GetCargoIcon());
+					DrawSprite(cs->GetCargoIcon(), PAL_NONE,
+					           r.left + max_icon_size.width - icon_size.width,
+					           y + (line_height - (int)icon_size.height) / 2);
+
+					SetDParam(0, cs->name);
+					DrawString(r.left + icon_space, r.right, y + text_y_ofs, STR_TOOLBAR_CARGOS_NAME);
+
+					y += line_height;
+				}
+
+				GfxFillRect(r.left, y + 1, r.right, y + 1, PC_BLACK);
+				y += CT_LINESPACE;
+
+				StringID string_to_draw = STR_TOOLBAR_CARGOS_HEADER_TOTAL;
+				if (this->cargoPeriod != WID_CT_OPTION_CARGO_TOTAL) string_to_draw++;
+				DrawString(r.left, r.right, y, string_to_draw);
+				break;
+			}
+			case WID_CT_AMOUNT:
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+
+					if (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH) {
+						sum_cargo_amount += c->cargo_units_period[0][cs->Index()];
+						SetDParam(0,  c->cargo_units_period[0][cs->Index()]);
+					} else {
+						sum_cargo_amount += c->cargo_units[cs->Index()];
+						SetDParam(0,  c->cargo_units[cs->Index()]);
+					}
+
+					DrawString(r.left, r.right, y + text_y_ofs, STR_TOOLBAR_CARGOS_UNITS, TC_FROMSTRING, SA_RIGHT); //cargo amount in pcs
+					y += line_height;
+				}
+
+				GfxFillRect(r.left, y + 1, r.right, y + 1, PC_BLACK);
+				y += CT_LINESPACE;
+				SetDParam(0, sum_cargo_amount);
+				DrawString(r.left, r.right, y, STR_TOOLBAR_CARGOS_UNITS_TOTAL, TC_FROMSTRING, SA_RIGHT);
+				break;
+
+			case WID_CT_INCOME:
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+
+					if (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH) {
+						sum_cargo_income += c->cargo_income_period[0][cs->Index()];
+						DrawPrice(c->cargo_income_period[0][cs->Index()], r.left, r.right, y + text_y_ofs);
+					} else {
+						sum_cargo_income += c->cargo_income[cs->Index()];
+						DrawPrice(c->cargo_income[cs->Index()], r.left, r.right, y + text_y_ofs);
+					}
+
+					y += line_height;
+				}
+
+				GfxFillRect(r.left, y + 1, r.right, y + 1, PC_BLACK);
+				y += CT_LINESPACE;
+				DrawPrice(sum_cargo_income, r.left, r.right, y);
+				break;
+		}
+	}
+};
+
+static const NWidgetPart _nested_cargos_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY, WID_CT_CAPTION), SetDataTip(STR_TOOLBAR_CARGOS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_GREY),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 1),
+		NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CT_HEADER_CARGO), SetFill(1, 0), SetPadding(2,2,2,2), SetDataTip(STR_TOOLBAR_CARGOS_HEADER_CARGO, STR_TOOLBAR_CARGOS_HEADER_CARGO),
+			NWidget(WWT_TEXT, COLOUR_GREY, WID_CT_HEADER_AMOUNT), SetMinimalSize(108, 16), SetFill(1, 0), SetPadding(2,2,2,2), SetDataTip(STR_NULL, STR_NULL),
+			NWidget(WWT_TEXT, COLOUR_GREY, WID_CT_HEADER_INCOME), SetMinimalSize(108, 16), SetFill(1, 0), SetPadding(2,2,2,2), SetDataTip(STR_NULL, STR_NULL),
+		EndContainer(),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 1),
+		NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0),
+			NWidget(WWT_EMPTY, COLOUR_GREY, WID_CT_LIST),SetFill(1, 0), SetPadding(2,2,2,2), SetResize(1, 1),
+			NWidget(WWT_EMPTY, COLOUR_GREY, WID_CT_AMOUNT),SetMinimalSize(108, 0),SetFill(1, 0), SetPadding(2,2,2,2), SetResize(1, 1),
+			NWidget(WWT_EMPTY, COLOUR_GREY, WID_CT_INCOME),SetMinimalSize(108, 0),SetFill(1, 0), SetPadding(2,2,2,2), SetResize(1, 1),
+		EndContainer(),
+	EndContainer(),
+};
+
+static WindowDesc _cargos_desc(
+	WDP_AUTO, NULL, 0, 0,
+	WC_CARGOS, WC_NONE,
+	WDF_CONSTRUCTION,
+	_nested_cargos_widgets, lengthof(_nested_cargos_widgets)
+);
+
+void ShowCompanyCargos(CompanyID company)
+{
+	if (!Company::IsValidID(company)) return;
+	AllocateWindowDescFront<CargosWindow>(&_cargos_desc, company);
+}
+
diff -r e16bdc0054ce src/cargo_table_gui.h
--- /dev/null
+++ b/src/cargo_table_gui.h
@@ -0,0 +1,14 @@
+/* $Id: cargo_table_gui.h 21700 2011-01-03 11:55:08Z  $ */
+
+/** @file cargo_table_gui.h GUI Functions related to cargos. */
+
+#ifndef CARGO_TABLE_H
+#define CARGO_TABLE_H
+
+#include "company_type.h"
+#include "gfx_type.h"
+
+void ShowCompanyCargos(CompanyID company);
+void InvalidateCargosWindows(CompanyID cid);
+
+#endif /* CARGO_TABLE_H */
diff -r e16bdc0054ce src/command.cpp
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -26,6 +26,10 @@
 #include "signal_func.h"
 #include "core/backup_type.hpp"
 #include "object_base.h"
+#include "window_func.h"
+#include "watch_gui.h"
+#include "network/network_base.h"
+#include "window_func.h"
 
 #include "table/strings.h"
 
@@ -547,14 +551,22 @@
 bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
 {
 	/* Cost estimation is generally only done when the
-	 * local user presses shift while doing somthing.
-	 * However, in case of incoming network commands,
-	 * map generation or the pause button we do want
-	 * to execute. */
-	bool estimate_only = _shift_pressed && IsLocalCompany() &&
-			!_generating_world &&
-			!(cmd & CMD_NETWORK_COMMAND) &&
-			(cmd & CMD_ID_MASK) != CMD_PAUSE;
+	 * local user presses shift while constructing somthing.
+	 * However, in case of incoming network commands or
+	 * map generation we do want to execute. */
+	bool estimate_only = false;
+	if (!(cmd & CMD_NO_ESTIMATE)) {
+		switch (_command_proc_table[cmd & CMD_ID_MASK].type) {
+			case CMDT_LANDSCAPE_CONSTRUCTION:
+			case CMDT_VEHICLE_CONSTRUCTION:
+				estimate_only = _shift_pressed && IsLocalCompany() &&
+						!_generating_world && !(cmd & CMD_NETWORK_COMMAND);
+				break;
+			default:
+				break; // just to silence warnings
+		}
+	}
+	cmd &= ~CMD_NO_ESTIMATE;
 
 	/* We're only sending the command, so don't do
 	 * fancy things for 'success'. */
@@ -756,6 +768,23 @@
 		if (c != NULL) c->last_build_coordinate = tile;
 	}
 
+	/* Send Tile Number to Watching Company Windows */
+	WatchCompany *wc;
+	for(int watching_window = 0; ; watching_window++){
+		wc = dynamic_cast<WatchCompany*>(FindWindowById(WC_WATCH_COMPANY, watching_window));
+		if(wc != NULL) wc->OnDoCommand(_current_company, tile);
+		else break;
+	}
+
+	NetworkClientInfo *ci;
+	FOR_ALL_CLIENT_INFOS(ci) {
+		if (ci->client_playas == _current_company) {
+			wc = dynamic_cast<WatchCompany*>(FindWindowById(WC_WATCH_COMPANYA, ci->client_id));
+			if (wc != NULL) wc->OnDoCommand(_current_company, tile);
+			break;
+		}
+	}
+
 	SubtractMoneyFromCompany(res2);
 
 	/* update signals if needed */
diff -r e16bdc0054ce src/command_type.h
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -372,6 +372,7 @@
  */
 enum FlaggedCommands {
 	CMD_NETWORK_COMMAND       = 0x0100, ///< execute the command without sending it on the network
+	CMD_NO_ESTIMATE           = 0x0200, ///< execute command instead of doing estimate even if shift is pressed
 	CMD_FLAGS_MASK            = 0xFF00, ///< mask for all command flags
 	CMD_ID_MASK               = 0x00FF, ///< mask for the command ID
 };
diff -r e16bdc0054ce src/commands_gui.cpp
--- /dev/null
+++ b/src/commands_gui.cpp
@@ -0,0 +1,815 @@
+/* $Id: commands_gui.cpp 21909 2011-01-26 08:14:36Z xi $ */
+
+#ifdef ENABLE_NETWORK
+#include "stdafx.h"
+#include "widgets/dropdown_type.h" //fillrect
+#include "core/geometry_func.hpp" //maxdim
+#include "settings_type.h"
+#include "settings_func.h" //saveconfig
+#include "3rdparty/md5/md5.h" //pass crypt
+#include "network/network_func.h" //network chat
+#include "textbuf_gui.h"  //show query
+#include "network/network.h" //networking
+#include "network/core/tcp_http.h" //http connector
+#include "ini_type.h" //ini file
+#include "fileio_func.h" //personal dir
+#include "error.h" //error message
+#include "debug.h"
+
+bool _novahost = false;
+IniFile *_inilogin = NULL;
+
+static const int HTTPBUFLEN = 128;
+
+// nova* stuff probabaly obsolete
+static const char * const NOVAPOLIS_IPV4_PRIMARY   = "188.165.194.77";
+static const char * const NOVAPOLIS_IPV6_PRIMARY   = "2a02:2b88:2:1::1d73:1";
+static const char * const NOVAPOLIS_IPV4_SECONDARY = "89.111.65.225";
+static const char * const NOVAPOLIS_IPV6_SECONDARY = "fe80::20e:7fff:fe23:bee0";
+static const char * const NOVAPOLIS_STRING         = "CityMania";
+static const char * const NICE_HTTP_LOGIN          = "http://n-ice.org/openttd/gettoken.php?user=%s&password=%s";
+static const char * const BTPRO_HTTP_LOGIN         = "http://openttd.btpro.nl/gettoken.php?user=%s&password=%s";
+
+static const char * const NOVA_IP_ADDRESSES[] = {
+	NOVAPOLIS_IPV4_PRIMARY,
+	NOVAPOLIS_IPV6_PRIMARY,
+	NOVAPOLIS_IPV4_SECONDARY,
+	NOVAPOLIS_IPV6_SECONDARY,
+};
+
+static const char * const CFG_LOGIN_FILE  = "citymania.cfg";
+static const char * const CFG_LOGIN_KEY   = "login";
+static const char * const NOVAPOLIS_LOGIN = "citymania_login";
+static const char * const NOVAPOLIS_PW    = "citymania_pw";
+static const char * const NICE_LOGIN      = "nice_login";
+static const char * const NICE_PW         = "nice_pw";
+static const char * const BTPRO_LOGIN     = "btpro_login";
+static const char * const BTPRO_PW        = "btpro_pw";
+
+static const char * const INI_LOGIN_KEYS[] = {
+	NOVAPOLIS_LOGIN,
+	NOVAPOLIS_PW,
+	NICE_LOGIN,
+	NICE_PW,
+	BTPRO_LOGIN,
+	BTPRO_PW,
+};
+
+/** Widget number of the commands window. */
+enum CommandsToolbarWidgets {
+	CTW_BACKGROUND,
+	CTW_GOAL,
+	CTW_SCORE,
+	CTW_TOWN,
+	CTW_QUEST,
+	CTW_TOWN_ID,
+	CTW_HINT,
+	CTW_LOGIN,
+	CTW_NAME,
+	CTW_TIMELEFT,
+	CTW_INFO,
+	CTW_RESETME,
+	CTW_SAVEME,
+	CTW_HELP,
+	CTW_RULES,
+	CTW_CBHINT,
+	CTW_CLIENTS,
+	CTW_BEST,
+	CTW_ME,
+	CTW_RANK,
+	CTW_TOPICS,
+	CTW_TOPIC1,
+	CTW_TOPIC2,
+	CTW_TOPIC3,
+	CTW_TOPIC4,
+	CTW_TOPIC5,
+	CTW_TOPIC6,
+	CTW_CHOOSE_CARGO,
+	CTW_CHOOSE_CARGO_AMOUNT,
+	CTW_CHOOSE_CARGO_INCOME,
+	CTW_NS0,
+	CTW_NS1,
+	CTW_NS2,
+	CTW_NS3,
+	CTW_NS4,
+	CTW_NS5,
+	CTW_NS6,
+	CTW_NS7,
+	CTW_NS8,
+	CTW_NS9,
+	CTW_NS10,
+	CTW_NSX1,
+	CTW_NSX2,
+	CTW_NSX3,
+	CTW_NSX4,
+	CTW_NSX5,
+	CTW_NSX6,
+	CTW_NSX7,
+	CTW_NSEND,
+	CTW_CARGO_FIRST,
+};
+
+enum CommandsToolbarQuery {
+	CTQ_TOWN_ID = 0,
+	CTQ_LOGIN_NAME,
+	CTQ_LOGIN_PASSWORD,
+	CTQ_NAME_NEWNAME,
+	CTQ_LOGIN_CREDENTIALS_PW,
+};
+
+enum CommandsToolbarCargoOption {
+	CTW_OPTION_CARGO = 0,
+	CTW_OPTION_CARGO_AMOUNT,
+	CTW_OPTION_CARGO_INCOME,
+};
+
+enum LoginWindowWidgets {
+	LWW_NOVAPOLIS,
+	LWW_NICE,
+	LWW_BTPRO,
+	LWW_NOVAPOLIS_LOGIN,
+	LWW_NOVAPOLIS_PW,
+	LWW_NICE_LOGIN,
+	LWW_NICE_PW,
+	LWW_BTPRO_LOGIN,
+	LWW_BTPRO_PW,
+	LWW_USERNAME,
+	LWW_PASSWORD,
+};
+
+enum LoginWindowQueryWidgets {
+	LQW_NOVAPOLIS,
+	LQW_NICE,
+	LQW_BTPRO,
+	LQW_NOVAPOLIS_LOGIN,
+	LQW_NOVAPOLIS_PW,
+	LQW_NICE_LOGIN,
+	LQW_NICE_PW,
+	LQW_BTPRO_LOGIN,
+	LQW_BTPRO_PW,
+};
+
+enum CommunityName {
+	CITYMANIA,
+	NICE,
+	BTPRO,
+};
+
+enum IniLoginKeys {
+	NOVAPOLISUSER,
+	NOVAPOLISPW,
+	NICEUSER,
+	NICEPW,
+	BTPROUSER,
+	BTPROPW,
+};
+
+char _inilogindata[6][64];
+
+void ShowLoginWindow();
+void AccountLogin(CommunityName community);
+void IniReloadLogin();
+char * GetLoginItem(const char * item);
+
+bool novahost() {
+	return _novahost;
+}
+
+void strtomd5(char * buf, char * bufend, int length){
+	uint8 digest[16];
+	Md5 checksum;
+	checksum.Append(buf, length);
+	checksum.Finish(digest);
+	md5sumToString(buf, bufend, digest);
+	strtolower(buf);
+}
+
+void UrlEncode(char * buf, const char * buflast, const char * url){
+	while(*url != '\0' && buf < buflast){
+		if((*url >= '0' && *url <= '9') || (*url >= 'A' && *url <= 'Z') || (*url >= 'a' && *url <= 'z')
+			|| *url == '-' || *url == '_' || *url == '.' || *url == '~'
+		){
+			*buf++ = *url++;
+		}
+		else{
+			buf += seprintf(buf, buflast, "%%%02X", *url++);
+		}
+	}
+	*buf = '\0';
+}
+
+/** Commands toolbar window handler. */
+struct CommandsToolbarWindow : Window {
+
+	CommandsToolbarQuery query_widget;
+	CommandsToolbarCargoOption cargo_option;
+
+	CommandsToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
+	{
+		this->InitNested(window_number);
+		this->cargo_option = CTW_OPTION_CARGO_AMOUNT;
+		this->LowerWidget(CTW_CHOOSE_CARGO_AMOUNT);
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		if(widget >= CTW_NS0 && widget < CTW_NSEND){
+			SetDParam(0, widget - CTW_NS0);
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count)
+	{
+		if (!_networking) return;
+		char msg[64];
+		switch (widget) {
+			case CTW_GOAL:
+				NetworkClientSendChatToServer("!goal");
+				break;
+			case CTW_SCORE:
+				NetworkClientSendChatToServer("!score");
+				break;
+			case CTW_TOWN:
+				NetworkClientSendChatToServer("!town");
+				break;
+			case CTW_QUEST:
+				NetworkClientSendChatToServer("!quest");
+				break;
+			case CTW_TIMELEFT:
+				NetworkClientSendChatToServer("!timeleft");
+				break;
+			case CTW_INFO:
+				NetworkClientSendChatToServer("!info");
+				break;
+			case CTW_HINT:
+				NetworkClientSendChatToServer("!hint");
+				break;
+			case CTW_RESETME:
+				NetworkClientSendChatToServer("!resetme");
+				break;
+			case CTW_SAVEME:
+				NetworkClientSendChatToServer("!saveme");
+				break;
+			case CTW_HELP:
+				NetworkClientSendChatToServer("!help");
+				break;
+			case CTW_RULES:
+				NetworkClientSendChatToServer("!rules");
+				break;
+			case CTW_CBHINT:
+				NetworkClientSendChatToServer("!hint");
+				break;
+			case CTW_CLIENTS:
+				NetworkClientSendChatToServer("!clients");
+				break;
+			case CTW_BEST:
+				NetworkClientSendChatToServer("!best");
+				break;
+			case CTW_ME:
+				NetworkClientSendChatToServer("!me");
+				break;
+			case CTW_RANK:
+				NetworkClientSendChatToServer("!rank");
+				break;
+			case CTW_TOPICS:
+				NetworkClientSendChatToServer("!topic");
+				break;
+			case CTW_TOWN_ID:
+				this->query_widget = CTQ_TOWN_ID;
+				ShowQueryString(STR_EMPTY, STR_TOOLBAR_COMMANDS_TOWN_QUERY, 8, this, CS_NUMERAL, QSF_NONE);
+				break;
+			case CTW_LOGIN:
+				this->query_widget = CTQ_LOGIN_NAME;
+				ShowQueryString(STR_EMPTY, STR_TOOLBAR_COMMANDS_LOGIN_NAME_QUERY, 24, this, CS_ALPHANUMERAL, QSF_NONE);
+				break;
+			case CTW_NAME:
+				this->query_widget = CTQ_NAME_NEWNAME;
+				ShowQueryString(STR_EMPTY, STR_TOOLBAR_COMMANDS_NAME_NEWNAME_QUERY, 25, this, CS_ALPHANUMERAL, QSF_NONE);
+				break;
+			case CTW_TOPIC1:
+			case CTW_TOPIC2:
+			case CTW_TOPIC3:
+			case CTW_TOPIC4:
+			case CTW_TOPIC5:
+			case CTW_TOPIC6:
+				seprintf(msg, lastof(msg), "!topic %i", widget - CTW_TOPIC1 + 1);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case CTW_CHOOSE_CARGO:
+			case CTW_CHOOSE_CARGO_AMOUNT:
+			case CTW_CHOOSE_CARGO_INCOME:
+				this->cargo_option = (CommandsToolbarCargoOption)(widget - CTW_CHOOSE_CARGO);
+				this->RaiseWidget(CTW_CHOOSE_CARGO);
+				this->RaiseWidget(CTW_CHOOSE_CARGO_AMOUNT);
+				this->RaiseWidget(CTW_CHOOSE_CARGO_INCOME);
+				this->LowerWidget(widget);
+				this->SetWidgetDirty(CTW_CHOOSE_CARGO);
+				this->SetWidgetDirty(CTW_CHOOSE_CARGO_AMOUNT);
+				this->SetWidgetDirty(CTW_CHOOSE_CARGO_INCOME);
+				break;
+			default:
+				if(widget >= CTW_NS0 && widget < CTW_NSEND){
+					char ip[16];
+					// if(widget < CTW_NSX4)
+					strecpy(ip, NOVAPOLIS_IPV4_PRIMARY, lastof(ip));
+					// else strecpy(ip, NOVAPOLIS_IPV4_SECONDARY, lastof(ip));
+
+					NetworkClientConnectGame(NetworkAddress(ip, (3980 + widget - CTW_NS0)), COMPANY_SPECTATOR);
+				}
+				else if (widget >= CTW_CARGO_FIRST) {
+					int i = widget - CTW_CARGO_FIRST;
+					char name[128];
+					GetString(name, _sorted_cargo_specs[i]->name, lastof(name));
+					switch(this->cargo_option){
+						case CTW_OPTION_CARGO:        seprintf(msg, lastof(msg), "!%s", name); break;
+						case CTW_OPTION_CARGO_AMOUNT: seprintf(msg, lastof(msg), "!A%s", name); break;
+						case CTW_OPTION_CARGO_INCOME: seprintf(msg, lastof(msg), "!I%s", name); break;
+					}
+					NetworkClientSendChatToServer(msg);
+					this->ToggleWidgetLoweredState(widget);
+					this->SetWidgetDirty(widget);
+				}
+				break;
+		}
+	}
+
+	void OnQueryTextFinished(char * str)
+	{
+		if (!_networking || str == NULL) return;
+		char msg[128];
+		switch (this->query_widget) {
+			case CTQ_TOWN_ID:
+				seprintf(msg, lastof(msg), "!town %s", str);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case CTQ_LOGIN_NAME:
+				seprintf(msg, lastof(msg), "!login %s", str);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case CTQ_NAME_NEWNAME:
+				seprintf(msg, lastof(msg), "!name %s", str);
+				NetworkClientSendChatToServer(msg);
+				break;
+			default:
+				NOT_REACHED();
+		}
+	}
+
+	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		if (widget < CTW_CARGO_FIRST) return;
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - CTW_CARGO_FIRST];
+		SetDParam(0, cs->name);
+		Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO);
+		d.width += 14; // colour field
+		d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+		d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+		*size = maxdim(d, *size);
+	}
+
+	void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget < CTW_CARGO_FIRST) return;
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - CTW_CARGO_FIRST];
+		bool rtl = _current_text_dir == TD_RTL;
+
+		/* Since the buttons have no text, no images,
+		 * both the text and the coloured 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 = this->IsWidgetLowered(widget) ? 1 : 0;
+		int x = r.left + WD_FRAMERECT_LEFT;
+		int y = r.top;
+
+		int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT);
+
+		GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, 0);
+		GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour);
+		SetDParam(0, cs->name);
+		DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
+	}
+
+	void OnHundredthTick()
+	{
+		for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+			if (this->IsWidgetLowered(i + CTW_CARGO_FIRST)) {
+				static int x = 0;
+				x++;
+				if (x >= 2) {
+					this->ToggleWidgetLoweredState(i + CTW_CARGO_FIRST);
+					this->SetWidgetDirty(i + CTW_CARGO_FIRST);
+					x = 0;
+				}
+			}
+		}
+	}
+
+};
+
+/** Construct the row containing the digit keys. */
+static NWidgetBase *MakeCargoButtons(int *biggest_index)
+{
+	NWidgetVertical *ver = new NWidgetVertical;
+
+	for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+		NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, CTW_CARGO_FIRST + i, NULL);
+		leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO;
+		leaf->SetFill(1, 0);
+		ver->Add(leaf);
+	}
+	*biggest_index = CTW_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1;
+	return ver;
+}
+
+static const NWidgetPart _nested_commands_toolbar_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_TOOLBAR_COMMANDS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget(NWID_HORIZONTAL),
+		NWidget(NWID_VERTICAL),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_GOAL), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_GOAL_CAPTION, STR_TOOLBAR_COMMANDS_GOAL_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_QUEST), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_QUEST_CAPTION, STR_TOOLBAR_COMMANDS_QUEST_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_SCORE), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_SCORE_CAPTION, STR_TOOLBAR_COMMANDS_SCORE_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOWN), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOWN_CAPTION, STR_TOOLBAR_COMMANDS_TOWN_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOWN_ID), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOWN_ID_CAPTION, STR_TOOLBAR_COMMANDS_TOWN_ID_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_HINT), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_HINT_CAPTION, STR_TOOLBAR_COMMANDS_HINT_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_LOGIN), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_LOGIN_CAPTION, STR_TOOLBAR_COMMANDS_LOGIN_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_NAME), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NAME_CAPTION, STR_TOOLBAR_COMMANDS_NAME_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TIMELEFT), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TIMELEFT_CAPTION, STR_TOOLBAR_COMMANDS_TIMELEFT_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_INFO), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_INFO_CAPTION, STR_TOOLBAR_COMMANDS_INFO_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS1), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS2), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS3), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS4), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS5), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS6), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS7), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NS9), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX1), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX2), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX3), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX4), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX5), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX6), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, CTW_NSX7), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_NS_CAPTION, STR_TOOLBAR_COMMANDS_NS_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_RESETME), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_RESETME_CAPTION, STR_TOOLBAR_COMMANDS_RESETME_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_SAVEME), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_SAVEME_CAPTION, STR_TOOLBAR_COMMANDS_SAVEME_TOOLTIP),
+			EndContainer(),
+			//more
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPICS), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPICS_CAPTION, STR_TOOLBAR_COMMANDS_TOPICS_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_HELP), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_HELP_CAPTION, STR_TOOLBAR_COMMANDS_HELP_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC1), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC1_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC1_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_RULES), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_RULES_CAPTION, STR_TOOLBAR_COMMANDS_RULES_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC2), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC2_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC2_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_CBHINT), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_CBHINT_CAPTION, STR_TOOLBAR_COMMANDS_CBHINT_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC3), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC3_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC3_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_BEST), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_BEST_CAPTION, STR_TOOLBAR_COMMANDS_BEST_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC4), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC4_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC4_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_RANK), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_RANK_CAPTION, STR_TOOLBAR_COMMANDS_RANK_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC5), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC5_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC5_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_ME), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_ME_CAPTION, STR_TOOLBAR_COMMANDS_ME_TOOLTIP),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CTW_TOPIC6), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_TOPIC6_CAPTION, STR_TOOLBAR_COMMANDS_TOPIC6_TOOLTIP),
+				NWidget(WWT_PANEL, COLOUR_GREY), SetResize(0, 1), EndContainer(),
+			EndContainer(),
+			NWidget(WWT_PANEL, COLOUR_GREY), SetResize(0, 1), EndContainer(),
+		EndContainer(),
+		NWidget(NWID_VERTICAL),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, CTW_CHOOSE_CARGO_AMOUNT), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_CAPTION, STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_TOOLTIP),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, CTW_CHOOSE_CARGO_INCOME), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_CAPTION, STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_TOOLTIP),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, CTW_CHOOSE_CARGO), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_TOOLBAR_COMMANDS_OPTION_CARGO_CAPTION, STR_TOOLBAR_COMMANDS_OPTION_CARGO_TOOLTIP),
+			NWidgetFunction(MakeCargoButtons),
+			NWidget(WWT_PANEL, COLOUR_GREY), SetResize(0, 1), EndContainer(),
+		EndContainer(),
+	EndContainer(),
+};
+
+static WindowDesc _commands_toolbar_desc(
+	WDP_ALIGN_TOOLBAR, NULL, 0, 0,
+	WC_COMMAND_TOOLBAR, WC_NONE,
+	WDF_CONSTRUCTION,
+	_nested_commands_toolbar_widgets, lengthof(_nested_commands_toolbar_widgets)
+);
+
+void ShowCommandsToolbar()
+{
+	DeleteWindowByClass(WC_COMMAND_TOOLBAR);
+	AllocateWindowDescFront<CommandsToolbarWindow>(&_commands_toolbar_desc, 0);
+}
+
+// login window
+class GetHTTPContent: public HTTPCallback {
+public:
+	GetHTTPContent(char *uri): uri(uri) {
+		this->proccessing = false;
+		this->buf_last = lastof(buf);
+	}
+	bool proccessing;
+
+	void InitiateLoginSequence() {
+		if(this->proccessing) return;
+		this->proccessing = true;
+		this->cursor = this->buf;
+		NetworkHTTPSocketHandler::Connect(this->uri, this);
+	}
+
+	virtual void OnReceiveData(const char *data, size_t length) {
+		if (data == NULL) {
+			this->cursor = NULL;
+			this->LoginAlready();
+		}
+		else {
+			for(size_t i=0; i<length && this->cursor < this->buf_last; i++, data++, this->cursor++) {
+				*(this->cursor) = *data;
+			}
+			*(this->cursor) = '\0';
+		}
+	}
+
+	virtual void OnFailure() {
+		ShowErrorMessage(STR_LOGINERROR_NOCONNECT, INVALID_STRING_ID, WL_ERROR);
+	}
+
+	void LoginAlready(){
+		if(strlen(this->buf) == 4 && _networking){
+			char msg[32];
+			seprintf(msg, lastof(msg), "!login %s", this->buf);
+			NetworkClientSendChatToServer(msg);
+		}
+		else{
+			ShowErrorMessage(STR_LOGINERROR_BADINPUT, INVALID_STRING_ID, WL_ERROR);
+		}
+		this->proccessing = false;
+	}
+
+	virtual ~GetHTTPContent() {
+	}
+private:
+	NetworkHTTPContentConnecter *conn;
+	char buf[HTTPBUFLEN];
+	char *buf_last;
+	char *cursor;
+	char *uri;
+};
+//send login
+void AccountLogin(CommunityName community){
+	char uri[128];
+	switch(community){
+		case CITYMANIA:
+			seprintf(uri, lastof(uri), "!login %s %s", _inilogindata[NOVAPOLISUSER], _inilogindata[NOVAPOLISPW]);
+			NetworkClientSendChatToServer(uri);
+			return;
+		case NICE:
+			seprintf(uri, lastof(uri), NICE_HTTP_LOGIN, GetLoginItem(NICE_LOGIN), GetLoginItem(NICE_PW));
+			break;
+		case BTPRO:
+			seprintf(uri, lastof(uri), BTPRO_HTTP_LOGIN, GetLoginItem(BTPRO_LOGIN), GetLoginItem(BTPRO_PW));
+			break;
+		default:
+			return;
+	}
+	static GetHTTPContent login(uri);
+	login.InitiateLoginSequence();
+}
+#endif /* ENABLE_NETWORK */
+
+//ini login hadling
+void IniLoginInitiate(){
+	static const char * const list_login[] = {
+		CFG_LOGIN_KEY,
+		NULL
+	};
+
+	if(_inilogin != NULL) return; //it was already set
+	_inilogin = new IniFile(list_login);
+	_inilogin->LoadFromDisk(CFG_LOGIN_FILE, BASE_DIR);
+	IniReloadLogin();
+}
+
+void IniReloadLogin(){
+	char str[64];
+	const char * itemvalue;
+	for(int i = 0, len = lengthof(INI_LOGIN_KEYS); i < len; i++){
+		itemvalue = GetLoginItem(INI_LOGIN_KEYS[i]);
+		if(itemvalue == NULL){
+			GetString(str, STR_LOGIN_NOTSET, lastof(str));
+		}
+		else{
+			strecpy(str, itemvalue, lastof(str));
+		}
+		strecpy(_inilogindata[i], str, lastof(_inilogindata[i]));
+	}
+}
+
+char * GetLoginItem(const char * itemname){
+	IniGroup *group = _inilogin->GetGroup(CFG_LOGIN_KEY);
+	if(group == NULL) return NULL;
+	IniItem *item = group->GetItem(itemname, true);
+	if(item == NULL || item->value == NULL) return NULL;
+	return item->value;
+}
+
+void SetLoginItem(const char * itemname, const char * value){
+	IniGroup *group = _inilogin->GetGroup(CFG_LOGIN_KEY);
+	if(group == NULL) return;
+	IniItem *item = group->GetItem(itemname, true);
+	if(item == NULL) return;
+	item->SetValue(value);
+	_inilogin->SaveToDisk(str_fmt("%s%s", _personal_dir, CFG_LOGIN_FILE));
+	IniReloadLogin();
+}
+//login window
+struct LoginWindow : Window {
+	LoginWindowQueryWidgets query_widget;
+
+	LoginWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
+	{
+		this->InitNested(window_number);
+		if(_novahost || !_networking){
+			this->DisableWidget(LWW_NICE);
+			this->DisableWidget(LWW_BTPRO);
+		}
+		if(!_novahost || !_networking) this->DisableWidget(LWW_NOVAPOLIS);
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		switch(widget){
+			case LWW_NOVAPOLIS_LOGIN:
+				SetDParamStr(0, _inilogindata[NOVAPOLISUSER]);
+				break;
+			case LWW_NOVAPOLIS_PW:
+				SetDParam(0, (GetLoginItem(NOVAPOLIS_PW) == NULL ? STR_LOGIN_NOTSET : STR_LOGIN_SET));
+				break;
+			case LWW_NICE_LOGIN:
+				SetDParamStr(0, _inilogindata[NICEUSER]);
+				break;
+			case LWW_NICE_PW:
+				SetDParam(0, (GetLoginItem(NICE_PW) == NULL ? STR_LOGIN_NOTSET : STR_LOGIN_SET));
+				break;
+			case LWW_BTPRO_LOGIN:
+				SetDParamStr(0, _inilogindata[BTPROUSER]);
+				break;
+			case LWW_BTPRO_PW:
+				SetDParam(0, (GetLoginItem(BTPRO_PW) == NULL ? STR_LOGIN_NOTSET : STR_LOGIN_SET));
+				break;
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count)
+	{
+		switch (widget) {
+			case LWW_NOVAPOLIS:
+				if(_novahost && _networking) AccountLogin(CITYMANIA);
+				break;
+			case LWW_NICE:
+				if(_networking) AccountLogin(NICE);
+				break;
+			case LWW_BTPRO:
+				if(_networking) AccountLogin(BTPRO);
+				break;
+			case LWW_NOVAPOLIS_LOGIN:
+			case LWW_NOVAPOLIS_PW:
+			case LWW_NICE_LOGIN:
+			case LWW_NICE_PW:
+			case LWW_BTPRO_LOGIN:
+			case LWW_BTPRO_PW:
+				this->query_widget = (LoginWindowQueryWidgets)widget;
+				ShowQueryString(STR_EMPTY, STR_LOGIN_CHANGE_USERNAME, 32, this, CS_ALPHANUMERAL, QSF_NONE);
+				break;
+		}
+	}
+
+	void OnQueryTextFinished(char * str)
+	{
+		if (str == NULL) return;
+		char item[128];
+		switch(this->query_widget){
+			case LQW_NOVAPOLIS_LOGIN: {
+				SetLoginItem(NOVAPOLIS_LOGIN, str);
+				break;
+			}
+			case LQW_NOVAPOLIS_PW: {
+				char msg[128];
+				strecpy(msg, str, lastof(msg));
+				strtomd5(msg, lastof(msg), (int)strlen(msg));
+				SetLoginItem(NOVAPOLIS_PW, msg);
+				break;
+			}
+			case LQW_NICE_LOGIN:
+			case LQW_NICE_PW:
+			case LQW_BTPRO_LOGIN:
+			case LQW_BTPRO_PW:
+				UrlEncode(item, lastof(item), str);
+				SetLoginItem(INI_LOGIN_KEYS[this->query_widget - 3], item); // - LWW_NICE_LOGIN + NICE_LOGIN
+				break;
+			default: return;
+		}
+		this->SetDirty();
+	}
+};
+
+static const NWidgetPart _nested_login_window_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LOGINWINDOW_CAPTION, 0),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0),
+		NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPadding(10),
+			//novapolis
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_USERNAME), SetDataTip(STR_LOGIN_USERNAME, 0),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_PASSWORD), SetDataTip(STR_LOGIN_PASSWORD, 0),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 5),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_NOVAPOLIS_LOGIN), SetMinimalSize(60, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_USERNAME_DISPLAY, STR_LOGIN_CHANGE_USERNAME),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_NOVAPOLIS_PW), SetMinimalSize(30, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_PASSWORD_DISPLAY, STR_LOGIN_CHANGE_PASSWORD),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 10),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_PURPLE, LWW_NOVAPOLIS), SetMinimalSize(100, 30), SetFill(1, 0), SetDataTip(STR_LOGINWINDOW_CITYMANIA, STR_LOGIN_SEND_LOGIN_TT),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 10),
+			//n-ice
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_USERNAME), SetDataTip(STR_LOGIN_USERNAME, 0),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_PASSWORD), SetDataTip(STR_LOGIN_PASSWORD, 0),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 5),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_NICE_LOGIN), SetMinimalSize(60, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_USERNAME_DISPLAY, STR_LOGIN_CHANGE_USERNAME),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_NICE_PW), SetMinimalSize(30, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_PASSWORD_DISPLAY, STR_LOGIN_CHANGE_PASSWORD),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 10),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, LWW_NICE), SetMinimalSize(100, 30), SetFill(1, 0), SetDataTip(STR_LOGINWINDOW_NICE, STR_LOGIN_SEND_LOGIN_TT),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 10),
+			//btpro
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_USERNAME), SetDataTip(STR_LOGIN_USERNAME, 0),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_TEXT, COLOUR_BROWN, LWW_PASSWORD), SetDataTip(STR_LOGIN_PASSWORD, 0),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 5),
+			NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_BTPRO_LOGIN), SetMinimalSize(60, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_USERNAME_DISPLAY, STR_LOGIN_CHANGE_USERNAME),
+				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, LWW_BTPRO_PW), SetMinimalSize(30, 20), SetFill(1, 0), SetDataTip(STR_LOGIN_PASSWORD_DISPLAY, STR_LOGIN_CHANGE_PASSWORD),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 10),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, LWW_BTPRO), SetMinimalSize(100, 30), SetFill(1, 0), SetDataTip(STR_LOGINWINDOW_BTPRO, STR_LOGIN_SEND_LOGIN_TT),
+		EndContainer(),
+	EndContainer(),
+};
+
+static WindowDesc _login_window_desc(
+	WDP_CENTER, NULL, 0, 0,
+	WC_LOGIN_WINDOW, WC_NONE,
+	WDF_CONSTRUCTION,
+	_nested_login_window_widgets, lengthof(_nested_login_window_widgets)
+);
+
+void ShowLoginWindow()
+{
+	IniLoginInitiate();
+	DeleteWindowByClass(WC_LOGIN_WINDOW);
+	AllocateWindowDescFront<LoginWindow>(&_login_window_desc, 0);
+}
diff -r e16bdc0054ce src/company_base.h
--- a/src/company_base.h
+++ b/src/company_base.h
@@ -17,6 +17,7 @@
 #include "autoreplace_type.h"
 #include "tile_type.h"
 #include "settings_type.h"
+#include "cargo_type.h"
 #include "group.h"
 
 /** Statistics about the economy. */
@@ -26,6 +27,7 @@
 	CargoArray delivered_cargo; ///< The amount of delivered cargo.
 	int32 performance_history;  ///< Company score (scale 0-1000)
 	Money company_value;        ///< The value of the company.
+	Money cargo_income[NUM_CARGO]; ///< Cargo income from each cargo type	
 };
 
 struct CompanyInfrastructure {
@@ -124,6 +126,12 @@
 
 	CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure.
 
+	uint32 cargo_units[NUM_CARGO];   ///< Total amount of transported cargo for each cargo ID
+	Money cargo_income[NUM_CARGO];   ///< Total income from transported cargo for each cargo ID
+
+	uint32 cargo_units_period[2][NUM_CARGO];   ///< Monthly amount of transported cargo for each cargo ID 
+	Money cargo_income_period[2][NUM_CARGO];   ///< Monthly income from transported cargo for each cargo ID
+
 	/**
 	 * Is this company a valid company, controlled by the computer (a NoAI program)?
 	 * @param index Index in the pool.
diff -r e16bdc0054ce src/company_cmd.cpp
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -38,6 +38,7 @@
 #include "story_base.h"
 
 #include "table/strings.h"
+#include "cargo_type.h"
 
 #include "safeguards.h"
 
@@ -69,6 +70,8 @@
 
 	for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR;
 	InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY);
+	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
+	InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1);
 }
 
 /** Destructor. */
@@ -91,6 +94,8 @@
 	InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
 	/* If the currently shown error message has this company in it, then close it. */
 	InvalidateWindowData(WC_ERRMSG, 0);
+	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
+	InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1);
 }
 
 /**
@@ -576,9 +581,23 @@
 	AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
 	Game::NewEvent(new ScriptEventCompanyNew(c->index));
 
+	if (!is_ai) UpdateAllTownVirtCoords(); //coloured rating
+
+	for (uint j = 0; j < NUM_CARGO; j++) {
+		c->cargo_income[j] = 0;
+		c->cargo_units[j] = 0;
+	}
+	CargoResetPeriods(c);
+
 	return c;
 }
 
+void CargoResetPeriods(Company *c){
+	memmove(&c->cargo_income_period[1], &c->cargo_income_period[0], sizeof(c->cargo_income_period[0]));
+	memset(&c->cargo_income_period, 0, sizeof(c->cargo_income_period[0]));
+	memmove(&c->cargo_units_period[1], &c->cargo_units_period[0], sizeof(c->cargo_units_period[0]));
+	memset(&c->cargo_units_period, 0, sizeof(c->cargo_units_period[0]));
+}
 /** Start the next competitor now. */
 void StartupCompanies()
 {
@@ -1081,6 +1100,7 @@
 		free(c->name);
 		c->name = reset ? NULL : stredup(text);
 		MarkWholeScreenDirty();
+		InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
 		CompanyAdminUpdate(c);
 	}
 
diff -r e16bdc0054ce src/company_func.h
--- a/src/company_func.h
+++ b/src/company_func.h
@@ -31,6 +31,7 @@
 void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cost);
 CommandCost CheckOwnership(Owner owner, TileIndex tile = 0);
 CommandCost CheckTileOwnership(TileIndex tile);
+void CargoResetPeriods(Company *c);
 
 extern CompanyByte _local_company;
 extern CompanyByte _current_company;
diff -r e16bdc0054ce src/company_gui.cpp
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -1919,7 +1919,14 @@
 							NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
 							NWidget(NWID_SPACER), SetMinimalSize(90, 0),
 						EndContainer(),
-						NWidget(NWID_SPACER), SetFill(0, 1),
+						NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_MOD),
+							NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1),
+							NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
+								NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_MOD_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_MOD_COMPANY_JOIN_BUTTON, STR_NULL),
+								NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_MOD_COMPANY_TOGGLE_LOCK), SetFill(1, 0), SetDataTip(STR_MOD_TOGGLE_LOCK_BUTTON, STR_NULL),
+								NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_MOD_COMPANY_RESET), SetFill(1, 0), SetDataTip(STR_MOD_COMPANY_RESET_BUTTON, STR_NULL),
+							EndContainer(),
+						EndContainer(),
 					EndContainer(),
 				EndContainer(),
 				NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
@@ -1989,6 +1996,16 @@
 /**
  * Window with general information about a company
  */
+static void ResetCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		CompanyID company2 = (CompanyID)w->window_number;
+		char msg[128];
+		seprintf(msg, lastof(msg), "!reset %i", company2 + 1);
+		NetworkClientSendChatToServer(msg);
+	}
+}
+
 struct CompanyWindow : Window
 {
 	CompanyWidgets query_widget;
@@ -2010,6 +2027,9 @@
 		/* Display planes of the #WID_C_SELECT_BUTTONS selection widget. */
 		CWP_BUTTONS_LOCAL = 0, ///< Buttons of the local company.
 		CWP_BUTTONS_OTHER,     ///< Buttons of the other companies.
+
+		CWP_BUTTONS_PLAYER = 0,
+		CWP_BUTTONS_MOD,
 	};
 
 	CompanyWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
@@ -2079,12 +2099,26 @@
 			}
 			this->SetWidgetDisabledState(WID_C_COMPANY_JOIN,   c->is_ai);
 
+			plane = (int)(_networking && _novarole ? CWP_BUTTONS_MOD: CWP_BUTTONS_PLAYER);
+			wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_MOD);
+			if (plane != wi->shown_plane) {
+				wi->SetDisplayedPlane(plane);
+				reinit = true;
+			}
+
 			if (reinit) {
 				this->ReInit();
 				return;
 			}
 		}
 
+		// if(!_networking) {
+		// 	this->SetWidgetDisabledState(CW_WIDGET_COMPANY_RESUME, true);
+		// 	this->SetWidgetDisabledState(CW_WIDGET_COMPANY_SUSPEND, true);
+		// 	this->SetWidgetDisabledState(CW_WIDGET_COMPANY_RESET, true);
+		// 	this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN2, true);
+		// }
+
 		this->DrawWidgets();
 	}
 
@@ -2141,6 +2175,15 @@
 				break;
 			}
 
+			// case CW_WIDGET_COMPANY_RESUME:
+			// case CW_WIDGET_COMPANY_SUSPEND:
+			// case CW_WIDGET_COMPANY_RESET:
+			// case CW_WIDGET_COMPANY_JOIN2:
+			// 	if(!_novarole){
+			// 		size->width = 0;
+			// 		size->height = 0;
+			// 	}
+			// 	break;
 #ifdef ENABLE_NETWORK
 			case WID_C_HAS_PASSWORD:
 				*size = maxdim(*size, GetSpriteSize(SPR_LOCK));
@@ -2367,6 +2410,34 @@
 					/* just send the join command */
 					NetworkClientRequestMove(company);
 				}
+				MarkWholeScreenDirty();
+				break;
+			}
+
+			case WID_C_MOD_COMPANY_JOIN: {
+				if (!_novarole) return;
+				CompanyID company2 = (CompanyID)this->window_number;
+				// this->query_widget = WID_C_MOD_COMPANY_JOIN;
+				char msg[128];
+				seprintf(msg, lastof(msg), "!move %i", company2 + 1);
+				NetworkClientSendChatToServer(msg);
+				MarkWholeScreenDirty();
+				break;
+			}
+			case WID_C_MOD_COMPANY_RESET: {
+				if (!_networking) return;
+				this->query_widget = WID_C_MOD_COMPANY_RESET;
+				ShowQuery(STR_XI_RESET_CAPTION, STR_XI_REALY_RESET, this, ResetCallback);
+				MarkWholeScreenDirty();
+				break;
+			}
+			case WID_C_MOD_COMPANY_TOGGLE_LOCK: {
+				if (!_novarole) return;
+				CompanyID company2 = (CompanyID)this->window_number;
+				char msg[128];
+				seprintf(msg, lastof(msg), "!lockp %i", company2 + 1);
+				NetworkClientSendChatToServer(msg);
+				MarkWholeScreenDirty();
 				break;
 			}
 #endif /* ENABLE_NETWORK */
diff -r e16bdc0054ce src/crashlog.cpp
--- a/src/crashlog.cpp
+++ b/src/crashlog.cpp
@@ -87,7 +87,7 @@
 char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const
 {
 	return buffer + seprintf(buffer, last,
-			"OpenTTD version:\n"
+			"OpenTTD version: Novapolis patched client  http://www.novapolis.net\n\n\n"
 			" Version:    %s (%d)\n"
 			" NewGRF ver: %08x\n"
 			" Bits:       %d\n"
@@ -318,7 +318,7 @@
 char *CrashLog::FillCrashLog(char *buffer, const char *last) const
 {
 	time_t cur_time = time(NULL);
-	buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n");
+	buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\nNovapolis patched client  http://www.novapolis.net\nPlease, unless you encounter this bug with unpatched OpenTTD version, report bug to Novapolis team\n\n");
 	buffer += seprintf(buffer, last, "Crash at: %s", asctime(gmtime(&cur_time)));
 
 	YearMonthDay ymd;
diff -r e16bdc0054ce src/depot_gui.cpp
--- a/src/depot_gui.cpp
+++ b/src/depot_gui.cpp
@@ -28,7 +28,7 @@
 #include "vehiclelist.h"
 #include "order_backup.h"
 #include "zoom_func.h"
-
+#include "hotkeys.h"
 #include "widgets/depot_widget.h"
 
 #include "table/strings.h"
@@ -81,34 +81,6 @@
 	EndContainer(),
 };
 
-static WindowDesc _train_depot_desc(
-	WDP_AUTO, "depot_train", 362, 123,
-	WC_VEHICLE_DEPOT, WC_NONE,
-	0,
-	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
-);
-
-static WindowDesc _road_depot_desc(
-	WDP_AUTO, "depot_roadveh", 316, 97,
-	WC_VEHICLE_DEPOT, WC_NONE,
-	0,
-	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
-);
-
-static WindowDesc _ship_depot_desc(
-	WDP_AUTO, "depot_ship", 306, 99,
-	WC_VEHICLE_DEPOT, WC_NONE,
-	0,
-	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
-);
-
-static WindowDesc _aircraft_depot_desc(
-	WDP_AUTO, "depot_aircraft", 332, 99,
-	WC_VEHICLE_DEPOT, WC_NONE,
-	0,
-	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
-);
-
 extern void DepotSortList(VehicleList *list);
 
 /**
@@ -297,9 +269,16 @@
 						this->sel, EIT_IN_DEPOT, free_wagon ? 0 : this->hscroll->GetPosition(), this->vehicle_over);
 
 				/* Length of consist in tiles with 1 fractional digit (rounded up) */
-				SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE));
-				SetDParam(1, 1);
-				DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter
+				if (_settings_client.gui.old_depot_train_length_calc) {
+					SetDParam(0, CeilDiv(u->gcache.cached_total_length, 8));
+					SetDParam(1, 1);
+					DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT); // Draw the counter
+				}
+				else {
+					SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE));
+					SetDParam(1, 1);
+					DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter
+				}
 				break;
 			}
 
@@ -1017,8 +996,24 @@
 
 		return ES_NOT_HANDLED;
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		if (this->owner != _local_company) return ES_NOT_HANDLED;
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey depot_hotkeys[] = {
+	Hotkey(WKC_CTRL | 'F', "depot_go_all", WID_D_START_ALL),
+	Hotkey('R', "depot_build_vehicle", WID_D_BUILD),
+	Hotkey(WKC_NONE, "depot_clone_vehicle", WID_D_CLONE),
+	HOTKEY_LIST_END
+};
+HotkeyList DepotWindow::hotkeys("depot_gui", depot_hotkeys);
+
 static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
 {
 	if (confirmed) {
@@ -1029,6 +1024,38 @@
 	}
 }
 
+static WindowDesc _train_depot_desc(
+	WDP_AUTO, "depot_train", 362, 123,
+	WC_VEHICLE_DEPOT, WC_NONE,
+	0,
+	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets),
+	&DepotWindow::hotkeys
+);
+
+static WindowDesc _road_depot_desc(
+	WDP_AUTO, "depot_roadveh", 316, 97,
+	WC_VEHICLE_DEPOT, WC_NONE,
+	0,
+	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets),
+	&DepotWindow::hotkeys
+);
+
+static WindowDesc _ship_depot_desc(
+	WDP_AUTO, "depot_ship", 306, 99,
+	WC_VEHICLE_DEPOT, WC_NONE,
+	0,
+	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets),
+	&DepotWindow::hotkeys
+);
+
+static WindowDesc _aircraft_depot_desc(
+	WDP_AUTO, "depot_aircraft", 332, 99,
+	WC_VEHICLE_DEPOT, WC_NONE,
+	0,
+	_nested_train_depot_widgets, lengthof(_nested_train_depot_widgets),
+	&DepotWindow::hotkeys
+);
+
 /**
  * Opens a depot window
  * @param tile The tile where the depot/hangar is located
diff -r e16bdc0054ce src/economy.cpp
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -53,6 +53,7 @@
 
 #include "table/strings.h"
 #include "table/pricebase.h"
+#include "cargo_table_gui.h"
 
 #include "safeguards.h"
 
@@ -386,6 +387,8 @@
 		/* Reset the ratings for the old owner */
 		t->ratings[old_owner] = RATING_INITIAL;
 		ClrBit(t->have_ratings, old_owner);
+		ClrBit(t->advertise_regularly, old_owner);
+		ClrBit(t->do_powerfund, old_owner);
 
 		/* Transfer exclusive rights */
 		if (t->exclusive_counter > 0 && t->exclusivity == old_owner) {
@@ -1108,6 +1111,14 @@
 	const CargoSpec *cs = CargoSpec::Get(cargo_type);
 	st->town->received[cs->town_effect].new_act += accepted;
 
+	/* Increase town's counter for all goods types only if delivered near town*/
+	if(CB_Enabled()){
+		if (_settings_client.gui.cb_distance_check == 0 || (DistanceManhattan(st->town->xy, st->xy) <= _settings_client.gui.cb_distance_check)) {
+			st->town->new_act_cargo[cargo_type] += accepted;
+			InvalidateWindowData(WC_CB_TOWN, st->town->index);
+		}
+	}
+
 	/* Determine profit */
 	Money profit = GetTransportedGoodsIncome(accepted, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type);
 
@@ -1124,6 +1135,16 @@
 		}
 	}
 
+	company->cargo_income[cargo_type] += profit;
+	company->cargo_units[cargo_type] += num_pieces;
+
+	company->cargo_income_period[0][cargo_type] += profit;
+	company->cargo_units_period[0][cargo_type] += num_pieces;
+
+	company->cur_economy.cargo_income[cargo_type] += profit;
+
+	InvalidateCargosWindows(company->index);
+
 	return profit;
 }
 
@@ -1950,6 +1971,11 @@
 	}
 	CompaniesPayInterest();
 	HandleEconomyFluctuations();
+
+	Company *c;
+	FOR_ALL_COMPANIES(c){
+		CargoResetPeriods(c);
+	}
 }
 
 static void DoAcquireCompany(Company *c)
diff -r e16bdc0054ce src/gfx.cpp
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -34,6 +34,7 @@
 byte _support8bpp;
 CursorVars _cursor;
 bool _ctrl_pressed;   ///< Is Ctrl pressed?
+bool _alt_pressed;    ///< Is Alt pressed?
 bool _shift_pressed;  ///< Is Shift pressed?
 byte _fast_forward;
 bool _left_button_down;     ///< Is left mouse button pressed?
diff -r e16bdc0054ce src/gfx_func.h
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -55,6 +55,7 @@
 extern byte _support8bpp;
 extern CursorVars _cursor;
 extern bool _ctrl_pressed;   ///< Is Ctrl pressed?
+extern bool _alt_pressed;    ///< Is Alt pressed?
 extern bool _shift_pressed;  ///< Is Shift pressed?
 extern byte _fast_forward;
 
diff -r e16bdc0054ce src/gfx_type.h
--- a/src/gfx_type.h
+++ b/src/gfx_type.h
@@ -104,6 +104,16 @@
 	WKC_COMMA       = 151, ///< , Comma
 	WKC_PERIOD      = 152, ///< . Period
 	WKC_MINUS       = 153, ///< - Minus
+
+	WKC_L_BRACE     = 154, ///< { Left brace
+	WKC_R_BRACE     = 155, ///< } Right brace
+	
+	WKC_L_PAREN     = 157, ///< ( Left parentheses
+	WKC_R_PAREN     = 158, ///< ) Right parentheses
+	WKC_PLUS        = 159, ///< + Plus
+	WKC_EXCLAIM     = 160, ///< ! Exclamation mark
+	WKC_ASTERISK    = 161, ///< * Asterisk
+	WKC_DOLLAR      = 162, ///< $ Dollar sign
 };
 
 /** A single sprite of a list of animated cursors */
diff -r e16bdc0054ce src/gfxinit.cpp
--- a/src/gfxinit.cpp
+++ b/src/gfxinit.cpp
@@ -192,6 +192,7 @@
 			i++
 		);
 	}
+	LoadGrfFile("innerhighlight.grf", SPR_INNER_HIGHLIGHT_BASE, i++);
 
 	/* Initialize the unicode to sprite mapping table */
 	InitializeUnicodeGlyphMap();
diff -r e16bdc0054ce src/goal_gui.cpp
--- a/src/goal_gui.cpp
+++ b/src/goal_gui.cpp
@@ -184,7 +184,15 @@
 
 		resize->height = d.height;
 
-		d.height *= 5;
+		uint num = 0;
+		const Goal *s;
+		FOR_ALL_GOALS(s) {
+			if (s->company == INVALID_COMPANY || s->company == this->window_number) {
+				num++;
+			}
+		}
+
+		d.height *= (5 + num);
 		d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT;
 		d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
 		*size = maxdim(*size, d);
diff -r e16bdc0054ce src/graph_gui.cpp
--- a/src/graph_gui.cpp
+++ b/src/graph_gui.cpp
@@ -103,6 +103,23 @@
 	}
 };
 
+
+/** Construct the row containing the digit keys. */
+static NWidgetBase *MakeCargoButtons(int *biggest_index)
+{
+	NWidgetVertical *ver = new NWidgetVertical;
+
+	for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+		NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, WID_CPR_CARGO_FIRST + i, NULL);
+		leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO;
+		leaf->SetFill(1, 0);
+		leaf->SetLowered(true);
+		ver->Add(leaf);
+	}
+	*biggest_index = WID_CPR_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1;
+	return ver;
+}
+
 /**
  * Construct a vertical list of buttons, one for each company.
  * @param biggest_index Storage for collecting the biggest index used in the returned tree.
@@ -533,10 +550,64 @@
 		return INVALID_DATAPOINT;
 	}
 
+	void UpdateExcludedData()
+	{
+		this->excluded_data = 0;
+
+		int i = 0;
+		const CargoSpec *cs;
+		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+			if (HasBit(_legend_excluded_cargo, cs->Index())) SetBit(this->excluded_data, i);
+			i++;
+		}
+	}
+
+	void UpdateLoweredWidgets()
+	{
+		for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+			this->SetWidgetLoweredState(WID_CPR_CARGO_FIRST + i, !HasBit(this->excluded_data, i));
+		}
+	}
+
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
+		switch (widget) {
 		/* Clicked on legend? */
-		if (widget == WID_CV_KEY_BUTTON) ShowGraphLegend();
+			case WID_CV_KEY_BUTTON:
+				ShowGraphLegend();
+				break;
+			case WID_CPR_ENABLE_CARGOES:
+				/* Remove all cargoes from the excluded lists. */
+				_legend_excluded_cargo = 0;
+				this->excluded_data = 0;
+				this->UpdateLoweredWidgets();
+				this->SetDirty();
+				break;
+
+			case WID_CPR_DISABLE_CARGOES: {
+				/* Add all cargoes to the excluded lists. */
+				int i = 0;
+				const CargoSpec *cs;
+				FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+					SetBit(_legend_excluded_cargo, cs->Index());
+					SetBit(this->excluded_data, i);
+					i++;
+				}
+				this->UpdateLoweredWidgets();
+				this->SetDirty();
+				break;
+			}
+
+			default:
+				if (widget >= WID_CPR_CARGO_FIRST) {
+					int i = widget - WID_CPR_CARGO_FIRST;
+					ToggleBit(_legend_excluded_cargo, _sorted_cargo_specs[i]->Index());
+					this->ToggleWidgetLoweredState(widget);
+					this->UpdateExcludedData();
+					this->SetDirty();
+				}
+				break;
+		}
 	}
 
 	virtual void OnTick()
@@ -674,8 +745,60 @@
 
 	virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 	{
+		if(_legend_excluded_cargo == 0){
 		return c->old_economy[j].income;
 	}
+		uint total_income = 0;
+		const CargoSpec *cs;
+		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+			if (!HasBit(_legend_excluded_cargo, cs->Index())){
+				total_income += c->old_economy[j].cargo_income[cs->Index()];
+			}
+		}
+		return total_income;
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		if (widget < WID_CPR_CARGO_FIRST) {
+			BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
+			return;
+		}
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST];
+		SetDParam(0, cs->name);
+		Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO);
+		d.width += 14; // colour field
+		d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+		d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+		*size = maxdim(d, *size);
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget < WID_CPR_CARGO_FIRST) {
+			BaseGraphWindow::DrawWidget(r, widget);
+			return;
+		}
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST];
+		bool rtl = _current_text_dir == TD_RTL;
+
+		/* Since the buttons have no text, no images,
+		 * both the text and the coloured 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 = this->IsWidgetLowered(widget) ? 1 : 0;
+		int x = r.left + WD_FRAMERECT_LEFT;
+		int y = r.top;
+
+		int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT);
+
+		GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK);
+		GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour);
+		SetDParam(0, cs->name);
+		DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
+	}
 };
 
 static const NWidgetPart _nested_income_graph_widgets[] = {
@@ -690,6 +813,14 @@
 	NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND),
 		NWidget(NWID_HORIZONTAL),
 			NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
+			NWidget(NWID_VERTICAL),//add
+				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0), SetResize(0, 1),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0),
+				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
+				NWidgetFunction(MakeCargoButtons),
+				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), SetResize(0, 1),
+			EndContainer(),//add
 			NWidget(NWID_VERTICAL),
 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
 				NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE),
@@ -723,8 +854,60 @@
 
 	virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 	{
+		if(_legend_excluded_cargo == 0){
 		return c->old_economy[j].delivered_cargo.GetSum<OverflowSafeInt64>();
 	}
+		uint total_delivered = 0;
+		const CargoSpec *cs;
+		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+			if (!HasBit(_legend_excluded_cargo, cs->Index())){
+				total_delivered += c->old_economy[j].delivered_cargo[cs->Index()];
+			}
+		}
+		return total_delivered;
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		if (widget < WID_CPR_CARGO_FIRST) {
+			BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
+			return;
+		}
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST];
+		SetDParam(0, cs->name);
+		Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO);
+		d.width += 14; // colour field
+		d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+		d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+		*size = maxdim(d, *size);
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget < WID_CPR_CARGO_FIRST) {
+			BaseGraphWindow::DrawWidget(r, widget);
+			return;
+		}
+
+		const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST];
+		bool rtl = _current_text_dir == TD_RTL;
+
+		/* Since the buttons have no text, no images,
+		 * both the text and the coloured 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 = this->IsWidgetLowered(widget) ? 1 : 0;
+		int x = r.left + WD_FRAMERECT_LEFT;
+		int y = r.top;
+
+		int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT);
+
+		GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK);
+		GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour);
+		SetDParam(0, cs->name);
+		DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
+	}
 };
 
 static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
@@ -739,6 +922,15 @@
 	NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND),
 		NWidget(NWID_HORIZONTAL),
 			NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
+			NWidget(NWID_VERTICAL),//add
+				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0), SetResize(0, 1),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0),
+				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
+				NWidgetFunction(MakeCargoButtons),
+				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), SetResize(0, 1),
+			EndContainer(),//add
+			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
 			NWidget(NWID_VERTICAL),
 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
 				NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE),
@@ -899,7 +1091,7 @@
 		}
 		this->first_init = false;
 	}
-
+/*
 	void UpdateExcludedData()
 	{
 		this->excluded_data = 0;
@@ -918,7 +1110,7 @@
 			this->SetWidgetLoweredState(WID_CPR_CARGO_FIRST + i, !HasBit(this->excluded_data, i));
 		}
 	}
-
+*/
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
 		if (widget < WID_CPR_CARGO_FIRST) {
@@ -960,12 +1152,12 @@
 		SetDParam(0, cs->name);
 		DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
 	}
-
+/*
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
 		switch (widget) {
 			case WID_CPR_ENABLE_CARGOES:
-				/* Remove all cargoes from the excluded lists. */
+				/* Remove all cargoes from the excluded lists. * /
 				_legend_excluded_cargo = 0;
 				this->excluded_data = 0;
 				this->UpdateLoweredWidgets();
@@ -973,7 +1165,7 @@
 				break;
 
 			case WID_CPR_DISABLE_CARGOES: {
-				/* Add all cargoes to the excluded lists. */
+				/* Add all cargoes to the excluded lists. * /
 				int i = 0;
 				const CargoSpec *cs;
 				FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
@@ -997,7 +1189,7 @@
 				break;
 		}
 	}
-
+*/
 	virtual void OnTick()
 	{
 		/* Override default OnTick */
@@ -1031,23 +1223,6 @@
 	}
 };
 
-/** Construct the row containing the digit keys. */
-static NWidgetBase *MakeCargoButtons(int *biggest_index)
-{
-	NWidgetVertical *ver = new NWidgetVertical;
-
-	for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
-		NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, WID_CPR_CARGO_FIRST + i, NULL);
-		leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO;
-		leaf->SetFill(1, 0);
-		leaf->SetLowered(true);
-		ver->Add(leaf);
-	}
-	*biggest_index = WID_CPR_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1;
-	return ver;
-}
-
-
 static const NWidgetPart _nested_cargo_payment_rates_widgets[] = {
 	NWidget(NWID_HORIZONTAL),
 		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
diff -r e16bdc0054ce src/gui.h
--- a/src/gui.h
+++ b/src/gui.h
@@ -39,12 +39,16 @@
 /* airport_gui.cpp */
 Window *ShowBuildAirToolbar();
 
+/* commands_gui.cpp */
+void ShowCommandsToolbar();
+void ShowLoginWindow();
+
 /* tgp_gui.cpp */
 void ShowGenerateLandscape();
 void ShowHeightmapLoad();
 
 /* misc_gui.cpp */
-void ShowLandInfo(TileIndex tile);
+void ShowLandInfo(TileIndex tile, TileIndex end_tile=INVALID_TILE);
 void ShowAboutWindow();
 void ShowBuildTreesToolbar();
 void ShowTownDirectory();
diff -r e16bdc0054ce src/hotkeys.cpp
--- a/src/hotkeys.cpp
+++ b/src/hotkeys.cpp
@@ -61,6 +61,22 @@
 	{"NUM_MINUS", WKC_NUM_MINUS},
 	{"=", WKC_EQUALS},
 	{"-", WKC_MINUS},
+
+	{"BACKSPACE", WKC_BACKSPACE},
+	{"SLASH", WKC_SLASH},
+	{"SEMICOLON", WKC_SEMICOLON},
+	{"L_BRACKET", WKC_L_BRACKET},
+	{"BACKSLASH", WKC_BACKSLASH},
+	{"R_BRACKET", WKC_R_BRACKET},
+	{"SINGLEQUOTE", WKC_SINGLEQUOTE},
+	{"PERIOD", WKC_PERIOD},
+
+	{"L_BRACE", WKC_L_BRACE},
+	{"R_BRACE", WKC_R_BRACE},
+	{"L_PAREN", WKC_L_PAREN},
+	{"R_PAREN", WKC_R_PAREN},
+	{"EXCLAIM", WKC_EXCLAIM},
+	{"ASTERISK", WKC_ASTERISK},
 };
 
 /**
diff -r e16bdc0054ce src/industry_cmd.cpp
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -1844,6 +1844,40 @@
 }
 
 /**
+  * Return whether industry can be built on tile or not
+  * regardless of terrain
+  */
+bool CanBuildIndustryOnTile(IndustryType type, TileIndex tile) {
+	const IndustrySpec *indspec = GetIndustrySpec(type);
+    CommandCost ret;
+
+	if (HasBit(indspec->callback_mask, CBM_IND_LOCATION)) {
+		ret = CheckIfCallBackAllowsCreation(
+			tile, type, 0, 0, 0, _current_company,
+			_current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION);
+	} else {
+		ret = _check_new_industry_procs[GetIndustrySpec(type)->check_proc](tile);
+	}
+	if (ret.Failed())
+		return false;
+
+	ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
+	if (ret.Failed())
+		return false;
+
+	Town *t = NULL;
+	ret = FindTownForIndustry(tile, type, &t);
+	if (ret.Failed())
+		return false;
+
+	ret = CheckIfIndustryIsAllowed(tile, type, t);
+	if (ret.Failed())
+		return false;
+
+	return true;
+}
+
+/**
  * Build/Fund an industry
  * @param tile tile where industry is built
  * @param flags of operations to conduct
diff -r e16bdc0054ce src/industry_gui.cpp
--- a/src/industry_gui.cpp
+++ b/src/industry_gui.cpp
@@ -30,6 +30,7 @@
 #include "tilehighlight_func.h"
 #include "string_func.h"
 #include "sortlist_type.h"
+#include "widgets/dropdown_type.h"
 #include "widgets/dropdown_func.h"
 #include "company_base.h"
 #include "core/geometry_func.hpp"
@@ -41,6 +42,7 @@
 #include "widgets/industry_widget.h"
 
 #include "table/strings.h"
+#include "hotkeys.h"
 
 #include <bitset>
 
@@ -180,6 +182,21 @@
 	EndContainer(),
 	NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_DPI_INFOPANEL), SetResize(1, 0),
 	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetResize(1, 0),
+		NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
+			NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(140, 14), SetDataTip(STR_FUND_INDUSTRY_FORBIDDEN_TILES_TITLE, STR_NULL),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+		EndContainer(),
+		NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_DPI_FT_OFF), SetMinimalSize(60, 12),
+											SetDataTip(STR_FUND_INDUSTRY_FORBIDDEN_TILES_OFF, STR_FUND_INDUSTRY_FORBIDDEN_TILES_OFF_TOOLTIP),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_DPI_FT_ON), SetMinimalSize(60, 12),
+											SetDataTip(STR_FUND_INDUSTRY_FORBIDDEN_TILES_ON, STR_FUND_INDUSTRY_FORBIDDEN_TILES_ON_TOOLTIP),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+		EndContainer(),
+		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+	EndContainer(),
 	NWidget(NWID_HORIZONTAL),
 		NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_DISPLAY_WIDGET), SetFill(1, 0), SetResize(1, 0),
 				SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
@@ -188,14 +205,6 @@
 	EndContainer(),
 };
 
-/** Window definition of the dynamic place industries gui */
-static WindowDesc _build_industry_desc(
-	WDP_AUTO, "build_industry", 170, 212,
-	WC_BUILD_INDUSTRY, WC_NONE,
-	WDF_CONSTRUCTION,
-	_nested_build_industry_widgets, lengthof(_nested_build_industry_widgets)
-);
-
 /** Build (fund or prospect) a new industry, */
 class BuildIndustryWindow : public Window {
 	int selected_index;                         ///< index of the element in the matrix
@@ -206,6 +215,7 @@
 	IndustryType index[NUM_INDUSTRYTYPES + 1];  ///< Type of industry, in the order it was loaded
 	bool enabled[NUM_INDUSTRYTYPES + 1];        ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever)
 	Scrollbar *vscroll;
+	bool funding_enabled;
 
 	/** The offset for the text in the matrix. */
 	static const int MATRIX_TEXT_OFFSET = 17;
@@ -254,20 +264,24 @@
 		if (this->selected_index == -1) {
 			this->selected_index = 0;
 			this->selected_type = this->index[0];
+			SetIndustryForbiddenTilesHighlight(this->selected_type);
 		}
 
 		this->vscroll->SetCount(this->count);
+
+		this->funding_enabled = (_game_mode == GM_EDITOR || Company::IsValidID(_local_company));
 	}
 
 	/** Update status of the fund and display-chain widgets. */
 	void SetButtons()
 	{
-		this->SetWidgetDisabledState(WID_DPI_FUND_WIDGET, this->selected_type != INVALID_INDUSTRYTYPE && !this->enabled[this->selected_index]);
+		this->SetWidgetDisabledState(WID_DPI_FUND_WIDGET,  !this->funding_enabled || (this->selected_type != INVALID_INDUSTRYTYPE && !this->enabled[this->selected_index]));
 		this->SetWidgetDisabledState(WID_DPI_DISPLAY_WIDGET, this->selected_type == INVALID_INDUSTRYTYPE && this->enabled[this->selected_index]);
+		this->LowerWidget(_settings_client.gui.show_industry_forbidden_tiles + WID_DPI_FT_OFF);
 	}
 
 public:
-	BuildIndustryWindow() : Window(&_build_industry_desc)
+	BuildIndustryWindow(WindowDesc *desc) : Window(desc)
 	{
 		this->timer_enabled = _loaded_newgrf_features.has_newindustries;
 
@@ -275,6 +289,7 @@
 		this->selected_type = INVALID_INDUSTRYTYPE;
 
 		this->callback_timer = DAY_TICKS;
+		this->funding_enabled = false;
 
 		this->CreateNestedTree();
 		this->vscroll = this->GetScrollbar(WID_DPI_SCROLLBAR);
@@ -283,6 +298,11 @@
 		this->SetButtons();
 	}
 
+	~BuildIndustryWindow()
+	{
+		SetIndustryForbiddenTilesHighlight(INVALID_INDUSTRYTYPE);
+	}
+
 	virtual void OnInit()
 	{
 		this->SetupArrays();
@@ -492,6 +512,7 @@
 				if (y < this->count) { // Is it within the boundaries of available data?
 					this->selected_index = y;
 					this->selected_type = this->index[y];
+					SetIndustryForbiddenTilesHighlight(this->selected_type);
 					const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type);
 
 					this->SetDirty();
@@ -535,6 +556,16 @@
 				}
 				break;
 			}
+
+			case WID_DPI_FT_OFF:
+			case WID_DPI_FT_ON:
+				this->RaiseWidget(_settings_client.gui.show_industry_forbidden_tiles + WID_DPI_FT_OFF);
+				_settings_client.gui.show_industry_forbidden_tiles = (widget != WID_DPI_FT_OFF);
+				this->LowerWidget(_settings_client.gui.show_industry_forbidden_tiles + WID_DPI_FT_OFF);
+				if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				MarkWholeScreenDirty();
+				break;
 		}
 	}
 
@@ -603,12 +634,12 @@
 
 	virtual void OnTimeout()
 	{
-		this->RaiseButtons();
+		this->RaiseWidget(WID_DPI_FUND_WIDGET);
 	}
 
 	virtual void OnPlaceObjectAbort()
 	{
-		this->RaiseButtons();
+		this->RaiseWidget(WID_DPI_FUND_WIDGET);
 	}
 
 	/**
@@ -625,13 +656,37 @@
 		if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY;
 		this->SetButtons();
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey build_industry_hotkeys[] = {
+	Hotkey((uint16)0, "display_chain", WID_DPI_DISPLAY_WIDGET),
+	Hotkey((uint16)0, "build_button", WID_DPI_FUND_WIDGET),
+	HOTKEY_LIST_END
+};
+
+HotkeyList BuildIndustryWindow::hotkeys("industry_fund_gui", build_industry_hotkeys);
+
+/** Window definition of the dynamic place industries gui */
+static WindowDesc _build_industry_desc(
+	WDP_AUTO, "build_industry", 170, 212,
+	WC_BUILD_INDUSTRY, WC_NONE,
+	WDF_CONSTRUCTION,
+	_nested_build_industry_widgets, lengthof(_nested_build_industry_widgets),
+	&BuildIndustryWindow::hotkeys
+);
+
+
 void ShowBuildIndustryWindow()
 {
-	if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
 	if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return;
-	new BuildIndustryWindow();
+	new BuildIndustryWindow(&_build_industry_desc);
 }
 
 static void UpdateIndustryProduction(Industry *i);
@@ -1059,6 +1114,7 @@
 			NWidget(NWID_HORIZONTAL),
 				NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
 				NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
+				NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_FILTER), SetDataTip(STR_BUTTON_FILTER, STR_TOOLTIP_FILTER_CRITERIA),
 				NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(),
 			EndContainer(),
 			NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(),
@@ -1086,6 +1142,10 @@
 	static const StringID sorter_names[];
 	static GUIIndustryList::SortFunction * const sorter_funcs[];
 
+	/* type_filter[industry_type] is set to true if player wishes that type to by displayed */
+	static bool type_filter[NUM_INDUSTRYTYPES];
+	static bool initialized;
+
 	GUIIndustryList industries;
 	Scrollbar *vscroll;
 
@@ -1097,7 +1157,9 @@
 
 			const Industry *i;
 			FOR_ALL_INDUSTRIES(i) {
-				*this->industries.Append() = i;
+				if (this->type_filter[i->type]){
+					*this->industries.Append() = i;
+				}
 			}
 
 			this->industries.Compact();
@@ -1229,9 +1291,17 @@
 		}
 	}
 
+	void initIndustryTypeFilter()
+	{
+		for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt)
+			this->type_filter[indt] = true;
+			IndustryDirectoryWindow::initialized = true;
+	}
+
 public:
 	IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
 	{
+		if (IndustryDirectoryWindow::initialized == false) this->initIndustryTypeFilter();
 		this->CreateNestedTree();
 		this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR);
 
@@ -1300,6 +1370,11 @@
 				break;
 			}
 
+			case WID_ID_DROPDOWN_FILTER: {
+				size->width = 65;
+				break;
+			}
+
 			case WID_ID_INDUSTRY_LIST: {
 				Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE);
 				for (uint i = 0; i < this->industries.Length(); i++) {
@@ -1328,6 +1403,22 @@
 				ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0);
 				break;
 
+			case WID_ID_DROPDOWN_FILTER: {
+				DropDownList *list = new DropDownList();
+				*list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_ALL,     -2, false);
+				*list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_NONE,    -1, false);
+				*list->Append() = new DropDownListItem(-3, false);
+
+				for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) {
+					const IndustrySpec *inds = GetIndustrySpec(indt);
+					if (inds->enabled)
+						*list->Append() = new DropDownListCheckedItem(inds->name, indt, false, IndustryDirectoryWindow::type_filter[indt]);
+				}
+
+				ShowDropDownList(this, list, -2, WID_ID_DROPDOWN_FILTER, 0, true, false);
+				break;
+			}
+
 			case WID_ID_INDUSTRY_LIST: {
 				uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP);
 				if (p < this->industries.Length()) {
@@ -1344,10 +1435,27 @@
 
 	virtual void OnDropdownSelect(int widget, int index)
 	{
-		if (this->industries.SortType() != index) {
-			this->industries.SetSortType(index);
-			this->BuildSortIndustriesList();
+		if (widget == WID_ID_DROPDOWN_CRITERIA) {
+			if (this->industries.SortType() != index) {
+				this->industries.SetSortType(index);
+			}
 		}
+		else if (widget == WID_ID_DROPDOWN_FILTER) {
+			if ( index == -1 ) { // aka SELECT NONE
+				for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt)
+					IndustryDirectoryWindow::type_filter[indt] = false;
+				// must SetDurty to force redraw of the listing widget
+				this->SetDirty();
+			}
+			else if ( index == -2 ) { // aka SELECT ALL
+				for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt)
+					IndustryDirectoryWindow::type_filter[indt] = true;
+			}
+			else
+				IndustryDirectoryWindow::type_filter[index] = IndustryDirectoryWindow::type_filter[index] ? false: true;
+			this->industries.ForceRebuild();
+		}
+		this->BuildSortIndustriesList();
 	}
 
 	virtual void OnResize()
@@ -1385,6 +1493,8 @@
 
 Listing IndustryDirectoryWindow::last_sorting = {false, 0};
 const Industry *IndustryDirectoryWindow::last_industry = NULL;
+bool IndustryDirectoryWindow::initialized = false;
+bool IndustryDirectoryWindow::type_filter[NUM_INDUSTRYTYPES];
 
 /* Available station sorting functions. */
 GUIIndustryList::SortFunction * const IndustryDirectoryWindow::sorter_funcs[] = {
diff -r e16bdc0054ce src/industry_type.h
--- a/src/industry_type.h
+++ b/src/industry_type.h
@@ -12,6 +12,8 @@
 #ifndef INDUSTRY_TYPE_H
 #define INDUSTRY_TYPE_H
 
+#include "tile_type.h"
+
 typedef uint16 IndustryID;
 typedef uint16 IndustryGfx;
 typedef uint8 IndustryType;
@@ -38,5 +40,6 @@
 static const int INDUSTRY_COMPLETED = 3; ///< final stage of industry construction.
 
 void CheckIndustries();
+bool CanBuildIndustryOnTile(IndustryType type, TileIndex tile);
 
 #endif /* INDUSTRY_TYPE_H */
diff -r e16bdc0054ce src/lang/english.txt
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -232,6 +232,9 @@
 STR_TOOLTIP_SORT_ORDER                                          :{BLACK}Select sorting order (descending/ascending)
 STR_TOOLTIP_SORT_CRITERIA                                       :{BLACK}Select sorting criteria
 STR_TOOLTIP_FILTER_CRITERIA                                     :{BLACK}Select filtering criteria
+STR_BUTTON_FILTER                                               :{BLACK}Filter
+STR_BUTTON_FILTER_SELECT_ALL                                    :Select All
+STR_BUTTON_FILTER_SELECT_NONE                                   :Select None
 STR_BUTTON_SORT_BY                                              :{BLACK}Sort by
 STR_BUTTON_LOCATION                                             :{BLACK}Location
 STR_BUTTON_RENAME                                               :{BLACK}Rename
@@ -273,7 +276,7 @@
 STR_MEASURE_AREA                                                :{BLACK}Area: {NUM} x {NUM}
 STR_MEASURE_LENGTH_HEIGHTDIFF                                   :{BLACK}Length: {NUM}{}Height difference: {HEIGHT}
 STR_MEASURE_AREA_HEIGHTDIFF                                     :{BLACK}Area: {NUM} x {NUM}{}Height difference: {HEIGHT}
-
+STR_MEASURE_DIST_HEIGHTDIFF                                     :{BLACK}Area: {NUM} x {NUM}{}Distance: {NUM}{}Height difference: {HEIGHT}
 
 # These are used in buttons
 STR_SORT_BY_CAPTION_NAME                                        :{BLACK}Name
@@ -322,9 +325,11 @@
 STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES                           :{BLACK}Display subsidies
 STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS            :{BLACK}Display list of company's stations
 STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES                    :{BLACK}Display company finances information
+STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_CARGOS                      :{BLACK}Display company cargos information
 STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL                     :{BLACK}Display general company information
 STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK                          :{BLACK}Display story book
 STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST                          :{BLACK}Display goal list
+STR_TOOLBAR_TOOLTIP_DISPLAY_WATCH                               :{BLACK}Watch company's actions
 STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS                              :{BLACK}Display graphs
 STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE                      :{BLACK}Display company league table
 STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW                    :{BLACK}Fund construction of new industry or list all industries
@@ -376,6 +381,7 @@
 STR_SETTINGS_MENU_SCRIPT_SETTINGS                               :AI/Game script settings
 STR_SETTINGS_MENU_NEWGRF_SETTINGS                               :NewGRF settings
 STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS                          :Transparency options
+STR_SETTINGS_MENU_ZONING                                        :Zoning
 STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED                          :Town names displayed
 STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED                       :Station names displayed
 STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED                           :Waypoint names displayed
@@ -400,6 +406,7 @@
 STR_MAP_MENU_EXTRA_VIEW_PORT                                    :Extra viewport
 STR_MAP_MENU_LINGRAPH_LEGEND                                    :Cargo Flow Legend
 STR_MAP_MENU_SIGN_LIST                                          :Sign list
+STR_MAP_MENU_WATCH_COMPANY                                      :Watch Company
 
 ############ range for town menu starts
 STR_TOWN_MENU_TOWN_DIRECTORY                                    :Town directory
@@ -468,7 +475,7 @@
 
 ############ range for about menu starts
 STR_ABOUT_MENU_LAND_BLOCK_INFO                                  :Land area information
-STR_ABOUT_MENU_SEPARATOR                                        :
+STR_ABOUT_MENU_SEPARATOR                                        :CityMania
 STR_ABOUT_MENU_TOGGLE_CONSOLE                                   :Toggle console
 STR_ABOUT_MENU_AI_DEBUG                                         :AI/Game script debug
 STR_ABOUT_MENU_SCREENSHOT                                       :Screenshot
@@ -479,6 +486,7 @@
 STR_ABOUT_MENU_SPRITE_ALIGNER                                   :Sprite aligner
 STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES                            :Toggle bounding boxes
 STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS                              :Toggle colouring of dirty blocks
+STR_ABOUT_MENU_LOGIN_WINDOW                                     :Login Window
 ############ range ends here
 
 ############ range for ordinal numbers used for the place in the highscore window
@@ -1703,6 +1711,26 @@
 
 STR_CONFIG_SETTING_QUERY_CAPTION                                :{WHITE}Change setting value
 
+STR_CONFIG_SETTING_VEHICLES_CTRL                                :{ORANGE}Controls & Orders
+STR_CONFIG_SETTING_ORDER_SHORTCUTS                              :{ORANGE}Order's Shortcuts
+STR_CONFIG_SETTING_CTRL_ENABLE_CTRLCLICK_STARTSTOP              :Allow ctrl+left-click vehicles to start or stop them: {STRING2}
+STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_TRANSFER                   :"Transfer" orders are "No Loading" by default: {STRING2}
+STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_UNLOAD                     :"Unload all" orders are "No Loading" by default: {STRING2}
+
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLLCLICK                 :ctrl+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLSHIFTLCLICK            :ctrl+shift+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_SHIFTLCLICK                :shift+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTLCLICK                  :alt+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTSHIFTCLICK              :alt+shift+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLALTLCLICK              :ctrl+alt+left-click: {STRING2}
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE                      :do nothing
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FULL_LOAD_ANY             :Full load any cargo
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_TRANSFER_CARGO            :Transfer cargo
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_UNLOAD_ALL                :Force unload of all cargo
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FEEDERLOAD                :Feeder Load (replace first order)
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_FEEDERDROP                :Feeder Unload (replace last order)
+STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NO_LOAD                   :Do not load any cargo
+
 # Config errors
 STR_CONFIG_ERROR                                                :{WHITE}Error with the configuration file...
 STR_CONFIG_ERROR_ARRAY                                          :{WHITE}... error in array '{RAW_STRING}'
@@ -2312,6 +2340,7 @@
 
 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK                   :{BLACK}Build railway track. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate
 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL                         :{BLACK}Build railway track using the Autorail mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate
+STR_RAIL_TOOLBAR_TOOLTIP_BUILD_POLYRAIL                         :{BLACK}Build railway track using the Polyline mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate
 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING         :{BLACK}Build train depot (for buying and servicing trains). Shift toggles building/showing cost estimate
 STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT               :{BLACK}Convert rail to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate
 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION                 :{BLACK}Build railway station. Ctrl enables joining stations. Shift toggles building/showing cost estimate
@@ -2329,6 +2358,7 @@
 # Rail depot construction window
 STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION                       :{WHITE}Train Depot Orientation
 STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP                       :{BLACK}Select railway depot orientation
+STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP                  :{BLACK}Automatically select railway depot orientation based on environment
 
 # Rail waypoint construction window
 STR_WAYPOINT_CAPTION                                            :{WHITE}Waypoint
@@ -2337,6 +2367,8 @@
 # Rail station construction window
 STR_STATION_BUILD_RAIL_CAPTION                                  :{WHITE}Rail Station Selection
 STR_STATION_BUILD_ORIENTATION                                   :{BLACK}Orientation
+STR_STATION_BUILD_ORIENTATION_AUTO                              :{BLACK}Auto
+STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP                      :{BLACK}Automatically select station orientation based on environment
 STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP                  :{BLACK}Select railway station orientation
 STR_STATION_BUILD_NUMBER_OF_TRACKS                              :{BLACK}Number of tracks
 STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP                      :{BLACK}Select number of platforms for railway station
@@ -2392,6 +2424,7 @@
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION                     :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION                  :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD                         :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate
+STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD                         :{BLACK}Build road section using the Autoroad mode with only full tile roads. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM                         :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT               :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate
 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT               :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate
@@ -2412,6 +2445,7 @@
 STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP                 :{BLACK}Select road vehicle depot orientation
 STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION                        :{WHITE}Tram Depot Orientation
 STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP                 :{BLACK}Select tram vehicle depot orientation
+STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP                   :{BLACK}Automatically select road depot orientation based on environment
 
 # Road vehicle station construction window
 STR_STATION_BUILD_BUS_ORIENTATION                               :{WHITE}Bus Station Orientation
@@ -4879,10 +4913,18 @@
 STR_SAVEGAME_NAME_SPECTATOR                                     :Spectator, {1:STRING1}
 
 # Viewport strings
+STR_VIEWPORT_TOWN_POP_VERY_POOR_RATING                          :{WHITE}{TOWN} {RED}({COMMA})
+STR_VIEWPORT_TOWN_POP_MEDIOCRE_RATING                           :{WHITE}{TOWN} {ORANGE}({COMMA})
+STR_VIEWPORT_TOWN_POP_GOOD_RATING                               :{WHITE}{TOWN} {YELLOW}({COMMA})
 STR_VIEWPORT_TOWN_POP                                           :{WHITE}{TOWN} ({COMMA})
+STR_VIEWPORT_TOWN_POP_EXCELLENT_RATING                          :{WHITE}{TOWN} {GREEN}({COMMA})
 STR_VIEWPORT_TOWN                                               :{WHITE}{TOWN}
 STR_VIEWPORT_TOWN_TINY_BLACK                                    :{TINY_FONT}{BLACK}{TOWN}
+STR_VIEWPORT_TOWN_TINY_VERY_POOR_RATING                         :{TINY_FONT}{RED}{TOWN}
+STR_VIEWPORT_TOWN_TINY_MEDIOCRE_RATING                          :{TINY_FONT}{ORANGE}{TOWN}
+STR_VIEWPORT_TOWN_TINY_GOOD_RATING                              :{TINY_FONT}{YELLOW}{TOWN}
 STR_VIEWPORT_TOWN_TINY_WHITE                                    :{TINY_FONT}{WHITE}{TOWN}
+STR_VIEWPORT_TOWN_TINY_EXCELLENT_RATING                         :{TINY_FONT}{GREEN}{TOWN}
 
 STR_VIEWPORT_SIGN_SMALL_BLACK                                   :{TINY_FONT}{BLACK}{SIGN}
 STR_VIEWPORT_SIGN_SMALL_WHITE                                   :{TINY_FONT}{WHITE}{SIGN}
@@ -4968,3 +5010,313 @@
 STR_SHIP                                                        :{BLACK}{SHIP}
 
 STR_TOOLBAR_RAILTYPE_VELOCITY                                   :{STRING} ({VELOCITY})
+
+### PATCH
+STR_TOWN_DIRECTORY_CAPTION_EXTRA                                :{WHITE}Towns ({YELLOW}{COMMA}{WHITE} / {ORANGE}{COMMA}{WHITE})
+STR_LOCAL_AUTHORITY_COMPANY_RATING_NUM                          :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} {BLACK}({COMMA})
+STR_TOWN_VIEW_GROWTH                                            :{BLACK}GR: {ORANGE}{COMMA}{STRING}  {BLACK}Next: {ORANGE}{COMMA}  {BLACK}RH: {ORANGE}{COMMA}  {BLACK}Flag {ORANGE}{NUM}  {BLACK}FB: {ORANGE}{NUM} {BLACK}month{P "" s}
+STR_TOWN_VIEW_GROWTH_RATE_CUSTOM                                :*
+STR_TOWN_VIEW_GROWTH_TILES                                      :{BLACK}HS: {ORANGE}{COMMA}(+{COMMA})  {BLACK}CS: {ORANGE}{COMMA}(+{COMMA})  {BLACK}HR: {ORANGE}{COMMA}(+{COMMA})
+STR_TOWN_VIEW_REALPOP_RATE                                      :{BLACK}Real Population: {YELLOW}{COMMA}  {BLACK}Rating: {YELLOW}{COMMA}
+STR_TOWN_VIEW_HOUSE_STATE                                       :{BLACK}Houses: UC {ORANGE}{COMMA}  {BLACK}RTM: {ORANGE}{COMMA}  {BLACK}DTM: {ORANGE}{COMMA}
+STR_CB_DISTANCE_CHECK                                           :CB town acceptance: {STRING2}
+
+###ADMIN
+STR_WATCH_WINDOW_TITLE                                          :{WHITE}Watching {RAW_STRING}.
+STR_WATCH_CLICK_TO_WATCH_COMPANY                                :{BLACK}Click here to watch company building
+STR_WATCH_CLICK_NEW_WINDOW                                      :{BLACK}Click here to open new watching window
+
+STR_WATCH_WINDOW_TITLE_CLIENT                                   :{WHITE}{RAW_STRING} in {RAW_STRING}({NUM}).
+STR_XI_KICK                                                     :{BLACK}Kick
+STR_XI_KICKC                                                    :{BLACK}Kick from cp
+STR_XI_BAN                                                      :{BLACK}Ban
+STR_XI_BAN1                                                     :{BLACK}Ban (1 day)
+STR_XI_LOCK                                                     :{BLACK}Lock
+STR_XI_UNLOCK                                                   :{BLACK}UNLock
+STR_XI_JOIN                                                     :{BLACK}Join company
+STR_XI_RESET                                                    :{BLACK}Reset company
+STR_XI_WATCH                                                    :Watch
+STR_MOD_COMPANY_RESET_BUTTON                                    :{BLACK}Reset
+STR_MOD_COMPANY_JOIN_BUTTON                                     :{BLACK}Join as mod
+STR_MOD_TOGGLE_LOCK_BUTTON                                      :{BLACK}Lock/unlock
+STR_XI_ENABLE                                                   :{BLACK}En/Dis
+STR_XI_SIGN_TOOLTIP                                             :{BLACK}Put a sign to attract player
+STR_XI_PLAYERS_TOOLTIP                                          :{BLACK}Show clients
+STR_XI_COMPANYW_TOOLTIP                                         :{BLACK}Open Company window
+STR_XI_COMPANYHQ                                                :{BLACK}HQ
+STR_XI_COMPANYHQ_TOOLTIP                                        :{BLACK}Go to company's HQ
+STR_XI_PRIVATE_PLAYER_MESSAGE                                   :{BLACK}.{GREEN}P{BLACK}.
+STR_XI_PRIVATE_PLAYER_MESSAGE_TOOLTIP                           :{BLACK}Send a Custom private message to this player
+STR_XI_PRIVATE_COMPANY_MESSAGE                                  :{BLACK}.{GREEN}C{BLACK}.
+STR_XI_PRIVATE_COMPANY_MESSAGE_TOOLTIP                          :{BLACK}Send a Custom private message to this company
+
+STR_XI_BAN_QUERY                                                :{WHITE}<days> <reason>
+STR_XI_BAN_DAYSDEFAULT                                          :1
+STR_XI_REALY_RESET                                              :{WHITE}Are you sure?.
+STR_XI_RESET_CAPTION                                            :{WHITE}Reset
+
+STR_NETWORK_CLIENT_EXTRA                                        :{WHITE}(#{NUM} in c#{NUM})
+
+######## Zoning toolbar
+
+STR_ZONING_TOOLBAR                                              :{WHITE}Zoning toolbar
+STR_ZONING_OUTER                                                :{BLACK}Outer tile borders:
+STR_ZONING_INNER                                                :{BLACK}Inner tile borders:
+STR_ZONING_OUTER_INFO                                           :{BLACK}Select which type of zoning you want on the outer border of a tile.
+STR_ZONING_INNER_INFO                                           :{BLACK}Select which type of zoning you want on the inner border of a tile.
+
+STR_ZONING_NO_ZONING                                            :{BLACK}Nothing
+STR_ZONING_AUTHORITY                                            :{BLACK}Authority
+STR_ZONING_CAN_BUILD                                            :{BLACK}Where I can't build
+STR_ZONING_STA_CATCH                                            :{BLACK}Station catchment
+STR_ZONING_IND_CATCH                                            :{BLACK}Industry catchment
+STR_ZONING_BUL_CATCH                                            :{BLACK}City catchment
+STR_ZONING_BUL_UNSER                                            :{BLACK}Unserved buildings
+STR_ZONING_IND_UNSER                                            :{BLACK}Unserved industries
+STR_ZONING_TOWN_ZONES                                           :{BLACK}Town zones
+STR_ZONING_CB_TOWN_BORDERS                                      :{BLACK}CB town borders
+STR_ZONING_CB_BORDERS                                           :{BLACK}CB borders
+STR_ZONING_NEW_CB_BORDERS                                           :{BLACK}New CB borders
+STR_ZONING_ADVERTISEMENT_ZONES                                  :{BLACK}Advertisement
+STR_ZONING_TOWN_GROWTH_TILES                                    :{BLACK}Town growth tiles
+STR_ZONING_ACTIVE_STATIONS                                      :{BLACK}Active stations
+
+# Commands toolbar
+STR_TOOLBAR_COMMANDS_CAPTION                                    :{WHITE}Commands
+STR_TOOLBAR_COMMANDS_GOAL_CAPTION                               :{BLACK}Goal
+STR_TOOLBAR_COMMANDS_GOAL_TOOLTIP                               :{BLACK}Send !goal command to server.
+STR_TOOLBAR_COMMANDS_QUEST_CAPTION                              :{BLACK}Quest list
+STR_TOOLBAR_COMMANDS_QUEST_TOOLTIP                              :{BLACK}Send !quest command to server.
+STR_TOOLBAR_COMMANDS_SCORE_CAPTION                              :{BLACK}Score
+STR_TOOLBAR_COMMANDS_SCORE_TOOLTIP                              :{BLACK}Send !score command to server.
+STR_TOOLBAR_COMMANDS_TOWN_CAPTION                               :{BLACK}Town
+STR_TOOLBAR_COMMANDS_TOWN_TOOLTIP                               :{BLACK}Send !town command to server.
+STR_TOOLBAR_COMMANDS_TOWN_ID_CAPTION                            :{BLACK}Town ID
+STR_TOOLBAR_COMMANDS_TOWN_ID_TOOLTIP                            :{BLACK}Send !town c-id command to server.
+STR_TOOLBAR_COMMANDS_HINT_CAPTION                               :{BLACK}CB Hint
+STR_TOOLBAR_COMMANDS_HINT_TOOLTIP                               :{BLACK}Send !hint command to server(Shows town demand in CB mode).
+STR_TOOLBAR_COMMANDS_LOGIN_CAPTION                              :{BLACK}Login
+STR_TOOLBAR_COMMANDS_LOGIN_TOOLTIP                              :{BLACK}Send !login command to server.
+STR_TOOLBAR_COMMANDS_TIMELEFT_CAPTION                           :{BLACK}Timeleft
+STR_TOOLBAR_COMMANDS_TIMELEFT_TOOLTIP                           :{BLACK}Send !timeleft command to server.
+STR_TOOLBAR_COMMANDS_NS_CAPTION                                 :{BLACK}CM{NUM}
+STR_TOOLBAR_COMMANDS_NS_TOOLTIP                                 :{BLACK}Join CM{NUM}
+STR_TOOLBAR_COMMANDS_RESETME_CAPTION                            :{BLACK}ResetMe
+STR_TOOLBAR_COMMANDS_RESETME_TOOLTIP                            :{BLACK}Send !resetme command to server.
+STR_TOOLBAR_COMMANDS_SAVEME_CAPTION                             :{BLACK}SaveMe
+STR_TOOLBAR_COMMANDS_SAVEME_TOOLTIP                             :{BLACK}Send !saveme command to server.
+STR_TOOLBAR_COMMANDS_NAME_CAPTION                               :{BLACK}New name
+STR_TOOLBAR_COMMANDS_NAME_TOOLTIP                               :{BLACK}Send !name command to server.
+STR_TOOLBAR_COMMANDS_INFO_CAPTION                               :{BLACK}Info
+STR_TOOLBAR_COMMANDS_INFO_TOOLTIP                               :{BLACK}Send !info command to server.
+
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_CAPTION                       :{BLACK}Both
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_TOOLTIP                       :{BLACK}Switch cargo buttons to both amount and income
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_CAPTION                     :{BLACK}Income
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_CAPTION                     :{BLACK}Amount
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_A_TOOLTIP                     :{BLACK}Switch cargo buttons to amount
+STR_TOOLBAR_COMMANDS_OPTION_CARGO_I_TOOLTIP                     :{BLACK}Switch cargo buttons to income
+
+
+STR_TOOLBAR_COMMANDS_TOWN_QUERY                                 :{WHITE}Company ID:
+STR_TOOLBAR_COMMANDS_LOGIN_NAME_QUERY                           :{WHITE}<Name> <password>
+STR_TOOLBAR_COMMANDS_LOGIN_PASSWORD_QUERY                       :{WHITE}Password:
+STR_TOOLBAR_COMMANDS_NAME_NEWNAME_QUERY                         :{WHITE}New name:
+
+STR_TOOLBAR_COMMANDS_TOPICS_CAPTION                             :{BLACK}Topics
+STR_TOOLBAR_COMMANDS_TOPICS_TOOLTIP                             :{BLACK}Display help topics
+STR_TOOLBAR_COMMANDS_TOPIC1_CAPTION                             :{BLACK}HELP Login
+STR_TOOLBAR_COMMANDS_TOPIC1_TOOLTIP                             :{BLACK}How to use login
+STR_TOOLBAR_COMMANDS_TOPIC2_CAPTION                             :{BLACK}HELP Coal Accept
+STR_TOOLBAR_COMMANDS_TOPIC2_TOOLTIP                             :{BLACK}What to do when town does not accept Coal
+STR_TOOLBAR_COMMANDS_TOPIC3_CAPTION                             :{BLACK}HELP Food accept
+STR_TOOLBAR_COMMANDS_TOPIC3_TOOLTIP                             :{BLACK}What to do when town does not accept Food
+STR_TOOLBAR_COMMANDS_TOPIC4_CAPTION                             :{BLACK}HELP energy
+STR_TOOLBAR_COMMANDS_TOPIC4_TOOLTIP                             :{BLACK}What are tourists, business mail or energy?
+STR_TOOLBAR_COMMANDS_TOPIC5_CAPTION                             :{BLACK}HELP admin
+STR_TOOLBAR_COMMANDS_TOPIC5_TOOLTIP                             :{BLACK}How to use admin command?
+STR_TOOLBAR_COMMANDS_TOPIC6_CAPTION                             :{BLACK}HELP New Comp.
+STR_TOOLBAR_COMMANDS_TOPIC6_TOOLTIP                             :{BLACK}Why new company can not be starter?
+
+STR_TOOLBAR_COMMANDS_HELP_CAPTION                               :{BLACK}Help
+STR_TOOLBAR_COMMANDS_HELP_TOOLTIP                               :{BLACK}Display Help
+STR_TOOLBAR_COMMANDS_RULES_CAPTION                              :{BLACK}RULES
+STR_TOOLBAR_COMMANDS_RULES_TOOLTIP                              :{BLACK}Show Rules
+STR_TOOLBAR_COMMANDS_CBHINT_CAPTION                             :{BLACK}CB Hint
+STR_TOOLBAR_COMMANDS_CBHINT_TOOLTIP                             :{BLACK}Display help for City builder
+STR_TOOLBAR_COMMANDS_BEST_CAPTION                               :{BLACK}Best
+STR_TOOLBAR_COMMANDS_BEST_TOOLTIP                               :{BLACK}Show 5 best games
+STR_TOOLBAR_COMMANDS_RANK_CAPTION                               :{BLACK}Rank
+STR_TOOLBAR_COMMANDS_RANK_TOOLTIP                               :{BLACK}Show top 10 players
+STR_TOOLBAR_COMMANDS_ME_CAPTION                                 :{BLACK}My Rank
+STR_TOOLBAR_COMMANDS_ME_TOOLTIP                                 :{BLACK}Show your ranking position
+
+#login window
+STR_LOGINWINDOW_CAPTION                                         :{WHITE}Login Window
+STR_LOGINWINDOW_CITYMANIA                                       :{BLACK}CityMania
+STR_LOGINWINDOW_NICE                                            :{BLACK}N-ice
+STR_LOGINWINDOW_BTPRO                                           :{BLACK}BTPro
+STR_LOGINERROR_NOCONNECT                                        :{WHITE}Failed to connect
+STR_LOGINERROR_BADINPUT                                         :{WHITE}Bad username or password
+STR_LOGIN_USERNAME                                              :{WHITE}Username
+STR_LOGIN_PASSWORD                                              :{WHITE}Password
+STR_LOGIN_SET                                                   :{WHITE}Set
+STR_LOGIN_NOTSET                                                :{WHITE}Not Set
+STR_LOGIN_CHANGE_USERNAME                                       :{WHITE}Change username
+STR_LOGIN_CHANGE_PASSWORD                                       :{WHITE}Change password
+STR_LOGIN_SEND_LOGIN_TT                                         :{WHITE}Send Login - you must but on the correct community server
+STR_LOGIN_USERNAME_DISPLAY                                      :{WHITE}{RAW_STRING}
+STR_LOGIN_PASSWORD_DISPLAY                                      :{WHITE}{STRING}
+
+#cargo table
+STR_TOOLBAR_CARGOS_HEADER_CARGO                                 :{BLACK}Cargo Name
+STR_TOOLBAR_CARGOS_HEADER_AMOUNT                                :{BLACK}Amount
+STR_TOOLBAR_CARGOS_HEADER_INCOME                                :{BLACK}Income
+STR_TOOLBAR_CARGOS_HEADER_TOTAL                                 :{BLACK}Total
+STR_TOOLBAR_CARGOS_HEADER_TOTAL_MONTH                           :{BLACK}Total this Month
+
+STR_TOOLBAR_CARGOS_UNITS                                        :{BLACK}{COMMA}
+STR_TOOLBAR_CARGOS_UNITS_TOTAL                                  :{BLACK}{COMMA}
+STR_TOOLBAR_CARGOS_CAPTION                                      :{WHITE}{COMPANY} Cargo Transported {BLACK}{COMPANY_NUM}
+STR_TOOLBAR_CARGOS_NAME                                         :{BLACK}{STRING}
+
+#towns
+STR_TOWN_DIRECTORY_TOWN_COLOUR                                  :{ORANGE}{TOWN}{BLACK} ({COMMA}->{COMMA}) {YELLOW}{COMMA} {P "house" "houses"}
+STR_TOWN_DIRECTORY_CITY_COLOUR                                  :{YELLOW}{TOWN}{BLACK} ({COMMA}->{COMMA}) {YELLOW}{COMMA} {P "house" "houses"}
+STR_OLD_DEPOT_TRAINT_LENGTH                                     :Old depot length format: {STRING2}
+STR_SMALLMAP_TOWN_LARGE                                         :{TINY_FONT}{YELLOW}{TOWN}
+
+STR_SORT_BY_HOUSES                                              :Houses
+STR_SORT_BY_REAL_POPULATION                                     :Real population
+STR_ORDER_DIST                                                  :{NUM}, {NUM}
+
+#server list
+STR_NETWORK_SELECT_CITYMANIA                                    :{BLACK}CityMania
+STR_NETWORK_SELECT_NICE                                         :{BLACK}N-ice
+STR_NETWORK_SELECT_BTPRO                                        :{BLACK}BTPro
+STR_NETWORK_SELECT_REDDIT                                       :{BLACK}reddit
+STR_NETWORK_SELECT_SERVER_TOOLTIP                               :{BLACK}Filter this one
+
+### Town CB gui
+STR_BUTTON_CB                                                   :{STRING}
+STR_BUTTON_CB_YES                                               :{BLACK}CB
+STR_TOWN_VIEW_CB_CAPTION                                        :{WHITE}{TOWN}
+
+STR_CB_LARGE_ADVERTISING_CAMPAIGN                               :{BLACK}Large Advertising
+STR_CB_NEW_BUILDINGS                                            :{BLACK}Fund Buildings
+STR_CB_FUND_REGULAR                                             :{BLACK}Fund Regularly
+STR_CB_FUND_REGULAR_TT                                          :{BLACK}Every time fund buildings is zero and company has enough money, buildings will be funded automatically
+STR_CB_FUNDED_REGULARLY                                         :{GREEN}Town is funded regularly
+STR_CB_ADVERT_REGULAR                                           :{BLACK}Adv. Regularly
+STR_CB_ADVERT_REGULAR_TT                                        :{BLACK}Automatically advertise town whenever stations rating drops below a certain point
+STR_CB_POWERFUND                                                :{BLACK}Powerfund
+STR_CB_ADVERT_REGULAR_RATING_TO_KEEP                            :{BLACK}Keep station rating at
+STR_CB_POWERFUND_TT                                             :{BLACK}Continiously funds town with maximum speed possible
+
+STR_TOWN_CB_FUNDING                                             :{ORANGE}Funded for {YELLOW}{COMMA}{ORANGE} month{P "" s}
+STR_TOWN_CB_GROWING                                             :{GREEN}Town is growing!
+STR_TOWN_CB_NOT_GROWING                                         :{WHITE}Town is not growing
+STR_TOWN_CB_GROWING_DETAIL                                      :{ORANGE}1 house in {YELLOW}{COMMA} {ORANGE}days ({YELLOW}{COMMA}%{ORANGE}). Next House in {YELLOW}{COMMA} {ORANGE}days
+
+STR_TOWN_GROWTH_HEADER_CARGO                                    :{BLACK}Cargo
+STR_TOWN_GROWTH_HEADER_AMOUNT                                   :{BLACK}Delivered
+STR_TOWN_GROWTH_HEADER_REQ                                      :{BLACK}Required
+STR_TOWN_GROWTH_HEADER_LAST                                     :{BLACK}Last Month
+STR_TOWN_GROWTH_HEADER_STORE                                    :{BLACK}Stored
+STR_TOWN_GROWTH_HEADER_STORE_PCT                                :{BLACK}Use%
+STR_TOWN_GROWTH_HEADER_FROM                                     :{BLACK}From
+
+STR_TOWN_CB_CARGO_NAME                                          :{BLACK}{STRING}:
+
+STR_TOWN_CB_CARGO_AMOUNT_GOOD                                   :{GREEN}{COMMA}
+STR_TOWN_CB_CARGO_AMOUNT_BAD                                    :{YELLOW}{COMMA}
+STR_TOWN_CB_CARGO_AMOUNT_NOT                                    :{SILVER}{COMMA}
+
+STR_TOWN_CB_CARGO_REQ_YES                                       :{ORANGE}{COMMA}
+STR_TOWN_CB_CARGO_REQ_NOT                                       :{SILVER}{COMMA}
+
+STR_TOWN_CB_CARGO_STORE_YES                                     :{LTBLUE}{COMMA}
+STR_TOWN_CB_CARGO_STORE_NOT                                     :{SILVER}{COMMA}
+STR_TOWN_CB_CARGO_STORE_DECAY                                   :{BLACK}-
+
+STR_TOWN_CB_CARGO_STORE_PCT_YES                                 :{LTBLUE}{COMMA}%
+STR_TOWN_CB_CARGO_STORE_PCT_NOT                                 :{SILVER}{COMMA}%
+
+STR_TOWN_CB_CARGO_PREVIOUS_YES                                  :{GREEN}{COMMA}
+STR_TOWN_CB_CARGO_PREVIOUS_EDGE                                 :{YELLOW}{COMMA}
+STR_TOWN_CB_CARGO_PREVIOUS_BAD                                  :{RED}{COMMA}
+STR_TOWN_CB_CARGO_PREVIOUS_NOT                                  :{SILVER}{COMMA}
+
+STR_TOWN_CB_CARGO_FROM_YES                                      :{YELLOW}{COMMA}
+STR_TOWN_CB_CARGO_FROM_NOT                                      :{SILVER}{COMMA}
+
+#polyrail double click option
+STR_CONFIG_SETTING_POLYRAIL_DOUBLECLICK_TOOLTIPS                :Enable finishing polyrail with mouse double click{STRING2}
+
+#tooltips extra
+STR_CONFIG_SETTING_ENABLE_EXTRA_TOOLTIPS                        :Enable extra tooltips{STRING2}
+STR_TTE_HOUSE_NAME                                              :{LTBLUE}{STRING}
+STR_TTE_HOUSE                                                   :{BLACK}Population: {NUM}
+STR_TTE_INDUSTRY_NAME                                           :{LTBLUE}{INDUSTRY}
+STR_TTE_INDUSTRY                                                :{WHITE}{STRING}  {BLACK}{CARGO_SHORT} {YELLOW}{NUM} %
+STR_TTE_STATION_NAME                                            :{LTBLUE}{STATION}
+STR_TTE_STATION                                                 :{WHITE}{STRING}  {BLACK}{CARGO_SHORT} {YELLOW}{NUM} %
+STR_LAND_AREA_INFORMATION_POP                                   :{BLACK}Population: {LTBLUE}{NUM}
+
+# Industry funding forbidden tiles
+STR_FUND_INDUSTRY_FORBIDDEN_TILES_TITLE                         :{BLACK}Forbidden areas highlight
+STR_FUND_INDUSTRY_FORBIDDEN_TILES_OFF                           :{BLACK}Off
+STR_FUND_INDUSTRY_FORBIDDEN_TILES_ON                            :{BLACK}On
+STR_FUND_INDUSTRY_FORBIDDEN_TILES_OFF_TOOLTIP                   :{BLACK}Don't highlight areas where particular industry can not be funded
+STR_FUND_INDUSTRY_FORBIDDEN_TILES_ON_TOOLTIP                    :{BLACK}Highlight areas where particular industry can not be funded
+
+STR_CB_GUI_TOWN_VIEW_BUTTON                                     :{BLACK}Town view
+STR_CB_GUI_TOWN_VIEW_TOOLTIP                                    :{BLACK}Show information on town
+
+STR_CONFIG_SETTING_WARN_IF_RUNWAY_IS_TOO_SHORT                  :Warn if airplane has in its orders an airport whose runway is too short
+
+STR_CONFIG_SETTING_POWERFUND_MONEY                              :Powerfund minimum needed money for fund: {STRING2}
+STR_CONFIG_SETTING_POWERFUND_HOUSES                             :Maximum amount of houses to powerfund up to: {STRING2}
+
+STR_STATION_RATING_TOOLTIP_RATING_DETAILS                       :{STRING} Rating Details
+STR_STATION_RATING_TOOLTIP_TOTAL_RATING                         :Total target rating: {LTBLUE}{NUM}%
+STR_STATION_RATING_TOOLTIP_NEWGRF_RATING                        :NewGRF station rating: {STRING1} {BLACK}based on
+STR_STATION_RATING_TOOLTIP_NEWGRF_RATING_0                      :{GOLD}{NUM}%
+STR_STATION_RATING_TOOLTIP_NEWGRF_RATING_1                      :{LTBLUE}+{NUM}%
+STR_STATION_RATING_TOOLTIP_NEWGRF_SPEED                         :Max speed of last vehicle: {LTBLUE}{VELOCITY}
+STR_STATION_RATING_TOOLTIP_NEWGRF_WAITUNITS                     :Units of cargo waiting: {LTBLUE}{NUM}
+STR_STATION_RATING_TOOLTIP_NEWGRF_WAITTIME                      :Time since last pickup: {LTBLUE}{NUM} days
+
+STR_STATION_RATING_TOOLTIP_SPEED                                :Max speed of last vehicle (max 17%): {STRING2}
+STR_STATION_RATING_TOOLTIP_SPEED_MAX                            :{GREEN}{VELOCITY} or more, +{NUM}%
+STR_STATION_RATING_TOOLTIP_SPEED_ZERO                           :{RED}{VELOCITY}, {NUM}%
+STR_STATION_RATING_TOOLTIP_SPEED_0                              :{ORANGE}{VELOCITY}, +{NUM}%
+STR_STATION_RATING_TOOLTIP_SPEED_1                              :{GOLD}{VELOCITY}, +{NUM}%
+STR_STATION_RATING_TOOLTIP_SPEED_2                              :{YELLOW}{VELOCITY}, +{NUM}%
+STR_STATION_RATING_TOOLTIP_SPEED_3                              :{GREEN}{VELOCITY}, +{NUM}%
+
+STR_STATION_RATING_TOOLTIP_AGE                                  :Age of last vehicle (max 13%): {STRING2}
+STR_STATION_RATING_TOOLTIP_AGE_0                                :{ORANGE}{NUM} years, {NUM}%
+STR_STATION_RATING_TOOLTIP_AGE_1                                :{GOLD}{NUM} years, +{NUM}%
+STR_STATION_RATING_TOOLTIP_AGE_2                                :{YELLOW}{NUM} year, +{NUM}%
+STR_STATION_RATING_TOOLTIP_AGE_3                                :{GREEN}{NUM} years, +{NUM}%
+
+STR_STATION_RATING_TOOLTIP_WAITTIME                             :Time since last pickup (max 51%): {STRING2}
+STR_STATION_RATING_TOOLTIP_WAITTIME_SHIP                        :Time since last pickup (max 51%): {STRING2} (by ship)
+STR_STATION_RATING_TOOLTIP_WAITTIME_0                           :{RED}{NUM} days, {NUM}%
+STR_STATION_RATING_TOOLTIP_WAITTIME_1                           :{ORANGE}{NUM} days, +{NUM}%
+STR_STATION_RATING_TOOLTIP_WAITTIME_2                           :{GOLD}{NUM} days, +{NUM}%
+STR_STATION_RATING_TOOLTIP_WAITTIME_3                           :{YELLOW}{NUM} days, +{NUM}%
+STR_STATION_RATING_TOOLTIP_WAITTIME_4                           :{GREEN}{NUM} day{P "" s}, +{NUM}%
+
+STR_STATION_RATING_TOOLTIP_WAITUNITS                            :Units of cargo waiting (max 16%): {STRING2}
+STR_STATION_RATING_TOOLTIP_WAITUNITS_0                          :{RED}{NUM}, {NUM}%
+STR_STATION_RATING_TOOLTIP_WAITUNITS_1                          :{ORANGE}{NUM}, {NUM}%
+STR_STATION_RATING_TOOLTIP_WAITUNITS_2                          :{GOLD}{NUM}, {NUM}%
+STR_STATION_RATING_TOOLTIP_WAITUNITS_3                          :{YELLOW}{NUM}, +{NUM}%
+STR_STATION_RATING_TOOLTIP_WAITUNITS_4                          :{YELLOW}{NUM}, +{NUM}%
+STR_STATION_RATING_TOOLTIP_WAITUNITS_5                          :{GREEN}{NUM}, +{NUM}%
+
+STR_STATION_RATING_TOOLTIP_STATUE                               :Statue in town (max 10%): {STRING}
+STR_STATION_RATING_TOOLTIP_STATUE_NO                            :{GOLD}no, 0%
+STR_STATION_RATING_TOOLTIP_STATUE_YES                           :{GREEN}yes, +10%
diff -r e16bdc0054ce src/main_gui.cpp
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -107,7 +107,7 @@
 	if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
 	w->SetDirty();
 
-	if (w->IsWidgetLowered(widget)) {
+	if (w->IsWidgetLowered(widget) && mode == _thd.place_mode) {
 		ResetObjectToPlace();
 		return false;
 	}
@@ -227,6 +227,7 @@
 	GHK_TOGGLE_INVISIBILITY = GHK_TOGGLE_TRANSPARENCY + 9,
 	GHK_TRANSPARENCY_TOOLBAR = GHK_TOGGLE_INVISIBILITY + 8,
 	GHK_TRANSPARANCY,
+	GHK_BORROW_ALL,
 	GHK_CHAT,
 	GHK_CHAT_ALL,
 	GHK_CHAT_COMPANY,
@@ -393,6 +394,10 @@
 				ResetRestoreAllTransparency();
 				break;
 
+			case GHK_BORROW_ALL:
+				DoCommandP(0, 0, 1, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
+				break;
+
 #ifdef ENABLE_NETWORK
 			case GHK_CHAT: // smart chat; send to team if any, otherwise to all
 				if (_networking) {
@@ -465,6 +470,11 @@
 		InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true);
 	}
 
+	virtual void OnMouseOver(Point pt, int widget)
+	{
+		if (_game_mode != GM_MENU && _settings_client.gui.enable_extra_tooltips && pt.x != -1) GuiPrepareTooltipsExtra(this);
+	}
+
 	static HotkeyList hotkeys;
 };
 
@@ -511,6 +521,7 @@
 	Hotkey('8' | WKC_CTRL | WKC_SHIFT, "invisibility_catenary", GHK_TOGGLE_INVISIBILITY + 7),
 	Hotkey('X' | WKC_CTRL, "transparency_toolbar", GHK_TRANSPARENCY_TOOLBAR),
 	Hotkey('X', "toggle_transparency", GHK_TRANSPARANCY),
+	Hotkey(WKC_NONE, "borrow_all", GHK_BORROW_ALL),
 #ifdef ENABLE_NETWORK
 	Hotkey(_ghk_chat_keys, "chat", GHK_CHAT),
 	Hotkey(_ghk_chat_all_keys, "chat_all", GHK_CHAT_ALL),
diff -r e16bdc0054ce src/misc_gui.cpp
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -25,6 +25,7 @@
 #include "querystring_gui.h"
 #include "core/geometry_func.hpp"
 #include "newgrf_debug.h"
+#include "newgrf_cargo.h"
 #include "zoom_func.h"
 
 #include "widgets/misc_widget.h"
@@ -33,6 +34,14 @@
 
 #include "safeguards.h"
 
+#include "house.h"
+#include "town_map.h"
+#include "station_base.h"
+#include "viewport_func.h"
+#include "industry.h"
+
+void GuiShowTooltipsExtra(Window *parent, uint param, TooltipCloseCondition close_tooltip);
+
 /** Method to open the OSK. */
 enum OskActivation {
 	OSKA_DISABLED,           ///< The OSK shall not be activated at all.
@@ -43,16 +52,11 @@
 
 
 static const NWidgetPart _nested_land_info_widgets[] = {
-	NWidget(NWID_HORIZONTAL),
-		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
-		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LAND_AREA_INFORMATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
-		NWidget(WWT_DEBUGBOX, COLOUR_GREY),
-	EndContainer(),
-	NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), SetMinimalSize(64, 32),	EndContainer(),
 };
 
 static WindowDesc _land_info_desc(
-	WDP_AUTO, "land_info", 0, 0,
+	WDP_MANUAL, "land_info", 0, 0,
 	WC_LAND_INFO, WC_NONE,
 	0,
 	_nested_land_info_widgets, lengthof(_nested_land_info_widgets)
@@ -70,11 +74,28 @@
 public:
 	char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE];
 	TileIndex tile;
+	TileIndex end_tile;  ///< For use in ruler(dragdrop) mode
+
+	virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
+	{
+		int scr_top = GetMainViewTop() + 2;
+		int scr_bot = GetMainViewBottom() - 2;
+		Point pt;
+		pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot);
+		if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height;
+		pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width);
+		return pt;
+	}
 
 	virtual void DrawWidget(const Rect &r, int widget) const
 	{
 		if (widget != WID_LI_BACKGROUND) return;
 
+		GfxDrawLine(r.left,  r.top,    r.right, r.top,    PC_BLACK);
+		GfxDrawLine(r.left,  r.bottom, r.right, r.bottom, PC_BLACK);
+		GfxDrawLine(r.left,  r.top,    r.left,  r.bottom, PC_BLACK);
+		GfxDrawLine(r.right, r.top,    r.right, r.bottom, PC_BLACK);
+
 		uint y = r.top + WD_TEXTPANEL_TOP;
 		for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) {
 			if (StrEmpty(this->landinfo_data[i])) break;
@@ -113,9 +134,11 @@
 		}
 	}
 
-	LandInfoWindow(TileIndex tile) : Window(&_land_info_desc), tile(tile)
+	LandInfoWindow(TileIndex tile, TileIndex end_tile=INVALID_TILE) :
+		Window(&_land_info_desc), tile(tile), end_tile(end_tile)
 	{
 		this->InitNested();
+		CLRBITS(this->flags, WF_WHITE_BORDER);
 
 #if defined(_DEBUG)
 #	define LANDINFOD_LEVEL 0
@@ -164,6 +187,7 @@
 		td.airport_tile_name = STR_NULL;
 		td.rail_speed = 0;
 		td.road_speed = 0;
+		td.population = 0;
 
 		td.grf = NULL;
 
@@ -293,6 +317,13 @@
 			line_nr++;
 		}
 
+		/* House pop */
+		if (td.population != 0) {
+			SetDParam(0, td.population);
+			GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_POP, lastof(this->landinfo_data[line_nr]));
+			line_nr++;
+		}
+
 		assert(line_nr < LAND_INFO_CENTERED_LINES);
 
 		/* Mark last line empty */
@@ -349,16 +380,34 @@
 				break;
 		}
 	}
+
+	virtual void OnMouseLoop()
+	{
+		/* Always close tooltips when the cursor is not in our window. */
+		if (!_cursor.in_window) {
+			delete this;
+			return;
+		}
+		if (!_mouse_hovering) delete this;
+
+		/* We can show tooltips while dragging tools. These are shown as long as
+		 * we are dragging the tool. Normal tooltips work with hover or rmb. */
+		// switch (this->close_cond) {
+		// 	case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break;
+		// 	case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break;
+		// 	case TCC_HOVER: if (!_mouse_hovering) delete this; break;
+		// }
+	}
 };
 
 /**
  * Show land information window.
  * @param tile The tile to show information about.
  */
-void ShowLandInfo(TileIndex tile)
+void ShowLandInfo(TileIndex tile, TileIndex end_tile)
 {
 	DeleteWindowById(WC_LAND_INFO, 0);
-	new LandInfoWindow(tile);
+	new LandInfoWindow(tile, end_tile);
 }
 
 static const NWidgetPart _nested_about_widgets[] = {
@@ -1208,3 +1257,495 @@
 
 	new QueryWindow(&_query_desc, caption, message, parent, callback);
 }
+
+/** Window for displaying a tooltip. */
+void GuiPrepareTooltipsExtra(Window *parent){
+	const Point p = GetTileBelowCursor();
+	if (p.x == -1) return;
+	const TileIndex tile = TileVirtXY(p.x, p.y);
+
+	if (_cursor.sprite == SPR_CURSOR_QUERY) {
+		// Land info tool active
+		ShowLandInfo(tile);
+		return;
+	}
+
+	if (!_settings_client.gui.enable_extra_tooltips)
+		return;
+
+	if (tile >= MapSize()) return;
+	uint param = 0;
+	switch (GetTileType(tile)) {
+		/*case MP_HOUSE: {
+			const HouseID house = GetHouseType(tile);
+			param = ((house & 0xFFFF) << 16) | MP_HOUSE;
+			break;
+		}*/
+		case MP_INDUSTRY: {
+			const Industry *ind = Industry::GetByTile(tile);
+			if(ind->produced_cargo[0] == CT_INVALID && ind->produced_cargo[1] == CT_INVALID) return;
+			param = ((ind->index & 0xFFFF) << 16) | MP_INDUSTRY;
+			break;
+		}
+		case MP_STATION: {
+			if (IsRailWaypoint(tile) || HasTileWaterGround(tile)) break;
+			const Station *st = Station::GetByTile(tile);
+			param |= ((st->index & 0xFFFF) << 16) | MP_STATION;
+			break;
+		}
+		default:
+			return;
+	}
+	if(param != 0) GuiShowTooltipsExtra(parent, param, TCC_HOVER);
+}
+
+static const NWidgetPart _nested_tooltips_extra_widgets[] = {
+	NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(64, 32),	EndContainer(),
+};
+
+static WindowDesc _tool_tips_extra_desc(
+	WDP_MANUAL, NULL, 0, 0,
+	WC_TOOLTIPS_EXTRA, WC_NONE,
+	0,
+	_nested_tooltips_extra_widgets, lengthof(_nested_tooltips_extra_widgets)
+);
+
+struct TooltipsExtraWindow : public Window
+{
+	TileType tiletype;
+	uint16 objIndex;
+	TooltipCloseCondition close_cond;
+
+	TooltipsExtraWindow(Window *parent, uint param, TooltipCloseCondition close_tooltip) : Window(&_tool_tips_extra_desc)
+	{
+		this->parent = parent;
+		this->tiletype = (TileType)(param & 0xFFFF);
+		this->objIndex = (uint16)((param >> 16) & 0xFFFF);
+		this->close_cond = close_tooltip;
+		this->InitNested();
+		CLRBITS(this->flags, WF_WHITE_BORDER);
+	}
+
+	virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
+	{
+		int scr_top = GetMainViewTop() + 2;
+		int scr_bot = GetMainViewBottom() - 2;
+		Point pt;
+		pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot);
+		if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height;
+		pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width);
+		return pt;
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		uint icon_size = ScaleGUITrad(10);
+		uint line_height = max((uint)FONT_HEIGHT_NORMAL, icon_size) + 2;
+		uint icons_width = icon_size * 3 + 20;
+		size->width = 200;
+		size->height = FONT_HEIGHT_NORMAL + 6;
+		switch(this->tiletype) {
+			/*case MP_HOUSE: {
+				size->height += LINE_HEIGHT;
+				SetDParam(0, 1000);
+				size->width = GetStringBoundingBox(STR_TTE_HOUSE).width;
+				break;
+			}*/
+			case MP_INDUSTRY: {
+				const Industry *ind = Industry::GetIfValid((IndustryID)this->objIndex);
+				if(ind == NULL) break;
+
+				for (CargoID i = 0; i < lengthof(ind->produced_cargo); i++) {
+					if (ind->produced_cargo[i] == CT_INVALID) continue;
+					const CargoSpec *cs = CargoSpec::Get(ind->produced_cargo[i]);
+					if(cs == NULL) continue;
+					size->height += line_height;
+					SetDParam(0, cs->name);
+					SetDParam(1, cs->Index());
+					SetDParam(2, ind->last_month_production[i]);
+					SetDParam(3, ToPercent8(ind->last_month_pct_transported[i]));
+					size->width = max(GetStringBoundingBox(STR_TTE_INDUSTRY).width + icons_width, size->width);
+				}
+				break;
+			}
+			case MP_STATION: {
+				const Station *st = Station::GetIfValid((StationID)this->objIndex);
+				if(st == NULL) break;
+
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+					if(cs == NULL) continue;
+					int cargoid = cs->Index();
+					if (HasBit(st->goods[cargoid].status, GoodsEntry::GES_RATING)) {
+						size->height += line_height;
+						SetDParam(0, cs->name);
+						SetDParam(1, cargoid);
+						SetDParam(2, st->goods[cargoid].cargo.TotalCount());
+						SetDParam(3, ToPercent8(st->goods[cargoid].rating));
+						size->width = max(GetStringBoundingBox(STR_TTE_STATION).width + icons_width, size->width);
+					}
+				}
+				break;
+			}
+			default:
+				break;
+		}
+		size->width  += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
+		size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		uint icon_size = ScaleGUITrad(10);
+		uint line_height = max((uint)FONT_HEIGHT_NORMAL, icon_size) + 2;
+		uint icons_width = icon_size * 3 + 10;
+		uint text_ofs = (line_height - FONT_HEIGHT_NORMAL) >> 1;
+		uint icon_ofs = (line_height - icon_size) >> 1;
+
+		GfxDrawLine(r.left,  r.top,    r.right, r.top,    PC_BLACK);
+		GfxDrawLine(r.left,  r.bottom, r.right, r.bottom, PC_BLACK);
+		GfxDrawLine(r.left,  r.top,    r.left,  r.bottom, PC_BLACK);
+		GfxDrawLine(r.right, r.top,    r.right, r.bottom, PC_BLACK);
+
+		int y = r.top + WD_FRAMERECT_TOP + 4;
+		int left = r.left + WD_FRAMERECT_LEFT + 4;
+
+		switch(this->tiletype) {
+			/*case MP_HOUSE: {
+				const HouseID house = (HouseID)this->objIndex;
+				const HouseSpec *hs = HouseSpec::Get(house);
+				if(hs == NULL) break;
+
+				SetDParam(0, hs->building_name);
+				DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_HOUSE_NAME, TC_BLACK, SA_CENTER);
+				y += LINE_HEIGHT;
+				SetDParam(0, hs->population);
+				DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_HOUSE);
+				break;
+			}*/
+			case MP_INDUSTRY: {
+				const Industry *ind = Industry::GetIfValid((IndustryID)this->objIndex);
+				if(ind == NULL) break;
+
+				SetDParam(0, ind->index);
+				DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_INDUSTRY_NAME, TC_BLACK, SA_CENTER);
+				y += FONT_HEIGHT_NORMAL + 2;
+
+				for (CargoID i = 0; i < lengthof(ind->produced_cargo); i++) {
+					if (ind->produced_cargo[i] == CT_INVALID) continue;
+					const CargoSpec *cs = CargoSpec::Get(ind->produced_cargo[i]);
+					if(cs == NULL) continue;
+					SetDParam(0, cs->name);
+					SetDParam(1, cs->Index());
+					SetDParam(2, ind->last_month_production[i]);
+					SetDParam(3, ToPercent8(ind->last_month_pct_transported[i]));
+
+					this->DrawSpriteIcons(cs->GetCargoIcon(), left, y + icon_ofs);
+					DrawString(left + icons_width, r.right - WD_FRAMERECT_RIGHT, y + text_ofs, STR_TTE_INDUSTRY);
+					y += line_height;
+				}
+				break;
+			}
+			case MP_STATION: {
+				const Station *st = Station::GetIfValid((StationID)this->objIndex);
+				if(st == NULL) break;
+
+				SetDParam(0, st->index);
+				DrawString(left, r.right - WD_FRAMERECT_RIGHT, y, STR_TTE_STATION_NAME, TC_BLACK, SA_CENTER);
+				y += FONT_HEIGHT_NORMAL + 2;
+
+				for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) {
+					const CargoSpec *cs = _sorted_cargo_specs[i];
+					if(cs == NULL) continue;
+					int cargoid = cs->Index();
+					if (HasBit(st->goods[cargoid].status, GoodsEntry::GES_RATING)) {
+						SetDParam(0, cs->name);
+						SetDParam(1, cargoid);
+						SetDParam(2, st->goods[cargoid].cargo.TotalCount());
+						SetDParam(3, ToPercent8(st->goods[cargoid].rating));
+
+						this->DrawSpriteIcons(cs->GetCargoIcon(), left, y + icon_ofs);
+						DrawString(left + icons_width, r.right - WD_FRAMERECT_RIGHT, y + text_ofs, STR_TTE_STATION);
+						y += line_height;
+					}
+				}
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		if (!_cursor.in_window) {
+			delete this;
+			return;
+		}
+
+		switch (this->close_cond) {
+			case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break;
+			case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break;
+			case TCC_HOVER: if (!_mouse_hovering) delete this; break;
+		}
+	}
+
+	void DrawSpriteIcons(SpriteID sprite, int left, int top) const
+	{
+		uint step = ScaleGUITrad(10);
+		for(int i = 0; i < 3; i++) {
+			DrawSprite(sprite, PAL_NONE, left + i * step, top);
+		}
+	}
+};
+
+static const NWidgetPart _nested_station_rating_tooltip_widgets[] = {
+	NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(64, 32),	EndContainer(),
+};
+
+static WindowDesc _station_rating_tooltip_desc(
+	WDP_MANUAL, NULL, 0, 0,
+	WC_STATION_RATING_TOOLTIP, WC_NONE,
+	0,
+	_nested_tooltips_extra_widgets, lengthof(_nested_station_rating_tooltip_widgets)
+);
+
+static const int STATION_RATING_AGE[] = {0, 10, 20, 33};
+static const int STATION_RATING_WAITTIME[] = {0, 25, 50, 95, 130};
+static const int STATION_RATING_WAITUNITS[] = {-90, -35, 0, 10, 30, 40};
+
+
+struct StationRatingTooltipWindow : public Window
+{
+	TileType tiletype;
+	uint16 objIndex;
+	TooltipCloseCondition close_cond;
+	const Station *st;
+	const CargoSpec *cs;
+	bool newgrf_rating_used;
+
+	static const uint RATING_TOOLTIP_LINE_BUFF_SIZE = 512;
+	static const uint RATING_TOOLTIP_MAX_LINES = 8;
+	static const uint RATING_TOOLTIP_NEWGRF_INDENT = 20;
+
+public:
+	char data[RATING_TOOLTIP_MAX_LINES + 1][RATING_TOOLTIP_LINE_BUFF_SIZE];
+
+	StationRatingTooltipWindow(Window *parent, const Station *st, const CargoSpec *cs) : Window(&_station_rating_tooltip_desc)
+	{
+		this->parent = parent;
+		this->st = st;
+		this->cs = cs;
+		this->InitNested();
+		CLRBITS(this->flags, WF_WHITE_BORDER);
+	}
+
+	virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
+	{
+		int scr_top = GetMainViewTop() + 2;
+		int scr_bot = GetMainViewBottom() - 2;
+		Point pt;
+		pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot);
+		if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height;
+		pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width);
+		return pt;
+	}
+
+	int RoundRating(int rating) {
+		// if (rating >= 0) {
+		// 	return rating * 101 +
+		// }
+		return RoundDivSU(rating * 101, 256);
+	}
+
+	virtual void OnInit() {
+		const GoodsEntry *ge = &this->st->goods[this->cs->Index()];
+
+		SetDParam(0, this->cs->name);
+		GetString(this->data[0], STR_STATION_RATING_TOOLTIP_RATING_DETAILS, lastof(this->data[0]));
+		if (!ge->HasRating()) {
+			this->data[1][0] = '\0';
+			return;
+		}
+
+		uint line_nr = 1;
+		int total_rating = 0;
+
+		if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) {
+			uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF;
+
+			uint32 var18 = min(ge->time_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24);
+			uint32 var10 = (this->st->last_vehicle_type == VEH_INVALID) ? 0x0 : (this->st->last_vehicle_type + 0x10);
+			uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, this->cs);
+			int newgrf_rating = 0;
+			if (callback != CALLBACK_FAILED) {
+				newgrf_rating = GB(callback, 0, 14);
+				if (HasBit(callback, 14)) newgrf_rating -= 0x4000;
+
+				this->newgrf_rating_used = true;
+
+				total_rating += newgrf_rating;
+				newgrf_rating = this->RoundRating(newgrf_rating);
+
+				SetDParam(0, STR_STATION_RATING_TOOLTIP_NEWGRF_RATING_0 + (newgrf_rating <= 0 ? 0 : 1));
+				SetDParam(1, newgrf_rating);
+				GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_RATING, lastof(this->data[line_nr]));
+				line_nr++;
+
+				SetDParam(0, min(last_speed, 0xFF));
+				GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_SPEED, lastof(this->data[line_nr]));
+				line_nr++;
+
+				SetDParam(0, min(ge->max_waiting_cargo, 0xFFFF));
+				GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_WAITUNITS, lastof(this->data[line_nr]));
+				line_nr++;
+
+				SetDParam(0, (min(ge->time_since_pickup, 0xFF) * 5 + 1) / 2);
+				GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_WAITTIME, lastof(this->data[line_nr]));
+				line_nr++;
+			}
+		}
+
+		if (!this->newgrf_rating_used) {
+
+			byte waittime = ge->time_since_pickup;
+			if (this->st->last_vehicle_type == VEH_SHIP) waittime >>= 2;
+			int waittime_stage = 0;
+			(waittime > 21) ||
+			(waittime_stage = 1, waittime > 12) ||
+			(waittime_stage = 2, waittime > 6) ||
+			(waittime_stage = 3, waittime > 3) ||
+			(waittime_stage = 4, true);
+			total_rating += STATION_RATING_WAITTIME[waittime_stage];
+
+			SetDParam(0, STR_STATION_RATING_TOOLTIP_WAITTIME_0 + waittime_stage);
+			SetDParam(1, (ge->time_since_pickup * 5 + 1) / 2);
+			SetDParam(2, this->RoundRating(STATION_RATING_WAITTIME[waittime_stage]));
+			GetString(this->data[line_nr], this->st->last_vehicle_type == VEH_SHIP ? STR_STATION_RATING_TOOLTIP_WAITTIME_SHIP : STR_STATION_RATING_TOOLTIP_WAITTIME, lastof(this->data[line_nr]));
+			line_nr++;
+
+			uint waitunits = ge->max_waiting_cargo;
+			int waitunits_stage = 0;
+			(ge->max_waiting_cargo > 1500) ||
+			(waitunits_stage = 1, ge->max_waiting_cargo > 1000) ||
+			(waitunits_stage = 2, ge->max_waiting_cargo > 600) ||
+			(waitunits_stage = 3, ge->max_waiting_cargo > 300) ||
+			(waitunits_stage = 4, ge->max_waiting_cargo > 100) ||
+			(waitunits_stage = 5, true);
+			total_rating += STATION_RATING_WAITUNITS[waitunits_stage];
+
+			SetDParam(0, STR_STATION_RATING_TOOLTIP_WAITUNITS_0 + waitunits_stage);
+			SetDParam(1, ge->max_waiting_cargo);
+			SetDParam(2, this->RoundRating(STATION_RATING_WAITUNITS[waitunits_stage]));
+			GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_WAITUNITS, lastof(this->data[line_nr]));
+			line_nr++;
+
+			int b = ge->last_speed - 85;
+			int r_speed = b >= 0 ? b >> 2 : 0;
+			int r_speed_round = this->RoundRating(r_speed);
+			total_rating += r_speed;
+			if (ge->last_speed == 255) {
+				SetDParam(0, STR_STATION_RATING_TOOLTIP_SPEED_MAX);
+			} else if (r_speed_round == 0) {
+				SetDParam(0, STR_STATION_RATING_TOOLTIP_SPEED_ZERO);
+			} else {
+				SetDParam(0, STR_STATION_RATING_TOOLTIP_SPEED_0 + r_speed / 11);
+			}
+			SetDParam(0, ge->last_speed == 255 ? STR_STATION_RATING_TOOLTIP_SPEED_MAX : STR_STATION_RATING_TOOLTIP_SPEED_0 + r_speed / 11);
+			SetDParam(1, ge->last_speed);
+			SetDParam(2, r_speed_round);
+			GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_SPEED, lastof(this->data[line_nr]));
+			line_nr++;
+		}
+
+		int age_stage = (ge->last_age >= 3 ? 0 : 3 - ge->last_age);
+		total_rating += STATION_RATING_AGE[age_stage];
+		SetDParam(0, STR_STATION_RATING_TOOLTIP_AGE_0 + age_stage);
+		SetDParam(1, ge->last_age);
+		SetDParam(2, this->RoundRating(STATION_RATING_AGE[age_stage]));
+		GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_AGE, lastof(this->data[line_nr]));
+		line_nr++;
+
+		if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) {
+			SetDParam(0, STR_STATION_RATING_TOOLTIP_STATUE_YES);
+			total_rating += 26;
+		} else {
+			SetDParam(0, STR_STATION_RATING_TOOLTIP_STATUE_NO);
+		}
+		GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_STATUE, lastof(this->data[line_nr]));
+		line_nr++;
+
+		SetDParam(0, ToPercent8(Clamp(total_rating, 0, 255)));
+		GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_TOTAL_RATING, lastof(this->data[line_nr]));
+		line_nr++;
+
+		this->data[line_nr][0] = '\0';
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		if (widget != WID_LI_BACKGROUND) return;
+
+		size->height = WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + 2;
+		for (uint i = 0; i <= RATING_TOOLTIP_MAX_LINES; i++) {
+			if (StrEmpty(this->data[i])) break;
+
+			uint width = GetStringBoundingBox(this->data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + 2;
+			if (this->newgrf_rating_used && i >= 2 && i <= 4)
+				width += RATING_TOOLTIP_NEWGRF_INDENT;
+			size->width = max(size->width, width);
+			size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
+		}
+		size->height -= WD_PAR_VSEP_NORMAL;
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		uint icon_size = ScaleGUITrad(10);
+		uint line_height = max((uint)FONT_HEIGHT_NORMAL, icon_size) + 2;
+		uint text_ofs = (line_height - FONT_HEIGHT_NORMAL) >> 1;
+		uint icon_ofs = (line_height - icon_size) >> 1;
+
+		GfxDrawLine(r.left,  r.top,    r.right, r.top,    PC_BLACK);
+		GfxDrawLine(r.left,  r.bottom, r.right, r.bottom, PC_BLACK);
+		GfxDrawLine(r.left,  r.top,    r.left,  r.bottom, PC_BLACK);
+		GfxDrawLine(r.right, r.top,    r.right, r.bottom, PC_BLACK);
+
+		int y = r.top + WD_FRAMETEXT_TOP + 1;
+		int left0 = r.left + WD_FRAMETEXT_LEFT + 1;
+		int right0 = r.right - WD_FRAMETEXT_RIGHT - 1;
+		DrawString(left0, right0, y, this->data[0], TC_LIGHT_BLUE, SA_CENTER);
+		y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
+		for (uint i = 1; i <= RATING_TOOLTIP_MAX_LINES; i++) {
+			if (StrEmpty(this->data[i])) break;
+			int left = left0, right = right0;
+			if (this->newgrf_rating_used && i >= 2 && i <= 4) {
+				if (_current_text_dir == TD_RTL) {
+					right -= RATING_TOOLTIP_NEWGRF_INDENT;
+				} else {
+					left += RATING_TOOLTIP_NEWGRF_INDENT;
+				}
+			}
+			DrawString(left, right, y, this->data[i], TC_BLACK);
+			y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		if (!_cursor.in_window || !_mouse_hovering) {
+			delete this;
+		}
+	}
+};
+
+void GuiShowTooltipsExtra(Window *parent, uint param, TooltipCloseCondition close_tooltip)
+{
+	DeleteWindowById(WC_TOOLTIPS_EXTRA, 0);
+	new TooltipsExtraWindow(parent, param, close_tooltip);
+}
+
+void GuiShowStationRatingTooltip(Window *parent, const Station *st, const CargoSpec *cs) {
+	DeleteWindowById(WC_STATION_RATING_TOOLTIP, 0);
+	new StationRatingTooltipWindow(parent, st, cs);
+}
diff -r e16bdc0054ce src/network/network.cpp
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -82,7 +82,7 @@
 uint16 _network_udp_broadcast;        ///< Timeout for the UDP broadcasts.
 uint8 _network_advertise_retries;     ///< The number of advertisement retries we did.
 CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies.
-
+bool _novarole = false;
 /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */
 assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
 assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH);
@@ -116,6 +116,7 @@
 {
 	/* Delete the chat window, if you were chatting with this client. */
 	InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id);
+	InvalidateWindowData(WC_WATCH_COMPANYA, this->client_id, 2);
 }
 
 /**
diff -r e16bdc0054ce src/network/network_client.cpp
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -34,10 +34,14 @@
 
 #include "table/strings.h"
 
+#include "../town.h"
+#include "network_func.h"
+
 #include "../safeguards.h"
 
 /* This file handles all the client-commands */
 
+void SyncCMUser(const char *msg);
 
 /** Read some packets, and when do use that data as initial load filter. */
 struct PacketReader : LoadFilter {
@@ -265,6 +269,10 @@
 			if (_network_first_time) {
 				_network_first_time = false;
 				SendAck();
+				extern bool novahost();
+				if(novahost()) {
+					NetworkClientSendChatToServer("!check 1512"); //check version
+				}
 			}
 
 			_sync_frame = 0;
@@ -614,6 +622,10 @@
 		strecpy(ci->client_name, name, lastof(ci->client_name));
 
 		SetWindowDirty(WC_CLIENT_LIST, 0);
+		InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
+		SetWindowClassesDirty(WC_WATCH_COMPANY);
+		InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1);
+		SetWindowClassesDirty(WC_WATCH_COMPANYA);
 
 		return NETWORK_RECV_STATUS_OKAY;
 	}
@@ -633,6 +645,10 @@
 	strecpy(ci->client_name, name, lastof(ci->client_name));
 
 	SetWindowDirty(WC_CLIENT_LIST, 0);
+	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
+	SetWindowClassesDirty(WC_WATCH_COMPANY);
+	InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1);
+	SetWindowClassesDirty(WC_WATCH_COMPANYA);
 
 	return NETWORK_RECV_STATUS_OKAY;
 }
@@ -984,7 +1000,8 @@
 	}
 
 	if (ci != NULL) {
-		NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data);
+		if (strncmp(msg, "synccmuser", 10) == 0) SyncCMUser(msg);
+		else NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data);
 	}
 	return NETWORK_RECV_STATUS_OKAY;
 }
@@ -1021,6 +1038,8 @@
 	}
 
 	SetWindowDirty(WC_CLIENT_LIST, 0);
+	InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
+	SetWindowClassesDirty( WC_WATCH_COMPANYA );
 
 	/* If we come here it means we could not locate the client.. strange :s */
 	return NETWORK_RECV_STATUS_OKAY;
@@ -1107,6 +1126,8 @@
 	if (client_id == _network_own_client_id) {
 		SetLocalCompany(company_id);
 	}
+	InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
+	SetWindowClassesDirty( WC_WATCH_COMPANYA );
 
 	return NETWORK_RECV_STATUS_OKAY;
 }
@@ -1253,6 +1274,10 @@
 	MyClient::SendChat(action, type, dest, msg, data);
 }
 
+void NetworkClientSendChatToServer(const char * msg)
+{
+	NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, CLIENT_ID_SERVER, msg);
+}
 /**
  * Set/Reset company password on the client side.
  * @param password Password to be set.
@@ -1298,4 +1323,10 @@
 	return NetworkSpectatorCount() >= (_network_server ? _settings_client.network.max_spectators : _network_server_max_spectators);
 }
 
+void SyncCMUser(const char *msg) {
+	uint user_id, role;
+	sscanf(msg + 10, "%u %u", &user_id, &role);
+	_novarole = (role >= 50);
+	DEBUG(net, 1, "CityMania user synchronized: %u %u", user_id, role);
+}
 #endif /* ENABLE_NETWORK */
diff -r e16bdc0054ce src/network/network_func.h
--- a/src/network/network_func.h
+++ b/src/network/network_func.h
@@ -38,7 +38,7 @@
 extern StringList _network_bind_list;
 extern StringList _network_host_list;
 extern StringList _network_ban_list;
-
+extern bool _novarole;
 byte NetworkSpectatorCount();
 void NetworkUpdateClientName();
 bool NetworkCompanyHasClients(CompanyID company);
@@ -57,6 +57,7 @@
 void NetworkClientRequestMove(CompanyID company, const char *pass = "");
 void NetworkClientSendRcon(const char *password, const char *command);
 void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0);
+void NetworkClientSendChatToServer(const char * msg);
 bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
 bool NetworkCompanyIsPassworded(CompanyID company_id);
 bool NetworkMaxCompaniesReached();
diff -r e16bdc0054ce src/network/network_gui.cpp
--- a/src/network/network_gui.cpp
+++ b/src/network/network_gui.cpp
@@ -31,6 +31,7 @@
 #include "../core/geometry_func.hpp"
 #include "../genworld.h"
 #include "../map_type.h"
+#include "../zoom_func.h"
 
 #include "../widgets/network_widget.h"
 
@@ -38,6 +39,7 @@
 #include "../table/sprites.h"
 
 #include "../stringfilter_type.h"
+#include "../watch_gui.h"
 
 #include "../safeguards.h"
 
@@ -234,6 +236,7 @@
 	Scrollbar *vscroll;           ///< vertical scrollbar of the list of servers
 	QueryString name_editbox;     ///< Client name editbox.
 	QueryString filter_editbox;   ///< Editbox for filter on servers
+	bool UDP_CC_queried;
 
 	int lock_offset; ///< Left offset for lock icon.
 	int blot_offset; ///< Left offset for green/yellow/red compatibility icon.
@@ -388,6 +391,7 @@
 		/* offsets to vertically centre text and icons */
 		int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2 + 1;
 		int icon_y_offset = (this->resize.step_height - GetSpriteSize(SPR_BLOT).height) / 2;
+		int lock_y_offset = (this->resize.step_height - GetSpriteSize(SPR_LOCK).height) / 2;
 
 		DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + text_y_offset, cur_item->info.server_name, TC_BLACK);
 
@@ -432,13 +436,13 @@
 			}
 
 			/* draw a lock if the server is password protected */
-			if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + this->lock_offset, y + icon_y_offset - 1);
+			if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + this->lock_offset, y + lock_y_offset);
 
 			/* 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)), nwi_info->pos_x + this->blot_offset, y + icon_y_offset);
+			DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), nwi_info->pos_x + this->blot_offset, y + icon_y_offset + 1);
 
 			/* draw flag according to server language */
-			DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + icon_y_offset);
+			DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + (this->resize.step_height - GetSpriteSize(SPR_FLAGS_BASE + cur_item->info.server_lang).height) / 2);
 		}
 	}
 
@@ -474,6 +478,7 @@
 
 		this->querystrings[WID_NG_FILTER] = &this->filter_editbox;
 		this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
+		this->UDP_CC_queried = false;
 		this->SetFocusedWidget(WID_NG_FILTER);
 
 		this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
@@ -782,6 +787,23 @@
 			case WID_NG_NEWGRF_MISSING: // Find missing content online
 				if (this->server != NULL) ShowMissingContentWindow(this->server->info.grfconfig);
 				break;
+			case WID_NG_NICE:
+			case WID_NG_BTPRO:
+			case WID_NG_REDDIT:
+			case WID_NG_CITYMANIA:
+				if(!UDP_CC_queried){
+					NetworkUDPQueryMasterServer();
+					UDP_CC_queried = true;
+				}
+				if(widget == WID_NG_NICE) this->filter_editbox.text.Assign("n-ice");
+				else if(widget == WID_NG_BTPRO) this->filter_editbox.text.Assign("BTPro");
+				else if(widget == WID_NG_CITYMANIA) this->filter_editbox.text.Assign("citymania");
+				else if(widget == WID_NG_REDDIT) this->filter_editbox.text.Assign("reddit");
+				this->servers.ForceRebuild();
+				this->BuildGUINetworkGameList();
+				this->ScrollToSelectedServer();
+				this->SetDirty();
+				break;
 		}
 	}
 
@@ -909,7 +931,7 @@
 	}
 };
 
-Listing NetworkGameWindow::last_sorting = {false, 5};
+Listing NetworkGameWindow::last_sorting = {false, 0};
 GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
 	&NGameNameSorter,
 	&NGameClientSorter,
@@ -946,6 +968,10 @@
 						NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN),
 											SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
 						NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CITYMANIA), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_CITYMANIA, STR_NETWORK_SELECT_SERVER_TOOLTIP),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_BTPRO), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_BTPRO, STR_NETWORK_SELECT_SERVER_TOOLTIP),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NICE), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_NICE, STR_NETWORK_SELECT_SERVER_TOOLTIP),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REDDIT), SetFill(1, 0), SetDataTip(STR_NETWORK_SELECT_REDDIT, STR_NETWORK_SELECT_SERVER_TOOLTIP),
 					EndContainer(),
 					NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
 						NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
@@ -1386,8 +1412,9 @@
 				break;
 
 			case WID_NL_MATRIX:
-				resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
+				resize->height = WD_MATRIX_TOP + max(max(GetSpriteSize(SPR_LOCK).height, GetSpriteSize(SPR_PROFIT_LOT).height), (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
 				size->height = 10 * resize->height;
+				size->width = ScaleGUITrad(146);
 				break;
 
 			case WID_NL_DETAILS:
@@ -1440,31 +1467,32 @@
 		bool rtl = _current_text_dir == TD_RTL;
 		uint left = r.left + WD_FRAMERECT_LEFT;
 		uint right = r.right - WD_FRAMERECT_RIGHT;
+		uint text_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - FONT_HEIGHT_NORMAL) / 2 + WD_MATRIX_TOP;
 
 		Dimension lock_size = GetSpriteSize(SPR_LOCK);
 		int lock_width      = lock_size.width;
-		int lock_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2;
+		int lock_y_offset   = (this->resize.step_height - lock_size.height) / 2;
 
 		Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
 		int profit_width      = lock_size.width;
-		int profit_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2;
+		int profit_y_offset   = (this->resize.step_height - profit_size.height) / 2;
 
 		uint text_left   = left  + (rtl ? lock_width + profit_width + 4 : 0);
 		uint text_right  = right - (rtl ? 0 : lock_width + profit_width + 4);
 		uint profit_left = rtl ? left : right - profit_width;
 		uint lock_left   = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
 
-		int y = r.top + WD_MATRIX_TOP;
+		int y = r.top;
 		/* Draw company list */
 		int pos = this->vscroll->GetPosition();
 		while (pos < this->server->info.companies_on) {
 			byte company = NetworkLobbyFindCompanyIndex(pos);
 			bool income = false;
 			if (this->company == company) {
-				GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, PC_GREY); // show highlighted item with a different colour
+				GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY); // show highlighted item with a different colour
 			}
 
-			DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK);
+			DrawString(text_left, text_right, y + text_offset, this->company_info[company].company_name, TC_BLACK);
 			if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
 
 			/* If the company's income was positive puts a green dot else a red dot */
@@ -1691,6 +1719,14 @@
 	NetworkServerKickOrBanIP(ci->client_id, true);
 }
 
+static void ClientList_Watch(const NetworkClientInfo *ci)
+{
+	if (ci != NULL){
+		CompanyID cid = (CompanyID)ci->client_id;
+		ShowWatchWindow(cid, 1);
+	}
+}
+
 static void ClientList_GiveMoney(const NetworkClientInfo *ci)
 {
 	ShowNetworkGiveMoneyWindow(ci->client_playas);
@@ -1767,6 +1803,9 @@
 			this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban);
 		}
 
+		if (_network_own_client_id != ci->client_id && ci->client_id != CLIENT_ID_SERVER && _novarole) {
+			this->AddAction(STR_XI_WATCH, &ClientList_Watch);
+		}
 		this->InitNested(client_id);
 		CLRBITS(this->flags, WF_WHITE_BORDER);
 	}
@@ -1911,8 +1950,10 @@
 		FOR_ALL_CLIENT_INFOS(ci) {
 			width = max(width, GetStringBoundingBox(ci->client_name).width);
 		}
-
-		size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
+		SetDParam(0, 0xFFFF);
+		SetDParam(1, INVALID_COMPANY);
+		uint width2 = GetStringBoundingBox(STR_NETWORK_CLIENT_EXTRA).width;
+		size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT + width2;
 	}
 
 	virtual void OnPaint()
@@ -1965,6 +2006,11 @@
 
 			DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
 
+			uint extra = GetStringBoundingBox(ci->client_name).width + 15;
+			SetDParam(0, ci->client_id);
+			SetDParam(1, ci->client_playas == INVALID_COMPANY ? ci->client_playas : ci->client_playas + 1);
+			DrawString(rtl ? left : name_left + extra, rtl ? name_right - extra : right, y + text_offset, STR_NETWORK_CLIENT_EXTRA, TC_FROMSTRING, SA_RIGHT);
+
 			y += line_height;
 		}
 	}
diff -r e16bdc0054ce src/order_cmd.cpp
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -1794,6 +1794,7 @@
 				} else if (v->type == VEH_AIRCRAFT &&
 							(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
 							(st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
+							_settings_client.gui.runway_too_short_warn &&
 							_settings_game.vehicle.plane_crashes != 0 &&
 							!_cheats.no_jetcrash.value &&
 							message == INVALID_STRING_ID) {
diff -r e16bdc0054ce src/order_gui.cpp
--- a/src/order_gui.cpp
+++ b/src/order_gui.cpp
@@ -171,6 +171,78 @@
 	INVALID_STRING_ID,
 };
 
+struct OrdersFromSettings
+{
+	enum OrderUnloadFlags unload;
+	enum OrderLoadFlags   load;
+};
+
+typedef enum {
+	GOFS_NONE = 0,
+	GOFS_FULL,
+	GOFS_XFER,
+	GOFS_UNLOAD,
+	GOFS_FEEDLOAD,
+	GOFS_FEEDUNLOAD,
+	GOFS_NOLOAD
+} GetOrderFromSettingsTypes;
+
+static enum {
+	GOFS_FEEDER_NULL,
+	GOFS_FEEDER_LOAD,
+	GOFS_FEEDER_UNLOAD
+} gofsfeeder_ordermod = GOFS_FEEDER_NULL;
+
+#define GOFSFEEDER_ORDERMOD_RESET gofsfeeder_ordermod = GOFS_FEEDER_NULL
+
+
+/* fetch and compute orders set from settings */
+
+static void GetOrdersFromSettings(const Vehicle *v, uint8 setting, struct OrdersFromSettings *rv)
+{
+	rv->load = (enum OrderLoadFlags)-1;
+	rv->unload = (enum OrderUnloadFlags)-1;
+
+	switch(setting) {
+
+	case GOFS_FEEDLOAD:
+		if (v->GetNumOrders()) gofsfeeder_ordermod = GOFS_FEEDER_LOAD;
+		rv->unload = OUFB_NO_UNLOAD;
+		rv->load = OLF_FULL_LOAD_ANY;
+		break;
+	case GOFS_FULL:
+		rv->load = OLF_FULL_LOAD_ANY;
+		break;
+
+	case GOFS_UNLOAD:
+		rv->unload = OUFB_UNLOAD;
+		if (_settings_client.gui.auto_noload_on_unloadall)
+			rv->load = OLFB_NO_LOAD;
+		break;
+
+	case GOFS_FEEDUNLOAD:
+		if (v->GetNumOrders()) gofsfeeder_ordermod = GOFS_FEEDER_UNLOAD;
+		rv->unload = OUFB_TRANSFER;
+		rv->load = OLFB_NO_LOAD;
+		break;
+
+	case GOFS_XFER:
+		rv->unload = OUFB_TRANSFER;
+		if (_settings_client.gui.auto_noload_on_transfer)
+			rv->load = OLFB_NO_LOAD;
+		break;
+
+	case GOFS_NOLOAD:
+		rv->load = OLFB_NO_LOAD;
+		break;
+
+	case GOFS_NONE:
+		break;
+
+	default: NOT_REACHED();
+	}
+}
+
 extern uint ConvertSpeedToDisplaySpeed(uint speed);
 extern uint ConvertDisplaySpeedToSpeed(uint speed);
 
@@ -346,6 +418,19 @@
 	}
 
 	DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, colour);
+
+	uint order_dist_sq = 0;
+	uint order_dist_mh = 0;
+	const Order *next2 = order->next != NULL ? order->next : v->GetFirstOrder();
+	TileIndex prev_tile = order->GetLocation(v, true);
+	TileIndex cur_tile = next2->GetLocation(v, true);
+	if (prev_tile != INVALID_TILE && cur_tile != INVALID_TILE){
+		order_dist_sq = IntSqrt(DistanceSquare(prev_tile, cur_tile));
+		order_dist_mh = DistanceManhattan(prev_tile, cur_tile);
+	}
+	SetDParam(0, order_dist_sq);
+	SetDParam(1, order_dist_mh);
+	DrawString(middle, right, y, STR_ORDER_DIST, TC_WHITE, SA_RIGHT);
 }
 
 /**
@@ -400,8 +485,34 @@
 			(facil = FACIL_BUS_STOP, v->type == VEH_ROAD && RoadVehicle::From(v)->IsBus()) ||
 			(facil = FACIL_TRUCK_STOP, 1);
 			if (st->facilities & facil) {
+			uint8 os = 0xff;
 				order.MakeGoToStation(st_index);
-				if (_ctrl_pressed) order.SetLoadType(OLF_FULL_LOAD_ANY);
+				if (_ctrl_pressed) {
+					if (_shift_pressed)
+						os = _settings_client.gui.goto_shortcuts_ctrlshift_lclick;
+					else if (_alt_pressed)
+						os = _settings_client.gui.goto_shortcuts_altctrl_lclick;
+					else
+						os = _settings_client.gui.goto_shortcuts_ctrl_lclick;
+				}
+				else if (_shift_pressed) {
+					if (_alt_pressed)
+						os = _settings_client.gui.goto_shortcuts_altshift_lclick;
+					else
+						os = _settings_client.gui.goto_shortcuts_shift_lclick;
+				}
+				else if (_alt_pressed)
+					os = _settings_client.gui.goto_shortcuts_alt_lclick;
+
+				if (os != 0xff) {
+					struct OrdersFromSettings ofs;
+					GetOrdersFromSettings(v, os, &ofs);
+					if (ofs.load != (enum OrderLoadFlags)-1)
+						order.SetLoadType(ofs.load);
+					if (ofs.unload != (enum OrderUnloadFlags)-1)
+					order.SetUnloadType(ofs.unload);
+				}
+
 				if (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) order.SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 				order.SetStopLocation(v->type == VEH_TRAIN ? (OrderStopLocation)(_settings_client.gui.stop_location) : OSL_PLATFORM_FAR_END);
 				return order;
@@ -427,6 +538,7 @@
 	OHK_TRANSFER,
 	OHK_NO_UNLOAD,
 	OHK_NO_LOAD,
+	OHK_CLOSE,
 };
 
 /**
@@ -635,8 +747,15 @@
 
 		DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_UNLOAD | (unload_type << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER));
 
+		bool set_no_load = false;
+		if (unload_type == OUFB_TRANSFER){
+			set_no_load = _settings_client.gui.auto_noload_on_transfer;
+		}
+		else if (unload_type == OUFB_UNLOAD){
+			set_no_load = _settings_client.gui.auto_noload_on_unloadall;
+		}
 		/* Transfer orders with leave empty as default */
-		if (unload_type == OUFB_TRANSFER) {
+		if (set_no_load) {
 			DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (OLFB_NO_LOAD << 4), CMD_MODIFY_ORDER);
 			this->SetWidgetDirty(WID_O_FULL_LOAD);
 		}
@@ -1423,6 +1542,11 @@
 	virtual EventState OnHotkey(int hotkey)
 	{
 		if (this->vehicle->owner != _local_company) return ES_NOT_HANDLED;
+		if(hotkey == OHK_GOTO && this->goto_type != OPOS_NONE){
+			this->RaiseWidget(WID_O_GOTO);
+			ResetObjectToPlace();
+			return ES_NOT_HANDLED;
+		}
 
 		switch (hotkey) {
 			case OHK_SKIP:           this->OrderClick_Skip();          break;
@@ -1436,6 +1560,7 @@
 			case OHK_TRANSFER:       this->OrderHotkey_Transfer();     break;
 			case OHK_NO_UNLOAD:      this->OrderHotkey_NoUnload();     break;
 			case OHK_NO_LOAD:        this->OrderHotkey_NoLoad();       break;
+			case OHK_CLOSE:          delete this; break;
 			default: return ES_NOT_HANDLED;
 		}
 		return ES_HANDLED;
@@ -1447,7 +1572,21 @@
 			const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
 			if (cmd.IsType(OT_NOTHING)) return;
 
-			if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
+			if (gofsfeeder_ordermod != GOFS_FEEDER_NULL) {
+				if (gofsfeeder_ordermod == GOFS_FEEDER_LOAD) {
+					if (DoCommandP(this->vehicle->tile, this->vehicle->index + ((1) << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
+						DoCommandP(this->vehicle->tile, this->vehicle->index,  0, CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER));
+					}
+
+				}
+				else if (gofsfeeder_ordermod == GOFS_FEEDER_UNLOAD) { // still flushes the whole order table
+					if (DoCommandP(this->vehicle->tile, this->vehicle->index + ((this->vehicle->GetNumOrders()) << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
+						DoCommandP(this->vehicle->tile, this->vehicle->index, (this->vehicle->GetNumOrders()-2+(int)_networking) , CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER));
+					}
+				}
+				gofsfeeder_ordermod = GOFS_FEEDER_NULL;
+			}
+			else if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
 				/* With quick goto the Go To button stays active */
 				if (!_settings_client.gui.quick_goto) ResetObjectToPlace();
 			}
@@ -1525,6 +1664,7 @@
 	Hotkey((uint16)0, "transfer", OHK_TRANSFER),
 	Hotkey((uint16)0, "no_unload", OHK_NO_UNLOAD),
 	Hotkey((uint16)0, "no_load", OHK_NO_LOAD),
+	Hotkey('Q', "close", OHK_CLOSE),
 	HOTKEY_LIST_END
 };
 HotkeyList OrdersWindow::hotkeys("order", order_hotkeys);
diff -r e16bdc0054ce src/os/windows/ottdres.rc
--- /dev/null
+++ b/src/os/windows/ottdres.rc
@@ -0,0 +1,121 @@
+//Microsoft Developer Studio generated resource script.
+// $Id: ottdres.rc.in 27103 2015-01-01 20:51:18Z rubidium $
+//
+// This file is part of OpenTTD.
+// OpenTTD 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, version 2.
+// OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_READONLY_SYMBOLS
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#ifdef MSVC
+#include "winres.h"
+#else
+#define IDC_STATIC              (-1)     // all static controls
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral (Default) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+100                     ICON    DISCARDABLE     "../../../media/openttd.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+100 DIALOG DISCARDABLE  0, 0, 305, 99
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Fatal Application Failure"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "&Close",12,7,80,50,14
+    PUSHBUTTON      "&Emergency save",13,155,80,68,14
+    PUSHBUTTON      "",15,243,80,55,14
+    EDITTEXT        11,7,101,291,118,ES_MULTILINE | ES_READONLY | WS_VSCROLL |
+                    WS_HSCROLL | NOT WS_TABSTOP
+    LTEXT           "",10,36,7,262,65
+    ICON            100,IDC_STATIC,9,9,20,20
+END
+
+
+101 DIALOG DISCARDABLE  0, 0, 600, 400
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "OpenTTD command line help"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "&OK",12,274,378,50,14,BS_CENTER
+    EDITTEXT        11,7,6,583,365,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,5,0,0
+ PRODUCTVERSION 1,5,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "Comments", "This program is licensed under the GNU General Public License version 2.\0"
+            VALUE "CompanyName", "OpenTTD Development Team\0"
+            VALUE "FileDescription", "OpenTTD\0"
+            VALUE "FileVersion", "norev000\0"
+            VALUE "InternalName", "openttd\0"
+            VALUE "LegalCopyright", "Copyright \xA9 OpenTTD Developers 2002-2015. All Rights Reserved.\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "openttd.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "OpenTTD\0"
+            VALUE "ProductVersion", "norev000\0"
+            VALUE "SpecialBuild", "-\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END
+
+#endif    // !_MAC
+
+#endif    // Neutral (Default) resources
+/////////////////////////////////////////////////////////////////////////////
diff -r e16bdc0054ce src/rail_cmd.cpp
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -46,6 +46,7 @@
 RailtypeInfo _railtypes[RAILTYPE_END];
 RailType _sorted_railtypes[RAILTYPE_END];
 uint8 _sorted_railtypes_size;
+TileIndex _rail_track_endtile; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes.
 
 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
 
@@ -437,6 +438,8 @@
 	Track track = Extract<Track, 0, 3>(p2);
 	CommandCost cost(EXPENSES_CONSTRUCTION);
 
+	_rail_track_endtile = INVALID_TILE;
+
 	if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
 	Slope tileh = GetTileSlope(tile);
@@ -453,7 +456,10 @@
 
 			ret = CheckTrackCombination(tile, trackbit, flags);
 			if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
-			if (ret.Failed()) return ret;
+			if (ret.Failed()) {
+				if (ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) _rail_track_endtile = tile;
+				return ret;
+			}
 
 			ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
 			if (ret.Failed()) return ret;
@@ -544,6 +550,7 @@
 			}
 
 			if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
+				_rail_track_endtile = tile;
 				return_cmd_error(STR_ERROR_ALREADY_BUILT);
 			}
 			/* FALL THROUGH */
@@ -583,6 +590,7 @@
 	}
 
 	cost.AddCost(RailBuildCost(railtype));
+	_rail_track_endtile = tile;
 	return cost;
 }
 
@@ -601,6 +609,8 @@
 	CommandCost cost(EXPENSES_CONSTRUCTION);
 	bool crossing = false;
 
+	_rail_track_endtile = INVALID_TILE;
+
 	if (!ValParamTrackOrientation(track)) return CMD_ERROR;
 	TrackBits trackbit = TrackToTrackBits(track);
 
@@ -727,6 +737,7 @@
 		if (v != NULL) TryPathReserve(v, true);
 	}
 
+	_rail_track_endtile = tile;
 	return cost;
 }
 
@@ -860,6 +871,8 @@
 	bool remove = HasBit(p2, 7);
 	RailType railtype = Extract<RailType, 0, 4>(p2);
 
+	_rail_track_endtile = INVALID_TILE;
+
 	if ((!remove && !ValParamRailtype(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 	if (p1 >= MapSize()) return CMD_ERROR;
 	TileIndex end_tile = p1;
@@ -871,10 +884,12 @@
 	bool had_success = false;
 	CommandCost last_error = CMD_ERROR;
 	for (;;) {
+		TileIndex last_endtile = _rail_track_endtile;
 		CommandCost ret = DoCommand(tile, remove ? 0 : railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
 
 		if (ret.Failed()) {
 			last_error = ret;
+			if (_rail_track_endtile == INVALID_TILE) _rail_track_endtile = last_endtile;
 			if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
 				if (HasBit(p2, 8)) return last_error;
 				break;
diff -r e16bdc0054ce src/rail_gui.cpp
--- a/src/rail_gui.cpp
+++ b/src/rail_gui.cpp
@@ -52,9 +52,16 @@
 static SignalVariant _cur_signal_variant;    ///< set the signal variant (for signal GUI)
 static SignalType _cur_signal_type;          ///< set the signal type (for signal GUI)
 
+extern TileIndex _rail_track_endtile; // rail_cmd.cpp
+
 /* Map the setting: default_signal_type to the corresponding signal type */
 static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
 
+static const int HOTKEY_POLYRAIL     = 0x1000;
+static const int HOTKEY_NEW_POLYRAIL = 0x1001;
+static const int HOTKEY_BUILD_STATION_SIZED = 0x1010;     ///< Build a station in fixed size mode.
+static const int HOTKEY_BUILD_STATION_DRAGDROP = 0x1011;  ///< Build a station in dragdrop mode.
+
 struct RailStationGUISettings {
 	Axis orientation;                 ///< Currently selected rail station orientation
 
@@ -91,13 +98,20 @@
 	if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile);
 }
 
-static void GenericPlaceRail(TileIndex tile, int cmd)
+static CommandContainer GenericPlaceRailCmd(TileIndex tile, Track track)
 {
-	DoCommandP(tile, _cur_railtype, cmd,
-			_remove_button_clicked ?
-			CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
-			CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
-			CcPlaySound1E);
+	CommandContainer ret = {
+		tile,          // tile
+		_cur_railtype, // p1
+		track,         // p2
+		_remove_button_clicked ?
+				CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
+				CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), // cmd
+		CcPlaySound1E, // callback
+		""             // text
+	};
+
+	return ret;
 }
 
 /**
@@ -276,6 +290,7 @@
 	if (result.Succeeded()) {
 		if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile);
 		if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
+		StoreRailPlacementEndpoints(tile, _build_tunnel_endtile, TileX(tile) == TileX(_build_tunnel_endtile) ? TRACK_Y : TRACK_X, false);
 	} else {
 		SetRedErrorSquare(_build_tunnel_endtile);
 	}
@@ -305,7 +320,7 @@
 
 	/* allow ctrl to switch remove mode only for these widgets */
 	for (uint i = WID_RAT_BUILD_NS; i <= WID_RAT_BUILD_STATION; i++) {
-		if ((i <= WID_RAT_AUTORAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
+		if ((i <= WID_RAT_POLYRAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
 			ToggleRailButton_Remove(w);
 			return true;
 		}
@@ -349,25 +364,45 @@
 	}
 }
 
-static void DoRailroadTrack(int mode)
+static CommandContainer DoRailroadTrackCmd(TileIndex start_tile, TileIndex end_tile, Track track)
 {
-	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4),
-			_remove_button_clicked ?
-			CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
-			CMD_BUILD_RAILROAD_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
-			CcPlaySound1E);
+	CommandContainer ret = {
+		start_tile,                   // tile
+		end_tile,                     // p1
+		_cur_railtype | (track << 4), // p2
+		_remove_button_clicked ?
+				CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
+				CMD_BUILD_RAILROAD_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), // cmd
+		CcPlaySound1E,                // callback
+		""                            // text
+	};
+
+	return ret;
 }
 
 static void HandleAutodirPlacement()
 {
-	int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5
+	Track track = (Track)(_thd.drawstyle & HT_DIR_MASK); // 0..5
+	TileIndex start_tile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
+	TileIndex end_tile = TileVirtXY(_thd.selend.x, _thd.selend.y);
 
-	if (_thd.drawstyle & HT_RAIL) { // one tile case
-		GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat);
-		return;
+	CommandContainer cmd = (_thd.drawstyle & HT_RAIL) ?
+			GenericPlaceRailCmd(end_tile, track) : // one tile case
+			DoRailroadTrackCmd(start_tile, end_tile, track); // multitile selection
+
+	/* When overbuilding existing tracks in polyline mode we just want to move the
+	 * snap point without altering the user with the "already built" error. Don't
+	 * execute the command right away, firstly check if tracks are being overbuilt. */
+	if (!(_thd.place_mode & HT_POLY) || _shift_pressed ||
+			DoCommand(&cmd, DC_AUTO | DC_NO_WATER).GetErrorMessage() != STR_ERROR_ALREADY_BUILT) {
+		/* place tracks */
+		if (!DoCommandP(&cmd)) return;
 	}
 
-	DoRailroadTrack(trackstat);
+	/* save new snap points for the polyline tool */
+	if (!_shift_pressed && _rail_track_endtile != INVALID_TILE) {
+		StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true);
+	}
 }
 
 /**
@@ -414,6 +449,73 @@
 }
 
 
+// FIXME duplicate from road_gui.cpp
+static DiagDirection TileFractCoordsToDiagDir() {
+	bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16;
+	if (_tile_fract_coords.x < _tile_fract_coords.y) {
+		return diag ? DIAGDIR_NE : DIAGDIR_SE;
+	}
+	return diag ? DIAGDIR_NW : DIAGDIR_SW;
+}
+
+// FIXME duplicate from road_gui.cpp
+static DiagDirection RoadBitsToDiagDir(RoadBits bits) {
+	if (bits < ROAD_SE) {
+		return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW;
+	}
+	return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE;
+}
+
+RoadBits FindRailsToConnect(TileIndex tile) {
+	RoadBits directed = ROAD_NONE;
+	RoadBits passing = ROAD_NONE;
+	DiagDirection ddir;
+	for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
+		TileIndex cur_tile = TileAddByDiagDir(tile, ddir);
+		if (HasStationTileRail(cur_tile)) {
+			if (GetRailStationTrackBits(cur_tile) & DiagdirReachesTracks(ddir)) {
+				directed |= DiagDirToRoadBits(ddir);
+			}
+			continue;
+		}
+		if (!IsTileType(cur_tile, MP_RAILWAY)) continue;
+		if (!IsPlainRail(cur_tile)) continue;
+		passing |= DiagDirToRoadBits(ddir);
+		if (GetTrackBits(cur_tile) & DiagdirReachesTracks(ddir)) {
+			directed |= DiagDirToRoadBits(ddir);
+		}
+	}
+	// Prioritize track bits that head in this direction
+	if (directed != ROAD_NONE) {
+		return directed;
+	}
+	return passing;
+}
+
+/*
+ * Selects orientation for rail object (depot)
+ */
+static DiagDirection AutodetectRailObjectDirection(TileIndex tile) {
+	RoadBits bits = FindRailsToConnect(tile);
+	// FIXME after this point repeats road autodetection
+	if (HasExactlyOneBit(bits)) return RoadBitsToDiagDir(bits);
+	if (bits == ROAD_NONE) bits = ROAD_ALL;
+	RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir());
+	if (HasExactlyOneBit(frac_bits & bits)) {
+		return RoadBitsToDiagDir(frac_bits & bits);
+	}
+	frac_bits |= MirrorRoadBits(frac_bits);
+	if (HasExactlyOneBit(frac_bits & bits)) {
+		return RoadBitsToDiagDir(frac_bits & bits);
+	}
+	for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
+		if (DiagDirToRoadBits(ddir) & bits) {
+			return ddir;
+		}
+	}
+	NOT_REACHED();
+}
+
 /** Rail toolbar management class. */
 struct BuildRailToolbarWindow : Window {
 	RailType railtype;    ///< Rail type to build.
@@ -461,6 +563,7 @@
 		this->GetWidget<NWidgetCore>(WID_RAT_BUILD_EW)->widget_data     = rti->gui_sprites.build_ew_rail;
 		this->GetWidget<NWidgetCore>(WID_RAT_BUILD_Y)->widget_data      = rti->gui_sprites.build_y_rail;
 		this->GetWidget<NWidgetCore>(WID_RAT_AUTORAIL)->widget_data     = rti->gui_sprites.auto_rail;
+		this->GetWidget<NWidgetCore>(WID_RAT_POLYRAIL)->widget_data     = rti->gui_sprites.auto_rail;
 		this->GetWidget<NWidgetCore>(WID_RAT_BUILD_DEPOT)->widget_data  = rti->gui_sprites.build_depot;
 		this->GetWidget<NWidgetCore>(WID_RAT_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail;
 		this->GetWidget<NWidgetCore>(WID_RAT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel;
@@ -489,6 +592,7 @@
 			case WID_RAT_BUILD_EW:
 			case WID_RAT_BUILD_Y:
 			case WID_RAT_AUTORAIL:
+			case WID_RAT_POLYRAIL:
 			case WID_RAT_BUILD_WAYPOINT:
 			case WID_RAT_BUILD_STATION:
 			case WID_RAT_BUILD_SIGNALS:
@@ -520,9 +624,19 @@
 		}
 	}
 
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget == WID_RAT_POLYRAIL) {
+			Dimension d = GetSpriteSize(SPR_BLOT);
+			uint offset = this->IsWidgetLowered(WID_RAT_POLYRAIL) ? 1 : 0;
+			DrawSprite(SPR_BLOT, PALETTE_TO_GREY, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset);
+		}
+	}
+
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
 		if (widget < WID_RAT_BUILD_NS) return;
+		bool remove_on_ctrl = true;  /* do not check ctrl for hotkeys */
 
 		_remove_button_clicked = false;
 		switch (widget) {
@@ -551,6 +665,40 @@
 				this->last_user_action = widget;
 				break;
 
+			case WID_RAT_POLYRAIL: {
+				bool was_snap = CurrentlySnappingRailPlacement();
+				bool was_open = this->IsWidgetLowered(WID_RAT_POLYRAIL);
+				bool do_snap;
+				bool do_open;
+				/* "polyrail" hotkey     - activate polyline tool in snapping mode, close the tool if snapping mode is already active
+				 * "new_polyrail" hotkey - activate polyline tool in non-snapping (new line) mode, close the tool if non-snapping mode is already active
+				 * button ctrl-clicking  - switch between snapping and non-snapping modes, open the tool in non-snapping mode if it is closed
+				 * button clicking       - open the tool in non-snapping mode, close the tool if it is opened */
+				if (this->last_user_action == HOTKEY_POLYRAIL) {
+					do_snap = true;
+					do_open = !was_open || !was_snap;
+				} else if (this->last_user_action == HOTKEY_NEW_POLYRAIL) {
+					do_snap = false;
+					do_open = !was_open || was_snap;
+				} else if (_ctrl_pressed) {
+					do_snap = !was_open || !was_snap;
+					do_open = true;
+				} else {
+					do_snap = false;
+					do_open = !was_open;
+				}
+				/* close the tool explicitly so it can be re-opened in different snapping mode */
+				if (was_open) ResetObjectToPlace();
+				/* open the tool in desired mode */
+				if (do_open && HandlePlacePushButton(this, WID_RAT_POLYRAIL, GetRailTypeInfo(railtype)->cursor.autorail, do_snap ? (HT_RAIL | HT_POLY) : (HT_RAIL | HT_NEW_POLY))) {
+					/* if we are re-opening the tool but we couldn't switch the snapping
+					 * then close the tool instead of appearing to be doing nothing */
+					if (was_open && do_snap != CurrentlySnappingRailPlacement()) ResetObjectToPlace();
+				}
+				this->last_user_action = WID_RAT_POLYRAIL;
+				break;
+			}
+
 			case WID_RAT_DEMOLISH:
 				HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
 				this->last_user_action = widget;
@@ -571,12 +719,28 @@
 				}
 				break;
 
-			case WID_RAT_BUILD_STATION:
-				if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT)) {
-					ShowStationBuilder(this);
-					this->last_user_action = widget;
+			case WID_RAT_BUILD_STATION: {
+				bool dragdrop = (this->last_user_action == HOTKEY_BUILD_STATION_DRAGDROP);
+
+				if (dragdrop || this->last_user_action == HOTKEY_BUILD_STATION_SIZED) { /* hotkey */
+					bool was_open = this->IsWidgetLowered(WID_RAT_BUILD_STATION);
+					/* close the tool explicitly so it can be re-opened in different snapping mode */
+					if (was_open) ResetObjectToPlace();
+					if (!was_open || dragdrop != _settings_client.gui.station_dragdrop) {
+						_settings_client.gui.station_dragdrop = dragdrop;
+						if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT))
+							ShowStationBuilder(this);
+					}
+					this->last_user_action = WID_RAT_BUILD_STATION;
+					remove_on_ctrl = false;
+				} else { /* button */
+					if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT)) {
+						ShowStationBuilder(this);
+						this->last_user_action = WID_RAT_BUILD_STATION;
+					}
 				}
 				break;
+			}
 
 			case WID_RAT_BUILD_SIGNALS: {
 				this->last_user_action = widget;
@@ -609,17 +773,34 @@
 			default: NOT_REACHED();
 		}
 		this->UpdateRemoveWidgetStatus(widget);
-		if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
+		if (_ctrl_pressed && remove_on_ctrl) RailToolbar_CtrlChanged(this);
 	}
 
 	virtual EventState OnHotkey(int hotkey)
 	{
+		// EventState es;
 		MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
+
+		switch (hotkey) {
+			/* Indicate to the OnClick that the action comes from a hotkey rather
+			 * then from a click and that the CTRL state should be ignored. */
+			case HOTKEY_POLYRAIL:
+			case HOTKEY_NEW_POLYRAIL:
+				this->last_user_action = hotkey;
+				return this->Window::OnHotkey(WID_RAT_POLYRAIL);
+
+			case HOTKEY_BUILD_STATION_SIZED:
+			case HOTKEY_BUILD_STATION_DRAGDROP:
+				this->last_user_action = hotkey;
+				return this->Window::OnHotkey(WID_RAT_BUILD_STATION);
+		}
+
 		return Window::OnHotkey(hotkey);
 	}
 
 	virtual void OnPlaceObject(Point pt, TileIndex tile)
 	{
+		DiagDirection ddir;
 		switch (this->last_user_action) {
 			case WID_RAT_BUILD_NS:
 				VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
@@ -638,6 +819,7 @@
 				break;
 
 			case WID_RAT_AUTORAIL:
+			case WID_RAT_POLYRAIL:
 				VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
 				break;
 
@@ -646,7 +828,11 @@
 				break;
 
 			case WID_RAT_BUILD_DEPOT:
-				DoCommandP(tile, _cur_railtype, _build_depot_direction,
+				ddir = _build_depot_direction;
+				if (ddir == DIAGDIR_NW + 1) {
+					ddir = AutodetectRailObjectDirection(tile);
+				}
+				DoCommandP(tile, _cur_railtype, ddir,
 						CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT),
 						CcRailDepot);
 				break;
@@ -785,6 +971,8 @@
 }
 
 const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0};
+const uint16 _railtoolbar_polyrail_keys[] = {'5' | WKC_CTRL, 'A' | WKC_CTRL | WKC_GLOBAL_HOTKEY, 0};
+const uint16 _railtoolbar_new_poly_keys[] = {'5' | WKC_CTRL | WKC_SHIFT, 'A' | WKC_CTRL | WKC_SHIFT | WKC_GLOBAL_HOTKEY, 0};
 
 static Hotkey railtoolbar_hotkeys[] = {
 	Hotkey('1', "build_ns", WID_RAT_BUILD_NS),
@@ -792,9 +980,13 @@
 	Hotkey('3', "build_ew", WID_RAT_BUILD_EW),
 	Hotkey('4', "build_y", WID_RAT_BUILD_Y),
 	Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL),
+	Hotkey(_railtoolbar_polyrail_keys, "polyrail", HOTKEY_POLYRAIL),
+	Hotkey(_railtoolbar_new_poly_keys, "new_polyrail", HOTKEY_NEW_POLYRAIL),
 	Hotkey('6', "demolish", WID_RAT_DEMOLISH),
 	Hotkey('7', "depot", WID_RAT_BUILD_DEPOT),
 	Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT),
+	Hotkey((uint16)0, "station_sized", HOTKEY_BUILD_STATION_SIZED),  // has to go before station hotkey to override it
+	Hotkey((uint16)0, "station_dragdrop", HOTKEY_BUILD_STATION_DRAGDROP),
 	Hotkey('9', "station", WID_RAT_BUILD_STATION),
 	Hotkey('S', "signal", WID_RAT_BUILD_SIGNALS),
 	Hotkey('B', "bridge", WID_RAT_BUILD_BRIDGE),
@@ -822,6 +1014,8 @@
 						SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
 		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_AUTORAIL),
 						SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL),
+		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_POLYRAIL),
+						SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_POLYRAIL),
 
 		NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(),
 
@@ -1703,10 +1897,19 @@
 
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
-		if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return;
+		switch (widget) {
+			case WID_BRAD_DEPOT_NE:
+			case WID_BRAD_DEPOT_SE:
+			case WID_BRAD_DEPOT_SW:
+			case WID_BRAD_DEPOT_NW:
+				size->width  = ScaleGUITrad(64) + 2;
+				size->height = ScaleGUITrad(48) + 2;
+				break;
 
-		size->width  = ScaleGUITrad(64) + 2;
-		size->height = ScaleGUITrad(48) + 2;
+			case WID_BRAD_DEPOT_AUTO:
+				size->width  = ScaleGUITrad(128) + 6;
+				break;
+		}
 	}
 
 	virtual void DrawWidget(const Rect &r, int widget) const
@@ -1723,6 +1926,7 @@
 			case WID_BRAD_DEPOT_SE:
 			case WID_BRAD_DEPOT_SW:
 			case WID_BRAD_DEPOT_NW:
+			case WID_BRAD_DEPOT_AUTO:
 				this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
 				_build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE);
 				this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
@@ -1760,6 +1964,12 @@
 			EndContainer(),
 			NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
 		EndContainer(),
+		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+		NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+		EndContainer(),
 		NWidget(NWID_SPACER), SetMinimalSize(0, 3),
 	EndContainer(),
 };
@@ -1880,7 +2090,7 @@
  */
 void InitializeRailGui()
 {
-	_build_depot_direction = DIAGDIR_NW;
+	_build_depot_direction = (DiagDirection)(DIAGDIR_NW + 1);
 }
 
 /**
diff -r e16bdc0054ce src/road_cmd.cpp
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -807,7 +807,7 @@
  * @param dir Direction that the road is following.
  * @return True if the next tile at dir direction is suitable for being connected directly by a second roadbit at the end of the road being built.
  */
-static bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir)
+bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir)
 {
 	RoadBits bits = GetAnyRoadBits(tile + TileOffsByDiagDir(dir), rt, false);
 	return (bits & DiagDirToRoadBits(ReverseDiagDir(dir))) != 0;
diff -r e16bdc0054ce src/road_func.h
--- a/src/road_func.h
+++ b/src/road_func.h
@@ -181,4 +181,6 @@
 
 void UpdateLevelCrossing(TileIndex tile, bool sound = true);
 
+bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir);
+
 #endif /* ROAD_FUNC_H */
diff -r e16bdc0054ce src/road_gui.cpp
--- a/src/road_gui.cpp
+++ b/src/road_gui.cpp
@@ -1,4 +1,4 @@
-/* $Id: road_gui.cpp 27381 2015-08-10 20:24:13Z michi_cc $ */
+/* $Id: road_gui.cpp 27163 2015-02-22 15:26:27Z frosch $ */
 
 /*
  * This file is part of OpenTTD.
@@ -11,7 +11,9 @@
 
 #include "stdafx.h"
 #include "gui.h"
+#include "cmd_helper.h"
 #include "window_gui.h"
+#include "station_func.h"
 #include "station_gui.h"
 #include "terraform_gui.h"
 #include "viewport_func.h"
@@ -29,7 +31,7 @@
 #include "hotkeys.h"
 #include "road_gui.h"
 #include "zoom_func.h"
-
+#include "industry.h"
 #include "widgets/road_widget.h"
 
 #include "table/strings.h"
@@ -211,6 +213,107 @@
 	}
 }
 
+
+static RoadBits FindRoadsToConnect(TileIndex tile) {
+	RoadBits bits = ROAD_NONE;
+	DiagDirection ddir;
+	// Prioritize roadbits that head in this direction
+	for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
+		TileIndex cur_tile = TileAddByDiagDir(tile, ddir);
+		if (GetAnyRoadBits(cur_tile, ROADTYPE_ROAD, true) &
+			DiagDirToRoadBits(ReverseDiagDir(ddir)))
+		{
+			bits |= DiagDirToRoadBits(ddir);
+		}
+	}
+	if (bits != ROAD_NONE) {
+		return bits;
+	}
+	// Try to connect to any road passing by
+	for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
+		TileIndex cur_tile = TileAddByDiagDir(tile, ddir);
+		if (HasTileRoadType(cur_tile, ROADTYPE_ROAD) && (GetTileType(cur_tile) == MP_ROAD) &&
+				(GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) {
+			bits |= DiagDirToRoadBits(ddir);
+		}
+	}
+	return bits;
+}
+
+static DiagDirection RoadBitsToDiagDir(RoadBits bits) {
+	if (bits < ROAD_SE) {
+		return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW;
+	}
+	return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE;
+}
+
+static DiagDirection TileFractCoordsToDiagDir() {
+	bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16;
+	if (_tile_fract_coords.x < _tile_fract_coords.y) {
+		return diag ? DIAGDIR_NE : DIAGDIR_SE;
+	}
+	return diag ? DIAGDIR_NW : DIAGDIR_SW;
+}
+/*
+ * Selects orientation for road object (depot, terminal station)
+ */
+static DiagDirection AutodetectRoadObjectDirection(TileIndex tile) {
+	RoadBits bits = FindRoadsToConnect(tile);
+	if (HasExactlyOneBit(bits)) {
+		return RoadBitsToDiagDir(bits);
+	}
+	if (bits == ROAD_NONE){
+		bits = ROAD_ALL;
+	}
+	RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir());
+	if (HasExactlyOneBit(frac_bits & bits)) {
+		return RoadBitsToDiagDir(frac_bits & bits);
+	}
+	frac_bits |= MirrorRoadBits(frac_bits);
+	if (HasExactlyOneBit(frac_bits & bits)) {
+		return RoadBitsToDiagDir(frac_bits & bits);
+	}
+	for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
+		if (DiagDirToRoadBits(ddir) & bits) {
+			return ddir;
+		}
+	}
+	NOT_REACHED();
+}
+
+static bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r) {
+	TILE_AREA_LOOP(tile, area) {
+		if (!HasTileRoadType(tile, ROADTYPE_ROAD)) continue;
+		if (GetTileType(tile) != MP_ROAD) continue;
+		if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) continue;
+		if (GetRoadBits(tile, ROADTYPE_ROAD) & ~r) return false;
+	}
+	return true;
+}
+
+
+/*
+ * Automaticaly selects direction to use for road stop.
+ * @param area road stop area
+ * @return selected direction
+ */
+static DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area) {
+	bool se_suits, ne_suits;
+
+	// Check which direction is available
+	// If both are not use SE, building will fail anyway
+	se_suits = CheckDriveThroughRoadStopDirection(area, ROAD_Y);
+	ne_suits = CheckDriveThroughRoadStopDirection(area, ROAD_X);
+	if (!ne_suits) return DIAGDIR_SE;
+	if (!se_suits) return DIAGDIR_NE;
+
+	// Build station along the longer direction
+	if (area.w > area.h) return DIAGDIR_NE;
+	if (area.w < area.h) return DIAGDIR_SE;
+
+	return AutodetectRoadObjectDirection(area.tile);
+}
+
 /**
  * Place a new road stop.
  * @param start_tile First tile of the area.
@@ -225,14 +328,23 @@
 {
 	uint8 ddir = _road_station_picker_orientation;
 	SB(p2, 16, 16, INVALID_STATION); // no station to join
+	TileArea ta(start_tile, end_tile);
 
 	if (ddir >= DIAGDIR_END) {
-		SetBit(p2, 1); // It's a drive-through stop.
-		ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
+		if (ddir < DIAGDIR_END + 2) {
+			SetBit(p2, 1); // It's a drive-through stop.
+			ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
+		}
+		else if (ddir == DIAGDIR_END + 2) {
+			ddir = AutodetectRoadObjectDirection(start_tile);
+		}
+		else if (ddir == DIAGDIR_END + 3) {
+			SetBit(p2, 1); // It's a drive-through stop.
+			ddir = AutodetectDriveThroughRoadStopDirection(ta);
+		}
 	}
 	p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7.
 
-	TileArea ta(start_tile, end_tile);
 	CommandContainer cmdcont = { ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop, "" };
 	ShowSelectStationIfNeeded(cmdcont, ta);
 }
@@ -297,8 +409,8 @@
 	if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false;
 
 	/* allow ctrl to switch remove mode only for these widgets */
-	for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) {
-		if (w->IsWidgetLowered(i)) {
+	for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_FULLROAD; i++) {
+		if (w->GetWidget<NWidgetCore>(i) && w->IsWidgetLowered(i)) {
 			ToggleRoadButton_Remove(w);
 			return true;
 		}
@@ -382,6 +494,7 @@
 			case WID_ROT_ROAD_X:
 			case WID_ROT_ROAD_Y:
 			case WID_ROT_AUTOROAD:
+			case WID_ROT_FULLROAD:
 				this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget),
 						WID_ROT_REMOVE,
 						WID_ROT_ONE_WAY,
@@ -403,8 +516,19 @@
 		}
 	}
 
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget == WID_ROT_FULLROAD) {
+			Dimension d = GetSpriteSize(SPR_BLOT);
+			uint offset = this->IsWidgetLowered(WID_ROT_FULLROAD) ? 1 : 0;
+			DrawSprite(SPR_BLOT, PALETTE_TO_GREY, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset);
+		}
+	}
+
+
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
+		static bool fullroad_warned = false;
 		_remove_button_clicked = false;
 		_one_way_button_clicked = false;
 		switch (widget) {
@@ -423,6 +547,16 @@
 				this->last_started_action = widget;
 				break;
 
+			case WID_ROT_FULLROAD:
+				HandlePlacePushButton(this, WID_ROT_FULLROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT);
+				if (!fullroad_warned) {
+					ShowGoalQuestion(0, 2 /* WARNING */, 2 /* OK */, "Full-tile autoroad tool is deprecated and will be removed in next release.\n Use regular autoroad tool instead.");
+					fullroad_warned = true;
+				}
+
+				this->last_started_action = widget;
+				break;
+
 			case WID_ROT_DEMOLISH:
 				HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
 				this->last_started_action = widget;
@@ -491,6 +625,7 @@
 
 	virtual void OnPlaceObject(Point pt, TileIndex tile)
 	{
+		DiagDirection ddir;
 		_remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
 		_one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY);
 		switch (this->last_started_action) {
@@ -513,12 +648,23 @@
 				VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
 				break;
 
+			case WID_ROT_FULLROAD:
+				_place_road_flag = RF_NONE;
+				if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
+				if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
+				VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_FULLROAD);
+				break;
+
 			case WID_ROT_DEMOLISH:
 				PlaceProc_DemolishArea(tile);
 				break;
 
 			case WID_ROT_DEPOT:
-				DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0,
+				ddir = _road_depot_orientation;
+				if (ddir == DIAGDIR_NW + 1) {
+					ddir = AutodetectRoadObjectDirection(tile);
+				}
+				DoCommandP(tile, _cur_roadtype << 2 | ddir, 0,
 						CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot);
 				break;
 
@@ -578,6 +724,7 @@
 				break;
 
 			case DDSP_PLACE_AUTOROAD:
+			case DDSP_PLACE_FULLROAD:
 				_place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
 				if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
 				if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
@@ -603,6 +750,20 @@
 		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
 	}
 
+	void TryToRemoveExtraRoadBits(TileIndex tile, RoadBits &rb) {
+		for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
+			RoadBits dir_rb = DiagDirToRoadBits(dir);
+			if (!(rb & dir_rb)) continue;
+			if (CanConnectToRoad(tile, _cur_roadtype, dir)) continue;
+			DoCommandP(tile, tile,
+			    (dir_rb == ROAD_NW || dir_rb == ROAD_NE ? 0 : 3) |
+			    (dir_rb & ROAD_X ? 0 : 4) |
+			    (_cur_roadtype << 3),
+			    CMD_REMOVE_LONG_ROAD);
+			rb &= ~dir_rb;
+		}
+	}
+
 	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
 	{
 		if (pt.x != -1) {
@@ -632,6 +793,30 @@
 							CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D);
 					break;
 
+				case DDSP_PLACE_FULLROAD:
+					if (start_tile == end_tile || _remove_button_clicked) {
+						_place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
+						DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5),
+							_remove_button_clicked ?
+							CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
+							CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D);
+					} else {
+						_place_road_flag &= RF_DIR_Y;
+						RoadBits road_dir = _place_road_flag ? ROAD_Y : ROAD_X;
+						// if (start_tile > end_tile) Swap(start_tile, end_tile);
+						RoadBits start_extra_rb = GetAnyRoadBits(start_tile, _cur_roadtype, false) & ~road_dir;
+						RoadBits end_extra_rb = GetAnyRoadBits(end_tile, _cur_roadtype, false) & ~road_dir;
+						this->TryToRemoveExtraRoadBits(start_tile, start_extra_rb);
+						this->TryToRemoveExtraRoadBits(end_tile, end_extra_rb);
+						if ((bool)start_extra_rb != (start_tile > end_tile)) _place_road_flag |= RF_START_HALFROAD_Y;
+						if (!end_extra_rb != (start_tile > end_tile)) _place_road_flag |= RF_END_HALFROAD_Y;
+						DoCommandP(start_tile, end_tile,
+							_place_road_flag | (_cur_roadtype << 3) |
+							(_one_way_button_clicked << 5) | (1 << 6),
+							CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D);
+					}
+					break;
+
 				case DDSP_BUILD_BUSSTOP:
 					PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS]));
 					break;
@@ -642,13 +827,13 @@
 
 				case DDSP_REMOVE_BUSSTOP: {
 					TileArea ta(start_tile, end_tile);
-					DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D);
+					DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D);
 					break;
 				}
 
 				case DDSP_REMOVE_TRUCKSTOP: {
 					TileArea ta(start_tile, end_tile);
-					DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D);
+					DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D);
 					break;
 				}
 			}
@@ -706,6 +891,7 @@
 	Hotkey('6', "bus_station", WID_ROT_BUS_STATION),
 	Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION),
 	Hotkey('8', "oneway", WID_ROT_ONE_WAY),
+	Hotkey('9', "fullroad", WID_ROT_FULLROAD),
 	Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE),
 	Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL),
 	Hotkey('R', "remove", WID_ROT_REMOVE),
@@ -738,6 +924,8 @@
 		NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
 		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY),
 						SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD),
+		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_FULLROAD),
+						SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD),
 		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
 						SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE),
 		NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
@@ -864,7 +1052,7 @@
 		this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
 		if ( _cur_roadtype == ROADTYPE_TRAM) {
 			this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
-			for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
+			for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_AUTO; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
 		}
 
 		this->FinishInitNested(TRANSPORT_ROAD);
@@ -872,10 +1060,20 @@
 
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
-		if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return;
-
-		size->width  = ScaleGUITrad(64) + 2;
-		size->height = ScaleGUITrad(48) + 2;
+		switch (widget) {
+			case WID_BROD_DEPOT_NW:
+			case WID_BROD_DEPOT_NE:
+			case WID_BROD_DEPOT_SW:
+			case WID_BROD_DEPOT_SE:
+				size->width  = ScaleGUITrad(64) + 2;
+				size->height = ScaleGUITrad(48) + 2;
+				break;
+			case WID_BROD_DEPOT_AUTO:
+				size->width = ScaleGUITrad(128) + 6;
+				break;
+			default:
+				break;
+		}
 	}
 
 	virtual void DrawWidget(const Rect &r, int widget) const
@@ -892,6 +1090,7 @@
 			case WID_BROD_DEPOT_NE:
 			case WID_BROD_DEPOT_SW:
 			case WID_BROD_DEPOT_SE:
+			case WID_BROD_DEPOT_AUTO:
 				this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
 				_road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
 				this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
@@ -931,6 +1130,12 @@
 			EndContainer(),
 			NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
 		EndContainer(),
+		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+		NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+		EndContainer(),
 		NWidget(NWID_SPACER), SetMinimalSize(0, 3),
 	EndContainer(),
 };
@@ -1008,10 +1213,25 @@
 
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
-		if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
-
-		size->width  = ScaleGUITrad(64) + 2;
-		size->height = ScaleGUITrad(48) + 2;
+		switch (widget) {
+			case WID_BROS_STATION_NE:
+			case WID_BROS_STATION_SE:
+			case WID_BROS_STATION_SW:
+			case WID_BROS_STATION_NW:
+			case WID_BROS_STATION_X:
+			case WID_BROS_STATION_Y:
+				size->width  = ScaleGUITrad(64) + 2;
+				size->height = ScaleGUITrad(48) + 2;
+				break;
+			case WID_BROS_STATION_AUTO:
+				size->width  = ScaleGUITrad(128) + 6;
+				break;
+			case WID_BROS_STATION_XY_AUTO:
+				size->width  = ScaleGUITrad(64) + 2;
+				break;
+			default:
+				break;
+		}
 	}
 
 	virtual void DrawWidget(const Rect &r, int widget) const
@@ -1031,6 +1251,8 @@
 			case WID_BROS_STATION_NW:
 			case WID_BROS_STATION_X:
 			case WID_BROS_STATION_Y:
+			case WID_BROS_STATION_AUTO:
+			case WID_BROS_STATION_XY_AUTO:
 				this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
 				_road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
 				this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
@@ -1082,6 +1304,13 @@
 			NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y),  SetMinimalSize(66, 50), EndContainer(),
 			NWidget(NWID_SPACER), SetFill(1, 0),
 		EndContainer(),
+		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+		NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
+			NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_XY_AUTO), SetMinimalSize(66, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
+			NWidget(NWID_SPACER), SetFill(1, 0),
+		EndContainer(),
 		NWidget(NWID_SPACER), SetMinimalSize(0, 1),
 		NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
 			NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
@@ -1113,6 +1342,6 @@
 
 void InitializeRoadGui()
 {
-	_road_depot_orientation = DIAGDIR_NW;
-	_road_station_picker_orientation = DIAGDIR_NW;
+	_road_depot_orientation = (DiagDirection)(DIAGDIR_NW + 1);
+	_road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3);
 }
diff -r e16bdc0054ce src/saveload/citymania_sl.cpp
--- /dev/null
+++ b/src/saveload/citymania_sl.cpp
@@ -0,0 +1,260 @@
+#include "citymania_sl.h"
+#include "../bitstream.h"
+#include "../date_func.h"
+#include "../debug.h"
+#include "../town.h"
+
+#define CM_DATA_FORMAT_VERSION 1
+
+assert_compile(NUM_CARGO == 32);
+
+
+static void CM_EncodeTownsExtraInfo(BitOStream &bs)
+{
+	Town *t;
+	uint n_affected_towns = 0;
+	FOR_ALL_TOWNS(t) {
+		if (t->growing_by_chance || t->houses_reconstruction ||
+				t->houses_demolished)
+			n_affected_towns++;
+	}
+	bs.WriteBytes(n_affected_towns, 2);
+	FOR_ALL_TOWNS(t) {
+		if (t->growing_by_chance || t->houses_reconstruction ||
+				t->houses_demolished) {
+			bs.WriteBytes(t->index, 2);
+			bs.WriteBytes(t->growing_by_chance, 1);
+			bs.WriteBytes(t->houses_reconstruction, 2);
+			bs.WriteBytes(t->houses_demolished, 2);
+		}
+	}
+}
+
+static void CM_EncodeTownsGrowthTiles(BitOStream &bs, TownsGrowthTilesIndex &tiles)
+{
+	bs.WriteBytes(tiles.size(), 4);
+	for (TownsGrowthTilesIndex::iterator p = tiles.begin();
+			p != tiles.end(); p++) {
+		bs.WriteBytes(p->first, 4);
+		bs.WriteBytes(p->second, 1);
+	}
+}
+
+static void CM_EncodeTownsLayoutErrors(BitOStream &bs)
+{
+	Town *t;
+	uint n_affected_towns = 0;
+	FOR_ALL_TOWNS(t) {
+		if (t->cb_houses_removed || t->houses_skipped || t->cycles_skipped)
+			n_affected_towns++;
+	}
+	bs.WriteBytes(n_affected_towns, 2);
+	FOR_ALL_TOWNS(t) {
+		if (t->cb_houses_removed || t->houses_skipped || t->cycles_skipped) {
+			bs.WriteBytes(t->index, 2);
+			bs.WriteBytes(t->houses_skipped, 2);
+			bs.WriteBytes(t->houses_skipped_prev, 2);
+			bs.WriteBytes(t->houses_skipped_last_month, 2);
+			bs.WriteBytes(t->cycles_skipped, 2);
+			bs.WriteBytes(t->cycles_skipped_prev, 2);
+			bs.WriteBytes(t->cycles_skipped_last_month, 2);
+			bs.WriteBytes(t->cb_houses_removed, 2);
+			bs.WriteBytes(t->cb_houses_removed_prev, 2);
+			bs.WriteBytes(t->cb_houses_removed_last_month, 2);
+		}
+	}
+	CM_EncodeTownsGrowthTiles(bs, _towns_growth_tiles);
+	CM_EncodeTownsGrowthTiles(bs, _towns_growth_tiles_last_month);
+}
+
+static void CM_EncodeTownsCargo(BitOStream &bs)
+{
+	uint n_cb_cargos = 0;
+	CargoID cb_cargos[NUM_CARGO];
+	for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
+		if (CB_GetReq(cargo) > 0)
+			cb_cargos[n_cb_cargos++] = cargo;
+	}
+
+	bs.WriteBytes(CB_GetStorage(), 1);
+	bs.WriteBytes(_settings_client.gui.cb_distance_check, 1);
+	bs.WriteBytes(n_cb_cargos, 1);
+	for (uint i = 0; i < n_cb_cargos; i++) {
+		CargoID cargo = cb_cargos[i];
+		bs.WriteBytes(cargo, 1);
+		bs.WriteBytes(CB_GetReq(cargo), 4);
+		bs.WriteBytes(CB_GetFrom(cargo), 4);
+		bs.WriteBytes(CB_GetDecay(cargo), 1);
+	}
+
+	Town *t;
+	bs.WriteBytes(Town::GetNumItems(), 2);
+	FOR_ALL_TOWNS(t) {
+		bs.WriteBytes(t->index, 2);
+		for (uint i = 0; i < n_cb_cargos; i++) {
+			CargoID cargo = cb_cargos[i];
+			bs.WriteBytes(t->storage[cargo], 4);
+			bs.WriteBytes(t->act_cargo[cargo], 4);
+			bs.WriteBytes(t->new_act_cargo[cargo], 4);
+			bs.WriteBytes(t->delivered_enough[cargo], 1);
+		}
+	}
+}
+
+static void CM_DecodeTownsExtraInfo(BitIStream &bs)
+{
+	Town *t;
+	uint n_affected_towns = bs.ReadBytes(2);
+	for (uint i = 0; i < n_affected_towns; i++) {
+		uint town_id = bs.ReadBytes(2);
+		t = Town::Get(town_id);
+		// TODO is it even supposed to return null? or just invalid pointer
+		if (!t) {
+			DEBUG(sl, 0, "Invalid TownID in CM extra towns info (%u)", town_id);
+			continue;
+		}
+		t->growing_by_chance = bs.ReadBytes(1);
+		t->houses_reconstruction = bs.ReadBytes(2);
+		t->houses_demolished = bs.ReadBytes(2);
+	}
+}
+
+static void CM_DecodeTownsGrowthTiles(BitIStream &bs, TownsGrowthTilesIndex &tiles)
+{
+	uint n = bs.ReadBytes(4);
+	for (uint i = 0; i < n; i++) {
+		TileIndex tile = bs.ReadBytes(4);
+		TownGrowthTileState state = (TownGrowthTileState)bs.ReadBytes(1);
+		tiles[tile] = state;
+	}
+}
+
+static void CM_DecodeTownsLayoutErrors(BitIStream &bs)
+{
+	Town *t;
+	uint n_affected_towns = bs.ReadBytes(2);
+	for (uint i = 0; i < n_affected_towns; i++) {
+		uint town_id = bs.ReadBytes(2);
+		t = Town::Get(town_id);
+		if (!t) {
+			DEBUG(sl, 0, "Invalid TownID in CB towns layout errors (%u)", town_id);
+			continue;
+		}
+		t->houses_skipped = bs.ReadBytes(2);
+		t->houses_skipped_prev = bs.ReadBytes(2);
+		t->houses_skipped_last_month = bs.ReadBytes(2);
+		t->cycles_skipped = bs.ReadBytes(2);
+		t->cycles_skipped_prev = bs.ReadBytes(2);
+		t->cycles_skipped_last_month = bs.ReadBytes(2);
+		t->cb_houses_removed = bs.ReadBytes(2);
+		t->cb_houses_removed_prev = bs.ReadBytes(2);
+		t->cb_houses_removed_last_month = bs.ReadBytes(2);
+	}
+	CM_DecodeTownsGrowthTiles(bs, _towns_growth_tiles);
+	CM_DecodeTownsGrowthTiles(bs, _towns_growth_tiles_last_month);
+}
+
+static void CM_DecodeTownsCargo(BitIStream &bs)
+{
+	CB_SetStorage(bs.ReadBytes(1));
+	_settings_client.gui.cb_distance_check = bs.ReadBytes(1);
+	uint n_cb_cargos = bs.ReadBytes(1);
+	CB_ResetRequirements();
+	CargoID cb_cargos[NUM_CARGO];
+	for (uint i = 0; i < n_cb_cargos; i++) {
+		uint cargo = bs.ReadBytes(1);
+		if (cargo >= NUM_CARGO) {
+			DEBUG(sl, 0, "Invalid CargoID in CB towns cargo data (%u)", cargo);
+			return;
+		}
+		cb_cargos[i] = cargo;
+		uint req = bs.ReadBytes(4);
+		uint from = bs.ReadBytes(4);
+		uint decay = bs.ReadBytes(1);
+		CB_SetRequirements(cargo, req, from, decay);
+	}
+	Town *t;
+	uint n_affected_towns = bs.ReadBytes(2);
+	for (uint i = 0; i < n_affected_towns; i++) {
+		uint town_id = bs.ReadBytes(2);
+		t = Town::Get(town_id);
+		if (!t) {
+			DEBUG(sl, 0, "Invalid TownID in CB towns cargo data (%u)", town_id);
+			continue;
+		}
+		for (uint i = 0; i < n_cb_cargos; i++) {
+			CargoID cargo = cb_cargos[i];
+			t->storage[cargo] = bs.ReadBytes(4);
+			t->act_cargo[cargo] = bs.ReadBytes(4);
+			t->new_act_cargo[cargo] = bs.ReadBytes(4);
+			t->delivered_enough[cargo] = bs.ReadBytes(1);
+		}
+	}
+}
+
+u8vector CM_EncodeData()
+{
+	BitOStream bs;
+	bs.Reserve(1000);
+	bs.WriteBytes(CM_DATA_FORMAT_VERSION, 2);
+	bs.WriteBytes(1512, 2);  // TODO client version
+	bs.WriteBytes(CB_Enabled(), 1);
+	bs.WriteBytes(_date, 4);  // Just in case we'll need to detect that game
+	bs.WriteBytes(_date_fract, 1);  // was saved by unmodified client
+	bs.WriteBytes(0, 4);  // Reserved
+	bs.WriteBytes(0, 4);  // Reserved
+
+	if (CB_Enabled()) CM_EncodeTownsCargo(bs);
+	CM_EncodeTownsExtraInfo(bs);
+	CM_EncodeTownsLayoutErrors(bs);
+
+	// fill with 0 to fit in persistent storage chunks (16 * 4)
+	int mod = bs.GetByteSize() % 64;
+	if (mod) {
+		for (int i = 0; i < 64 - mod; i++)
+			bs.WriteBytes(0, 1);
+	}
+	DEBUG(sl, 2, "Citybuilder data takes %u bytes", bs.GetByteSize());
+	return bs.GetVector();
+}
+
+void CM_DecodeData(u8vector &data)
+{
+	ResetTownsGrowthTiles();
+	extern bool _novahost;
+	if (data.size() == 0) {
+		_novahost = false;
+		CB_SetCB(false);
+		DEBUG(sl, 2, "No citybuilder data");
+		return;
+	}
+	DEBUG(sl, 2, "Citybuilder data takes %lu bytes", data.size());
+	_novahost = true;
+	BitIStream bs(data);
+	try {
+		uint version = bs.ReadBytes(2);
+		if (version != CM_DATA_FORMAT_VERSION) {
+			DEBUG(sl, 0, "Savegame was made with different version of client, extra citybuilder data was not loaded");
+			return;
+		}
+		bs.ReadBytes(2);  // client version
+		bool is_cb = bs.ReadBytes(1);
+		CB_SetCB(is_cb);
+		int32 date = bs.ReadBytes(4);  // date
+		uint32 date_fract = bs.ReadBytes(1);  // date_fract
+		if (date != _date || date_fract != _date_fract) {
+			DEBUG(sl, 0, "Savegame was run in unmodified client, extra cb data "
+			      "preserved, but may not be accurate");
+		}
+		bs.ReadBytes(4);  // reserved
+		bs.ReadBytes(4);  // reserved
+		if (is_cb) {
+			CM_DecodeTownsCargo(bs);
+		}
+		CM_DecodeTownsExtraInfo(bs);
+		CM_DecodeTownsLayoutErrors(bs);
+	}
+	catch (BitIStreamUnexpectedEnd &e) {
+		DEBUG(sl, 0, "Invalid citybuilder data");
+	}
+}
\ No newline at end of file
diff -r e16bdc0054ce src/saveload/citymania_sl.h
--- /dev/null
+++ b/src/saveload/citymania_sl.h
@@ -0,0 +1,9 @@
+#ifndef SAVELOAD_CITYMANIA_SL_H
+#define SAVELOAD_CITYMANIA_SL_H
+
+#include "../bitstream.h"
+
+u8vector CM_EncodeData();
+void CM_DecodeData(u8vector &data);
+
+#endif
diff -r e16bdc0054ce src/saveload/storage_sl.cpp
--- a/src/saveload/storage_sl.cpp
+++ b/src/saveload/storage_sl.cpp
@@ -11,10 +11,14 @@
 
 #include "../stdafx.h"
 #include "../newgrf_storage.h"
+#include "citymania_sl.h"
 #include "saveload.h"
 
 #include "../safeguards.h"
 
+// Luukland_Citybuilder grf id actually
+#define CITYMANIA_GRFID 0x534B0501U
+
 /** Description of the data to save and load in #PersistentStorage. */
 static const SaveLoad _storage_desc[] = {
 	 SLE_CONDVAR(PersistentStorage, grfid,    SLE_UINT32,                  6, SL_MAX_VERSION),
@@ -22,15 +26,62 @@
 	 SLE_END()
 };
 
+// static void hexdump(uint8 *data) {
+// 	uint i;
+// 	for (i = 0; i < 20; i++) {
+// 		if (i) fprintf(stderr, " : ");
+// 		fprintf(stderr, "%02x", data[i]);
+// 	}
+// 	fprintf(stderr, i >= 20 ? " ...\n" : "\n");
+// }
+
 /** Load persistent storage data. */
 static void Load_PSAC()
 {
 	int index;
 
+	/*
+		CITYMANIA_GRFID is used to hide extra data in persitant storages.
+		To save a bit of memory we only keep at most one PS with this
+		grfid and it is later discarded on save.
+	*/
+	PersistentStorage *ps = NULL;
+	u8vector cmdata;
+
 	while ((index = SlIterateArray()) != -1) {
-		assert(PersistentStorage::CanAllocateItem());
-		PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0);
+		if (ps == NULL) {
+			assert(PersistentStorage::CanAllocateItem());
+			ps = new (index) PersistentStorage(0, 0, 0);
+		}
 		SlObject(ps, _storage_desc);
+
+		if (ps->grfid == CITYMANIA_GRFID) {
+			uint8 *data = (uint8 *)(ps->storage);
+			cmdata.insert(cmdata.end(), data, data + 64);
+		} else {
+			ps = NULL;
+		}
+	}
+
+	CM_DecodeData(cmdata);
+}
+
+static void Save_CMDataAsPSAC() {
+	uint32 grfid = CITYMANIA_GRFID;
+	u8vector data = CM_EncodeData();
+	uint8 *ptr = &data[0];
+	SaveLoadGlobVarList _desc[] = {
+		SLEG_CONDVAR(grfid, SLE_UINT32,       6, SL_MAX_VERSION),
+		SLEG_CONDARR(*ptr, SLE_UINT32, 16, 161, SL_MAX_VERSION),
+		SLEG_END()
+	};
+	uint index = PersistentStorage::GetNumItems();
+
+	int n_chunks = data.size() / 64;
+	for (int i = 0; i < n_chunks; i++, ptr += 64) {
+		_desc[1].address = (void *)ptr;
+		SlSetArrayIndex(index + i);
+		SlGlobList(_desc);
 	}
 }
 
@@ -41,10 +92,15 @@
 
 	/* Write the industries */
 	FOR_ALL_STORAGES(ps) {
+		if (ps->grfid == CITYMANIA_GRFID) {
+			continue;
+		}
 		ps->ClearChanges();
 		SlSetArrayIndex(ps->index);
 		SlObject(ps, _storage_desc);
 	}
+
+	Save_CMDataAsPSAC();
 }
 
 /** Chunk handler for persistent storages. */
diff -r e16bdc0054ce src/saveload/town_sl.cpp
--- a/src/saveload/town_sl.cpp
+++ b/src/saveload/town_sl.cpp
@@ -32,6 +32,7 @@
 	FOR_ALL_TOWNS(town) {
 		town->cache.population = 0;
 		town->cache.num_houses = 0;
+		town->cache.potential_pop = 0;
 	}
 
 	for (TileIndex t = 0; t < MapSize(); t++) {
@@ -41,6 +42,8 @@
 		town = Town::GetByTile(t);
 		IncreaseBuildingCount(town, house_id);
 		if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population;
+		else town->houses_construction++;
+		town->cache.potential_pop += HouseSpec::Get(house_id)->population;
 
 		/* Increase the number of houses for every house, but only once. */
 		if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
diff -r e16bdc0054ce src/settings_gui.cpp
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -36,6 +36,7 @@
 #include "textfile_gui.h"
 #include "stringfilter_type.h"
 #include "querystring_gui.h"
+#include "hotkeys.h"
 
 #include <vector>
 
@@ -570,6 +571,8 @@
 		missing_files = BaseMusic::GetUsedSet()->GetNumInvalid() == 0;
 		this->GetWidget<NWidgetCore>(WID_GO_BASE_MUSIC_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_MUSIC_STATUS, STR_NULL);
 	}
+
+	static HotkeyList hotkeys;
 };
 
 static const NWidgetPart _nested_game_options_widgets[] = {
@@ -653,11 +656,25 @@
 	EndContainer(),
 };
 
+static EventState GameOptionsWindowGlobalHotkeys(int hotkey) {
+	if (!ToggleFullScreen(!_fullscreen)) {
+		ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR);
+	}
+	return ES_HANDLED;
+}
+
+static Hotkey game_options_hotkeys[] = {
+	Hotkey((uint16)0, "toggle_fullscreen", WID_GO_FULLSCREEN_BUTTON),
+	HOTKEY_LIST_END
+};
+HotkeyList GameOptionsWindow::hotkeys("game_options", game_options_hotkeys, GameOptionsWindowGlobalHotkeys);
+
 static WindowDesc _game_options_desc(
 	WDP_CENTER, "settings_game", 0, 0,
 	WC_GAME_OPTIONS, WC_NONE,
 	0,
-	_nested_game_options_widgets, lengthof(_nested_game_options_widgets)
+	_nested_game_options_widgets, lengthof(_nested_game_options_widgets),
+	&GameOptionsWindow::hotkeys
 );
 
 /** Open the game options window. */
@@ -1524,6 +1541,10 @@
 				viewports->Add(new SettingEntry("gui.measure_tooltip"));
 				viewports->Add(new SettingEntry("gui.loading_indicators"));
 				viewports->Add(new SettingEntry("gui.show_track_reservation"));
+				viewports->Add(new SettingEntry("gui.cb_distance_check"));
+				viewports->Add(new SettingEntry("gui.old_depot_train_length_calc"));
+				viewports->Add(new SettingEntry("gui.enable_extra_tooltips"));
+				// viewports->Add(new SettingEntry("gui.polyrail_double_click"));
 			}
 
 			SettingsPage *construction = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION));
@@ -1544,6 +1565,8 @@
 			interface->Add(new SettingEntry("gui.timetable_in_ticks"));
 			interface->Add(new SettingEntry("gui.timetable_arrival_departure"));
 			interface->Add(new SettingEntry("gui.expenses_layout"));
+			interface->Add(new SettingEntry("gui.powerfund_money"));
+			interface->Add(new SettingEntry("gui.powerfund_houses"));
 		}
 
 		SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS));
@@ -1560,6 +1583,7 @@
 			advisors->Add(new SettingEntry("gui.order_review_system"));
 			advisors->Add(new SettingEntry("gui.vehicle_income_warn"));
 			advisors->Add(new SettingEntry("gui.lost_vehicle_warn"));
+			advisors->Add(new SettingEntry("gui.runway_too_short_warn"));
 			advisors->Add(new SettingEntry("gui.show_finances"));
 			advisors->Add(new SettingEntry("news_display.economy"));
 			advisors->Add(new SettingEntry("news_display.subsidies"));
@@ -1602,6 +1626,26 @@
 
 		SettingsPage *vehicles = main->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES));
 		{
+			/** Vehicle control page */
+			SettingsPage *veh_control = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_CTRL));
+			{
+				veh_control->Add(new SettingEntry("gui.enable_ctrl_click_start_stop"));
+				veh_control->Add(new SettingEntry("gui.new_nonstop"));
+				veh_control->Add(new SettingEntry("gui.auto_noload_on_transfer"));
+				veh_control->Add(new SettingEntry("gui.auto_noload_on_unloadall"));
+			}
+
+			/** Order Shorcuts page */
+			SettingsPage *orders = veh_control->Add(new SettingsPage(STR_CONFIG_SETTING_ORDER_SHORTCUTS));
+			{
+				orders->Add(new SettingEntry("gui.goto_shortcuts_ctrl_lclick"));
+				orders->Add(new SettingEntry("gui.goto_shortcuts_shift_lclick"));
+				orders->Add(new SettingEntry("gui.goto_shortcuts_ctrlshift_lclick"));
+				orders->Add(new SettingEntry("gui.goto_shortcuts_alt_lclick"));
+				orders->Add(new SettingEntry("gui.goto_shortcuts_altshift_lclick"));
+				orders->Add(new SettingEntry("gui.goto_shortcuts_altctrl_lclick"));
+			}
+
 			SettingsPage *physics = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_PHYSICS));
 			{
 				physics->Add(new SettingEntry("vehicle.train_acceleration_model"));
diff -r e16bdc0054ce src/settings_type.h
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -79,6 +79,15 @@
 	bool   vehicle_income_warn;              ///< if a vehicle isn't generating income, show a warning
 	bool   show_finances;                    ///< show finances at end of year
 	bool   sg_new_nonstop;                   ///< ttdpatch compatible nonstop handling read from pre v93 savegames
+	bool   enable_ctrl_click_start_stop;     ///< allow ctrl+click to start or stop vehicles
+	uint8  goto_shortcuts_ctrl_lclick;       ///< goto action shortcut CTRL+LEFT-CLICK
+	uint8  goto_shortcuts_shift_lclick;      ///< goto action shortcut SHIFT+LEFT-CLICK
+	uint8  goto_shortcuts_ctrlshift_lclick;  ///< goto action shortcut CTRL+SHIFT+LEFT-CLICK
+	uint8  goto_shortcuts_alt_lclick;        ///< goto action shortcut ALT+LEFT-CLICK
+	uint8  goto_shortcuts_altshift_lclick;   ///< goto action shortcut ALT+SHIFT+LEFT-CLICK
+	uint8  goto_shortcuts_altctrl_lclick;    ///< goto action shortcut ALT+CTRL+LEFT-CLICK
+	bool   auto_noload_on_transfer;          ///< automatically set no-loading when ordering to transfer all cargo
+	bool   auto_noload_on_unloadall;         ///< automatically set no-loading when ordering to unload all cargo
 	bool   new_nonstop;                      ///< ttdpatch compatible nonstop handling
 	uint8  stop_location;                    ///< what is the default stop location of trains?
 	uint8  auto_scrolling;                   ///< scroll when moving mouse to the edge (see #ViewportAutoscrolling)
@@ -158,6 +167,16 @@
 	bool   newgrf_show_old_versions;         ///< whether to show old versions in the NewGRF list
 	uint8  newgrf_default_palette;           ///< default palette to use for NewGRFs without action 14 palette information
 
+	bool   old_depot_train_length_calc;      ///< display vehicle length in whole numbers - old style
+	uint8  cb_distance_check;                ///< zoning cb distance
+	bool   enable_extra_tooltips;            ///< enable extra tooltips when hovering over various elements
+	bool   polyrail_double_click;            ///< finish polyrail with mouse double click
+	bool   show_industry_forbidden_tiles;    ///< higlight areas where industry placement is forbidden regardless of terrain
+	bool   runway_too_short_warn;            ///< warn about aircrafts using too short runways
+
+	uint32 powerfund_money;                  ///< minimum amount of money for powerfund to work
+	uint16 powerfund_houses;                 ///< powerfunding maximum houses limit
+
 	/**
 	 * Returns true when the user has sufficient privileges to edit newgrfs on a running game
 	 * @return whether the user has sufficient privileges to edit newgrfs in an existing game
diff -r e16bdc0054ce src/smallmap_gui.cpp
--- a/src/smallmap_gui.cpp
+++ b/src/smallmap_gui.cpp
@@ -896,7 +896,7 @@
 				y < dpi->top + dpi->height) {
 			/* And draw it. */
 			SetDParam(0, t->index);
-			DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN);
+			DrawString(x, x + t->cache.sign.width_small, y, t->larger_town ? STR_SMALLMAP_TOWN_LARGE : STR_SMALLMAP_TOWN);
 		}
 	}
 }
diff -r e16bdc0054ce src/station.cpp
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -19,6 +19,7 @@
 #include "news_func.h"
 #include "aircraft.h"
 #include "vehiclelist.h"
+#include "town.h"
 #include "core/pool_func.hpp"
 #include "station_base.h"
 #include "roadstop_base.h"
@@ -75,6 +76,15 @@
  */
 Station::~Station()
 {
+	Town *t;
+	FOR_ALL_TOWNS(t) {
+		// Using poiter comparison instead of cycling cargos
+		if (t->ad_ref_goods_entry >= this->goods &&
+		 	   t->ad_ref_goods_entry < this->goods + NUM_CARGO) {
+		    t->ad_ref_goods_entry = NULL;
+		}
+	}
+
 	if (CleaningPool()) {
 		for (CargoID c = 0; c < NUM_CARGO; c++) {
 			this->goods[c].cargo.OnCleanPool();
diff -r e16bdc0054ce src/station_gui.cpp
--- a/src/station_gui.cpp
+++ b/src/station_gui.cpp
@@ -1282,6 +1282,7 @@
 
 	int scroll_to_row;                  ///< If set, scroll the main viewport to the station pointed to by this row.
 	int grouping_index;                 ///< Currently selected entry in the grouping drop down.
+	int ratings_list_y = 0;             ///< Y coordinate of first line in station ratings panel.
 	Mode current_mode;                  ///< Currently selected display mode of cargo view.
 	Grouping groupings[NUM_COLUMNS];    ///< Grouping modes for the different columns.
 
@@ -1813,7 +1814,7 @@
 	 * @param r Rectangle of the widget.
 	 * @return Number of lines needed for drawing the cargo ratings.
 	 */
-	int DrawCargoRatings(const Rect &r) const
+	int DrawCargoRatings(const Rect &r)
 	{
 		const Station *st = Station::Get(this->window_number);
 		int y = r.top + WD_FRAMERECT_TOP;
@@ -1827,6 +1828,7 @@
 		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
 		y += FONT_HEIGHT_NORMAL;
 
+		this->ratings_list_y = y;
 		const CargoSpec *cs;
 		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
 			const GoodsEntry *ge = &st->goods[cs->Index()];
@@ -2060,6 +2062,28 @@
 		this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
 	}
 
+	virtual void OnHover(Point pt, int widget)
+	{
+		if (widget != WID_SV_ACCEPT_RATING_LIST ||
+		    	this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON)
+			Window::OnHover(pt, widget);
+
+		int ofs_y = pt.y - this->ratings_list_y;
+		if (ofs_y < 0) return;
+
+		const Station *st = Station::Get(this->window_number);
+		const CargoSpec *cs;
+		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+			const GoodsEntry *ge = &st->goods[cs->Index()];
+			if (!ge->HasRating()) continue;
+			ofs_y -= FONT_HEIGHT_NORMAL;
+			if (ofs_y < 0) {
+				GuiShowStationRatingTooltip(this, st, cs);
+				break;
+			}
+		}
+	}
+
 	/**
 	 * Some data on this window has become invalid. Invalidate the cache for the given cargo if necessary.
 	 * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo data.
@@ -2234,16 +2258,17 @@
  * @tparam T The type of station to join with
  */
 template <class T>
-struct SelectStationWindow : Window {
+struct SelectStationWindow : WindowPopup {
 	CommandContainer select_station_cmd; ///< Command to build new station
 	TileArea area; ///< Location of new station
 	Scrollbar *vscroll;
 
 	SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
-		Window(desc),
+		WindowPopup(desc, WPUT_WIDGET_RELATIVE),
 		select_station_cmd(cmd),
 		area(ta)
 	{
+		this->wpu_widget = WID_JS_PANEL;
 		this->CreateNestedTree();
 		this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
 		this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
diff -r e16bdc0054ce src/table/settings.ini
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -3936,5 +3936,172 @@
 strval   = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND
 cat      = SC_BASIC
 
+; //MODGUI *********************************
+[SDTC_BOOL]
+var      = gui.enable_ctrl_click_start_stop
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = true
+str      = STR_CONFIG_SETTING_CTRL_ENABLE_CTRLCLICK_STARTSTOP
+
+[SDTC_BOOL]
+var      = gui.auto_noload_on_transfer
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = true
+str      = STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_TRANSFER
+
+[SDTC_BOOL]
+var      = gui.auto_noload_on_unloadall
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = false
+str      = STR_CONFIG_SETTING_AUTOSET_NOLOAD_ON_UNLOAD
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_ctrl_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 1
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLLCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_shift_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_SHIFTLCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_ctrlshift_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLSHIFTLCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_alt_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTLCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_altshift_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_ALTSHIFTCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_VAR]
+var      = gui.goto_shortcuts_altctrl_lclick
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 6
+interval = 1
+str      = STR_CONFIG_SETTING_CTRL_GOTOSHORTCUT_CTRLALTLCLICK
+strval   = STR_CONFIG_SETTING_CTRL_GOTOSHORTOPTS_NONE
+proc     = RedrawScreen
+cat      = SC_BASIC
+
+[SDTC_BOOL]
+var      = gui.old_depot_train_length_calc
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = true
+str      = STR_OLD_DEPOT_TRAINT_LENGTH
+
+[SDTC_VAR]
+var      = gui.cb_distance_check
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = 25
+min      = 0
+max      = 100
+interval = 5
+str      = STR_CB_DISTANCE_CHECK
+strval   = STR_JUST_COMMA
+proc     = RedrawScreen
+
+[SDTC_BOOL]
+var      = gui.enable_extra_tooltips
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = true
+str      = STR_CONFIG_SETTING_ENABLE_EXTRA_TOOLTIPS
+
+[SDTC_BOOL]
+var      = gui.polyrail_double_click
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = false
+str      = STR_CONFIG_SETTING_POLYRAIL_DOUBLECLICK_TOOLTIPS
+
+[SDTC_BOOL]
+var      = gui.show_industry_forbidden_tiles
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = false
+cat      = SC_BASIC
+
+[SDTC_BOOL]
+var      = gui.runway_too_short_warn
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = true
+str      = STR_CONFIG_SETTING_WARN_IF_RUNWAY_IS_TOO_SHORT
+
+[SDTC_VAR]
+var      = gui.powerfund_money
+type     = SLE_UINT
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_CURRENCY
+def      = 200000
+min      = 0
+max      = 2000000
+str      = STR_CONFIG_SETTING_POWERFUND_MONEY
+strval   = STR_JUST_CURRENCY_LONG
+
+[SDTC_VAR]
+var      = gui.powerfund_houses
+type     = SLE_UINT16
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def      = 10000
+min      = 0
+max      = 10000
+interval = 10
+str      = STR_CONFIG_SETTING_POWERFUND_HOUSES
+strval   = STR_JUST_COMMA
+
 [SDT_END]
 
diff -r e16bdc0054ce src/table/sprites.h
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -296,8 +296,22 @@
 static const SpriteID SPR_PALETTE_BASE = SPR_EMPTY_BOUNDING_BOX + EMPTY_BOUNDING_BOX_SPRITE_COUNT;
 static const uint16 PALETTE_SPRITE_COUNT = 1;
 
+/* zoning stuff */
+static const SpriteID SPR_INNER_HIGHLIGHT_BASE      = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT;
+static const SpriteID SPR_IMG_COMPANY_CARGO         = SPR_INNER_HIGHLIGHT_BASE + 19;
+static const SpriteID SPR_IMG_COMPANY_GOAL          = SPR_INNER_HIGHLIGHT_BASE + 20;
+static const SpriteID SPR_PALETTE_ZONING_RED        = SPR_INNER_HIGHLIGHT_BASE + 21;
+static const SpriteID SPR_PALETTE_ZONING_GREEN      = SPR_INNER_HIGHLIGHT_BASE + 22;
+static const SpriteID SPR_PALETTE_ZONING_BLACK      = SPR_INNER_HIGHLIGHT_BASE + 23;
+static const SpriteID SPR_PALETTE_ZONING_LIGHT_BLUE = SPR_INNER_HIGHLIGHT_BASE + 24;
+static const SpriteID SPR_PALETTE_ZONING_ORANGE     = SPR_INNER_HIGHLIGHT_BASE + 25;
+static const SpriteID SPR_PALETTE_ZONING_WHITE      = SPR_INNER_HIGHLIGHT_BASE + 26;
+static const SpriteID SPR_PALETTE_ZONING_YELLOW     = SPR_INNER_HIGHLIGHT_BASE + 27;
+static const SpriteID SPR_PALETTE_ZONING_PURPLE     = SPR_INNER_HIGHLIGHT_BASE + 28;
+static const SpriteID SPR_INNER_HIGHLIGHT_COUNT     = 29;
+
 /* From where can we start putting NewGRFs? */
-static const SpriteID SPR_NEWGRFS_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT;
+static const SpriteID SPR_NEWGRFS_BASE = SPR_INNER_HIGHLIGHT_BASE + SPR_INNER_HIGHLIGHT_COUNT;
 
 /* Manager face sprites */
 static const SpriteID SPR_GRADIENT = 874; // background gradient behind manager face
diff -r e16bdc0054ce src/tile_cmd.h
--- a/src/tile_cmd.h
+++ b/src/tile_cmd.h
@@ -64,6 +64,7 @@
 	uint64 dparam[2];           ///< Parameters of the \a str string
 	uint16 rail_speed;          ///< Speed limit of rail (bridges and track)
 	uint16 road_speed;          ///< Speed limit of road (bridges)
+	uint16 population;
 };
 
 /**
diff -r e16bdc0054ce src/tilehighlight_func.h
--- a/src/tilehighlight_func.h
+++ b/src/tilehighlight_func.h
@@ -14,6 +14,8 @@
 
 #include "gfx_type.h"
 #include "tilehighlight_type.h"
+#include "track_type.h"
+#include "industry_type.h"
 
 void PlaceProc_DemolishArea(TileIndex tile);
 bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile);
@@ -30,6 +32,12 @@
 
 void UpdateTileSelection();
 
+void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional = true);
+void ResetRailPlacementSnapping();
+bool CurrentlySnappingRailPlacement();
+
+void SetIndustryForbiddenTilesHighlight(IndustryType type);
+
 extern TileHighlightData _thd;
 
 #endif /* TILEHIGHLIGHT_FUNC_H */
diff -r e16bdc0054ce src/tilehighlight_type.h
--- a/src/tilehighlight_type.h
+++ b/src/tilehighlight_type.h
@@ -28,6 +28,8 @@
 	HT_RAIL      = 0x080, ///< autorail (one piece), lower bits: direction
 	HT_VEHICLE   = 0x100, ///< vehicle is accepted as target as well (bitmask)
 	HT_DIAGONAL  = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT.
+	HT_POLY      = 0x400, ///< polyline mode; connect highlighted track with previous one
+	HT_NEW_POLY  = 0xC00, ///< start completly new polyline; implies #HT_POLY
 	HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes.
 
 	/* lower bits (used with HT_LINE and HT_RAIL):
@@ -54,11 +56,15 @@
 
 	Point new_pos;       ///< New value for \a pos; used to determine whether to redraw the selection.
 	Point new_size;      ///< New value for \a size; used to determine whether to redraw the selection.
+	Point new_offs;      ///< New value for \a offs; used to determine whether to redraw the selection.
 	Point new_outersize; ///< New value for \a outersize; used to determine whether to redraw the selection.
 	byte dirty;          ///< Whether the build station window needs to redraw due to the changed selection.
 
 	Point selstart;      ///< The location where the dragging started.
 	Point selend;        ///< The location where the drag currently ends.
+	Point selstart2;     ///< The location where the second segment of a polyline track starts.
+	Point selend2;       ///< The location where the second segment of a polyline track ends.
+	HighLightStyle dir2; ///< Direction of the second segment of a polyline track, HT_DIR_END if second segment is not selected. HT_LINE drawstyle.
 	byte sizelimit;      ///< Whether the selection is limited in length, and what the maximum length is.
 
 	HighLightStyle drawstyle;      ///< Lower bits 0-3 are reserved for detailed highlight information.
diff -r e16bdc0054ce src/toolbar_gui.cpp
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -53,6 +53,10 @@
 #include "network/network.h"
 #include "network/network_gui.h"
 #include "network/network_func.h"
+#include "cargo_table_gui.h"
+#include "object_type.h"
+#include "zoning.h"
+#include "watch_gui.h"
 
 #include "safeguards.h"
 
@@ -77,11 +81,12 @@
 	CBF_NONE,
 	CBF_PLACE_SIGN,
 	CBF_PLACE_LANDINFO,
+	CBF_BUILD_HQ,
 };
 
 /**
  * Drop down list entry for showing a checked/unchecked toggle item.
- */
+ */ /*
 class DropDownListCheckedItem : public DropDownListStringItem {
 	uint checkmark_width;
 public:
@@ -107,19 +112,28 @@
 		}
 		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK);
 	}
-};
+};*/
 
 /**
  * Drop down list entry for showing a company entry, with companies 'blob'.
  */
 class DropDownListCompanyItem : public DropDownListItem {
 	Dimension icon_size;
+	Dimension lock_icon_size;
+	uint line_height;
 public:
 	bool greyed;
 
 	DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
 	{
 		this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
+		if (_networking) {
+			this->lock_icon_size = GetSpriteSize(SPR_LOCK);
+			this->line_height = max(this->lock_icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
+		} else {
+			this->lock_icon_size.width = 0;
+			this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
+		}
 	}
 
 	virtual ~DropDownListCompanyItem() {}
@@ -134,12 +148,12 @@
 		CompanyID company = (CompanyID)this->result;
 		SetDParam(0, company);
 		SetDParam(1, company);
-		return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3;
+		return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + this->lock_icon_size.width + 3;
 	}
 
 	uint Height(uint width) const
 	{
-		return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
+		return this->line_height;
 	}
 
 	void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
@@ -152,8 +166,13 @@
 
 		int icon_offset = (bottom - top - icon_size.height) / 2;
 		int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
+		int lock_icon_offset = (bottom - top - this->lock_icon_size.height) / 2;
 
 		DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
+		int text_x_ofs = WD_FRAMERECT_LEFT + this->icon_size.width + this->lock_icon_size.width;
+		if (_networking && NetworkCompanyIsPassworded(company)){
+			DrawSprite(SPR_LOCK, PAL_NONE, rtl ? right - this->icon_size.width - this->lock_icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT + this->icon_size.width + WD_FRAMERECT_LEFT, top + lock_icon_offset);
+		}
 
 		SetDParam(0, company);
 		SetDParam(1, company);
@@ -163,7 +182,7 @@
 		} else {
 			col = sel ? TC_WHITE : TC_BLACK;
 		}
-		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col);
+		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : text_x_ofs), right - WD_FRAMERECT_RIGHT - (rtl ? text_x_ofs : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col);
 	}
 };
 
@@ -256,6 +275,18 @@
 	}
 }
 
+/* hq hotkey */
+static CallBackFunction BuildCompanyHQ(){
+	if (_cursor.sprite == SPR_CURSOR_HQ) {
+		ResetObjectToPlace();
+		return CBF_NONE;
+	} else {
+		SetObjectToPlace(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
+		SetTileSelectSize(2, 2);
+		return CBF_BUILD_HQ;
+	}
+}
+
 /* --- Pausing --- */
 
 static CallBackFunction ToolbarPauseClick(Window *w)
@@ -289,6 +320,7 @@
 	OME_SETTINGS,
 	OME_SCRIPT_SETTINGS,
 	OME_NEWGRFSETTINGS,
+	OME_ZONING,
 	OME_TRANSPARENCIES,
 	OME_SHOW_TOWNNAMES,
 	OME_SHOW_STATIONNAMES,
@@ -317,6 +349,7 @@
 	 * to network clients. */
 	if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false);
 	*list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS,          OME_NEWGRFSETTINGS, false);
+	*list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_ZONING,                   OME_ZONING, false);
 	*list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS,     OME_TRANSPARENCIES, false);
 	*list->Append() = new DropDownListItem(-1, false);
 	*list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED,    OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES));
@@ -347,6 +380,7 @@
 		case OME_SETTINGS:             ShowGameSettings();                              return CBF_NONE;
 		case OME_SCRIPT_SETTINGS:      ShowAIConfigWindow();                            return CBF_NONE;
 		case OME_NEWGRFSETTINGS:       ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
+		case OME_ZONING:               ShowZoningToolbar();                             break;
 		case OME_TRANSPARENCIES:       ShowTransparencyToolbar();                       break;
 
 		case OME_SHOW_TOWNNAMES:       ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES);     break;
@@ -582,6 +616,37 @@
 	return CBF_NONE;
 }
 
+/* --- CARGOS button menu --- */
+
+static CallBackFunction ToolbarCargosClick(Window *w)
+{
+	PopupMainCompanyToolbMenu(w, WID_TN_CARGOS);
+	return CBF_NONE;
+}
+
+static CallBackFunction MenuClickCargos(int index)
+{
+	ShowCompanyCargos((CompanyID)index);
+	return CBF_NONE;
+}
+
+/* --- WATCH button menu --- */
+
+static CallBackFunction ToolbarWatchClick(Window *w)
+{
+	PopupMainCompanyToolbMenu(w, WID_TN_WATCH);
+	return CBF_NONE;
+}
+
+static CallBackFunction MenuClickWatch(int index)
+{
+	if(Company::IsValidID((CompanyID)index)){
+		ShowWatchWindow((CompanyID)index, 0);
+	}
+	else ShowWatchWindow(INVALID_COMPANY, 0);
+	return CBF_NONE;
+}
+
 /* --- Company's button menu --- */
 
 static CallBackFunction ToolbarCompaniesClick(Window *w)
@@ -727,7 +792,7 @@
 static CallBackFunction ToolbarIndustryClick(Window *w)
 {
 	/* Disable build-industry menu if we are a spectator */
-	PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
+	PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, 3);
 	return CBF_NONE;
 }
 
@@ -1042,7 +1107,7 @@
 
 static CallBackFunction ToolbarHelpClick(Window *w)
 {
-	PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9);
+	PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 13 : 9);
 	return CBF_NONE;
 }
 
@@ -1137,7 +1202,13 @@
 static CallBackFunction MenuClickHelp(int index)
 {
 	switch (index) {
-		case  0: return PlaceLandBlockInfo();
+		case 0: return PlaceLandBlockInfo();
+		case 1:
+			extern bool _novahost;
+			if (_networking && _novahost){
+				ShowCommandsToolbar();
+			}
+			break;
 		case  2: IConsoleSwitch();                 break;
 		case  3: ShowAIDebugWindow();              break;
 		case  4: MenuClickSmallScreenshot();       break;
@@ -1148,6 +1219,7 @@
 		case  9: ShowSpriteAlignerWindow();        break;
 		case 10: ToggleBoundingBoxes();            break;
 		case 11: ToggleDirtyBlocks();              break;
+		case 12: ShowLoginWindow();                break;
 	}
 	return CBF_NONE;
 }
@@ -1281,9 +1353,11 @@
 	MenuClickSubsidies,   // 6
 	MenuClickStations,    // 7
 	MenuClickFinances,    // 8
+	MenuClickCargos,      // 8.5
 	MenuClickCompany,     // 9
 	MenuClickStory,       // 10
 	MenuClickGoal,        // 11
+	MenuClickWatch,       // 11.5
 	MenuClickGraphs,      // 12
 	MenuClickLeague,      // 13
 	MenuClickIndustry,    // 14
@@ -1495,7 +1569,7 @@
 			0,  1,  3,  4,  7,  8,  9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29,
 		};
 		static const byte arrange_all[] = {
-			0, 1, 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
+			0, 1, 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
 		};
 
 		/* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
@@ -1537,14 +1611,14 @@
 	/* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
 	{
 		static const byte arrange_all[] = {
-			0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
+			0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 28, 30,
 		};
 		static const byte arrange_nopanel[] = {
-			0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
+			0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 28, 30,
 		};
 		static const byte arrange_switch[] = {
-			18,  8, 11, 12, 13, 14, 15, 16, 17, 29,
-			 0,  1,  2,  3, 18,  9, 10, 26, 28, 29,
+			18,  8, 11, 12, 13, 14, 15, 16, 17, 31,
+			 0,  1,  2,  3, 18,  9, 10, 28, 30, 31,
 		};
 
 		/* If we can place all buttons *and* the panels, show them. */
@@ -1590,9 +1664,11 @@
 	ToolbarSubsidiesClick,
 	ToolbarStationsClick,
 	ToolbarFinancesClick,
+	ToolbarCargosClick,
 	ToolbarCompaniesClick,
 	ToolbarStoryClick,
 	ToolbarGoalClick,
+	ToolbarWatchClick,
 	ToolbarGraphsClick,
 	ToolbarLeagueClick,
 	ToolbarIndustryClick,
@@ -1652,6 +1728,15 @@
 	MTHK_EXTRA_VIEWPORT,
 	MTHK_CLIENT_LIST,
 	MTHK_SIGN_LIST,
+	MTHK_BUILD_HQ,
+	MTHK_COMMANDS_GUI,
+	MTHK_CARGOTABLE,
+	MTHK_TREES,
+	MTHK_ZONING,
+	MTHK_LOGINWINDOW,
+	MTHK_SETTINGS_ADV,
+	MTHK_NEWGRF,
+	MTHK_LANDINFO,
 };
 
 /** Main toolbar. */
@@ -1682,7 +1767,7 @@
 		 * Since enabled state is the default, just disable when needed */
 		this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END);
 		/* disable company list drop downs, if there are no companies */
-		this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END);
+		this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_CARGOS, WID_TN_WATCH, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END);
 
 		this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
 		this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
@@ -1693,6 +1778,14 @@
 		this->DrawWidgets();
 	}
 
+	virtual void DrawWidget(const Rect &r, int widget) const {
+		if (widget == WID_TN_WATCH) {
+			Dimension d = GetSpriteSize(SPR_CENTRE_VIEW_VEHICLE);
+			uint offset = this->IsWidgetLowered(WID_TN_WATCH) ? 1 : 0;
+			DrawSprite(SPR_CENTRE_VIEW_VEHICLE, PAL_NONE, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset);
+		}
+	}
+
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
 		if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
@@ -1740,18 +1833,45 @@
 			case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
 			case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
 			case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
-			case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
+			case MTHK_CHEATS: ShowCheatWindow(); break;
 			case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
 			case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
 #ifdef ENABLE_NETWORK
 			case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
+			case MTHK_COMMANDS_GUI: extern bool _novahost; if (_networking && _novahost){ ShowCommandsToolbar(); } break;
 #endif
+			case MTHK_BUILD_HQ: if(_current_company != COMPANY_SPECTATOR){ this->last_started_action = CBF_BUILD_HQ; BuildCompanyHQ(); } break;
+			case MTHK_CARGOTABLE: if(_current_company != COMPANY_SPECTATOR){ ShowCompanyCargos(_current_company); } break;
+			case MTHK_TREES: if(_current_company != COMPANY_SPECTATOR){ BuildTreesWindow(); } break;
 			case MTHK_SIGN_LIST: ShowSignList(); break;
+			case MTHK_ZONING: ShowZoningToolbar(); break;
+			case MTHK_LOGINWINDOW: ShowLoginWindow(); break;
+			case MTHK_SETTINGS_ADV: ShowGameSettings(); break;
+			case MTHK_NEWGRF: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); break;
+			case MTHK_LANDINFO: this->last_started_action = PlaceLandBlockInfo(); break;
 			default: return ES_NOT_HANDLED;
 		}
 		return ES_HANDLED;
 	}
 
+	virtual void BuildTreesWindow(){
+		ShowBuildTreesToolbar();
+		Window *w = FindWindowById(WC_BUILD_TREES, 0);
+		if(w != NULL){
+			if(w->IsWidgetLowered(WID_BT_TYPE_RANDOM)){
+				w->RaiseWidget(WID_BT_TYPE_RANDOM);
+				ResetObjectToPlace();
+			}
+			else{
+				w->OnHotkey(WID_BT_TYPE_RANDOM);
+			}
+
+		}
+		/*
+		if (!w->IsWidgetLowered(WID_BT_TYPE_RANDOM))
+			w->OnClick(Point(), WID_BT_TYPE_RANDOM, 1);*/
+	}
+
 	virtual void OnPlaceObject(Point pt, TileIndex tile)
 	{
 		switch (this->last_started_action) {
@@ -1760,13 +1880,25 @@
 				break;
 
 			case CBF_PLACE_LANDINFO:
-				ShowLandInfo(tile);
+				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_MEASURE);
+				break;
+
+			case CBF_BUILD_HQ:
+				if(DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))){
+					ResetObjectToPlace();
+					this->RaiseButtons();
+				}
 				break;
 
 			default: NOT_REACHED();
 		}
 	}
 
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
 	virtual void OnTick()
 	{
 		if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
@@ -1850,8 +1982,17 @@
 	Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
 #ifdef ENABLE_NETWORK
 	Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
+	Hotkey('N', "nova_commands", MTHK_COMMANDS_GUI),
+	Hotkey(WKC_CTRL | WKC_F2, "cargo_table", MTHK_CARGOTABLE),
 #endif
+	Hotkey(WKC_CTRL  | 'H', "build_hq", MTHK_BUILD_HQ),
+	Hotkey('I', "trees", MTHK_TREES),
+	Hotkey((uint16)0, "zoning", MTHK_ZONING),
+	Hotkey((uint16)0, "login_window", MTHK_LOGINWINDOW),
+	Hotkey((uint16)0, "settings_advanced", MTHK_SETTINGS_ADV),
+	Hotkey((uint16)0, "newgrf_window", MTHK_NEWGRF),
 	Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
+	Hotkey((uint16)0, "land_info", MTHK_LANDINFO),
 	HOTKEY_LIST_END
 };
 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
@@ -1869,9 +2010,11 @@
 		SPR_IMG_SUBSIDIES,       // WID_TN_SUBSIDIES
 		SPR_IMG_COMPANY_LIST,    // WID_TN_STATIONS
 		SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
+		SPR_IMG_COMPANY_CARGO,   // WID_TN_CARGOS
 		SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
 		SPR_IMG_STORY_BOOK,      // WID_TN_STORY
 		SPR_IMG_GOAL,            // WID_TN_GOAL
+		0,                       // WID_TN_WATCH
 		SPR_IMG_GRAPHS,          // WID_TN_GRAPHS
 		SPR_IMG_COMPANY_LEAGUE,  // WID_TN_LEAGUE
 		SPR_IMG_INDUSTRY,        // WID_TN_INDUSTRIES
@@ -1895,7 +2038,7 @@
 	NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
 	for (uint i = 0; i < WID_TN_END; i++) {
 		switch (i) {
-			case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break;
+			case 4: case 8: case 17: case 21: case 23: case 28: hor->Add(new NWidgetSpacer(0, 0)); break;
 		}
 		hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i));
 	}
@@ -2096,7 +2239,7 @@
 				break;
 
 			case CBF_PLACE_LANDINFO:
-				ShowLandInfo(tile);
+				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_MEASURE);
 				break;
 
 			default: NOT_REACHED();
diff -r e16bdc0054ce src/town.h
--- a/src/town.h
+++ b/src/town.h
@@ -15,10 +15,15 @@
 #include "viewport_type.h"
 #include "town_map.h"
 #include "subsidy_type.h"
+#include "station_base.h"
+#include "openttd.h"
+#include "table/strings.h"
+#include "company_func.h"
 #include "newgrf_storage.h"
 #include "cargotype.h"
 #include "tilematrix_type.hpp"
 #include <list>
+#include <map>
 
 template <typename T>
 struct BuildingCounts {
@@ -45,6 +50,7 @@
 struct TownCache {
 	uint32 num_houses;                        ///< Amount of houses
 	uint32 population;                        ///< Current population of people
+	uint32 potential_pop;                     ///< Potential population (if all houses are finished)
 	ViewportSign sign;                        ///< Location of name sign, UpdateVirtCoord updates this
 	PartOfSubsidyByte part_of_subsidy;        ///< Is this town a source/destination of a subsidy?
 	uint32 squared_town_zone_radius[HZB_END]; ///< UpdateTownRadius updates this given the house count
@@ -80,6 +86,32 @@
 	TransportedCargoStat<uint16> received[NUM_TE];    ///< Cargo statistics about received cargotypes.
 	uint32 goal[NUM_TE];                              ///< Amount of cargo required for the town to grow.
 
+	StringID town_label;                ///< Label dependent on _local_company rating.
+	bool growing;                       //CB
+	/* amounts in storage */
+	int storage[NUM_CARGO];             //CB stored cargo
+	uint act_cargo[NUM_CARGO];          //CB delivered last month
+	uint new_act_cargo[NUM_CARGO];      //CB  delivered current month
+	bool delivered_enough[NUM_CARGO];   //CB
+	bool growing_by_chance;             ///< town growing due to 1/12 chance?
+	uint16 houses_skipped;              ///< number of failed house buildings with next counter reset
+	uint16 houses_skipped_prev;         ///< house_failures on start of previous month
+	uint16 houses_skipped_last_month;   ///< house_failures during last month
+	uint16 cycles_skipped;              ///< number of house building cycles skipped due to placement failure
+	uint16 cycles_skipped_prev;
+	uint16 cycles_skipped_last_month;
+	uint16 cb_houses_removed;            ///< houses removed by cb server (excluding ones when town is not growing)
+	uint16 cb_houses_removed_prev;       ///< houses removed by cb server on start of previous month
+	uint16 cb_houses_removed_last_month; ///< houses removed by cb server during last month
+	uint houses_construction;            ///< number of houses currently being built
+	uint houses_reconstruction;          ///< number of houses currently being rebuilt
+	uint houses_demolished;              ///< number of houses demolished this month
+	CompanyMask fund_regularly;          ///< funds buildings regularly when previous fund ends
+	CompanyMask do_powerfund;            ///< funds buildings when grow counter is maximal (results in fastest funding possible)
+	CompanyMask advertise_regularly;     ///< advertised regularly to keep stations rating on desired value
+	uint8 ad_rating_goal;                ///< value to keep rating at (for regular advertisement) (0..255)
+	const GoodsEntry *ad_ref_goods_entry;      ///< poiter to goods entry of some station, used to check rating for regular advertisement
+
 	char *text; ///< General text with additional information.
 
 	inline byte GetPercentTransported(CargoID cid) const { return this->supplied[cid].old_act * 256 / (this->supplied[cid].old_max + 1); }
@@ -113,6 +145,32 @@
 
 	void InitializeLayout(TownLayout layout);
 
+	void UpdateLabel();
+
+	/* Returns the correct town label, based on rating. */
+	//FORCEINLINE StringID Label() const{
+	StringID Label() const{
+		if (!_settings_client.gui.population_in_label)
+			return STR_VIEWPORT_TOWN;
+		if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) {
+			return STR_VIEWPORT_TOWN_POP_VERY_POOR_RATING + this->town_label;
+		}
+		else {
+			return STR_VIEWPORT_TOWN_POP;
+		}
+	}
+
+	/* Returns the correct town small label, based on rating. */
+	//FORCEINLINE StringID SmallLabel() const{
+	StringID SmallLabel() const{
+		if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) {
+			return STR_VIEWPORT_TOWN_TINY_VERY_POOR_RATING + this->town_label;
+		}
+		else {
+			return STR_VIEWPORT_TOWN_TINY_WHITE;
+		}
+	}
+
 	/**
 	 * Calculate the max town noise.
 	 * The value is counted using the population divided by the content of the
@@ -194,6 +252,36 @@
 bool GenerateTowns(TownLayout layout);
 const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect);
 
+bool CB_Enabled();
+void CB_SetCB(bool cb);
+uint CB_GetStorage();
+void CB_SetStorage(uint storage);
+void CB_SetRequirements(CargoID cargo, uint req, uint from, uint decay);
+void CB_ResetRequirements();
+uint CB_GetReq(CargoID cargo);
+uint CB_GetFrom(CargoID cargo);
+uint CB_GetDecay(CargoID cargo);
+int CB_GetTownReq(uint population, uint req, uint from, bool from_non_important, bool prev_month = false);
+uint CB_GetMaxTownStorage(Town *town, uint cargo);
+bool TownExecuteAction(const Town *town, uint action);
+
+enum TownGrowthTileState {
+	TGTS_NONE = 0,
+	TGTS_RH_REMOVED,
+	TGTS_NEW_HOUSE,
+	TGTS_RH_REBUILT,               // rebuilt and removed houses are also
+	TGTS_CB_HOUSE_REMOVED_NOGROW,  // new, so larger priority
+	TGTS_CYCLE_SKIPPED,
+	TGTS_HOUSE_SKIPPED,
+	TGTS_CB_HOUSE_REMOVED
+};
+
+typedef std::map<TileIndex, TownGrowthTileState> TownsGrowthTilesIndex;
+extern TownsGrowthTilesIndex _towns_growth_tiles_last_month;
+extern TownsGrowthTilesIndex _towns_growth_tiles;
+
+void UpdateTownGrowthTile(TileIndex tile, TownGrowthTileState state);
+void ResetTownsGrowthTiles();
 
 /** Town actions of a company. */
 enum TownActions {
diff -r e16bdc0054ce src/town_cmd.cpp
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -52,6 +52,18 @@
 
 #include "safeguards.h"
 
+bool _cb_enabled = false;
+uint _cb_storage = 0;
+uint CBREQ[NUM_CARGO] = {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};//CB
+uint CBFROM[NUM_CARGO] = {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};//CB
+uint CBDECAY[NUM_CARGO] = {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};//CB
+uint days_in_month[] = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//CB
+void CB_UpdateTownStorage(Town *t); //CB
+
+const Money NOVAPOLIS_COMPANY_MONEY_THRESHOLD = INT64_MAX >> 4;
+TownsGrowthTilesIndex _towns_growth_tiles_last_month;
+TownsGrowthTilesIndex _towns_growth_tiles;
+
 TownID _new_town_id;
 uint32 _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses.
 
@@ -162,6 +174,26 @@
 	return Town::Get(index);
 }
 
+ /**
+ * Updates the town label of the town after changes in rating. The colour scheme is:
+ * Red: Appalling and Very poor ratings.
+ * Orange: Poor and mediocre ratings.
+ * Yellow: Good rating.
+ * White: Very good rating (standard).
+ * Green: Excellent and outstanding ratings.
+ */
+void Town::UpdateLabel()
+{
+	if (!(_game_mode == GM_EDITOR) && (_local_company < MAX_COMPANIES)) {
+		int r = this->ratings[_local_company];
+		if     (r < RATING_VERYPOOR) this->town_label = 0; // Appalling and Very Poor, RED
+		else if(r < RATING_MEDIOCRE) this->town_label = 1; // Poor and Mediocre, ORANGE
+		else if(r < RATING_GOOD)     this->town_label = 2; // Good, YELLOW
+		else if(r < RATING_VERYGOOD) this->town_label = 3; // Very Good, WHITE
+		else                         this->town_label = 4; // Excellent and Outstanding, GREEN
+	}
+}
+
 /**
  * Get the cost for removing this house
  * @return the cost (inflation corrected etc)
@@ -373,6 +405,7 @@
  */
 void Town::UpdateVirtCoord()
 {
+	this->UpdateLabel();
 	Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
 	SetDParam(0, this->index);
 	SetDParam(1, this->cache.population);
@@ -381,6 +414,7 @@
 		STR_VIEWPORT_TOWN);
 
 	SetWindowDirty(WC_TOWN_VIEW, this->index);
+	SetWindowDirty(WC_CB_TOWN, this->index);
 }
 
 /** Update the virtual coords needed to draw the town sign for all towns. */
@@ -400,6 +434,8 @@
  */
 static void ChangePopulation(Town *t, int mod)
 {
+	// if(mod > 0 && t->houses_construction > 0) t->houses_construction--;
+
 	t->cache.population += mod;
 	InvalidateWindowData(WC_TOWN_VIEW, t->index); // Cargo requirements may appear/vanish for small populations
 	t->UpdateVirtCoord();
@@ -438,8 +474,13 @@
 	if (IsHouseCompleted(tile)) {
 		/* Now that construction is complete, we can add the population of the
 		 * building to the town. */
-		ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population);
+		HouseID house_id = GetHouseType(tile);
+		Town *town = Town::GetByTile(tile);
+		const HouseSpec *hs = HouseSpec::Get(house_id);
+		ChangePopulation(town, hs->population);
 		ResetHouseAge(tile);
+		if (hs->building_flags & BUILDING_HAS_1_TILE)
+			town->houses_construction--;
 	}
 	MarkTileDirtyByTile(tile);
 }
@@ -540,7 +581,13 @@
 		ClearTownHouse(t, tile);
 
 		/* Rebuild with another house? */
-		if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
+		if (GB(r, 24, 8) >= 12 && BuildTownHouse(t, tile)) {
+			t->houses_reconstruction++;
+			UpdateTownGrowthTile(tile, TGTS_RH_REBUILT);
+		} else {
+			t->houses_demolished++;
+			UpdateTownGrowthTile(tile, TGTS_RH_REMOVED);
+		}
 	}
 
 	cur_company.Restore();
@@ -568,6 +615,11 @@
 
 	ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags);
 	if (flags & DC_EXEC) {
+		if (_current_company == COMPANY_FIRST &&
+				Company::Get(_current_company)->money > NOVAPOLIS_COMPANY_MONEY_THRESHOLD) {
+			if (t->growing) t->cb_houses_removed++;
+			UpdateTownGrowthTile(tile, t->growing ? TGTS_CB_HOUSE_REMOVED: TGTS_CB_HOUSE_REMOVED_NOGROW);
+		}
 		ClearTownHouse(t, tile);
 	}
 
@@ -658,6 +710,7 @@
 	bool house_completed = IsHouseCompleted(tile);
 
 	td->str = hs->building_name;
+	td->population = hs->population;
 
 	uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), tile);
 	if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
@@ -777,19 +830,97 @@
 
 static bool GrowTown(Town *t);
 
+static void DoRegularFunding(Town *t)
+{
+	bool fund_regularly = HasBit(t->fund_regularly, _local_company);
+	bool do_powerfund = HasBit(t->do_powerfund, _local_company);
+
+	if (do_powerfund && (_settings_client.gui.powerfund_money > Company::Get(_local_company)->money ||
+		    _settings_client.gui.powerfund_houses < t->cache.num_houses)) {
+	    do_powerfund = false;
+	}
+
+	if (!fund_regularly && !do_powerfund)
+		return;
+
+	if (_local_company == COMPANY_SPECTATOR)
+		return;
+
+	if (CB_Enabled() && !t->growing)
+		return;
+
+	uint16 gr = (t->growth_rate & ~TOWN_GROW_RATE_CUSTOM);
+
+	// Funding with grow_counter == 1 doesn't speed up next house building,
+	// so trying to avoid it. This means no powerfunding with gr <= 1, and no
+	// regular funding with grow_counter == 1 unless gr is also 1
+	// (we need to fund anyway even if it doesn't speed up next house)
+	// And in case town is not growing ignore grow_counter and growth_rate
+	// completely (it will start growing once we fund it)
+	bool not_growing = !HasBit(t->flags, TOWN_IS_GROWING);
+	if ((fund_regularly && t->fund_buildings_months == 0 &&
+	    	((t->grow_counter > 0 && (t->grow_counter > 1 || gr == 1)) || not_growing)) ||
+		(do_powerfund && gr > 1 && (t->grow_counter == gr || not_growing))) {
+
+		CompanyByte old = _current_company;
+		_current_company = _local_company;
+		DoCommandP(t->xy, t->index, HK_FUND, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE);
+		_current_company = old;
+	}
+}
+
+static void DoRegularAdvertising(Town *t) {
+	if (!HasBit(t->advertise_regularly, _local_company))
+		return;
+
+	if (t->ad_ref_goods_entry == NULL) {
+		// Pick as ref station and cargo with min rating
+		const Station *st;
+		FOR_ALL_STATIONS(st) {
+			if (st->owner == _local_company && DistanceManhattan(t->xy, st->xy) <= 20) {
+				for (CargoID i = 0; i < NUM_CARGO; i++)
+					if (st->goods[i].HasRating() && (t->ad_ref_goods_entry == NULL ||
+					    	t->ad_ref_goods_entry->rating < st->goods[i].rating)) {
+						t->ad_ref_goods_entry = &st->goods[i];
+					}
+			}
+		}
+
+		if (t->ad_ref_goods_entry == NULL)
+			return;
+	}
+
+	if (t->ad_ref_goods_entry->rating >= t->ad_rating_goal)
+		return;
+
+    CompanyByte old = _current_company;
+    _current_company = _local_company;
+    DoCommandP(t->xy, t->index, HK_LADVERT, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE);
+    _current_company = old;
+}
+
 static void TownTickHandler(Town *t)
 {
 	if (HasBit(t->flags, TOWN_IS_GROWING)) {
 		int i = t->grow_counter - 1;
+		uint16 houses_prev = t->cache.num_houses;
 		if (i < 0) {
 			if (GrowTown(t)) {
 				i = t->growth_rate & (~TOWN_GROW_RATE_CUSTOM);
+				if (t->cache.num_houses <= houses_prev && (t->growing || !CB_Enabled())){
+					t->houses_skipped++;
+				}
 			} else {
+				if (t->growing || !CB_Enabled()){
+					t->cycles_skipped++;
+				}
 				i = 0;
 			}
 		}
 		t->grow_counter = i;
 	}
+	DoRegularFunding(t);
+	DoRegularAdvertising(t);
 }
 
 void OnTick_Town()
@@ -1346,11 +1477,12 @@
  * @param tile to inquiry
  * @return true if town expansion was possible
  */
-static bool GrowTownAtRoad(Town *t, TileIndex tile)
+static bool GrowTownAtRoad(Town *t, TileIndex start_tile, TileIndex &tile)
 {
 	/* Special case.
 	 * @see GrowTownInTile Check the else if
 	 */
+	tile = start_tile;
 	DiagDirection target_dir = DIAGDIR_END; // The direction in which we want to extend the town
 
 	assert(tile < MapSize());
@@ -1469,8 +1601,14 @@
 	const TileIndexDiffC *ptr;
 	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 		if (GetTownRoadBits(tile) != ROAD_NONE) {
-			bool success = GrowTownAtRoad(t, tile);
+			uint16 houses_prev = t->cache.num_houses;
+			TileIndex end_tile;
+			bool success = GrowTownAtRoad(t, tile, end_tile);
 			cur_company.Restore();
+			if (!success)
+				UpdateTownGrowthTile(end_tile, TGTS_CYCLE_SKIPPED);
+			else if (t->cache.num_houses <= houses_prev)
+				UpdateTownGrowthTile(end_tile, TGTS_HOUSE_SKIPPED);
 			return success;
 		}
 		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
@@ -1485,6 +1623,7 @@
 			if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) {
 				if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) {
 					DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
+					UpdateTownGrowthTile(tile, TGTS_HOUSE_SKIPPED);
 					cur_company.Restore();
 					return true;
 				}
@@ -1493,6 +1632,7 @@
 		}
 	}
 
+	UpdateTownGrowthTile(tile, TGTS_CYCLE_SKIPPED);
 	cur_company.Restore();
 	return false;
 }
@@ -1546,6 +1686,123 @@
 	t->supplied[CT_MAIL].old_max = t->cache.population >> 4;
 }
 
+//CB
+
+bool CB_Enabled(){
+	return _cb_enabled;
+}
+void CB_SetCB(bool cb){
+	_cb_enabled = cb;
+	if(!_cb_enabled){
+		CB_ResetRequirements();
+	}
+}
+
+uint CB_GetStorage() {
+	return _cb_storage;
+}
+
+void CB_SetStorage(uint storage){
+	_cb_storage = storage;
+}
+
+void CB_SetRequirements(CargoID cargo, uint req, uint from, uint decay){
+	CBREQ[cargo] = req;
+	CBFROM[cargo] = from;
+	CBDECAY[cargo] = decay;
+}
+void CB_ResetRequirements() {
+	for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++){
+		CB_SetRequirements(cargo, 0, 0, 0);
+	}
+}
+uint CB_GetReq(CargoID cargo){
+	return CBREQ[cargo];
+}
+uint CB_GetFrom(CargoID cargo){
+	return CBFROM[cargo];
+}
+uint CB_GetDecay(CargoID cargo){
+	return CBDECAY[cargo];
+}
+int CB_GetTownReq(uint population, uint req, uint from, bool from_non_important, bool prev_month)
+{
+	if (req > 0 && (population >= from || from_non_important)) {
+		uint leap = 0;
+		Month month = _cur_month;
+		if (!prev_month) month++;
+		if(month == 2){
+			if((_cur_year % 4 == 0 && _cur_year % 100 != 0) || _cur_year % 400 == 0) leap = 1;
+		}
+		uint days_this_month = days_in_month[month] + leap;
+		// x cargo for 1000 people
+		return population * req * days_this_month / 31000; // 31 days divide by 1000 (pop)
+	}
+	return 0;
+}
+uint CB_GetMaxTownStorage(uint32 population, uint req)
+{
+	return req > 0 ? (population * req * _cb_storage / 1000) : 0;
+}
+
+uint CB_GetMaxTownStorage(Town *town, uint cargo) {
+	return CBREQ[cargo] > 0 ? (town->cache.population * CBREQ[cargo] * _cb_storage / 1000) : 0;
+}
+
+void CB_UpdateTownStorage(Town *t)
+{
+	InvalidateWindowData(WC_CB_TOWN, t->index);
+	t->growing = true;
+	if (!HasBit(t->flags, TOWN_IS_GROWING)) { //dont grow if not funded or missing transportation
+		t->growing = false;
+	}
+	for (uint i = 0; i < NUM_CARGO ; i++) {
+		if(CBREQ[i] == 0) continue;
+
+		t->storage[i] += t->new_act_cargo[i]; // add accumulated last month
+		t->storage[i] -= CB_GetTownReq(t->cache.population, CBREQ[i], CBFROM[i], false, true); //subtract monthly req
+		t->storage[i] = min((int)CB_GetMaxTownStorage(t->cache.population, CBREQ[i]), t->storage[i]); //check max storage
+
+		if (t->storage[i] < 0) {
+			t->growing = false;
+			t->delivered_enough[i] = false;
+			t->storage[i] = 0;
+		}
+		else t->delivered_enough[i] = true;
+
+		if (CBDECAY[i] == 100 && t->storage[i] > 0) {
+			t->storage[i] = 0;
+		}
+		else {
+			t->storage[i] *= (100 - CBDECAY[i]);
+			t->storage[i] /= 100;
+		}
+		t->act_cargo[i] = t->new_act_cargo[i];
+		t->new_act_cargo[i] = 0;
+	}
+
+	if (_settings_game.game_creation.landscape == LT_TROPIC) {
+		if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->received[TE_FOOD].old_act <= 0 || t->received[TE_WATER].old_act <= 0) && t->cache.population > 60) {
+			t->growing = false;
+		}
+	}
+	else if (_settings_game.game_creation.landscape == LT_ARCTIC) {
+		if (TilePixelHeight(t->xy) >= GetSnowLine() && t->received[TE_FOOD].old_act <= 0 && t->cache.population > 90) {
+			t->growing = false;
+		}
+	}
+}
+//CB
+
+void UpdateTownGrowthTile(TileIndex tile, TownGrowthTileState state) {
+	_towns_growth_tiles[tile] = max(_towns_growth_tiles[tile], state);
+}
+
+void ResetTownsGrowthTiles() {
+	_towns_growth_tiles_last_month.clear();
+	_towns_growth_tiles.clear();
+}
+
 /**
  * Does the actual town creation.
  *
@@ -1581,6 +1838,23 @@
 	}
 
 	t->fund_buildings_months = 0;
+	//CB
+	t->growing = false;
+	for (uint i = 0; i < NUM_CARGO ; i++) {
+		t->storage[i] = 0;
+		t->act_cargo[i] = 0;
+		t->new_act_cargo[i] = 0;
+		t->delivered_enough[i] = false;
+	}
+	t->houses_construction = 0;
+	t->houses_reconstruction = 0;
+	t->houses_demolished = 0;
+	t->fund_regularly = 0;
+	t->do_powerfund = 0;
+	t->advertise_regularly = 0;
+	t->ad_rating_goal = 95;
+	t->ad_ref_goods_entry = NULL;
+	//CB
 
 	for (uint i = 0; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
 
@@ -1601,6 +1875,7 @@
 	}
 	t->townnameparts = townnameparts;
 
+	t->town_label = 3;
 	t->UpdateVirtCoord();
 	InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
 
@@ -2365,6 +2640,8 @@
 
 		/* build the house */
 		t->cache.num_houses++;
+		t->cache.potential_pop += hs->population;
+		t->houses_construction++;
 
 		/* Special houses that there can be only one of. */
 		t->flags |= oneof;
@@ -2380,12 +2657,14 @@
 
 			if (construction_stage == TOWN_HOUSE_COMPLETED) {
 				ChangePopulation(t, hs->population);
+				t->houses_construction--;
 			} else {
 				construction_counter = GB(r, 2, 2);
 			}
 		}
 
 		MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
+		UpdateTownGrowthTile(tile, TGTS_NEW_HOUSE);
 		UpdateTownRadius(t);
 		UpdateTownCargoes(t, tile);
 
@@ -2452,9 +2731,12 @@
 	/* Remove population from the town if the house is finished. */
 	if (IsHouseCompleted(tile)) {
 		ChangePopulation(t, -hs->population);
+	} else {
+		t->houses_construction--;
 	}
 
 	t->cache.num_houses--;
+	t->cache.potential_pop -= hs->population;
 
 	/* Clear flags for houses that only may exist once/town. */
 	if (hs->building_flags & BUILDING_IS_CHURCH) {
@@ -2618,6 +2900,7 @@
 		}
 		UpdateTownGrowRate(t);
 		InvalidateWindowData(WC_TOWN_VIEW, p1);
+		InvalidateWindowData(WC_CB_TOWN, p1);
 	}
 
 	return CommandCost();
@@ -2908,6 +3191,7 @@
 		UpdateTownGrowRate(t);
 
 		SetWindowDirty(WC_TOWN_VIEW, t->index);
+		SetWindowDirty(WC_CB_TOWN, t->index);
 	}
 	return CommandCost();
 }
@@ -2964,6 +3248,7 @@
 			 */
 			if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) {
 				t->ratings[_current_company] = RATING_BRIBE_DOWN_TO;
+				t->UpdateVirtCoord();
 				SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
 			}
 		} else {
@@ -3096,13 +3381,16 @@
 		t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM);
 	}
 
+	t->UpdateVirtCoord();
 	SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
 }
 
 static void UpdateTownGrowRate(Town *t)
 {
 	ClrBit(t->flags, TOWN_IS_GROWING);
+	t->growing_by_chance = false;
 	SetWindowDirty(WC_TOWN_VIEW, t->index);
+	SetWindowDirty(WC_CB_TOWN, t->index);
 
 	if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return;
 
@@ -3126,6 +3414,7 @@
 	if ((t->growth_rate & TOWN_GROW_RATE_CUSTOM) != 0) {
 		if (t->growth_rate != TOWN_GROW_RATE_CUSTOM_NONE) SetBit(t->flags, TOWN_IS_GROWING);
 		SetWindowDirty(WC_TOWN_VIEW, t->index);
+		SetWindowDirty(WC_CB_TOWN, t->index);
 		return;
 	}
 
@@ -3156,6 +3445,7 @@
 	} else {
 		m = _grow_count_values[1][min(n, 5)];
 		if (n == 0 && !Chance16(1, 12)) return;
+		if (n == 0) t->growing_by_chance = true;
 	}
 
 	/* Use the normal growth rate values if new buildings have been funded in
@@ -3170,6 +3460,7 @@
 
 	SetBit(t->flags, TOWN_IS_GROWING);
 	SetWindowDirty(WC_TOWN_VIEW, t->index);
+	SetWindowDirty(WC_CB_TOWN, t->index);
 }
 
 static void UpdateTownAmounts(Town *t)
@@ -3179,6 +3470,7 @@
 	if (t->fund_buildings_months != 0) t->fund_buildings_months--;
 
 	SetWindowDirty(WC_TOWN_VIEW, t->index);
+	SetWindowDirty(WC_CB_TOWN, t->index);
 }
 
 static void UpdateTownUnwanted(Town *t)
@@ -3347,6 +3639,7 @@
 	} else {
 		SetBit(t->have_ratings, _current_company);
 		t->ratings[_current_company] = rating;
+		t->UpdateVirtCoord();
 		SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
 	}
 }
@@ -3392,6 +3685,9 @@
 {
 	Town *t;
 
+	_towns_growth_tiles_last_month = _towns_growth_tiles;
+	_towns_growth_tiles.clear();
+
 	FOR_ALL_TOWNS(t) {
 		if (t->road_build_months != 0) t->road_build_months--;
 
@@ -3399,11 +3695,24 @@
 			if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY;
 		}
 
+		if (CB_Enabled() && !t->larger_town) CB_UpdateTownStorage(t); //CB
+
 		UpdateTownAmounts(t);
 		UpdateTownRating(t);
 		UpdateTownGrowRate(t);
 		UpdateTownUnwanted(t);
 		UpdateTownCargoes(t);
+
+		DoRegularFunding(t);
+
+		t->houses_demolished = 0;
+		t->houses_reconstruction = 0;
+		t->houses_skipped_last_month = t->houses_skipped - t->houses_skipped_prev;
+		t->houses_skipped_prev = t->houses_skipped;
+		t->cycles_skipped_last_month = t->cycles_skipped - t->cycles_skipped_prev;
+		t->cycles_skipped_prev = t->cycles_skipped;
+		t->cb_houses_removed_last_month = t->cb_houses_removed - t->cb_houses_removed_prev;
+		t->cb_houses_removed_prev = t->cb_houses_removed;
 	}
 
 	UpdateTownCargoBitmap();
diff -r e16bdc0054ce src/town_gui.cpp
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -39,6 +39,24 @@
 
 #include "safeguards.h"
 
+#include "hotkeys.h"
+#include <list>
+#include "console_func.h"
+
+struct CargoX {
+	int id;
+	int from;
+};
+void ShowCBTownWindow(uint town);
+static void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line, bool show_house_states_info=false);
+
+bool TownExecuteAction(const Town *town, uint action){
+	if(!(action == HK_STATUE && HasBit(town->statues, _current_company))){ //don't built statue when there is one
+		return DoCommandP(town->xy, town->index, action, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS));
+	}
+	return false;
+}
+
 typedef GUIList<const Town*> GUITownList;
 
 static const NWidgetPart _nested_town_authority_widgets[] = {
@@ -165,11 +183,12 @@
 				(str++,                    true);                    // Outstanding
 
 				SetDParam(2, str);
+				SetDParam(3, this->town->ratings[c->index]);
 				if (this->town->exclusivity == c->index) {
 					DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset);
 				}
 
-				DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING);
+				DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING_NUM);
 				y += FONT_HEIGHT_NORMAL;
 			}
 		}
@@ -281,13 +300,32 @@
 	{
 		this->SetDirty();
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		TownExecuteAction(this->town, hotkey);
+		return ES_HANDLED;
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey town_hotkeys[] = {
+	Hotkey((uint16)0, "small_advert", HK_SADVERT),
+	Hotkey((uint16)0, "medium_advert", HK_MADVERT),
+	Hotkey(WKC_CTRL | 'D', "large_advert", HK_LADVERT),
+	Hotkey(WKC_CTRL | 'S', "build_statue", HK_STATUE),
+	Hotkey(WKC_CTRL | 'F', "fund_buildings", HK_FUND),
+	HOTKEY_LIST_END
+};
+HotkeyList TownAuthorityWindow::hotkeys("town_gui", town_hotkeys);
+
 static WindowDesc _town_authority_desc(
 	WDP_AUTO, "view_town_authority", 317, 222,
 	WC_TOWN_AUTHORITY, WC_NONE,
 	0,
-	_nested_town_authority_widgets, lengthof(_nested_town_authority_widgets)
+	_nested_town_authority_widgets, lengthof(_nested_town_authority_widgets),
+	&TownAuthorityWindow::hotkeys
 );
 
 static void ShowTownAuthorityWindow(uint town)
@@ -295,6 +333,9 @@
 	AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
 }
 
+static int TownTicksToDays(int ticks) {
+ 	return (ticks * TOWN_GROWTH_TICKS + DAY_TICKS / 2) / DAY_TICKS;
+}
 
 /* Town view window. */
 struct TownViewWindow : Window {
@@ -303,6 +344,7 @@
 
 public:
 	static const int WID_TV_HEIGHT_NORMAL = 150;
+	bool wcb_disable;
 
 	TownViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
 	{
@@ -319,11 +361,25 @@
 
 		/* disable renaming town in network games if you are not the server */
 		this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server);
+		// extern bool _novahost;
+		// this->wcb_disable = !_networking || !_novahost || this->town->larger_town || _game_mode == GM_EDITOR;
+		// this->SetWidgetDisabledState(WID_TV_CB, this->wcb_disable);
 	}
 
 	virtual void SetStringParameters(int widget) const
 	{
-		if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index);
+		if (widget == WID_TV_CAPTION){
+			SetDParam(0, this->town->index);
+		}
+		if (widget == WID_TV_CB){
+			// if(this->wcb_disable) SetDParam(0, STR_EMPTY);
+			// else
+			SetDParam(0, STR_BUTTON_CB_YES);
+		}
+	}
+
+	virtual void OnHundrethTick() {
+		this->SetDirty();
 	}
 
 	virtual void DrawWidget(const Rect &r, int widget) const
@@ -344,6 +400,8 @@
 		SetDParam(1, this->town->supplied[CT_MAIL].old_max);
 		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX);
 
+		DrawExtraTownInfo(r, y, this->town, FONT_HEIGHT_NORMAL, true); //CB
+
 		bool first = true;
 		for (int i = TE_BEGIN; i < TE_END; i++) {
 			if (this->town->goal[i] == 0) continue;
@@ -391,7 +449,7 @@
 		}
 
 		if (HasBit(this->town->flags, TOWN_IS_GROWING)) {
-			SetDParam(0, ((this->town->growth_rate & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS);
+			SetDParam(0, TownTicksToDays((this->town->growth_rate & ~TOWN_GROW_RATE_CUSTOM) + 1));
 			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED);
 		} else {
 			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_TOWN_GROW_STOPPED);
@@ -443,6 +501,11 @@
 				break;
 			}
 
+			case WID_TV_CB:
+				// if(_networking)
+				ShowCBTownWindow(this->window_number);
+				break;
+
 			case WID_TV_DELETE: // delete town - only available on Scenario editor
 				DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE));
 				break;
@@ -455,6 +518,9 @@
 			case WID_TV_INFO:
 				size->height = GetDesiredInfoHeight(size->width);
 				break;
+			// case WID_TV_CB:
+				// if(this->wcb_disable || !CB_Enabled()) size->width = 0;
+				// break;
 		}
 	}
 
@@ -464,7 +530,7 @@
 	 */
 	uint GetDesiredInfoHeight(int width) const
 	{
-		uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+		uint aimed_height = 8 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
 
 		bool first = true;
 		for (int i = TE_BEGIN; i < TE_END; i++) {
@@ -528,8 +594,29 @@
 
 		DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str);
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		if(hotkey == WID_TV_CB) ShowCBTownWindow(this->window_number);
+		else if (hotkey == HK_STATUE + 0x80){
+			TownExecuteAction(this->town, HK_STATUE);
+			return ES_NOT_HANDLED;
+		}
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey town_window_hotkeys[] = {
+	Hotkey((uint16)0, "location", WID_TV_CENTER_VIEW),
+	Hotkey((uint16)0, "local_authority", WID_TV_SHOW_AUTHORITY),
+	Hotkey((uint16)0, "cb_window", WID_TV_CB),
+	Hotkey(WKC_CTRL | 'S', "build_statue", HK_STATUE + 0x80),
+	HOTKEY_LIST_END
+};
+HotkeyList TownViewWindow::hotkeys("town_window", town_window_hotkeys);
+
 static const NWidgetPart _nested_town_game_view_widgets[] = {
 	NWidget(NWID_HORIZONTAL),
 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
@@ -545,10 +632,11 @@
 	EndContainer(),
 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
 	NWidget(NWID_HORIZONTAL),
-		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
-			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
+		NWidget(NWID_HORIZONTAL), //, NC_EQUALSIZE
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
 			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
-			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0),
 		EndContainer(),
 		NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
 	EndContainer(),
@@ -558,7 +646,8 @@
 	WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
 	WC_TOWN_VIEW, WC_NONE,
 	0,
-	_nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets)
+	_nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets),
+	&TownViewWindow::hotkeys
 );
 
 static const NWidgetPart _nested_town_editor_view_widgets[] = {
@@ -581,6 +670,7 @@
 			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
 			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
 			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0),
 		EndContainer(),
 		NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
 	EndContainer(),
@@ -605,7 +695,7 @@
 static const NWidgetPart _nested_town_directory_widgets[] = {
 	NWidget(NWID_HORIZONTAL),
 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
-		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_CAPTION, COLOUR_BROWN, TDW_CAPTION_TEXT), SetDataTip(STR_TOWN_DIRECTORY_CAPTION_EXTRA, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
@@ -697,6 +787,24 @@
 		return (a_population < b_population) ? -1 : 1;
 	}
 
+	/** Sort by real population (default descending, as big towns are of the most interest). */
+	static int CDECL TownRealPopulationSorter(const Town * const *a, const Town * const *b)
+	{
+		uint32 a_population = (*a)->cache.potential_pop;
+		uint32 b_population = (*b)->cache.potential_pop;
+		if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b);
+		return (a_population < b_population) ? -1 : 1;
+	}
+
+	/** Sort by number of houses (default descending, as big towns are of the most interest). */
+	static int CDECL TownHousesSorter(const Town * const *a, const Town * const *b)
+	{
+		uint32 a_houses = (*a)->cache.num_houses;
+		uint32 b_houses = (*b)->cache.num_houses;
+		if (a_houses == b_houses) return TownDirectoryWindow::TownPopulationSorter(a, b);
+		return (a_houses < b_houses) ? -1 : 1;
+	}
+
 	/** Sort by town rating */
 	static int CDECL TownRatingSorter(const Town * const *a, const Town * const *b)
 	{
@@ -741,6 +849,18 @@
 			case WID_TD_SORT_CRITERIA:
 				SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]);
 				break;
+			case TDW_CAPTION_TEXT: {
+				uint16 town_number = 0;
+				uint16 city_number = 0;
+				const Town *t;
+				FOR_ALL_TOWNS(t){
+					if(t->larger_town) city_number++;
+					town_number++;
+				}
+				SetDParam(0, city_number);
+				SetDParam(1, town_number);
+				break;
+			}
 		}
 	}
 
@@ -782,7 +902,10 @@
 
 					SetDParam(0, t->index);
 					SetDParam(1, t->cache.population);
-					DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, STR_TOWN_DIRECTORY_TOWN);
+					SetDParam(2, t->cache.potential_pop);
+					SetDParam(3, t->cache.num_houses);
+					/* CITIES DIFFERENT COLOUR*/
+					DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, t->larger_town ? STR_TOWN_DIRECTORY_CITY_COLOUR : STR_TOWN_DIRECTORY_TOWN_COLOUR);
 
 					y += this->resize.step_height;
 					if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window
@@ -821,7 +944,8 @@
 
 					SetDParam(0, t->index);
 					SetDParamMaxDigits(1, 8);
-					d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN));
+					SetDParamMaxDigits(2, 5);
+					d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN_COLOUR));
 				}
 				Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
 				d.width += icon_size.width + 2;
@@ -932,6 +1056,8 @@
 const StringID TownDirectoryWindow::sorter_names[] = {
 	STR_SORT_BY_NAME,
 	STR_SORT_BY_POPULATION,
+	STR_SORT_BY_REAL_POPULATION,
+	STR_SORT_BY_HOUSES,
 	STR_SORT_BY_RATING,
 	INVALID_STRING_ID
 };
@@ -940,6 +1066,8 @@
 GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
 	&TownNameSorter,
 	&TownPopulationSorter,
+	&TownRealPopulationSorter,
+	&TownHousesSorter,
 	&TownRatingSorter,
 };
 
@@ -1197,3 +1325,385 @@
 	if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
 	AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
 }
+
+//CB
+static void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line, bool show_house_states_info) {
+	//real pop and rating
+	SetDParam(0, town->cache.potential_pop);
+	SetDParam(1, town->ratings[_current_company]);
+	DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_REALPOP_RATE);
+	//town stats
+	int grow_rate = 0;
+	if(town->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) grow_rate = 0;
+	else grow_rate = TownTicksToDays((town->growth_rate & ~TOWN_GROW_RATE_CUSTOM) + 1);
+
+	SetDParam(0, grow_rate);
+	SetDParam(1, town->growth_rate & TOWN_GROW_RATE_CUSTOM ? STR_TOWN_VIEW_GROWTH_RATE_CUSTOM : STR_EMPTY);
+	// SetDParam(2, town->grow_counter < 16000 ? TownTicksToDays(town->grow_counter + 1) : -1);
+	SetDParam(2, TownTicksToDays(town->grow_counter + 1));
+	SetDParam(3, town->time_until_rebuild);
+	SetDParam(4, HasBit(town->flags, TOWN_IS_GROWING) ? 1 : 0);
+	SetDParam(5, town->fund_buildings_months);
+	DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_GROWTH);
+
+	if (show_house_states_info) {
+		SetDParam(0, town->houses_construction);
+		SetDParam(1, town->houses_reconstruction);
+		SetDParam(2, town->houses_demolished);
+		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_HOUSE_STATE);
+	}
+
+	///houses stats
+	SetDParam(0, town->houses_skipped);
+	SetDParam(1, town->houses_skipped_last_month);
+	SetDParam(2, town->cycles_skipped);
+	SetDParam(3, town->cycles_skipped_last_month);
+	SetDParam(4, town->cb_houses_removed);
+	SetDParam(5, town->cb_houses_removed_last_month);
+	DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_GROWTH_TILES);
+}
+
+bool CB_sortCargoesByFrom(CargoX first, CargoX second){
+	return (first.from < second.from) ? true : false;
+}
+
+struct CBTownWindow : Window {
+private:
+	Town *town;
+	std::list<CargoX> cargoes;
+
+public:
+	CBTownWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
+	{
+		for (uint i = 0; i < NUM_CARGO ; i++) {
+			CargoX c;
+			c.id = i;
+			c.from = CB_GetFrom(i);
+			this->cargoes.push_back(c);
+		}
+		cargoes.sort(CB_sortCargoesByFrom);
+		this->town = Town::Get(window_number);
+		this->InitNested(window_number);
+
+		if(HasBit(this->town->fund_regularly, _local_company)) this->LowerWidget(WID_CB_FUND_REGULAR);
+		if(HasBit(this->town->do_powerfund, _local_company)) this->LowerWidget(WID_CB_POWERFUND);
+		if(HasBit(this->town->advertise_regularly, _local_company)) this->LowerWidget(WID_CB_ADVERT_REGULAR);
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count)
+	{
+		switch (widget) {
+			case WID_CB_LOCATION:
+			case WID_CB_CENTER_VIEW: // scroll to location
+				if (_ctrl_pressed) {
+					ShowExtraViewPortWindow(this->town->xy);
+				}
+				else {
+					ScrollMainWindowToTile(this->town->xy);
+				}
+				break;
+			case WID_CB_ADVERT:
+				TownExecuteAction(this->town, HK_LADVERT);
+				break;
+			case WID_CB_FUND:
+				TownExecuteAction(this->town, HK_FUND);
+				break;
+			case WID_CB_FUND_REGULAR:
+				ToggleBit(this->town->fund_regularly, _local_company);
+				this->SetWidgetLoweredState(widget, HasBit(this->town->fund_regularly, _local_company));
+				this->SetWidgetDirty(widget);
+				break;
+			case WID_CB_POWERFUND:
+				ToggleBit(this->town->do_powerfund, _local_company);
+				this->SetWidgetLoweredState(widget, HasBit(this->town->do_powerfund, _local_company));
+				this->SetWidgetDirty(widget);
+				break;
+			case WID_CB_ADVERT_REGULAR:
+				if (!this->town->advertise_regularly) {
+					SetDParam(0, ToPercent8(this->town->ad_rating_goal));
+					ShowQueryString(STR_JUST_INT, STR_CB_ADVERT_REGULAR_RATING_TO_KEEP,
+					                4, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED);
+				} else this->OnQueryTextFinished(NULL);
+				break;
+			case WID_CB_TOWN_VIEW: // Town view window
+				ShowTownViewWindow(this->window_number);
+				break;
+			case WID_CB_SHOW_AUTHORITY: // town authority
+				ShowTownAuthorityWindow(this->window_number);
+				break;
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (str != NULL) SetBit(this->town->advertise_regularly, _local_company);
+		else ClrBit(this->town->advertise_regularly, _local_company);
+		this->town->ad_ref_goods_entry = NULL;
+		this->SetWidgetLoweredState(WID_CB_ADVERT_REGULAR, HasBit(this->town->advertise_regularly, _local_company));
+		this->SetWidgetDirty(WID_CB_ADVERT_REGULAR);
+
+		if (str == NULL)
+			return;
+		uint val = Clamp(StrEmpty(str) ? 0 : strtol(str, NULL, 10), 1, 100);
+		this->town->ad_rating_goal = ((val << 8) + 255) / 101;
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		if (widget == WID_TV_CAPTION){
+			SetDParam(0, this->town->index);
+		}
+	}
+
+	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		static const uint EXP_TOPPADDING = 5;
+		static const uint EXP_LINESPACE  = 2; // Amount of vertical space for a horizontal (sub-)total line.
+
+		switch(widget){
+			case WID_CB_DETAILS:
+				size->height = (FONT_HEIGHT_NORMAL + EXP_LINESPACE) * 7;
+				break;
+			case WID_CB_CARGO_NAME:
+			case WID_CB_CARGO_AMOUNT:
+			case WID_CB_CARGO_REQ:
+			case WID_CB_CARGO_STORE:
+			case WID_CB_CARGO_STORE_PCT:
+			case WID_CB_CARGO_FROM:
+			case WID_CB_CARGO_PREVIOUS:
+				uint desired_height = 1;
+				for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++){
+					if(CB_GetReq(cargo) > 0) desired_height++;
+				}
+				size->height = desired_height * (FONT_HEIGHT_NORMAL + EXP_LINESPACE) + EXP_TOPPADDING - EXP_LINESPACE;
+				break;
+		}
+	}
+
+	void DrawWidget(const Rect &r, int widget) const
+	{
+		static const uint EXP_LINESPACE  = FONT_HEIGHT_NORMAL + 2;
+		uint y = r.top + WD_FRAMERECT_TOP;
+		switch(widget){
+			case WID_CB_DETAILS:{
+				//growing
+				if(this->town->growing) DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_GROWING );
+				else DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_NOT_GROWING );
+				//population
+				SetDParam(0, this->town->cache.population);
+				SetDParam(1, this->town->cache.num_houses);
+				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += EXP_LINESPACE, STR_TOWN_VIEW_POPULATION_HOUSES);
+
+				DrawExtraTownInfo(r, y, this->town, EXP_LINESPACE, false);
+				//regular funding
+				if(this->town->fund_regularly != 0){
+					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += EXP_LINESPACE, STR_CB_FUNDED_REGULARLY);
+				}
+				break;
+			}
+			/* Citybuilder things*/
+			case WID_CB_CARGO_NAME:
+			case WID_CB_CARGO_AMOUNT:
+			case WID_CB_CARGO_REQ:
+			case WID_CB_CARGO_STORE:
+			case WID_CB_CARGO_STORE_PCT:
+			case WID_CB_CARGO_FROM:
+			case WID_CB_CARGO_PREVIOUS: {
+				if (!CB_Enabled() || this->town->larger_town) break;
+
+				uint delivered;
+				uint requirements;
+				uint from;
+				StringID string_to_draw;
+
+				//for cycle
+				std::list<CargoX> cargoes2 = this->cargoes;
+				std::list<CargoX>::iterator it2;
+				for (it2 = cargoes2.begin(); it2 != cargoes2.end(); ++it2) {
+					CargoX cargox;
+					cargox = *it2;
+					if (it2 == cargoes2.begin()) { //header
+						DrawString(r.left + WD_FRAMERECT_LEFT + 14, r.right - WD_FRAMERECT_LEFT, y,
+							(STR_TOWN_GROWTH_HEADER_CARGO + widget - WID_CB_CARGO_NAME), TC_FROMSTRING,
+							(widget == WID_CB_CARGO_NAME) ? SA_LEFT : SA_RIGHT);
+
+						y += (FONT_HEIGHT_NORMAL + 2);
+					}
+
+					const CargoSpec *cargos = CargoSpec::Get(cargox.id);
+					//cargo needed?
+					if (!cargos->IsValid() || CB_GetReq(cargos->Index()) == 0) continue;
+
+					from = CB_GetFrom(cargos->Index());
+
+					switch(widget) {
+						case WID_CB_CARGO_NAME: {
+							int rect_x = (r.left + WD_FRAMERECT_LEFT);
+							GfxFillRect(rect_x, y + 1, rect_x + 8, y + 6, 0);
+							GfxFillRect(rect_x + 1, y + 2, rect_x + 7, y + 5, cargos->legend_colour);
+
+							SetDParam(0, cargos->name);
+							DrawString(r.left + WD_FRAMERECT_LEFT + 14, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_CB_CARGO_NAME);
+							break;
+						}
+						case WID_CB_CARGO_AMOUNT: {
+							delivered = this->town->new_act_cargo[cargos->Index()];
+							requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true);
+							SetDParam(0, delivered);
+
+							//when required
+							if (this->town->cache.population >= from) {
+								if((delivered + (uint)this->town->storage[cargos->Index()]) >= requirements) string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_GOOD;
+								else string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_BAD;
+							}
+							//when not required -> all faded
+							else string_to_draw = STR_TOWN_CB_CARGO_AMOUNT_NOT;
+
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						case WID_CB_CARGO_REQ: {
+							requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true);
+							SetDParam(0, requirements);
+							 //when required
+							string_to_draw = (this->town->cache.population >= from) ? STR_TOWN_CB_CARGO_REQ_YES : STR_TOWN_CB_CARGO_REQ_NOT;
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						case WID_CB_CARGO_PREVIOUS: {
+							requirements = CB_GetTownReq(this->town->cache.population, CB_GetReq(cargos->Index()), from, true);
+							SetDParam(0, this->town->act_cargo[cargos->Index()]);
+							if (this->town->cache.population >= from){
+								if (this->town->delivered_enough[cargos->Index()]) {
+									string_to_draw = (this->town->act_cargo[cargos->Index()] >= requirements) ? STR_TOWN_CB_CARGO_PREVIOUS_YES : STR_TOWN_CB_CARGO_PREVIOUS_EDGE;
+								}
+								else string_to_draw = STR_TOWN_CB_CARGO_PREVIOUS_BAD;
+							}
+							else string_to_draw = STR_TOWN_CB_CARGO_PREVIOUS_NOT;
+
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						case WID_CB_CARGO_STORE: {
+							SetDParam(0, this->town->storage[cargos->Index()]);
+							if (CB_GetDecay(cargos->Index()) == 100) string_to_draw = STR_TOWN_CB_CARGO_STORE_DECAY;  //when 100% decay
+							else {
+								if (this->town->cache.population >= from) string_to_draw = STR_TOWN_CB_CARGO_STORE_YES;  //when required
+								else string_to_draw = STR_TOWN_CB_CARGO_STORE_NOT;
+							}
+
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						case WID_CB_CARGO_STORE_PCT: {
+							uint max_storage = CB_GetMaxTownStorage(this->town, cargos->Index());
+							if (CB_GetDecay(cargos->Index()) == 100 || !max_storage) string_to_draw = STR_TOWN_CB_CARGO_STORE_DECAY;  //when 100% decay
+							else {
+								SetDParam(0, 100 * this->town->storage[cargos->Index()] / max_storage);
+								if (this->town->cache.population >= from) string_to_draw = STR_TOWN_CB_CARGO_STORE_PCT_YES;  //when required
+								else string_to_draw = STR_TOWN_CB_CARGO_STORE_PCT_NOT;
+							}
+
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						case WID_CB_CARGO_FROM: {
+							SetDParam(0, from);
+							string_to_draw = (this->town->cache.population >= from) ? STR_TOWN_CB_CARGO_FROM_YES : STR_TOWN_CB_CARGO_FROM_NOT; //when required
+
+							DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, string_to_draw, TC_FROMSTRING, SA_RIGHT);
+							break;
+						}
+						//last case
+					}
+					//switch
+					y += (FONT_HEIGHT_NORMAL + 2);
+					//cargo needed?
+				}
+				//for cycle
+			}
+			break;
+		}
+		/* Citybuilder things enabled*/
+	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		TownExecuteAction(this->town, hotkey);
+		return ES_HANDLED;
+	}
+
+	static HotkeyList hotkeys;
+};
+
+HotkeyList CBTownWindow::hotkeys("town_gui", town_hotkeys);
+
+static const NWidgetPart _nested_cb_town_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
+		NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_CB_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
+		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
+		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_BROWN),
+		NWidget(NWID_VERTICAL),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 5),  SetResize(1, 0), SetFill(1, 0),
+			NWidget(NWID_HORIZONTAL),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_DETAILS), SetMinimalSize(250, 0), SetResize(1, 0), SetFill(1, 0),
+				NWidget(NWID_VERTICAL),
+					NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_ADVERT),SetMinimalSize(66, 20),SetFill(1, 0), SetDataTip(STR_CB_LARGE_ADVERTISING_CAMPAIGN, 0),
+						NWidget(NWID_SPACER), SetMinimalSize(2, 0),
+						NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_FUND),SetMinimalSize(66, 20),SetFill(1, 0), SetDataTip(STR_CB_NEW_BUILDINGS, 0),
+						NWidget(NWID_SPACER), SetMinimalSize(4, 0),
+					EndContainer(),
+					NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+					NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+						NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_CB_ADVERT_REGULAR),SetMinimalSize(66, 20),SetFill(1, 0), SetDataTip(STR_CB_ADVERT_REGULAR, STR_CB_ADVERT_REGULAR_TT),
+ 						NWidget(NWID_SPACER), SetMinimalSize(2, 0),
+						NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_CB_FUND_REGULAR),SetMinimalSize(66, 20),SetFill(1, 0), SetDataTip(STR_CB_FUND_REGULAR, STR_CB_FUND_REGULAR_TT),
+						NWidget(NWID_SPACER), SetMinimalSize(4, 0),
+					EndContainer(),
+					NWidget(NWID_SPACER), SetMinimalSize(0, 2),
+					NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+  						NWidget(NWID_SPACER), SetMinimalSize(132, 0),
+  						NWidget(NWID_SPACER), SetMinimalSize(2, 0),
+						NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_CB_POWERFUND),SetMinimalSize(66, 20),SetFill(1, 0), SetDataTip(STR_CB_POWERFUND, STR_CB_POWERFUND_TT),
+						NWidget(NWID_SPACER), SetMinimalSize(4, 0),
+					EndContainer(),
+				EndContainer(),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 5),  SetResize(1, 0), SetFill(1, 0),
+			NWidget(NWID_HORIZONTAL),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_NAME),SetMinimalSize(100, 0), SetResize(0, 0), SetFill(1, 0),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_AMOUNT),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_REQ),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_PREVIOUS),SetMinimalSize(80, 0),  SetResize(1, 0), SetFill(0, 0),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE),SetMinimalSize(70, 0), SetResize(1, 0), SetFill(0, 0),
+				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE_PCT),SetMinimalSize(60, 0), SetResize(1, 0), SetFill(0, 0),
+			EndContainer(),
+			NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetResize(1, 1), SetFill(1, 1),
+		EndContainer(),
+	EndContainer(),
+	NWidget(NWID_HORIZONTAL),
+		NWidget(NWID_HORIZONTAL),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_CENTER_VIEW), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_TOWN_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_CB_GUI_TOWN_VIEW_BUTTON, STR_CB_GUI_TOWN_VIEW_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
+		EndContainer(),
+		NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
+	EndContainer(),
+};
+
+static WindowDesc _cb_town_desc(
+	WDP_AUTO, "cb_town", 320, 80,
+	WC_CB_TOWN, WC_NONE,
+	0,
+	_nested_cb_town_widgets, lengthof(_nested_cb_town_widgets),
+	&CBTownWindow::hotkeys
+);
+
+void ShowCBTownWindow(uint town) {
+	AllocateWindowDescFront<CBTownWindow>(&_cb_town_desc, town);
+}
diff -r e16bdc0054ce src/vehicle_gui.cpp
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -38,6 +38,7 @@
 #include "station_base.h"
 #include "tilehighlight_func.h"
 #include "zoom_func.h"
+#include "hotkeys.h"
 
 #include "safeguards.h"
 
@@ -2302,24 +2303,7 @@
 	EndContainer(),
 };
 
-/** Vehicle view window descriptor for all vehicles but trains. */
-static WindowDesc _vehicle_view_desc(
-	WDP_AUTO, "view_vehicle", 250, 116,
-	WC_VEHICLE_VIEW, WC_NONE,
-	0,
-	_nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets)
-);
-
-/**
- * Vehicle view window descriptor for trains. Only minimum_height and
- *  default_height are different for train view.
- */
-static WindowDesc _train_view_desc(
-	WDP_AUTO, "view_vehicle_train", 250, 134,
-	WC_VEHICLE_VIEW, WC_NONE,
-	0,
-	_nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets)
-);
+
 
 
 /* Just to make sure, nobody has changed the vehicle type constants, as we are
@@ -2778,8 +2762,45 @@
 	{
 		::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number);
 	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		if (this->owner != _local_company) return ES_NOT_HANDLED;
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
 };
 
+static Hotkey vehiclegui_hotkeys[] = {
+	Hotkey('G', "vehicle_orders", WID_VV_SHOW_ORDERS),
+	Hotkey('F', "vehicle_go", WID_VV_START_STOP),
+	Hotkey((uint16)0, "vehicle_refit", WID_VV_REFIT),
+	Hotkey((uint16)0, "vehicle_clone", WID_VV_CLONE),
+	HOTKEY_LIST_END
+};
+HotkeyList VehicleViewWindow::hotkeys("vehiclegui", vehiclegui_hotkeys);
+
+/** Vehicle view window descriptor for all vehicles but trains. */
+static WindowDesc _vehicle_view_desc(
+	WDP_AUTO, "view_vehicle", 250, 116,
+	WC_VEHICLE_VIEW, WC_NONE,
+	0,
+	_nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets),
+	&VehicleViewWindow::hotkeys
+);
+
+/**
+ * Vehicle view window descriptor for trains. Only minimum_height and
+ *  default_height are different for train view.
+ */
+static WindowDesc _train_view_desc(
+	WDP_AUTO, "view_vehicle_train", 250, 134,
+	WC_VEHICLE_VIEW, WC_NONE,
+	0,
+	_nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets),
+	&VehicleViewWindow::hotkeys
+);
 
 /** Shows the vehicle view window of the given vehicle. */
 void ShowVehicleViewWindow(const Vehicle *v)
diff -r e16bdc0054ce src/video/sdl_v.cpp
--- a/src/video/sdl_v.cpp
+++ b/src/video/sdl_v.cpp
@@ -494,7 +494,15 @@
 	AS(SDLK_QUOTE,   WKC_SINGLEQUOTE),
 	AS(SDLK_COMMA,   WKC_COMMA),
 	AS(SDLK_MINUS,   WKC_MINUS),
-	AS(SDLK_PERIOD,  WKC_PERIOD)
+	AS(SDLK_PERIOD,  WKC_PERIOD),
+
+	AS(0x7B,            WKC_L_BRACE),
+	AS(0x7D,            WKC_R_BRACE),
+	AS(SDLK_LEFTPAREN,  WKC_L_PAREN),
+	AS(SDLK_RIGHTPAREN, WKC_R_PAREN),
+	AS(SDLK_PLUS,       WKC_PLUS),
+	AS(SDLK_EXCLAIM,    WKC_EXCLAIM),
+	AS(SDLK_ASTERISK,   WKC_ASTERISK),
 };
 
 static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character)
@@ -742,6 +750,7 @@
 			bool old_ctrl_pressed = _ctrl_pressed;
 
 			_ctrl_pressed  = !!(mod & KMOD_CTRL);
+			_alt_pressed = !!(mod & KMOD_ALT);
 			_shift_pressed = !!(mod & KMOD_SHIFT);
 
 			/* determine which directional keys are down */
diff -r e16bdc0054ce src/video/win32_v.cpp
--- a/src/video/win32_v.cpp
+++ b/src/video/win32_v.cpp
@@ -1251,6 +1251,7 @@
 			bool old_ctrl_pressed = _ctrl_pressed;
 
 			_ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
+			_alt_pressed = _wnd.has_focus && GetAsyncKeyState(VK_MENU)<0;
 			_shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0;
 
 			/* determine which directional keys are down */
diff -r e16bdc0054ce src/viewport.cpp
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -63,6 +63,9 @@
  */
 
 #include "stdafx.h"
+#include "math.h"
+#include "core/math_func.hpp"
+#include "core/smallvec_type.hpp"
 #include "landscape.h"
 #include "viewport_func.h"
 #include "station_base.h"
@@ -89,6 +92,8 @@
 
 #include "table/strings.h"
 #include "table/string_colours.h"
+#include "zoning.h"
+#include "industry_type.h"
 
 #include "safeguards.h"
 
@@ -149,6 +154,34 @@
 typedef SmallVector<ParentSpriteToDraw, 64> ParentSpriteToDrawVector;
 typedef SmallVector<ChildScreenSpriteToDraw, 16> ChildScreenSpriteToDrawVector;
 
+enum RailSnapMode {
+	RSM_NO_SNAP,
+	RSM_SNAP_TO_TILE,
+	RSM_SNAP_TO_RAIL,
+};
+
+/**
+ * Snapping point for a track.
+ *
+ * Point where a track (rail/road/other) can be snapped to while selecting tracks with polyline
+ * tool (HT_POLY). Besides of x/y coordinates expressed in tile "units" it contains a set of
+ * allowed line directions.
+ */
+struct LineSnapPoint : Point {
+	uint8 dirs; ///< Allowed line directions, set of #Direction bits.
+};
+
+typedef SmallVector<LineSnapPoint, 4> LineSnapPoints; ///< Set of snapping points
+
+/** Coordinates of a polyline track made of 2 connected line segments. */
+struct Polyline {
+	Point start;           ///< The point where the first segment starts (as given in LineSnapPoint).
+	Direction first_dir;   ///< Direction of the first line segment.
+	uint first_len;        ///< Length of the first segment - number of track pieces.
+	Direction second_dir;  ///< Direction of the second line segment.
+	uint second_len;       ///< Length of the second segment - number of track pieces.
+};
+
 /** Data structure storing rendering information */
 struct ViewportDrawer {
 	DrawPixelInfo dpi;
@@ -180,6 +213,18 @@
 uint _dirty_block_colour = 0;
 static VpSpriteSorter _vp_sprite_sorter = NULL;
 
+static RailSnapMode _rail_snap_mode = RSM_NO_SNAP; ///< Type of rail track snapping (polyline tool).
+static LineSnapPoints _tile_snap_points; ///< Tile to which a rail track will be snapped to (polyline tool).
+static LineSnapPoints _rail_snap_points; ///< Set of points where a rail track will be snapped to (polyline tool).
+static LineSnapPoint _current_snap_lock; ///< Start point and direction at which selected track is locked on currently (while dragging in polyline mode).
+
+static IndustryType _industry_forbidden_tiles = INVALID_INDUSTRYTYPE;
+
+static RailSnapMode GetRailSnapMode();
+static void SetRailSnapMode(RailSnapMode mode);
+static TileIndex GetRailSnapTile();
+static void SetRailSnapTile(TileIndex tile);
+
 static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z)
 {
 	Point p = RemapCoords(x, y, z);
@@ -814,13 +859,17 @@
 }
 
 /**
- * Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd.pos
+ * Checks whether a point is inside the selected rectangle given by _thd.size, _thd.pos and _thd.diagonal
  * @param x The x coordinate of the point to be checked.
  * @param y The y coordinate of the point to be checked.
  * @return True if the point is inside the rectangle, else false.
  */
-bool IsInsideRotatedRectangle(int x, int y)
+static bool IsInsideSelectedRectangle(int x, int y)
 {
+	if (!_thd.diagonal) {
+		return IsInsideBS(x, _thd.pos.x, _thd.size.x) && IsInsideBS(y, _thd.pos.y, _thd.size.y);
+	}
+
 	int dist_a = (_thd.size.x + _thd.size.y);      // Rotated coordinate system for selected rectangle.
 	int dist_b = (_thd.size.x - _thd.size.y);      // We don't have to divide by 2. It's all relative!
 	int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny.
@@ -937,53 +986,45 @@
 	DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL);
 }
 
-static bool IsPartOfAutoLine(int px, int py)
+static HighLightStyle GetPartOfAutoLine(int px, int py, const Point &selstart, const Point &selend, HighLightStyle dir)
 {
-	px -= _thd.selstart.x;
-	py -= _thd.selstart.y;
-
-	if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false;
-
-	switch (_thd.drawstyle & HT_DIR_MASK) {
-		case HT_DIR_X:  return py == 0; // x direction
-		case HT_DIR_Y:  return px == 0; // y direction
-		case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
-		case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
-		case HT_DIR_VL: return px == py || px == py + 16; // vertical left
-		case HT_DIR_VR: return px == py || px == py - 16; // vertical right
-		default:
-			NOT_REACHED();
+	if (!IsInRangeInclusive(selstart.x & ~TILE_UNIT_MASK, selend.x & ~TILE_UNIT_MASK, px)) return HT_DIR_END;
+	if (!IsInRangeInclusive(selstart.y & ~TILE_UNIT_MASK, selend.y & ~TILE_UNIT_MASK, py)) return HT_DIR_END;
+
+	px -= selstart.x & ~TILE_UNIT_MASK;
+	py -= selstart.y & ~TILE_UNIT_MASK;
+
+	switch (dir) {
+		case HT_DIR_X: return (py == 0) ? HT_DIR_X : HT_DIR_END;
+		case HT_DIR_Y: return (px == 0) ? HT_DIR_Y : HT_DIR_END;
+		case HT_DIR_HU: return (px == -py) ? HT_DIR_HU : (px == -py - (int)TILE_SIZE) ? HT_DIR_HL : HT_DIR_END;
+		case HT_DIR_HL: return (px == -py) ? HT_DIR_HL : (px == -py + (int)TILE_SIZE) ? HT_DIR_HU : HT_DIR_END;
+		case HT_DIR_VL: return (px ==  py) ? HT_DIR_VL : (px ==  py + (int)TILE_SIZE) ? HT_DIR_VR : HT_DIR_END;
+		case HT_DIR_VR: return (px ==  py) ? HT_DIR_VR : (px ==  py - (int)TILE_SIZE) ? HT_DIR_VL : HT_DIR_END;
+		default: NOT_REACHED(); break;
 	}
+
+	return HT_DIR_END;
 }
 
-/* [direction][side] */
-static const HighLightStyle _autorail_type[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"
 
 /**
  * Draws autorail highlights.
  *
  * @param *ti TileInfo Tile that is being drawn
- * @param autorail_type Offset into _AutorailTilehSprite[][]
+ * @param autorail_type \c HT_DIR_XXX, offset into _AutorailTilehSprite[][]
+ * @param pal Palette to use, -1 to autodetect
  */
-static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
+static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_type, PaletteID pal = -1)
 {
 	SpriteID image;
-	PaletteID pal;
 	int offset;
 
 	FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
 	Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
 	if (IsHalftileSlope(ti->tileh)) {
-		static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
+		static const HighLightStyle _lower_rail[CORNER_END] = { HT_DIR_VR, HT_DIR_HU, HT_DIR_VL, HT_DIR_HL }; // CORNER_W, CORNER_S, CORNER_E, CORNER_N
 		Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
 		if (autorail_type != _lower_rail[halftile_corner]) {
 			foundation_part = FOUNDATION_PART_HALFTILE;
@@ -992,16 +1033,17 @@
 		}
 	}
 
+	assert(autorail_type < HT_DIR_END);
 	offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
 	if (offset >= 0) {
 		image = SPR_AUTORAIL_BASE + offset;
-		pal = PAL_NONE;
+		if (pal == (PaletteID)-1) pal = _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE;
 	} else {
 		image = SPR_AUTORAIL_BASE - offset;
-		pal = PALETTE_SEL_TILE_RED;
+		if (pal == (PaletteID)-1) pal = PALETTE_SEL_TILE_RED;
 	}
 
-	DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
+	DrawSelectionSprite(image, pal, ti, 7, foundation_part);
 }
 
 /**
@@ -1014,66 +1056,77 @@
 	bool is_redsq = _thd.redsq == ti->tile;
 	if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING);
 
-	/* No tile selection active? */
-	if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
-
-	if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle
-		if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner;
-		return;
-	}
-
-	/* Inside the inner area? */
-	if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) &&
-			IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) {
-draw_inner:
-		if (_thd.drawstyle & HT_RECT) {
-			if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE);
-		} else if (_thd.drawstyle & HT_POINT) {
-			/* Figure out the Z coordinate for the single dot. */
-			int z = 0;
-			FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
-			if (ti->tileh & SLOPE_N) {
-				z += TILE_HEIGHT;
-				if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
-			}
-			if (IsHalftileSlope(ti->tileh)) {
-				Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
-				if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
-				if (halftile_corner != CORNER_S) {
-					foundation_part = FOUNDATION_PART_HALFTILE;
-					if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
+	switch (_thd.drawstyle & HT_DRAG_MASK) {
+		default: break; // No tile selection active?
+
+		case HT_RECT:
+			if (!is_redsq) {
+				if (IsInsideSelectedRectangle(ti->x, ti->y)) {
+					DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE);
+				} else if (_thd.outersize.x > 0 &&
+						/* Check if it's inside the outer area? */
+						IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
+						IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
+					/* Draw a blue rect. */
+					DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE);
 				}
 			}
-			DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part);
-		} else if (_thd.drawstyle & HT_RAIL) {
-			/* autorail highlight piece under cursor */
-			HighLightStyle type = _thd.drawstyle & HT_DIR_MASK;
-			assert(type < HT_DIR_END);
-			DrawAutorailSelection(ti, _autorail_type[type][0]);
-		} else if (IsPartOfAutoLine(ti->x, ti->y)) {
-			/* autorail highlighting long line */
-			HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK;
-			uint side;
-
-			if (dir == HT_DIR_X || dir == HT_DIR_Y) {
-				side = 0;
-			} else {
-				TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
-				side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile)));
+			break;
+
+		case HT_POINT:
+			if (IsInsideSelectedRectangle(ti->x, ti->y)) {
+				/* Figure out the Z coordinate for the single dot. */
+				int z = 0;
+				FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
+				if (ti->tileh & SLOPE_N) {
+					z += TILE_HEIGHT;
+					if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
+				}
+				if (IsHalftileSlope(ti->tileh)) {
+					Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
+					if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
+					if (halftile_corner != CORNER_S) {
+						foundation_part = FOUNDATION_PART_HALFTILE;
+						if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
+					}
+				}
+				DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part);
 			}
-
-			DrawAutorailSelection(ti, _autorail_type[dir][side]);
+			break;
+
+		case HT_RAIL:
+			if (ti->tile == TileVirtXY(_thd.pos.x, _thd.pos.y)) {
+				assert((_thd.drawstyle & HT_DIR_MASK) < HT_DIR_END);
+				DrawAutorailSelection(ti, _thd.drawstyle & HT_DIR_MASK);
+			}
+			break;
+
+		case HT_LINE: {
+			HighLightStyle type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart, _thd.selend, _thd.drawstyle & HT_DIR_MASK);
+			if (type < HT_DIR_END) {
+				DrawAutorailSelection(ti, type);
+			} else if (_thd.dir2 < HT_DIR_END) {
+				type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart2, _thd.selend2, _thd.dir2);
+				if (type < HT_DIR_END) DrawAutorailSelection(ti, type, PALETTE_SEL_TILE_BLUE);
+			}
+			break;
 		}
-		return;
 	}
-
-	/* Check if it's inside the outer area? */
-	if (!is_redsq && _thd.outersize.x > 0 &&
-			IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
-			IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
-		/* Draw a blue rect. */
-		DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE);
-		return;
+}
+
+void SetIndustryForbiddenTilesHighlight(IndustryType type) {
+	if (_settings_client.gui.show_industry_forbidden_tiles &&
+	    	_industry_forbidden_tiles != type) {
+		MarkWholeScreenDirty();
+	}
+	_industry_forbidden_tiles = type;
+}
+
+static void DrawIndustryForbiddenTiles(const TileInfo *ti) {
+	if (_settings_client.gui.show_industry_forbidden_tiles &&
+			_industry_forbidden_tiles != INVALID_INDUSTRYTYPE &&
+			!CanBuildIndustryOnTile(_industry_forbidden_tiles, ti->tile)) {
+		DrawTileSelectionRect(ti, PALETTE_SEL_TILE_RED);
 	}
 }
 
@@ -1200,7 +1253,11 @@
 				_vd.last_foundation_child[1] = NULL;
 
 				_tile_type_procs[tile_type]->draw_tile_proc(&tile_info);
-				if (tile_info.tile != INVALID_TILE) DrawTileSelection(&tile_info);
+				if (tile_info.tile != INVALID_TILE){
+					DrawTileZoning(&tile_info);
+					DrawIndustryForbiddenTiles(&tile_info);
+					DrawTileSelection(&tile_info);
+				}
 			}
 		}
 	}
@@ -1255,8 +1312,7 @@
 	const Town *t;
 	FOR_ALL_TOWNS(t) {
 		ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign,
-				_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
-				STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
+				t->Label(), t->SmallLabel(), STR_VIEWPORT_TOWN_TINY_BLACK,
 				t->index, t->cache.population);
 	}
 }
@@ -1943,7 +1999,7 @@
 		int x_start = _thd.pos.x;
 		int y_start = _thd.pos.y;
 
-		if (_thd.outersize.x != 0) {
+		if (_thd.outersize.x != 0 || _thd.outersize.y != 0) {
 			x_size  += _thd.outersize.x;
 			x_start += _thd.offs.x;
 			y_size  += _thd.outersize.y;
@@ -2079,7 +2135,8 @@
 	const Town *t;
 	FOR_ALL_TOWNS(t) {
 		if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) {
-			ShowTownViewWindow(t->index);
+ 			if (_ctrl_pressed) TownExecuteAction(t, 4); //build statue
+ 			else ShowTownViewWindow(t->index);
 			return true;
 		}
 	}
@@ -2166,7 +2223,7 @@
 }
 
 
-bool HandleViewportClicked(const ViewPort *vp, int x, int y)
+bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click)
 {
 	const Vehicle *v = CheckClickOnVehicle(vp, x, y);
 
@@ -2176,6 +2233,18 @@
 
 	/* Vehicle placement mode already handled above. */
 	if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
+		if (_thd.place_mode & HT_POLY) {
+			/* In polyline mode double-clicking on a single white line, finishes current polyline.
+			 * If however the user double-clicks on a line that has a white and a blue section,
+			 * both lines (white and blue) will be constructed consecutively. */
+			static bool stop_snap_on_double_click = false;
+			if (double_click && stop_snap_on_double_click) {
+				SetRailSnapMode(RSM_NO_SNAP);
+				return true;
+			}
+			stop_snap_on_double_click = !(_thd.drawstyle & HT_LINE) || (_thd.dir2 == HT_DIR_END);
+		}
+
 		PlaceObject();
 		return true;
 	}
@@ -2190,7 +2259,8 @@
 		if (IsCompanyBuildableVehicleType(v)) {
 			v = v->First();
 			if (_ctrl_pressed && v->owner == _local_company) {
-				StartStopVehicle(v, true);
+				if (_settings_client.gui.enable_ctrl_click_start_stop)
+					StartStopVehicle(v, true);
 			} else {
 				ShowVehicleViewWindow(v);
 			}
@@ -2302,8 +2372,8 @@
 
 void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
 {
-	_thd.offs.x = ox * TILE_SIZE;
-	_thd.offs.y = oy * TILE_SIZE;
+	_thd.new_offs.x = ox * TILE_SIZE;
+	_thd.new_offs.y = oy * TILE_SIZE;
 	_thd.new_outersize.x = sx * TILE_SIZE;
 	_thd.new_outersize.y = sy * TILE_SIZE;
 }
@@ -2343,7 +2413,36 @@
 	return FindWindowById(this->window_class, this->window_number);
 }
 
-
+static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging);
+
+static inline void CalcNewPolylineOutersize()
+{
+	/* use the 'outersize' to mark the second (blue) part of a polyline selection */
+	if (_thd.dir2 < HT_DIR_END) {
+		/* get bounds of the second part */
+		int outer_x1 = _thd.selstart2.x & ~TILE_UNIT_MASK;
+		int outer_y1 = _thd.selstart2.y & ~TILE_UNIT_MASK;
+		int outer_x2 = _thd.selend2.x & ~TILE_UNIT_MASK;
+		int outer_y2 = _thd.selend2.y & ~TILE_UNIT_MASK;
+		if (outer_x1 > outer_x2) Swap(outer_x1, outer_x2);
+		if (outer_y1 > outer_y2) Swap(outer_y1, outer_y2);
+		/* include the first part */
+		outer_x1 = min<int>(outer_x1, _thd.new_pos.x);
+		outer_y1 = min<int>(outer_y1, _thd.new_pos.y);
+		outer_x2 = max<int>(outer_x2, _thd.new_pos.x + _thd.new_size.x - TILE_SIZE);
+		outer_y2 = max<int>(outer_y2, _thd.new_pos.y + _thd.new_size.y - TILE_SIZE);
+		/* write new values */
+		_thd.new_offs.x = outer_x1 - _thd.new_pos.x;
+		_thd.new_offs.y = outer_y1 - _thd.new_pos.y;
+		_thd.new_outersize.x = outer_x2 - outer_x1 + TILE_SIZE - _thd.new_size.x;
+		_thd.new_outersize.y = outer_y2 - outer_y1 + TILE_SIZE - _thd.new_size.y;
+	} else {
+		_thd.new_offs.x = 0;
+		_thd.new_offs.y = 0;
+		_thd.new_outersize.x = 0;
+		_thd.new_outersize.y = 0;
+	}
+}
 
 /**
  * Updates tile highlighting for all cases.
@@ -2400,10 +2499,42 @@
 					y1 += TILE_SIZE / 2;
 					break;
 				case HT_RAIL:
-					/* Draw one highlighted tile in any direction */
-					new_drawstyle = GetAutorailHT(pt.x, pt.y);
-					break;
 				case HT_LINE:
+					/* HT_POLY */
+					if (_thd.place_mode & HT_POLY) {
+						RailSnapMode snap_mode = GetRailSnapMode();
+						if (snap_mode == RSM_NO_SNAP ||
+								(snap_mode == RSM_SNAP_TO_TILE && GetRailSnapTile() == TileVirtXY(pt.x, pt.y))) {
+							new_drawstyle = GetAutorailHT(pt.x, pt.y);
+							_thd.new_offs.x = 0;
+							_thd.new_offs.y = 0;
+							_thd.new_outersize.x = 0;
+							_thd.new_outersize.y = 0;
+							_thd.dir2 = HT_DIR_END;
+						} else {
+							new_drawstyle = CalcPolyrailDrawstyle(pt, false);
+							if (new_drawstyle != HT_NONE) {
+								x1 = _thd.selstart.x & ~TILE_UNIT_MASK;
+								y1 = _thd.selstart.y & ~TILE_UNIT_MASK;
+								int x2 = _thd.selend.x & ~TILE_UNIT_MASK;
+								int y2 = _thd.selend.y & ~TILE_UNIT_MASK;
+								if (x1 > x2) Swap(x1, x2);
+								if (y1 > y2) Swap(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;
+							}
+						}
+						break;
+					}
+					/* HT_RAIL */
+					if (_thd.place_mode & HT_RAIL) {
+						/* Draw one highlighted tile in any direction */
+						new_drawstyle = GetAutorailHT(pt.x, pt.y);
+						break;
+					}
+					/* HT_LINE */
 					switch (_thd.place_mode & HT_DIR_MASK) {
 						case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break;
 						case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break;
@@ -2422,6 +2553,8 @@
 					}
 					_thd.selstart.x = x1 & ~TILE_UNIT_MASK;
 					_thd.selstart.y = y1 & ~TILE_UNIT_MASK;
+					_thd.selend.x = x1;
+					_thd.selend.y = y1;
 					break;
 				default:
 					NOT_REACHED();
@@ -2432,10 +2565,13 @@
 		}
 	}
 
+	if (new_drawstyle & HT_LINE) CalcNewPolylineOutersize();
+
 	/* redraw selection */
 	if (_thd.drawstyle != 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.offs.x != _thd.new_offs.x || _thd.offs.y != _thd.new_offs.y ||
 			_thd.outersize.x != _thd.new_outersize.x ||
 			_thd.outersize.y != _thd.new_outersize.y ||
 			_thd.diagonal    != new_diagonal) {
@@ -2445,6 +2581,7 @@
 		_thd.drawstyle = new_drawstyle;
 		_thd.pos = _thd.new_pos;
 		_thd.size = _thd.new_size;
+		_thd.offs = _thd.new_offs;
 		_thd.outersize = _thd.new_outersize;
 		_thd.diagonal = new_diagonal;
 		_thd.dirty = 0xff;
@@ -2463,7 +2600,6 @@
  */
 static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_LEFT_CLICK)
 {
-	if (!_settings_client.gui.measure_tooltip) return;
 	GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond);
 }
 
@@ -2494,6 +2630,11 @@
 	} else if (_thd.place_mode & (HT_RAIL | HT_LINE)) {
 		_thd.place_mode = HT_SPECIAL | others;
 		_thd.next_drawstyle = _thd.drawstyle | others;
+		_current_snap_lock.x = -1;
+		if ((_thd.place_mode & HT_POLY) != 0 && GetRailSnapMode() == RSM_NO_SNAP) {
+			SetRailSnapMode(RSM_SNAP_TO_TILE);
+			SetRailSnapTile(tile);
+		}
 	} else {
 		_thd.place_mode = HT_SPECIAL | others;
 		_thd.next_drawstyle = HT_POINT | others;
@@ -2522,7 +2663,8 @@
 	_thd.next_drawstyle = HT_RECT;
 
 	/* show measurement only if there is any length to speak of */
-	if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER);
+	if (distance > 1 && _settings_client.gui.measure_tooltip)
+		ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER);
 }
 
 static void VpStartPreSizing()
@@ -2685,7 +2827,31 @@
 	return (int)(h1 - h0) * TILE_HEIGHT_STEP;
 }
 
-static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
+static void ShowLengthMeasurement(HighLightStyle style, TileIndex start_tile, TileIndex end_tile, TooltipCloseCondition close_cond = TCC_LEFT_CLICK, bool show_single_tile_length = false)
+{
+	static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
+
+	if (_settings_client.gui.measure_tooltip) {
+		uint distance = DistanceManhattan(start_tile, end_tile) + 1;
+		byte index = 0;
+		uint64 params[2];
+
+		if (show_single_tile_length || distance != 1) {
+			int heightdiff = CalcHeightdiff(style, distance, start_tile, end_tile);
+			/* 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 ((style & HT_DIR_MASK) != HT_DIR_X && (style & HT_DIR_MASK) != HT_DIR_Y) {
+				distance = CeilDiv(distance, 2);
+			}
+
+			params[index++] = distance;
+			if (heightdiff != 0) params[index++] = heightdiff;
+		}
+
+		ShowMeasurementTooltips(measure_strings_length[index], index, params, close_cond);
+	}
+}
 
 /**
  * Check for underflowing the map.
@@ -2716,6 +2882,170 @@
 	test = max;
 }
 
+static const uint X_DIRS = (1 << DIR_NE) | (1 << DIR_SW);
+static const uint Y_DIRS = (1 << DIR_SE) | (1 << DIR_NW);
+static const uint HORZ_DIRS = (1 << DIR_W) | (1 << DIR_E);
+static const uint VERT_DIRS = (1 << DIR_N) | (1 << DIR_S);
+
+Trackdir PointDirToTrackdir(const Point &pt, Direction dir)
+{
+	Trackdir ret;
+
+	if (IsDiagonalDirection(dir)) {
+		ret = DiagDirToDiagTrackdir(DirToDiagDir(dir));
+	} else {
+		int x = pt.x & TILE_UNIT_MASK;
+		int y = pt.y & TILE_UNIT_MASK;
+		int ns = x + y;
+		int we = y - x;
+		if (HasBit(HORZ_DIRS, dir)) {
+			ret = TrackDirectionToTrackdir(ns < (int)TILE_SIZE ? TRACK_UPPER : TRACK_LOWER, dir);
+		} else {
+			ret = TrackDirectionToTrackdir(we < 0 ? TRACK_LEFT : TRACK_RIGHT, dir);
+		}
+	}
+
+	return ret;
+}
+
+static bool FindPolyline(const Point &pt, const LineSnapPoint &start, Polyline *ret)
+{
+	/* relative coordinats of the mouse point (offset against the snap point) */
+	int x = pt.x - start.x;
+	int y = pt.y - start.y;
+	int we = y - x;
+	int ns = x + y;
+
+	/* in-tile alignment of the snap point (there are two variants: [0, 8] or [8, 0]) */
+	uint align_x = start.x & TILE_UNIT_MASK;
+	uint align_y = start.y & TILE_UNIT_MASK;
+	assert((align_x == TILE_SIZE / 2 && align_y == 0 && !(start.dirs & X_DIRS)) || (align_x == 0 && align_y == TILE_SIZE / 2 && !(start.dirs & Y_DIRS)));
+
+	/* absolute distance between points (in tiles) */
+	uint d_x = abs(RoundDivSU(x < 0 ? x - align_y : x + align_y, TILE_SIZE));
+	uint d_y = abs(RoundDivSU(y < 0 ? y - align_x : y + align_x, TILE_SIZE));
+	uint d_ns = abs(RoundDivSU(ns, TILE_SIZE));
+	uint d_we = abs(RoundDivSU(we, TILE_SIZE));
+
+	/* Find on which quadrant is the mouse point (reltively to the snap point).
+	 * Numeration (clockwise like in Direction):
+	 * ortho            diag
+	 *   \   2   /       2 | 3
+	 *     \   /         --+---> [we]
+	 *  1    X    3      1 | 0
+	 *     /   \           v
+	 *  [x]  0  [y]       [ns]          */
+	uint ortho_quadrant = 2 * (x < 0) + ((x < 0) != (y < 0)); // implicit cast: false/true --> 0/1
+	uint diag_quadrant = 2 * (ns < 0) + ((ns < 0) != (we < 0));
+
+	/* direction from the snap point to the mouse point */
+	Direction ortho_line_dir = ChangeDir(DIR_S, (DirDiff)(2 * ortho_quadrant)); // DIR_S is the middle of the ortho quadrant no. 0
+	Direction diag_line_dir = ChangeDir(DIR_SE, (DirDiff)(2 * diag_quadrant));  // DIR_SE is the middle of the diag quadrant no. 0
+	if (!HasBit(start.dirs, ortho_line_dir) && !HasBit(start.dirs, diag_line_dir)) return false;
+
+	/* length of booth segments of auto line (choosing orthogonal direction first) */
+	uint ortho_len = 0, ortho_len2 = 0;
+	if (HasBit(start.dirs, ortho_line_dir)) {
+		bool is_len_even = (align_x != 0) ? d_x >= d_y : d_x <= d_y;
+		ortho_len = 2 * min(d_x, d_y) - (int)is_len_even;
+		assert((int)ortho_len >= 0);
+		if (d_ns == 0 || d_we == 0) { // just single segment?
+			ortho_len++;
+		} else {
+			ortho_len2 = abs((int)d_x - (int)d_y) + (int)is_len_even;
+		}
+	}
+
+	/* length of booth segments of auto line (choosing diagonal direction first) */
+	uint diag_len = 0, diag_len2 = 0;
+	if (HasBit(start.dirs, diag_line_dir)) {
+		if (d_x == 0 || d_y == 0) { // just single segment?
+			diag_len = d_x + d_y;
+		} else {
+			diag_len = min(d_ns, d_we);
+			diag_len2 = d_x + d_y - diag_len;
+		}
+	}
+
+	/* choose the best variant */
+	if (ortho_len != 0 && diag_len != 0) {
+		/* in the first place, choose this line whose first segment ends up closer
+		 * to the mouse point (thus the second segment is shorter) */
+		int cmp = ortho_len2 - diag_len2;
+		/* if equeal, choose the shorter line */
+		if (cmp == 0) cmp = ortho_len - diag_len;
+		/* finally look at small "units" and choose the line which is closer to the mouse point */
+		if (cmp == 0) cmp = min(abs(we), abs(ns)) - min(abs(x), abs(y));
+		/* based on comparison, disable one of variants */
+		if (cmp > 0) {
+			ortho_len = 0;
+		} else {
+			diag_len = 0;
+		}
+	}
+
+	/* store results */
+	if (ortho_len != 0) {
+		ret->first_dir = ortho_line_dir;
+		ret->first_len = ortho_len;
+		ret->second_dir = (ortho_len2 != 0) ? diag_line_dir : INVALID_DIR;
+		ret->second_len = ortho_len2;
+	} else if (diag_len != 0) {
+		ret->first_dir = diag_line_dir;
+		ret->first_len = diag_len;
+		ret->second_dir = (diag_len2 != 0) ? ortho_line_dir : INVALID_DIR;
+		ret->second_len = diag_len2;
+	} else {
+		return false;
+	}
+
+	ret->start = start;
+	return true;
+}
+
+/**
+ * Calculate squared euclidean distance between two points.
+ * @param a the first point
+ * @param b the second point
+ * @return |b - a| ^ 2
+ */
+static inline uint SqrDist(const Point &a, const Point &b)
+{
+	return (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y);
+}
+
+static LineSnapPoint *FindBestPolyline(const Point &pt, LineSnapPoint *snap_points, uint num_points, Polyline *ret)
+{
+	/* Find the best polyline (a pair of two lines - the white one and the blue
+	 * one) led from any of saved snap points to the mouse cursor. */
+
+	LineSnapPoint *best_snap_point = NULL; // the best polyline we found so far is led from this snap point
+
+	for (int i = 0; i < (int)num_points; i++) {
+		/* try to fit a polyline */
+		Polyline polyline;
+		if (!FindPolyline(pt, snap_points[i], &polyline)) continue; // skip non-matching snap points
+		/* check whether we've found a better polyline */
+		if (best_snap_point != NULL) {
+			/* firstly choose shorter polyline (the one with smaller amount of
+			 * track pieces composing booth the white and the blue line) */
+			uint cur_len = polyline.first_len + polyline.second_len;
+			uint best_len = ret->first_len + ret->second_len;
+			if (cur_len > best_len) continue;
+			/* secondly choose that polyline which has longer first (white) line */
+			if (cur_len == best_len && polyline.first_len < ret->first_len) continue;
+			/* finally check euclidean distance to snap points and choose the
+			 * one which is closer */
+			if (cur_len == best_len && polyline.first_len == ret->first_len && SqrDist(pt, snap_points[i]) >= SqrDist(pt, *best_snap_point)) continue;
+		}
+		/* save the found polyline */
+		*ret = polyline;
+		best_snap_point = &snap_points[i];
+	}
+
+	return best_snap_point;
+}
+
 /** while dragging */
 static void CalcRaildirsDrawstyle(int x, int y, int method)
 {
@@ -2902,32 +3232,83 @@
 		}
 	}
 
-	if (_settings_client.gui.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;
-		uint64 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 = CeilDiv(distance, 2);
-			}
-
-			params[index++] = distance;
-			if (heightdiff != 0) params[index++] = heightdiff;
-		}
-
-		ShowMeasurementTooltips(measure_strings_length[index], index, params);
-	}
-
 	_thd.selend.x = x;
 	_thd.selend.y = y;
+	_thd.dir2 = HT_DIR_END;
 	_thd.next_drawstyle = b;
+
+	ShowLengthMeasurement(b, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
+}
+
+static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging)
+{
+	RailSnapMode snap_mode = GetRailSnapMode();
+
+	/* are we only within one tile? */
+	if (snap_mode == RSM_SNAP_TO_TILE && GetRailSnapTile() == TileVirtXY(pt.x, pt.y)) {
+		_thd.selend.x = pt.x;
+		_thd.selend.y = pt.y;
+		return GetAutorailHT(pt.x, pt.y);
+	}
+
+	/* find the best track */
+	Polyline line;
+
+	bool lock_snapping = dragging && snap_mode == RSM_SNAP_TO_RAIL;
+	if (!lock_snapping) _current_snap_lock.x = -1;
+
+	const LineSnapPoint *snap_point;
+	if (_current_snap_lock.x != -1) {
+		snap_point = FindBestPolyline(pt, &_current_snap_lock, 1, &line);
+	} else if (snap_mode == RSM_SNAP_TO_TILE) {
+		snap_point = FindBestPolyline(pt, _tile_snap_points.Begin(), _tile_snap_points.Length(), &line);
+	} else {
+		assert(snap_mode == RSM_SNAP_TO_RAIL);
+		snap_point = FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line);
+	}
+
+	if (snap_point == NULL) return HT_NONE; // no match
+
+	if (lock_snapping && _current_snap_lock.x == -1) {
+		/* lock down the snap point */
+		_current_snap_lock = *snap_point;
+		_current_snap_lock.dirs &= (1 << line.first_dir) | (1 << ReverseDir(line.first_dir));
+	}
+
+	TileIndexDiffC first_dir = TileIndexDiffCByDir(line.first_dir);
+	_thd.selstart.x  = line.start.x;
+	_thd.selstart.y  = line.start.y;
+	_thd.selend.x    = _thd.selstart.x + line.first_len * first_dir.x * (IsDiagonalDirection(line.first_dir) ? TILE_SIZE : TILE_SIZE / 2);
+	_thd.selend.y    = _thd.selstart.y + line.first_len * first_dir.y * (IsDiagonalDirection(line.first_dir) ? TILE_SIZE : TILE_SIZE / 2);
+	_thd.selstart2.x = _thd.selend.x;
+	_thd.selstart2.y = _thd.selend.y;
+	_thd.selstart.x  += first_dir.x;
+	_thd.selstart.y  += first_dir.y;
+	_thd.selend.x    -= first_dir.x;
+	_thd.selend.y    -= first_dir.y;
+	Trackdir seldir = PointDirToTrackdir(_thd.selstart, line.first_dir);
+	_thd.selstart.x  &= ~TILE_UNIT_MASK;
+	_thd.selstart.y  &= ~TILE_UNIT_MASK;
+
+	if (line.second_len != 0) {
+		TileIndexDiffC second_dir = TileIndexDiffCByDir(line.second_dir);
+		_thd.selend2.x   = _thd.selstart2.x + line.second_len * second_dir.x * (IsDiagonalDirection(line.second_dir) ? TILE_SIZE : TILE_SIZE / 2);
+		_thd.selend2.y   = _thd.selstart2.y + line.second_len * second_dir.y * (IsDiagonalDirection(line.second_dir) ? TILE_SIZE : TILE_SIZE / 2);
+		_thd.selstart2.x += second_dir.x;
+		_thd.selstart2.y += second_dir.y;
+		_thd.selend2.x   -= second_dir.x;
+		_thd.selend2.y   -= second_dir.y;
+		Trackdir seldir2 = PointDirToTrackdir(_thd.selstart2, line.second_dir);
+		_thd.selstart2.x &= ~TILE_UNIT_MASK;
+		_thd.selstart2.y &= ~TILE_UNIT_MASK;
+		_thd.dir2 = (HighLightStyle)TrackdirToTrack(seldir2);
+	} else {
+		_thd.dir2 = HT_DIR_END;
+	}
+
+	HighLightStyle ret = HT_LINE | (HighLightStyle)TrackdirToTrack(seldir);
+	ShowLengthMeasurement(ret, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), TCC_HOVER, true);
+	return ret;
 }
 
 /**
@@ -2947,6 +3328,12 @@
 		return;
 	}
 
+	if ((_thd.place_mode & HT_POLY) && GetRailSnapMode() != RSM_NO_SNAP) {
+		Point pt = { x, y };
+		_thd.next_drawstyle = CalcPolyrailDrawstyle(pt, true);
+		return;
+	}
+
 	/* Special handling of drag in any (8-way) direction */
 	if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) {
 		_thd.selend.x = x;
@@ -2999,27 +3386,12 @@
 				x = sx + Clamp(x - sx, -limit, limit);
 				y = sy + Clamp(y - sy, -limit, limit);
 			}
-			if (_settings_client.gui.measure_tooltip) {
-				TileIndex t0 = TileVirtXY(sx, sy);
-				TileIndex t1 = TileVirtXY(x, y);
-				uint distance = DistanceManhattan(t0, t1) + 1;
-				byte index = 0;
-				uint64 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;
-				}
-
-				ShowMeasurementTooltips(measure_strings_length[index], index, params);
-			}
+			/* 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; */
+			ShowLengthMeasurement(HT_LINE | style, TileVirtXY(sx, sy), TileVirtXY(x, y));
 			break;
 
 		case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area.
@@ -3029,9 +3401,10 @@
 			/* FALL THROUGH */
 
 		case VPM_X_AND_Y: // drag an X by Y area
-			if (_settings_client.gui.measure_tooltip) {
+			if (_settings_client.gui.measure_tooltip || _thd.select_proc == DDSP_MEASURE) {
 				static const StringID measure_strings_area[] = {
-					STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
+					STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF,
+					STR_MEASURE_DIST_HEIGHTDIFF,
 				};
 
 				TileIndex t0 = TileVirtXY(sx, sy);
@@ -3039,7 +3412,7 @@
 				uint dx = Delta(TileX(t0), TileX(t1)) + 1;
 				uint dy = Delta(TileY(t0), TileY(t1)) + 1;
 				byte index = 0;
-				uint64 params[3];
+				uint64 params[4];
 
 				/* 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 */
@@ -3086,7 +3459,13 @@
 
 					params[index++] = dx - (style & HT_POINT ? 1 : 0);
 					params[index++] = dy - (style & HT_POINT ? 1 : 0);
-					if (heightdiff != 0) params[index++] = heightdiff;
+
+					if (_thd.select_proc == DDSP_MEASURE) {
+						params[index++] = sqrtl(dx * dx + dy * dy);
+					}
+
+					if (heightdiff != 0 || index == 3)
+						params[index++] = heightdiff;
 				}
 
 				ShowMeasurementTooltips(measure_strings_area[index], index, params);
@@ -3098,6 +3477,7 @@
 
 	_thd.selend.x = x;
 	_thd.selend.y = y;
+	_thd.dir2 = HT_DIR_END;
 }
 
 /**
@@ -3115,11 +3495,10 @@
 		return ES_HANDLED;
 	}
 
-	/* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
-	if (_left_button_down) {
-		w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
-		return ES_HANDLED;
-	}
+	/* While dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ).
+	 * Do it even if the button is no longer pressed to make sure that OnPlaceDrag was called at least once. */
+	w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
+	if (_left_button_down) return ES_HANDLED;
 
 	/* mouse button released..
 	 * keep the selected tool, but reset it to the original mode. */
@@ -3130,24 +3509,22 @@
 	} else if (_thd.select_method & VPM_SIGNALDIRS) {
 		_thd.place_mode = HT_RECT | others;
 	} else if (_thd.select_method & VPM_RAILDIRS) {
-		_thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others);
+		_thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS ? _thd.next_drawstyle : HT_RAIL) | others;
 	} else {
 		_thd.place_mode = HT_POINT | others;
 	}
 	SetTileSelectSize(1, 1);
 
+	if (_thd.place_mode & HT_POLY) {
+		if (GetRailSnapMode() == RSM_SNAP_TO_TILE) SetRailSnapMode(RSM_NO_SNAP);
+		if (_thd.drawstyle == HT_NONE) return ES_HANDLED;
+	}
+
 	w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
 
 	return ES_HANDLED;
 }
 
-/**
- * Change the cursor and mouse click/drag handling to a mode for performing special operations like tile area selection, object placement, etc.
- * @param icon New shape of the mouse cursor.
- * @param pal Palette to use.
- * @param mode Mode to perform.
- * @param w %Window requesting the mode change.
- */
 void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
 {
 	SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number);
@@ -3155,14 +3532,6 @@
 
 #include "table/animcursors.h"
 
-/**
- * Change the cursor and mouse click/drag handling to a mode for performing special operations like tile area selection, object placement, etc.
- * @param icon New shape of the mouse cursor.
- * @param pal Palette to use.
- * @param mode Mode to perform.
- * @param window_class %Window class of the window requesting the mode change.
- * @param window_num Number of the window in its class requesting the mode change.
- */
 void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
 {
 	if (_thd.window_class != WC_INVALID) {
@@ -3199,6 +3568,10 @@
 		VpStartPreSizing();
 	}
 
+	if (mode & HT_POLY) {
+		SetRailSnapMode((mode & HT_NEW_POLY) == HT_NEW_POLY ? RSM_NO_SNAP : RSM_SNAP_TO_RAIL);
+	}
+
 	if ((icon & ANIMCURSOR_FLAG) != 0) {
 		SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]);
 	} else {
@@ -3207,7 +3580,6 @@
 
 }
 
-/** Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows). */
 void ResetObjectToPlace()
 {
 	SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
@@ -3250,3 +3622,116 @@
 	}
 	assert(_vp_sprite_sorter != NULL);
 }
+
+static LineSnapPoint LineSnapPointAtRailTrackEndpoint(TileIndex tile, DiagDirection exit_dir, bool bidirectional)
+{
+	LineSnapPoint ret;
+	ret.x = (TILE_SIZE / 2) * (uint)(2 * TileX(tile) + TileIndexDiffCByDiagDir(exit_dir).x + 1);
+	ret.y = (TILE_SIZE / 2) * (uint)(2 * TileY(tile) + TileIndexDiffCByDiagDir(exit_dir).y + 1);
+
+	ret.dirs = 0;
+	SetBit(ret.dirs, DiagDirToDir(exit_dir));
+	SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45LEFT));
+	SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45RIGHT));
+	if (bidirectional) ret.dirs |= ROR<uint8>(ret.dirs, DIRDIFF_REVERSE);
+
+	return ret;
+}
+
+/**
+ * Store the position of lastly built rail track; for highlighting purposes.
+ *
+ * In "polyline" highlighting mode, the stored end point will be used as a snapping point for new
+ * tracks allowing to place multi-segment polylines.
+ *
+ * @param start_tile         tile where the track starts
+ * @param end_tile           tile where the track ends
+ * @param start_track        track piece on the start_tile
+ * @param bidirectional_exit whether to allow to highlight next track in any direction; otherwise new track will have to fallow the stored one (usefull when placing tunnels and bridges)
+ */
+void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional_exit)
+{
+	if (start_tile != INVALID_TILE && end_tile != INVALID_TILE) {
+		/* calculate trackdirs at booth ends of the track */
+		Trackdir exit_trackdir_at_start = TrackToTrackdir(start_track);
+		Trackdir exit_trackdir_at_end = ReverseTrackdir(TrackToTrackdir(start_track));
+		if (start_tile != end_tile) { // multi-tile case
+			/* determine proper direction (pointing outside of the track) */
+			uint distance = DistanceManhattan(start_tile, end_tile);
+			if (distance > DistanceManhattan(TileAddByDiagDir(start_tile, TrackdirToExitdir(exit_trackdir_at_start)), end_tile)) {
+				Swap(exit_trackdir_at_start, exit_trackdir_at_end);
+			}
+			/* determine proper track on the end tile - switch between upper/lower or left/right based on the length */
+			if (distance % 2 != 0) exit_trackdir_at_end = NextTrackdir(exit_trackdir_at_end);
+		}
+
+		LineSnapPoint snap_start = LineSnapPointAtRailTrackEndpoint(start_tile, TrackdirToExitdir(exit_trackdir_at_start), bidirectional_exit);
+		LineSnapPoint snap_end = LineSnapPointAtRailTrackEndpoint(end_tile, TrackdirToExitdir(exit_trackdir_at_end), bidirectional_exit);
+		/* Find if we already had these coordinates before. */
+		LineSnapPoint *snap;
+		bool had_start = false;
+		bool had_end = false;
+		for (snap = _rail_snap_points.Begin(); snap != _rail_snap_points.End(); snap++) {
+			had_start |= (snap->x == snap_start.x && snap->y == snap_start.y);
+			had_end |= (snap->x == snap_end.x && snap->y == snap_end.y);
+		}
+		/* Create new snap point set. */
+		if (had_start && had_end) {
+			/* just stop snaping, don't forget snap points */
+			SetRailSnapMode(RSM_NO_SNAP);
+		} else {
+			/* include only new points */
+			_rail_snap_points.Clear();
+			if (!had_start) *_rail_snap_points.Append() = snap_start;
+			if (!had_end) *_rail_snap_points.Append() = snap_end;
+			SetRailSnapMode(RSM_SNAP_TO_RAIL);
+		}
+	}
+}
+
+bool CurrentlySnappingRailPlacement()
+{
+	return (_thd.place_mode & HT_POLY) && GetRailSnapMode() == RSM_SNAP_TO_RAIL;
+}
+
+static RailSnapMode GetRailSnapMode()
+{
+	if (_rail_snap_mode == RSM_SNAP_TO_TILE && _tile_snap_points.Length() == 0) return RSM_NO_SNAP;
+	if (_rail_snap_mode == RSM_SNAP_TO_RAIL && _rail_snap_points.Length() == 0) return RSM_NO_SNAP;
+	return _rail_snap_mode;
+}
+
+static void SetRailSnapMode(RailSnapMode mode)
+{
+	_rail_snap_mode = mode;
+
+	if ((_thd.place_mode & HT_POLY) && (GetRailSnapMode() == RSM_NO_SNAP)) {
+		SetTileSelectSize(1, 1);
+	}
+}
+
+static TileIndex GetRailSnapTile()
+{
+	if (_tile_snap_points.Length() == 0) return INVALID_TILE;
+	return TileVirtXY(_tile_snap_points[DIAGDIR_NE].x, _tile_snap_points[DIAGDIR_NE].y);
+}
+
+static void SetRailSnapTile(TileIndex tile)
+{
+	_tile_snap_points.Clear();
+	if (tile == INVALID_TILE) return;
+
+	for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
+		LineSnapPoint *point = _tile_snap_points.Append();
+		*point = LineSnapPointAtRailTrackEndpoint(tile, dir, false);
+		point->dirs = ROR<uint8>(point->dirs, DIRDIFF_REVERSE);
+	}
+}
+
+void ResetRailPlacementSnapping()
+{
+	_rail_snap_mode = RSM_NO_SNAP;
+	_tile_snap_points.Clear();
+	_rail_snap_points.Clear();
+	_current_snap_lock.x = -1;
+}
diff -r e16bdc0054ce src/viewport_func.h
--- a/src/viewport_func.h
+++ b/src/viewport_func.h
@@ -59,7 +59,7 @@
 void StartSpriteCombine();
 void EndSpriteCombine();
 
-bool HandleViewportClicked(const ViewPort *vp, int x, int y);
+bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click);
 void SetRedErrorSquare(TileIndex tile);
 void SetTileSelectSize(int w, int h);
 void SetTileSelectBigSize(int ox, int oy, int sx, int sy);
diff -r e16bdc0054ce src/viewport_gui.cpp
--- a/src/viewport_gui.cpp
+++ b/src/viewport_gui.cpp
@@ -154,6 +154,11 @@
 		/* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
 		HandleZoomMessage(this, this->viewport, WID_EV_ZOOM_IN, WID_EV_ZOOM_OUT);
 	}
+
+	virtual void OnMouseOver(Point pt, int widget)
+	{
+		if (pt.x != -1) GuiPrepareTooltipsExtra(this);
+	}
 };
 
 static WindowDesc _extra_view_port_desc(
diff -r e16bdc0054ce src/viewport_type.h
--- a/src/viewport_type.h
+++ b/src/viewport_type.h
@@ -105,6 +105,7 @@
 	DDSP_CREATE_RIVER,         ///< Create rivers
 	DDSP_PLANT_TREES,          ///< Plant trees
 	DDSP_BUILD_BRIDGE,         ///< Bridge placement
+	DDSP_MEASURE,              ///< Measurement tool
 
 	/* Rail specific actions */
 	DDSP_PLACE_RAIL,           ///< Rail placement
@@ -117,6 +118,7 @@
 	DDSP_PLACE_ROAD_X_DIR,     ///< Road placement (X axis)
 	DDSP_PLACE_ROAD_Y_DIR,     ///< Road placement (Y axis)
 	DDSP_PLACE_AUTOROAD,       ///< Road placement (auto)
+	DDSP_PLACE_FULLROAD,       ///< Road placement (auto, full roads)
 	DDSP_BUILD_BUSSTOP,        ///< Road stop placement (buses)
 	DDSP_BUILD_TRUCKSTOP,      ///< Road stop placement (trucks)
 	DDSP_REMOVE_BUSSTOP,       ///< Road stop removal (buses)
diff -r e16bdc0054ce src/watch_gui.cpp
--- /dev/null
+++ b/src/watch_gui.cpp
@@ -0,0 +1,608 @@
+/* $Id: watch_gui.cpp  17678 2009-10-07 20:54:05  muxy $ */
+
+/** @file watch_gui.cpp GUI that follow other company building. */
+
+#include "stdafx.h"
+#include "watch_gui.h"
+#include "widget_type.h"
+#include "gfx_type.h"
+#include "gfx_func.h"
+#include "company_base.h"
+#include "company_gui.h"
+#include "viewport_func.h"
+#include "window_func.h"
+#include "strings_func.h"
+#include "zoom_func.h"
+#include "map_func.h"
+
+#include "network/network.h"
+#include "network/network_func.h"
+#include "network/network_base.h"
+#include "network/network_gui.h"
+#include "table/sprites.h"
+#include "table/strings.h"
+
+#include "textbuf_gui.h"
+#include "company_gui.h" //company window
+#include "network/network_gui.h" //private message
+#include "console_func.h" //IConsolePrintF
+#include "debug.h"
+/** Make the widgets columns for company button, has_client and activity Blot.
+ * @param biggest_index Storage for collecting the biggest index used in the returned tree.
+ * @return Horizontal container with butons columns.
+ * @post \c *biggest_index contains the largest used index in the tree.
+ */
+static NWidgetBase *MakeCompanyButtons(int *biggest_index)
+{
+	NWidgetHorizontal *widget_container_horiz = NULL;         // Storage for all cols.
+	NWidgetVertical *widget_container_company = NULL;         // Storage for company Col.
+	NWidgetVertical *widget_container_hasclient = NULL;       // Storage for Has Client Blot.
+	// NWidgetVertical *widget_container_activity = NULL;        // Storage for Activity Blot.
+
+	widget_container_horiz = new NWidgetHorizontal( );
+	widget_container_company = new NWidgetVertical( );
+	widget_container_hasclient  = new NWidgetVertical( );
+	// widget_container_activity = new NWidgetVertical( );
+
+	Dimension company_sprite_size = GetSpriteSize( SPR_COMPANY_ICON );
+	company_sprite_size.width  += WD_MATRIX_LEFT + WD_MATRIX_RIGHT;
+	company_sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed
+
+	Dimension blot_sprite_size = GetSpriteSize( SPR_BLOT );
+	blot_sprite_size.width  += WD_MATRIX_LEFT + WD_MATRIX_RIGHT;
+	blot_sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed
+
+
+	for (int company_num = COMPANY_FIRST; company_num < MAX_COMPANIES; company_num++ ) {
+		/* Manage Company Buttons */
+		NWidgetBackground *company_panel = new NWidgetBackground( WWT_PANEL, COLOUR_GREY, EWW_PB_COMPANY_FIRST + company_num );
+		company_panel->SetMinimalSize( company_sprite_size.width, company_sprite_size.height );
+		company_panel->SetResize( 0, 0 );
+		company_panel->SetFill( 1, 0 );
+		company_panel->SetDataTip( 0x0, STR_WATCH_CLICK_TO_WATCH_COMPANY );
+		widget_container_company->Add( company_panel );
+
+		/* Manage Has Client Blot */
+		NWidgetBackground *hasclient_panel = new NWidgetBackground( WWT_PANEL, COLOUR_GREY, EWW_HAS_CLIENT_FIRST + company_num );
+		company_panel->SetMinimalSize( blot_sprite_size.width, blot_sprite_size.height );
+		company_panel->SetResize( 0, 0 );
+		company_panel->SetFill( 1, 0 );
+		widget_container_hasclient->Add( hasclient_panel );
+	}
+
+	/* Add the verticals widgets to the horizontal container */
+	widget_container_horiz->Add( widget_container_company );
+	widget_container_horiz->Add( widget_container_hasclient );
+
+	/* return the horizontal widget container */
+	return widget_container_horiz;
+}
+
+/**
+ * Watch Company Window Widgets Array
+ * The Company Button, Has Client Blot and Activity Blot Columns
+ * Are made through a function regarding MAX_COMPANIES value
+ */
+static const NWidgetPart _nested_watch_company_widgets[] = {
+	/* Title Bar with close box, title, shade and stick boxes */
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY, EWW_CAPTION ), SetDataTip(STR_WATCH_WINDOW_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_GREY),
+		NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer( ),
+	NWidget( NWID_HORIZONTAL ),
+		NWidget( NWID_VERTICAL ),
+			NWidgetFunction( MakeCompanyButtons ),
+			/* Buton Zoom Out, In, Scrollto */
+			NWidget(NWID_HORIZONTAL),
+				NWidget( WWT_PUSHIMGBTN, COLOUR_GREY, EWW_ZOOMOUT ), SetDataTip( SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
+				NWidget( WWT_PUSHIMGBTN, COLOUR_GREY, EWW_ZOOMIN ),  SetDataTip( SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
+				NWidget( WWT_PUSHIMGBTN, COLOUR_GREY, EWW_CENTER ),  SetDataTip( SPR_CENTRE_VIEW_VEHICLE, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT),
+				NWidget( WWT_PANEL, COLOUR_GREY, EWW_NEW_WINDOW ),   SetDataTip( 0, STR_WATCH_CLICK_NEW_WINDOW ), EndContainer( ),
+			EndContainer( ),
+			/* Background panel for resize purpose */
+			NWidget( WWT_PANEL, COLOUR_GREY ), SetResize( 0, 1 ), EndContainer( ),
+		EndContainer( ),
+		/* Watch Pannel */
+		NWidget(WWT_PANEL, COLOUR_GREY),
+			NWidget(NWID_VIEWPORT, INVALID_COLOUR, EWW_WATCH), SetPadding(2, 2, 2, 2), SetResize(1, 1), SetFill(1, 1),
+		EndContainer( ),
+	EndContainer( ),
+	/* Status Bar with resize buton */
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
+		NWidget(WWT_RESIZEBOX, COLOUR_GREY),
+	EndContainer( ),
+};
+
+/**
+ * Watch Company Window Descriptor
+ */
+static WindowDesc _watch_company_desc(
+	WDP_AUTO, "watch_gui", 300, 257,
+	WC_WATCH_COMPANY, WC_NONE,
+	WDF_NO_FOCUS,
+	_nested_watch_company_widgets, lengthof( _nested_watch_company_widgets )
+);
+
+// admin version
+static const NWidgetPart _nested_watch_company_widgetsA[] = {
+	/* Title Bar with close box, title, shade and stick boxes */
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY, EWW_CAPTION ), SetDataTip(STR_WATCH_WINDOW_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_GREY),
+		NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget( NWID_HORIZONTAL ),
+		NWidget( NWID_VERTICAL ),
+			/* Buton Zoom Out, In, Scrollto */
+			NWidget(NWID_SELECTION, INVALID_COLOUR, EWW_ENABLE_SELECT),
+				NWidget(NWID_VERTICAL ),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_KICK), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_KICK, 0),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_BAN), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_BAN, 0 ),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_LOCK), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_LOCK, 0),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_UNLOCK), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_UNLOCK, 0),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_JOIN), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_JOIN, 0),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_KICKC), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_KICKC, 0),
+					NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_RESET), SetMinimalSize(40, 20), SetFill(1, 0), SetDataTip(STR_XI_RESET, 0),
+				EndContainer(),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL),
+				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, EWW_ZOOMOUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
+				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, EWW_ZOOMIN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
+				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, EWW_CENTER), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT),
+				NWidget(WWT_PANEL, COLOUR_GREY, EWW_NEW_WINDOW), SetDataTip(0, 0), EndContainer(),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL),
+				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, EWW_CLIENTS), SetMinimalSize(23, 10), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_XI_PLAYERS_TOOLTIP),
+				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, EWW_COMPANYW), SetMinimalSize(23, 10), SetDataTip(SPR_IMG_COMPANY_LIST, STR_XI_COMPANYW_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_COMPANYHQ), SetMinimalSize(23, 10), SetDataTip(STR_XI_COMPANYHQ, STR_XI_COMPANYHQ_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_PRIVATEP_MESSAGE), SetMinimalSize(23, 10), SetDataTip(STR_XI_PRIVATE_PLAYER_MESSAGE, STR_XI_PRIVATE_PLAYER_MESSAGE_TOOLTIP),
+				NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, EWW_PRIVATEC_MESSAGE), SetMinimalSize(23, 10), SetDataTip(STR_XI_PRIVATE_COMPANY_MESSAGE, STR_XI_PRIVATE_COMPANY_MESSAGE_TOOLTIP),
+				NWidget(WWT_PANEL, COLOUR_GREY, EWW_NEW_WINDOW), SetDataTip(0, 0), EndContainer(),
+			EndContainer(),
+			/* Background panel for resize purpose */
+			NWidget(WWT_PANEL, COLOUR_GREY), SetResize(0, 1), EndContainer(),
+		EndContainer(),
+		/* Watch Pannel */
+		NWidget(WWT_PANEL, COLOUR_GREY),
+			NWidget(NWID_VIEWPORT, INVALID_COLOUR, EWW_WATCH), SetPadding(2, 2, 2, 2), SetResize(1, 1), SetFill(1, 1),
+		EndContainer(),
+	EndContainer(),
+	/* Status Bar with resize buton */
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
+		NWidget(WWT_RESIZEBOX, COLOUR_GREY),
+	EndContainer(),
+};
+
+/**
+ * Watch Company Window Descriptor
+ */
+static WindowDesc _watch_company_descA(
+	WDP_AUTO, "watch_gui_client", 448, 256,
+	WC_WATCH_COMPANYA, WC_NONE,
+	WDF_CONSTRUCTION,
+	_nested_watch_company_widgetsA, lengthof(_nested_watch_company_widgetsA)
+);
+
+static void ResetCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)w->window_number);
+		if (ci && ci->client_playas != INVALID_COMPANY) {
+			char msg[16];
+			seprintf(msg, lastof(msg), "!reset %i", ci->client_playas + 1);
+			NetworkClientSendChatToServer(msg);
+		}
+	}
+}
+
+/** Watch Company Class Constructor
+ * @param desc Window Descriptor The Window Descriptor
+ * @param window_number The window number for the class
+ * @param company_to_watch Company ID for watching a particular company
+ */
+WatchCompany::WatchCompany(WindowDesc *desc, int window_number, CompanyID company_to_watch = INVALID_COMPANY, int Wtype = EWT_COMPANY) : Window(desc)
+{
+	this->Wtype = Wtype;
+	if(this->Wtype == EWT_CLIENT){
+		this->watched_client = window_number;
+		NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)this->watched_client);
+
+		this->watched_company = (ci != NULL) ? ci->client_playas : INVALID_COMPANY;
+		this->InitNested(window_number);
+		this->owner = (Owner)this->watched_company;
+	}
+	else if(this->Wtype == EWT_COMPANY){
+
+		this->watched_company = company_to_watch;
+
+		this->InitNested(window_number);
+		this->owner = this->watched_company;
+
+		/* Reset activity and client count for all companies */
+		for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
+			this->company_activity[i] = 0;
+			this->company_count_client[i] = 0;
+		}
+
+		GetString( this->company_name, STR_JUST_NOTHING, lastof(this->company_name) );
+	}
+	/* Init the viewport area */
+	NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(EWW_WATCH);
+	nvp->InitializeViewport(this, 0, ZOOM_LVL_NORMAL);
+
+	Point pt;
+	/* the main window with the main view */
+	const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+
+	/* center on same place as main window (zoom is maximum, no adjustment needed) */
+	pt.x = w->viewport->scrollpos_x + w->viewport->virtual_width / 2;
+	pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2;
+
+	this->viewport->scrollpos_x = pt.x - this->viewport->virtual_width / 2;
+	this->viewport->scrollpos_y = pt.y - this->viewport->virtual_height / 2;
+	this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+	this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+
+	if ( this->watched_company != INVALID_COMPANY ) {
+		Company *c = Company::Get( this->watched_company );
+		this->ScrollToTile( c->last_build_coordinate );
+	}
+	this->InvalidateData( );
+}
+
+void WatchCompany::SetStringParameters(int widget) const
+{
+	if(widget != EWW_CAPTION) return;
+	if(this->Wtype == EWT_COMPANY){
+		SetDParamStr(0, this->company_name);
+		return;
+	}
+	//EWT_CLIENT
+	if (!Company::IsValidHumanID(this->watched_company)){
+		// GetString((char *)this->company_name, STR_JUST_NOTHING, lastof(this->company_name));
+	}
+	else {
+		const Company *c = Company::Get(this->watched_company);
+		SetDParam(0, c->index);
+		// GetString((char *)this->company_name, STR_COMPANY_NAME, lastof(this->company_name));
+	}
+	NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)this->watched_client);
+	if(ci){
+		// strecpy((char *)this->client_name, ci->client_name, lastof(this->client_name));
+	}
+	else{
+		// GetString((char *)this->client_name, STR_JUST_NOTHING, lastof(this->client_name));
+	}
+	SetDParamStr(0, this->client_name);
+	SetDParamStr(1, this->company_name);
+	if (Company::IsValidHumanID(this->watched_company)){
+		SetDParam(2, this->watched_company + 1);
+	}
+	else {
+		SetDParam(2, COMPANY_SPECTATOR);
+	}
+}
+
+void WatchCompany::OnPaint()
+{
+	if(this->Wtype == EWT_CLIENT){
+		bool wstate = this->watched_company == INVALID_COMPANY ? true : false;
+		for(int i = EWW_LOCK; i <= EWW_COMPANYW; i++){
+			this->SetWidgetDisabledState(i, wstate);
+		}
+	}
+
+	this->DrawWidgets();
+}
+
+void WatchCompany::DrawWidget(const Rect &r, int widget) const
+{
+	if(this->Wtype != EWT_COMPANY) return;
+	/* draw the widget */
+	/* Company Button */
+	if (IsInsideMM(widget, EWW_PB_COMPANY_FIRST, EWW_PB_COMPANY_LAST + 1)) {
+		if (this->IsWidgetDisabled(widget)) return;
+		if ( Company::IsValidID( widget - EWW_PB_COMPANY_FIRST ) ) {
+		    CompanyID cid = (CompanyID)(widget - ( EWW_PB_COMPANY_FIRST ) );
+		    int offset = (cid == this->watched_company) ? 1 : 0;
+		    Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON);
+		    DrawCompanyIcon(cid, (r.left + r.right - sprite_size.width) / 2 + offset, (r.top + r.bottom - sprite_size.height) / 2 + offset);
+		}
+		return;
+	}
+	/* Has Client Blot */
+	if (IsInsideMM( widget, EWW_HAS_CLIENT_FIRST, EWW_HAS_CLIENT_LAST + 1 )) {
+		if ( Company::IsValidID( widget-EWW_HAS_CLIENT_FIRST ) ) {
+			/* Draw the Blot only if Company Exists */
+			Dimension sprite_size = GetSpriteSize(SPR_BLOT);
+#ifdef ENABLE_NETWORK
+			if (!_networking) { // Local game, draw the Blot
+				DrawSprite(SPR_BLOT, Company::IsValidAiID(widget - EWW_HAS_CLIENT_FIRST) ? PALETTE_TO_ORANGE : PALETTE_TO_GREEN, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 );
+			} else { // Network game, draw the blot according to company client count
+				DrawSprite(SPR_BLOT, this->company_count_client[widget-EWW_HAS_CLIENT_FIRST] > 0 ? (company_activity[widget-EWW_HAS_CLIENT_FIRST] > 0 ? PALETTE_TO_RED : PALETTE_TO_GREEN) : PALETTE_TO_GREY, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 );
+			}
+#else
+			DrawSprite(SPR_BLOT, Company::IsValidAiID(widget-EWW_HAS_CLIENT_FIRST) ? PALETTE_TO_ORANGE : PALETTE_TO_GREEN, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 );
+#endif
+		}
+	}
+}
+
+void WatchCompany::OnResize()
+{
+	if (this->viewport != NULL) {
+		NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(EWW_WATCH);
+		nvp->UpdateViewportCoordinates(this);
+	}
+}
+
+void WatchCompany::OnScroll(Point delta)
+{
+	const ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
+	if (vp == NULL) return;
+
+	this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
+	this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
+	this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+	this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+}
+
+void WatchCompany::OnMouseWheel( int wheel )
+{
+	ZoomInOrOutToCursorWindow(wheel < 0, this);
+}
+
+void WatchCompany::OnClick(Point pt, int widget, int click_count)
+{
+	if (IsInsideMM(widget, EWW_PB_COMPANY_FIRST, EWW_PB_COMPANY_LAST + 1)) {
+		/* Click on Company Button */
+		if (!this->IsWidgetDisabled(widget)) {
+			if (this->watched_company != INVALID_COMPANY) {
+				/* Raise the watched company button  */
+				this->RaiseWidget(this->watched_company + EWW_PB_COMPANY_FIRST);
+			}
+			if (this->watched_company == (CompanyID)(widget - EWW_PB_COMPANY_FIRST)) {
+				/* Stop watching watched_company */
+				this->watched_company = INVALID_COMPANY;
+                                GetString( this->company_name, STR_JUST_NOTHING, lastof(this->company_name) );
+			} else {
+				/* Lower the new watched company button */
+				this->watched_company = (CompanyID)(widget - EWW_PB_COMPANY_FIRST);
+				this->LowerWidget(this->watched_company + EWW_PB_COMPANY_FIRST);
+				Company *c = Company::Get( this->watched_company );
+				SetDParam( 0, c->index );
+				GetString( this->company_name, STR_COMPANY_NAME, lastof(this->company_name) );
+
+				this->ScrollToTile( c->last_build_coordinate );
+			}
+			this->owner = this->watched_company;
+			this->SetDirty();
+		}
+	}
+	else if ( IsInsideMM(widget, EWW_PB_ACTION1_FIRST, EWW_PB_ACTION1_LAST + 1)) {
+		if ( !this->IsWidgetDisabled(widget) ) {
+			this->ToggleWidgetLoweredState( widget );
+			this->SetDirty();
+		}
+	}
+#ifdef ENABLE_NETWORK
+	else if ( IsInsideMM(widget, EWW_HAS_CLIENT_FIRST, EWW_HAS_CLIENT_LAST + 1)) {
+		if(_networking && Company::IsValidID(widget - EWW_HAS_CLIENT_FIRST)){
+			ShowNetworkChatQueryWindow(DESTTYPE_TEAM, widget - EWW_HAS_CLIENT_FIRST);
+		}
+	}
+#endif
+	else {
+		char msg[128];
+		switch (widget) {
+			case EWW_ZOOMOUT: DoZoomInOutWindow(ZOOM_OUT, this); break;
+			case EWW_ZOOMIN: DoZoomInOutWindow(ZOOM_IN,  this); break;
+			case EWW_CENTER: { // location button (move main view to same spot as this view) 'Center Main View'
+				Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+				int x = this->viewport->scrollpos_x; // Where is the watch looking at
+				int y = this->viewport->scrollpos_y;
+
+				/* set the main view to same location. Based on the center, adjusting for zoom */
+				w->viewport->dest_scrollpos_x =  x - (w->viewport->virtual_width -  this->viewport->virtual_width) / 2;
+				w->viewport->dest_scrollpos_y =  y - (w->viewport->virtual_height - this->viewport->virtual_height) / 2;
+			} break;
+			case EWW_NEW_WINDOW:
+				ShowWatchWindow(this->watched_company, 0);
+				break;
+			case EWW_LOCK:
+			case EWW_UNLOCK:
+				seprintf(msg, lastof(msg), "!lockp %i", this->watched_company + 1);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case EWW_KICK:
+				seprintf(msg, lastof(msg), "!kick %i", this->watched_client);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case EWW_KICKC:
+				seprintf(msg, lastof(msg), "!move %i %i", this->watched_client, COMPANY_SPECTATOR);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case EWW_JOIN:
+				seprintf(msg, lastof(msg), "!move %i", this->watched_company + 1);
+				NetworkClientSendChatToServer(msg);
+				break;
+			case EWW_BAN:
+				this->query_widget = EWQ_BAN;
+				ShowQueryString(STR_XI_BAN_DAYSDEFAULT, STR_XI_BAN_QUERY, 128, this, CS_ALPHANUMERAL, QSF_NONE);
+				break;
+			case EWW_RESET:
+				ShowQuery(STR_XI_RESET_CAPTION, STR_XI_REALY_RESET, this, ResetCallback);
+				break;
+			case EWW_PRIVATEP_MESSAGE:{
+				const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)this->watched_client);
+				if(ci) ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id);
+				break;
+			}
+			case EWW_PRIVATEC_MESSAGE:
+				ShowNetworkChatQueryWindow(DESTTYPE_TEAM, this->watched_company);
+				break;
+			case EWW_CLIENTS:
+				seprintf(msg, lastof(msg), "!clients");
+				NetworkClientSendChatToServer(msg);
+				break;
+			case EWW_COMPANYW:
+				if(this->watched_company != INVALID_COMPANY) ShowCompany(this->watched_company);
+				break;
+			case EWW_COMPANYHQ:
+				if(this->watched_company != INVALID_COMPANY){
+					TileIndex tile = Company::Get((CompanyID)this->watched_company)->location_of_HQ;
+					ScrollMainWindowToTile(tile);
+				}
+				break;
+		}
+	}
+}
+
+void WatchCompany::OnQueryTextFinished(char *str)
+{
+	if (str == NULL) return;
+	char msg[128];
+	switch (this->query_widget) {
+		case EWQ_BAN:
+			seprintf(msg, lastof(msg), "!ban %i %s", this->watched_client, str);
+			NetworkClientSendChatToServer(msg);
+			break;
+	}
+}
+
+void WatchCompany::OnInvalidateData(int data, bool gui_scope)
+{
+	if(this->Wtype == EWT_COMPANY){
+		/* Disable the companies who are not active */
+		for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
+			this->SetWidgetDisabledState(EWW_PB_COMPANY_FIRST + i , !Company::IsValidID(i) );
+			this->SetWidgetDisabledState(EWW_PB_ACTION1_FIRST + i , !Company::IsValidID(i) );
+		}
+		/* Check if the currently selected company is still active. */
+		if (this->watched_company != INVALID_COMPANY) {
+			/* Make sure the widget is lowered */
+			this->LowerWidget(EWW_PB_COMPANY_FIRST + this->watched_company);
+			/* Check if the watched Company is still a valid one */
+			if (!Company::IsValidID(this->watched_company)) {
+				/* Invalid Company Raise the associated widget. */
+				this->RaiseWidget(this->watched_company + EWW_PB_COMPANY_FIRST );
+				this->watched_company = INVALID_COMPANY;
+				GetString( this->company_name, STR_JUST_NOTHING, lastof(this->company_name) );
+			} else {
+				Company *c = Company::Get( this->watched_company );
+				SetDParam( 0, c->index );
+				GetString( this->company_name, STR_COMPANY_NAME, lastof(this->company_name) );
+			}
+		} else {
+			GetString( this->company_name, STR_JUST_NOTHING, lastof(this->company_name) );
+
+		}
+	#ifdef ENABLE_NETWORK
+		if (_networking) { // Local game, draw the Blot
+			/* Reset company count - network only */
+			for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
+				this->company_count_client[i] = 0;
+			}
+			/* Calculate client count into company - network only */
+			NetworkClientInfo *ci;
+			FOR_ALL_CLIENT_INFOS( ci ) {
+				if (Company::IsValidID(ci->client_playas)) {
+					company_count_client[ci->client_playas] += 1;
+				}
+			}
+		}
+	#endif
+	}
+	else if(this->Wtype == EWT_CLIENT){
+		if (data == 2) {
+			delete this;
+			return;
+		}
+		NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)this->watched_client);
+		if (!ci) {
+			delete this;
+			return;
+		}
+		else {
+			this->watched_company = ci->client_playas;
+			this->owner = (Owner)this->watched_company;
+			bool wstate = this->watched_company == INVALID_COMPANY ? true : false;
+			for(int i = EWW_LOCK; i <= EWW_COMPANYW; i++){
+				this->SetWidgetDisabledState(i, wstate);
+			}
+		}
+	}
+	HandleZoomMessage(this, this->viewport, EWW_ZOOMIN, EWW_ZOOMOUT);
+}
+
+void WatchCompany::ScrollToTile( TileIndex tile )
+{
+	/* Scroll window to the tile, only if not zero */
+	if (tile != 0) {
+		ScrollWindowTo( TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, this );
+	}
+}
+
+/** OnDoCommand function - Called by the DoCommand
+ *  @param company The company ID who's client is building
+ *  @param tile The tile number where action took place
+ */
+void WatchCompany::OnDoCommand( CompanyByte company, TileIndex tile )
+{
+	/* Check if its my company */
+	if (this->watched_company == company)
+	{
+		this->ScrollToTile(tile);
+	}
+	/* set the company_activity to its max in order to paint the BLOT in red
+	 * This will result by having the activity blot set to red for all companies
+	 * even the one watched. To avoid this behaviour and not to light the blot of
+	 * the watched company, the code can be moved just after the ScrollToTile call.
+	 */
+	if (tile != 0) {
+		this->company_activity[company] = MAX_ACTIVITY;
+		this->SetDirty( );
+	}
+}
+
+/** Used to decrement the activity counter
+ *
+ */
+void WatchCompany::OnTick()
+{
+	bool set_dirty = false;
+	for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
+		if ( this->company_activity[i]>0 ) {
+			this->company_activity[i]--;
+			if ( this->company_activity[i]==0 ) {
+				set_dirty = true;
+			}
+		}
+	}
+	/* If one company_activity reaches 0, then redraw */
+	if (set_dirty) {
+		this->SetDirty();
+	}
+}
+
+void ShowWatchWindow(CompanyID company_to_watch = INVALID_COMPANY, int type = EWT_COMPANY)
+{
+	if(type == EWT_COMPANY || !_novarole){
+		int i = 0;
+		/* find next free window number for watch viewport */
+		while (FindWindowById(WC_WATCH_COMPANY, i) != NULL) i++;
+		new WatchCompany(&_watch_company_desc, i, company_to_watch, type);
+	}
+	else if(type == EWT_CLIENT){
+		if (BringWindowToFrontById(WC_WATCH_COMPANYA, company_to_watch)) return;
+		new WatchCompany(&_watch_company_descA, company_to_watch, company_to_watch, type);
+	}
+}
+
diff -r e16bdc0054ce src/watch_gui.h
--- /dev/null
+++ b/src/watch_gui.h
@@ -0,0 +1,91 @@
+/* $Id: watch_gui.h 17678 2009-10-07 20:54:05  muxy $ */
+
+/** @file watch_gui.h GUI Functions related to watching. */
+
+#ifndef WATCH_GUI_H
+#define WATCH_GUI_H
+
+#include "window_gui.h"
+#include "company_base.h"
+
+#define MAX_ACTIVITY 30
+
+enum WatchCompanyWidgets {
+	EWW_CAPTION,
+	EWW_PB_COMPANY_FIRST,
+	EWW_PB_COMPANY_LAST  = EWW_PB_COMPANY_FIRST + MAX_COMPANIES - 1,
+	EWW_HAS_CLIENT_FIRST,
+	EWW_HAS_CLIENT_LAST = EWW_HAS_CLIENT_FIRST + MAX_COMPANIES - 1,
+	EWW_ACTIVITY_FIRST,
+	EWW_ACTIVITY_LAST = EWW_ACTIVITY_FIRST + MAX_COMPANIES - 1,
+	EWW_PB_ACTION1_FIRST,
+	EWW_PB_ACTION1_LAST = EWW_PB_ACTION1_FIRST + MAX_COMPANIES - 1,
+	EWW_WATCH,
+	EWW_ZOOMIN,
+	EWW_ZOOMOUT,
+	EWW_CENTER,
+	EWW_NEW_WINDOW,
+
+	EWW_KICK,
+	EWW_BAN,
+	EWW_BAN1,
+	EWW_LOCK,
+	EWW_UNLOCK,
+	EWW_JOIN,
+	EWW_KICKC,
+	EWW_RESET,
+	EWW_COMPANYW,
+	EWW_COMPANYHQ,
+	EWW_PRIVATEP_MESSAGE,
+	EWW_PRIVATEC_MESSAGE,
+	EWW_CLIENTS,
+	EWW_ENABLE_SELECT,
+};
+
+enum WatchCompanyQuery {
+	EWQ_BAN = 0,
+	EWQ_BAN1,
+};
+
+enum WatchCompanyType {
+	EWT_COMPANY = 0,
+	EWT_CLIENT,
+};
+
+class WatchCompany : public Window
+{
+protected:
+	CompanyID watched_company;                            // Company ID beeing watched.
+	int company_activity[MAX_COMPANIES];                  // int array for activity blot.
+	int company_count_client[MAX_COMPANIES];              // company client count.
+	char company_name[MAX_LENGTH_COMPANY_NAME_CHARS];     // company name for title display
+	char client_name[NETWORK_CLIENT_NAME_LENGTH];
+
+	int watched_client;
+	WatchCompanyQuery query_widget;
+	int Wtype;
+
+	void SetWatchWindowTitle( );
+	void ScrollToTile( TileIndex tile );
+
+public:
+	WatchCompany(WindowDesc *desc, int window_number, CompanyID company_to_watch, int Wtype);
+
+	virtual void DrawWidget(const Rect &r, int widget) const;
+	virtual void OnClick(Point pt, int widget, int click_count);
+	virtual void OnResize();
+	virtual void OnScroll(Point delta);
+	virtual void OnMouseWheel(int wheel);
+	virtual void OnInvalidateData(int data, bool gui_scope);
+	virtual void SetStringParameters(int widget) const;
+	virtual void OnTick();
+	virtual void OnPaint();
+	virtual void OnQueryTextFinished(char *str);
+
+	void OnDoCommand(CompanyByte company, TileIndex tile);
+};
+
+void ShowWatchWindow(CompanyID company_to_watch, int type);
+
+#endif // COMPANY_GUI_H
+
diff -r e16bdc0054ce src/widget.cpp
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -217,8 +217,9 @@
  */
 static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img)
 {
-	assert(img != 0);
+
 	DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
+	if (img == 0) return;
 
 	if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2.
 	DrawSprite(img, PAL_NONE, r.left + WD_IMGBTN_LEFT + clicked, r.top + WD_IMGBTN_TOP + clicked);
diff -r e16bdc0054ce src/widgets/cargo_table_widget.h
--- /dev/null
+++ b/src/widgets/cargo_table_widget.h
@@ -0,0 +1,20 @@
+/* $Id: cargo_table_widget.h 23600 2011-12-19 20:46:17Z TheDude $ */
+
+/** @file cargo_table_widget.h Types related to the cargos widgets. */
+
+#ifndef WIDGETS_CARGO_TABLE_WIDGET_H
+#define WIDGETS_CARGO_TABLE_WIDGET_H
+
+/** Widgets of the #CargosWindow class. */
+enum CargosWidgets {
+	WID_CT_BACKGROUND,  ///< Caption of the window.
+	WID_CT_CAPTION,
+	WID_CT_HEADER_CARGO,
+	WID_CT_HEADER_AMOUNT,
+	WID_CT_HEADER_INCOME,
+	WID_CT_LIST,
+	WID_CT_AMOUNT,
+	WID_CT_INCOME,
+};
+
+#endif /* WIDGETS_CARGO_TABLE_WIDGET_H */
diff -r e16bdc0054ce src/widgets/company_widget.h
--- a/src/widgets/company_widget.h
+++ b/src/widgets/company_widget.h
@@ -52,6 +52,12 @@
 	WID_C_SELECT_MULTIPLAYER,         ///< Multiplayer selection panel.
 	WID_C_COMPANY_PASSWORD,           ///< Button to set company password.
 	WID_C_COMPANY_JOIN,               ///< Button to join company.
+
+	WID_C_SELECT_MOD,
+	WID_C_SELECT_MOD_JOIN,
+	WID_C_MOD_COMPANY_JOIN,
+	WID_C_MOD_COMPANY_RESET,
+	WID_C_MOD_COMPANY_TOGGLE_LOCK,
 };
 
 /** Widgets of the #CompanyFinancesWindow class. */
diff -r e16bdc0054ce src/widgets/dropdown.cpp
--- a/src/widgets/dropdown.cpp
+++ b/src/widgets/dropdown.cpp
@@ -42,7 +42,12 @@
 {
 	DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, this->String(), sel ? TC_WHITE : TC_BLACK);
 }
-
+/*
+const char * DropDownListCharStringItem::String() const
+{
+	return this->string;
+}
+*/
 /**
  * Natural sorting comparator function for DropDownList::sort().
  * @param first Left side of comparison.
diff -r e16bdc0054ce src/widgets/dropdown_type.h
--- a/src/widgets/dropdown_type.h
+++ b/src/widgets/dropdown_type.h
@@ -16,6 +16,11 @@
 #include "../gfx_func.h"
 #include "../core/smallvec_type.hpp"
 #include "table/strings.h"
+#include "../stdafx.h"
+#include "../window_gui.h"
+#include "../string_func.h"
+#include "../strings_func.h"
+#include "../window_func.h"
 
 /**
  * Base list item class from which others are derived. If placed in a list it
@@ -47,6 +52,7 @@
 
 	virtual bool Selectable() const { return true; }
 	virtual uint Width() const;
+	//virtual const char * String() const;
 	virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const;
 	virtual StringID String() const { return this->string; }
 
@@ -54,6 +60,39 @@
 };
 
 /**
+ * Drop down list entry for showing a checked/unchecked toggle item. Use
+ * DropDownListCheckedItem or DropDownListCharStringCheckedItem depending of
+ * type of string used (either StringID or const char*).
+ */
+
+template <class T, typename S>
+class DropDownListCheckedItemT : public T {
+	uint checkmark_width;
+public:
+	bool checked;
+	DropDownListCheckedItemT<T,S>(S string, int result, bool masked, bool checked) : T(string, result, masked), checked(checked)
+	{
+		this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
+	}
+	virtual ~DropDownListCheckedItemT<T,S>() {}
+	virtual uint Width() const
+	{
+		return T::Width() + this->checkmark_width;
+	}
+
+	virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
+	{
+		bool rtl = _current_text_dir == TD_RTL;
+		if (this->checked) {
+			DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
+		}
+		DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK);
+	}
+};
+
+#define DropDownListCheckedItem DropDownListCheckedItemT<DropDownListStringItem,StringID>
+#define DropDownListCharStringCheckedItem DropDownListCheckedItemT<DropDownListCharStringItem,const char*>
+/**
  * String list item with parameters.
  */
 class DropDownListParamStringItem : public DropDownListStringItem {
diff -r e16bdc0054ce src/widgets/graph_widget.h
--- a/src/widgets/graph_widget.h
+++ b/src/widgets/graph_widget.h
@@ -29,6 +29,10 @@
 	WID_CV_BACKGROUND, ///< Background of the window.
 	WID_CV_GRAPH,      ///< Graph itself.
 	WID_CV_RESIZE,     ///< Resize button.
+	WID_CPR2_FOOTER,          ///< Footer.
+	WID_CPR2_ENABLE_CARGOES,  ///< Enable cargoes button.
+	WID_CPR2_DISABLE_CARGOES, ///< Disable cargoes button.
+	WID_CPR2_CARGO_FIRST,     ///< First cargo in the list.
 };
 
 /** Widget of the #PerformanceHistoryGraphWindow class. */
diff -r e16bdc0054ce src/widgets/industry_widget.h
--- a/src/widgets/industry_widget.h
+++ b/src/widgets/industry_widget.h
@@ -19,6 +19,8 @@
 	WID_DPI_INFOPANEL,      ///< Info panel about the industry.
 	WID_DPI_DISPLAY_WIDGET, ///< Display chain button.
 	WID_DPI_FUND_WIDGET,    ///< Fund button.
+	WID_DPI_FT_OFF,         ///< Forbidden tiles highlight off button.
+	WID_DPI_FT_ON,          ///< Forbidden tiles highlight on button.
 };
 
 /** Widgets of the #IndustryViewWindow class. */
@@ -34,6 +36,7 @@
 enum IndustryDirectoryWidgets {
 	WID_ID_DROPDOWN_ORDER,    ///< Dropdown for the order of the sort.
 	WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort.
+	WID_ID_DROPDOWN_FILTER,   ///< Industry filter
 	WID_ID_INDUSTRY_LIST,     ///< Industry list.
 	WID_ID_SCROLLBAR,         ///< Scrollbar of the list.
 };
diff -r e16bdc0054ce src/widgets/network_widget.h
--- a/src/widgets/network_widget.h
+++ b/src/widgets/network_widget.h
@@ -51,6 +51,11 @@
 	WID_NG_ADD,                ///< 'Add server' button.
 	WID_NG_START,              ///< 'Start server' button.
 	WID_NG_CANCEL,             ///< 'Cancel' button.
+
+	WID_NG_CITYMANIA,          ///< filter citymania
+	WID_NG_REDDIT,             ///< filter reddit
+	WID_NG_NICE,               ///< filter n-ice
+	WID_NG_BTPRO,              ///< filter btpro
 };
 
 /** Widgets of the #NetworkStartServerWindow class. */
diff -r e16bdc0054ce src/widgets/rail_widget.h
--- a/src/widgets/rail_widget.h
+++ b/src/widgets/rail_widget.h
@@ -21,6 +21,7 @@
 	WID_RAT_BUILD_EW,       ///< Build rail along the game view X axis.
 	WID_RAT_BUILD_Y,        ///< Build rail along the game grid Y axis.
 	WID_RAT_AUTORAIL,       ///< Autorail tool.
+	WID_RAT_POLYRAIL,       ///< Polyline rail tool.
 	WID_RAT_DEMOLISH,       ///< Destroy something with dynamite!
 	WID_RAT_BUILD_DEPOT,    ///< Build a depot.
 	WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint.
@@ -99,10 +100,11 @@
 /** Widgets of the #BuildRailDepotWindow class. */
 enum BuildRailDepotWidgets {
 	/* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */
-	WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east.
-	WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east.
-	WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west.
-	WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west.
+	WID_BRAD_DEPOT_NE,   ///< Build a depot with the entrance in the north east.
+	WID_BRAD_DEPOT_SE,   ///< Build a depot with the entrance in the south east.
+	WID_BRAD_DEPOT_SW,   ///< Build a depot with the entrance in the south west.
+	WID_BRAD_DEPOT_NW,   ///< Build a depot with the entrance in the north west.
+	WID_BRAD_DEPOT_AUTO, ///< Build a depot, autoselect entrance.
 };
 
 /** Widgets of the #BuildRailWaypointWindow class. */
diff -r e16bdc0054ce src/widgets/road_widget.h
--- a/src/widgets/road_widget.h
+++ b/src/widgets/road_widget.h
@@ -17,7 +17,8 @@
 	/* Name starts with RO instead of R, because of collision with RailToolbarWidgets */
 	WID_ROT_ROAD_X,         ///< Build road in x-direction.
 	WID_ROT_ROAD_Y,         ///< Build road in y-direction.
-	WID_ROT_AUTOROAD,       ///< Autorail.
+	WID_ROT_AUTOROAD,       ///< Autoroad.
+	WID_ROT_FULLROAD,       ///< Auto full road (no half-tiles).
 	WID_ROT_DEMOLISH,       ///< Demolish.
 	WID_ROT_DEPOT,          ///< Build depot.
 	WID_ROT_BUS_STATION,    ///< Build bus station.
@@ -31,27 +32,30 @@
 /** Widgets of the #BuildRoadDepotWindow class. */
 enum BuildRoadDepotWidgets {
 	/* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */
-	WID_BROD_CAPTION,   ///< Caption of the window.
-	WID_BROD_DEPOT_NE,  ///< Depot with NE entry.
-	WID_BROD_DEPOT_SE,  ///< Depot with SE entry.
-	WID_BROD_DEPOT_SW,  ///< Depot with SW entry.
-	WID_BROD_DEPOT_NW,  ///< Depot with NW entry.
+	WID_BROD_CAPTION,    ///< Caption of the window.
+	WID_BROD_DEPOT_NE,   ///< Depot with NE entry.
+	WID_BROD_DEPOT_SE,   ///< Depot with SE entry.
+	WID_BROD_DEPOT_SW,   ///< Depot with SW entry.
+	WID_BROD_DEPOT_NW,   ///< Depot with NW entry.
+	WID_BROD_DEPOT_AUTO, ///< Depot, autodetect entry.
 };
 
 /** Widgets of the #BuildRoadStationWindow class. */
 enum BuildRoadStationWidgets {
 	/* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */
-	WID_BROS_CAPTION,       ///< Caption of the window.
-	WID_BROS_BACKGROUND,    ///< Background of the window.
-	WID_BROS_STATION_NE,    ///< Terminal station with NE entry.
-	WID_BROS_STATION_SE,    ///< Terminal station with SE entry.
-	WID_BROS_STATION_SW,    ///< Terminal station with SW entry.
-	WID_BROS_STATION_NW,    ///< Terminal station with NW entry.
-	WID_BROS_STATION_X,     ///< Drive-through station in x-direction.
-	WID_BROS_STATION_Y,     ///< Drive-through station in y-direction.
-	WID_BROS_LT_OFF,        ///< Turn off area highlight.
-	WID_BROS_LT_ON,         ///< Turn on area highlight.
-	WID_BROS_INFO,          ///< Station acceptance info.
+	WID_BROS_CAPTION,          ///< Caption of the window.
+	WID_BROS_BACKGROUND,       ///< Background of the window.
+	WID_BROS_STATION_NE,       ///< Terminal station with NE entry.
+	WID_BROS_STATION_SE,       ///< Terminal station with SE entry.
+	WID_BROS_STATION_SW,       ///< Terminal station with SW entry.
+	WID_BROS_STATION_NW,       ///< Terminal station with NW entry.
+	WID_BROS_STATION_X,        ///< Drive-through station in x-direction.
+	WID_BROS_STATION_Y,        ///< Drive-through station in y-direction.
+	WID_BROS_STATION_AUTO,     ///< Terminal station, autoselect entry.
+	WID_BROS_STATION_XY_AUTO,  ///< Drive-through station, autoselect direction.
+	WID_BROS_LT_OFF,           ///< Turn off area highlight.
+	WID_BROS_LT_ON,            ///< Turn on area highlight.
+	WID_BROS_INFO,             ///< Station acceptance info.
 };
 
 #endif /* WIDGETS_ROAD_WIDGET_H */
diff -r e16bdc0054ce src/widgets/toolbar_widget.h
--- a/src/widgets/toolbar_widget.h
+++ b/src/widgets/toolbar_widget.h
@@ -23,9 +23,11 @@
 	WID_TN_SUBSIDIES,     ///< Subsidy menu.
 	WID_TN_STATIONS,      ///< Station menu.
 	WID_TN_FINANCES,      ///< Finance menu.
+	WID_TN_CARGOS,        ///< Transported cargo menu
 	WID_TN_COMPANIES,     ///< Company menu.
 	WID_TN_STORY,         ///< Story menu.
 	WID_TN_GOAL,          ///< Goal menu.
+	WID_TN_WATCH,         ///< Watch gui menu
 	WID_TN_GRAPHS,        ///< Graph menu.
 	WID_TN_LEAGUE,        ///< Company league menu.
 	WID_TN_INDUSTRIES,    ///< Industry menu.
diff -r e16bdc0054ce src/widgets/town_widget.h
--- a/src/widgets/town_widget.h
+++ b/src/widgets/town_widget.h
@@ -19,6 +19,7 @@
 	WID_TD_LIST,             ///< List of towns.
 	WID_TD_SCROLLBAR,        ///< Scrollbar for the town list.
 	WID_TD_WORLD_POPULATION, ///< The world's population.
+	TDW_CAPTION_TEXT,
 };
 
 /** Widgets of the #TownAuthorityWindow class. */
@@ -41,6 +42,7 @@
 	WID_TV_CHANGE_NAME,    ///< Change the name of this town.
 	WID_TV_EXPAND,         ///< Expand this town (scenario editor only).
 	WID_TV_DELETE,         ///< Delete this town (scenario editor only).
+	WID_TV_CB,
 };
 
 /** Widgets of the #FoundTownWindow class. */
@@ -62,4 +64,33 @@
 	WID_TF_LAYOUT_RANDOM,     ///< Selection for a randomly chosen town layout.
 };
 
+enum TownHK {
+	HK_SADVERT,
+	HK_MADVERT,
+	HK_LADVERT,
+	HK_ROADS,
+	HK_STATUE,
+	HK_FUND,
+};
+
+enum CBTownWidgets {
+	WID_CB_LOCATION,
+	WID_CB_ADVERT,
+	WID_CB_ADVERT_REGULAR,
+	WID_CB_FUND,
+	WID_CB_FUND_REGULAR,
+	WID_CB_POWERFUND,
+	WID_CB_DETAILS,
+	WID_CB_CARGO_NAME,
+	WID_CB_CARGO_AMOUNT,
+	WID_CB_CARGO_REQ,
+	WID_CB_CARGO_PREVIOUS,
+	WID_CB_CARGO_STORE,
+	WID_CB_CARGO_STORE_PCT,
+	WID_CB_CARGO_FROM,
+	WID_CB_CENTER_VIEW,
+	WID_CB_TOWN_VIEW,
+	WID_CB_SHOW_AUTHORITY,
+};
+
 #endif /* WIDGETS_TOWN_WIDGET_H */
diff -r e16bdc0054ce src/window.cpp
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -11,6 +11,7 @@
 
 #include "stdafx.h"
 #include <stdarg.h>
+#include <limits>
 #include "company_func.h"
 #include "gfx_func.h"
 #include "console_func.h"
@@ -21,6 +22,7 @@
 #include "zoom_func.h"
 #include "vehicle_base.h"
 #include "window_func.h"
+#include "window_gui.h"
 #include "tilehighlight_func.h"
 #include "network/network.h"
 #include "querystring_gui.h"
@@ -1199,6 +1201,7 @@
 		switch (w->window_class) {
 			case WC_COMPANY_COLOUR:
 			case WC_FINANCES:
+			case WC_CARGOS:
 			case WC_STATION_LIST:
 			case WC_TRAINS_LIST:
 			case WC_ROADVEH_LIST:
@@ -2826,7 +2829,7 @@
 			case MC_DOUBLE_LEFT:
 			case MC_LEFT:
 				DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
-				if (!HandleViewportClicked(vp, x, y) &&
+				if (!HandleViewportClicked(vp, x, y, click == MC_DOUBLE_LEFT) &&
 						!(w->flags & WF_DISABLE_VP_SCROLL) &&
 						_settings_client.gui.left_mouse_btn_scrolling) {
 					_scrolling_viewport = true;
@@ -3478,3 +3481,55 @@
 	this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child
 	ResetObjectToPlace();
 }
+
+
+/**
+ * Sets safe-initial values.
+ * @param t The type of positioning desired.
+ */
+WindowPopup::WindowPopup(WindowDesc *desc, WindowPopupType t): Window(desc)
+{
+	this->type = t;
+	this->wpu_mod_x = -5;
+	this->wpu_mod_y = -5;
+	this->wpu_widget = std::numeric_limits<uint>::max();
+}
+
+/**
+ * Compute #WindowPopup origin Point.
+ *
+ * @param desc The window's #WindowDesc object
+ * @param sm_width Window's smallest_x.
+ * @param sm_height Window's smallest_y. Unused.
+ * @param window_number Unused.
+ * @return The origin coordinate of the window.
+ */
+/*virtual*/ Point WindowPopup::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
+{
+	int x, y;
+
+	switch (this->type) {
+		case WPUT_CENTERED:
+			x = _cursor.pos.x - sm_width / 2;
+			y = _cursor.pos.y - this->window_desc->GetDefaultHeight() / 2;
+			break;
+		case WPUT_WIDGET_RELATIVE:
+			if (this->wpu_widget != std::numeric_limits<uint>::max()) {
+				NWidgetBase *wid = this->GetWidget<NWidgetBase>(this->wpu_widget);
+				x = _cursor.pos.x - wid->pos_x + this->wpu_mod_x;
+				y = _cursor.pos.y - wid->pos_y + this->wpu_mod_y;
+				break;
+			}
+		case WPUT_ORIGIN:
+		default:
+			x = _cursor.pos.x + this->wpu_mod_x;
+			y = _cursor.pos.y + this->wpu_mod_y;
+			break;
+	}
+
+	Point rv;
+	rv.x = Clamp(x, 0, _screen.width - sm_width);
+	rv.y = Clamp(y, GetMainViewTop(), GetMainViewBottom() - this->window_desc->GetDefaultHeight());
+	return rv;
+}
+
diff -r e16bdc0054ce src/window_gui.h
--- a/src/window_gui.h
+++ b/src/window_gui.h
@@ -17,6 +17,7 @@
 #include "company_type.h"
 #include "tile_type.h"
 #include "widget_type.h"
+#include "station_base.h"
 #include "core/smallvec_type.hpp"
 #include "core/smallmap_type.hpp"
 #include "string_type.h"
@@ -873,6 +874,8 @@
 };
 
 void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const uint64 params[] = NULL, TooltipCloseCondition close_tooltip = TCC_HOVER);
+void GuiPrepareTooltipsExtra(Window *parent);
+void GuiShowStationRatingTooltip(Window *parent, const Station *st, const CargoSpec *cs);
 
 /* widget.cpp */
 int GetWidgetFromPos(const Window *w, int x, int y);
@@ -905,4 +908,31 @@
 
 void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y);
 
+
+/**
+ * #WindowPopup positioning types
+ */
+enum WindowPopupType {
+	WPUT_ORIGIN = 1,      ///< Align with the top-left corner of the window.
+	WPUT_WIDGET_RELATIVE, ///< Align from a nested widget.
+	WPUT_CENTERED,        ///< Center the widget under the cursor. Ignore modifiers.
+};
+
+/**
+ * Specialized Window bound to open around the cursor's position.
+ * Its sole purpose is to provide the OnInitialPosition() method
+ * and an simple interface to control its behaviour.
+ */
+struct WindowPopup: public Window {
+public:
+	WindowPopup(WindowDesc *desc, WindowPopupType t = WPUT_ORIGIN);
+	virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number);
+protected:
+	uint wpu_widget; ///< The widget to which the computation would be made from when type is #WPUT_WIDGET_RELATIVE.
+	int wpu_mod_x;   ///< The X axis modifier. A negative value would bring the window closer to the left edge of the screen. Default value is -5.
+	int wpu_mod_y;   ///< The Y axis modifier. A negative value would bring the window closer to the top edge of the screen. Default value is -5.
+private:
+	WindowPopupType type;
+};
+
 #endif /* WINDOW_GUI_H */
diff -r e16bdc0054ce src/window_type.h
--- a/src/window_type.h
+++ b/src/window_type.h
@@ -109,6 +109,8 @@
 	 *   - 0 = #ToolTipsWidgets
 	 */
 	WC_TOOLTIPS,
+	WC_TOOLTIPS_EXTRA,
+	WC_STATION_RATING_TOOLTIP,
 
 	/**
 	 * Query string window; %Window numbers:
@@ -370,6 +372,12 @@
 	 */
 	WC_BUILD_OBJECT,
 
+	//watch company
+	WC_WATCH_COMPANY,
+
+	//watch company admin version
+	WC_WATCH_COMPANYA,
+
 	/**
 	 * Build vehicle; %Window numbers:
 	 *   - #VehicleType = #BuildVehicleWidgets
@@ -516,6 +524,7 @@
 	 *   - #CompanyID = #CompanyWidgets
 	 */
 	WC_FINANCES,
+	WC_CARGOS,
 
 	/**
 	 * Income graph; %Window numbers:
@@ -681,6 +690,11 @@
 	 */
 	WC_SAVE_PRESET,
 
+	WC_ZONING_TOOLBAR,
+	WC_COMMAND_TOOLBAR,
+	WC_LOGIN_WINDOW,
+	WC_CB_TOWN,
+
 	WC_INVALID = 0xFFFF, ///< Invalid window.
 };
 
diff -r e16bdc0054ce src/zoning.h
--- /dev/null
+++ b/src/zoning.h
@@ -0,0 +1,35 @@
+/** @file zoning.h */
+
+#ifndef ZONING_H_
+#define ZONING_H_
+
+#include "tile_cmd.h"
+
+enum EvaluationMode {
+	CHECKNOTHING = 0,
+	CHECKOPINION,  ///< Check the local authority's opinion.
+	CHECKBUILD,    ///< Check wither or not the player can build.
+	CHECKSTACATCH, ///< Check catchment area for stations
+	CHECKACTIVESTATIONS,  ///< Active/inactive stations (serviced in 50 days)
+	CHECKBULUNSER, ///< Check for unserved buildings
+	CHECKINDUNSER, ///< Check for unserved industries
+	CHECKTOWNZONES,  ///< Town zones (Tz*)
+	CHECKCBBORDERS,  ///< Citybuilder cargo acceptment zone
+	CHECKNEWCBBORDERS,  ///< Citybuilder cargo acceptment zone
+	CHECKCBTOWNBORDERS,  ///< Citybuilder server town borders
+	CHECKTOWNADZONES,  ///< Town advertisement zone
+	CHECKTOWNGROWTHTILES, ///< Town growth tiles (new house, skipped/removed house)
+};
+
+struct Zoning {
+	EvaluationMode inner;
+	EvaluationMode outer;
+};
+
+extern Zoning _zoning;
+
+SpriteID TileZoningSpriteEvaluation(TileIndex tile, Owner owner, EvaluationMode ev_mode);
+void DrawTileZoning(const TileInfo *ti);
+void ShowZoningToolbar();
+
+#endif /*ZONING_H_*/
diff -r e16bdc0054ce src/zoning_cmd.cpp
--- /dev/null
+++ b/src/zoning_cmd.cpp
@@ -0,0 +1,326 @@
+/** @file zoning_cmd.cpp */
+#include "stdafx.h"
+#include "station_base.h"
+#include "industry.h"
+#include "viewport_func.h"
+#include "town.h"
+#include "zoning.h"
+
+Zoning _zoning = {CHECKNOTHING, CHECKNOTHING};
+static const SpriteID INVALID_SPRITE_ID = UINT_MAX;
+//RED GREEN BLACK LIGHT_BLUE ORANGE WHITE YELLOW PURPLE
+
+/**
+ * Draw the zoning sprites.
+ * @param SpriteID image
+ *        the image
+ * @param SpriteID colour
+ *        the colour of the zoning
+ * @param TileInfo ti
+ *        the tile
+ */
+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,
+};
+
+void DrawZoningSprites(SpriteID image, SpriteID colour, const TileInfo *ti) {
+	if (colour != INVALID_SPRITE_ID){
+		AddSortableSpriteToDraw(image + _tileh_to_sprite[ti->tileh], colour, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
+	}
+}
+
+/**
+ * Detect whether this area is within the acceptance of any station.
+ * @param TileArea area
+ *        the area to search by
+ * @return true if a station is found
+ */
+bool IsAreaWithinAcceptanceZoneOfStation(TileArea area) {
+	int catchment = _settings_game.station.station_spread + (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED);
+
+	StationFinder morestations(TileArea(TileXY(TileX(area.tile) - catchment / 2, TileY(area.tile) - catchment / 2),
+		TileX(area.tile) + area.w + catchment, TileY(area.tile) + area.h + catchment));
+
+	for (Station * const *st_iter = morestations.GetStations()->Begin(); st_iter != morestations.GetStations()->End(); ++st_iter) {
+		Station *st = *st_iter;
+		Rect rect = st->GetCatchmentRect();
+		return TileArea(TileXY(rect.left, rect.top), TileXY(rect.right, rect.bottom)).Intersects(area);
+	}
+	return false;
+}
+
+/**
+ * Detect whether this tile is within the acceptance of any station.
+ * @param TileIndex tile
+ *        the tile to search by
+ * @return true if a station is found
+ */
+bool IsTileWithinAcceptanceZoneOfStation(TileIndex tile) {
+	int catchment = _settings_game.station.station_spread + (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED);
+
+	StationFinder morestations(TileArea(TileXY(TileX(tile) - catchment / 2, TileY(tile) - catchment / 2),
+		catchment, catchment));
+
+	for (Station * const *st_iter = morestations.GetStations()->Begin(); st_iter != morestations.GetStations()->End(); ++st_iter) {
+		Station *st = *st_iter;
+		Rect rect = st->GetCatchmentRect();
+		if ((uint)rect.left <= TileX(tile) && TileX(tile) <= (uint)rect.right
+			&& (uint)rect.top <= TileY(tile) && TileY(tile) <= (uint)rect.bottom )
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+//Check the opinion of the local authority in the tile.
+SpriteID TileZoneCheckOpinionEvaluation(TileIndex tile, Owner owner) {
+	Town *town = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
+
+	if (town == NULL) return INVALID_SPRITE_ID; // no town
+	else if (HasBit(town->have_ratings, owner)) {  // good : bad
+		int16 rating = town->ratings[owner];
+		if(rating <= RATING_APPALLING) return SPR_PALETTE_ZONING_RED;
+		if(rating <= RATING_POOR) return SPR_PALETTE_ZONING_ORANGE;
+		if(rating <= RATING_MEDIOCRE) return SPR_PALETTE_ZONING_YELLOW;
+		if(rating <= RATING_GOOD) return SPR_PALETTE_ZONING_WHITE;
+		if(rating <= RATING_VERYGOOD) return SPR_PALETTE_ZONING_PURPLE;
+		if(rating <= RATING_EXCELLENT) return SPR_PALETTE_ZONING_LIGHT_BLUE;
+		return SPR_PALETTE_ZONING_GREEN;
+	}
+	else {
+		return SPR_PALETTE_ZONING_BLACK;      // no opinion
+	}
+}
+
+//Check whether the player can build in tile.
+SpriteID TileZoneCheckBuildEvaluation(TileIndex tile, Owner owner) {
+	/* Let's first check for the obvious things you cannot build on */
+	switch ( GetTileType(tile) ) {
+		case MP_INDUSTRY:
+		case MP_OBJECT:
+		case MP_HOUSE:
+			return SPR_PALETTE_ZONING_RED; //can't build
+		case MP_STATION:
+		case MP_TUNNELBRIDGE:
+		case MP_ROAD:
+		case MP_RAILWAY: {
+			if (GetTileOwner(tile) != owner) return SPR_PALETTE_ZONING_RED; //can't build
+			else return INVALID_SPRITE_ID;
+		}
+		default: return INVALID_SPRITE_ID;
+	}
+}
+
+//Detect whether the tile is within the catchment zone of a station.
+//black if within, light blue if only in acceptance zone and nothing if no nearby station.
+ SpriteID TileZoneCheckStationCatchmentEvaluation(TileIndex tile) {
+	// Never on a station.
+	if (IsTileType(tile, MP_STATION)){
+		return INVALID_SPRITE_ID;
+	}
+	// For provided goods
+	StationFinder stations(TileArea(tile, 1, 1));
+	if (stations.GetStations()->Length() > 0) {
+		return SPR_PALETTE_ZONING_GREEN;
+	}
+	// For accepted goods
+	if (IsTileWithinAcceptanceZoneOfStation(tile)){
+		return SPR_PALETTE_ZONING_LIGHT_BLUE;
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Detect whether a building is unserved by a station of owner.
+//return red if unserved, orange if only accepting, nothing if served or not a building
+SpriteID TileZoneCheckUnservedBuildingsEvaluation(TileIndex tile) {
+	CargoArray dat;
+
+	if (IsTileType (tile, MP_HOUSE))
+		//&& ( ( memset(&dat, 0, sizeof(dat)), AddAcceptedCargo(tile, dat, NULL), (dat[CT_MAIL] + dat[CT_PASSENGERS] > 0) )
+		//	|| ( memset(&dat, 0, sizeof(dat)), AddProducedCargo(tile, dat), (dat[CT_MAIL] + dat[CT_PASSENGERS] > 0) ) ) )
+	{
+		StationFinder stations(TileArea(tile, 1, 1));
+
+		if (stations.GetStations()->Length() > 0) {
+			return INVALID_SPRITE_ID;
+		}
+		// For accepted goods
+		if (IsTileWithinAcceptanceZoneOfStation(tile)){
+			return SPR_PALETTE_ZONING_ORANGE;
+		}
+		return SPR_PALETTE_ZONING_RED;
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Detect whether an industry is unserved by a station of owner.
+//return red if unserved, orange if only accepting, nothing if served or not a building
+SpriteID TileZoneCheckUnservedIndustriesEvaluation(TileIndex tile) {
+	if (IsTileType(tile, MP_INDUSTRY)) {
+		Industry *ind = Industry::GetByTile(tile);
+		StationFinder stations(ind->location);
+
+		if (stations.GetStations()->Length() > 0){
+			return INVALID_SPRITE_ID;
+		}
+
+		// For accepted goods
+		if (IsAreaWithinAcceptanceZoneOfStation(ind->location)){
+			return SPR_PALETTE_ZONING_ORANGE;
+		}
+		return SPR_PALETTE_ZONING_RED;
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Check which town zone tile belongs to.
+SpriteID TileZoneCheckTownZones(TileIndex tile) {
+	HouseZonesBits next_zone = HZB_BEGIN, tz = HZB_END;
+
+	Town *town;
+	FOR_ALL_TOWNS(town) {
+		while (next_zone < HZB_END
+			&& (town->cache.squared_town_zone_radius[next_zone] == 0
+				|| DistanceSquare(tile, town->xy) <= town->cache.squared_town_zone_radius[next_zone])
+		){
+			if(town->cache.squared_town_zone_radius[next_zone] != 0)  tz = next_zone;
+			next_zone++;
+		}
+	}
+
+	switch (tz) {
+		case HZB_TOWN_EDGE:         return SPR_PALETTE_ZONING_LIGHT_BLUE; // Tz0
+		case HZB_TOWN_OUTSKIRT:     return SPR_PALETTE_ZONING_RED; // Tz1
+		case HZB_TOWN_OUTER_SUBURB: return SPR_PALETTE_ZONING_YELLOW; // Tz2
+		case HZB_TOWN_INNER_SUBURB: return SPR_PALETTE_ZONING_GREEN; // Tz3
+		case HZB_TOWN_CENTRE:       return SPR_PALETTE_ZONING_WHITE; // Tz4 - center
+		default:                    return INVALID_SPRITE_ID; // no town
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Check CB town acceptance area
+SpriteID TileZoneCheckNewCBBorders(TileIndex tile) {
+	Town *town;
+	FOR_ALL_TOWNS(town) {
+		if (DistanceSquare(tile, town->xy) <= town->cache.squared_town_zone_radius[0] + 30)
+			return SPR_PALETTE_ZONING_BLACK;
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Check CB town acceptance area
+SpriteID TileZoneCheckCBBorders(TileIndex tile) {
+	Town *town = CalcClosestTownFromTile(tile);
+
+	if (town != NULL) {
+		if (DistanceManhattan(town->xy, tile) <= _settings_client.gui.cb_distance_check) {
+			return SPR_PALETTE_ZONING_LIGHT_BLUE; //cb catchment
+		}
+	}
+	return INVALID_SPRITE_ID; // no town
+}
+
+//Check whether the tile is within citybuilder server town border (where houses could be built)
+SpriteID TileZoneCheckCBTownBorders(TileIndex tile) {
+	Town *town;
+	FOR_ALL_TOWNS(town) {
+		uint32 distMax = DistanceMax(town->xy, tile);
+		if (distMax * distMax < town->cache.squared_town_zone_radius[0]){
+			return SPR_PALETTE_ZONING_GREEN;
+		}
+	}
+	return INVALID_SPRITE_ID;
+}
+
+//Check which advertisement zone(small, medium, large) tile belongs to
+SpriteID TileZoneCheckTownAdvertisementZones(TileIndex tile) {
+	Town *town = CalcClosestTownFromTile(tile, 21U);
+	if (town == NULL) return INVALID_SPRITE_ID; //nothing
+
+	uint dist = DistanceManhattan(town->xy, tile);
+
+	if (dist <= 10) return SPR_PALETTE_ZONING_GREEN;
+	if (dist <= 15) return SPR_PALETTE_ZONING_YELLOW;
+	if (dist <= 20) return SPR_PALETTE_ZONING_LIGHT_BLUE;
+	return INVALID_SPRITE_ID;
+}
+
+//Checks for tile in growth tiles info
+SpriteID TileZoneCheckTownsGrowthTiles(TileIndex tile) {
+	switch (max(_towns_growth_tiles[tile], _towns_growth_tiles_last_month[tile])) {
+		case TGTS_CB_HOUSE_REMOVED_NOGROW: return SPR_PALETTE_ZONING_LIGHT_BLUE;
+		case TGTS_RH_REMOVED:              return SPR_PALETTE_ZONING_LIGHT_BLUE;
+		case TGTS_RH_REBUILT:              return SPR_PALETTE_ZONING_WHITE;
+		case TGTS_NEW_HOUSE:               return SPR_PALETTE_ZONING_GREEN;
+		case TGTS_CYCLE_SKIPPED:           return SPR_PALETTE_ZONING_ORANGE;
+		case TGTS_HOUSE_SKIPPED:           return SPR_PALETTE_ZONING_YELLOW;
+		case TGTS_CB_HOUSE_REMOVED:        return SPR_PALETTE_ZONING_RED;
+		default: return INVALID_SPRITE_ID;
+	}
+}
+
+// For station shows whether it is active
+SpriteID TileZoneCheckActiveStations(TileIndex tile) {
+	// Never on a station.
+	if (!IsTileType(tile, MP_STATION)){
+		return INVALID_SPRITE_ID;
+	}
+
+	Station *st = Station::GetByTile(tile);
+	if (st == NULL) {
+		return INVALID_SPRITE_ID;
+	}
+
+	if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
+		return SPR_PALETTE_ZONING_GREEN;
+	}
+
+	return SPR_PALETTE_ZONING_RED;
+}
+
+
+/**
+ * General evaluation function; calls all the other functions depending on
+ * evaluation mode.
+ * @param TileIndex tile
+ *        Tile to be evaluated.
+ * @param EvaluationMode ev_mode
+ *        The current evaluation mode.
+ * @return The colour returned by the evaluation functions (none if no ev_mode).
+ */
+SpriteID TileZoningSpriteEvaluation(TileIndex tile, Owner owner, EvaluationMode ev_mode) {
+	switch (ev_mode) {
+		case CHECKOPINION:     return TileZoneCheckOpinionEvaluation(tile, owner);
+		case CHECKBUILD:       return TileZoneCheckBuildEvaluation(tile, owner);
+		case CHECKSTACATCH:    return TileZoneCheckStationCatchmentEvaluation(tile);
+		case CHECKBULUNSER:    return TileZoneCheckUnservedBuildingsEvaluation(tile);
+		case CHECKINDUNSER:    return TileZoneCheckUnservedIndustriesEvaluation(tile);
+		case CHECKTOWNZONES:   return TileZoneCheckTownZones(tile);
+		case CHECKCBBORDERS:   return TileZoneCheckCBBorders(tile);
+		case CHECKNEWCBBORDERS:   return TileZoneCheckNewCBBorders(tile);
+		case CHECKCBTOWNBORDERS: return TileZoneCheckCBTownBorders(tile);
+		case CHECKTOWNADZONES: return TileZoneCheckTownAdvertisementZones(tile);
+		case CHECKTOWNGROWTHTILES: return TileZoneCheckTownsGrowthTiles(tile);
+		case CHECKACTIVESTATIONS: return TileZoneCheckActiveStations(tile);
+		default:               return INVALID_SPRITE_ID;
+	}
+}
+
+/**
+ * Draw the the zoning on the tile.
+ * @param TileInfo ti
+ *        the tile to draw on.
+ */
+void DrawTileZoning(const TileInfo *ti) {
+	if(_zoning.outer == CHECKNOTHING && _zoning.inner == CHECKNOTHING) return; //nothing to do
+	if (_game_mode != GM_NORMAL || ti->tile >= MapSize() || IsTileType(ti->tile, MP_VOID)) return; //check invalid
+	if (_zoning.outer != CHECKNOTHING){
+		DrawZoningSprites(SPR_SELECT_TILE, TileZoningSpriteEvaluation(ti->tile, _local_company, _zoning.outer), ti);
+	}
+	if (_zoning.inner != CHECKNOTHING){
+		DrawZoningSprites(SPR_INNER_HIGHLIGHT_BASE, TileZoningSpriteEvaluation(ti->tile, _local_company, _zoning.inner), ti);
+	}
+}
diff -r e16bdc0054ce src/zoning_gui.cpp
--- /dev/null
+++ b/src/zoning_gui.cpp
@@ -0,0 +1,201 @@
+/** @file zoning_gui.cpp */
+#include "stdafx.h"
+#include "widgets/dropdown_func.h"
+#include "table/strings.h"
+#include "strings_func.h"
+#include "gfx_func.h"
+#include "core/geometry_func.hpp"
+#include "zoning.h"
+#include "hotkeys.h"
+
+const StringID _zone_types[] = {
+	//STR_ZONING_NO_ZONING,
+	STR_ZONING_AUTHORITY,
+	STR_ZONING_CAN_BUILD,
+	STR_ZONING_STA_CATCH,
+	STR_ZONING_ACTIVE_STATIONS,
+	STR_ZONING_BUL_UNSER,
+	STR_ZONING_IND_UNSER,
+	STR_ZONING_TOWN_ZONES,
+	STR_ZONING_CB_BORDERS,
+	STR_ZONING_NEW_CB_BORDERS,
+	STR_ZONING_CB_TOWN_BORDERS,
+	STR_ZONING_ADVERTISEMENT_ZONES,
+	STR_ZONING_TOWN_GROWTH_TILES,
+};
+
+const int ZONES_COUNT = 12;
+
+enum ZoningToolbarWidgets {
+	ZTW_CAPTION,
+	ZTW_OUTER_FIRST,
+	ZTW_INNER_FIRST = ZTW_OUTER_FIRST + ZONES_COUNT,
+	ZTW_INNER_END = ZTW_INNER_FIRST + ZONES_COUNT,
+};
+
+struct ZoningWindow : public Window {
+	uint maxwidth;
+	uint maxheight;
+
+	ZoningWindow(WindowDesc *desc, int window_number) : Window(desc) {
+		Dimension dim;
+		this->maxwidth = 0;
+		this->maxheight = 0;
+		for (int i = 0; i < ZONES_COUNT; i++) {
+			dim = GetStringBoundingBox(_zone_types[i]);
+			this->maxwidth = max(this->maxwidth, dim.width);
+			this->maxheight = max(this->maxheight, dim.height);
+		}
+
+		this->InitNested(window_number);
+		this->InvalidateData();
+		if(_zoning.outer != CHECKNOTHING) this->LowerWidget(ZTW_OUTER_FIRST + _zoning.outer - 1); //-1:skip CHECKNOTHING
+		if(_zoning.inner != CHECKNOTHING) this->LowerWidget(ZTW_INNER_FIRST + _zoning.inner - 1);
+	}
+
+	virtual void OnPaint() {
+		this->DrawWidgets();
+	}
+
+	virtual void OnClick(Point pt, int widget, int click_count) {
+		bool outer = true;
+		bool deselect = false;
+		EvaluationMode clicked;
+		if (widget >= ZTW_OUTER_FIRST && widget < ZTW_INNER_FIRST){
+			clicked = (EvaluationMode)(widget - ZTW_OUTER_FIRST + 1); //+1:skip CHECKNOTHING
+			deselect = _zoning.outer == clicked;
+			_zoning.outer = deselect ? CHECKNOTHING : clicked;
+		}
+		else if (widget >= ZTW_INNER_FIRST && widget < ZTW_INNER_END){
+			clicked = (EvaluationMode)(widget - ZTW_INNER_FIRST + 1);
+			deselect = _zoning.inner == clicked;
+			_zoning.inner = deselect ? CHECKNOTHING : clicked;
+			outer = false;
+		}
+		else return;
+
+		this->RaiseAllWidgets(outer);
+		if(!deselect) this->ToggleWidgetLoweredState(widget);
+		this->InvalidateData();
+		MarkWholeScreenDirty();
+	}
+
+	void DrawWidget(const Rect &r, int widget) const
+	{
+		StringID strid = STR_EMPTY;
+		if (widget >= ZTW_OUTER_FIRST && widget < ZTW_INNER_FIRST){
+			strid = _zone_types[widget - ZTW_OUTER_FIRST];
+		}
+		else if (widget >= ZTW_INNER_FIRST && widget < ZTW_INNER_END){
+			strid = _zone_types[widget - ZTW_INNER_FIRST];
+		}
+		else return;
+
+		bool rtl = _current_text_dir == TD_RTL;
+		byte clk_dif = this->IsWidgetLowered(widget) ? 1 : 0;
+		int x = r.left + WD_FRAMERECT_LEFT;
+		int y = r.top;
+
+		DrawString(rtl ? r.left : x + clk_dif + 1, (rtl ? r.right + clk_dif : r.right), y + 1 + clk_dif, strid, TC_FROMSTRING, SA_LEFT);
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) {
+		if (widget >= ZTW_OUTER_FIRST && widget < ZTW_INNER_END){
+			size->width = this->maxwidth + padding.width + 8;
+			size->height = this->maxheight + 2;
+		}
+	}
+
+	void RaiseAllWidgets(bool outer){
+		byte start = outer ? ZTW_OUTER_FIRST : ZTW_INNER_FIRST;
+		byte end = outer ? ZTW_INNER_FIRST : ZTW_INNER_END;
+		for(byte i = start; i < end; i++){
+			if(this->IsWidgetLowered(i)){
+				this->ToggleWidgetLoweredState(i);
+				break;
+			}
+		}
+	}
+
+	virtual EventState OnHotkey(int hotkey)
+	{
+		return Window::OnHotkey(hotkey);
+	}
+
+	static HotkeyList hotkeys;
+};
+
+
+static EventState ZoningWindowGlobalHotkeys(int hotkey) {
+	EvaluationMode zoning = (EvaluationMode)(hotkey - ZTW_OUTER_FIRST + 1); // +1:skip CHECKNOTHING
+	bool deselect = (_zoning.outer == zoning);
+	_zoning.outer = deselect ? CHECKNOTHING : zoning;
+	MarkWholeScreenDirty();
+	return ES_HANDLED;
+}
+
+static Hotkey zoning_hotkeys[] = {
+	Hotkey(WKC_SHIFT | '1', "authority", ZTW_OUTER_FIRST),
+	Hotkey(WKC_SHIFT | '2', "build_status", ZTW_OUTER_FIRST + 1),
+	Hotkey(WKC_SHIFT | '3', "station_catchment", ZTW_OUTER_FIRST + 2),
+	Hotkey(WKC_SHIFT | '4', "unserved_buildings", ZTW_OUTER_FIRST + 3),
+	Hotkey(WKC_SHIFT | '5', "unserved_industries", ZTW_OUTER_FIRST + 4),
+	Hotkey(WKC_SHIFT | '6', "town_zone", ZTW_OUTER_FIRST + 5),
+	Hotkey(WKC_SHIFT | '7', "CB_acceptance", ZTW_OUTER_FIRST + 6),
+	Hotkey(WKC_SHIFT | '8', "CB_build_borders", ZTW_OUTER_FIRST + 7),
+	Hotkey(WKC_SHIFT | '9', "advertisement", ZTW_OUTER_FIRST + 8),
+	Hotkey(WKC_SHIFT | '0', "growth_tiles", ZTW_OUTER_FIRST + 9),
+	Hotkey((uint16)0, "active_stations", ZTW_OUTER_FIRST + 10),
+	HOTKEY_LIST_END
+};
+
+HotkeyList ZoningWindow::hotkeys("zoning_gui", zoning_hotkeys, ZoningWindowGlobalHotkeys);
+
+
+/** Construct the row containing the digit keys. */
+static NWidgetBase *MakeZoningButtons(int *biggest_index)
+{
+	NWidgetHorizontal *hor = new NWidgetHorizontal(NC_EQUALSIZE);
+	int zone_types_size = lengthof(_zone_types);
+	hor->SetPadding(1, 1, 1, 1);
+
+	for(int i = 0; i < 2; i++){
+		NWidgetVertical *ver = new NWidgetVertical;
+
+		int offset = (i == 0) ? ZTW_OUTER_FIRST : ZTW_INNER_FIRST;
+
+		for (int j = 0; j < zone_types_size; j++) {
+			NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, i==0 ? COLOUR_ORANGE : COLOUR_YELLOW, offset + j, NULL);
+			leaf->SetFill(1, 0);
+			leaf->SetPadding(0, 0, 0, 0);
+			ver->Add(leaf);
+		}
+		hor->Add(ver);
+	}
+	*biggest_index = ZTW_INNER_END - 1;
+	return hor;
+}
+
+static const NWidgetPart _nested_zoning_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY, ZTW_CAPTION), SetDataTip(STR_ZONING_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_GREY),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY),
+		NWidgetFunction(MakeZoningButtons),
+	EndContainer()
+};
+
+static WindowDesc _zoning_desc (
+	WDP_AUTO, NULL, 0, 0,
+	WC_ZONING_TOOLBAR, WC_NONE,
+	0,
+	_nested_zoning_widgets, lengthof(_nested_zoning_widgets),
+	&ZoningWindow::hotkeys
+);
+
+void ShowZoningToolbar() {
+	AllocateWindowDescFront<ZoningWindow>(&_zoning_desc, 0);
+}
