Only in cmclient: azure-pipelines
Only in cmclient: azure-pipelines-ci.yml
Only in cmclient: azure-pipelines-release-stable.yml
Only in cmclient: azure-pipelines-release.yml
Only in cmclient/bin/ai: CMakeLists.txt
Only in cmclient/bin/ai: regression
Only in cmclient/bin: CMakeLists.txt
Only in cmclient/bin: data
Only in cmclient/bin/game: CMakeLists.txt
Only in cmclient: .clang-format
Only in cmclient/cmake: FindZSTD.cmake
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/cmake/InstallAndPackage.cmake cmclient/cmake/InstallAndPackage.cmake
29,30c29,31
<                 ${CMAKE_SOURCE_DIR}/bin/ai
<                 ${CMAKE_SOURCE_DIR}/bin/game
---
>                 ${CMAKE_BINARY_DIR}/ai
>                 ${CMAKE_BINARY_DIR}/game
>                 ${CMAKE_BINARY_DIR}/data
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/CMakeLists.txt cmclient/CMakeLists.txt
119a120
> find_package(ZSTD 1.4)
222a224
> add_subdirectory(${CMAKE_SOURCE_DIR}/bin)
243c245
< set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
---
> set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
250a253
> link_package(ZSTD ENCOURAGED)
Only in cmclient: cm_changelog.txt
Only in cmclient: cmclient.sublime-project
Only in cmclient: config.lib
Only in cmclient: .diff-exclude
Only in cmclient/docs: Readme_Windows_MSVC.txt
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/Doxyfile.in cmclient/Doxyfile.in
292a293
>                          WITH_ZSTD \
Only in cmclient: gen_newgrf_revisions.py
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/.github/workflows/ci-build.yml cmclient/.github/workflows/ci-build.yml
102a103
>           libzstd-dev \
175c176
<         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
---
>         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified
182a184
>           zstd \
257c259
<         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
---
>         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified
265a268
>           zstd \
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/.github/workflows/release.yml cmclient/.github/workflows/release.yml
299a300
>           libzstd-devel \
381a383,384
>         - container_image: "debian:bullseye"
>           bundle_name: "bullseye"
414a418
>           libzstd-dev \
499c503
<         key: ${{ steps.key.outputs.image }}-vcpkg-release-0 # Increase the number whenever dependencies are modified
---
>         key: ${{ steps.key.outputs.image }}-vcpkg-release-1 # Increase the number whenever dependencies are modified
508a513,514
>           zstd:x64-osx \
>           zstd:arm64-osx \
702c708
<         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
---
>         key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified
710a717
>           zstd \
832c839
<     if: always() && needs.source.result == 'success' && needs.docs.result == 'success' && needs.linux.result == 'success' && (needs.linux-distro.result == 'success' || needs.linux-distro.result == 'skipped') && needs.macos.result == 'success' && needs.windows.result == 'success'
---
>     if: ${{ false }} # always() && needs.source.result == 'success' && needs.docs.result == 'success' && needs.linux.result == 'success' && (needs.linux-distro.result == 'success' || needs.linux-distro.result == 'skipped') && needs.macos.result == 'success' && needs.windows.result == 'success'
885c892
<     if: needs.source.outputs.trigger_type == 'new-master' || needs.source.outputs.trigger_type == 'new-tag'
---
>     if: ${{ false }} # needs.source.outputs.trigger_type == 'new-master' || needs.source.outputs.trigger_type == 'new-tag'
Only in cmclient/media: openttd.desktop.filter.awk
Only in cmclient/media: openttd.desktop.in
Only in cmclient/media: openttd.desktop.translation.awk
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/.ottdrev cmclient/.ottdrev
1c1
< 1.11.0	20210401	0	bd80ec7cff2f2186b133ea4bee431cb1a2f1fc95	1	1	2021
---
> 1.11.0	20210404	0	edba868423c885f8e269b40b6362a40a3f9b3421	1	1	2021
Only in cmclient: projects
Only in cmclient: readme.txt
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/.release_date cmclient/.release_date
1c1
< 2021-04-01 12:33 UTC
---
> 2021-04-04 16:31 UTC
Only in cmclient/src/3rdparty/squirrel: COMPILE
Only in cmclient/src/3rdparty/squirrel: doc
Only in cmclient/src/3rdparty/squirrel: etc
Only in cmclient/src/3rdparty/squirrel: HISTORY
Only in cmclient/src/3rdparty/squirrel/include: sqstdblob.h
Only in cmclient/src/3rdparty/squirrel/include: sqstdio.h
Only in cmclient/src/3rdparty/squirrel/include: sqstdsystem.h
Only in cmclient/src/3rdparty/squirrel: Makefile
Only in cmclient/src/3rdparty/squirrel: README
Only in cmclient/src/3rdparty/squirrel: samples
Only in cmclient/src/3rdparty/squirrel: sq
Only in cmclient/src/3rdparty/squirrel/sqstdlib: Makefile
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdblob.cpp
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdblobimpl.h
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdio.cpp
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdlib.dsp
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdstream.cpp
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdstream.h
Only in cmclient/src/3rdparty/squirrel/sqstdlib: sqstdsystem.cpp
Only in cmclient/src/3rdparty/squirrel/squirrel: Makefile
Only in cmclient/src/3rdparty/squirrel/squirrel: squirrel.dsp
Only in cmclient/src/3rdparty/squirrel: squirrel.dsw
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/aircraft_cmd.cpp cmclient/src/aircraft_cmd.cpp
2100c2100
< 	PerformanceAccumulator framerate(PFE_GL_AIRCRAFT);
---
> 	// PerformanceAccumulator framerate(PFE_GL_AIRCRAFT);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/aircraft_gui.cpp cmclient/src/aircraft_gui.cpp
42c42,43
< 			DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE);
---
> 			if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index);  // CM
> 			DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/airport_gui.cpp cmclient/src/airport_gui.cpp
31a32,34
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_station_gui.hpp"
> 
35,37c38,40
< static AirportClassID _selected_airport_class; ///< the currently visible airport class
< static int _selected_airport_index;            ///< the index of the selected airport in the current class or -1
< static byte _selected_airport_layout;          ///< selected airport layout number.
---
> AirportClassID _selected_airport_class; ///< the currently visible airport class
> int _selected_airport_index;            ///< the index of the selected airport in the current class or -1
> byte _selected_airport_layout;          ///< selected airport layout number.
56a60,64
> 	if (citymania::UseImprovedStationJoin()) {
> 		citymania::PlaceAirport(tile);
> 		return;
> 	}
> 
58c66
< 	uint32 p2 = _ctrl_pressed;
---
> 	uint32 p2 = (citymania::_fn_mod ? 1 : 0);
112c120
< 				if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) {
---
> 				if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT, CM_DDSP_BUILD_AIRPORT)) {
119c127
< 				HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
162a171,172
> 
> 		citymania::AbortStationPlacement();
434a445
> 			top = DrawStationAuthorityText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top) + WD_PAR_VSEP_NORMAL;
474c485,486
< 			if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
---
> 			//if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
> 			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_anim_sse4.hpp cmclient/src/blitter/32bpp_anim_sse4.hpp
39c39
< 		return Blitter_32bppSSE_Base::Encode(sprite, allocator);
---
> 		return Blitter_32bppSSE_Base::Encode(sprite, allocator, this);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_base.hpp cmclient/src/blitter/32bpp_base.hpp
178a179,200
> 
> 	/* CM */
> 	uint8 cm_mdict[64*64*64] = {0};
> 	uint8 CM_GetMForRGB(uint8 r, uint8 g, uint8 b) {
> 		if (r==0 && g==0 && b==0) return 0;
> 		r &= 252; g &= 252; b &= 252;
> 		auto key = (r << 10) | (g << 4) | (b >> 2);
> 		auto m = this->cm_mdict[key];
> 		if (m != 0) return m;
> 		uint md = UINT_MAX;
> 		for (uint8 i = 1; i < 0xc0; i++) {
> 			auto c = this->LookupColourInPalette(i);
> 			auto dist = ((uint)c.r - r) * ((uint)c.r - r) + ((uint)c.g - g) * ((uint)c.g - g) + ((uint)c.b - b) * ((uint)c.b - b);
> 			if (dist < md) {
> 				md = dist;
> 				m = i;
> 			}
> 		}
> 		this->cm_mdict[key] = m;
> 		return m;
> 	}
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_optimized.cpp cmclient/src/blitter/32bpp_optimized.cpp
367a368
> 						if (Tpal_to_rgb) *dst_n = this->CM_GetMForRGB(src->r, src->g, src->b) | (DEFAULT_BRIGHTNESS << 8);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_simple.cpp cmclient/src/blitter/32bpp_simple.cpp
131,132c130,131
< 			dst[i].m = 0;
< 			dst[i].v = 0;
---
> 			dst[i].m = this->CM_GetMForRGB(src->r, src->g, src->b);
> 			dst[i].v = DEFAULT_BRIGHTNESS;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_sse2.cpp cmclient/src/blitter/32bpp_sse2.cpp
23c23
< Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
---
> Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator, Blitter_32bppSimple *base_blitter)
91a92
> 						has_remap = true;
94a96
> 						dst_mv->m = base_blitter->CM_GetMForRGB(src->r, src->g, src->b);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/32bpp_sse2.hpp cmclient/src/blitter/32bpp_sse2.hpp
75c75
< 	Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
---
> 	Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator, Blitter_32bppSimple *base_blitter);
88c88
< 		return Blitter_32bppSSE_Base::Encode(sprite, allocator);
---
> 		return Blitter_32bppSSE_Base::Encode(sprite, allocator, this);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/blitter/40bpp_anim.cpp cmclient/src/blitter/40bpp_anim.cpp
192c192
< 								*anim = 0;
---
> 								*anim = mode == BM_CRASH_REMAP ? 0 : remap[this->CM_GetMForRGB(src_px->r, src_px->g, src_px->b)];
Only in cmclient/src/blitter: base.cpp
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/bridge_gui.cpp cmclient/src/bridge_gui.cpp
25a26
> #include "tilehighlight_func.h"
30a32,33
> #include "citymania/cm_hotkeys.hpp"
> 
74a78,79
> 
> 	StoreRailPlacementEndpoints(p1, end_tile, (TileX(p1) == TileX(end_tile)) ? TRACK_Y : TRACK_X, false);
385c390
< 	if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) {
---
> 	if (citymania::_fn_mod && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/build_vehicle_gui.cpp cmclient/src/build_vehicle_gui.cpp
35c35
< 
---
> #include "hotkeys.h"
37a38,39
> #include "citymania/cm_hotkeys.hpp"
> 
880a883,888
> 	if (_settings_client.gui.newgrf_developer_tools) {
> 		SetDParam(0, e->index);
> 		DrawString(left, right, y, STR_CM_PURCHASE_ENGINE_ID);
> 		y += FONT_HEIGHT_NORMAL;
> 	}
> 
1446c1454
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
1669a1678,1690
> 
> 	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
1670a1692
> HotkeyList BuildVehicleWindow::hotkeys("build_vehicle", build_vehicle_hotkeys);
1676c1698,1699
< 	_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
---
> 	_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets),
> 	&BuildVehicleWindow::hotkeys
Only in cmclient/src: citymania
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/CMakeLists.txt cmclient/src/CMakeLists.txt
11a12
> add_subdirectory(citymania)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/command.cpp cmclient/src/command.cpp
26a27,29
> #include "window_func.h"
> #include "network/network_base.h"
> #include "window_func.h"
29a33,35
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_watch_gui.hpp"
> 
568c574
< 	bool estimate_only = _shift_pressed && IsLocalCompany() &&
---
> 	bool estimate_only = citymania::_estimate_mod && IsLocalCompany() &&
571c577,578
< 			!(GetCommandFlags(cmd) & CMD_NO_EST);
---
> 			!(GetCommandFlags(cmd) & CMD_NO_EST) &&
> 			!(cmd & CMD_NO_ESTIMATE);
588a596
> 	if (!(cmd & CMD_NO_ESTIMATE) && my_cmd) citymania::CountEffectiveAction();
763a772,787
> 	}
> 
> 	/* Send Tile Number to Watching Company Windows */
> 	citymania::WatchCompany *wc;
> 	for(int watching_window = 0; ; watching_window++){
> 		wc = dynamic_cast<citymania::WatchCompany*>(FindWindowById(WC_WATCH_COMPANY, watching_window));
> 		if(wc != NULL) wc->OnDoCommand(_current_company, tile);
> 		else break;
> 	}
> 
> 	for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
> 		if (ci->client_playas == _current_company) {
> 			wc = dynamic_cast<citymania::WatchCompany*>(FindWindowById(WC_WATCH_COMPANYA, ci->client_id));
> 			if (wc != NULL) wc->OnDoCommand(_current_company, tile);
> 			break;
> 		}
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/command_type.h cmclient/src/command_type.h
372c372
< #define CMD_MSG(x) ((x) << 16)
---
> #define CMD_MSG(x) ((uint32)((x) << 16))
380a381
> 	CMD_NO_ESTIMATE           = 0x0200, ///< execute command instead of doing estimate even if shift is pressed
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/company_base.h cmclient/src/company_base.h
20a21,22
> #include "citymania/extensions/cmext_company.hpp"
> 
27a30
> 	citymania::ext::CompanyEconomyEntry cm;  ///< CityMania extra economy data.
99a103,104
> 
> 	citymania::ext::Company cm;  ///< CityMania extra company data.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/company_cmd.cpp cmclient/src/company_cmd.cpp
40a41,43
> #include "cargo_type.h"
> 
> #include "citymania/cm_hotkeys.hpp"
71a75,76
> 	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
> 	InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1);
93a99,100
> 	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
> 	InvalidateWindowClassesData(WC_WATCH_COMPANYA, 1);
118a126
> 	if (switching_company) citymania::ResetEffectivveActionCounter();
854a863
> 				UpdateAllTownVirtCoords();  // CityMania (for colouring towns)
1085a1095
> 		InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/company_gui.cpp cmclient/src/company_gui.cpp
42a43,44
> #include "citymania/cm_hotkeys.hpp"
> 
441c443
< 				DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
---
> 				DoCommandP(0, 0, citymania::_fn_mod, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
445c447
< 				DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
---
> 				DoCommandP(0, 0, citymania::_fn_mod, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
970c972
< 					if (_ctrl_pressed) {
---
> 					if (citymania::_fn_mod) {
1000c1002
< 				if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
---
> 				if (HasBit(this->sel, scheme) || (citymania::_fn_mod && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
2184c2186,2193
< 						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(),
2259a2269,2278
> 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);
> 	}
> }
> 
2280a2300,2302
> 
> 		CWP_BUTTONS_PLAYER = 0,
> 		CWP_BUTTONS_MOD,
2345a2368
> 			this->SetWidgetDisabledState(WID_C_COMPANY_JOIN,   c->is_ai);
2347,2349c2370,2371
< 			/* Multiplayer buttons. */
< 			plane = ((!_networking) ? (int)SZSP_NONE : (int)(local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
< 			wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER);
---
> 			plane = (int)(_networking && _novarole ? CWP_BUTTONS_MOD: CWP_BUTTONS_PLAYER);
> 			wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_MOD);
2361a2384,2390
> 		// 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);
> 		// }
> 
2431a2461,2469
> 			// 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;
2589c2627
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2604c2642
< 				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
---
> 				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this, CM_DDSP_BUILD_HQ);
2616c2654
< 				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
---
> 				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this, CM_DDSP_BUILD_HQ);
2655a2694,2721
> 				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();
2669c2735
< 		if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS)) && !_shift_pressed) {
---
> 		if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS)) && !citymania::_estimate_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/console_cmds.cpp cmclient/src/console_cmds.cpp
44a45,46
> #include "citymania/cm_console_cmds.hpp"
> 
2455a2458,2463
> 
> 	IConsoleCmdRegister("cmexport", citymania::ConExport);
> 	IConsoleCmdRegister("cmstep", citymania::ConStep, ConHookNoNetwork);
> 	IConsoleCmdRegister("cmtreemap", citymania::ConTreeMap, ConHookNoNetwork);
> 	IConsoleCmdRegister("cmresettowngrowth", citymania::ConResetTownGrowth, ConHookNoNetwork);
> 	IConsoleCmdRegister("cmloadcommands", citymania::ConLoadCommands, ConHookNoNetwork);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/crashlog.cpp cmclient/src/crashlog.cpp
58a59,61
> #ifdef WITH_ZSTD
> #include <zstd.h>
> #endif
120c123
< 			"OpenTTD version:\n"
---
> 			"OpenTTD version: CityMania patched client  http://citymania.org\n\n"
257a261,264
> #ifdef WITH_ZSTD
> 	buffer += seprintf(buffer, last, " ZSTD:       %s\n", ZSTD_versionString());
> #endif
> 
337c344
< 	buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n");
---
> 	buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\nCityMania patched client  http://citymania.org\nPlease, unless you encounter this bug with unpatched OpenTTD version, report bug to CityMania team\n\n");
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/date.cpp cmclient/src/date.cpp
23a24,25
> #include "citymania/cm_main.hpp"
> 
241a244
> 	citymania::Emit(citymania::event::NewMonth());
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/depot_gui.cpp cmclient/src/depot_gui.cpp
29c29
< 
---
> #include "hotkeys.h"
33a34,35
> #include "citymania/cm_hotkeys.hpp"
> 
82,109d83
< 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)
< );
< 
126a101,103
> 
> 	if (_settings_client.gui.cm_open_orders_for_new_vehicles)
> 		ShowOrdersWindow(v);
144c121
< 	DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == nullptr ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE));
---
> 	DoCommandP(v->tile, v->index | (citymania::_fn_mod ? 1 : 0) << 20, wagon == nullptr ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE));
330,332c307,316
< 				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
> 				}
560c544
< 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_DEPOT_MOVE);
562c546
< 					_cursor.vehchain = _ctrl_pressed;
---
> 					_cursor.vehchain = citymania::_fn_mod;
781c765
< 					SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, HT_VEHICLE, this);
---
> 					SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, HT_VEHICLE, this, CM_DDSP_DEPOT_CLONE);
788c772
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
857c841
< 		bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed);
---
> 		bool whole_chain = (this->type == VEH_TRAIN && citymania::_fn_mod);
904c888,894
< 		if (_ctrl_pressed) {
---
> 		if (_settings_client.gui.cm_open_vehicle_for_shared_clone) { // CM
> 			if (DoCommandP(this->window_number, v->index, citymania::_fn_mod ? 1 : 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle))
> 				ResetObjectToPlace();
> 			return true;
> 		}
> 
> 		if (citymania::_fn_mod) {
1002c992
< 						if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && _ctrl_pressed) {
---
> 						if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && citymania::_fn_mod) {
1028c1018
< 				int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
---
> 				int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || citymania::_fn_mod)) ? 1 : 0;
1065c1055
< 	EventState OnCTRLStateChange() override
---
> 	EventState CM_OnFnModStateChange() override
1068c1058
< 			_cursor.vehchain = _ctrl_pressed;
---
> 			_cursor.vehchain = citymania::_fn_mod;
1084a1075,1089
> 
> 	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
1085a1091
> HotkeyList DepotWindow::hotkeys("depot_gui", depot_hotkeys);
1095a1102,1133
> 
> 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
> );
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/dock_gui.cpp cmclient/src/dock_gui.cpp
33a34,36
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_station_gui.hpp"
> 
148c151
< 				HandlePlacePushButton(this, WID_DT_CANAL, SPR_CURSOR_CANAL, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_DT_CANAL, SPR_CURSOR_CANAL, HT_RECT, CM_DDSP_BUILD_CANNAL);
152c155
< 				HandlePlacePushButton(this, WID_DT_LOCK, SPR_CURSOR_LOCK, HT_SPECIAL);
---
> 				HandlePlacePushButton(this, WID_DT_LOCK, SPR_CURSOR_LOCK, HT_SPECIAL, CM_DDSP_BUILD_LOCK);
156c159
< 				HandlePlacePushButton(this, WID_DT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_DT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
160c163
< 				if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT)) ShowBuildDocksDepotPicker(this);
---
> 				if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT, CM_DDSP_BUILD_SHIP_DEPOT)) ShowBuildDocksDepotPicker(this);
164c167
< 				if (HandlePlacePushButton(this, WID_DT_STATION, SPR_CURSOR_DOCK, HT_SPECIAL)) ShowBuildDockStationPicker(this);
---
> 				if (HandlePlacePushButton(this, WID_DT_STATION, SPR_CURSOR_DOCK, HT_SPECIAL, CM_DDSP_BUILD_DOCK)) ShowBuildDockStationPicker(this);
168c171
< 				HandlePlacePushButton(this, WID_DT_BUOY, SPR_CURSOR_BUOY, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_DT_BUOY, SPR_CURSOR_BUOY, HT_RECT, CM_DDSP_BUILD_BUOY);
173c176
< 				HandlePlacePushButton(this, WID_DT_RIVER, SPR_CURSOR_RIVER, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_DT_RIVER, SPR_CURSOR_RIVER, HT_RECT, CM_DDSP_BUILD_RIVER);
177c180
< 				HandlePlacePushButton(this, WID_DT_BUILD_AQUEDUCT, SPR_CURSOR_AQUEDUCT, HT_SPECIAL);
---
> 				HandlePlacePushButton(this, WID_DT_BUILD_AQUEDUCT, SPR_CURSOR_AQUEDUCT, HT_SPECIAL, CM_DDSP_BUILD_AQUEDUCT);
201a205,206
> 				if (citymania::_fn_mod == _settings_client.gui.persistent_depottools)
> 					ResetObjectToPlace();
204a210,215
> 
> 				if (citymania::UseImprovedStationJoin()) {
> 					citymania::PlaceDock(tile);
> 					break;
> 				}
> 
208c219
< 				CommandContainer cmdcont = { tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" };
---
> 				CommandContainer cmdcont = { tile, citymania::_fn_mod, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" };
247c258
< 					DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcPlaySound_CONSTRUCTION_WATER);
---
> 					DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && citymania::_fn_mod) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcPlaySound_CONSTRUCTION_WATER);
267a279,280
> 
> 		citymania::AbortStationPlacement();
429a443,445
> 		SetTileSelectSize(1, 1);
> 		SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
> 		#if 0
434a451
> 		#endif
442a460
> 		top = DrawStationAuthorityText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top) + WD_PAR_VSEP_NORMAL;
461a480
> 				citymania::MarkCoverageHighlightDirty();
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/economy.cpp cmclient/src/economy.cpp
54a55,57
> #include "citymania/cm_cargo_table_gui.hpp"
> #include "citymania/cm_main.hpp"
> 
374a378,379
> 		ClrBit(t->advertise_regularly, old_owner);
> 		ClrBit(t->do_powerfund, old_owner);
1065a1071,1074
> 
> 		if (amount > 0)
> 			citymania::Emit(citymania::event::CargoDeliveredToIndustry{ind, cargo_type, amount, st});
> 
1109a1119,1126
> 	/* 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->cb.delivered[cargo_type] += accepted_total;
> 			InvalidateWindowData(WC_CB_TOWN, st->town->index);
> 		}
> 	}
> 
1123a1141,1146
> 	}
> 
> 	if (accepted_total > 0) {
> 		if (accepted_ind != accepted_total)
> 			citymania::Emit(citymania::event::CargoDeliveredToUnknown{cargo_type, accepted_total - accepted_ind, st});
> 		citymania::Emit(citymania::event::CargoAccepted{company, cargo_type, accepted_total, st, profit, src_type, src});
Only in cmclient/src: endian_check.cpp
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/engine_gui.cpp cmclient/src/engine_gui.cpp
30a31,32
> #include "citymania/cm_hotkeys.hpp"
> 
131c133
< 				if (!_shift_pressed) delete this;
---
> 				if (!citymania::_estimate_mod) delete this;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/fios_gui.cpp cmclient/src/fios_gui.cpp
56c56
< 	memset(&this->settings, 0, sizeof(this->settings));
---
> 	this->settings = {}; // CM memset(&this->settings, 0, sizeof(this->settings));
363c363
< 		SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
---
> 		SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0, CM_DDSP_ZZZ);
Only in cmclient/src: fontdetection.cpp
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/framerate_gui.cpp cmclient/src/framerate_gui.cpp
314c314
< static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX] = {
---
> static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX - 4] = {
317,320c317,320
< 	PFE_GL_TRAINS,
< 	PFE_GL_ROADVEHS,
< 	PFE_GL_SHIPS,
< 	PFE_GL_AIRCRAFT,
---
> 	// PFE_GL_TRAINS,
> 	// PFE_GL_ROADVEHS,
> 	// PFE_GL_SHIPS,
> 	// PFE_GL_AIRCRAFT,
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/genworld.cpp cmclient/src/genworld.cpp
99c99
< 		SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
---
> 		SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0, CM_DDSP_ZZZ);
314c314
< 	SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
---
> 	SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0, CM_DDSP_ZZZ);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gfx.cpp cmclient/src/gfx.cpp
35a36
> bool _alt_pressed;    ///< Is Alt pressed?
47a49
> uint32 _pause_countdown;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gfx_func.h cmclient/src/gfx_func.h
55a56
> extern bool _alt_pressed;    ///< Is Alt pressed?
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gfxinit.cpp cmclient/src/gfxinit.cpp
193a194
> 	LoadGrfFile("cmclient-3.grf", SPR_INNER_HIGHLIGHT_BASE - 4, i++);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gfx_layout.h cmclient/src/gfx_layout.h
48c48
< 		assert(c >= TC_BLUE && c <= TC_BLACK);
---
> 		// assert(c >= TC_BLUE && c <= TC_BLACK); CM seems redundant and crashes custom colors (in graphs)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gfx_type.h cmclient/src/gfx_type.h
104a105,118
> 
> 	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
> 
> 	CM_WKC_MOUSE_MIDDLE      = 0x703,  ///< CityMania: special code for middle mouse button
> 	CM_WKC_MOUSE_OTHER_START = 0x704,  ///< CityMania: start of the numbered buttons (whatever number driver reports), starts as MOUSE_4 hotkey
> 	CM_WKC_MOUSE_OTHER_END   = 0x71f, ///< CityMania: 30 buttons should be enough for any mouse, right? ;)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/goal_gui.cpp cmclient/src/goal_gui.cpp
30a31,32
> #include "citymania/cm_hotkeys.hpp"
> 
146c148
< 		if (_ctrl_pressed) {
---
> 		if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/graph_gui.cpp cmclient/src/graph_gui.cpp
23a24
> #include "zoom_func.h"
40a42,49
> static const Colours WINDOW_BG1 = COLOUR_BROWN;
> static const Colours WINDOW_BG2 = COLOUR_GREY;
> 
> template<typename T>
> T ChooseGraphColour(T a, T b) {
> 	return _settings_client.gui.cm_graph_background ? b : a;
> }
> 
116c125
< 		NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_BROWN, widnum);
---
> 		NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, ChooseGraphColour(WINDOW_BG1, WINDOW_BG2), widnum);
126c135,152
< static const NWidgetPart _nested_graph_legend_widgets[] = {
---
> static const NWidgetPart _nested_graph_legend_widgets1[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_GL_BACKGROUND),
> 		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(2, 0),
> 			NWidgetFunction(MakeNWidgetCompanyLines),
> 			NWidget(NWID_SPACER), SetMinimalSize(2, 0),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static const NWidgetPart _nested_graph_legend_widgets2[] = {
128,131c154,157
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
133c159
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_GL_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_GL_BACKGROUND),
143c169
< static WindowDesc _graph_legend_desc(
---
> static WindowDesc _graph_legend_desc1(
147c173,180
< 	_nested_graph_legend_widgets, lengthof(_nested_graph_legend_widgets)
---
> 	_nested_graph_legend_widgets1, lengthof(_nested_graph_legend_widgets1)
> );
> 
> static WindowDesc _graph_legend_desc2(
> 	WDP_AUTO, "graph_legend", 0, 0,
> 	WC_GRAPH_LEGEND, WC_NONE,
> 	0,
> 	_nested_graph_legend_widgets2, lengthof(_nested_graph_legend_widgets2)
152c185
< 	AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
---
> 	AllocateWindowDescFront<GraphLegendWindow>(ChooseGraphColour(&_graph_legend_desc1, &_graph_legend_desc2), 0);
164a198,205
> #define GRAPH_BASE_COLOUR (ChooseGraphColour<uint8>(GREY_SCALE(2), GREY_SCALE(8)))
> #define GRAPH_GRID_COLOUR (ChooseGraphColour<uint8>(GREY_SCALE(3), _colour_gradient[COLOUR_GREY][4]))
> #define GRAPH_AXIS_LINE_COLOUR (ChooseGraphColour<uint8>(GREY_SCALE(3), GREY_SCALE(2)))
> #define GRAPH_ZERO_LINE_COLOUR (ChooseGraphColour<uint8>(GREY_SCALE(8), GREY_SCALE(2)))
> #define GRAPH_YEAR_LINE_COLOUR (ChooseGraphColour<uint8>(GREY_SCALE(5), GREY_SCALE(7)))
> #define GRAPH_AXIS_LABEL_COLOUR (ChooseGraphColour((TextColour)((uint)TC_IS_PALETTE_COLOUR | 0xC), TC_BLACK))
> #define GRAPH_OUTLINE_COLOUR (ChooseGraphColour<uint8>(PC_GREY, GREY_SCALE(6)))
> 
168,172d208
< 	static const int GRAPH_BASE_COLOUR      =  GREY_SCALE(2);
< 	static const int GRAPH_GRID_COLOUR      =  GREY_SCALE(3);
< 	static const int GRAPH_AXIS_LINE_COLOUR =  GREY_SCALE(1);
< 	static const int GRAPH_ZERO_LINE_COLOUR =  GREY_SCALE(8);
< 	static const int GRAPH_YEAR_LINE_COLOUR =  GREY_SCALE(5);
175,176d210
< 	static const TextColour GRAPH_AXIS_LABEL_COLOUR = TC_BLACK; ///< colour of the graph axis label.
< 
178c212
< 	static const int MIN_GRID_PIXEL_SIZE    =  20; ///< Minimum distance between graph lines.
---
> 	static const int MIN_GRID_PIXEL_SIZE    =  10; ///< Minimum distance between graph lines.
299a334,339
> 		r.top += ScaleGUITrad(2);
> 		r.left += ScaleGUITrad(2);
> 		r.bottom -= ScaleGUITrad(2);
> 
> 		GfxFillRect(r.left, r.top, r.right, r.bottom, GRAPH_BASE_COLOUR);
> 
302,305c342,345
< 		r.top    += 5 + GetCharacterHeight(FS_SMALL) / 2;
< 		r.bottom -= (this->month == 0xFF ? 1 : 2) * GetCharacterHeight(FS_SMALL) + 4;
< 		r.left   += 9;
< 		r.right  -= 5;
---
> 		r.top    += ScaleGUITrad(5) + GetCharacterHeight(FS_SMALL) / 2;
> 		r.bottom -= (this->month == 0xFF ? 1 : 2) * GetCharacterHeight(FS_SMALL) + ScaleGUITrad(4);
> 		r.left   += ScaleGUITrad(9);
> 		r.right  -= ScaleGUITrad(5);
306a347
> 		int grid_size_y = std::max(ScaleGUITrad(MIN_GRID_PIXEL_SIZE), FONT_HEIGHT_NORMAL + ScaleGUITrad(WD_PAR_VSEP_NORMAL));
308c349
< 		int num_hori_lines = 160 / MIN_GRID_PIXEL_SIZE;
---
> 		int num_hori_lines = ScaleGUITrad(160) / grid_size_y;
310c351
< 		int resize = (r.bottom - r.top - 160) / (2 * MIN_GRID_PIXEL_SIZE);
---
> 		int resize = (r.bottom - r.top - ScaleGUITrad(160)) / (2 * grid_size_y);
332a374
> 		// GfxFillRect(r.left, r.top, r.right, r.bottom, GRAPH_BASE_COLOUR);
336,342c378,385
< 		/* Don't draw the first line, as that's where the axis will be. */
< 		x = r.left + x_sep;
< 
< 		for (int i = 0; i < this->num_vert_lines; i++) {
< 			GfxFillRect(x, r.top, x, r.bottom, GRAPH_GRID_COLOUR);
< 			x += x_sep;
< 		}
---
> 		// CityMania don't draw for less clutter
> 		// /* Don't draw the first line, as that's where the axis will be. */
> 		// x = r.left + x_sep;
> 
> 		// for (int i = 0; i < this->num_vert_lines; i++) {
> 		// 	GfxFillRect(x, r.top, x, r.bottom, GRAPH_GRID_COLOUR);
> 		// 	x += x_sep;
> 		// }
346a390,391
> 		uint line_rect_sub = (ScaleGUITrad(1) - 1) / 2;
> 		uint line_rect_add = ScaleGUITrad(1) / 2;
348,349c393
< 			GfxFillRect(r.left - 3, y, r.left - 1, y, GRAPH_AXIS_LINE_COLOUR);
< 			GfxFillRect(r.left, y, r.right, y, GRAPH_GRID_COLOUR);
---
> 			GfxFillRect(r.left - (i && i != num_hori_lines ? ScaleGUITrad(3) : 0), y - line_rect_sub, r.right, y + line_rect_add, GRAPH_GRID_COLOUR);
354c398
< 		GfxFillRect(r.left, r.top, r.left, r.bottom, GRAPH_AXIS_LINE_COLOUR);
---
> 		GfxFillRect(r.left - line_rect_sub, r.top, r.left + line_rect_add, r.bottom, GRAPH_AXIS_LINE_COLOUR);
358c402
< 		GfxFillRect(r.left, y, r.right, y, GRAPH_ZERO_LINE_COLOUR);
---
> 		GfxFillRect(r.left, y - line_rect_sub, r.right, y + line_rect_add, GRAPH_ZERO_LINE_COLOUR);
372c416
< 		for (int i = 0; i < (num_hori_lines + 1); i++) {
---
> 		for (int i = 0; i < num_hori_lines; i++) {
375c419
< 			DrawString(r.left - label_width - 4, r.left - 4, y, STR_GRAPH_Y_LABEL, GRAPH_AXIS_LABEL_COLOUR, SA_RIGHT);
---
> 			if (i) DrawString(r.left - label_width - ScaleGUITrad(4), r.left - ScaleGUITrad(4), y, STR_GRAPH_Y_LABEL, GRAPH_AXIS_LABEL_COLOUR, SA_RIGHT);
390c434
< 				DrawStringMultiLine(x, x + x_sep, y, this->height, month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, GRAPH_AXIS_LABEL_COLOUR, SA_LEFT);
---
> 				if (i) DrawStringMultiLine(x - x_sep / 2, x + x_sep / 2, y + ScaleGUITrad(4), this->height, month == 6 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, GRAPH_AXIS_LABEL_COLOUR, SA_HOR_CENTER);
398c442
< 					GfxFillRect(x + x_sep, r.top + 1, x + x_sep, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
---
> 					GfxFillRect(x + x_sep - line_rect_sub, r.top + 1, x + x_sep + line_rect_add, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
425a470,513
> 				Colour c = _cur_palette.palette[this->colours[i]];
> 				uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
> 				if (_settings_client.gui.cm_graph_background == 0 && sq1000_brightness > 64 * 64 * 1000) continue;
> 				if (_settings_client.gui.cm_graph_background == 1 && sq1000_brightness < 192 * 64 * 1000) continue;
> 
> 				uint prev_x = INVALID_DATAPOINT_POS;
> 				uint prev_y = INVALID_DATAPOINT_POS;
> 
> 				for (int j = 0; j < this->num_on_x_axis; j++) {
> 					OverflowSafeInt64 datapoint = this->cost[i][j];
> 
> 					if (datapoint != INVALID_DATAPOINT) {
> 						int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
> 						int reduce_range = std::max(mult_range - 31, 0);
> 
> 						if (datapoint < 0) {
> 							datapoint = -(abs(datapoint) >> reduce_range);
> 						} else {
> 							datapoint >>= reduce_range;
> 						}
> 						y = r.top + x_axis_offset - ((r.bottom - r.top) * datapoint) / (interval_size >> reduce_range);
> 
> 						/* Draw the point. */
> 						GfxFillRect(x - pointoffs1 - 1, y - pointoffs1 - 1, x + pointoffs2 + 1, y + pointoffs2 + 1, GRAPH_OUTLINE_COLOUR);
> 
> 						/* Draw the line connected to the previous point. */
> 						if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, GRAPH_OUTLINE_COLOUR, linewidth + 2);
> 
> 						prev_x = x;
> 						prev_y = y;
> 					} else {
> 						prev_x = INVALID_DATAPOINT_POS;
> 						prev_y = INVALID_DATAPOINT_POS;
> 					}
> 
> 					x += x_sep;
> 				}
> 			}
> 		}
> 		for (int i = 0; i < this->num_dataset; i++) {
> 			if (!HasBit(this->excluded_data, i)) {
> 				/* Centre the dot between the grid lines. */
> 				x = r.left + (x_sep / 2);
> 
525,526c613,614
< 		size->width  = std::max<uint>(size->width,  5 + y_label_width + this->num_on_x_axis * (x_label_width + 5) + 9);
< 		size->height = std::max<uint>(size->height, 5 + (1 + MIN_GRAPH_NUM_LINES_Y * 2 + (this->month != 0xFF ? 3 : 1)) * FONT_HEIGHT_SMALL + 4);
---
> 		size->width  = std::max<uint>(size->width,  ScaleGUITrad(7) + y_label_width + this->num_on_x_axis * (x_label_width + ScaleGUITrad(5)) + ScaleGUITrad(9));
> 		size->height = std::max<uint>(size->height, ScaleGUITrad(8) + (1 + MIN_GRAPH_NUM_LINES_Y * 2 + (this->month != 0xFF ? 3 : 1)) * FONT_HEIGHT_SMALL + ScaleGUITrad(4));
617a706,858
> struct ExcludingCargoBaseGraphWindow : BaseGraphWindow {
> 	bool show_cargo_colors;
> 
> 	ExcludingCargoBaseGraphWindow(WindowDesc *desc, int widget, StringID format_str_y_axis, bool show_cargo_colors):
> 			BaseGraphWindow(desc, widget, format_str_y_axis), show_cargo_colors{show_cargo_colors}
> 	{
> 	}
> 
> 	uint line_height;   ///< Pixel height of each cargo type row.
> 	uint icon_size;     ///< Size of the cargo color icon.
> 	Scrollbar *vscroll; ///< Cargo list scrollbar.
> 
> 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
> 	{
> 		if (widget != WID_CPR_MATRIX) {
> 			BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
> 			return;
> 		}
> 
> 		Dimension max_cargo_dim = {0, 0};
> 		const CargoSpec *cs;
> 		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
> 			SetDParam(0, cs->name);
> 			max_cargo_dim = maxdim(max_cargo_dim, GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO));
> 		}
> 
> 		this->icon_size = std::max<uint>(max_cargo_dim.height, 6);
> 		this->line_height = this->icon_size + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
> 		size->width = (max_cargo_dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + 1
> 		               + (this->show_cargo_colors ? this->icon_size + WD_PAR_VSEP_NORMAL : 0));
> 		size->height = std::max<uint>(size->height, this->line_height * _sorted_standard_cargo_specs_size);
> 		resize->width = 0;
> 		resize->height = this->line_height;
> 		fill->width = 0;
> 		fill->height = this->line_height;
> 	}
> 
> 	virtual void DrawWidget(const Rect &r, int widget) const
> 	{
> 		if (widget != WID_CPR_MATRIX) {
> 			BaseGraphWindow::DrawWidget(r, widget);
> 			return;
> 		}
> 
> 		bool rtl = _current_text_dir == TD_RTL;
> 
> 		int x = r.left + WD_FRAMERECT_LEFT;
> 		int y = r.top;
> 
> 		int pos = this->vscroll->GetPosition();
> 		int max = pos + this->vscroll->GetCapacity();
> 
> 		const CargoSpec *cs;
> 		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
> 			if (pos-- > 0) continue;
> 			if (--max < 0) break;
> 
> 			bool lowered = !HasBit(_legend_excluded_cargo, cs->Index());
> 
> 			/* Redraw box if lowered */
> 			if (lowered) DrawFrameRect(r.left, y, r.right, y + this->line_height - 1, ChooseGraphColour(WINDOW_BG1, WINDOW_BG2), lowered ? FR_LOWERED : FR_NONE);
> 
> 			byte clk_dif = lowered ? 1 : 0;
> 
> 			uint icon_offset = 0;
> 			if (this->show_cargo_colors) {
> 				int rect_x = clk_dif + 1 + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT);
> 				GfxFillRect(rect_x, y + 1 + clk_dif, rect_x + this->icon_size - 2, y + this->icon_size - 2 + clk_dif, PC_BLACK);
> 				GfxFillRect(rect_x + 1, y + 2 + clk_dif, rect_x + this->icon_size - 3, y + this->icon_size - 3 + clk_dif, cs->legend_colour);
> 				icon_offset = this->icon_size + WD_PAR_VSEP_NORMAL;
> 			}
> 
> 			SetDParam(0, cs->name);
> 			DrawString(rtl ? r.left : x + icon_offset + clk_dif, (rtl ? r.right - icon_offset + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
> 
> 			y += this->line_height;
> 		}
> 	}
> 
> 	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++;
> 		}
> 	}
> 
> 	virtual void OnClick(Point pt, int widget, int click_count)
> 	{
> 		switch (widget) {
> 			case WID_CPR_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->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->SetDirty();
> 				break;
> 			}
> 
> 			case WID_CPR_MATRIX: {
> 				uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX, 0, this->line_height);
> 				if (row >= this->vscroll->GetCount()) return;
> 
> 				const CargoSpec *cs;
> 				FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
> 					if (row-- > 0) continue;
> 
> 					ToggleBit(_legend_excluded_cargo, cs->Index());
> 					this->UpdateExcludedData();
> 					this->SetDirty();
> 					break;
> 				}
> 				break;
> 			}
> 		}
> 	}
> 
> 	virtual void OnResize()
> 	{
> 		this->vscroll->SetCapacityFromWidget(this, WID_CPR_MATRIX);
> 	}
> 
> 	/**
> 	 * Some data on this window has become invalid.
> 	 * @param data Information about the changed data.
> 	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
> 	 */
> 	virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
> 	{
> 		if (!gui_scope) return;
> 		this->UpdateExcludedData();
> 	}
> };
> 
635c876,896
< static const NWidgetPart _nested_operating_profit_widgets[] = {
---
> static const NWidgetPart _nested_operating_profit_widgets1[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CV_BACKGROUND),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_CV_GRAPH), SetMinimalSize(576, 160), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_CV_RESIZE),
> 			EndContainer(),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static const NWidgetPart _nested_operating_profit_widgets2[] = {
637,642c898,903
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
644c905
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CV_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CV_BACKGROUND),
646c907
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CV_GRAPH), SetMinimalSize(576, 160), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_CV_GRAPH), SetMinimalSize(576, 160), SetFill(1, 1), SetResize(1, 1),
649c910
< 				NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_CV_RESIZE),
---
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_CV_RESIZE),
655c916
< static WindowDesc _operating_profit_desc(
---
> static WindowDesc _operating_profit_desc1(
659c920
< 	_nested_operating_profit_widgets, lengthof(_nested_operating_profit_widgets)
---
> 	_nested_operating_profit_widgets1, lengthof(_nested_operating_profit_widgets1)
661a923,928
> static WindowDesc _operating_profit_desc2(
> 	WDP_AUTO, "graph_operating_profit", 0, 0,
> 	WC_OPERATING_PROFIT, WC_NONE,
> 	0,
> 	_nested_operating_profit_widgets2, lengthof(_nested_operating_profit_widgets2)
> );
665c932
< 	AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
---
> 	AllocateWindowDescFront<OperatingProfitGraphWindow>(ChooseGraphColour(&_operating_profit_desc1, &_operating_profit_desc2), 0);
673c940
< struct IncomeGraphWindow : BaseGraphWindow {
---
> struct IncomeGraphWindow : ExcludingCargoBaseGraphWindow {
675c942
< 			BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_CURRENCY_SHORT)
---
> 			ExcludingCargoBaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_CURRENCY_SHORT, false)
677c944,948
< 		this->InitializeWindow(window_number);
---
> 		this->CreateNestedTree();
> 		this->vscroll = this->GetScrollbar(WID_CPR_MATRIX_SCROLLBAR);
> 		this->vscroll->SetCount(_sorted_standard_cargo_specs_size);
> 		this->UpdateExcludedData();
> 		this->FinishInitNested(window_number);
681a953
> 		if(_legend_excluded_cargo == 0){
683a956,964
> 		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].cm.cargo_income[cs->Index()];
> 			}
> 		}
> 		return total_income;
> 	}
686c967
< static const NWidgetPart _nested_income_graph_widgets[] = {
---
> static const NWidgetPart _nested_income_graph_widgets1[] = {
688,693c969,974
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
695c976
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CV_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CPR_BACKGROUND),
697c978
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_CPR_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
699,700c980,1022
< 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
< 				NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_CV_RESIZE),
---
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, 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),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_MATRIX, WINDOW_BG1, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG1, WID_CPR_MATRIX_SCROLLBAR),
> 				EndContainer(),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 			EndContainer(),
> 			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG1, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_CPR_RESIZE),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static const NWidgetPart _nested_income_graph_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CPR_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CPR_BACKGROUND),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_CPR_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, 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),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_MATRIX, WINDOW_BG2, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG2, WID_CPR_MATRIX_SCROLLBAR),
> 				EndContainer(),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
701a1024,1030
> 			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG2, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_CPR_RESIZE),
706c1035,1042
< static WindowDesc _income_graph_desc(
---
> static WindowDesc _income_graph_desc1(
> 	WDP_AUTO, "graph_income", 0, 0,
> 	WC_INCOME_GRAPH, WC_NONE,
> 	0,
> 	_nested_income_graph_widgets1, lengthof(_nested_income_graph_widgets1)
> );
> 
> static WindowDesc _income_graph_desc2(
710c1046
< 	_nested_income_graph_widgets, lengthof(_nested_income_graph_widgets)
---
> 	_nested_income_graph_widgets2, lengthof(_nested_income_graph_widgets2)
715c1051
< 	AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
---
> 	AllocateWindowDescFront<IncomeGraphWindow>(ChooseGraphColour(&_income_graph_desc1, &_income_graph_desc2), 0);
722c1058
< struct DeliveredCargoGraphWindow : BaseGraphWindow {
---
> struct DeliveredCargoGraphWindow : ExcludingCargoBaseGraphWindow {
724c1060
< 			BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_COMMA)
---
> 			ExcludingCargoBaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_COMMA, false)
726c1062,1066
< 		this->InitializeWindow(window_number);
---
> 		this->CreateNestedTree();
> 		this->vscroll = this->GetScrollbar(WID_CPR_MATRIX_SCROLLBAR);
> 		this->vscroll->SetCount(_sorted_standard_cargo_specs_size);
> 		this->OnHundredthTick();
> 		this->FinishInitNested(window_number);
730a1071
> 		if(_legend_excluded_cargo == 0){
732a1074,1082
> 		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;
> 	}
735c1085
< static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
---
> static const NWidgetPart _nested_delivered_cargo_graph_widgets1[] = {
737,742c1087,1092
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
744c1094
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CV_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CPR_BACKGROUND),
746c1096
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_CPR_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
748,749c1098,1140
< 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
< 				NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_CV_RESIZE),
---
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4), SetFill(0, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, 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),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_MATRIX, WINDOW_BG1, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG1, WID_CPR_MATRIX_SCROLLBAR),
> 				EndContainer(),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 			EndContainer(),
> 			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG1, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_CPR_RESIZE),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static const NWidgetPart _nested_delivered_cargo_graph_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CPR_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CPR_BACKGROUND),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_CPR_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4), SetFill(0, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, 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),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_MATRIX, WINDOW_BG2, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG2, WID_CPR_MATRIX_SCROLLBAR),
> 				EndContainer(),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
750a1142,1148
> 			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG2, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_CPR_RESIZE),
755c1153,1160
< static WindowDesc _delivered_cargo_graph_desc(
---
> static WindowDesc _delivered_cargo_graph_desc1(
> 	WDP_AUTO, "graph_delivered_cargo", 0, 0,
> 	WC_DELIVERED_CARGO, WC_NONE,
> 	0,
> 	_nested_delivered_cargo_graph_widgets1, lengthof(_nested_delivered_cargo_graph_widgets1)
> );
> 
> static WindowDesc _delivered_cargo_graph_desc2(
759c1164
< 	_nested_delivered_cargo_graph_widgets, lengthof(_nested_delivered_cargo_graph_widgets)
---
> 	_nested_delivered_cargo_graph_widgets2, lengthof(_nested_delivered_cargo_graph_widgets2)
764c1169
< 	AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
---
> 	AllocateWindowDescFront<DeliveredCargoGraphWindow>(ChooseGraphColour(&_delivered_cargo_graph_desc1, &_delivered_cargo_graph_desc2), 0);
790c1195
< static const NWidgetPart _nested_performance_history_widgets[] = {
---
> static const NWidgetPart _nested_performance_history_widgets1[] = {
792,798c1197,1203
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_PHG_DETAILED_PERFORMANCE), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_PHG_KEY), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_PHG_DETAILED_PERFORMANCE), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_PHG_KEY), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
800c1205
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_PHG_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_PHG_BACKGROUND),
802c1207
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_PHG_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_PHG_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
805c1210
< 				NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_PHG_RESIZE),
---
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_PHG_RESIZE),
811c1216,1236
< static WindowDesc _performance_history_desc(
---
> static const NWidgetPart _nested_performance_history_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_PHG_DETAILED_PERFORMANCE), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_PHG_KEY), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_PHG_BACKGROUND),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_PHG_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_PHG_RESIZE),
> 			EndContainer(),
> 		EndContainer(),
> 	EndContainer(),
> };
> static WindowDesc _performance_history_desc1(
815c1240,1247
< 	_nested_performance_history_widgets, lengthof(_nested_performance_history_widgets)
---
> 	_nested_performance_history_widgets1, lengthof(_nested_performance_history_widgets1)
> );
> 
> static WindowDesc _performance_history_desc2(
> 	WDP_AUTO, "graph_performance", 0, 0,
> 	WC_PERFORMANCE_HISTORY, WC_NONE,
> 	0,
> 	_nested_performance_history_widgets2, lengthof(_nested_performance_history_widgets2)
820c1252
< 	AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
---
> 	AllocateWindowDescFront<PerformanceHistoryGraphWindow>(ChooseGraphColour(&_performance_history_desc1, &_performance_history_desc2), 0);
840c1272,1292
< static const NWidgetPart _nested_company_value_graph_widgets[] = {
---
> static const NWidgetPart _nested_company_value_graph_widgets1[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CV_BACKGROUND),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_CV_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1),
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_CV_RESIZE),
> 			EndContainer(),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static const NWidgetPart _nested_company_value_graph_widgets2[] = {
842,847c1294,1299
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
849c1301
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CV_BACKGROUND),
---
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CV_BACKGROUND),
851c1303
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CV_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_CV_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1),
854c1306
< 				NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_CV_RESIZE),
---
> 				NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_CV_RESIZE),
860c1312,1319
< static WindowDesc _company_value_graph_desc(
---
> static WindowDesc _company_value_graph_desc1(
> 	WDP_AUTO, "graph_company_value", 0, 0,
> 	WC_COMPANY_VALUE, WC_NONE,
> 	0,
> 	_nested_company_value_graph_widgets1, lengthof(_nested_company_value_graph_widgets1)
> );
> 
> static WindowDesc _company_value_graph_desc2(
864c1323
< 	_nested_company_value_graph_widgets, lengthof(_nested_company_value_graph_widgets)
---
> 	_nested_company_value_graph_widgets2, lengthof(_nested_company_value_graph_widgets2)
869c1328
< 	AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
---
> 	AllocateWindowDescFront<CompanyValueGraphWindow>(ChooseGraphColour(&_company_value_graph_desc1, &_company_value_graph_desc2), 0);
876,879c1335
< struct PaymentRatesGraphWindow : BaseGraphWindow {
< 	uint line_height;   ///< Pixel height of each cargo type row.
< 	Scrollbar *vscroll; ///< Cargo list scrollbar.
< 
---
> struct PaymentRatesGraphWindow : ExcludingCargoBaseGraphWindow {
881c1337
< 			BaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_CURRENCY_SHORT)
---
> 			ExcludingCargoBaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_CURRENCY_SHORT, true)
883,884c1339,1340
< 		this->num_on_x_axis = 20;
< 		this->num_vert_lines = 20;
---
> 		this->num_on_x_axis = 24;
> 		this->num_vert_lines = 24;
886,887c1342,1343
< 		this->x_values_start     = 10;
< 		this->x_values_increment = 10;
---
> 		this->x_values_start     = 20;
> 		this->x_values_increment = 20;
899,1016d1354
< 	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 UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
< 	{
< 		if (widget != WID_CPR_MATRIX) {
< 			BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
< 			return;
< 		}
< 
< 		const CargoSpec *cs;
< 		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
< 			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);
< 		}
< 
< 		this->line_height = size->height;
< 		size->height = this->line_height * 11; /* Default number of cargo types in most climates. */
< 		resize->width = 0;
< 		resize->height = this->line_height;
< 	}
< 
< 	void DrawWidget(const Rect &r, int widget) const override
< 	{
< 		if (widget != WID_CPR_MATRIX) {
< 			BaseGraphWindow::DrawWidget(r, widget);
< 			return;
< 		}
< 
< 		bool rtl = _current_text_dir == TD_RTL;
< 
< 		int x = r.left + WD_FRAMERECT_LEFT;
< 		int y = r.top;
< 
< 		int pos = this->vscroll->GetPosition();
< 		int max = pos + this->vscroll->GetCapacity();
< 
< 		const CargoSpec *cs;
< 		FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
< 			if (pos-- > 0) continue;
< 			if (--max < 0) break;
< 
< 			bool lowered = !HasBit(_legend_excluded_cargo, cs->Index());
< 
< 			/* Redraw box if lowered */
< 			if (lowered) DrawFrameRect(r.left, y, r.right, y + this->line_height - 1, COLOUR_BROWN, lowered ? FR_LOWERED : FR_NONE);
< 
< 			byte clk_dif = lowered ? 1 : 0;
< 			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);
< 
< 			y += this->line_height;
< 		}
< 	}
< 
< 	void OnClick(Point pt, int widget, int click_count) override
< 	{
< 		switch (widget) {
< 			case WID_CPR_ENABLE_CARGOES:
< 				/* Remove all cargoes from the excluded lists. */
< 				_legend_excluded_cargo = 0;
< 				this->excluded_data = 0;
< 				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->SetDirty();
< 				break;
< 			}
< 
< 			case WID_CPR_MATRIX: {
< 				uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX, 0, this->line_height);
< 				if (row >= this->vscroll->GetCount()) return;
< 
< 				const CargoSpec *cs;
< 				FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
< 					if (row-- > 0) continue;
< 
< 					ToggleBit(_legend_excluded_cargo, cs->Index());
< 					this->UpdateExcludedData();
< 					this->SetDirty();
< 					break;
< 				}
< 				break;
< 			}
< 		}
< 	}
< 
< 	void OnResize() override
< 	{
< 		this->vscroll->SetCapacityFromWidget(this, WID_CPR_MATRIX);
< 	}
< 
1022,1032d1359
< 	/**
< 	 * Some data on this window has become invalid.
< 	 * @param data Information about the changed data.
< 	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
< 	 */
< 	void OnInvalidateData(int data = 0, bool gui_scope = true) override
< 	{
< 		if (!gui_scope) return;
< 		this->OnHundredthTick();
< 	}
< 
1041,1042c1368,1369
< 			for (uint j = 0; j != 20; j++) {
< 				this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index());
---
> 			for (uint j = 0; j != 24; j++) {
> 				this->cost[i][j] = GetTransportedGoodsIncome(10, 20, 2*(j * 4 + 4), cs->Index());
1050c1377
< static const NWidgetPart _nested_cargo_payment_rates_widgets[] = {
---
> static const NWidgetPart _nested_cargo_payment_rates_widgets1[] = {
1052,1056c1379,1383
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
1058c1385
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CPR_BACKGROUND), SetMinimalSize(568, 128),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CPR_BACKGROUND), SetMinimalSize(568, 128),
1061c1388
< 			NWidget(WWT_TEXT, COLOUR_BROWN, WID_CPR_HEADER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE, STR_NULL),
---
> 			NWidget(WWT_TEXT, WINDOW_BG1, WID_CPR_HEADER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE, STR_NULL),
1065c1392
< 			NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CPR_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1),
---
> 			NWidget(WWT_EMPTY, WINDOW_BG1, WID_CPR_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1),
1067,1069c1394,1396
< 				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
< 				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
< 				NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, 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),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG1, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0),
1072,1073c1399,1400
< 					NWidget(WWT_MATRIX, COLOUR_BROWN, WID_CPR_MATRIX), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
< 					NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_CPR_MATRIX_SCROLLBAR),
---
> 					NWidget(WWT_MATRIX, WINDOW_BG1, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG1, WID_CPR_MATRIX_SCROLLBAR),
1075c1402
< 				NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
---
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
1081c1408
< 			NWidget(WWT_TEXT, COLOUR_BROWN, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
---
> 			NWidget(WWT_TEXT, WINDOW_BG1, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
1083c1410
< 			NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_CPR_RESIZE),
---
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG1, WID_CPR_RESIZE),
1088c1415,1453
< static WindowDesc _cargo_payment_rates_desc(
---
> static const NWidgetPart _nested_cargo_payment_rates_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_DEFSIZEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CPR_BACKGROUND), SetMinimalSize(568, 128),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG2, WID_CPR_HEADER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_EMPTY, WINDOW_BG2, WID_CPR_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1),
> 			NWidget(NWID_VERTICAL),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0),
> 				NWidget(WWT_PUSHTXTBTN, WINDOW_BG2, 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),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_MATRIX, WINDOW_BG2, WID_CPR_MATRIX), SetFill(0, 2), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR),
> 					NWidget(NWID_VSCROLLBAR, WINDOW_BG2, WID_CPR_MATRIX_SCROLLBAR),
> 				EndContainer(),
> 				NWidget(NWID_SPACER), SetMinimalSize(0, 4),
> 			EndContainer(),
> 			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1),
> 		EndContainer(),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_TEXT, WINDOW_BG2, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
> 			NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
> 			NWidget(WWT_RESIZEBOX, WINDOW_BG2, WID_CPR_RESIZE),
> 		EndContainer(),
> 	EndContainer(),
> };
> 
> static WindowDesc _cargo_payment_rates_desc1(
1092c1457,1464
< 	_nested_cargo_payment_rates_widgets, lengthof(_nested_cargo_payment_rates_widgets)
---
> 	_nested_cargo_payment_rates_widgets1, lengthof(_nested_cargo_payment_rates_widgets1)
> );
> 
> static WindowDesc _cargo_payment_rates_desc2(
> 	WDP_AUTO, "graph_cargo_payment_rates", 0, 0,
> 	WC_PAYMENT_RATES, WC_NONE,
> 	0,
> 	_nested_cargo_payment_rates_widgets2, lengthof(_nested_cargo_payment_rates_widgets2)
1098c1470
< 	AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
---
> 	AllocateWindowDescFront<PaymentRatesGraphWindow>(ChooseGraphColour(&_cargo_payment_rates_desc1, &_cargo_payment_rates_desc2), 0);
1265c1637
< static const NWidgetPart _nested_company_league_widgets[] = {
---
> static const NWidgetPart _nested_company_league_widgets1[] = {
1267,1270c1639,1642
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
1272c1644
< 	NWidget(WWT_PANEL, COLOUR_BROWN, WID_CL_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1, WID_CL_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM),
1275c1647,1664
< static WindowDesc _company_league_desc(
---
> static const NWidgetPart _nested_company_league_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2, WID_CL_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM),
> };
> 
> static WindowDesc _company_league_desc1(
> 	WDP_AUTO, "league", 0, 0,
> 	WC_COMPANY_LEAGUE, WC_NONE,
> 	0,
> 	_nested_company_league_widgets1, lengthof(_nested_company_league_widgets1)
> );
> 
> static WindowDesc _company_league_desc2(
1279c1668
< 	_nested_company_league_widgets, lengthof(_nested_company_league_widgets)
---
> 	_nested_company_league_widgets2, lengthof(_nested_company_league_widgets2)
1284c1673
< 	AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
---
> 	AllocateWindowDescFront<CompanyLeagueWindow>(ChooseGraphColour(&_company_league_desc1, &_company_league_desc2), 0);
1542c1931
< 		NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_BROWN, widnum);
---
> 		NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, ChooseGraphColour(WINDOW_BG1, WINDOW_BG2), widnum);
1554c1943
< 	return MakeCompanyButtonRows(biggest_index, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, COLOUR_BROWN, 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP);
---
> 	return MakeCompanyButtonRows(biggest_index, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, ChooseGraphColour(WINDOW_BG1, WINDOW_BG2), 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP);
1557c1946
< static const NWidgetPart _nested_performance_rating_detail_widgets[] = {
---
> static const NWidgetPart _nested_performance_rating_detail_widgets1[] = {
1559,1562c1948,1951
< 		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
< 		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_PERFORMANCE_DETAIL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
< 		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
< 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
---
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG1),
> 		NWidget(WWT_CAPTION, WINDOW_BG1), SetDataTip(STR_PERFORMANCE_DETAIL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG1),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG1),
1564c1953
< 	NWidget(WWT_PANEL, COLOUR_BROWN),
---
> 	NWidget(WWT_PANEL, WINDOW_BG1),
1570c1959,1979
< static WindowDesc _performance_rating_detail_desc(
---
> static const NWidgetPart _nested_performance_rating_detail_widgets2[] = {
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(WWT_CLOSEBOX, WINDOW_BG2),
> 		NWidget(WWT_CAPTION, WINDOW_BG2), SetDataTip(STR_PERFORMANCE_DETAIL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_SHADEBOX, WINDOW_BG2),
> 		NWidget(WWT_STICKYBOX, WINDOW_BG2),
> 	EndContainer(),
> 	NWidget(WWT_PANEL, WINDOW_BG2),
> 		NWidgetFunction(MakeCompanyButtonRowsGraphGUI), SetPadding(0, 1, 1, 2),
> 	EndContainer(),
> 	NWidgetFunction(MakePerformanceDetailPanels),
> };
> 
> static WindowDesc _performance_rating_detail_desc1(
> 	WDP_AUTO, "league_details", 0, 0,
> 	WC_PERFORMANCE_DETAIL, WC_NONE,
> 	0,
> 	_nested_performance_rating_detail_widgets1, lengthof(_nested_performance_rating_detail_widgets1)
> );
> 
> static WindowDesc _performance_rating_detail_desc2(
1574c1983
< 	_nested_performance_rating_detail_widgets, lengthof(_nested_performance_rating_detail_widgets)
---
> 	_nested_performance_rating_detail_widgets2, lengthof(_nested_performance_rating_detail_widgets2)
1579c1988
< 	AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
---
> 	AllocateWindowDescFront<PerformanceRatingDetailWindow>(ChooseGraphColour(&_performance_rating_detail_desc1, &_performance_rating_detail_desc2), 0);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/group_gui.cpp cmclient/src/group_gui.cpp
31a32,33
> #include "citymania/cm_hotkeys.hpp"
> 
717c719
< 				SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 				SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_GROUP);
756c758
< 					if (_ctrl_pressed) {
---
> 					if (citymania::_fn_mod) {
760c762
< 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_GROUP);
807c809
< 					DoCommandP(0, this->vli.index, (g->replace_protection ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION);
---
> 					DoCommandP(0, this->vli.index, (g->replace_protection ? 0 : 1) | (citymania::_fn_mod ? 2 : 0), CMD_SET_GROUP_REPLACE_PROTECTION);
850c852
< 				DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE));
---
> 				DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (citymania::_fn_mod || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE));
867c869
< 				DoCommandP(0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
---
> 				DoCommandP(0, new_g, vindex | (citymania::_fn_mod || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
895c897,902
< 							ShowVehicleListWindow(v);
---
> 							if (vehgroup.NumVehicles() == 1) {
> 								ShowVehicleViewWindow(v);
> 							}
> 							else {
> 								ShowVehicleListWindow(v);
> 							}
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/gui.h cmclient/src/gui.h
44c44
< void ShowLandInfo(TileIndex tile);
---
> void ShowLandInfo(TileIndex tile, TileIndex end_tile=INVALID_TILE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/heightmap.cpp cmclient/src/heightmap.cpp
453c453
< static bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map)
---
> bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/hotkeys.cpp cmclient/src/hotkeys.cpp
88a89,126
> 
> 	/* CityMania additions */
> 	{"TAB", WKC_TAB},
> 	{"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},
> 
> 	{"MOUSE_MIDDLE", CM_WKC_MOUSE_MIDDLE},
> 	{"MOUSE_4", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 0)},
> 	{"MOUSE_5", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 1)},
> 	{"MOUSE_6", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 2)},
> 	{"MOUSE_7", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 3)},
> 	{"MOUSE_8", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 4)},
> 	{"MOUSE_9", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 5)},
> 	{"MOUSE_10", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 6)},
> 	{"MOUSE_11", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 7)},
> 	{"MOUSE_12", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 8)},
> 	{"MOUSE_13", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 9)},
> 	{"MOUSE_14", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 10)},
> 	{"MOUSE_15", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 11)},
> 	{"MOUSE_16", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 12)},
> 	{"MOUSE_17", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 13)},
> 	{"MOUSE_18", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 14)},
> 	{"MOUSE_19", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 15)},
> 	{"MOUSE_20", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 16)},
> 	{"MOUSE_21", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 17)},
> 	{"MOUSE_22", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 18)},
> 	{"MOUSE_23", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 19)},
> 	{"MOUSE_24", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 20)},
> 	{"MOUSE_25", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 21)},
> 	{"MOUSE_26", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 22)},
> 	{"MOUSE_27", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 23)},
> 	{"MOUSE_28", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 24)},
> 	{"MOUSE_29", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 25)},
> 	{"MOUSE_30", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 26)},
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/industry_cmd.cpp cmclient/src/industry_cmd.cpp
49a50,51
> #include "citymania/cm_highlight.hpp"
> 
201a204
> 	citymania::UpdateIndustryHighlight();
1907a1911
> 	citymania::UpdateIndustryHighlight();
1970a1975,2008
> }
> 
> /**
>   * 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;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/industry_gui.cpp cmclient/src/industry_gui.cpp
42a43
> #include "hotkeys.h"
45a47,50
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_minimap.hpp"
> 
261a267,281
> 	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(),
269a290
> #if 0  // CM defined later
276a298
> #endif
281a304,305
> 	uint16 callback_timer;                      ///< timer counter for callback eventual verification
> 	bool timer_enabled;                         ///< timer can be used
285a310
> 	bool funding_enabled;
328a354
> 			citymania::SetIndustryForbiddenTilesHighlight(this->selected_type);
331a358,359
> 
> 		this->funding_enabled = (_game_mode == GM_EDITOR || Company::IsValidID(_local_company));
337c365
< 		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]));
338a367
> 		this->LowerWidget(_settings_client.gui.show_industry_forbidden_tiles + WID_DPI_FT_OFF);
389c418
< 	BuildIndustryWindow() : Window(&_build_industry_desc)
---
> 	BuildIndustryWindow(WindowDesc *desc) : Window(desc)
393a423,424
> 		this->funding_enabled = false;
> 
407a439,443
> 	~BuildIndustryWindow()
> 	{
> 		citymania::SetIndustryForbiddenTilesHighlight(INVALID_INDUSTRYTYPE);
> 	}
> 
643a680
> 					citymania::SetIndustryForbiddenTilesHighlight(this->selected_type);
673c710
< 						HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT);
---
> 						HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT, CM_DDSP_FUND_INDUSTRY);
677a715,724
> 
> 			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;
722a770
> 		citymania::UpdateIndustryHighlight();
740c788
< 		this->RaiseButtons();
---
> 		this->RaiseWidget(WID_DPI_FUND_WIDGET);
745c793
< 		this->RaiseButtons();
---
> 		this->RaiseWidget(WID_DPI_FUND_WIDGET);
761a810,816
> 
> 	virtual EventState OnHotkey(int hotkey)
> 	{
> 		return Window::OnHotkey(hotkey);
> 	}
> 
> 	static HotkeyList hotkeys;
763a819,836
> 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
> );
> 
> 
766c839,840
< 	if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
---
> 	// CM always enable window to allow checking stuff as a spectator
> 	// if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
768c842
< 	new BuildIndustryWindow();
---
> 	new BuildIndustryWindow(&_build_industry_desc);
1071c1145
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
1682c1756
< 					if (_ctrl_pressed) {
---
> 					if (citymania::_fn_mod) {
2965c3039
< 					if (FindWindowByClass(WC_SMALLMAP) == nullptr) ShowSmallMap();
---
> 					if (FindWindowByClass(WC_SMALLMAP) == nullptr) citymania::ShowSmallMap();
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/industry_type.h cmclient/src/industry_type.h
12a13,14
> #include "tile_type.h"
> 
42a45
> bool CanBuildIndustryOnTile(IndustryType type, TileIndex tile);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/intro_gui.cpp cmclient/src/intro_gui.cpp
33a34,35
> #include "citymania/cm_hotkeys.hpp"
> 
120c122
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/lang/english_AU.txt cmclient/src/lang/english_AU.txt
245a246
> STR_TOOLTIP_DEMOLISH_TREES                                      :{BLACK}Demolish only trees on a square of land. Ctrl selects the area diagonally.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/lang/english.txt cmclient/src/lang/english.txt
235a236,238
> STR_BUTTON_FILTER                                               :{BLACK}Filter
> STR_BUTTON_FILTER_SELECT_ALL                                    :Select All
> STR_BUTTON_FILTER_SELECT_NONE                                   :Select None
250a254
> STR_TOOLTIP_DEMOLISH_TREES                                      :{BLACK}Demolish only trees on a square of land. Ctrl selects the area diagonally.
278c282
< 
---
> STR_MEASURE_DIST_HEIGHTDIFF                                     :{BLACK}Area: {NUM} x {NUM}{}Distance: {NUM}{}Height difference: {HEIGHT}
335a340
> STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_CARGOS                      :{BLACK}Display company cargos information
338a344
> STR_TOOLBAR_TOOLTIP_DISPLAY_WATCH                               :{BLACK}Watch company's actions
391a398
> STR_SETTINGS_MENU_ZONING                                        :Zoning
415a423
> STR_MAP_MENU_WATCH_COMPANY                                      :Watch Company
485c493,494
< STR_ABOUT_MENU_SEPARATOR                                        :
---
> STR_ABOUT_MENU_SEPARATOR                                        :CityMania
> STR_ABOUT_MENU_LOGIN_WINDOW                                     :Server Login
1475a1485,1488
> STR_CONFIG_SETTING_PERSISTENT_DEPOTTOOLS                        :Keep depot building tools active after usage: {STRING2}
> STR_CONFIG_SETTING_PERSISTENT_DEPOTTOOLS_HELPTEXT               :Keep the building tools for road, train and ship depots (reversible by placing with Ctrl).
> STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN                     :Use improved station joining controls: {STRING2}
> STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT            :Use Ctrl-click on station tile to select or deselect station to join. If station has no tiles Ctrl-click its sign. Ctrl-click empty tile for a new station. Also recently built station is automatically selected as a station to join. {RED}Does't work if joining stations not directly adjacent(distant join) is not allowed in settings.
1797a1811,1830
> 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
> 
2407a2441
> 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
2424a2459
> STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP                  :{BLACK}Automatically select railway depot orientation based on environment
2432a2468,2469
> STR_STATION_BUILD_ORIENTATION_AUTO                              :{BLACK}Auto
> STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP                      :{BLACK}Automatically select station orientation based on environment
2512a2550
> STR_BUILD_DEPOT_ROAD_ORIENTATION_AUTO_TOOLTIP                   :{BLACK}Automatically select road depot orientation based on environment
3908a3947
> STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID                         :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM}
3932a3972
> STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID     :{LTBLUE}{ENGINE}{BLACK}   Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK}   ID: {LTBLUE}{NUM}
3933a3974
> STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID                :{LTBLUE}{ENGINE}{BLACK}   Value: {LTBLUE}{CURRENCY_LONG}{BLACK}   ID: {LTBLUE}{NUM}
5150a5192,5194
> 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})
5151a5196
> STR_VIEWPORT_TOWN_POP_EXCELLENT_RATING                          :{WHITE}{TOWN} {GREEN}({COMMA})
5153a5199,5201
> 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}
5154a5203
> STR_VIEWPORT_TOWN_TINY_EXCELLENT_RATING                         :{TINY_FONT}{GREEN}{TOWN}
5239a5289,5645
> 
> ### 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_ACCEPTANCE                                        :{BLACK}CB cargo acceptance
> STR_ZONING_CB_TOWN_LIMIT                                        :{BLACK}CB town limit
> 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}
> 
> # 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%
> 
> STR_IGNORE_VERSION_CHECK_WARNING : WARNING! You're about to join server running a different version of the game!
> STR_IGNORE_VERSION_CHECK_WARNING_DETAILS : OpenTTD was never indended to work in such way. If you're lucky you may be able to play it but most likely something is going to break sooner or later. Desyncs or crashes are to be expected. So proceed at your own risk and don't report any errors you encounter there.
> STR_CM_STATION_BUILD_TOWN :{BLACK}Town: {GOLD}{TOWN}
> STR_CM_STATION_BUILD_TOWN_LARGE :{BLACK}Town: {GOLD}{TOWN} (L)
> STR_CM_STATION_BUILD_TOWN_MEDIUM :{BLACK}Town: {GOLD}{TOWN} (M)
> STR_CM_STATION_BUILD_TOWN_SMALL :{BLACK}Town: {GOLD}{TOWN} (S)
> STR_CM_CONFIG_SETTING_OPEN_VEHICLE_FOR_SHARED_CLONE :Open vehicle window for shared clones: {STRING2}
> STR_CM_CONFIG_SETTING_OPEN_VEHICLE_FOR_SHARED_CLONE_HELPTEXT :Open vehicle window when cloning vehicles with shared orders (as it does for non-shared ones)
> STR_CM_CONFIG_SETTING_OPEN_ORDERS_FOR_NEW_VEHICLES :Open orders window for new vehicles: {STRING2}
> STR_CM_CONFIG_SETTING_OPEN_ORDERS_FOR_NEW_VEHICLES_HELPTEXT :Automatically open oreders windown along with a vehicle window for a new vehicles
> STR_CM_PURCHASE_ENGINE_ID :{BLACK}Engine ID: {GOLD}{NUM}
> STR_CM_SMALLMAP_TOOLTIP_SHOW_IMBA_ON_MAP :{BLACK}Show industries on map combined with land contours and vegetation
> STR_CM_CONFIG_SETTING_PAUSE_AFTER_LOAD                             :Pause the game after loading: {STRING2}
> STR_CM_CONFIG_SETTING_PAUSE_AFTER_LOAD_HELPTEXT                    :Control whether the game should be paused after load (if it's not already paused). Useful for desync debugging.
> 
> 
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_HOUSES                        :Show tooltips when hovering over houses: {STRING2}
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_INDUSTRIES                    :Show tooltips when hovering over industries: {STRING2}
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_STATIONS                      :Show tooltips when hovering over stations: {STRING2}
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_HOUSES_HELPTEXT               :Show tooltips when hovering over houses in the viewport. {GOLD}(CityMania addon)
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_INDUSTRIES_HELPTEXT           :Show tooltips when hovering over industries in the viewport. {GOLD}(CityMania addon)
> STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_STATIONS_HELPTEXT             :Show tooltips when hovering over stations in the viewport. {GOLD}(CityMania addon)
> STR_CM_LAND_TOOLTIPS_HOUSE_NAME                   :{LTBLUE}{STRING}
> STR_CM_LAND_TOOLTIPS_HOUSE_POPULATION             :{BLACK}Population: {NUM}
> STR_CM_LAND_TOOLTIPS_INDUSTRY_NAME                :{LTBLUE}{INDUSTRY}
> STR_CM_LAND_TOOLTIPS_INDUSTRY_CARGO               :{WHITE}{STRING}  {BLACK}{CARGO_SHORT} {YELLOW}{NUM} %
> STR_CM_LAND_TOOLTIPS_STATION_NAME                 :{LTBLUE}{STATION}
> STR_CM_LAND_TOOLTIPS_STATION_CARGO                :{WHITE}{STRING}  {BLACK}{CARGO_SHORT} {YELLOW}{NUM} %
> 
> STR_LAND_AREA_INFORMATION_POP                                   :{BLACK}Population: {LTBLUE}{NUM}
> 
> STR_CM_CONFIG_SETTING_MODIFIER_FN          : Additional function modifier key: {STRING2}
> STR_CM_CONFIG_SETTING_MODIFIER_FN_HELPTEXT : Modifier key for accessing additional functions.
> STR_CM_CONFIG_SETTING_MODIFIER_REMOVE          : Remove modifier key: {STRING2}
> STR_CM_CONFIG_SETTING_MODIFIER_REMOVE_HELPTEXT : Modifier key for removal mode on building tools.
> STR_CM_CONFIG_SETTING_MODIFIER_ESTIMATE          : Estimate modifier key: {STRING2}
> STR_CM_CONFIG_SETTING_MODIFIER_ESTIMATE_HELPTEXT : Modifier key for estimating action cost.
> STR_CM_CONFIG_SETTING_MODIFIER_NONE  : None
> STR_CM_CONFIG_SETTING_MODIFIER_SHIFT : Shift
> STR_CM_CONFIG_SETTING_MODIFIER_CTRL  : Ctrl
> STR_CM_CONFIG_SETTING_MODIFIER_ALT   : Alt
> 
> STR_CM_CONFIG_SETTING_SHADED_TREES          : Shaded trees: {STRING2}
> STR_CM_CONFIG_SETTING_SHADED_TREES_HELPTEXT : Change tree brightness depending on a slope. Enhances visual appeal of mountaneous forests.
> STR_CM_CONFIG_SETTING_SHADED_TREES_OFF      : Always off
> STR_CM_CONFIG_SETTING_SHADED_TREES_ON       : Always on
> STR_CM_CONFIG_SETTING_SHADED_TREES_SERVER   : As server
> 
> STR_CM_CONFIG_SETTING_SHOW_APM          : Show APM counter: {STRING2}
> STR_CM_CONFIG_SETTING_SHOW_APM_HELPTEXT : Adds APM (actions per minute) counter to the statusbar.
> STR_CM_STATUSBAR_APM                    : {WHITE}APM: {NUM} AVG: {NUM}
> STR_CM_STATION_BUILD_SUPPLIES     :{BLACK}Supplies: {GOLD}
> 
> STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND : Graph background colour: {STRING2}
> STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND_HELPTEXT : Main background colour for the graph windows. Other related colours are changed accordingly.
> STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND_BLACK : Black
> STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND_GREY : Light grey
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/lang/english_US.txt cmclient/src/lang/english_US.txt
250a251
> STR_TOOLTIP_DEMOLISH_TREES                                      :{BLACK}Demolish only trees on a square of land. Ctrl selects the area diagonally.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/linkgraph/linkgraph_gui.cpp cmclient/src/linkgraph/linkgraph_gui.cpp
17c17
< #include "../smallmap_gui.h"
---
> // #include "../smallmap_gui.h"
22a23,24
> #include "../citymania/cm_minimap.hpp"
> 
349c351
< 		return static_cast<const SmallMapWindow *>(this->window)->GetStationMiddle(st);
---
> 		return static_cast<const citymania::SmallMapWindow *>(this->window)->GetStationMiddle(st);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/main_gui.cpp cmclient/src/main_gui.cpp
61c61
< bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode)
---
> bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode, ViewportDragDropSelectionProcess cm_process)
68c68
< 	if (w->IsWidgetLowered(widget)) {
---
> 	if (w->IsWidgetLowered(widget) && mode == _thd.place_mode) {
73c73
< 	SetObjectToPlace(cursor, PAL_NONE, mode, w->window_class, w->window_number);
---
> 	SetObjectToPlace(cursor, PAL_NONE, mode, w->window_class, w->window_number, cm_process);
188a189
> 	GHK_BORROW_ALL,
358a360,363
> 			case GHK_BORROW_ALL:
> 				DoCommandP(0, 0, 1, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
> 				break;
> 
436a442,446
> 	virtual void OnMouseOver(Point pt, int widget)
> 	{
> 		if (_game_mode != GM_MENU && pt.x != -1) GuiPrepareTooltipsExtra(this);
> 	}
> 
483a494
> 	Hotkey(WKC_NONE, "borrow_all", GHK_BORROW_ALL),
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/map.cpp cmclient/src/map.cpp
14a15
> #include "citymania/cm_highlight.hpp"
63a65
> 	citymania::AllocateZoningMap(_map_size);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/misc_cmd.cpp cmclient/src/misc_cmd.cpp
181c181
< 			if (p2 == 0) {
---
> 			if ((p2 & 1) == 0) {
182a183
> 				_pause_countdown = (p2 >> 1);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/misc.cpp cmclient/src/misc.cpp
67a68
> 	_pause_countdown = 0;
122a124
> 	ResetRailPlacementEndpoints();
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/misc_gui.cpp cmclient/src/misc_gui.cpp
34a35,43
> #include "house.h"
> #include "town_map.h"
> #include "station_base.h"
> #include "viewport_func.h"
> #include "industry.h"
> 
> #include "citymania/cm_tooltips.hpp"
> #include "citymania/cm_misc_gui.hpp"
> 
36a46,47
> extern const Station *_viewport_highlight_station; // CM
> 
47,53c58
< 	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_PUSHIMGBTN, COLOUR_GREY, WID_LI_LOCATION), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_LAND_AREA_INFORMATION_LOCATION_TOOLTIP),
< 		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(),
57c62
< 	WDP_AUTO, "land_info", 0, 0,
---
> 	WDP_MANUAL, "land_info", 0, 0,
74a80,91
> 	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.total_size.y + _cursor.total_offs.y + 5, scr_top, scr_bot);
> 		if (pt.y + sm_height > scr_bot) pt.y = std::min(_cursor.pos.y + _cursor.total_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;
> 	}
79a97,101
> 		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);
> 
112c134
< 			size->width = std::max(size->width, std::min(300u, width));
---
> 			size->width = std::max(size->width, std::min<uint>(ScaleGUITrad(300), width));
118c140,141
< 	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)
120a144
> 		CLRBITS(this->flags, WF_WHITE_BORDER);
173a198
>  		td.population = 0;
327a353,359
> 		/* 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++;
> 		}
> 
400c432
< void ShowLandInfo(TileIndex tile)
---
> void ShowLandInfo(TileIndex tile, TileIndex end_tile)
401a434,437
>     static TileIndex last_tooltip_tile = INVALID_TILE;
>     if (tile == last_tooltip_tile) return;
>     last_tooltip_tile = tile;
> 
403c439,440
< 	new LandInfoWindow(tile);
---
> 	if (tile == INVALID_TILE) return;
> 	new LandInfoWindow(tile, end_tile);
1290a1328,1343
> }
> 
> /** Window for displaying a tooltip. */
> void GuiPrepareTooltipsExtra(Window *parent){
> 	const Point p = GetTileBelowCursor();
> 	TileIndex tile = (p.x == -1 ? INVALID_TILE : TileVirtXY(p.x, p.y));
> 
> 	if (_cursor.sprite_seq[0].sprite == SPR_CURSOR_QUERY) {
> 		// Land info tool active
> 		citymania::ShowLandInfo(tile);
> 		return;
> 	}
> 	citymania::ShowLandInfo(INVALID_TILE);
> 
> 	if (tile >= MapSize()) tile = INVALID_TILE;
> 	citymania::ShowLandTooltips(tile, parent);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/core/packet.cpp cmclient/src/network/core/packet.cpp
182a183,197
> /* CityMania code begin */
> bool Packet::CMCheckRead(uint bytes_to_read)
> {
> 	/* Don't allow reading from a quit client/client who send bad data */
> 	if (this->cs->HasClientQuit()) return false;
> 
> 	/* Check if variable is within packet-size */
> 	if (this->pos + bytes_to_read > this->size) {
> 		return false;
> 	}
> 
> 	return true;
> }
> /* CityMania code end */
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/core/packet.h cmclient/src/network/core/packet.h
77a78
> 	bool   CMCheckRead (uint bytes_to_read);  // CityMaina needs check that doesn't close connections
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_client.cpp cmclient/src/network/network_client.cpp
33a34,37
> #include "../town.h"
> #include "network_func.h"
> #include "../citymania/cm_newgrf_revisions.hpp"
> 
37a42,45
> void SyncCMUser(const char *msg);
> // extern const std::map<std::string, uint32> OPENTTD_NEWGRF_VERSIONS;
> // extern const std::map<uint32, uint32> OPENTTD_RELEASE_REVISIONS;
> static const uint32 OPENTTD_NEWGRF_REVISION_MASK = (1 << 19) - 1;
331a340,341
> /** Server revision to use when fooling revision check */
> const char *_network_join_server_revision = NULL;
361,362c371,394
< 	p->Send_string(GetNetworkRevisionString());
< 	p->Send_uint32(_openttd_newgrf_version);
---
> 	if (_network_join_server_revision) {
> 		auto r = _network_join_server_revision;
> 		p->Send_string(r);
> 		auto nr = OPENTTD_NEWGRF_VERSIONS.find(r);
> 		uint32 rev;
> 		if (nr != OPENTTD_NEWGRF_VERSIONS.end()) {
> 			p->Send_uint32(nr->second);
> 		} else if (r[0] == 'r' && r[6] == 0 && (rev = strtoul(r + 1, nullptr, 10)) > 0) {
> 			// assume it's nightly
> 			uint32 max_rev = 0;
> 			// find release closest to the nightly
> 			for (auto &kv: OPENTTD_RELEASE_REVISIONS) {
> 				if (kv.first > max_rev && kv.first <= rev)
> 					max_rev = kv.first;
> 			}
> 			p->Send_uint32(OPENTTD_RELEASE_REVISIONS.at(max_rev) |
> 			               (rev & OPENTTD_NEWGRF_REVISION_MASK));
> 		} else {
> 			p->Send_uint32(_openttd_newgrf_version);
> 		}
> 	} else {
> 		p->Send_string(GetNetworkRevisionString());
> 		p->Send_uint32(_openttd_newgrf_version);
> 	}
365a398
> 	p->Send_uint8 (citymania::GetAvailableLoadFormats());  // Compressnion formats that we can decompress
644a678,681
> 		InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
> 		SetWindowClassesDirty(WC_WATCH_COMPANY);
> 		InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1);
> 		SetWindowClassesDirty(WC_WATCH_COMPANYA);
663a701,704
> 	InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
> 	SetWindowClassesDirty(WC_WATCH_COMPANY);
> 	InvalidateWindowData(WC_WATCH_COMPANYA, ci->client_id, 1);
> 	SetWindowClassesDirty(WC_WATCH_COMPANYA);
1022c1062,1063
< 		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);
1058a1100,1101
> 	InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
> 	SetWindowClassesDirty( WC_WATCH_COMPANYA );
1148a1192,1193
> 	InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
> 	SetWindowClassesDirty( WC_WATCH_COMPANYA );
1288a1334,1337
> void NetworkClientSendChatToServer(const char * msg)
> {
> 	NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, CLIENT_ID_SERVER, msg);
> }
1331a1381,1388
> 
> 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);
> }
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_client.h cmclient/src/network/network_client.h
115a116
> extern const char *_network_join_server_revision;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_command.cpp cmclient/src/network/network_command.cpp
206c206
< 			error("[net] Trying to execute a packet in the past!");
---
> 			error("[net] Trying to execute a packet in the past! (frame=%u cmd_frame=%u tile=%u p1=%u p2=%u cmd=%u)", (uint)_frame_counter, (uint)cp->frame, (uint)cp->tile, (uint)cp->p1, (uint)cp->p2, (uint)cp->cmd);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network.cpp cmclient/src/network/network.cpp
81c81
< 
---
> bool _novarole = false;
111a112
> 	InvalidateWindowData(WC_WATCH_COMPANYA, this->client_id, 2);
983a985
> 		if (_pause_countdown > 0 && --_pause_countdown == 0) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_func.h cmclient/src/network/network_func.h
37c37
< 
---
> extern bool _novarole;
55a56
> void NetworkClientSendChatToServer(const char * msg);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_gui.cpp cmclient/src/network/network_gui.cpp
40a41,46
> #include "../error.h"
> #include "../zoom_func.h"
> 
> #include "../citymania/cm_hotkeys.hpp"
> #include "../citymania/cm_watch_gui.hpp"
> 
231a238,239
> 	bool UDP_CC_queried; ///< CityMania for buttons check
> 
470a479
> 		this->UDP_CC_queried = false;
596c605
< 				!sel->info.compatible); // Revision mismatch
---
> 				(!sel->info.compatible && !citymania::_fn_mod)); // Revision mismatch
760a770,780
> 					if (this->server->info.compatible) {
> 						_network_join_server_revision = NULL;
> 					} else {
> 						_network_join_server_revision = this->server->info.server_revision;
> 						ShowErrorMessage(STR_IGNORE_VERSION_CHECK_WARNING,
> 						                 STR_IGNORE_VERSION_CHECK_WARNING_DETAILS,
> 						                 WL_WARNING,
> 						                 0, 0,
> 						                 NULL, 0, NULL);
> 						// 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.");
> 					}
775a796,812
> 			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;
892c929
< Listing NetworkGameWindow::last_sorting = {false, 5};
---
> Listing NetworkGameWindow::last_sorting = {false, 0};
923a961,969
> 					/* CityMania code */
> 					NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
> 						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(),
> 					/* end CityMania code */
1156c1202
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
1365a1412
> 				size->width = ScaleGUITrad(146);
1668a1716,1723
> static void ClientList_Watch(const NetworkClientInfo *ci)
> {
> 	if (ci != NULL){
> 		CompanyID cid = (CompanyID)ci->client_id;
> 		citymania::ShowWatchWindow(cid, 1);
> 	}
> }
> 
1730a1786,1788
> 		if (_network_own_client_id != ci->client_id && ci->client_id != CLIENT_ID_SERVER && _novarole) {
> 			this->AddAction(STR_XI_WATCH, &ClientList_Watch);
> 		}
1874,1875c1932,1935
< 
< 		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;
1925a1986,1990
> 
> 			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);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_server.cpp cmclient/src/network/network_server.cpp
632c632
< 		if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed");
---
> 		if (SaveWithFilter(this->savegame, true, this->cm_preset) != SL_OK) usererror("network savedump failed");
927a928
> 	uint8 savegame_formats = p->CMCheckRead(1) ? p->Recv_uint8() : 23u /* assume non-modded has everything but zstd */;
929a931,937
> 
> 	/* Find common savegame compression format to use */
> 	auto preset = citymania::FindCompatibleSavePreset("", savegame_formats);
> 	if (!preset) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
> 	this->cm_preset = *preset;
> 
> 	DEBUG(sl, 2, "Using saveload preset '%s:%d' for client %d (mask %d)", this->cm_preset.format->name, (int)this->cm_preset.compression_level, (int)this->client_id, (int)savegame_formats);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/network/network_server.h cmclient/src/network/network_server.h
14a15
> #include "../saveload/saveload.h"
73a75
> 	citymania::SavePreset cm_preset; ///< Preset to use for the savegame
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/newgrf_debug_gui.cpp cmclient/src/newgrf_debug_gui.cpp
44a45,46
> #include "citymania/cm_hotkeys.hpp"
> 
461a464
> 		this->DrawString(r, i++, "Industry type: %d", (int)((const Industry *)base)->type);
980,983c983,986
< 					case WID_SA_UP:    spr->y_offs -= _ctrl_pressed ? 8 : 1; break;
< 					case WID_SA_DOWN:  spr->y_offs += _ctrl_pressed ? 8 : 1; break;
< 					case WID_SA_LEFT:  spr->x_offs -= _ctrl_pressed ? 8 : 1; break;
< 					case WID_SA_RIGHT: spr->x_offs += _ctrl_pressed ? 8 : 1; break;
---
> 					case WID_SA_UP:    spr->y_offs -= citymania::_fn_mod ? 8 : 1; break;
> 					case WID_SA_DOWN:  spr->y_offs += citymania::_fn_mod ? 8 : 1; break;
> 					case WID_SA_LEFT:  spr->x_offs -= citymania::_fn_mod ? 8 : 1; break;
> 					case WID_SA_RIGHT: spr->x_offs += citymania::_fn_mod ? 8 : 1; break;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/newgrf_gui.cpp cmclient/src/newgrf_gui.cpp
1014c1014
< 					if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 					if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_NEWGRF_SELECT);
1072c1072
< 					if (this->editable && this->avail_sel != nullptr && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 					if (this->editable && this->avail_sel != nullptr && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_NEWGRF_SELECT);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/news_gui.cpp cmclient/src/news_gui.cpp
42a43,44
> #include "citymania/cm_hotkeys.hpp"
> 
510c512
< 					if (_ctrl_pressed) {
---
> 					if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/object_gui.cpp cmclient/src/object_gui.cpp
452c452
< 			SetObjectToPlaceWnd(SPR_CURSOR_TRANSMITTER, PAL_NONE, HT_RECT, this);
---
> 			SetObjectToPlaceWnd(SPR_CURSOR_TRANSMITTER, PAL_NONE, HT_RECT, this, CM_DDSP_PLACE_OBJECT);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/openttd.cpp cmclient/src/openttd.cpp
70a71,74
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_main.hpp"
> #include "citymania/cm_console_cmds.hpp"
> 
346a351,352
> 	citymania::ResetGame();
> 
356a363
> 	_pause_countdown = 0;
908a916
> 	citymania::InitializeZoningMap();
928a937
> 	citymania::InitializeZoningMap();
995a1005
> 	citymania::SwitchToMode(new_mode);
1417a1428,1432
> 	if (_pause_countdown > 0 && --_pause_countdown == 0) {
> 		_pause_mode = PM_PAUSED_NORMAL;
> 		SetWindowDirty(WC_MAIN_TOOLBAR, 0);
> 	}
> 
1504a1520
> 		citymania::ExecuteFakeCommands(_date, _date_fract);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/openttd.h cmclient/src/openttd.h
74a75
> extern uint32 _pause_countdown;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/order_cmd.cpp cmclient/src/order_cmd.cpp
1765a1766
> 							_settings_client.gui.runway_too_short_warn &&
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/order_gui.cpp cmclient/src/order_gui.cpp
3c3
<  * 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 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  error:141A318A:SSL routines:tls_process_ske_dhe:dh key too smal.
34a35,36
> #include "citymania/cm_hotkeys.hpp"
> 
174a177,252
> enum class FeederOrderMod{
> 	NONE,
> 	LOAD,
> 	UNLOAD
> };
> 
> struct OrdersFromSettings {
> 	OrderLoadFlags load;
> 	OrderUnloadFlags unload;
> 	FeederOrderMod mod;
> };
> 
> enum  GetOrderFromSettingsTypes {
> 	GOFS_NONE = 0,
> 	GOFS_FULL,
> 	GOFS_XFER,
> 	GOFS_UNLOAD,
> 	GOFS_FEEDLOAD,
> 	GOFS_FEEDUNLOAD,
> 	GOFS_NOLOAD
> };
> 
> #define GOFSFEEDER_ORDERMOD_RESET gofsfeeder_ordermod = GOFS_FEEDER_NULL
> 
> 
> /* fetch and compute orders set from settings */
> 
> static OrdersFromSettings GetOrdersFromSettings(const Vehicle *v, uint8 setting)
> {
> 	OrdersFromSettings res = {
> 		OLF_LOAD_IF_POSSIBLE,
> 		OUF_UNLOAD_IF_POSSIBLE,
> 		FeederOrderMod::NONE
> 	};
> 
> 	switch(setting) {
> 
> 	case GOFS_FEEDLOAD:
> 		if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::LOAD;
> 		res.unload = OUFB_NO_UNLOAD;
> 		res.load = OLF_FULL_LOAD_ANY;
> 		break;
> 	case GOFS_FULL:
> 		res.load = OLF_FULL_LOAD_ANY;
> 		break;
> 
> 	case GOFS_UNLOAD:
> 		res.unload = OUFB_UNLOAD;
> 		if (_settings_client.gui.auto_noload_on_unloadall)
> 			res.load = OLFB_NO_LOAD;
> 		break;
> 
> 	case GOFS_FEEDUNLOAD:
> 		if (v->GetNumOrders() > 0) res.mod = FeederOrderMod::UNLOAD;
> 		res.unload = OUFB_TRANSFER;
> 		res.load = OLFB_NO_LOAD;
> 		break;
> 
> 	case GOFS_XFER:
> 		res.unload = OUFB_TRANSFER;
> 		if (_settings_client.gui.auto_noload_on_transfer)
> 			res.load = OLFB_NO_LOAD;
> 		break;
> 
> 	case GOFS_NOLOAD:
> 		res.load = OLFB_NO_LOAD;
> 		break;
> 
> 	case GOFS_NONE:
> 		break;
> 
> 	default: NOT_REACHED();
> 	}
> 	return res;
> }
> 
350a429,441
> 
> 	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);
359c450
< static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
---
> static std::pair<Order, FeederOrderMod> GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
373c464
< 		if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
---
> 		if (citymania::_fn_mod) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
375c466
< 		return order;
---
> 		return std::make_pair(order, FeederOrderMod::NONE);
383,384c474,475
< 		if (_settings_client.gui.new_nonstop != _ctrl_pressed) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
< 		return order;
---
> 		if (_settings_client.gui.new_nonstop != citymania::_fn_mod) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
> 		return std::make_pair(order, FeederOrderMod::NONE);
390c481
< 		return order;
---
> 		return std::make_pair(order, FeederOrderMod::NONE);
414c505,533
< 				if (_ctrl_pressed) order.SetLoadType(OLF_FULL_LOAD_ANY);
---
> 
> 				uint8 os = 0xff;
> 				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;
> 
> 				auto feeder_mod = FeederOrderMod::NONE;
> 				if (os != 0xff) {
> 					auto ofs = GetOrdersFromSettings(v, os);
> 					if (ofs.load != (enum OrderLoadFlags)-1)
> 						order.SetLoadType(ofs.load);
> 					if (ofs.unload != (enum OrderUnloadFlags)-1)
> 					order.SetUnloadType(ofs.unload);
> 					feeder_mod = ofs.mod;
> 				}
> 
417c536
< 				return order;
---
> 				return std::make_pair(order, feeder_mod);
424c543
< 	return order;
---
> 	return std::make_pair(order, FeederOrderMod::NONE);
439a559
> 	OHK_CLOSE,
572c692
< 		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this);
---
> 		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this, CM_DDSP_PICK_STATION);
645a766,772
> 		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;
> 		}
647c774
< 		if (unload_type == OUFB_TRANSFER) {
---
> 		if (set_no_load) {
682c809
< 		if (_ctrl_pressed && this->vehicle->cur_implicit_order_index == this->OrderGetSel()) return;
---
> 		if (citymania::_fn_mod && this->vehicle->cur_implicit_order_index == this->OrderGetSel()) return;
685,686c812,813
< 		DoCommandP(this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_implicit_order_index + 1) % this->vehicle->GetNumOrders()),
< 				CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER));
---
> 		DoCommandP(this->vehicle->tile, this->vehicle->index, citymania::_fn_mod ? this->OrderGetSel() : ((this->vehicle->cur_implicit_order_index + 1) % this->vehicle->GetNumOrders()),
> 				CMD_SKIP_TO_ORDER | CMD_MSG(citymania::_fn_mod ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER));
714c841
< 		if (_ctrl_pressed) {
---
> 		if (citymania::_fn_mod) {
735c862
< 		if (_ctrl_pressed) {
---
> 		if (citymania::_fn_mod) {
1170c1297
< 				if (_ctrl_pressed && sel < this->vehicle->GetNumOrders()) {
---
> 				if (citymania::_fn_mod && sel < this->vehicle->GetNumOrders()) {
1195c1322
< 						SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 						SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_SELECT_ORDER);
1416a1544,1548
> 		if(hotkey == OHK_GOTO && this->goto_type != OPOS_NONE){
> 			this->RaiseWidget(WID_O_GOTO);
> 			ResetObjectToPlace();
> 			return ES_NOT_HANDLED;
> 		}
1429a1562
> 			case OHK_CLOSE:          delete this; break;
1438c1571,1574
< 			const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
---
> 			auto cmd_pair = GetOrderCmdFromTile(this->vehicle, tile);
> 			auto cmd = cmd_pair.first;
> 			auto feeder_mod = cmd_pair.second;
> 
1441c1577,1590
< 			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 (feeder_mod != FeederOrderMod::NONE) {
> 				if (feeder_mod == FeederOrderMod::LOAD) {
> 					if (DoCommandP(this->vehicle->tile, this->vehicle->index + (1 << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_NO_ESTIMATE | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
> 						DoCommandP(this->vehicle->tile, this->vehicle->index,  0, CMD_DELETE_ORDER |  CMD_NO_ESTIMATE | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER));
> 					}
> 
> 				}
> 				else if (feeder_mod == FeederOrderMod::UNLOAD) { // still flushes the whole order table
> 					if (DoCommandP(this->vehicle->tile, this->vehicle->index + ((uint32)(this->vehicle->GetNumOrders()) << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_NO_ESTIMATE | 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_NO_ESTIMATE | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER));
> 					}
> 				}
> 			}
> 			else if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER |  CMD_NO_ESTIMATE | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
1455c1604
< 		bool share_order = _ctrl_pressed || this->goto_type == OPOS_SHARE;
---
> 		bool share_order = citymania::_fn_mod || this->goto_type == OPOS_SHARE;
1518a1668
> 	Hotkey('Q', "close", OHK_CLOSE),
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/os/macosx/osx_stdafx.h cmclient/src/os/macosx/osx_stdafx.h
89a90
> #include <string>
Only in cmclient/src/os/macosx: splash.cpp
Only in cmclient/src/os/macosx: splash.h
Only in cmclient/src/os/windows: ottdres.rc
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/rail_cmd.cpp cmclient/src/rail_cmd.cpp
45a46,47
> 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.
443a446,447
> 	_rail_track_endtile = INVALID_TILE;
> 
460c464,467
< 			if (ret.Failed()) return ret;
---
> 			if (ret.Failed()) {
> 				if (ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) _rail_track_endtile = tile;
> 				return ret;
> 			}
570a578
> 				_rail_track_endtile = tile;
612a621
> 	_rail_track_endtile = tile;
630a640,641
> 	_rail_track_endtile = INVALID_TILE;
> 
759a771
> 	_rail_track_endtile = tile;
894a907,908
> 	_rail_track_endtile = INVALID_TILE;
> 
905a920
> 		TileIndex last_endtile = _rail_track_endtile;
909a925
> 			if (_rail_track_endtile == INVALID_TILE) _rail_track_endtile = last_endtile;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/rail_gui.cpp cmclient/src/rail_gui.cpp
44a45,48
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_station_gui.hpp"
> 
48c52
< static RailType _cur_railtype;               ///< Rail type of the current build-rail toolbar.
---
> RailType _cur_railtype;               ///< Rail type of the current build-rail toolbar.
50c54,55
< static DiagDirection _build_depot_direction; ///< Currently selected depot direction
---
> static bool _cm_invert_remove;                  ///< Invert remove mode on tools (when fn-clicked)
> /* CM  static */ DiagDirection _build_depot_direction; ///< Currently selected depot direction
56a62,63
> extern TileIndex _rail_track_endtile; // rail_cmd.cpp
> 
59a67,72
> static const int HOTKEY_MASK        = 0x1000;
> 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.
> 
68c81
< static RailStationGUISettings _railstation; ///< Settings of the station builder GUI
---
> RailStationGUISettings _railstation; ///< Settings of the station builder GUI
96c109
< static void GenericPlaceRail(TileIndex tile, int cmd)
---
> static CommandContainer GenericPlaceRailCmd(TileIndex tile, uint32 cmd)
98,102c111,122
< 	DoCommandP(tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3),
< 			_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),
< 			CcPlaySound_CONSTRUCTION_RAIL);
---
> 	CommandContainer ret = {
> 		tile,  // tile
> 		_cur_railtype,  // p1
> 		cmd | ((uint32)_settings_client.gui.auto_remove_signals << 3),  // 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
> 		CcPlaySound_CONSTRUCTION_RAIL, // callback
> 		""             // text
> 	};
> 
> 	return ret;
160c180
< 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
---
> 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_STATION);
192c212
< 		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
---
> 		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
198c218,222
< 		uint32 p1 = _cur_railtype | _railstation.orientation << 6 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24;
---
> 		if (citymania::UseImprovedStationJoin()) {
> 			citymania::PlaceRail_Station(tile);
> 			return;
> 		}
> 		uint32 p1 = _cur_railtype | _railstation.orientation << 6 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | citymania::_fn_mod << 24;
242c266
< 			SB(p1, 3, 1, _ctrl_pressed);
---
> 			SB(p1, 3, 1, citymania::_fn_mod);
248c272
< 			SB(p1, 3, 1, _ctrl_pressed);
---
> 			SB(p1, 3, 1, citymania::_fn_mod);
282a307
> 		StoreRailPlacementEndpoints(tile, _build_tunnel_endtile, TileX(tile) == TileX(_build_tunnel_endtile) ? TRACK_Y : TRACK_X, false);
312c337
< 		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)) {
356c381
< static void DoRailroadTrack(int mode)
---
> static CommandContainer DoRailroadTrackCmd(TileIndex start_tile, TileIndex end_tile, Track track)
358,363c383,394
< 	uint32 p2 = _cur_railtype | (mode << 6) | (_settings_client.gui.auto_remove_signals << 11);
< 	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), 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),
< 			CcPlaySound_CONSTRUCTION_RAIL);
---
> 	CommandContainer ret = {
> 		start_tile,                             // tile
> 		end_tile,                               // p1
> 		((uint32)_cur_railtype | ((uint32)track << 6) | ((uint32)_settings_client.gui.auto_remove_signals << 11)), // 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
> 		CcPlaySound_CONSTRUCTION_RAIL,          // callback
> 		""                                      // text
> 	};
> 
> 	return ret;
368,372c399,421
< 	int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5
< 
< 	if (_thd.drawstyle & HT_RAIL) { // one tile case
< 		GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat);
< 		return;
---
> 	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);
> 
> 	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 want to move the
> 	 * snap point over the last overbuilt track piece. In such case we don't
> 	 * wan't to show any errors to the user. Don't execute the command right
> 	 * away, first check if overbuilding. */
> 	if (citymania::_estimate_mod || !(_thd.place_mode & HT_POLY) ||
> 			DoCommand(&cmd, DC_AUTO | DC_NO_WATER).GetErrorMessage() != STR_ERROR_ALREADY_BUILT ||
> 			_rail_track_endtile == INVALID_TILE) {
> 		/* Execute. */
> 		if (!DoCommandP(&cmd)) return;
> 	}
> 
> 	/* Save new snap points for the polyline tool, no matter if the command
> 	 * succeeded, the snapping will be extended over overbuilt track pieces. */
> 	if (!citymania::_estimate_mod && _rail_track_endtile != INVALID_TILE) {
> 		StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true);
374,375d422
< 
< 	DoRailroadTrack(trackstat);
399c446
< 		SB(p2,  6, 1, _ctrl_pressed);
---
> 		SB(p2,  6, 1, citymania::_fn_mod);
406c453
< 		SB(p2,  6, 1, _ctrl_pressed);
---
> 		SB(p2,  6, 1, citymania::_fn_mod);
420a468,492
> 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;
> }
443a516,527
> 	 * Some data on this window has become invalid.
> 	 * @param data Information about the changed data.
> 	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
> 	 */
> 	void OnInvalidateData(int data = 0, bool gui_scope = true) override
> 	{
> 		if (!gui_scope) return;
> 
> 		if (!CanBuildVehicleInfrastructure(VEH_TRAIN)) delete this;
> 	}
> 
> 	/**
457a542
> 		this->GetWidget<NWidgetCore>(WID_RAT_POLYRAIL)->widget_data     = rti->gui_sprites.auto_rail;
485a571
> 			case WID_RAT_POLYRAIL:
516a603,611
> 	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);
> 		}
> 	}
> 
521d615
< 		_remove_button_clicked = false;
524c618
< 				HandlePlacePushButton(this, WID_RAT_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL, DDSP_PLACE_RAIL);
529c623
< 				HandlePlacePushButton(this, WID_RAT_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X, DDSP_PLACE_RAIL);
534c628
< 				HandlePlacePushButton(this, WID_RAT_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL, DDSP_PLACE_RAIL);
539c633
< 				HandlePlacePushButton(this, WID_RAT_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y, DDSP_PLACE_RAIL);
544c638
< 				HandlePlacePushButton(this, WID_RAT_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL);
---
> 				HandlePlacePushButton(this, WID_RAT_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL, DDSP_PLACE_RAIL);
547a642,673
> 			case WID_RAT_POLYRAIL: {
> 				bool was_snap = GetRailSnapMode() == RSM_SNAP_TO_RAIL;
> 				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 (citymania::_fn_mod) {
> 					do_snap = !was_open || !was_snap;
> 					do_open = true;
> 				} else {
> 					do_snap = false;
> 					do_open = !was_open;
> 				}
> 				/* close/open the tool */
> 				if (was_open != do_open) HandlePlacePushButton(this, WID_RAT_POLYRAIL, GetRailTypeInfo(railtype)->cursor.autorail, HT_RAIL | HT_POLY, DDSP_PLACE_RAIL);
> 				/* set snapping mode */
> 				if (do_open) SetRailSnapMode(do_snap ? RSM_SNAP_TO_RAIL : RSM_NO_SNAP);
> 
> 				this->last_user_action = WID_RAT_POLYRAIL;
> 				if (was_open == do_open) return; // prevent switching the "remove" button state
> 				break;
> 			}
> 
549c675
< 				HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
554c680,681
< 				if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT)) {
---
> 				if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT | (HighLightStyle)_build_depot_direction, CM_DDSP_BUILD_RAIL_DEPOT)) {
> 					citymania::ResetRotateAutodetection();
563c690
< 				if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT) && _waypoint_count > 1) {
---
> 				if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT, CM_DDSP_BUILD_WAYPOINT) && _waypoint_count > 1) {
568,571c695,712
< 			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, DDSP_BUILD_STATION))
> 							ShowStationBuilder(this);
> 					}
> 					this->last_user_action = WID_RAT_BUILD_STATION;
> 				} else { /* button */
> 					if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT, DDSP_BUILD_STATION)) {
> 						ShowStationBuilder(this);
> 						this->last_user_action = WID_RAT_BUILD_STATION;
> 					}
573a715
> 			}
577,578c719,720
< 				bool started = HandlePlacePushButton(this, WID_RAT_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT);
< 				if (started && _settings_client.gui.enable_signal_gui != _ctrl_pressed) {
---
> 				bool started = HandlePlacePushButton(this, WID_RAT_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT, DDSP_BUILD_SIGNALS);
> 				if (started && _settings_client.gui.enable_signal_gui != citymania::_fn_mod) {
585c727
< 				HandlePlacePushButton(this, WID_RAT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT, CM_DDSP_BUILD_RAIL_BRIDGE);
590c732
< 				HandlePlacePushButton(this, WID_RAT_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL);
---
> 				HandlePlacePushButton(this, WID_RAT_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL, CM_DDSP_BUILD_RAIL_TUNNEL);
599c741
< 				HandlePlacePushButton(this, WID_RAT_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_RAT_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT | HT_DIAGONAL, DDSP_CONVERT_RAIL);
605,606c747,756
< 		this->UpdateRemoveWidgetStatus(widget);
< 		if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
---
> 
> 		bool is_hotkey = (pt.x == 0 && pt.y == 0);
> 		if (widget != WID_RAT_REMOVE) {
> 			_cm_invert_remove = (!is_hotkey && citymania::RailToolbar_IsRemoveInverted(widget));
> 			_remove_button_clicked = _cm_invert_remove;
> 		}
> 
> 		citymania::RailToolbar_UpdateRemoveWidgetStatus(this, widget, _remove_button_clicked);
> 		// this->UpdateRemoveWidgetStatus(widget);
> 		// if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
610a761
> 		// EventState es;
611a763,777
> 
> 		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);
> 		}
> 
616a783
> 		DiagDirection ddir;
634a802
> 			case WID_RAT_POLYRAIL:
643c811,816
< 				DoCommandP(tile, _cur_railtype, _build_depot_direction,
---
> 				ddir = _build_depot_direction;
> 				if (ddir == citymania::DEPOTDIR_AUTO) {
> 					assert(_thd.cm.type == citymania::ObjectHighlight::Type::RAIL_DEPOT);
> 					ddir = _thd.cm.ddir;
> 				}
> 				DoCommandP(tile, _cur_railtype, ddir,
645a819,820
> 				if (citymania::_fn_mod == _settings_client.gui.persistent_depottools)
> 					ResetObjectToPlace();
707c882
< 					DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 1 << 6 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound_CONSTRUCTION_RAIL);
---
> 					DoCommandP(end_tile, start_tile, _cur_railtype | (citymania::_fn_mod ? 1 << 6 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound_CONSTRUCTION_RAIL);
715c890
< 							DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound_CONSTRUCTION_RAIL);
---
> 							DoCommandP(end_tile, start_tile, citymania::_fn_mod ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound_CONSTRUCTION_RAIL);
722c897
< 							DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound_CONSTRUCTION_RAIL);
---
> 							DoCommandP(end_tile, start_tile, citymania::_fn_mod ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound_CONSTRUCTION_RAIL);
725c900
< 							uint32 p1 = _cur_railtype | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 6 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24;
---
> 							uint32 p1 = _cur_railtype | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 6 | ta.w << 8 | ta.h << 16 | citymania::_fn_mod << 24;
750a926,927
> 
> 		citymania::AbortStationPlacement();
759c936
< 	EventState OnCTRLStateChange() override
---
> 	EventState CM_OnRemoveModStateChange() override
761,762c938,942
< 		/* do not toggle Remove button by Ctrl when placing station */
< 		if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
---
> 		auto new_remove = citymania::RailToolbar_RemoveModChanged(this, _cm_invert_remove, _remove_button_clicked, false);
> 		if (new_remove != _remove_button_clicked) {
> 			_remove_button_clicked = new_remove;
> 			return ES_HANDLED;
> 		}
783a964,965
> 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};
790a973,974
> 	Hotkey(_railtoolbar_polyrail_keys, "polyrail", HOTKEY_POLYRAIL),
> 	Hotkey(_railtoolbar_new_poly_keys, "new_polyrail", HOTKEY_NEW_POLYRAIL),
793a978,979
> 	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),
820a1007,1008
> 		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),
877a1066,1070
> 	if (citymania::UseImprovedStationJoin()) {
> 		citymania::HandleStationPlacement(start, end);
> 		return;
> 	}
> 
884c1077
< 	uint32 p1 = _cur_railtype | _railstation.orientation << 6 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24;
---
> 	uint32 p1 = _cur_railtype | _railstation.orientation << 6 | numtracks << 8 | platlength << 16 | citymania::_fn_mod << 24;
891a1086,1091
> /* CityMania code start */
> public:
> 	enum class Hotkey : int {
> 		ROTATE,
> 	};
> /* CityMania code end */
1142c1342,1343
< 		if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
---
> 		if (citymania::UseImprovedStationJoin() || _settings_client.gui.station_show_coverage)
> 			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
1165a1367
> 		top = DrawStationAuthorityText(left, right, top) + WD_PAR_VSEP_NORMAL;
1443a1646
> 				citymania::MarkCoverageHighlightDirty();
1492a1696,1719
> 
> 	/* CityMania code start */
> 	EventState OnHotkey(int hotkey) override
> 	{
> 		switch ((BuildRailStationWindow::Hotkey)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 BuildRailStationWindow::Hotkey::ROTATE:
> 				this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X);
> 				_railstation.orientation = OtherAxis(_railstation.orientation);
> 				this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X);
> 				this->SetDirty();
> 				DeleteWindowById(WC_SELECT_STATION, 0);
> 				return ES_HANDLED;
> 
> 			default:
> 				NOT_REACHED();
> 		}
> 
> 		return ES_NOT_HANDLED;
> 	}
> 
> 	static HotkeyList hotkeys;
> 	/* CityMania code end */
1606a1834,1841
> /* CityMania code start */
> static Hotkey build_station_hotkeys[] = {
> 	Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailStationWindow::Hotkey::ROTATE),
> 	HOTKEY_LIST_END
> };
> HotkeyList BuildRailStationWindow::hotkeys("cm_build_rail_station", build_station_hotkeys);
> /* CityMania code end */
> 
1612c1847,1848
< 	_nested_station_builder_widgets, lengthof(_nested_station_builder_widgets)
---
> 	_nested_station_builder_widgets, lengthof(_nested_station_builder_widgets),
> 	&BuildRailStationWindow::hotkeys  // CityMania addition
1835a2073,2079
> /* CityMania code start */
> public:
> 	enum class Hotkey : int {
> 		ROTATE,
> 	};
> /* CityMania code end */
> 
1844c2088,2095
< 		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;
1846,1847c2097,2100
< 		size->width  = ScaleGUITrad(64) + 2;
< 		size->height = ScaleGUITrad(48) + 2;
---
> 			case WID_BRAD_DEPOT_AUTO:
> 				size->width  = ScaleGUITrad(128) + 6;
> 				break;
> 		}
1863a2117
> 			case WID_BRAD_DEPOT_AUTO:
1871a2126,2158
> 
> 	/* CityMania code start */
> 	EventState OnHotkey(int hotkey) override
> 	{
> 		switch ((BuildRailDepotWindow::Hotkey)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 BuildRailDepotWindow::Hotkey::ROTATE:
> 				if (_build_depot_direction < DIAGDIR_END) {
> 					this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
> 					_build_depot_direction = ChangeDiagDir(_build_depot_direction, DIAGDIRDIFF_90RIGHT);
> 					this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
> 				} else {
> 					citymania::RotateAutodetection();
> 				}
> 				this->SetDirty();
> 				return ES_HANDLED;
> 
> 			default:
> 				NOT_REACHED();
> 		}
> 
> 		return ES_NOT_HANDLED;
> 	}
> 
> 	static HotkeyList hotkeys;
> 	/* CityMania code end */
> };
> 
> /* CityMania code start */
> static Hotkey build_depot_hotkeys[] = {
> 	Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailDepotWindow::Hotkey::ROTATE),
> 	HOTKEY_LIST_END
1872a2160,2161
> HotkeyList BuildRailDepotWindow::hotkeys("cm_build_rail_depot", build_depot_hotkeys);
> /* CityMania code end */
1900a2190,2195
> 		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(),
1909a2205
> 	,&BuildRailDepotWindow::hotkeys  // CityMania addition
2021c2317
< 	_build_depot_direction = DIAGDIR_NW;
---
> 	_build_depot_direction = (DiagDirection)(DIAGDIR_NW + 1);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/rev.cpp.in cmclient/src/rev.cpp.in
38c38
< const char _openttd_revision[] = "${REV_VERSION}";
---
> const char _openttd_revision[] = "1.11.0";
51c51
< const char _openttd_revision_hash[] = "${REV_HASH}";
---
> const char _openttd_revision_hash[] = "bd80ec7cff2f2186b133ea4bee431cb1a2f1fc95";
56c56
< const char _openttd_revision_year[] = "${REV_YEAR}";
---
> const char _openttd_revision_year[] = "2021";
66c66
< const byte _openttd_revision_modified = ${REV_MODIFIED};
---
> const byte _openttd_revision_modified = 0;
73c73
< const byte _openttd_revision_tagged = ${REV_ISTAG};
---
> const byte _openttd_revision_tagged = 1;
88c88
< const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 0 << 20 | ${REV_ISSTABLETAG} << 19 | 28004;
---
> const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 0 << 20 | 1 << 19 | 28004;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/road_cmd.cpp cmclient/src/road_cmd.cpp
953c953
< static bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir)
---
> bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/road_func.h cmclient/src/road_func.h
161a162,163
> bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir);
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/road_gui.cpp cmclient/src/road_gui.cpp
11a12
> #include "cmd_helper.h"
12a14
> #include "station_func.h"
29a32
> #include "industry.h"
38a42,45
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_station_gui.hpp"
> 
64c71
< static RoadType _cur_roadtype;
---
> /* CM static */ RoadType _cur_roadtype;
66,67c73,74
< static DiagDirection _road_depot_orientation;
< static DiagDirection _road_station_picker_orientation;
---
> /* CM static */ DiagDirection _road_depot_orientation;
> DiagDirection _road_station_picker_orientation;
185c192,198
< 	uint8 ddir = _road_station_picker_orientation;
---
> 	if (citymania::UseImprovedStationJoin()) {
> 		citymania::PlaceRoadStop(start_tile, end_tile, p2, cmd);
> 		return;
> 	}
> 
> 	assert(_thd.cm.type == citymania::ObjectHighlight::Type::ROAD_STOP);
> 	uint8 ddir = _thd.cm.ddir;
186a200
> 	TileArea ta(start_tile, end_tile);
188,190c202,204
< 	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) { // drive-through stops
> 		SetBit(p2, 1);
> 		ddir -= DIAGDIR_END;
194d207
< 	TileArea ta(start_tile, end_tile);
206c219
< 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
---
> 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_BUSSTOP);
224c237
< 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
---
> 		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_TRUCKSTOP);
260c273
< 		if (w->IsWidgetLowered(i)) {
---
> 		if (w->GetWidget<NWidgetCore>(i) && w->IsWidgetLowered(i)) {
437c450
< 		_remove_button_clicked = false;
---
> 		if (widget != WID_ROT_REMOVE) _remove_button_clicked = false;
441c454
< 				HandlePlacePushButton(this, WID_ROT_ROAD_X, this->rti->cursor.road_nwse, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ROT_ROAD_X, this->rti->cursor.road_nwse, HT_RECT, DDSP_PLACE_ROAD_X_DIR);
446c459
< 				HandlePlacePushButton(this, WID_ROT_ROAD_Y, this->rti->cursor.road_swne, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ROT_ROAD_Y, this->rti->cursor.road_swne, HT_RECT, DDSP_PLACE_ROAD_Y_DIR);
451c464
< 				HandlePlacePushButton(this, WID_ROT_AUTOROAD, this->rti->cursor.autoroad, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ROT_AUTOROAD, this->rti->cursor.autoroad, HT_RECT, DDSP_PLACE_AUTOROAD);
456c469
< 				HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
461c474,475
< 				if (HandlePlacePushButton(this, WID_ROT_DEPOT, this->rti->cursor.depot, HT_RECT)) {
---
> 				if (HandlePlacePushButton(this, WID_ROT_DEPOT, this->rti->cursor.depot, HT_RECT, CM_DDSP_BUILD_ROAD_DEPOT)) {
> 					citymania::ResetRotateAutodetection();
468c482
< 				if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) {
---
> 				if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT, DDSP_BUILD_BUSSTOP)) {
475c489
< 				if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) {
---
> 				if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT, DDSP_BUILD_TRUCKSTOP)) {
485c499
< 				SetSelectionRed(false);
---
> 				// CM SetSelectionRed(false);
489c503
< 				HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT, CM_DDSP_BUILD_ROAD_BRIDGE);
494c508
< 				HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, this->rti->cursor.tunnel, HT_SPECIAL);
---
> 				HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, this->rti->cursor.tunnel, HT_SPECIAL, CM_DDSP_BUILD_ROAD_TUNNEL);
499c513,514
< 				if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return;
---
> 				_remove_button_clicked = citymania::RoadToolbar_RemoveModChanged(this, _remove_button_clicked, true, RoadTypeIsRoad(this->roadtype));
> 				// if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return;
501,503c516,518
< 				DeleteWindowById(WC_SELECT_STATION, 0);
< 				ToggleRoadButton_Remove(this);
< 				if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
---
> 				// DeleteWindowById(WC_SELECT_STATION, 0);
> 				// ToggleRoadButton_Remove(this);
> 				// if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
507c522
< 				HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, this->rti->cursor.convert_road, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, this->rti->cursor.convert_road, HT_RECT, DDSP_CONVERT_ROAD);
513,514c528,530
< 		this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
< 		if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
---
> 		citymania::RoadToolbar_UpdateOptionWidgetStatus(this, widget, _remove_button_clicked, RoadTypeIsRoad(this->roadtype));
> 		// this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
> 		// if (citymania::_remove_mod) RoadToolbar_CtrlChanged(this);
525c541,542
< 		_remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
---
> 		DiagDirection ddir;
> 		// CM _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
552c569,574
< 				DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0,
---
> 				ddir = _road_depot_orientation;
> 				if (ddir == citymania::DEPOTDIR_AUTO) {
> 					assert(_thd.cm.type == citymania::ObjectHighlight::Type::ROAD_DEPOT);
> 					ddir = _thd.cm.ddir;
> 				}
> 				DoCommandP(tile, _cur_roadtype << 2 | ddir, 0,
553a576,577
> 				if (citymania::_fn_mod == _settings_client.gui.persistent_depottools)
> 					ResetObjectToPlace();
598a623,624
> 
> 		citymania::AbortStationPlacement();
643a670,683
> 	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;
> 		}
> 	}
> 
682c722
< 							DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_CONSTRUCTION_OTHER);
---
> 							DoCommandP(ta.tile, ta.w | ta.h << 8, (citymania::_fn_mod ? 2 : 0) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_CONSTRUCTION_OTHER);
684c724
< 							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS]));
---
> 							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (citymania::_fn_mod << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS]));
694c734
< 							DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_CONSTRUCTION_OTHER);
---
> 							DoCommandP(ta.tile, ta.w | ta.h << 8, (citymania::_fn_mod << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_CONSTRUCTION_OTHER);
696c736
< 							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK]));
---
> 							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (citymania::_fn_mod << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK]));
714c754
< 	EventState OnCTRLStateChange() override
---
> 	EventState CM_OnRemoveModStateChange() override
716c756,760
< 		if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED;
---
> 		auto new_remove = citymania::RoadToolbar_RemoveModChanged(this, _remove_button_clicked, false, RoadTypeIsRoad(this->roadtype));
> 		if (new_remove != _remove_button_clicked) {
> 			_remove_button_clicked = new_remove;
> 			return ES_HANDLED;
> 		}
983a1028,1034
> /* CityMania code start */
> public:
> 	enum class Hotkey : int {
> 		ROTATE,
> 	};
> /* CityMania code end */
> 
991c1042
< 			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;
999,1002c1050,1063
< 		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;
> 		}
1018a1080
> 			case WID_BROD_DEPOT_AUTO:
1029a1092,1118
> 
> 	/* CityMania code start */
> 	EventState OnHotkey(int hotkey) override
> 	{
> 		switch ((BuildRoadDepotWindow::Hotkey)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 BuildRoadDepotWindow::Hotkey::ROTATE:
> 				if (_road_depot_orientation < DIAGDIR_END) {
> 					this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
> 					_road_depot_orientation = ChangeDiagDir(_road_depot_orientation, DIAGDIRDIFF_90RIGHT);
> 					this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
> 				} else {
> 					citymania::RotateAutodetection();
> 				}
> 				this->SetDirty();
> 				return ES_HANDLED;
> 
> 			default:
> 				NOT_REACHED();
> 		}
> 
> 		return ES_NOT_HANDLED;
> 	}
> 
> 	static HotkeyList hotkeys;
> 	/* CityMania code end */
1057a1147,1152
> 		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(),
1061a1157,1164
> /* CityMania code start */
> static Hotkey build_depot_hotkeys[] = {
> 	Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRoadDepotWindow::Hotkey::ROTATE),
> 	HOTKEY_LIST_END
> };
> HotkeyList BuildRoadDepotWindow::hotkeys("cm_build_road_depot", build_depot_hotkeys);
> /* CityMania code end */
> 
1066a1170
> 	,&BuildRoadDepotWindow::hotkeys  // CityMania addition
1074a1179,1185
> /* CityMania code start */
> public:
> 	enum class Hotkey : int {
> 		ROTATE,
> 	};
> /* CityMania code end */
> 
1082a1194,1196
> 		if (RoadTypeIsTram(_cur_roadtype) && _road_station_picker_orientation == (DiagDirection)(DIAGDIR_END + 2)) {
> 			_road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3);
> 		}
1086,1087c1200,1207
< 		for (uint i = RoadTypeIsTram(_cur_roadtype) ? WID_BROS_STATION_X : WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) {
< 			this->GetWidget<NWidgetCore>(i)->tool_tip = rti->strings.picker_tooltip[rs];
---
> 		if (RoadTypeIsTram(_cur_roadtype)) {
> 			this->GetWidget<NWidgetCore>(WID_BROS_STATION_X)->tool_tip = rti->strings.picker_tooltip[rs];
> 			this->GetWidget<NWidgetCore>(WID_BROS_STATION_Y)->tool_tip = rti->strings.picker_tooltip[rs];
> 			this->GetWidget<NWidgetCore>(WID_BROS_STATION_XY_AUTO)->tool_tip = rti->strings.picker_tooltip[rs];
> 		} else {
> 			for (uint i = WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) {
> 				this->GetWidget<NWidgetCore>(i)->tool_tip = rti->strings.picker_tooltip[rs];
> 			}
1108c1228,1229
< 		if (_settings_client.gui.station_show_coverage) {
---
> 		SetTileSelectSize(1, 1);
> 		if (citymania::UseImprovedStationJoin() || _settings_client.gui.station_show_coverage)
1110,1112d1230
< 		} else {
< 			SetTileSelectSize(1, 1);
< 		}
1121a1240
> 		top = DrawStationAuthorityText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top) + WD_PAR_VSEP_NORMAL;
1132,1135c1251,1272
< 		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:
> 				if (RoadTypeIsTram(_cur_roadtype))
> 					size->width  = ScaleGUITrad(128) + 6;
> 				else
> 					size->width  = ScaleGUITrad(64) + 2;
> 				break;
> 			default:
> 				break;
> 		}
1154a1292,1293
> 			case WID_BROS_STATION_AUTO:
> 			case WID_BROS_STATION_XY_AUTO:
1170a1310
> 				citymania::MarkCoverageHighlightDirty();
1181a1322,1354
> 
> 	/* CityMania code start */
> 	EventState OnHotkey(int hotkey) override
> 	{
> 		switch ((BuildRoadStationWindow::Hotkey)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 BuildRoadStationWindow::Hotkey::ROTATE:
> 				if (_road_station_picker_orientation < citymania::STATIONDIR_AUTO) {
> 					this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
> 					if (_road_station_picker_orientation < DIAGDIR_END) {
> 						_road_station_picker_orientation = ChangeDiagDir(_road_station_picker_orientation, DIAGDIRDIFF_90RIGHT);
> 					} else if (_road_station_picker_orientation == citymania::STATIONDIR_X) {
> 						_road_station_picker_orientation = citymania::STATIONDIR_Y;
> 					} else if (_road_station_picker_orientation == citymania::STATIONDIR_Y) {
> 						_road_station_picker_orientation = citymania::STATIONDIR_X;
> 					}
> 					this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
> 				} else {
> 					citymania::RotateAutodetection();
> 				}
> 				this->SetDirty();
> 				return ES_HANDLED;
> 
> 			default:
> 				NOT_REACHED();
> 		}
> 
> 		return ES_NOT_HANDLED;
> 	}
> 
> 	static HotkeyList hotkeys;
> 	/* CityMania code end */
1206a1380,1386
> 		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(),
1223a1404,1411
> /* CityMania code start */
> static Hotkey _cm_road_station_pickerhotkeys[] = {
> 	Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRoadStationWindow::Hotkey::ROTATE),
> 	HOTKEY_LIST_END
> };
> HotkeyList BuildRoadStationWindow::hotkeys("cm_build_road_station", _cm_road_station_pickerhotkeys);
> /* CityMania code end */
> 
1228a1417
> 	,&BuildRoadStationWindow::hotkeys // CityMania addition
1244a1434,1439
> 		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_XY_AUTO), SetMinimalSize(274, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP),
> 			NWidget(NWID_SPACER), SetFill(1, 0),
> 		EndContainer(),
1247c1442
< 			NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
---
> 			NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(134, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
1266a1462
> 	,&BuildRoadStationWindow::hotkeys // CityMania addition
1276,1277c1472,1473
< 	_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 -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/roadveh_cmd.cpp cmclient/src/roadveh_cmd.cpp
1641c1641
< 	PerformanceAccumulator framerate(PFE_GL_ROADVEHS);
---
> 	// PerformanceAccumulator framerate(PFE_GL_ROADVEHS);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/roadveh_gui.cpp cmclient/src/roadveh_gui.cpp
39c39,40
< 	DrawString(left, right, y + y_offset, STR_VEHICLE_INFO_BUILT_VALUE);
---
> 	if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index);  // CM
> 	DrawString(left, right, y + y_offset, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/saveload/afterload.cpp cmclient/src/saveload/afterload.cpp
59a60,64
> #include "../story_base.h"
> #include "../game/game_text.hpp"
> #include "../table/control_codes.h"
> 
> #include "../citymania/cm_highlight.hpp"
536a542,577
> extern GameStrings *_current_data;
> 
> void AfterLoadFindBTProCBInfo() {
> 	if (_current_data == NULL) return;
> 
> 	char buf[15];
> 	char *p = buf;
> 	int pn;
> 	p += Utf8Encode(p, SCC_ENCODED);
> 	for (const auto &ls : _current_data->raw_strings) {
> 		int string_id = 0;
> 		for (const auto &s : ls.lines) {
> 			if (s.empty() || s[0] == ';' || s[0] == '#' || s[0] == ' ' || s[0] == '\0') continue;
> 			if (strncmp(s.c_str(), "STR_TOWN_CLAIMED_CARGOS", strlen("STR_TOWN_CLAIMED_CARGOS")) == 0 ||
> 					strncmp(s.c_str(), "STR_TOWN_CARGOS_NEEDED_CB", strlen("STR_TOWN_CARGOS_NEEDED_CB")) == 0) {
> 				pn = p - buf + seprintf(p, lastof(buf), "%X:", string_id);
> 				bool with_decay = (strncmp(s.c_str(), "STR_TOWN_CLAIMED_CARGOS_DECAY",
> 					strlen("STR_TOWN_CLAIMED_CARGOS_DECAY")) == 0);
> 				for (StoryPageElement *se : StoryPageElement::Iterate()) {
> 					if (!se->text || strncmp(se->text, buf, pn) != 0) continue;
> 					uint req, cargomask, from, decay=0;
> 					if (with_decay) {
> 						sscanf(se->text + pn, "%X:%X:%X:%X", &req, &cargomask, &from, &decay);
> 				 	} else {
> 						sscanf(se->text + pn, "%X:%X:%X", &req, &cargomask, &from);
> 					}
> 					uint cargo_id = FindFirstBit(cargomask);
> 					if (!CB_Enabled()) CB_SetCB(true);
> 					CB_SetRequirements(cargo_id, req, from, decay);
> 				}
> 			}
> 			string_id++;
> 		}
> 	}
> }
> 
3150a3192,3196
> 	AfterLoadFindBTProCBInfo();
> 	citymania::InitializeZoningMap();
> 
> 	if ((!_networking || _network_server ) && _settings_client.gui.pause_after_load) _pause_mode = PM_PAUSED_NORMAL;
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/saveload/saveload.cpp cmclient/src/saveload/saveload.cpp
46a47
> #include <sstream>
2303a2305,2416
> /********************************************
>  ********** START OF ZSTD CODE **************
>  ********************************************/
> 
> #if defined(WITH_ZSTD)
> #include <zstd.h>
> 
> 
> /** Filter using ZSTD compression. */
> struct ZSTDLoadFilter : LoadFilter {
> 	ZSTD_DCtx *zstd;  ///< ZSTD decompression context
> 	byte fread_buf[MEMORY_CHUNK_SIZE];  ///< Buffer for reading from the file
> 	ZSTD_inBuffer input;  ///< ZSTD input buffer for fread_buf
> 
> 	/**
> 	 * Initialise this filter.
> 	 * @param chain The next filter in this chain.
> 	 */
> 	ZSTDLoadFilter(LoadFilter *chain) : LoadFilter(chain)
> 	{
> 		this->zstd = ZSTD_createDCtx();
> 		if (!this->zstd) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
> 		this->input = {this->fread_buf, 0, 0};
> 	}
> 
> 	/** Clean everything up. */
> 	~ZSTDLoadFilter()
> 	{
> 		ZSTD_freeDCtx(this->zstd);
> 	}
> 
> 	size_t Read(byte *buf, size_t size) override
> 	{
> 		ZSTD_outBuffer output{buf, size, 0};
> 
> 		do {
> 			/* read more bytes from the file? */
> 			if (this->input.pos == this->input.size) {
> 				this->input.size = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
> 				this->input.pos = 0;
> 			}
> 
> 			size_t ret = ZSTD_decompressStream(this->zstd, &output, &this->input);
> 			if (ZSTD_isError(ret)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "libzstd returned error code");
> 			if (ret == 0) break;
> 		} while (output.pos < output.size);
> 
> 		return output.pos;
> 	}
> };
> 
> /** Filter using ZSTD compression. */
> struct ZSTDSaveFilter : SaveFilter {
> 	ZSTD_CCtx *zstd;  ///< ZSTD compression context
> 
> 	/**
> 	 * Initialise this filter.
> 	 * @param chain             The next filter in this chain.
> 	 * @param compression_level The requested level of compression.
> 	 */
> 	ZSTDSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
> 	{
> 		this->zstd = ZSTD_createCCtx();
> 		if (!this->zstd) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
> 		if (ZSTD_isError(ZSTD_CCtx_setParameter(this->zstd, ZSTD_c_compressionLevel, (int)compression_level - 100))) {
> 			ZSTD_freeCCtx(this->zstd);
> 			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "invalid compresison level");
> 		}
> 	}
> 
> 	/** Clean up what we allocated. */
> 	~ZSTDSaveFilter()
> 	{
> 		ZSTD_freeCCtx(this->zstd);
> 	}
> 
> 	/**
> 	 * Helper loop for writing the data.
> 	 * @param p      The bytes to write.
> 	 * @param len    Amount of bytes to write.
> 	 * @param mode   Mode for ZSTD_compressStream2.
> 	 */
> 	void WriteLoop(byte *p, size_t len, ZSTD_EndDirective mode)
> 	{
> 		byte buf[MEMORY_CHUNK_SIZE]; // output buffer
> 		ZSTD_inBuffer input{p, len, 0};
> 
> 		bool finished;
> 		do {
> 			ZSTD_outBuffer output{buf, sizeof(buf), 0};
> 			size_t remaining = ZSTD_compressStream2(this->zstd, &output, &input, mode);
> 			if (ZSTD_isError(remaining)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "libzstd returned error code");
> 
> 			if (output.pos != 0) this->chain->Write(buf, output.pos);
> 
> 			finished = (mode == ZSTD_e_end ? (remaining == 0) : (input.pos == input.size));
> 		} while (!finished);
> 	}
> 
> 	void Write(byte *buf, size_t size) override
> 	{
> 		this->WriteLoop(buf, size, ZSTD_e_continue);
> 	}
> 
> 	void Finish() override
> 	{
> 		this->WriteLoop(nullptr, 0, ZSTD_e_end);
> 		this->chain->Finish();
> 	}
> };
> #endif /* WITH_LIBZSTD */
> 
2309,2319c2422,2432
< struct SaveLoadFormat {
< 	const char *name;                     ///< name of the compressor/decompressor (debug-only)
< 	uint32 tag;                           ///< the 4-letter tag by which it is identified in the savegame
< 
< 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
< 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
< 
< 	byte min_compression;                 ///< the minimum compression level of this format
< 	byte default_compression;             ///< the default compression level of this format
< 	byte max_compression;                 ///< the maximum compression level of this format
< };
---
> // struct SaveLoadFormat {
> // 	const char *name;                     ///< name of the compressor/decompressor (debug-only)
> // 	uint32 tag;                           ///< the 4-letter tag by which it is identified in the savegame
> 
> // 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
> // 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
> 
> // 	byte min_compression;                 ///< the minimum compression level of this format
> // 	byte default_compression;             ///< the default compression level of this format
> // 	byte max_compression;                 ///< the maximum compression level of this format
> // };
2322c2435,2437
< static const SaveLoadFormat _saveload_formats[] = {
---
> static const citymania::SaveLoadFormat _saveload_formats[] = {
> 	/* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
> 	{0, "none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, citymania::CompressionMethod::None, 0, 0, 0},
2325c2440
< 	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0},
---
> 	{1, "lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    citymania::CompressionMethod::LZO, 0, 0, 0},
2327c2442
< 	{"lzo",    TO_BE32X('OTTD'), nullptr,                            nullptr,                            0, 0, 0},
---
> 	{1, "lzo",    TO_BE32X('OTTD'), nullptr,                            nullptr,                            citymania::CompressionMethod::LZO, 0, 0, 0},
2329,2330d2443
< 	/* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
< 	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
2335c2448
< 	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 6, 9},
---
> 	{2, "zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   citymania::CompressionMethod::Zlib, 0, 6, 9},
2337c2450,2461
< 	{"zlib",   TO_BE32X('OTTZ'), nullptr,                            nullptr,                            0, 0, 0},
---
> 	{2, "zlib",   TO_BE32X('OTTZ'), nullptr,                            nullptr,                            citymania::CompressionMethod::Zlib, 0, 0, 0},
> #endif
> #if defined(WITH_ZSTD)
> 	/* Zstd provides a decent compression rate at a very high compression/decompression speed. Compared to lzma level 2
> 	 * zstd saves are about 40% larger (on level 1) but it has about 30x faster compression and 5x decompression making it
> 	 * a good choice for multiplayer servers. And zstd level 1 seems to be the optimal one for client connection speed
> 	 * (compress + 10 MB/s download + decompress time), about 3x faster than lzma:2 and 1.5x than zlib:2 and lzo.
> 	 * As zstd has negative compression levels the values were increased by 100 moving zstd level range -100..22 into
> 	 * openttd 0..122. Also note that value 100 mathes zstd level 0 which is a special value for default level 3 (openttd 103) */
> 	{3, "zstd",   TO_BE32X('OTTS'), CreateLoadFilter<ZSTDLoadFilter>,   CreateSaveFilter<ZSTDSaveFilter>,   citymania::CompressionMethod::ZSTD, 0, 101, 122},
> #else
> 	{3, "zstd",   TO_BE32X('OTTS'), nullptr,                            nullptr,                            citymania::CompressionMethod::ZSTD, 0, 0, 0},
2345c2469
< 	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 2, 9},
---
> 	{4, "lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   citymania::CompressionMethod::LZMA, 0, 2, 9},
2347c2471
< 	{"lzma",   TO_BE32X('OTTX'), nullptr,                            nullptr,                            0, 0, 0},
---
> 	{4, "lzma",   TO_BE32X('OTTX'), nullptr,                            nullptr,                            citymania::CompressionMethod::LZMA, 0, 0, 0},
2350a2475,2572
> namespace citymania {  // citymania savegame format handling
> 
> static const std::string DEFAULT_NETWORK_SAVEGAME_COMPRESSION = "zstd:1 zlib:2 lzma:0 lzo:0";
> 
> /**
>  * Parses the savegame format and compression level string ("format:[compression_level]").
>  * @param str  String to parse
>  * @return Parsest SavePreset or std::nullopt
>  */
> static std::optional<SavePreset> ParseSavePreset(const std::string &str)
> {
>     auto delimiter_pos = str.find(':');
>     auto format = (delimiter_pos != std::string::npos ? str.substr(0, delimiter_pos) : str);
>     for (auto &slf : _saveload_formats) {
>         if (slf.init_write != nullptr && format == slf.name) {
>             /* If compression level wasn't specified use the default one */
>             if (delimiter_pos == std::string::npos) return SavePreset{&slf, slf.default_compression};
> 
>             auto level_str = str.substr(delimiter_pos + 1);
>             int level;
>             try{
>                 level = stoi(level_str);
>             } catch(const std::exception &e) {
>                 /* Can't parse compression level, set it out ouf bounds to fail later */
>                 level = (int)slf.max_compression + 1;
>             }
> 
>             if (level != Clamp<int>(level, slf.min_compression, slf.max_compression)) {
>                 /* Invalid compression level, show the error and use default level */
>                 SetDParamStr(0, level_str.c_str());
>                 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
>                 return SavePreset{&slf, slf.default_compression};
>             }
> 
>             return SavePreset{&slf, (byte)level};
>         }
>     }
>     SetDParamStr(0, str.c_str());
>     ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
>     return {};
> }
> 
> static_assert(lengthof(_saveload_formats) <= 8);  // uint8 is used for the bitset of format ids
> 
> /**
>  * Finds the best savegame preset to use in network game based on server settings and client capabilies.
>  * @param server_formats  String of space-separated format descriptions in form format[:compression_level] acceptable for the server (listed first take priority).
>  * @param client_formats  Bitset of savegame formats available to the client (as returned by GetAvailableLoadFormats)
>  * @return SavePreset that satisfies both server and client or std::nullopt
>  */
> std::optional<SavePreset> FindCompatibleSavePreset(const std::string &server_formats, uint8 client_formats)
> {
>     std::istringstream iss(server_formats.empty() ? DEFAULT_NETWORK_SAVEGAME_COMPRESSION : server_formats);
>     std::string preset_str;
>     while (std::getline(iss, preset_str, ' ')) {
>         auto preset = ParseSavePreset(preset_str);
>         if (!preset) continue;
>         if ((client_formats & (1 << preset->format->id)) != 0) return preset;
>     }
>     return {};
> }
> 
> /**
>  * Return the bitset of savegame formats that this game instance can load
>  * @return bitset of available savegame formats
>  */
> uint8 GetAvailableLoadFormats()
> {
>     uint8 res = 0;
>     for(auto &slf : _saveload_formats) {
>         if (slf.init_load != nullptr) {
>             res |= (1 << slf.id);
>         }
>     }
>     return res;
> }
> 
> /**
>  * Return the save preset to use for local game saves.
>  * @return SavePreset to use
>  */
> static SavePreset GetLocalSavePreset()
> {
>     if (!StrEmpty(_savegame_format)) {
>         auto config = ParseSavePreset(_savegame_format);
>         if (config) return *config;
>     }
> 
>     const citymania::SaveLoadFormat *def = lastof(_saveload_formats);
> 
>     /* find default savegame format, the highest one with which files can be written */
>     while (!def->init_write) def--;
> 
>     return {def, def->default_compression};
> }
> 
> } // namespace citymania
> 
2357a2580,2581
> #if 0
> Citymania uses other way
2404a2629,2630
> #endif
> 
2496c2722
< static SaveOrLoadResult SaveFileToDisk(bool threaded)
---
> static SaveOrLoadResult SaveFileToDisk(bool threaded, citymania::SavePreset preset)
2499,2500c2725,2726
< 		byte compression;
< 		const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
---
> 		// byte compression;
> 		// const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
2503c2729
< 		uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
---
> 		uint32 hdr[2] = { preset.format->tag, TO_BE32(SAVEGAME_VERSION << 16) };
2506c2732
< 		_sl.sf = fmt->init_write(_sl.sf, compression);
---
> 		_sl.sf = preset.format->init_write(_sl.sf, preset.compression_level);
2554c2780
< static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
---
> static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded, citymania::SavePreset preset)
2568c2794
< 	if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true)) {
---
> 	if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true, std::move(preset))) {
2571c2797
< 		SaveOrLoadResult result = SaveFileToDisk(false);
---
> 		SaveOrLoadResult result = SaveFileToDisk(false, preset);
2586c2812
< SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
---
> SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded, citymania::SavePreset preset)
2590c2816
< 		return DoSave(writer, threaded);
---
> 		return DoSave(writer, threaded, preset);
2618c2844
< 	const SaveLoadFormat *fmt = _saveload_formats;
---
> 	const citymania::SaveLoadFormat *fmt = _saveload_formats;
2665a2892,2893
> 	DEBUG(sl, 2, "Using saveload format '%s'", fmt->name);
> 
2831c3059
< 			return DoSave(new FileWriter(fh), threaded);
---
> 			return DoSave(new FileWriter(fh), threaded, citymania::GetLocalSavePreset());
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/saveload/saveload.h cmclient/src/saveload/saveload.h
14a15,16
> #include "saveload_filter.h"
> #include <optional>
362a365,400
> namespace citymania {
> 
> enum class CompressionMethod : uint8 {
> 	None = 0u,
> 	LZO = 1u,
> 	Zlib = 2u,
> 	ZSTD = 3u,
> 	LZMA = 4u,
> };
> 
> /** The format for a reader/writer type of a savegame */
> struct SaveLoadFormat {
> 	uint8 id;                             ///< unique integer id of this savegame format (olny used for networkking so is not guaranteed to be preserved between versions)
> 	const char *name;                     ///< name of the compressor/decompressor (debug-only)
> 	uint32 tag;                           ///< the 4-letter tag by which it is identified in the savegame
> 
> 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
> 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
> 
> 	CompressionMethod method;             ///< compression method used in this format
> 	byte min_compression;                 ///< the minimum compression level of this format
> 	byte default_compression;             ///< the default compression level of this format
> 	byte max_compression;                 ///< the maximum compression level of this format
> };
> 
> /** The preset to use for generating savegames */
> struct SavePreset {
> 	const SaveLoadFormat *format;  ///< savegame format to use
> 	byte compression_level;        ///< compression level to use
> };
> 
> std::optional<SavePreset> FindCompatibleSavePreset(const std::string &server_formats, uint8 client_format_flags);
> uint8 GetAvailableLoadFormats();
> 
> } // namespace citymania
> 
373c411
< SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded);
---
> SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded, citymania::SavePreset preset);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/saveload/storage_sl.cpp cmclient/src/saveload/storage_sl.cpp
11a12
> #include "../citymania/cm_saveload.hpp"
49c50
< 	{ 'PSAC', Save_PSAC, Load_PSAC, nullptr, nullptr, CH_ARRAY | CH_LAST},
---
> 	{ 'PSAC', citymania::Save_PSAC, citymania::Load_PSAC, nullptr, nullptr, CH_ARRAY | CH_LAST},
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/saveload/town_sl.cpp cmclient/src/saveload/town_sl.cpp
20a21,22
> #include "../citymania/cm_main.hpp"
> 
54a57
> 	citymania::Emit(citymania::event::TownCachesRebuilt());
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/script/api/script_window.hpp.in cmclient/src/script/api/script_window.hpp.in
22a23
> #include "../../widgets/cargo_table_widget.h"
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/settings.cpp cmclient/src/settings.cpp
2326a2327,2333
> 
> // CM
> #include "statusbar_gui.h"
> static bool cm_v_RedrawStatusBar(int32 p1) {
> 	CM_RedrawStatusBar();
> 	return true;
> }
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/settings_gui.cpp cmclient/src/settings_gui.cpp
35a36
> #include "hotkeys.h"
579a581,582
> 
> 	static HotkeyList hotkeys;
674a678,690
> 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);
> 
679c695,696
< 	_nested_game_options_widgets, lengthof(_nested_game_options_widgets)
---
> 	_nested_game_options_widgets, lengthof(_nested_game_options_widgets),
> 	&GameOptionsWindow::hotkeys
1500a1518
> 			graphics->Add(new SettingEntry("gui.cm_shaded_trees"));
1524a1543,1547
> 				general->Add(new SettingEntry("gui.pause_after_load"));
> 				general->Add(new SettingEntry("gui.cm_fn_mod"));
> 				general->Add(new SettingEntry("gui.cm_remove_mod"));
> 				general->Add(new SettingEntry("gui.cm_estimate_mod"));
> 				general->Add(new SettingEntry("gui.cm_show_apm"));
1546a1570,1575
> 				viewports->Add(new SettingEntry("gui.cb_distance_check"));
> 				viewports->Add(new SettingEntry("gui.old_depot_train_length_calc"));
> 				viewports->Add(new SettingEntry("gui.cm_land_tooltips_for_industries"));
> 				viewports->Add(new SettingEntry("gui.cm_land_tooltips_for_stations"));
> 				viewports->Add(new SettingEntry("gui.cm_land_tooltips_for_houses"));
> 				// viewports->Add(new SettingEntry("gui.polyrail_double_click"));
1553a1583,1585
> 				construction->Add(new SettingEntry("gui.persistent_depottools"));
> 				construction->Add(new SettingEntry("gui.cm_open_vehicle_for_shared_clone"));
> 				construction->Add(new SettingEntry("gui.cm_open_orders_for_new_vehicles"));
1555a1588
> 				construction->Add(new SettingEntry("gui.cm_use_improved_station_join"));
1566a1600,1601
> 			interface->Add(new SettingEntry("gui.powerfund_money"));
> 			interface->Add(new SettingEntry("gui.powerfund_houses"));
1567a1603
> 			interface->Add(new SettingEntry("gui.cm_graph_background"));
1583a1620
> 			advisors->Add(new SettingEntry("gui.runway_too_short_warn"));
1627a1665,1684
> 			/** 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"));
> 			}
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/settings_type.h cmclient/src/settings_type.h
23a24,25
> #include "citymania/cm_settings.hpp"
> 
98a101,109
> 	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
129a141
> 	bool   pause_after_load;                 ///< CM should we pause the game after loading save?
151a164,165
> 	bool   persistent_depottools;            ///< keep the depot building tools active after usage
> 	bool   cm_use_improved_station_join;     ///< use ctrl-clicking station tiles to join instead of popup window
181a196,218
> 	bool   old_depot_train_length_calc;      ///< display vehicle length in whole numbers - old style
> 	uint8  cb_distance_check;                ///< zoning cb distance
> 	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
> 
> 	bool cm_open_vehicle_for_shared_clone;
> 	bool cm_open_orders_for_new_vehicles;
> 	bool cm_land_tooltips_for_industries;
> 	bool cm_land_tooltips_for_stations;
> 	bool cm_land_tooltips_for_houses;
> 
> 	citymania::ModKey cm_fn_mod;
> 	citymania::ModKey cm_remove_mod;
> 	citymania::ModKey cm_estimate_mod;
> 
> 	uint8 cm_shaded_trees;
> 	bool cm_show_apm;
> 	uint8 cm_graph_background;
> 
576a614,615
> 
> 	citymania::Settings  citymania;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/ship_cmd.cpp cmclient/src/ship_cmd.cpp
802c802
< 	PerformanceAccumulator framerate(PFE_GL_SHIPS);
---
> 	// PerformanceAccumulator framerate(PFE_GL_SHIPS);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/ship_gui.cpp cmclient/src/ship_gui.cpp
69c69,70
< 	DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE);
---
> 	if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index);  // CM
> 	DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/signs_gui.cpp cmclient/src/signs_gui.cpp
34a35,36
> #include "citymania/cm_hotkeys.hpp"
> 
566c568
< 	if (_ctrl_pressed && (si->owner == _local_company || (si->owner == OWNER_DEITY && _game_mode == GM_EDITOR))) {
---
> 	if (citymania::_fn_mod && (si->owner == _local_company || (si->owner == OWNER_DEITY && _game_mode == GM_EDITOR))) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/smallmap_gui.cpp cmclient/src/smallmap_gui.cpp
31a32,34
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_minimap.hpp"
> 
169a173,175
> 	citymania::BuildIndustriesLegend();
> 	return;
> 
199a206,208
> 	citymania::BuildLinkStatsLegend();
> 	return;
> 
235a245
> 	_legend_from_industries,
268a279
> 	{nullptr, citymania::_yellow_map_heights,     lengthof(citymania::_yellow_map_heights),     MKCOLOUR_XXXX(0xC1)},
275a287,289
> 	citymania::BuildLandLegend();
> 	return;
> 
326a341,343
> 	citymania::BuildOwnerLegend();
> 	return;
> 
586a604,628
> static inline uint32 CM_GetSmallMapIMBAPixels(TileIndex tile, TileType t)
> {
> 	const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
> 	switch (t) {
> 		// case MP_TREES:
> 		// 	if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
> 		// 		return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES);
> 		// 	}
> 		// 	return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES);
> 
> 		case MP_CLEAR:
> 			if (IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_DESERT)) {
> 				const SmallMapColourScheme *cs = &_heightmap_schemes[3];
> 				return cs->height_colours[TileHeight(tile)];
> 			}
> 			// if (IsClearGround(tile, CLEAR_SNOW))
> 			// 	return _vegetation_clear_bits[GetClearGround(tile)];
> 			FALLTHROUGH;
> 
> 		default:
> 			const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
> 			return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_vehicles_andor[t]);
> 	}
> }
> 
769c811
< 				if (this->map_type == SMT_INDUSTRY) {
---
> 				if (this->map_type == SMT_INDUSTRY || this->map_type == CM_SMT_IMBA) {
817a860,862
> 		case CM_SMT_IMBA:
> 			return CM_GetSmallMapIMBAPixels(tile, et);
> 
928c973
< 			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);
1039a1085
> 		case CM_SMT_IMBA:
1071a1118
> 	this->SetWidgetDisabledState(WID_SM_SHOW_HEIGHT, this->map_type == CM_SMT_IMBA);
1144c1191
< 			if (i == SMT_INDUSTRY) {
---
> 			if (i == SMT_INDUSTRY || i == CM_SMT_IMBA) {
1227a1275
> 				case CM_SMT_IMBA:
1241c1289
< 				if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) {
---
> 				if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS || this->map_type == CM_SMT_IMBA) && i++ >= number_of_rows)) {
1252a1301
> 					case CM_SMT_IMBA:
1291a1341,1347
> 			break;
> 		}
> 		case CM_WID_SM_IMBA: {
> 			uint offset = this->IsWidgetLowered(CM_WID_SM_IMBA) ? 1 : 0;
> 			Dimension d = GetSpriteSize(SPR_IMG_INDUSTRY);
> 			DrawSprite(SPR_IMG_INDUSTRY, PAL_NONE, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset);
> 			break;
1309c1365
< 	if (map_type != SMT_INDUSTRY) this->BreakIndustryChainLink();
---
> 	if (map_type != SMT_INDUSTRY && map_type != CM_SMT_IMBA) this->BreakIndustryChainLink();
1342c1398
< 	if (_ctrl_pressed) {
---
> 	if (citymania::_fn_mod) {
1362a1419
> 	if (this->map_type == CM_SMT_IMBA) this->BreakIndustryChainLink();
1401c1458
< 	if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) {
---
> 	if (widget == WID_SM_LEGEND && (this->map_type == SMT_INDUSTRY || this->map_type == CM_SMT_IMBA)) {
1446a1504
> 		case CM_WID_SM_IMBA:
1466c1524
< 			if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) {
---
> 			if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER || this->map_type == CM_SMT_IMBA) {
1471c1529
< 				if (this->map_type == SMT_INDUSTRY) {
---
> 				if (this->map_type == SMT_INDUSTRY || this->map_type == CM_SMT_IMBA) {
1494a1553
> 				case CM_SMT_IMBA:
1543c1602
< 			if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
---
> 			if (this->map_type != CM_SMT_IMBA) this->SwitchMapType(CM_SMT_IMBA);
1683c1742
< SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
---
> SmallMapWindow::SmallMapType SmallMapWindow::map_type = CM_SMT_IMBA;
1780,1781c1839,1840
< 					NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK),
< 							SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1),
---
> 					NWidget(WWT_IMGBTN, COLOUR_BROWN, CM_WID_SM_IMBA),
> 							SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_CM_SMALLMAP_TOOLTIP_SHOW_IMBA_ON_MAP), SetFill(1, 1),
1845a1905,1907
> #if 0
> CityMania has its own smallmap
> 
1859a1922
> #endif
1879c1942
< 	SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
---
> 	citymania::SmallMapWindow *w = dynamic_cast<citymania::SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/smallmap_gui.h cmclient/src/smallmap_gui.h
26c26
< void ShowSmallMap();
---
> // void ShowSmallMap(); CM
53a54
> 		CM_SMT_IMBA,
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/station_cmd.cpp cmclient/src/station_cmd.cpp
61a62,63
> #include "citymania/cm_station_gui.hpp"
> 
770a773
> 	citymania::OnStationTileSetChange(this, adding, type);
1467a1471
> 		citymania::OnStationPartBuilt(st, tile_org, p1, p2);
1951a1956
> 		if (st != nullptr) citymania::OnStationPartBuilt(st, tile, p1, p2);
2358a2364
> 		citymania::OnStationPartBuilt(st, tile, p1, p2);
2593a2600
> 		citymania::OnStationPartBuilt(st, tile, p1, p2);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/station.cpp cmclient/src/station.cpp
20a21
> #include "town.h"
38a40,41
> Kdtree_StationXYFunc kd_station_func;
> StationKdtree _station_kdtree(kd_station_func);
40c43,45
< StationKdtree _station_kdtree(Kdtree_StationXYFunc);
---
> uint16 Kdtree_StationXYFunc::operator()(StationID stid, int dim) const {
>     return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy);
> }
87a93,100
> 	for (Town *t : Town::Iterate()) {
> 		// 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;
> 		}
> 	}
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/station_gui.cpp cmclient/src/station_gui.cpp
41a42,45
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_station_gui.hpp"
> #include "citymania/cm_tooltips.hpp"
> 
58a63,69
> 		/* CityMania code begin */
> 		if (supplies) {
> 			auto s = citymania::GetStationCoverageProductionText(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad, sct);
> 			return DrawStringMultiLine(left, right, top, INT32_MAX, s.c_str());
> 		}
> 		/* CityMania code end */
> 
80a92,108
> int DrawStationAuthorityText(int left, int right, int top) {
> 	TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
> 	Town *town = ClosestTownFromTile(tile, UINT_MAX);
> 	auto dist = DistanceManhattan(town->xy, tile);
> 
> 	SetDParam(0, town ? town->index : INVALID_TOWN);
> 	if (dist <= 10) {
> 		return DrawStringMultiLine(left, right, top, INT32_MAX, STR_CM_STATION_BUILD_TOWN_SMALL);
> 	} else if (dist <= 15) {
> 		return DrawStringMultiLine(left, right, top, INT32_MAX, STR_CM_STATION_BUILD_TOWN_MEDIUM);
> 	} else if (dist <= 20) {
> 		return DrawStringMultiLine(left, right, top, INT32_MAX, STR_CM_STATION_BUILD_TOWN_LARGE);
> 	} else {
> 		return DrawStringMultiLine(left, right, top, INT32_MAX, STR_CM_STATION_BUILD_TOWN);
> 	}
> }
> 
88c116
< 	if (_ctrl_pressed) {
---
> 	if (citymania::_fn_mod) {
127a156,162
> 	/* CityMania code begin */
> 	if (citymania::UseImprovedStationJoin()) {
> 		if (citymania::CheckRedrawStationCoverage()) w->SetDirty();
> 		return;
> 	}
> 	/* CityMania code end */
> 
129,130c164,165
< 	static bool _last_ctrl_pressed;
< 	if (_ctrl_pressed != _last_ctrl_pressed) {
---
> 	static bool _last_fn_pressed;
> 	if (citymania::_fn_mod != _last_fn_pressed) {
132c167
< 		_last_ctrl_pressed = _ctrl_pressed;
---
> 		_last_fn_pressed = citymania::_fn_mod;
539c574
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
552c587
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
600c635
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
622c657
< 					if (_ctrl_pressed) {
---
> 					if (citymania::_fn_mod) {
1302a1338
> 	int ratings_list_y = 0;             ///< Y coordinate of first line in station ratings panel.
1840c1876
< 	int DrawCargoRatings(const Rect &r) const
---
> 	int DrawCargoRatings(const Rect &r)
1853a1890
> 		this->ratings_list_y = y;
1892c1929
< 		if (_ctrl_pressed) {
---
> 		if (citymania::_fn_mod) {
1917c1954
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2090a2128,2149
> 	bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override
> 	{
> 		if (widget != WID_SV_ACCEPT_RATING_LIST ||
> 		    	this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON)
> 			return false;
> 
> 		int ofs_y = pt.y - this->ratings_list_y;
> 		if (ofs_y < 0) return false;
> 
> 		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) {
> 				return citymania::ShowStationRatingTooltip(this, st, cs, close_cond);
> 			}
> 		}
> 		return false;
> 	}
> 
2262c2321
< struct SelectStationWindow : Window {
---
> struct SelectStationWindow : WindowPopup {
2268c2327
< 		Window(desc),
---
> 		WindowPopup(desc, WPUT_WIDGET_RELATIVE),
2271a2331
> 		this->wpu_widget = WID_JS_PANEL;
2425c2485
< 	if (!_ctrl_pressed) return false;
---
> 	if (!citymania::_fn_mod) return false;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/station_gui.h cmclient/src/station_gui.h
25a26
> int DrawStationAuthorityText(int left, int right, int top);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/station_kdtree.h cmclient/src/station_kdtree.h
18,19c18,23
< inline uint16 Kdtree_StationXYFunc(StationID stid, int dim) { return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy); }
< typedef Kdtree<StationID, decltype(&Kdtree_StationXYFunc), uint16, int> StationKdtree;
---
> class Kdtree_StationXYFunc {
> public:
>     uint16 operator()(StationID stid, int dim) const;
> };
> 
> typedef Kdtree<StationID, Kdtree_StationXYFunc, uint16, int> StationKdtree;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/statusbar_gui.cpp cmclient/src/statusbar_gui.cpp
34a35,36
> #include "citymania/cm_hotkeys.hpp"
> 
83a86
> 	GUITimer cm_epm_timer;
94a98
> 		this->cm_epm_timer.SetInterval(1000);
128a133,142
> 			case CM_WID_S_APM:
> 				if (!_settings_client.gui.cm_show_apm) {
> 					*size = Dimension(0, 0);
> 					return;
> 				}
> 				SetDParam(0, 999);
> 				SetDParam(1, 999);
> 				d = GetStringBoundingBox(STR_CM_STATUSBAR_APM);
> 				break;
> 
190a205,213
> 
> 			case CM_WID_S_APM:
> 				if (_settings_client.gui.cm_show_apm) {
> 					auto epm = citymania::GetEPM();
> 					SetDParam(0, epm.second);
> 					SetDParam(1, epm.first);
> 					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, text_top, STR_CM_STATUSBAR_APM, TC_FROMSTRING, SA_HOR_CENTER);
> 				}
> 				break;
239a263,266
> 
> 		if (this->cm_epm_timer.CountElapsed(delta_ms)) {
> 			this->SetWidgetDirty(CM_WID_S_APM);
> 		}
245c272
< 		NWidget(WWT_PANEL, COLOUR_GREY, WID_S_LEFT), SetMinimalSize(140, 12), EndContainer(),
---
> 		NWidget(WWT_PANEL, COLOUR_GREY, WID_S_LEFT), SetMinimalSize(100, 12), EndContainer(),
247c274,275
< 		NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_RIGHT), SetMinimalSize(140, 12),
---
> 		NWidget(WWT_PANEL, COLOUR_GREY, CM_WID_S_APM), SetMinimalSize(100, 12), EndContainer(),
> 		NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_RIGHT), SetMinimalSize(100, 12),
272a301,305
> }
> 
> void CM_RedrawStatusBar() {
> 	StatusBarWindow *w = dynamic_cast<StatusBarWindow*>(FindWindowById(WC_STATUS_BAR, 0));
> 	w->ReInit();
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/statusbar_gui.h cmclient/src/statusbar_gui.h
25a26,27
> void CM_RedrawStatusBar();
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/story_gui.cpp cmclient/src/story_gui.cpp
35a36,37
> #include "citymania/cm_hotkeys.hpp"
> 
552c554
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
578c580
< 					SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
---
> 					SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this, CM_DDSP_STORY_BUTTON);
590c592
< 					SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this);
---
> 					SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this, CM_DDSP_STORY_BUTTON);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/subsidy_gui.cpp cmclient/src/subsidy_gui.cpp
25a26,27
> #include "citymania/cm_hotkeys.hpp"
> 
85,86c87,88
< 		if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) {
< 			if (_ctrl_pressed) ShowExtraViewportWindow(xy);
---
> 		if (citymania::_fn_mod || !ScrollMainWindowToTile(xy)) {
> 			if (citymania::_fn_mod) ShowExtraViewportWindow(xy);
95c97
< 			if (_ctrl_pressed) {
---
> 			if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/table/settings.ini cmclient/src/table/settings.ini
50a51,52
> static bool cm_v_RedrawStatusBar(int32 p1);
> 
2757a2760,2767
> var      = gui.pause_after_load
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_PAUSE_AFTER_LOAD
> strhelp  = STR_CM_CONFIG_SETTING_PAUSE_AFTER_LOAD_HELPTEXT
> cat      = SC_BASIC
> 
> [SDTC_BOOL]
3031a3042,3057
> var      = gui.cm_open_vehicle_for_shared_clone
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_OPEN_VEHICLE_FOR_SHARED_CLONE
> strhelp  = STR_CM_CONFIG_SETTING_OPEN_VEHICLE_FOR_SHARED_CLONE_HELPTEXT
> cat      = SC_BASIC
> 
> [SDTC_BOOL]
> var      = gui.cm_open_orders_for_new_vehicles
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_OPEN_ORDERS_FOR_NEW_VEHICLES
> strhelp  = STR_CM_CONFIG_SETTING_OPEN_ORDERS_FOR_NEW_VEHICLES_HELPTEXT
> cat      = SC_BASIC
> 
> [SDTC_BOOL]
3283a3310,3325
> var      = gui.persistent_depottools
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CONFIG_SETTING_PERSISTENT_DEPOTTOOLS
> strhelp  = STR_CONFIG_SETTING_PERSISTENT_DEPOTTOOLS_HELPTEXT
> cat      = SC_BASIC
> 
> [SDTC_BOOL]
> var      = gui.cm_use_improved_station_join
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN
> strhelp  = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT
> cat      = SC_BASIC
> 
> [SDTC_BOOL]
4122a4165,4421
> 
> ; //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.cm_land_tooltips_for_industries
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = true
> str      = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_INDUSTRIES
> strhelp  = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_INDUSTRIES_HELPTEXT
> 
> [SDTC_BOOL]
> var      = gui.cm_land_tooltips_for_stations
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = true
> str      = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_STATIONS
> strhelp  = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_STATIONS_HELPTEXT
> 
> [SDTC_BOOL]
> var      = gui.cm_land_tooltips_for_houses
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_HOUSES
> strhelp  = STR_CM_CONFIG_SETTING_LAND_TOOLTIPS_FOR_HOUSES_HELPTEXT
> 
> [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
> 
> [SDTC_VAR]
> var      = gui.cm_fn_mod
> type     = SLE_UINT8
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> guiflags = SGF_MULTISTRING
> def      = 2
> min      = 0
> max      = 3
> str      = STR_CM_CONFIG_SETTING_MODIFIER_FN
> strhelp  = STR_CM_CONFIG_SETTING_MODIFIER_FN_HELPTEXT
> strval   = STR_CM_CONFIG_SETTING_MODIFIER_NONE
> cat      = SC_ADVANCED
> 
> [SDTC_VAR]
> var      = gui.cm_remove_mod
> type     = SLE_UINT8
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> guiflags = SGF_MULTISTRING
> def      = 2
> min      = 0
> max      = 3
> str      = STR_CM_CONFIG_SETTING_MODIFIER_REMOVE
> strhelp  = STR_CM_CONFIG_SETTING_MODIFIER_REMOVE_HELPTEXT
> strval   = STR_CM_CONFIG_SETTING_MODIFIER_NONE
> cat      = SC_ADVANCED
> 
> [SDTC_VAR]
> var      = gui.cm_estimate_mod
> type     = SLE_UINT8
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> guiflags = SGF_MULTISTRING
> def      = 1
> min      = 0
> max      = 3
> str      = STR_CM_CONFIG_SETTING_MODIFIER_ESTIMATE
> strhelp  = STR_CM_CONFIG_SETTING_MODIFIER_ESTIMATE_HELPTEXT
> strval   = STR_CM_CONFIG_SETTING_MODIFIER_NONE
> cat      = SC_ADVANCED
> 
> [SDTC_VAR]
> var      = gui.cm_shaded_trees
> type     = SLE_UINT8
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> guiflags = SGF_MULTISTRING
> def      = 2
> min      = 0
> max      = 2
> str      = STR_CM_CONFIG_SETTING_SHADED_TREES
> strhelp  = STR_CM_CONFIG_SETTING_SHADED_TREES_HELPTEXT
> strval   = STR_CM_CONFIG_SETTING_SHADED_TREES_OFF
> cat      = SC_ADVANCED
> proc     = RedrawScreen
> 
> [SDTC_BOOL]
> var      = gui.cm_show_apm
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> def      = false
> str      = STR_CM_CONFIG_SETTING_SHOW_APM
> strhelp  = STR_CM_CONFIG_SETTING_SHOW_APM_HELPTEXT
> cat      = SC_ADVANCED
> proc     = cm_v_RedrawStatusBar
> 
> [SDTC_VAR]
> var      = gui.cm_graph_background
> type     = SLE_UINT8
> flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
> guiflags = SGF_MULTISTRING
> def      = 0
> min      = 0
> max      = 1
> str      = STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND
> strhelp  = STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND_HELPTEXT
> strval   = STR_CM_CONFIG_SETTING_GRAPH_BACKGROUND_BLACK
> cat      = SC_ADVANCED
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/table/sprites.h cmclient/src/table/sprites.h
305a306,346
> /* 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_IMG_HOUSE_NEW             = SPR_INNER_HIGHLIGHT_BASE + 21;
> static const SpriteID SPR_PALETTE_ZONING_RED        = SPR_INNER_HIGHLIGHT_BASE + 22;
> static const SpriteID SPR_PALETTE_ZONING_GREEN      = SPR_INNER_HIGHLIGHT_BASE + 23;
> static const SpriteID SPR_PALETTE_ZONING_BLACK      = SPR_INNER_HIGHLIGHT_BASE + 24;
> static const SpriteID SPR_PALETTE_ZONING_LIGHT_BLUE = SPR_INNER_HIGHLIGHT_BASE + 25;
> static const SpriteID SPR_PALETTE_ZONING_ORANGE     = SPR_INNER_HIGHLIGHT_BASE + 26;
> static const SpriteID SPR_PALETTE_ZONING_WHITE      = SPR_INNER_HIGHLIGHT_BASE + 27;
> static const SpriteID SPR_PALETTE_ZONING_YELLOW     = SPR_INNER_HIGHLIGHT_BASE + 28;
> static const SpriteID SPR_PALETTE_ZONING_PURPLE     = SPR_INNER_HIGHLIGHT_BASE + 29;
> static const SpriteID SPR_INNER_HIGHLIGHT_COUNT     = 30;
> 
> static const SpriteID SPR_BORDER_HIGHLIGHT_BASE     = SPR_INNER_HIGHLIGHT_BASE + SPR_INNER_HIGHLIGHT_COUNT + 1;
> static const SpriteID SPR_BORDER_HIGHLIGHT_COUNT    = 19 * 19;
> static const SpriteID PALETTE_TINT_BASE             = SPR_BORDER_HIGHLIGHT_BASE + SPR_BORDER_HIGHLIGHT_COUNT;
> static const SpriteID PALETTE_TINT_RED_DEEP         = PALETTE_TINT_BASE;
> static const SpriteID PALETTE_TINT_ORANGE_DEEP      = PALETTE_TINT_BASE + 1;
> static const SpriteID PALETTE_TINT_GREEN_DEEP       = PALETTE_TINT_BASE + 2;
> static const SpriteID PALETTE_TINT_CYAN_DEEP        = PALETTE_TINT_BASE + 3;
> static const SpriteID PALETTE_TINT_RED              = PALETTE_TINT_BASE + 4;
> static const SpriteID PALETTE_TINT_ORANGE           = PALETTE_TINT_BASE + 5;
> static const SpriteID PALETTE_TINT_YELLOW           = PALETTE_TINT_BASE + 6;
> static const SpriteID PALETTE_TINT_YELLOW_WHITE     = PALETTE_TINT_BASE + 7;
> static const SpriteID PALETTE_TINT_WHITE            = PALETTE_TINT_BASE + 8;
> static const SpriteID PALETTE_TINT_GREEN            = PALETTE_TINT_BASE + 9;
> static const SpriteID PALETTE_TINT_CYAN             = PALETTE_TINT_BASE + 10;
> static const SpriteID PALETTE_TINT_CYAN_WHITE       = PALETTE_TINT_BASE + 11;
> static const SpriteID PALETTE_TINT_BLUE             = PALETTE_TINT_BASE + 12;
> static const SpriteID PALETTE_SHADE_N              = PALETTE_TINT_BASE + 13;
> static const SpriteID PALETTE_SHADE_NE               = PALETTE_TINT_BASE + 14;
> static const SpriteID PALETTE_SHADE_E               = PALETTE_TINT_BASE + 15;
> static const SpriteID PALETTE_SHADE_SE               = PALETTE_TINT_BASE + 16;
> static const SpriteID PALETTE_SHADE_S               = PALETTE_TINT_BASE + 17;
> static const SpriteID PALETTE_SHADE_SW               = PALETTE_TINT_BASE + 18;
> static const SpriteID PALETTE_SHADE_W               = PALETTE_TINT_BASE + 19;
> static const SpriteID PALETTE_SHADE_NW               = PALETTE_TINT_BASE + 20;
> static const SpriteID PALETTE_TINT_COUNT            = 13 + 8;
> 
307c348
< static const SpriteID SPR_NEWGRFS_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT;
---
> static const SpriteID SPR_NEWGRFS_BASE = PALETTE_TINT_BASE + PALETTE_TINT_COUNT;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/terraform_gui.cpp cmclient/src/terraform_gui.cpp
38a39,40
> #include "citymania/cm_hotkeys.hpp"
> 
61c63
< 		SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_NORMAL : TROPICZONE_DESERT);
---
> 		SetTropicZone(tile, citymania::_fn_mod ? TROPICZONE_NORMAL : TROPICZONE_DESERT);
117c119,176
< 			DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
---
> 			DoCommandP(end_tile, start_tile, citymania::_fn_mod ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
> 			break;
> 		case DDSP_DEMOLISH_TREES:
> 			// loop through every tile and send a demolish command for each tree
> 			// orthogonal area
> 			TileIndex tree_start_tile, tree_recent_tile, prev_tile;
> 			tree_start_tile = tree_recent_tile = prev_tile = 0;
> 			if (!citymania::_fn_mod) {
> 				OrthogonalTileArea square_area = OrthogonalTileArea(start_tile, end_tile);
> 				TILE_AREA_LOOP(curr_tile, square_area) {
> 					// if we're on a non-consecutive tile or we've hit a black-marked tile
> 					// safe tiles are: TREES or non-FIELD clear tiles (because they're expensive to demolish)
> 					if (tree_start_tile != 0 &&
> 							(curr_tile != prev_tile + 1 ||
> 							(!IsTileType(curr_tile, MP_TREES) && (!IsTileType(curr_tile, MP_CLEAR) || IsClearGround(curr_tile, CLEAR_FIELDS))))) {
> 						DoCommandP(tree_start_tile, tree_recent_tile, 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
> 						tree_start_tile = tree_recent_tile = 0;
> 					}
> 					// if current tile is a tree
> 					if (IsTileType(curr_tile, MP_TREES)) {
> 						if (tree_start_tile == 0) {
> 							tree_start_tile = curr_tile;
> 						}
> 						tree_recent_tile = curr_tile;
> 					}
> 					prev_tile = curr_tile;
> 				}
> 				// one last ride to flavortown
> 				if (tree_start_tile != 0) {
> 					DoCommandP(tree_start_tile, tree_recent_tile, 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
> 				}
> 			} else {  // diagonal area
> 				DiagonalTileArea diagonal_area = DiagonalTileArea(start_tile, end_tile);
> 				DIAGONAL_TILE_AREA_LOOP(curr_tile, diagonal_area) {
> 					// same as above but with a different criteria for consecutive tiles
> 					TileIndexDiffC tile_diff = TileIndexToTileIndexDiffC(curr_tile, prev_tile);
> 					// if we're on a non-consecutive tile or we've hit a black-marked tile
> 					// safe tiles are: TREES or non-FIELD clear tiles (because they're expensive to demolish)
> 					if (tree_start_tile != 0 &&
> 							(!((tile_diff.x == 1 && tile_diff.y == 1) || (tile_diff.x == -1 && tile_diff.y == -1)) ||
> 							(!IsTileType(curr_tile, MP_TREES) && (!IsTileType(curr_tile, MP_CLEAR) || IsClearGround(curr_tile, CLEAR_FIELDS))))) {
> 						DoCommandP(tree_start_tile, tree_recent_tile, 1, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
> 						tree_start_tile = tree_recent_tile = 0;
> 					}
> 					// if current tile is a tree
> 					if (IsTileType(curr_tile, MP_TREES)) {
> 						if (tree_start_tile == 0) {
> 							tree_start_tile = curr_tile;
> 						}
> 						tree_recent_tile = curr_tile;
> 					}
> 					prev_tile = curr_tile;
> 				}
> 				// one last ride to flavortown
> 				if (tree_start_tile != 0) {
> 					DoCommandP(tree_start_tile, tree_recent_tile, 1, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound_EXPLOSION);
> 				}
> 			}
120c179
< 			DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform);
---
> 			DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (citymania::_fn_mod ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform);
123c182
< 			DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform);
---
> 			DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (citymania::_fn_mod ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform);
126c185
< 			DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform);
---
> 			DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (citymania::_fn_mod ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform);
165a225,248
> 	void DrawWidget(const Rect &r, int widget) const override
> 	{
> 		if (widget == WID_TT_DEMOLISH_TREES) {
> 			uint offset = this->IsWidgetLowered(WID_TT_DEMOLISH_TREES) ? 1 : 0;
> 			ZoomLevel temp_zoom;
> 			switch (_gui_zoom) {
> 				case ZOOM_LVL_NORMAL:
> 					temp_zoom = ZOOM_LVL_OUT_2X;
> 					break;
> 				case ZOOM_LVL_OUT_2X:
> 					temp_zoom = ZOOM_LVL_OUT_4X;
> 					break;
> 				case ZOOM_LVL_OUT_4X:
> 					temp_zoom = ZOOM_LVL_OUT_8X;
> 					break;
> 				default:
> 					temp_zoom = ZOOM_LVL_OUT_8X;
> 					break;
> 			}
> 			Dimension d = GetSpriteSize(SPR_IMG_PLANTTREES, (Point *)0, temp_zoom);
> 			DrawSprite(SPR_IMG_PLANTTREES, PAL_NONE, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset, nullptr, temp_zoom);
> 		}
> 	}
> 
179c262
< 				HandlePlacePushButton(this, WID_TT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_TT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT | HT_DIAGONAL, CM_DDSP_TERRAFORM);
184c267
< 				HandlePlacePushButton(this, WID_TT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_TT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT | HT_DIAGONAL, CM_DDSP_TERRAFORM);
189c272
< 				HandlePlacePushButton(this, WID_TT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_TT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL, CM_DDSP_TERRAFORM);
194c277,282
< 				HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
> 				this->last_user_action = widget;
> 				break;
> 
> 			case WID_TT_DEMOLISH_TREES: // Demolish aka dynamite button
> 				HandlePlacePushButton(this, WID_TT_DEMOLISH_TREES, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH_TREES);
199c287
< 				HandlePlacePushButton(this, WID_TT_BUY_LAND, SPR_CURSOR_BUY_LAND, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_TT_BUY_LAND, SPR_CURSOR_BUY_LAND, HT_RECT, CM_DDSP_BUY_LAND);
208c296
< 				HandlePlacePushButton(this, WID_TT_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_TT_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT, CM_DDSP_PLACE_SIGN);
238a327,330
> 			case WID_TT_DEMOLISH_TREES: // Demolish trees only
> 				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_TREES);
> 				break;
> 
268a361
> 				case DDSP_DEMOLISH_TREES:
303a397
> 	Hotkey('D' | WKC_CTRL | WKC_GLOBAL_HOTKEY, "treedozer", WID_TT_DEMOLISH_TREES),
329a424,425
>         NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_DEMOLISH_TREES), SetMinimalSize(22, 22),
> 								SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_TREES),
577c673
< 				HandlePlacePushButton(this, WID_ETT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_ETT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL, CM_DDSP_DEMOLISH);
582c678
< 				HandlePlacePushButton(this, WID_ETT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT);
---
> 				HandlePlacePushButton(this, WID_ETT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT, CM_DDSP_TERRAFORM);
587c683
< 				HandlePlacePushButton(this, WID_ETT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT);
---
> 				HandlePlacePushButton(this, WID_ETT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT, CM_DDSP_TERRAFORM);
592c688
< 				HandlePlacePushButton(this, WID_ETT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL);
---
> 				HandlePlacePushButton(this, WID_ETT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL, CM_DDSP_TERRAFORM);
597c693
< 				HandlePlacePushButton(this, WID_ETT_PLACE_ROCKS, SPR_CURSOR_ROCKY_AREA, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ETT_PLACE_ROCKS, SPR_CURSOR_ROCKY_AREA, HT_RECT, CM_DDSP_TERRAFORM);
602c698
< 				HandlePlacePushButton(this, WID_ETT_PLACE_DESERT, SPR_CURSOR_DESERT, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_ETT_PLACE_DESERT, SPR_CURSOR_DESERT, HT_RECT, CM_DDSP_TERRAFORM);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tilearea_type.h cmclient/src/tilearea_type.h
233a234,235
> #define DIAGONAL_TILE_AREA_LOOP(var, ta) for (DiagonalTileIterator var(ta); var != INVALID_TILE; ++var)
> 
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tile_cmd.h cmclient/src/tile_cmd.h
64a65
> 	uint16 population;          ///< CM
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tilehighlight_func.h cmclient/src/tilehighlight_func.h
13a14
> #include "tilearea_type.h"
14a16,17
> #include "track_type.h"
> #include "industry_type.h"
19,21c22,24
< bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode);
< void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w);
< void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num);
---
> bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode, ViewportDragDropSelectionProcess cm_process);
> void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w, ViewportDragDropSelectionProcess cm_process);
> void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num, ViewportDragDropSelectionProcess cm_process);
30a34,40
> 
> RailSnapMode GetRailSnapMode();
> void SetRailSnapMode(RailSnapMode mode);
> 
> void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional = true);
> void StoreRailStationPlacementEndpoints(const TileArea &ta, Axis station_axis);
> void ResetRailPlacementEndpoints();
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tilehighlight_type.h cmclient/src/tilehighlight_type.h
12a13,14
> #include "citymania/cm_highlight_type.hpp"
> 
28a31
> 	HT_POLY      = 0x400, ///< polyline mode; connect highlighted track with previous one
40a44
> 	CM_HT_DIR_AUTO = 4,
43a48,53
> /** Methods of rail track snapping. */
> enum RailSnapMode {
> 	RSM_NO_SNAP,      ///< Not snapping.
> 	RSM_SNAP_TO_TILE, ///< Snap to a tile.
> 	RSM_SNAP_TO_RAIL, ///< Snap to other rail tracks.
> };
56a67
> 	Point new_offs;      ///< New value for \a offs; used to determine whether to redraw the selection.
61a73,75
> 	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.
75a90,92
> 
> 	citymania::ObjectHighlight cm;
> 	citymania::ObjectHighlight cm_new;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/timetable_gui.cpp cmclient/src/timetable_gui.cpp
30a31,32
> #include "citymania/cm_hotkeys.hpp"
> 
532c534
< 				ShowSetDateWindow(this, v->index | (v->orders.list->IsCompleteTimetable() && _ctrl_pressed ? 1U << 20 : 0), _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback);
---
> 				ShowSetDateWindow(this, v->index | (v->orders.list->IsCompleteTimetable() && citymania::_fn_mod ? 1U << 20 : 0), _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback);
598c600
< 				if (_ctrl_pressed) SetBit(p2, 1);
---
> 				if (citymania::_fn_mod) SetBit(p2, 1);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/toolbar_gui.cpp cmclient/src/toolbar_gui.cpp
57a58,66
> #include "object_type.h"
> 
> #include "citymania/cm_cargo_table_gui.hpp"
> #include "citymania/cm_commands_gui.hpp"
> #include "citymania/cm_locations.hpp"
> #include "citymania/cm_main.hpp"
> #include "citymania/cm_minimap.hpp"
> #include "citymania/cm_watch_gui.hpp"
> #include "citymania/cm_zoning.hpp"
80a90
> 	CBF_BUILD_HQ,
261c271
< 		SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
---
> 		SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0, CM_DDSP_PLACE_SIGN);
265a276,287
> /* hq hotkey */
> static CallBackFunction BuildCompanyHQ(){
> 	if (_last_started_action == CBF_BUILD_HQ) {
> 		ResetObjectToPlace();
> 		return CBF_NONE;
> 	} else {
> 		SetObjectToPlace(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0, CM_DDSP_BUILD_HQ);
> 		SetTileSelectSize(2, 2);
> 		return CBF_BUILD_HQ;
> 	}
> }
> 
299a322
> 	OME_ZONING,
327a351
> 	list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_ZONING,                   OME_ZONING, false));
357a382
> 		case OME_ZONING:               citymania::ShowZoningToolbar();                  break;
496c521
< 		case MME_SHOW_SMALLMAP:          ShowSmallMap();            break;
---
> 		case MME_SHOW_SMALLMAP:          citymania::ShowSmallMap();            break;
592a618,648
> /* --- CARGOS button menu --- */
> 
> static CallBackFunction ToolbarCargosClick(Window *w)
> {
> 	PopupMainCompanyToolbMenu(w, WID_TN_CARGOS);
> 	return CBF_NONE;
> }
> 
> static CallBackFunction MenuClickCargos(int index)
> {
> 	citymania::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)){
> 		citymania::ShowWatchWindow((CompanyID)index, 0);
> 	}
> 	else citymania::ShowWatchWindow(INVALID_COMPANY, 0);
> 	return CBF_NONE;
> }
> 
736c792,794
< 	PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
---
> 	// CM don't disable
> 	// 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);
1062c1120
< 		SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
---
> 		SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0, CM_DDSP_LAND_INFO);
1069c1127
< 	PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 10 : 7);
---
> 	PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 11 : 8);
1129,1136c1187,1196
< 		case  2: IConsoleSwitch();                 break;
< 		case  3: ShowAIDebugWindow();              break;
< 		case  4: ShowScreenshotWindow();           break;
< 		case  5: ShowFramerateWindow();            break;
< 		case  6: ShowAboutWindow();                break;
< 		case  7: ShowSpriteAlignerWindow();        break;
< 		case  8: ToggleBoundingBoxes();            break;
< 		case  9: ToggleDirtyBlocks();              break;
---
> 		case  1: citymania::ShowCommandsToolbar(); break;
> 		case  2: citymania::ShowLoginWindow();     break;
> 		case  3: IConsoleSwitch();                 break;
> 		case  4: ShowAIDebugWindow();              break;
> 		case  5: ShowScreenshotWindow();           break;
> 		case  6: ShowFramerateWindow();            break;
> 		case  7: ShowAboutWindow();                break;
> 		case  8: ShowSpriteAlignerWindow();        break;
> 		case  9: ToggleBoundingBoxes();            break;
> 		case 10: ToggleDirtyBlocks();              break;
1301a1362
> 	MenuClickCargos,      // 8.5
1304a1366
> 	MenuClickWatch,       // 11.5
1763a1826
> 			WID_TN_CARGOS,
1766a1830
> 			WID_TN_WATCH,
1934a1999
> 	ToolbarCargosClick,
1937a2003
> 	ToolbarWatchClick,
1999a2066,2075
> 	CM_MTHK_BUILD_HQ,
> 	CM_MTHK_COMMANDS_GUI,
> 	CM_MTHK_CARGOTABLE,
> 	CM_MTHK_TREES,
> 	CM_MTHK_ZONING,
> 	CM_MTHK_LOGINWINDOW,
> 	CM_MTHK_SETTINGS_ADV,
> 	CM_MTHK_NEWGRF,
>     CM_MTHK_SMALLMAP_TOGGLE,
>     CM_LOCATION_HOTKEYS,
2032c2108
< 		this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFT, 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_AIRCRAFT, WIDGET_LIST_END);
2039a2116,2123
> 	void DrawWidget(const Rect &r, int widget) const override {
> 		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);
> 		}
> 	}
> 
2060c2144
< 			case MTHK_SMALLMAP: ShowSmallMap(); break;
---
> 			case MTHK_SMALLMAP: citymania::ShowSmallMap(); break;
2089c2173
< 			case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
---
> 			case MTHK_CHEATS: ShowCheatWindow(); break;
2095c2179,2188
< 			default: return ES_NOT_HANDLED;
---
> 			case CM_MTHK_COMMANDS_GUI: if (_networking) { citymania::ShowCommandsToolbar(); } break;
> 			case CM_MTHK_BUILD_HQ: if(_current_company != COMPANY_SPECTATOR){ cbf = BuildCompanyHQ(); } break;
> 			case CM_MTHK_CARGOTABLE: if(_current_company != COMPANY_SPECTATOR){ citymania::ShowCompanyCargos(_current_company); } break;
> 			case CM_MTHK_TREES: if(_current_company != COMPANY_SPECTATOR){ BuildTreesWindow(); } break;
> 			case CM_MTHK_ZONING: citymania::ShowZoningToolbar(); break;
> 			case CM_MTHK_LOGINWINDOW: citymania::ShowLoginWindow(); break;
> 			case CM_MTHK_SETTINGS_ADV: ShowGameSettings(); break;
> 			case CM_MTHK_NEWGRF: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); break;
> 			case CM_MTHK_SMALLMAP_TOGGLE: citymania::ToggleSmallMap(); break;
> 			default: return citymania::HandleToolbarHotkey(hotkey);
2100a2194,2211
> 	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);*/
> 	}
> 
2109c2220,2227
< 				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();
> 				}
2120a2239,2244
> 	void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
> 	{
> 		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
> 	}
> 
> 
2208a2333,2342
> 	Hotkey(WKC_CTRL  | 'H', "build_hq", CM_MTHK_BUILD_HQ),
> 	Hotkey('N', "nova_commands", CM_MTHK_COMMANDS_GUI),
> 	Hotkey(WKC_CTRL | WKC_F2, "cargo_table", CM_MTHK_CARGOTABLE),
> 	Hotkey('I', "trees", CM_MTHK_TREES),
> 	Hotkey((uint16)0, "zoning", CM_MTHK_ZONING),
> 	Hotkey((uint16)0, "login_window", CM_MTHK_LOGINWINDOW),
> 	Hotkey((uint16)0, "settings_advanced", CM_MTHK_SETTINGS_ADV),
> 	Hotkey((uint16)0, "newgrf_window", CM_MTHK_NEWGRF),
> 	Hotkey((uint16)0, "cm_smallmap_toggle", CM_MTHK_SMALLMAP_TOGGLE),
> 	CM_LOCATION_HOTKEYS_DECL,
2225a2360
> 		SPR_IMG_COMPANY_CARGO,   // WID_TN_CARGOS
2228a2364
> 		0,                       // WID_TN_WATCH
2359a2496
> 	CM_MTEHK_SMALLMAP_TOGGLE,
2467c2604
< 			case MTEHK_SMALLMAP:               ShowSmallMap(); break;
---
> 			case MTEHK_SMALLMAP:               citymania::ShowSmallMap(); break;
2468a2606
> 			case CM_MTEHK_SMALLMAP_TOGGLE:     citymania::ToggleSmallMap(); break;
2483c2621
< 				ShowLandInfo(tile);
---
> 				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_MEASURE);
2572a2711
> 	Hotkey((uint16)0, "cm_smallmap_toggle", CM_MTEHK_SMALLMAP_TOGGLE),
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/town_cmd.cpp cmclient/src/town_cmd.cpp
54a55,57
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_main.hpp"
> 
56a60,72
> 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
> 
> 
> namespace citymania {
> 	extern TileIndex _closest_cache_ref;
> }
> 
199a216,235
>  /**
>  * 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
> 	}
> }
> 
226c262
< static bool BuildTownHouse(Town *t, TileIndex tile);
---
> static bool BuildTownHouse(Town *t, TileIndex tile, bool is_rebuilding = false);
396a433
> 	this->UpdateLabel();
409a447
> 	SetWindowDirty(WC_CB_TOWN, this->index);
495c534,537
< 		ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population);
---
> 		HouseID house_id = GetHouseType(tile);
> 		auto hs = HouseSpec::Get(house_id);
> 		Town *town = Town::GetByTile(tile);
> 		ChangePopulation(Town::GetByTile(tile), hs->population);
496a539,541
> 
> 		if (hs->building_flags & BUILDING_HAS_1_TILE)
> 			citymania::Emit(citymania::event::HouseCompleted{town, tile, house_id, hs});
630a676
> 		bool rebuild_res = false;
651c697
< 			BuildTownHouse(t, tile);
---
> 			rebuild_res = BuildTownHouse(t, tile);
652a699
> 		citymania::Emit(citymania::event::HouseRebuilt{t, tile, rebuild_res});
680a728
> 		citymania::Emit(citymania::event::HouseDestroyed{_current_company, t, tile});
769a818
> 	td->population = hs->population;
808a858,955
> bool TownNeedsFunding(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 false;
> 
> 
> 	bool is_growing = HasBit(t->flags, TOWN_IS_GROWING);
> 
> 	if (HasBit(t->flags, TOWN_CUSTOM_GROWTH)) {
> 		if (!is_growing)
> 			return false;
> 
> 		if (do_powerfund && t->grow_counter > 2 * TOWN_GROWTH_TICKS)
> 			return true;
> 
> 		return (fund_regularly &&
> 		        t->fund_buildings_months == 0 && (
> 			     	t->growth_rate <= 2 * TOWN_GROWTH_TICKS ||
>                 	t->grow_counter > 2 * TOWN_GROWTH_TICKS
>                 ));
> 	}
> 
> 	if (!is_growing)
> 		return true;
> 
> 	if (do_powerfund && t->grow_counter > 2 * TOWN_GROWTH_TICKS)
> 		return true;
> 
> 	return (fund_regularly &&
> 	        t->fund_buildings_months == 0 &&
> 		    t->growth_rate >= TOWN_GROWTH_TICKS && (
> 		    	t->growth_rate <= 2 * TOWN_GROWTH_TICKS ||
>             	t->grow_counter > 2 * TOWN_GROWTH_TICKS
>             ));
> }
> 
> static void DoRegularFunding(Town *t)
> {
> 	if (_local_company == COMPANY_SPECTATOR)
> 		return;
> 
> 	if (!TownNeedsFunding(t))
> 		return;
> 
> 	/* never fund faster than every TOWN_GROWTH_TICKS */
> 	if (_tick_counter < t->last_funding) {
> 		if (UINT32_MAX - t->last_funding + _tick_counter < TOWN_GROWTH_TICKS) return;
> 	} else if (_tick_counter - t->last_funding < TOWN_GROWTH_TICKS) return;
> 
> 	CompanyID old = _current_company;
> 	_current_company = _local_company;
> 	DoCommandP(t->xy, t->index, HK_FUND, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE);
> 	t->last_funding = _tick_counter;
> 	_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
> 		for (Station *st : Station::Iterate()) {
> 			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;
> 
> 	// don't advertise faster that once per 30 ticks
> 	if (_tick_counter < t->last_advertisement) {
> 		if (UINT32_MAX - t->last_advertisement + _tick_counter < 30) return;
> 	} else if (_tick_counter - t->last_advertisement < 30) return;
> 	t->last_advertisement = _tick_counter;
> 
>     CompanyID old = _current_company;
>     _current_company = _local_company;
>     DoCommandP(t->xy, t->index, HK_LADVERT, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE);
>     _current_company = old;
> }
> 
822a970,971
> 	DoRegularFunding(t);
> 	DoRegularAdvertising(t);
1620a1770
> 	uint16 prev_houses = t->cache.num_houses;
1626c1776,1779
< 		if (_grow_town_result == GROWTH_SUCCEED) return true;
---
> 		if (_grow_town_result == GROWTH_SUCCEED) {
> 			citymania::Emit(citymania::event::TownGrowthSucceeded{t, tile, prev_houses});
> 			return true;
> 		}
1631c1784,1787
< 		if (cur_rb == ROAD_NONE) return false;
---
> 		if (cur_rb == ROAD_NONE) {
> 			citymania::Emit(citymania::event::TownGrowthFailed{t, tile});
> 			return false;
> 		}
1640c1796,1799
< 				if (cur_rb == ROAD_NONE) return false;
---
> 				if (cur_rb == ROAD_NONE) {
> 					citymania::Emit(citymania::event::TownGrowthFailed{t, tile});
> 					return false;
> 				}
1653a1813
> 				citymania::Emit(citymania::event::TownGrowthFailed{t, tile});
1665a1826
> 	citymania::Emit(citymania::event::TownGrowthFailed{t, tile});
1734a1896
> 					citymania::Emit(citymania::event::TownGrowthSucceeded{t, tile, t->cache.num_houses});
1742a1905
> 	citymania::Emit(citymania::event::TownGrowthFailed{t, tile});
1747a1911
> 	auto prev_tz0 = t->cache.squared_town_zone_radius[0];
1786a1951,1952
>   	if (!_generating_world)
> 		citymania::UpdateTownZoning(t, prev_tz0);
1797a1964,2071
> //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
> 
1837a2112,2126
> 	//CB
> 	t->cb.growth_state = TownGrowthState::NOT_GROWING;
> 	for (uint i = 0; i < NUM_CARGO ; i++) {
> 		t->cb.stored[i] = 0;
> 		t->cb.delivered[i] = 0;
> 		t->cb.required[i] = 0;
> 		t->cb.delivered_last_month[i] = 0;
> 		t->cb.required_last_month[i] = 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
1852a2142
> 	t->town_label = 3;
1873a2164
> 	citymania::_closest_cache_ref = INVALID_TILE;
1877a2169
> 	citymania::Emit(citymania::event::TownBuilt{t});
2510c2802
< static bool BuildTownHouse(Town *t, TileIndex tile)
---
> static bool BuildTownHouse(Town *t, TileIndex tile, bool is_rebuilding)
2634a2927
> 		bool completed = false;
2642a2936
> 				completed = true;
2647a2942,2943
> 		citymania::UpdateZoningTownHouses(t, t->cache.num_houses - 1);
> 
2651a2948,2952
> 		if (!_generating_world) {
> 			citymania::Emit(citymania::event::HouseBuilt{t, tile, house, hs, is_rebuilding});
> 			if (completed) citymania::Emit(citymania::event::HouseCompleted{t, tile, house, hs});
> 		}
> 
2713c3014,3015
< 	if (IsHouseCompleted(tile)) {
---
> 	bool is_completed = IsHouseCompleted(tile);
> 	if (is_completed) {
2734a3037,3039
> 	citymania::UpdateZoningTownHouses(t, t->cache.num_houses + 1);
> 
> 	citymania::Emit(citymania::event::HouseCleared{t, tile, house, hs, is_completed});
2882a3188
> 		InvalidateWindowData(WC_CB_TOWN, p1);
3218a3525
> 		SetWindowDirty(WC_CB_TOWN, t->index);
3273a3581
> 				t->UpdateVirtCoord();
3416a3725
> 	t->UpdateVirtCoord();
3504a3814,3815
> 	SetWindowDirty(WC_CB_TOWN, t->index);
> 	t->cm.growing_by_chance = false;
3527a3839
> 		SetWindowDirty(WC_CB_TOWN, t->index);
3531c3843,3846
< 	if (t->fund_buildings_months == 0 && CountActiveStations(t) == 0 && !Chance16(1, 12)) return;
---
> 	if (t->fund_buildings_months == 0 && CountActiveStations(t) == 0) {
> 		if(!Chance16(1, 12)) return;
> 		t->cm.growing_by_chance = true;
> 	}
3534a3850
> 	SetWindowDirty(WC_CB_TOWN, t->index);
3543a3860
> 	SetWindowDirty(WC_CB_TOWN, t->index);
3702a4020
> 		t->UpdateVirtCoord();
3752a4071,4072
> 		if (CB_Enabled() && !t->larger_town) CB_UpdateTownStorage(t); //CB
> 
3756a4077,4078
> 
> 		DoRegularFunding(t);
3825a4148,4151
> }
> 
> namespace citymania {
> 	auto UpdateTownGrowthRate = &::UpdateTownGrowthRate;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/town_gui.cpp cmclient/src/town_gui.cpp
39a40,48
> /* CityMania start */
> #include "goal_base.h"
> #include "hotkeys.h"
> #include <list>
> #include "console_func.h"
> 
> #include "citymania/cm_hotkeys.hpp"
> /* CityMania end */
> 
41a51,64
> 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;
> }
> 
169a193
> 				SetDParam(3, this->town->ratings[c->index]);
174c198
< 				DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING);
---
> 				DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING_NUM);
298a323,339
> 
> 	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
299a341
> HotkeyList TownAuthorityWindow::hotkeys("town_gui", town_hotkeys);
305c347,348
< 	_nested_town_authority_widgets, lengthof(_nested_town_authority_widgets)
---
> 	_nested_town_authority_widgets, lengthof(_nested_town_authority_widgets),
> 	&TownAuthorityWindow::hotkeys
312a356,358
> // static int TownTicksToDays(int ticks) {
> //  	return (ticks * TOWN_GROWTH_TICKS + DAY_TICKS / 2) / DAY_TICKS;
> // }
320a367
> 	bool wcb_disable;
336a384
> 		this->SetWidgetDisabledState(WID_TV_CB, _game_mode == GM_EDITOR);
346c394,405
< 		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();
376a436,437
> 		DrawExtraTownInfo(r, y, this->town, FONT_HEIGHT_NORMAL, true); //CB
> 
447c508
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
479a541,545
> 			case WID_TV_CB:
> 				// if(_networking)
> 				ShowCBTownWindow(this->window_number);
> 				break;
> 
491a558,560
> 			// case WID_TV_CB:
> 				// if(this->wcb_disable || !CB_Enabled()) size->width = 0;
> 				// break;
501c570
< 		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;
564a634,653
> 
> 	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
565a655
> HotkeyList TownViewWindow::hotkeys("town_window", town_window_hotkeys);
585a676
> 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0),
594c685,686
< 	_nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets)
---
> 	_nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets),
> 	&TownViewWindow::hotkeys
616a709
> 		NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0),
640c733
< 		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),
720a814,831
> 	/** Sort by real population (default descending, as big towns are of the most interest). */
> 	static bool TownRealPopulationSorter(const Town * const &a, const Town * const &b)
> 	{
> 		uint32 a_population = a->cm.real_population;
> 		uint32 b_population = b->cm.real_population;
> 		if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b);
> 		return a_population < b_population;
> 	}
> 
> 	/** Sort by number of houses (default descending, as big towns are of the most interest). */
> 	static bool 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;
> 	}
> 
770a882,892
> 			case TDW_CAPTION_TEXT: {
> 				uint16 town_number = 0;
> 				uint16 city_number = 0;
> 				for (Town *t : Town::Iterate()) {
> 					if(t->larger_town) city_number++;
> 					town_number++;
> 				}
> 				SetDParam(0, city_number);
> 				SetDParam(1, town_number);
> 				break;
> 			}
822c944,947
< 					DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, GetTownString(t));
---
> 					SetDParam(2, t->cm.real_population);
> 					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);
861c986,987
< 					d = maxdim(d, GetStringBoundingBox(GetTownString(t)));
---
> 					SetDParamMaxDigits(2, 5);
> 					d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN_COLOUR));
911c1037
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
985a1112,1113
> 	STR_SORT_BY_REAL_POPULATION,
> 	STR_SORT_BY_HOUSES,
993a1122,1123
> 	&TownRealPopulationSorter,
> 	&TownHousesSorter,
1168c1298
< 		if (success && !_shift_pressed) this->RandomTownName();
---
> 		if (success && !citymania::_estimate_mod) this->RandomTownName();
1175c1305
< 				HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT);
---
> 				HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT, CM_DDSP_NEW_TOWN);
1254a1385,1824
> }
> 
> //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->cm.real_population);
> 	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, town->growth_rate);
> 	SetDParam(1, HasBit(town->flags, TOWN_CUSTOM_GROWTH) ? STR_TOWN_VIEW_GROWTH_RATE_CUSTOM : STR_EMPTY);
> 	// SetDParam(2, town->grow_counter < 16000 ? TownTicksToDays(town->grow_counter + 1) : -1);
> 	SetDParam(2, town->grow_counter);
> 	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->cm.houses_constructing);
> 		SetDParam(1, town->cm.houses_reconstructed_last_month);
> 		SetDParam(2, town->cm.houses_demolished_last_month);
> 		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_HOUSE_STATE);
> 	}
> 
> 	///houses stats
> 	SetDParam(0, town->cm.hs_total);
> 	SetDParam(1, town->cm.hs_last_month);
> 	SetDParam(2, town->cm.cs_total);
> 	SetDParam(3, town->cm.cs_last_month);
> 	SetDParam(4, town->cm.hr_total);
> 	SetDParam(5, town->cm.hr_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;
> 
> 	enum CBTownWindowPlanes {
> 		CBTWP_MP_GOALS = 0,
> 		CBTWP_MP_CB,
> 	};
> 
> 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_CENTER_VIEW:
> 				if (citymania::_fn_mod) {
> 					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_CB_CAPTION){
> 			SetDParam(0, this->town->index);
> 		}
> 	}
> 
> 	const Company *GetCompany() const {
> 		for (Company *c : Company::Iterate()) {
> 			if (c->location_of_HQ != INVALID_TILE
> 			    	&& DistanceMax(c->location_of_HQ, this->town->xy) < 11)
> 				return c;
> 		}
> 		return nullptr;
> 	}
> 
> 	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) * 5;
> 				break;
> 			case WID_CB_GOALS: {
> 				uint desired_height = 0;
> 				auto company = GetCompany();
> 				if (company) {
> 					for(const Goal *g : Goal::Iterate()) {
> 						if (g->company == company->index) {
> 							desired_height++;
> 						}
> 					}
> 				}
> 				if (desired_height > 0)
> 					size->height = desired_height * (FONT_HEIGHT_NORMAL + EXP_LINESPACE) + EXP_TOPPADDING - EXP_LINESPACE;
> 				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 = 0;
> 				for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++){
> 					if(CB_GetReq(cargo) > 0) desired_height++;
> 				}
> 				if (desired_height > 0)
> 					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->cb.growth_state == TownGrowthState::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;
> 			}
> 			case WID_CB_GOALS: {
> 				auto company = GetCompany();
> 				if (!company) break;
> 				for(const Goal *g : Goal::Iterate()) {
> 					if (g->company != company->index)
> 						continue;
> 					SetDParamStr(0, g->text);
> 					DrawString(r.left + WD_FRAMERECT_LEFT,
> 					           r.right - WD_FRAMERECT_RIGHT,
> 					           y, STR_GOALS_TEXT);
> 					y += EXP_LINESPACE;
> 				}
> 				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 (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->cb.delivered[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->cb.stored[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->cb.delivered_last_month[cargos->Index()]);
> 							if (this->town->cache.population >= from){
> 								// if (this->town->delivered_enough[cargos->Index()]) {
> 									string_to_draw = (this->town->cb.delivered_last_month[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->cb.stored[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->cb.stored[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_RIGHT, 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 void OnPaint() {
> 		if (!this->IsShaded()) {
> 			int plane = CB_Enabled() ? CBTWP_MP_CB : CBTWP_MP_GOALS;
> 			NWidgetStacked *wi = this->GetWidget<NWidgetStacked>(WID_CB_SELECT_REQUIREMENTS);
> 			if (plane != wi->shown_plane) {
> 				wi->SetDisplayedPlane(plane);
> 				this->InvalidateData();
> 				return;
> 			}
> 		}
> 		this->DrawWidgets();
> 	}
> 
> 
> 	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_CB_CAPTION), SetDataTip(STR_TOWN_VIEW_CB_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
> 		NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_CB_CENTER_VIEW), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
> 		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(66, 0), SetResize(1, 0), SetFill(1, 0),
> 				NWidget(NWID_VERTICAL),
> 					NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
> 						NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_ADVERT),SetMinimalSize(33, 12),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(33, 12),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(33, 12),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(33, 12),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(33, 0), SetFill(1, 0),
>   						NWidget(NWID_SPACER), SetMinimalSize(2, 0),
> 						NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_CB_POWERFUND),SetMinimalSize(33, 12),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_SELECTION, INVALID_COLOUR, WID_CB_SELECT_REQUIREMENTS),
> 				NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_GOALS),SetMinimalSize(50 + 35 + 35 + 40 + 35 + 30, 0), SetResize(1, 0), SetFill(1, 0),
> 				NWidget(NWID_HORIZONTAL),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_NAME),SetMinimalSize(50, 0), SetResize(0, 0), SetFill(1, 0),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_AMOUNT),SetMinimalSize(35, 0), SetResize(1, 0), SetFill(0, 0),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_REQ),SetMinimalSize(35, 0), SetResize(1, 0), SetFill(0, 0),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_PREVIOUS),SetMinimalSize(40, 0),  SetResize(1, 0), SetFill(0, 0),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE),SetMinimalSize(35, 0), SetResize(1, 0), SetFill(0, 0),
> 					NWidget(WWT_EMPTY, COLOUR_BROWN, WID_CB_CARGO_STORE_PCT),SetMinimalSize(30, 0), SetResize(1, 0), SetFill(0, 0),
> 				EndContainer(),
> 			EndContainer(),
> 			NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetResize(1, 0), SetFill(1, 1),
> 		EndContainer(),
> 	EndContainer(),
> 	NWidget(NWID_HORIZONTAL),
> 		NWidget(NWID_HORIZONTAL),
> 			NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CB_TOWN_VIEW), SetMinimalSize(40, 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(40, 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", 160, 30,
> 	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 -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/town.h cmclient/src/town.h
15a16,19
> #include "station_base.h"
> #include "openttd.h"
> #include "table/strings.h"
> #include "company_func.h"
18a23,25
> #include <map>
> 
> #include "citymania/extensions/cmext_town.hpp"
48a56,77
> enum class TownGrowthState: uint8 {
>     NOT_GROWING = 0,
>     GROWING = 1,
>     SHRINKING = 2,
> };
> 
> struct CBTownInfo {
> 	uint32 pax_delivered;
> 	uint32 mail_delivered;
> 	uint32 pax_delivered_last_month;
> 	uint32 mail_delivered_last_month;
> 	TownGrowthState growth_state;
> 	uint8 shrink_effeciency;
> 	uint16 shrink_rate;
> 	uint16 shrink_counter;
> 	uint32 stored[NUM_CARGO];
> 	uint32 delivered[NUM_CARGO];
> 	uint32 required[NUM_CARGO];
> 	uint32 delivered_last_month[NUM_CARGO];
> 	uint32 required_last_month[NUM_CARGO];
> };
> 
78a108,117
> 	StringID town_label;                ///< Label dependent on _local_company rating.
> 	CBTownInfo cb;
> 	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)
> 	uint32 last_funding = 0;             ///< when town was funded the last time
> 	CompanyMask advertise_regularly;     ///< advertised regularly to keep stations rating on desired value
> 	uint32 last_advertisement = 0;
> 	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
> 
99a139,140
> 	citymania::ext::Town cm;
> 
110a152,177
> 	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;
> 		}
> 	}
> 
206a274,286
> 
> 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);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/train_cmd.cpp cmclient/src/train_cmd.cpp
3911c3911
< 	PerformanceAccumulator framerate(PFE_GL_TRAINS);
---
> //	PerformanceAccumulator framerate(PFE_GL_TRAINS);
4033a4034,4037
> }
> 
> namespace citymania {
> 	auto GetDefaultTrainSprite = &::GetDefaultTrainSprite;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/train_gui.cpp cmclient/src/train_gui.cpp
229c230,231
< 		DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE);
---
> 		if (_settings_client.gui.newgrf_developer_tools) SetDParam(2, v->index);  // CM
> 		DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE);
234c236,237
< 		DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE);
---
> 		if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index);  // CM
> 		DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/transparency_gui.cpp cmclient/src/transparency_gui.cpp
20a21,22
> #include "citymania/cm_hotkeys.hpp"
> 
73c75
< 			if (_ctrl_pressed) {
---
> 			if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tree_cmd.cpp cmclient/src/tree_cmd.cpp
29a30,31
> #include "citymania/cm_highlight.hpp"
> 
556a559,560
> 	PaletteID shade_pal = citymania::GetTreeShadePal(ti->tile);
> 
571c575
< 		AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y);
---
> 		AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal != PAL_NONE ? te[mi].pal : shade_pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/tree_gui.cpp cmclient/src/tree_gui.cpp
105c105
< 			SetObjectToPlace(SPR_CURSOR_TREE, PAL_NONE, HT_RECT, this->window_class, this->window_number);
---
> 			SetObjectToPlace(SPR_CURSOR_TREE, PAL_NONE, HT_RECT, this->window_class, this->window_number, DDSP_PLANT_TREES);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/vehicle_gui.cpp cmclient/src/vehicle_gui.cpp
38a39,41
> #include "hotkeys.h"
> 
> #include "citymania/cm_hotkeys.hpp"
985c988
< 					if (_ctrl_pressed) this->num_vehicles = UINT8_MAX;
---
> 					if (citymania::_fn_mod) this->num_vehicles = UINT8_MAX;
1008,1009c1011,1012
< 				if (!_ctrl_pressed) {
< 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
---
> 				if (!citymania::_fn_mod) {
> 					SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_SELECT_REFIT);
1824c1827
< 							if (_ctrl_pressed) {
---
> 							if (citymania::_fn_mod) {
1833c1836
< 					case GB_SHARED_ORDERS:
---
> 					case GB_SHARED_ORDERS: {
1834a1838
> 						const Vehicle *v = vehgroup.vehicles_begin[0];
1837c1841,1846
< 						ShowVehicleListWindow(vehgroup.vehicles_begin[0]);
---
> 						if (vehgroup.NumVehicles() == 1) {
> 							ShowVehicleViewWindow(v);
> 						}
> 						else {
> 							ShowVehicleListWindow(v);
> 						}
1838a1848
> 					}
1964c1974
< 	 * if _ctrl_pressed, do the opposite action (Advanced list x Normal list)
---
> 	 * if citymania::_fn_mod, do the opposite action (Advanced list x Normal list)
1967c1977
< 	if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) {
---
> 	if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != citymania::_fn_mod) {
2378c2388
< 				int mod = _ctrl_pressed ? 5 : 10;
---
> 				int mod = citymania::_fn_mod ? 5 : 10;
2506,2525d2515
< /** 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)
< );
< 
< 
2616a2607,2617
> void CcCloneVehicleWithOrderIndex(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
> {
> 	if (result.Failed()) return;
> 	if (p2 != 1) CcCloneVehicle(result, tile, p1, p2, cmd);
> 	Vehicle *cloned = Vehicle::GetIfValid(p1);
> 	if (!cloned || !cloned->IsPrimaryVehicle()) return;
> 	const Vehicle *v = Vehicle::Get(_new_vehicle_id);
> 	if (cloned->cur_implicit_order_index == v->cur_implicit_order_index) return;
> 	DoCommandP(v->tile, v->index, cloned->cur_implicit_order_index, CMD_SKIP_TO_ORDER);
> }
> 
2902c2903
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2911c2912
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2925c2926
< 				DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v));
---
> 				DoCommandP(v->tile, v->index | (citymania::_fn_mod ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v));
2931c2932
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2938c2939
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
2949c2950
< 				DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0,
---
> 				DoCommandP(v->tile, v->index, citymania::_fn_mod ? 1 : 0,
2951c2952
< 										_ctrl_pressed ? nullptr : CcCloneVehicle);
---
> 										CcCloneVehicleWithOrderIndex);
3038a3040,3047
> 
> 	virtual EventState OnHotkey(int hotkey)
> 	{
> 		if (this->owner != _local_company) return ES_NOT_HANDLED;
> 		return Window::OnHotkey(hotkey);
> 	}
> 
> 	static HotkeyList hotkeys;
3040a3050,3078
> 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
> );
3087a3126,3128
> 
> 	if (_settings_client.gui.cm_open_orders_for_new_vehicles)
> 		ShowOrdersWindow(v);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/video/allegro_v.cpp cmclient/src/video/allegro_v.cpp
30a31,32
> #include "../../citymania/cm_hotkeys.hpp"
> 
467a470
> 	_alt_pressed = !!(key_shifts & KB_ALT_FLAG);
485c488,489
< 	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
---
> 		// CM if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
> 		citymania::UpdateModKeys(_shift_pressed, _ctrl_pressed, _alt_pressed);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/video/cocoa/cocoa_v.mm cmclient/src/video/cocoa/cocoa_v.mm
43a44,45
> #include "../../citymania/cm_hotkeys.hpp"
> 
227c229
< 	[ [ this->cocoaview inputContext ] discardMarkedText ];
---
> 	[ [ this->cocoaview inputContext ] performSelectorOnMainThread:@selector(discardMarkedText) withObject:nil waitUntilDone:[ NSThread isMainThread ] ];
448a451
> 	_alt_pressed = (cur_mods & NSAlternateKeyMask) != 0;
457c460,461
< 	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
---
> 	// if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
> 	citymania::UpdateModKeys(_shift_pressed, _ctrl_pressed, _alt_pressed);
Only in cmclient/src/video/cocoa: event.mm
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/video/sdl2_v.cpp cmclient/src/video/sdl2_v.cpp
30a31,32
> #include "../citymania/cm_hotkeys.hpp"
> 
418c420
< 			if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) {
---
> 			if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) {
437a440,450
> 			if (ev.button.button == SDL_BUTTON_MIDDLE) {
> 				HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
> 				break;
> 			} else if (ev.button.button > SDL_BUTTON_RIGHT) {
> 				int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4;
> 				if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
> 					HandleKeypress(button, 0);
> 				}
> 				break;
> 			}
> 
600a614
> 	_alt_pressed = !!(mod & KMOD_ALT);
618c632,633
< 	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
---
> 	// CM if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
> 	citymania::UpdateModKeys(_shift_pressed, _ctrl_pressed, _alt_pressed);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/video/sdl_v.cpp cmclient/src/video/sdl_v.cpp
26a27,28
> #include "../citymania/cm_hotkeys.hpp"
> 
439c441,449
< 	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),
493c503
< 			if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) {
---
> 			if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) {
515a526,536
> 			if (ev.button.button == SDL_BUTTON_MIDDLE) {
> 				HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
> 				break;
> 			} else if (ev.button.button > SDL_BUTTON_WHEELDOWN) {
> 				int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4;
> 				if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
> 					HandleKeypress(button, 0);
> 				}
> 				break;
> 			}
> 
629a651
> 	_alt_pressed = !!(mod & KMOD_ALT);	
647c669,670
< 	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
---
> 		// CM if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
> 		citymania::UpdateModKeys(_shift_pressed, _ctrl_pressed, _alt_pressed);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/video/win32_v.cpp cmclient/src/video/win32_v.cpp
28a29,30
> #include "../citymania/cm_hotkeys.hpp"
> 
453a456,471
> 		/* CityMania code start */
> 		case WM_MBUTTONUP:
> 			ReleaseCapture();
> 			HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
> 			return 0;
> 
> 		case WM_XBUTTONUP: {
> 			ReleaseCapture();
> 			int button = CM_WKC_MOUSE_OTHER_START + GET_XBUTTON_WPARAM(wParam) - 1;
> 			if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
> 				HandleKeypress(button, 0);
> 			}
> 			return 0;
> 		}
> 		/* CityMania code end */
> 
827a846
> 	_alt_pressed = this->has_focus && GetAsyncKeyState(VK_MENU) < 0;
849c868,869
< 	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
---
> 	// CM if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
> 	citymania::UpdateModKeys(_shift_pressed, _ctrl_pressed, _alt_pressed);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/viewport.cpp cmclient/src/viewport.cpp
63a64,66
> #include "math.h"
> #include "core/math_func.hpp"
> #include "core/smallvec_type.hpp"
86a90
> #include "tunnelbridge_map.h"
97a102,106
> #include "industry_type.h"
> 
> #include "citymania/cm_highlight.hpp"
> #include "citymania/cm_hotkeys.hpp"
> #include "citymania/cm_zoning.hpp"
161a171,192
> /**
>  * 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 std::vector<LineSnapPoint> LineSnapPoints; ///< Set of snapping points
> 
> /** Coordinates of a polyline track made of 2 connected line segments. */
> struct RailPolyline {
> 	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.
> };
> 
179a211,212
> 
> 	citymania::TileHighlight cm_highlight;
192a226,233
> 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 TileIndex GetRailSnapTile();
> static void SetRailSnapTile(TileIndex tile);
> 
524c565
< static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
---
> void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
557c598
< 
---
> 	if (_vd.cm_highlight.ground_pal) pal = _vd.cm_highlight.ground_pal;
665a707,708
> 	if (_vd.cm_highlight.structure_pal) pal = _vd.cm_highlight.structure_pal;
> 
788c831
<  * 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
793c836
< bool IsInsideRotatedRectangle(int x, int y)
---
> bool IsInsideSelectedRectangle(int x, int y)
794a838,841
> 	if (!_thd.diagonal) {
> 		return IsInsideBS(x, _thd.pos.x, _thd.size.x) && IsInsideBS(y, _thd.pos.y, _thd.size.y);
> 	}
> 
870c917
< static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part)
---
> void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part)
911c958
< static bool IsPartOfAutoLine(int px, int py)
---
> static HighLightStyle GetPartOfAutoLine(int px, int py, const Point &selstart, const Point &selend, HighLightStyle dir)
913,914c960,961
< 	px -= _thd.selstart.x;
< 	py -= _thd.selstart.y;
---
> 	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;
916c963,964
< 	if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false;
---
> 	px -= selstart.x & ~TILE_UNIT_MASK;
> 	py -= selstart.y & ~TILE_UNIT_MASK;
918,926c966,973
< 	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();
---
> 	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;
928d974
< }
930,938c976,977
< /* [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 }
< };
---
> 	return HT_DIR_END;
> }
946c985,986
<  * @param autorail_type Offset into _AutorailTilehSprite[][]
---
>  * @param autorail_type \c HT_DIR_XXX, offset into _AutorailTilehSprite[][]
>  * @param pal Palette to use, -1 to autodetect
948c988
< static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
---
> static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_type, PaletteID pal = -1)
951d990
< 	PaletteID pal;
957c996
< 		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
965a1005
> 	assert(autorail_type < HT_DIR_END);
969c1009
< 		pal = PAL_NONE;
---
> 		if (pal == (PaletteID)-1) pal = _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE;
972c1012
< 		pal = PALETTE_SEL_TILE_RED;
---
> 		if (pal == (PaletteID)-1) pal = PALETTE_SEL_TILE_RED;
975c1015
< 	DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
---
> 	DrawSelectionSprite(image, pal, ti, 7, foundation_part);
978,983c1018,1024
< enum TileHighlightType {
< 	THT_NONE,
< 	THT_WHITE,
< 	THT_BLUE,
< 	THT_RED,
< };
---
> // CM moved to cm_highlight.hpp
> // enum TileHighlightType {
> // 	THT_NONE,
> // 	THT_WHITE,
> // 	THT_BLUE,
> // 	THT_RED,
> // };
994a1036
> #if 0  // taken over by citymania highlight
999c1041
< 
---
> #endif
1087,1088c1129
< 	/* No tile selection active? */
< 	if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
---
> 	if (citymania::DrawTileSelection(ti, tht)) return;
1090,1093c1131,1132
< 	if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle
< 		if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner;
< 		return;
< 	}
---
> 	switch (_thd.drawstyle & HT_DRAG_MASK) {
> 		default: break; // No tile selection active?
1095,1114c1134,1143
< 	/* 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;
---
> 		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);
1117,1126c1146
< 			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;
---
> 			break;
1128,1132c1148,1165
< 			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)));
---
> 		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);
1133a1167
> 			break;
1135,1138c1169,1174
< 			DrawAutorailSelection(ti, _autorail_type[dir][side]);
< 		}
< 		return;
< 	}
---
> 		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;
1140,1146c1176,1185
< 	/* Check if it's inside the outer area? */
< 	if (!is_redsq && (tht == THT_NONE || tht == THT_RED) && _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;
---
> 		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;
> 		}
1270a1310
> 				_vd.cm_highlight = citymania::GetTileHighlight(&tile_info);
1273c1313,1318
< 				if (tile_info.tile != INVALID_TILE) DrawTileSelection(&tile_info);
---
> 
> 				if (tile_info.tile != INVALID_TILE){
> 					citymania::DrawTileZoning(&tile_info);
> 					citymania::DrawTileZoning(&tile_info, _vd.cm_highlight);
> 					DrawTileSelection(&tile_info);
> 				}
1276a1322
> 	_vd.cm_highlight = citymania::TileHighlight();
1321c1367
< static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
---
> Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
2011c2057
< 		if (_thd.outersize.x != 0) {
---
> 		if (_thd.outersize.x != 0 || _thd.outersize.y != 0) {
2127c2173
< static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y, const ViewportSign *sign)
---
> bool CheckClickOnViewportSign(const Viewport *vp, int x, int y, const ViewportSign *sign)
2210c2256,2257
< 		ShowTownViewWindow(last_t->index);
---
> 		if (citymania::_fn_mod) TownExecuteAction(last_t, 4); //CM build statue
> 		else ShowTownViewWindow(last_t->index);
2346c2393
< bool HandleViewportClicked(const Viewport *vp, int x, int y)
---
> bool HandleViewportClicked(const Viewport *vp, int x, int y, bool double_click)
2355a2403,2414
> 		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);
> 		}
> 
2367,2368c2426,2428
< 			if (_ctrl_pressed && v->owner == _local_company) {
< 				StartStopVehicle(v, true);
---
> 			if (citymania::_fn_mod && v->owner == _local_company) {
> 				if (_settings_client.gui.enable_ctrl_click_start_stop)
> 					StartStopVehicle(v, true);
2480,2481c2540,2541
< 	_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;
2509c2569
< 	return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down;
---
> 	return (this->place_mode & HT_DIAGONAL) != 0 && citymania::_fn_mod && _left_button_down;
2520a2581
> static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging);
2521a2583,2611
> /** Update size of the area occupied by the blue part of rail track highlight (polyline mode). */
> 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 = std::min<int>(outer_x1, _thd.new_pos.x);
> 		outer_y1 = std::min<int>(outer_y1, _thd.new_pos.y);
> 		outer_x2 = std::max<int>(outer_x2, _thd.new_pos.x + _thd.new_size.x - TILE_SIZE);
> 		outer_y2 = std::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;
> 	}
> }
2580,2582d2669
< 					/* Draw one highlighted tile in any direction */
< 					new_drawstyle = GetAutorailHT(pt.x, pt.y);
< 					break;
2583a2671,2705
> 					/* 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 */
2601a2724,2726
> 					_thd.selend.x = x1;
> 					_thd.selend.y = y1;
> 					_thd.dir2 = HT_DIR_END;
2610a2736,2738
> 	if (new_drawstyle & HT_LINE) CalcNewPolylineOutersize();
> 	new_drawstyle = citymania::UpdateTileSelection(new_drawstyle);
> 
2614a2743
> 			_thd.offs.x != _thd.new_offs.x || _thd.offs.y != _thd.new_offs.y ||
2623a2753
> 		_thd.offs = _thd.new_offs;
2642d2771
< 	if (!_settings_client.gui.measure_tooltip) return;
2677a2807,2811
> 		_current_snap_lock.x = -1;
> 		if ((_thd.place_mode & HT_POLY) != 0 && GetRailSnapMode() == RSM_NO_SNAP) {
> 			SetRailSnapMode(RSM_SNAP_TO_TILE);
> 			SetRailSnapTile(tile);
> 		}
2718c2852
< 	if (distance > 1) {
---
> 	if (distance > 1  && _settings_client.gui.measure_tooltip) {
2885c3019,3051
< static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
---
> /**
>  * Show a tooltip indicating the length of highlighted rail track.
>  * @param style                   Style of the highlight.
>  * @param start_tile              Tile where selection starts.
>  * @param end_tile                Tile where selection ends.
>  * @param close_cond              Close condition of the tooltip.
>  * @param show_single_tile_length Show a tooltip also when the length is 1 tile.
>  */
> static void ShowLengthMeasurement(HighLightStyle style, TileIndex start_tile, TileIndex end_tile, TooltipCloseCondition close_cond = TCC_NONE, 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);
> 	}
> }
2915a3082,3273
> 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);
> 
> /**
>  * Convert a given point and a given #Direction to best matching #Trackdir.
>  *
>  * For example, #DIR_N will be converted to #TRACKDIR_LEFT_N if the point
>  * is on left tile half or #TRACKDIR_RIGHT_N if the point is on right half.
>  *
>  * @param pt  The point expressed in inner-tile world "units".
>  * @param dir The direction.
>  * @return The matching #Trackdir.
>  */
> 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;
> }
> 
> /**
>  * Try to fit a pair of rail track lines (polyline) based on a given end point
>  * (mouse cursor position) and a given snap point (begin point).
>  *
>  * @param pt       The end point expressed in inner-tile world "units".
>  * @param start    The snap point, begin of the lines.
>  * @param[out] ret Coordinates of the lines (if found).
>  * @return Whether the lines were found.
>  */
> 
> static bool FindPolyline(const Point &pt, const LineSnapPoint &start, RailPolyline *ret) {
> 	/* relative coordinates 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 (relatively 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 * std::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 = std::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 equal, 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 = std::min(abs(we), abs(ns)) - std::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);
> }
> 
> /**
>  * Find best matching pair of lines (polyline).
>  *
>  * @param pt          The end point (mouse cursor position) expressed in inner-tile world "units".
>  * @param snap_points Array of snapping points, the best one will be chosen.
>  * @param num_points  Length of the array.
>  * @param[out] ret    Coordinates of the polyline (if found).
>  * @return The chosen snapping point or NULL if no matching line was found.
>  */
> static LineSnapPoint *FindBestPolyline(const Point &pt, LineSnapPoint *snap_points, uint num_points, RailPolyline *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 */
> 		RailPolyline 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;
> }
> 
3102,3107c3460,3463
< 	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];
---
> 	_thd.selend.x = x;
> 	_thd.selend.y = y;
> 	_thd.dir2 = HT_DIR_END;
> 	_thd.next_drawstyle = b;
3109,3116c3465,3466
< 		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);
< 			}
---
> 	ShowLengthMeasurement(b, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
> }
3118,3120c3468,3476
< 			params[index++] = distance;
< 			if (heightdiff != 0) params[index++] = heightdiff;
< 		}
---
> /**
>  * Calculate how tiles should be highlighted (polyline mode).
>  * @param pt       Current mouse cursor position expressed in inner-tile world "units".
>  * @param dragging Whether currently drag-dropping, in this case direction of rail track line is locked.
>  * @return New highlight style.
>  */
> static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging)
> {
> 	RailSnapMode snap_mode = GetRailSnapMode();
3122c3478,3482
< 		ShowMeasurementTooltips(measure_strings_length[index], index, params);
---
> 	/* 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);
3125,3127c3485,3542
< 	_thd.selend.x = x;
< 	_thd.selend.y = y;
< 	_thd.next_drawstyle = b;
---
> 	/* find the best track */
> 	RailPolyline 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.data(), _tile_snap_points.size(), &line);
> 	} else {
> 		assert(snap_mode == RSM_SNAP_TO_RAIL);
> 		snap_point = FindBestPolyline(pt, _rail_snap_points.data(), _rail_snap_points.size(), &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;
3146a3562,3567
> 	if ((_thd.place_mode & HT_POLY) && GetRailSnapMode() != RSM_NO_SNAP) {
> 		Point pt = { x, y };
> 		_thd.next_drawstyle = CalcPolyrailDrawstyle(pt, true);
> 		return;
> 	}
> 
3199,3219c3620,3625
< 			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));
3229c3635
< 			if (_settings_client.gui.measure_tooltip) {
---
> 			if (_settings_client.gui.measure_tooltip || _thd.select_proc == DDSP_MEASURE) {
3231c3637,3638
< 					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,
3239c3646
< 				uint64 params[3];
---
> 				uint64 params[4];
3286c3693,3699
< 					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;
3297a3711
> 	_thd.dir2 = HT_DIR_END;
3339c3753
< 		_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;
3358c3772
< void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
---
> void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w, ViewportDragDropSelectionProcess cm_process)
3360c3774
< 	SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number);
---
> 	SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number, cm_process);
3373c3787
< void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
---
> void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num, ViewportDragDropSelectionProcess cm_process)
3404a3819
> 	_thd.select_proc = cm_process;
3423c3838
< 	SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
---
> 	SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0, CM_DDSP_NONE);
3497c3912
< static void MarkCatchmentTilesDirty()
---
> void MarkCatchmentTilesDirty()
3556a3972,4181
> }
> 
> /**
>  * Construct a rail snapping point based on a spot where a rail tracks segment
>  * has been placed.
>  *
>  * The snapping point will allow to stick new segment of tracks to the line that
>  * was placed before.
>  *
>  * @param tile Tile where the placed segment ended.
>  * @param exit_dir Tile side at which the segment ended.
>  * @param bidirectional Whether to allow to reverse at this point
>  *        (e.g. reversing after a bridges/tunnels is undesired).
>  * @param extended If not \c NULL, the snapping point will be extended over
>  *        a bridge/tunnel/station etc. if the last placed segment touches such
>  *        an object. Additional snapping point may be stored under \a extended
>  *        if needed, otherwise it will be set to { -1, -1, 0 }.
>  * @return New rail snapping point.
>  */
> static LineSnapPoint LineSnapPointAtRailTrackEndpoint(TileIndex tile, DiagDirection exit_dir, bool bidirectional, LineSnapPoint *extended)
> {
> 	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;
> 	if (extended != NULL) {
> 		extended->x = -1;
> 		extended->y = -1;
> 		extended->dirs = 0;
> 	}
> 
> 	/* Check whether to extend the snap point over a tunnel/bridge/station etc. */
> 	tile = TileAddByDiagDir(tile, exit_dir);
> 	if (extended != NULL && !IsTileType(tile, MP_RAILWAY) && !IsTileType(tile, MP_ROAD) &&
> 			TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, INVALID_DIAGDIR)) == AxisToTrackBits(DiagDirToAxis(exit_dir)) &&
> 			IsTileOwner(tile, _local_company)) {
> 		/* Check if this is a tunnel/bridge and move the tile to the other end if so. */
> 		if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) == exit_dir) tile = GetOtherTunnelBridgeEnd(tile);
> 		LineSnapPoint ex = LineSnapPointAtRailTrackEndpoint(tile, exit_dir, false, extended);
> 		if (!bidirectional) return ex; // if we are interested in forward direction only then return just the extended point
> 		*extended = ex; // otherwise return two points, extended with forward direction and base with reverse direction
> 	} else {
> 		/* Add forward direction. */
> 		SetBit(ret.dirs, DiagDirToDir(exit_dir));
> 	}
> 
> 	/* Add reverse direction. */
> 	if (bidirectional) SetBit(ret.dirs, ReverseDir(DiagDirToDir(exit_dir)));
> 
> 	/* Add 45 degree rotated directions. */
> 	ret.dirs |= ROR<uint8>(ret.dirs, DIRDIFF_45LEFT);
> 	ret.dirs |= ROR<uint8>(ret.dirs, DIRDIFF_45RIGHT);
> 	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, snap_start_ex, snap_end, snap_end_ex;
> 		snap_start = LineSnapPointAtRailTrackEndpoint(start_tile, TrackdirToExitdir(exit_trackdir_at_start), bidirectional_exit, &snap_start_ex);
> 		snap_end = LineSnapPointAtRailTrackEndpoint(end_tile, TrackdirToExitdir(exit_trackdir_at_end), bidirectional_exit, &snap_end_ex);
> 		/* Find if we already had these coordinates before. */
> 		bool had_start = false;
> 		bool had_end = false;
> 		for (auto &snap: _rail_snap_points) {
> 			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 snapping, don't forget snap points */
> 			SetRailSnapMode(RSM_NO_SNAP);
> 		} else {
> 			/* include only new points */
> 			_rail_snap_points.clear();
> 			if (!had_start) {
> 				_rail_snap_points.push_back(snap_start);
> 				if (snap_start_ex.dirs != 0) _rail_snap_points.push_back(snap_start_ex);
> 			}
> 			if (!had_end) {
> 				_rail_snap_points.push_back(snap_end);
> 				if (snap_end_ex.dirs != 0) _rail_snap_points.push_back(snap_end_ex);
> 			}
> 			SetRailSnapMode(RSM_SNAP_TO_RAIL);
> 		}
> 	}
> }
> 
> /**
>  * Store the position of lastly built rail station; for highlighting purposes.
>  *
>  * In "polyline" highlighting mode, the stored end points will be used as snapping points for new tracks.
>  *
>  * @param ta           Station area.
>  * @param station_axis Station axis.
>  */
> void StoreRailStationPlacementEndpoints(const TileArea &ta, Axis station_axis)
> {
> 	uint start_x = TileX(ta.tile);
> 	uint start_y = TileY(ta.tile);
> 	uint end_x = start_x + ta.w - 1;
> 	uint end_y = start_y + ta.h - 1;
> 
> 	_rail_snap_points.clear();
> 	if (station_axis == AXIS_X) {
> 		for (uint y = start_y; y <= end_y; y++) {
> 			_rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(start_x, y), DIAGDIR_NE, false, NULL));
> 			_rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(end_x, y), DIAGDIR_SW, false, NULL));
> 		}
> 	} else {
> 		for (uint x = start_x; x <= end_x; x++) {
> 			_rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(x, start_y), DIAGDIR_NW, false, NULL));
> 			_rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(x, end_y), DIAGDIR_SE, false, NULL));
> 		}
> 	}
> }
> 
> /**
>  * Get current rail track snapping mode.
>  * @return Current snapping mode.
>  *
>  * @note This function will return #RSM_NO_SNAP if there are no snapping points
>  *       set (yet), even thought the snapping was set to some different mode.
>  */
> RailSnapMode GetRailSnapMode()
> {
> 	if (_rail_snap_mode == RSM_SNAP_TO_TILE && _tile_snap_points.empty()) return RSM_NO_SNAP;
> 	if (_rail_snap_mode == RSM_SNAP_TO_RAIL && _rail_snap_points.empty()) return RSM_NO_SNAP;
> 	return _rail_snap_mode;
> }
> 
> /**
>  * Set current current rail track snapping mode.
>  * @param mode New snapping mode.
>  */
> void SetRailSnapMode(RailSnapMode mode)
> {
> 	_rail_snap_mode = mode;
> 
> 	if ((_thd.place_mode & HT_POLY) && (GetRailSnapMode() == RSM_NO_SNAP)) {
> 		SetTileSelectSize(1, 1);
> 	}
> }
> 
> /**
>  * Get the tile that is set to be a snapping point for rail tracks (used when
>  * #RSM_SNAP_TO_TILE mode is active).
>  *
>  * @return The tile.
>  */
> static TileIndex GetRailSnapTile()
> {
> 	if (_tile_snap_points.empty()) return INVALID_TILE;
> 	return TileVirtXY(_tile_snap_points[DIAGDIR_NE].x, _tile_snap_points[DIAGDIR_NE].y);
> }
> 
> /**
>  * Set the tile that is meant to be a snapping point for rail tracks (used when
>  * #RSM_SNAP_TO_TILE mode is active).
>  *
>  * @param tile The tile.
>  */
> static void SetRailSnapTile(TileIndex tile)
> {
> 	_tile_snap_points.clear();
> 	if (tile == INVALID_TILE) return;
> 
> 	for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
> 		auto point = LineSnapPointAtRailTrackEndpoint(tile, dir, false, NULL);
> 		point.dirs = ROR<uint8>(point.dirs, DIRDIFF_REVERSE);
> 		_tile_snap_points.push_back(point);
> 	}
> }
> 
> /** Clear all stored rail snapping points and reset the snapping mode. */
> void ResetRailPlacementEndpoints()
> {
> 	_rail_snap_mode = RSM_NO_SNAP;
> 	_tile_snap_points.clear();
> 	_rail_snap_points.clear();
> 	_current_snap_lock.x = -1;
> }
> 
> namespace citymania {
> 	void (*DrawTileSelectionRect)(const TileInfo *ti, PaletteID pal) = &::DrawTileSelectionRect;
> 	void (*DrawAutorailSelection)(const TileInfo *ti, HighLightStyle autorail_type, PaletteID pal) = &::DrawAutorailSelection;
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/viewport_func.h cmclient/src/viewport_func.h
61c61
< bool HandleViewportClicked(const Viewport *vp, int x, int y);
---
> bool HandleViewportClicked(const Viewport *vp, int x, int y, bool double_click);
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/viewport_gui.cpp cmclient/src/viewport_gui.cpp
154a155,159
> 
> 	virtual void OnMouseOver(Point pt, int widget)
> 	{
> 		if (pt.x != -1) GuiPrepareTooltipsExtra(this);
> 	}
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/viewport_type.h cmclient/src/viewport_type.h
115a116
> 	CM_DDSP_NONE,			   ///< CM Nothing is being built
116a118
> 	DDSP_DEMOLISH_TREES,       ///< Clear trees
125a128
> 	DDSP_MEASURE,              ///< Measurement tool
142a146,186
> 
> 	/* CityMania extras */
> 	CM_DDSP_BUILD_HQ,
> 	CM_DDSP_DEPOT_MOVE,
> 	CM_DDSP_DEPOT_CLONE,
> 	CM_DDSP_ZZZ,
> 	CM_DDSP_STORY_BUTTON,
> 	CM_DDSP_GROUP,
> 	CM_DDSP_NEWGRF_SELECT,
> 	CM_DDSP_PLACE_OBJECT,
> 	CM_DDSP_PICK_STATION,
> 	CM_DDSP_SELECT_ORDER,
> 	CM_DDSP_PLACE_SIGN,
> 	CM_DDSP_LAND_INFO,
> 	CM_DDSP_SELECT_REFIT,
> 
> 	CM_DDSP_DEMOLISH,
> 
> 	CM_DDSP_BUILD_AIRPORT,
> 
> 	CM_DDSP_BUILD_CANNAL,
> 	CM_DDSP_BUILD_LOCK,
> 	CM_DDSP_BUILD_SHIP_DEPOT,
> 	CM_DDSP_BUILD_DOCK,
> 	CM_DDSP_BUILD_BUOY,
> 	CM_DDSP_BUILD_RIVER,
> 	CM_DDSP_BUILD_AQUEDUCT,
> 	CM_DDSP_BUILD_RAIL_DEPOT,
> 
> 	CM_DDSP_FUND_INDUSTRY,
> 	CM_DDSP_BUILD_WAYPOINT,
> 	CM_DDSP_BUILD_RAIL_BRIDGE,
> 	CM_DDSP_BUILD_RAIL_TUNNEL,
> 	CM_DDSP_BUILD_ROAD_DEPOT,
> 	CM_DDSP_BUILD_ROAD_BRIDGE,
> 	CM_DDSP_BUILD_ROAD_TUNNEL,
> 
> 	CM_DDSP_DEMOLISH_TREES,
> 	CM_DDSP_TERRAFORM,
> 	CM_DDSP_BUY_LAND,
> 	CM_DDSP_NEW_TOWN,
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/waypoint_gui.cpp cmclient/src/waypoint_gui.cpp
27a28,29
> #include "citymania/cm_hotkeys.hpp"
> 
91c93
< 				if (_ctrl_pressed) {
---
> 				if (citymania::_fn_mod) {
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widget.cpp cmclient/src/widget.cpp
218c218
< 	assert(img != 0);
---
> 
219a220
> 	if (img == 0) return;
Only in cmclient/src/widgets: cargo_table_widget.h
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/company_widget.h cmclient/src/widgets/company_widget.h
55a56,61
> 
> 	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,
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/dropdown.cpp cmclient/src/widgets/dropdown.cpp
44c44,49
< 
---
> /*
> const char * DropDownListCharStringItem::String() const
> {
> 	return this->string;
> }
> */
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/graph_widget.h cmclient/src/widgets/graph_widget.h
29a30,33
> 	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.
42a47
> 	WID_CPR_KEY_BUTTON,      ///< Key button.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/industry_widget.h cmclient/src/widgets/industry_widget.h
22a23,24
> 	WID_DPI_FT_OFF,                          ///< Forbidden tiles highlight off button.
> 	WID_DPI_FT_ON,                           ///< Forbidden tiles highlight on button.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/network_widget.h cmclient/src/widgets/network_widget.h
50a51,55
> 
> 	WID_NG_CITYMANIA,          ///< filter citymania
> 	WID_NG_REDDIT,             ///< filter reddit
> 	WID_NG_NICE,               ///< filter n-ice
> 	WID_NG_BTPRO,              ///< filter btpro
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/rail_widget.h cmclient/src/widgets/rail_widget.h
21a22
> 	WID_RAT_POLYRAIL,       ///< Polyline rail tool.
102,105c103,107
< 	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.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/road_widget.h cmclient/src/widgets/road_widget.h
19c19
< 	WID_ROT_AUTOROAD,       ///< Autorail.
---
> 	WID_ROT_AUTOROAD,       ///< Autoroad.
34,38c34,39
< 	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.
44,54c45,57
< 	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.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/smallmap_widget.h cmclient/src/widgets/smallmap_widget.h
28a29
> 	CM_WID_SM_IMBA,        ///< CityMania IMBA mode (Industries, Contour, Vegetation)
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/statusbar_widget.h cmclient/src/widgets/statusbar_widget.h
17a18
>     CM_WID_S_APM, ///< CityMania EPM counter.
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/terraform_widget.h cmclient/src/widgets/terraform_widget.h
20a21
> 	WID_TT_DEMOLISH_TREES,                    ///< Demolish trees only
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/toolbar_widget.h cmclient/src/widgets/toolbar_widget.h
23a24
> 	WID_TN_CARGOS,        ///< Transported cargo menu
26a28
> 	WID_TN_WATCH,         ///< Watch gui menu
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/widgets/town_widget.h cmclient/src/widgets/town_widget.h
20a21
> 	TDW_CAPTION_TEXT,
44a46
> 	WID_TV_CB,
63a66,96
> };
> 
> enum TownHK {
> 	HK_SADVERT,
> 	HK_MADVERT,
> 	HK_LADVERT,
> 	HK_ROADS,
> 	HK_STATUE,
> 	HK_FUND,
> };
> 
> enum CBTownWidgets {
> 	WID_CB_CAPTION,        ///< Caption of window.
> 	WID_CB_CENTER_VIEW,
> 	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_TOWN_VIEW,
> 	WID_CB_SHOW_AUTHORITY,
> 	WID_CB_SELECT_REQUIREMENTS,
> 	WID_CB_GOALS,
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/window.cpp cmclient/src/window.cpp
11a12
> #include <limits>
33a35
> #include "window_gui.h"
41a44,45
> #include "citymania/cm_hotkeys.hpp"
> 
725c729
< 			if (_ctrl_pressed) {
---
> 			if (citymania::_fn_mod) {
759c763
< 			if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0;
---
> 			if (citymania::_fn_mod) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0;
1234a1239
> 			case WC_CARGOS:
1793a1799,1800
> 		pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10);
> 		return pt;
2738,2745c2745,2753
< void HandleCtrlChanged()
< {
< 	/* Call the event, start with the uppermost window. */
< 	Window *w;
< 	FOR_ALL_WINDOWS_FROM_FRONT(w) {
< 		if (w->OnCTRLStateChange() == ES_HANDLED) return;
< 	}
< }
---
> // Use CityMania modifier key handling
> // void HandleCtrlChanged()
> // {
> // 	/* Call the event, start with the uppermost window. */
> // 	Window *w;
> // 	FOR_ALL_WINDOWS_FROM_FRONT(w) {
> // 		if (w->OnCTRLStateChange() == ES_HANDLED) return;
> // 	}
> // }
2934c2942
< 				if (HandleViewportClicked(vp, x, y)) return;
---
> 				if (HandleViewportClicked(vp, x, y, click == MC_DOUBLE_LEFT)) return;
3643a3653,3703
> }
> 
> /**
>  * 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;
> 			}
> 			FALLTHROUGH;  // suppress warning, no idea if it's actually correct
> 		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 -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/window_gui.h cmclient/src/window_gui.h
17a18
> #include "station_base.h"
613,614c614,616
< 	virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
< 
---
> 	// CM virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
> 	virtual EventState CM_OnFnModStateChange() { return ES_NOT_HANDLED; }
> 	virtual EventState CM_OnRemoveModStateChange() { return ES_NOT_HANDLED; }
885a888
> void GuiPrepareTooltipsExtra(Window *parent);
917a921,947
> 
> 
> /**
>  * #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;
> };
diff -r -B -X /home/pavels/Projects/cmclient/.diff-exclude vanilla/src/window_type.h cmclient/src/window_type.h
109a110
> 	WC_STATION_RATING_TOOLTIP,
370a372,377
> 	/* CityMania watch company */
> 	WC_WATCH_COMPANY,
> 
> 	/* CityMania watch company admin version */
> 	WC_WATCH_COMPANYA,
> 
516a524
> 	WC_CARGOS,
692a701,704
> 	WC_ZONING_TOOLBAR,
> 	WC_COMMAND_TOOLBAR,
> 	WC_LOGIN_WINDOW,
> 	WC_CB_TOWN,
698a711,715
> 
> 	/*
> 	 * CityMania extra windows
> 	 */
> 	CM_WC_LAND_TOOLTIPS,
Only in cmclient: update.sh
