diff -r 779c5a44c6a1 .hgtags
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgtags	Wed Dec 16 19:19:57 2009 +0100
@@ -0,0 +1,5 @@
+b40dd43fc1f27083cf2696c57ec6b907855fb007 IS2.0-beta1
+4cd407daac0d6fbaa012ef49eec43ffaf32bb207 IS2.0-beta2
+56a047d6bab4807fe6d89dd8bdc2edbc4e6c7ad4 IS2.0-beta3
+2d98b8a58b405fd24f84f27446b6d370b22bbf29 IS2.0-beta4
+1767ebc9758c27634714f1a667fd1e3f0e3fdc3e IS2.0-beta5
diff -r 779c5a44c6a1 backup.push
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backup.push	Wed Dec 16 19:19:57 2009 +0100
@@ -0,0 +1,1 @@
+ssh://hg@bitbucket.org/OpenTTD/infrastructure-sharing/
diff -r 779c5a44c6a1 projects/openttd_vs80.vcproj
--- a/projects/openttd_vs80.vcproj	Fri Dec 04 22:02:37 2009 +0000
+++ b/projects/openttd_vs80.vcproj	Wed Dec 16 19:19:57 2009 +0100
@@ -584,6 +584,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\infrastructure.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ini.cpp"
 				>
 			</File>
@@ -1072,6 +1076,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\infrastructure.h"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\infrastructure_func.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ini_type.h"
 				>
 			</File>
diff -r 779c5a44c6a1 projects/openttd_vs90.vcproj
--- a/projects/openttd_vs90.vcproj	Fri Dec 04 22:02:37 2009 +0000
+++ b/projects/openttd_vs90.vcproj	Wed Dec 16 19:19:57 2009 +0100
@@ -581,6 +581,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\infrastructure.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ini.cpp"
 				>
 			</File>
@@ -1069,6 +1073,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\infrastructure.h"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\infrastructure_func.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ini_type.h"
 				>
 			</File>
diff -r 779c5a44c6a1 source.list
--- a/source.list	Fri Dec 04 22:02:37 2009 +0000
+++ b/source.list	Wed Dec 16 19:19:57 2009 +0100
@@ -31,6 +31,7 @@
 gfxinit.cpp
 heightmap.cpp
 highscore.cpp
+infrastructure.cpp
 ini.cpp
 landscape.cpp
 map.cpp
@@ -177,6 +178,8 @@
 industry.h
 industry_type.h
 industrytype.h
+infrastructure.h
+infrastructure_func.h
 ini_type.h
 landscape.h
 landscape_type.h
diff -r 779c5a44c6a1 src/aircraft_cmd.cpp
--- a/src/aircraft_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/aircraft_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -35,6 +35,7 @@
 #include "effectvehicle_func.h"
 #include "station_base.h"
 #include "cargotype.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -113,7 +114,7 @@
 	const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
 
 	FOR_ALL_STATIONS(st) {
-		if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue;
+		if (!(st->facilities & FACIL_AIRPORT) || !IsInfraUsageAllowed(st->owner, v)) continue;
 
 		const AirportFTAClass *afc = st->Airport();
 		if (afc->nof_depots == 0 || (
@@ -144,7 +145,7 @@
 
 	FOR_VEHICLE_ORDERS(v, order) {
 		const Station *st = Station::Get(order->station);
-		if (st->owner == v->owner && (st->facilities & FACIL_AIRPORT)) {
+		if (IsInfraUsageAllowed(st->owner, v) && (st->facilities & FACIL_AIRPORT)) {
 			/* If an airport doesn't have a hangar, skip it */
 			if (st->Airport()->nof_depots != 0)
 				return true;
@@ -247,7 +248,7 @@
 	/* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
 	if (flags & DC_QUERY_COST) return value;
 
-	if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
+	if (!IsHangarTile(tile) || !CheckInfraUsageAllowed(tile, VEH_AIRCRAFT)) return CMD_ERROR;
 
 	/* Prevent building aircraft types at places which can't handle them */
 	if (!CanVehicleUseStation(p1, Station::GetByTile(tile))) return CMD_ERROR;
@@ -1569,7 +1570,7 @@
 	/* runway busy or not allowed to use this airstation, circle */
 	if ((apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES)) &&
 			st->airport_tile != INVALID_TILE &&
-			(st->owner == OWNER_NONE || st->owner == v->owner)) {
+			IsInfraUsageAllowed(st->owner, v)) {
 		/* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
 		 * if it is an airplane, look for LANDING, for helicopter HELILANDING
 		 * it is possible to choose from multiple landing runways, so loop until a free one is found */
diff -r 779c5a44c6a1 src/command.cpp
--- a/src/command.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/command.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -199,6 +199,7 @@
 DEF_COMMAND(CmdSetVehicleOnTime);
 DEF_COMMAND(CmdAutofillTimetable);
 DEF_COMMAND(CmdSetTimetableStart);
+DEF_COMMAND(CmdChangeSharingSetting);
 #undef DEF_COMMAND
 
 /**
@@ -345,6 +346,7 @@
 	{CmdSetVehicleOnTime,                           0}, // CMD_SET_VEHICLE_ON_TIME
 	{CmdAutofillTimetable,                          0}, // CMD_AUTOFILL_TIMETABLE
 	{CmdSetTimetableStart,                          0}, // CMD_SET_TIMETABLE_START
+	{CmdChangeSharingSetting,                       0}, // CMD_CHANGE_SHARING_SETTING
 };
 
 /*!
diff -r 779c5a44c6a1 src/command_type.h
--- a/src/command_type.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/command_type.h	Wed Dec 16 19:19:57 2009 +0100
@@ -294,6 +294,7 @@
 	CMD_SET_VEHICLE_ON_TIME,          ///< set the vehicle on time feature (timetable)
 	CMD_AUTOFILL_TIMETABLE,           ///< autofill the timetable
 	CMD_SET_TIMETABLE_START,          ///< set the date that a timetable should start
+	CMD_CHANGE_SHARING_SETTING,       ///< change one of the settings for infrastructure sharing
 };
 
 /**
diff -r 779c5a44c6a1 src/company_base.h
--- a/src/company_base.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/company_base.h	Wed Dec 16 19:19:57 2009 +0100
@@ -23,6 +23,7 @@
 #include "economy_type.h"
 #include "tile_type.h"
 #include "settings_type.h"
+#include "infrastructure.h"
 
 struct CompanyEconomyEntry {
 	Money income;
@@ -87,6 +88,12 @@
 	CompanySettings settings;          ///< settings specific for each company
 	uint16 *num_engines; ///< caches the number of engines of each type the company owns (no need to save this)
 
+	byte sharing_delay;                     ///< number of months before new settings go in effect
+	CompanySharingSettings sharing_current; ///< settings currently in effect
+	CompanySharingSettings sharing_future;  ///< future settings, will go in effect after (sharing_delay) months.
+	Date sharing_setting_change_news_date;  ///< NOSAVE: date when a news message regarding an announced change of sharing settings was issued of the last time
+	Date sharing_insolvency_news_date;      ///< NOSAVE: date when a news message regarding insolvency was issued for the last time
+
 	static FORCEINLINE bool IsValidAiID(size_t index)
 	{
 		const Company *c = Company::GetIfValid(index);
diff -r 779c5a44c6a1 src/company_cmd.cpp
--- a/src/company_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/company_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -75,6 +75,7 @@
 	InvalidateWindowData(WC_GRAPH_LEGEND, 0, (int)index);
 	InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, (int)index);
 	InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
+	InvalidateWindowClassesData(WC_SHARING_OPTIONS, 1);
 }
 
 /**
@@ -178,14 +179,16 @@
 	if (HasBit(1 << EXPENSES_TRAIN_INC    |
 	           1 << EXPENSES_ROADVEH_INC  |
 	           1 << EXPENSES_AIRCRAFT_INC |
-	           1 << EXPENSES_SHIP_INC, cost.GetExpensesType())) {
+	           1 << EXPENSES_SHIP_INC     |
+	           1 << EXPENSES_SHARED_INC, cost.GetExpensesType())) {
 		c->cur_economy.income -= cost.GetCost();
 	} else if (HasBit(1 << EXPENSES_TRAIN_RUN    |
 	                  1 << EXPENSES_ROADVEH_RUN  |
 	                  1 << EXPENSES_AIRCRAFT_RUN |
 	                  1 << EXPENSES_SHIP_RUN     |
 	                  1 << EXPENSES_PROPERTY     |
-	                  1 << EXPENSES_LOAN_INT, cost.GetExpensesType())) {
+	                  1 << EXPENSES_LOAN_INT     |
+	                  1 << EXPENSES_SHARED_RUN, cost.GetExpensesType())) {
 		c->cur_economy.expenses -= cost.GetCost();
 	}
 
@@ -463,11 +466,28 @@
 
 	SetDefaultCompanySettings(c->index);
 
+	/* sharing settings */
+	if (_settings_game.sharing.sharing_mode == SHARING_GLOBAL) {
+		c->sharing_current.CopyFromGameSettings();
+		c->sharing_future = c->sharing_current;
+		/* enable this company in all companies */
+		Company *d;
+		FOR_ALL_COMPANIES(d) {
+			d->sharing_current.SetCompanyAllowed(c->index, true);
+			d->sharing_future.SetCompanyAllowed(c->index, true);
+		}
+	} else {
+		/* only allow own company */
+		c->sharing_current.SetCompanyAllowed(c->index, true);
+		c->sharing_future.SetCompanyAllowed(c->index, true);
+	}
+
 	GeneratePresidentName(c);
 
 	SetWindowDirty(WC_GRAPH_LEGEND, 0);
 	SetWindowDirty(WC_TOOLBAR_MENU, 0);
 	SetWindowDirty(WC_CLIENT_LIST, 0);
+	InvalidateWindowClassesData(WC_SHARING_OPTIONS, 1);
 
 	if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index);
 
diff -r 779c5a44c6a1 src/company_gui.cpp
--- a/src/company_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/company_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -28,6 +28,10 @@
 #include "date_func.h"
 #include "widgets/dropdown_type.h"
 #include "tilehighlight_func.h"
+#include "company_gui.h"
+#include "currency.h"
+#include "openttd.h"
+#include "window_func.h"
 
 #include "table/strings.h"
 
@@ -40,8 +44,9 @@
 };
 
 static void DoSelectCompanyManagerFace(Window *parent);
+static void ShowCompanySharingSettings(CompanyID company);
 
-/** Standard unsorted list of expenses. */
+/** Standard unsorted list of expenses with infrastructure sharing disabled. */
 static ExpensesType _expenses_list_1[] = {
 	EXPENSES_CONSTRUCTION,
 	EXPENSES_NEW_VEHICLES,
@@ -58,7 +63,7 @@
 	EXPENSES_OTHER,
 };
 
-/** Grouped list of expenses. */
+/** Grouped list of expenses with infrastructure sharing disabled. */
 static ExpensesType _expenses_list_2[] = {
 	EXPENSES_TRAIN_INC,
 	EXPENSES_ROADVEH_INC,
@@ -78,6 +83,47 @@
 	INVALID_EXPENSES,
 };
 
+/** Standard unsorted list of expenses with infrastructure sharing enabled. */
+static ExpensesType _expenses_list_3[] = {
+	EXPENSES_CONSTRUCTION,
+	EXPENSES_NEW_VEHICLES,
+	EXPENSES_TRAIN_RUN,
+	EXPENSES_ROADVEH_RUN,
+	EXPENSES_AIRCRAFT_RUN,
+	EXPENSES_SHIP_RUN,
+	EXPENSES_SHARED_RUN,
+	EXPENSES_PROPERTY,
+	EXPENSES_TRAIN_INC,
+	EXPENSES_ROADVEH_INC,
+	EXPENSES_AIRCRAFT_INC,
+	EXPENSES_SHIP_INC,
+	EXPENSES_SHARED_INC,
+	EXPENSES_LOAN_INT,
+	EXPENSES_OTHER,
+};
+
+/** Grouped list of expenses with infrastructure sharing enabled. */
+static ExpensesType _expenses_list_4[] = {
+	EXPENSES_TRAIN_INC,
+	EXPENSES_ROADVEH_INC,
+	EXPENSES_AIRCRAFT_INC,
+	EXPENSES_SHIP_INC,
+	EXPENSES_SHARED_INC,
+	INVALID_EXPENSES,
+	EXPENSES_TRAIN_RUN,
+	EXPENSES_ROADVEH_RUN,
+	EXPENSES_AIRCRAFT_RUN,
+	EXPENSES_SHIP_RUN,
+	EXPENSES_SHARED_RUN,
+	EXPENSES_PROPERTY,
+	EXPENSES_LOAN_INT,
+	INVALID_EXPENSES,
+	EXPENSES_CONSTRUCTION,
+	EXPENSES_NEW_VEHICLES,
+	EXPENSES_OTHER,
+	INVALID_EXPENSES,
+};
+
 /** Expense list container. */
 struct ExpensesList {
 	const ExpensesType *et;   ///< Expenses items.
@@ -117,6 +163,8 @@
 static const ExpensesList _expenses_list_types[] = {
 	ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
 	ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
+	ExpensesList(_expenses_list_3, lengthof(_expenses_list_3), 0),
+	ExpensesList(_expenses_list_4, lengthof(_expenses_list_4), 3),
 };
 
 /** Widgets of the company finances windows. */
@@ -152,7 +200,7 @@
 	DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_CENTER, true);
 	y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
 
-	int type = _settings_client.gui.expenses_layout;
+	int type = _settings_game.sharing.sharing_mode != SHARING_NONE ? _settings_client.gui.expenses_layout + 2 : _settings_client.gui.expenses_layout;
 	for (uint i = 0; i < _expenses_list_types[type].length; i++) {
 		const ExpensesType et = _expenses_list_types[type].et[i];
 		if (et == INVALID_EXPENSES) {
@@ -201,7 +249,7 @@
 
 	Money sum = 0;
 	Money subtotal = 0;
-	int type = _settings_client.gui.expenses_layout;
+	int type = _settings_game.sharing.sharing_mode != SHARING_NONE ? _settings_client.gui.expenses_layout + 2: _settings_client.gui.expenses_layout;
 	for (uint i = 0; i < _expenses_list_types[type].length; i++) {
 		const ExpensesType et = _expenses_list_types[type].et[i];
 		if (et == INVALID_EXPENSES) {
@@ -315,7 +363,7 @@
 
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
-		int type = _settings_client.gui.expenses_layout;
+		int type = _settings_game.sharing.sharing_mode != SHARING_NONE ? _settings_client.gui.expenses_layout + 2: _settings_client.gui.expenses_layout;
 		switch (widget) {
 			case CFW_EXPS_CATEGORY:
 				size->width  = _expenses_list_types[type].GetCategoriesWidth();
@@ -404,7 +452,7 @@
 	{
 		if (!small) {
 			/* Check that the expenses panel height matches the height needed for the layout. */
-			int type = _settings_client.gui.expenses_layout;
+			int type = _settings_game.sharing.sharing_mode != SHARING_NONE ? _settings_client.gui.expenses_layout + 2 : _settings_client.gui.expenses_layout;
 			if (_expenses_list_types[type].GetHeight() != this->GetWidget<NWidgetBase>(CFW_EXPS_CATEGORY)->current_y) {
 				this->SetupWidgets();
 				this->ReInit();
@@ -1571,6 +1619,8 @@
 	CW_WIDGET_COLOUR_SCHEME,
 	CW_WIDGET_PRESIDENT_NAME,
 	CW_WIDGET_COMPANY_NAME,
+	CW_WIDGET_SELECT_SHARING,     ///< View/hide the 'sharing' button.
+	CW_WIDGET_SHARING,            ///< Button to open the infrastructure sharing window.
 	CW_WIDGET_BUY_SHARE,
 	CW_WIDGET_SELL_SHARE,
 
@@ -1624,6 +1674,10 @@
 							NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
 							NWidget(NWID_SPACER), SetMinimalSize(90, 0),
 						EndContainer(),
+						NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_SHARING),
+							NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_SHARING), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_SHARING_BUTTON, STR_COMPANY_VIEW_SHARING_TOOLTIP),
+							NWidget(NWID_SPACER), SetMinimalSize(90, 0),
+						EndContainer(),
 						NWidget(NWID_SPACER), SetFill(0, 1),
 					EndContainer(),
 				EndContainer(),
@@ -1696,6 +1750,10 @@
 		CWP_RELOCATE_SHOW = 0, ///< Show the relocate HQ button.
 		CWP_RELOCATE_HIDE,     ///< Hide the relocate HQ button.
 
+		/* Display planes of the #CW_WIDGET_SELECT_SHARING selection widget. */
+		CWP_SHARING_SHOW = 0, ///< Show the sharing button.
+		CWP_SHARING_HIDE,     ///< Hide the sharing button.
+
 		/* Display planes of the #CW_WIDGET_SELECT_BUTTONS selection widget. */
 		CWP_BUTTONS_LOCAL = 0, ///< Buttons of the local company.
 		CWP_BUTTONS_OTHER,     ///< Buttons of the other companies.
@@ -1741,6 +1799,15 @@
 			return;
 		}
 
+		/* Enable/disable 'Sharing' button. */
+		plane = (_settings_game.sharing.sharing_mode == SHARING_INDIVIDUAL) ? CWP_SHARING_SHOW : CWP_SHARING_HIDE;
+		wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_SHARING);
+		if (plane != wi->shown_plane) {
+			wi->SetDisplayedPlane(plane);
+			this->SetDirty();
+			return;
+		}
+
 		/* Multiplayer buttons. */
 		plane = ((!_networking) ? CWP_MP_EMPTY : (local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
 		wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_MULTIPLAYER);
@@ -1946,6 +2013,10 @@
 				DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
 				break;
 
+			case CW_WIDGET_SHARING:
+				ShowCompanySharingSettings((CompanyID)this->window_number);
+				break;
+
 #ifdef ENABLE_NETWORK
 			case CW_WIDGET_COMPANY_PASSWORD:
 				if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
@@ -2135,3 +2206,521 @@
 {
 	AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
 }
+
+/** Some constants used when creating the main panel widgets */
+enum SharingWindowConstants {
+	SWC_NUM_VEHTYPES       = 4,  ///< Number of vehicle types to be displayed
+	SWC_NUM_COMPANIES      = MAX_COMPANIES - 1, ///< Max number of companies to be displayed
+
+	SWC_MARGIN_TOP_BOTTOM  = 5,  ///< Margin between top/bottom edge of the panel and the widgets
+	SWC_MARGIN_LEFT_RIGHT  = 5,  ///< Margin between left/right edge of the panel and the widgets
+	SWC_MARGIN_COLUMNS     = 10, ///< Margin between two columns
+	SWC_MARGIN_LINES       = 2,  ///< Margin between two text lines
+	SWC_MARGIN_BLOCKS      = 8,  ///< Margin between two groups of lines (e.g. between two sets of lines belonging to two vehicle types)
+	SWC_EXTRA_BUTTON_WIDTH = 12, ///< Extra width for buttons, beyond the normal text width
+};
+
+/** per-company sharing settings window */
+enum SharingSettingsWidgets {
+	SSW_CAPTION,        ///< Caption
+	SSW_ICON_PANEL,     ///< Empty widget to draw the train/plane/ship icons on
+	SSW_SELECT_TEXTS,   ///< Selection widget to switch texts column between tabs
+	SSW_SELECT_CURRENT, ///< Selection widget to switch current settings column between tabs
+	SSW_SELECT_FUTURE,  ///< Selection widget to switch future column between tabs
+	SSW_CHANGES_EFFECT, ///< 'Changes take effect in' text widget
+	SSW_OPTIONS,        ///< Options button, switches to the options tab
+	SSW_COMPANIES,      ///< Companies button, switches to the companies tab
+	SSW_OPTION_FIRST,   ///< First widget index of the widgets on the options tab
+
+	/* The following widgets are each repeated SWC_NUM_VEHTYPES times */
+	SSW_OPTION_TEXT_OPTION    = SSW_OPTION_FIRST,                              ///< Text describing the sharing option (e.g. 'Enable sharing of train tracks')
+	SSW_OPTION_CURRENT_OPTION = SSW_OPTION_TEXT_OPTION    + SWC_NUM_VEHTYPES,  ///< Label telling whether the current setting is On or Off
+	SSW_OPTION_FUTURE_OPTION  = SSW_OPTION_CURRENT_OPTION + SWC_NUM_VEHTYPES,  ///< Button to toggle the future setting between On and Off
+	SSW_OPTION_TEXT_FEE       = SSW_OPTION_FUTURE_OPTION  + SWC_NUM_VEHTYPES,  ///< Text describing the sharing fee (e.g. 'Monthly toll for trains')
+	SSW_OPTION_CURRENT_FEE    = SSW_OPTION_TEXT_FEE       + SWC_NUM_VEHTYPES,  ///< Label to display the current fee
+	SSW_OPTION_FUTURE_FEE_INC = SSW_OPTION_CURRENT_FEE    + SWC_NUM_VEHTYPES,  ///< Button to increment the (future) fee
+	SSW_OPTION_FUTURE_FEE_DEC = SSW_OPTION_FUTURE_FEE_INC + SWC_NUM_VEHTYPES,  ///< Button to decrement the (future) fee
+	SSW_OPTION_FUTURE_FEE     = SSW_OPTION_FUTURE_FEE_DEC + SWC_NUM_VEHTYPES,  ///< Widget that shows the future fee
+
+	SSW_COMPANY_FIRST         = SSW_OPTION_FUTURE_FEE     + SWC_NUM_VEHTYPES,  ///< First widget index on the companies tab
+	/* the following widgets are each repeated SWC_NUM_COMPANIES times */
+	SSW_COMPANY_NAME          = SSW_COMPANY_FIRST,                             ///< Text widget displaying the company name
+	SSW_COMPANY_CURRENT       = SSW_COMPANY_NAME          + SWC_NUM_COMPANIES, ///< Label displaying whether the company is currently allowed or not
+	SSW_COMPANY_FUTURE        = SSW_COMPANY_CURRENT       + SWC_NUM_COMPANIES, ///< Button to toggle whether the company will be allowed in the future
+};
+
+/** Window that shows per-company infrastructure sharing settings and allows changing them */
+struct SharingSettingsWindow : public Window {
+private:
+	static const int SHARING_FEE_STEPSIZE = 10;  ///< Stepsize when incrementing or decrementing the sharing fee.
+
+	Company *company;         ///< The company this window belongs to
+	bool companies_tab;       ///< Is the companies tab currently open?
+	uint8 current_query_type; ///< type of vehicle for which a querystring window is open.
+
+	/**
+	 * Seperate a widget number into two parts:
+	 *  - A 'base' from the SharingSettingsWidgets enum, this defines the type of widget.
+	 *  - An 'index' which gives the VehicleType or CompanyID this widget is associated with.
+	 * @param widget The widget number.
+	 * @param index Pointer to the resulting 'index' (see above).
+	 * @return The new 'base' widget number (see above).
+	 */
+	int GetWidgetBaseAndIndex(int widget, int *index) const
+	{
+		int line = 0;
+		if (IsInsideMM(widget, SSW_OPTION_FIRST, SSW_COMPANY_FIRST)) {
+			line = (widget - SSW_OPTION_FIRST) % SWC_NUM_VEHTYPES;
+			*index = line;
+		} else if (widget >= SSW_COMPANY_FIRST) {
+			line = (widget - SSW_COMPANY_FIRST) % SWC_NUM_COMPANIES;
+			/* Determine which compny is shown on that line */
+			int i = 0;
+			*index = INVALID_COMPANY;
+			for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
+				if (Company::IsValidID(c) && c != this->company->index && i++ == line) {
+					*index = c;
+				}
+			}
+		}
+		return widget - line;
+	}
+
+public:
+	/** Constructor */
+	SharingSettingsWindow(const WindowDesc *desc, WindowNumber number) : Window()
+	{
+		this->company = Company::GetIfValid(number);
+		assert(this->company != NULL);
+
+		this->CreateNestedTree(desc, true);
+		this->FinishInitNested(desc, number);
+
+		/* Set this->owner after initializing the nested widgets. Don't use it anywhere in the code for widget resizing etc. ! */
+		this->owner = (Owner)number;
+
+		this->DisableWidget(SSW_OPTIONS);
+		this->InvalidateData();
+	}
+
+	virtual void OnInit()
+	{
+		int num_companies = Company::GetNumItems() - 1;
+		for (int i = 0; i < SWC_NUM_COMPANIES; i++) {
+			this->GetWidget<NWidgetBase>(SSW_COMPANY_FUTURE + i)->type = (i < num_companies) ? WWT_TEXTBTN : WWT_EMPTY;
+		}
+	}
+
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		/* Empty string as default parameter */
+		SetDParam(0, STR_EMPTY);
+		int index;
+		switch (this->GetWidgetBaseAndIndex(widget, &index)) {
+			case SSW_CAPTION:
+				SetDParam(0, this->company->index);
+				break;
+			case SSW_CHANGES_EFFECT:
+				if (this->company->sharing_delay != 0) {
+					SetDParam(0, STR_SHARING_CHANGES_TAKE_EFFECT);
+					SetDParam(1, this->company->sharing_delay);
+				}
+				break;
+			case SSW_OPTION_CURRENT_OPTION:
+				SetDParam(0, this->company->sharing_current.IsSharingAllowed((VehicleType)index) ? STR_SHARING_VALUE_ALLOWED : STR_SHARING_VALUE_NOT_ALLOWED);
+				break;
+			case SSW_OPTION_FUTURE_OPTION:
+				SetDParam(0, this->company->sharing_future.IsSharingAllowed((VehicleType)index) ? STR_SHARING_VALUE_ALLOWED : STR_SHARING_VALUE_NOT_ALLOWED);
+				break;
+			case SSW_OPTION_CURRENT_FEE:
+				SetDParam(0, this->company->sharing_current.GetSharingFee((VehicleType)index));
+				break;
+			case SSW_OPTION_FUTURE_FEE:
+				SetDParam(0, this->company->sharing_future.GetSharingFee((VehicleType)index));
+				break;
+			case SSW_COMPANY_NAME:
+				if (index != INVALID_COMPANY) {
+					SetDParam(0, STR_SHARING_SETTING_COMPANY);
+					SetDParam(1, index);
+				} else if (widget == SSW_COMPANY_NAME) {
+					/* if no companies at all, draw 'No other companies' on the first line */
+					SetDParam(0, STR_SHARING_SETTING_NO_COMPANIES);
+				}
+				break;
+			case SSW_COMPANY_CURRENT:
+				if (index != INVALID_COMPANY) SetDParam(0, this->company->sharing_current.IsCompanyAllowed((CompanyID)index) ? STR_SHARING_VALUE_ALLOWED : STR_SHARING_VALUE_NOT_ALLOWED);
+				break;
+			case SSW_COMPANY_FUTURE:
+				if (index != INVALID_COMPANY) SetDParam(0, this->company->sharing_future.IsCompanyAllowed((CompanyID)index) ? STR_SHARING_VALUE_ALLOWED : STR_SHARING_VALUE_NOT_ALLOWED);
+				break;
+		}
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		if (widget != SSW_ICON_PANEL) return;
+		if (this->companies_tab) {
+			int line = 0;
+			int y_offset = (int)(this->GetWidget<NWidgetBase>(SSW_COMPANY_NAME)->current_y - GetSpriteSize(SPR_COMPANY_ICON).height) / 2;
+			for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
+				if (Company::IsValidID(c) && c != this->company->index) DrawCompanyIcon(c, r.left, this->GetWidget<NWidgetBase>(SSW_COMPANY_NAME + line++)->pos_y + y_offset);
+			}
+		} else {
+			VehicleType type;
+			FOR_ALL_SHARING_VEHTYPES(type) {
+				int y_size   = this->GetWidget<NWidgetBase>(SSW_OPTION_TEXT_FEE)->pos_y + this->GetWidget<NWidgetBase>(SSW_OPTION_TEXT_FEE)->current_y - this->GetWidget<NWidgetBase>(SSW_OPTION_TEXT_OPTION)->pos_y;
+				int y_offset = (y_size - (int)GetSpriteSize(SPR_IMG_TRAINLIST + type).height) / 2;
+				DrawSprite(SPR_IMG_TRAINLIST + type, PAL_NONE, r.left, this->GetWidget<NWidgetBase>(SSW_OPTION_TEXT_OPTION + type)->pos_y + y_offset);
+			}
+		}
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		/* determine the height of a line, which is max(height of [<][>] buttons, height of [text] button) */
+		uint line_height = max<uint>(GetSpriteSize(SPR_ARROW_LEFT).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM, FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
+
+		int index;
+		int base = this->GetWidgetBaseAndIndex(widget, &index);
+		switch (base) {
+			case SSW_ICON_PANEL:
+				VehicleType type;
+				FOR_ALL_SHARING_VEHTYPES(type) {
+					size->width = max(size->width, GetSpriteSize(SPR_IMG_TRAINLIST + type).width);
+				}
+				size->width = max(size->width, GetSpriteSize(SPR_COMPANY_ICON).width);
+				break;
+			case SSW_OPTION_TEXT_OPTION:
+			case SSW_OPTION_TEXT_FEE:
+			case SSW_COMPANY_NAME:
+				/* Always leave the first company name widget visible to show 'no other companies' */
+				size->height = (index != INVALID_COMPANY || widget == SSW_COMPANY_NAME) ? line_height : 0;
+				break;
+			case SSW_OPTION_CURRENT_OPTION:
+			case SSW_OPTION_FUTURE_OPTION:
+			case SSW_COMPANY_CURRENT:
+			case SSW_COMPANY_FUTURE:
+				size->height = (index != INVALID_COMPANY) ? line_height : 0;
+				size->width = maxdim(GetStringBoundingBox(STR_SHARING_VALUE_ALLOWED), GetStringBoundingBox(STR_SHARING_VALUE_NOT_ALLOWED)).width + padding.width;
+				if (base == SSW_OPTION_FUTURE_OPTION || base == SSW_COMPANY_FUTURE) size->width += SWC_EXTRA_BUTTON_WIDTH;
+				break;
+			case SSW_OPTION_CURRENT_FEE:
+			case SSW_OPTION_FUTURE_FEE:
+				size->height = line_height;
+				SetDParam(0, MAX_SHARING_FEE);
+				size->width = GetStringBoundingBox(STR_FINANCES_TOTAL_CURRENCY).width;
+				if (base == SSW_OPTION_FUTURE_FEE) size->width += SWC_EXTRA_BUTTON_WIDTH;
+				break;
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (this->owner != _local_company && widget != SSW_OPTIONS && widget != SSW_COMPANIES) return;
+		int index;
+		switch (this->GetWidgetBaseAndIndex(widget, &index)) {
+			case SSW_OPTIONS:
+			case SSW_COMPANIES:
+				/* Switch to options / companies tab */
+				this->companies_tab = (widget == SSW_COMPANIES);
+				this->SetWidgetDisabledState(SSW_OPTIONS, !this->companies_tab);
+				this->SetWidgetDisabledState(SSW_COMPANIES, this->companies_tab);
+				for (int sel_widget = SSW_SELECT_TEXTS; sel_widget <= SSW_SELECT_FUTURE; sel_widget++) {
+					this->GetWidget<NWidgetStacked>(sel_widget)->SetDisplayedPlane(this->companies_tab);
+				}
+				this->SetDirty();
+				break;
+			case SSW_OPTION_FUTURE_OPTION:
+				DoCommandP(0, MODIFY_SHARING_OPTION | (index << 8), !this->company->sharing_future.IsSharingAllowed((VehicleType)index), CMD_CHANGE_SHARING_SETTING | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SHARING_SETTING));
+				break;
+			case SSW_OPTION_FUTURE_FEE_DEC: {
+				int value = this->company->sharing_future.GetSharingFee((VehicleType)index);
+				value =  value - min(value, SHARING_FEE_STEPSIZE);
+				DoCommandP(0, MODIFY_SHARING_FEE | (index << 8), value, CMD_CHANGE_SHARING_SETTING | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SHARING_SETTING));
+			} break;
+			case SSW_OPTION_FUTURE_FEE_INC: {
+				int value = this->company->sharing_future.GetSharingFee((VehicleType)index);
+				value = min(MAX_SHARING_FEE, value + SHARING_FEE_STEPSIZE);
+				DoCommandP(0, MODIFY_SHARING_FEE | (index << 8), value, CMD_CHANGE_SHARING_SETTING | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SHARING_SETTING));
+			} break;
+			case SSW_OPTION_FUTURE_FEE:
+				/* delete any old query string window */
+				DeleteWindowByClass(WC_QUERY_STRING);
+				this->RaiseWidget(SSW_OPTION_FUTURE_FEE + this->current_query_type);
+				this->SetWidgetDirty(SSW_OPTION_FUTURE_FEE + this->current_query_type);
+
+				this->current_query_type = index;
+				this->LowerWidget(SSW_OPTION_FUTURE_FEE + index);
+				this->SetWidgetDirty(SSW_OPTION_FUTURE_FEE + index);
+				SetDParam(0, this->company->sharing_future.GetSharingFee((VehicleType)index) * _currency->rate);
+				ShowQueryString(STR_JUST_INT, STR_SHARING_CHANGE_FEE_CAPTION, 10, 0, this, CS_NUMERAL, QSF_NONE);
+				break;
+			case SSW_COMPANY_FUTURE:
+				if (index != INVALID_COMPANY) {
+					DoCommandP(0, MODIFY_SHARING_COMPANIES | (index << 8), !this->company->sharing_future.IsCompanyAllowed((CompanyID)index), CMD_CHANGE_SHARING_SETTING | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SHARING_SETTING));
+				}
+				break;
+		}
+	}
+
+	virtual void OnInvalidateData(int data)
+	{
+		if (data != 0) {
+			/* number of companies got changed */
+			this->ReInit();
+		}
+		CompanySharingSettings *settings = &this->company->sharing_future;
+		VehicleType type;
+		FOR_ALL_SHARING_VEHTYPES(type) {
+			/* set option button state */
+			this->SetWidgetLoweredState(SSW_OPTION_FUTURE_OPTION + type, settings->IsSharingAllowed(type));
+			/* enable / disable buttons to increase/decrease the fee */
+			this->SetWidgetDisabledState(SSW_OPTION_FUTURE_FEE_INC + type, settings->GetSharingFee(type) >= MAX_SHARING_FEE);
+			this->SetWidgetDisabledState(SSW_OPTION_FUTURE_FEE_DEC + type, settings->GetSharingFee(type) == 0);
+		}
+
+		/* set buttons on the companies tab */
+		int line = 0;
+		for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
+			if (Company::IsValidID(c) && c != this->company->index) this->SetWidgetLoweredState(SSW_COMPANY_FUTURE + line++, settings->IsCompanyAllowed(c));
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		this->RaiseWidget(SSW_OPTION_FUTURE_FEE + this->current_query_type);
+		this->SetWidgetDirty(SSW_OPTION_FUTURE_FEE + this->current_query_type);
+
+		if (StrEmpty(str)) return;
+		int32 value = atoi(str);
+		value /= _currency->rate;
+		value = Clamp(value, 0, MAX_SHARING_FEE);
+		DoCommandP(0, MODIFY_SHARING_FEE | (this->current_query_type << 8), value, CMD_CHANGE_SHARING_SETTING | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SHARING_SETTING));
+	}
+};
+
+/**
+ * Make a single widget for the option tab.
+ * @note in the case of SSW_OPTION_FUTURE_FEE, three widgets inside a single container are created instead of just one.
+ * @param biggest_index Biggest widget index.
+ * @param widget Widget number of the widget to make.
+ * @param type Vehicle type to make the widget for.
+ * @reutn The newly created widget.
+ */
+static NWidgetBase *MakeOptionWidget(int *biggest_index, int widget, VehicleType type)
+{
+	NWidgetLeaf *leaf;
+	*biggest_index = max(*biggest_index, widget + type);
+	switch (widget) {
+		case SSW_OPTION_TEXT_OPTION:
+		case SSW_OPTION_TEXT_FEE: {
+			/* Text string describing option/fee */
+			StringID str = (widget == SSW_OPTION_TEXT_FEE) ? (type == VEH_TRAIN ? STR_SHARING_SETTING_MONTHLY_TOLL : STR_SHARING_SETTING_FEE) : STR_SHARING_SETTING_RAIL + type;
+			leaf = new NWidgetLeaf(WWT_TEXT, COLOUR_GREY, widget + type, str, STR_NULL);
+		} break;
+		case SSW_OPTION_CURRENT_OPTION:
+		case SSW_OPTION_CURRENT_FEE:
+			/* Current setting of option/fee */
+			leaf = new NWidgetLeaf(WWT_LABEL, COLOUR_GREY, widget + type, widget == SSW_OPTION_CURRENT_FEE ? STR_FINANCES_TOTAL_CURRENCY : STR_JUST_STRING, STR_NULL);
+			break;
+		case SSW_OPTION_FUTURE_OPTION:
+			/* Future setting for option */
+			leaf = new NWidgetLeaf(WWT_TEXTBTN, COLOUR_YELLOW, widget + type, STR_JUST_STRING, STR_FINANCES_TOTAL_CURRENCY);
+			break;
+		case SSW_OPTION_FUTURE_FEE: {
+			NWidgetHorizontal *hor = new NWidgetHorizontal;
+			/* [<] button to decrease fee */
+			leaf = new NWidgetLeaf(NWID_BUTTON_ARROW, COLOUR_YELLOW, SSW_OPTION_FUTURE_FEE_DEC + type, AWV_DECREASE, STR_NULL);
+			hor->Add(leaf);
+			/* current fee, click to open query window */
+			leaf = new NWidgetLeaf(WWT_TEXTBTN, COLOUR_YELLOW, SSW_OPTION_FUTURE_FEE + type, STR_FINANCES_TOTAL_CURRENCY, STR_NULL);
+			leaf->SetFill(1, 0);
+			hor->Add(leaf);
+			/* [>] button to increase fee */
+			leaf = new NWidgetLeaf(NWID_BUTTON_ARROW, COLOUR_YELLOW, SSW_OPTION_FUTURE_FEE_INC + type, AWV_INCREASE, STR_NULL);
+			hor->Add(leaf);
+			/* return here */
+			return hor;
+		}
+		default: NOT_REACHED();
+	}
+	leaf->SetFill(1, 0);
+	return leaf;
+}
+
+/**
+ * Make an entire column of widgets for the options tab. The column contains two widgets per vehicle type.
+ * @param biggest_index Biggest widget index.
+ * @param widget1 Widget number of the first widget to create.
+ * @param widget2 Widget number of the second widget to create.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeOptionWidgetColumn(int *biggest_index, int widget1, int widget2)
+{
+	NWidgetVertical *vert = new NWidgetVertical;
+	vert->SetPIP(0, SWC_MARGIN_LINES, 0);
+	VehicleType type;
+	FOR_ALL_SHARING_VEHTYPES(type) {
+		/* Add extra space between blocks */
+		NWidgetSpacer *spacer = new NWidgetSpacer(0, SWC_MARGIN_BLOCKS - SWC_MARGIN_LINES);
+		vert->Add(spacer);
+		/* Add widgets */
+		vert->Add(MakeOptionWidget(biggest_index, widget1, type));
+		vert->Add(MakeOptionWidget(biggest_index, widget2, type));
+	}
+	return vert;
+}
+
+/**
+ * Create all the widgets for the 'Texts' column on the options tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeOptionTextsColumn(int *biggest_index)
+{
+	return MakeOptionWidgetColumn(biggest_index, SSW_OPTION_TEXT_OPTION, SSW_OPTION_TEXT_FEE);
+}
+
+/**
+ * Create all the widgets for the 'Current settings' column on the options tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeOptionCurrentColumn(int *biggest_index)
+{
+	return MakeOptionWidgetColumn(biggest_index, SSW_OPTION_CURRENT_OPTION, SSW_OPTION_CURRENT_FEE);
+}
+
+/**
+ * Create all the widgets for the 'Future settings' column on the options tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeOptionFutureColumn(int *biggest_index)
+{
+	return MakeOptionWidgetColumn(biggest_index, SSW_OPTION_FUTURE_OPTION, SSW_OPTION_FUTURE_FEE);
+}
+
+/**
+ * Make an entire column of widgets for the companies tab. A column contains one widget per company.
+ * @param biggest_index Biggest widget index.
+ * @param widget Index of the (first) widget to create.
+ * @param tp The type of widget to create.
+ * @param colour The colour of the new widgets.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeCompanyWidgetColumn(int *biggest_index, int widget, WidgetType tp, Colours colour)
+{
+	NWidgetVertical *vert = new NWidgetVertical;
+	vert->SetPIP(SWC_MARGIN_BLOCKS, SWC_MARGIN_LINES, 0);
+
+	for (int i = 0; i < SWC_NUM_COMPANIES; i++) {
+		/* company name */
+		NWidgetLeaf *leaf = new NWidgetLeaf(tp, colour, widget + i, STR_JUST_STRING, STR_NULL);
+		leaf->SetFill(1, 0);
+		vert->Add(leaf);
+	}
+	*biggest_index = max(*biggest_index, widget + SWC_NUM_COMPANIES - 1);
+	return vert;
+}
+
+/**
+ * Create all the widgets for the 'Texts' column on the companies tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeCompanyTextsColumn(int *biggest_index)
+{
+	return MakeCompanyWidgetColumn(biggest_index, SSW_COMPANY_NAME, WWT_TEXT, COLOUR_GREY);
+}
+
+/**
+ * Create all the widgets for the 'Current settings' column on the companies tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeCompanyCurrentColumn(int *biggest_index)
+{
+	return MakeCompanyWidgetColumn(biggest_index, SSW_COMPANY_CURRENT, WWT_LABEL, COLOUR_GREY);
+}
+
+/**
+ * Create all the widgets for the 'Future settings' column on the companies tab.
+ * @param biggest_index Biggest widget index.
+ * @retun A container widget containing the newly created widgets.
+ */
+static NWidgetBase *MakeCompanyFutureColumn(int *biggest_index)
+{
+	return MakeCompanyWidgetColumn(biggest_index, SSW_COMPANY_FUTURE, WWT_TEXTBTN, COLOUR_YELLOW);
+}
+
+/** Nested widget tree for the sharing settings window. */
+static const NWidgetPart _nested_sharing_settings_widgets[] = {
+	NWidget(NWID_HORIZONTAL), // Window header
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY), SetFill(0, 1),
+		NWidget(WWT_CAPTION, COLOUR_GREY, SSW_CAPTION), SetDataTip(STR_SHARING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY), SetFill(0, 1),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_SHARING_PANEL_TOOLTIP), SetPIP(SWC_MARGIN_TOP_BOTTOM, SWC_MARGIN_BLOCKS, SWC_MARGIN_TOP_BOTTOM), // Main Panel
+		NWidget(NWID_HORIZONTAL), SetPIP(SWC_MARGIN_LEFT_RIGHT, SWC_MARGIN_COLUMNS, SWC_MARGIN_LEFT_RIGHT),
+			NWidget(WWT_EMPTY, COLOUR_GREY, SSW_ICON_PANEL), // Space to display the icons on
+			/* First column 'texts', describing each setting. */
+			NWidget(NWID_VERTICAL), SetPIP(0, SWC_MARGIN_LINES, 0),
+				NWidget(NWID_SPACER), SetMinimalTextLines(1, 0),
+				NWidget(NWID_SELECTION, INVALID_COLOUR, SSW_SELECT_TEXTS),
+					NWidgetFunction(MakeOptionTextsColumn),
+					NWidgetFunction(MakeCompanyTextsColumn),
+				EndContainer(),
+			EndContainer(),
+			/* Second column 'Current settings', showing the current value of each setting */
+			NWidget(NWID_VERTICAL), SetPIP(0, SWC_MARGIN_LINES, 0),
+			NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_SHARING_CURRENT, STR_NULL),
+				NWidget(NWID_SELECTION, INVALID_COLOUR, SSW_SELECT_CURRENT),
+					NWidgetFunction(MakeOptionCurrentColumn),
+					NWidgetFunction(MakeCompanyCurrentColumn),
+				EndContainer(),
+			EndContainer(),
+			/* Last column 'Future settings', to show and edit the new value of each setting */
+			NWidget(NWID_VERTICAL), SetPIP(0, SWC_MARGIN_LINES, 0),
+				NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_SHARING_FUTURE, STR_NULL),
+				NWidget(NWID_SELECTION, INVALID_COLOUR, SSW_SELECT_FUTURE),
+					NWidgetFunction(MakeOptionFutureColumn),
+					NWidgetFunction(MakeCompanyFutureColumn),
+				EndContainer(),
+			EndContainer(),
+		EndContainer(),
+		NWidget(NWID_HORIZONTAL), SetPIP(SWC_MARGIN_LEFT_RIGHT, 0, SWC_MARGIN_LEFT_RIGHT),
+			NWidget(WWT_TEXT, COLOUR_GREY, SSW_CHANGES_EFFECT), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0),
+		EndContainer(),
+	EndContainer(),
+	NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+		NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SSW_OPTIONS),   SetResize(1, 0),
+							SetDataTip(STR_SHARING_OPTIONS, STR_SHARING_OPTIONS_TOOLTIP), SetFill(1, 0),
+		NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SSW_COMPANIES), SetResize(1, 0),
+							SetDataTip(STR_SHARING_COMPANIES, STR_SHARING_COMPANIES_TOOLTIP), SetFill(1, 0),
+	EndContainer(),
+};
+
+/** Window description for the sharing settings window. */
+static const WindowDesc _sharing_settings_desc(
+	WDP_AUTO, 0, 0,
+	WC_SHARING_OPTIONS, WC_COMPANY,
+	WDF_UNCLICK_BUTTONS,
+	_nested_sharing_settings_widgets, lengthof(_nested_sharing_settings_widgets)
+);
+
+/**
+ * Show the sharing window of a company.
+ * @param company The company whose window to show.
+ */
+static void ShowCompanySharingSettings(CompanyID company)
+{
+	if ((_settings_game.sharing.sharing_mode == SHARING_INDIVIDUAL) && Company::IsValidID(company)) {
+		AllocateWindowDescFront<SharingSettingsWindow>(&_sharing_settings_desc, company);
+	}
+}
diff -r 779c5a44c6a1 src/depot_gui.cpp
--- a/src/depot_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/depot_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -29,6 +29,7 @@
 #include "tilehighlight_func.h"
 #include "window_gui.h"
 #include "vehiclelist.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -696,7 +697,7 @@
 
 		/* Setup disabled buttons. */
 		TileIndex tile = this->window_number;
-		this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_company),
+		this->SetWidgetsDisabledState(!IsInfraUsageAllowed(tile, _local_company, this->type),
 			DEPOT_WIDGET_STOP_ALL,
 			DEPOT_WIDGET_START_ALL,
 			DEPOT_WIDGET_SELL,
diff -r 779c5a44c6a1 src/economy.cpp
--- a/src/economy.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/economy.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -46,6 +46,7 @@
 #include "waypoint_base.h"
 #include "economy_base.h"
 #include "core/pool_func.hpp"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -387,6 +388,49 @@
 		}
 	}
 
+	/* make the sharing settings the most permissive of the two companies */
+	if (new_owner != INVALID_OWNER) {
+		Company *c_new = Company::Get(new_owner);
+		CompanySharingSettings *old_settings = &Company::Get(old_owner)->sharing_current;
+		CompanySharingSettings *new_settings = &c_new->sharing_current;
+
+		VehicleType type;
+		FOR_ALL_SHARING_VEHTYPES(type) {
+			if (old_settings->IsSharingAllowed(type)) new_settings->SetSharingAllowed(type, true);
+			new_settings->SetSharingFee(type, min(old_settings->GetSharingFee(type), new_settings->GetSharingFee(type)));
+		}
+		for (CompanyID cid = COMPANY_FIRST; cid < MAX_COMPANIES; cid++) {
+			if (Company::IsValidID(cid) && old_settings->IsCompanyAllowed(cid)) new_settings->SetCompanyAllowed(cid, true);
+		}
+
+		/* Make the future settings for the new company the same as the (new) current ones */
+		c_new->sharing_future = *new_settings;
+		c_new->sharing_delay = 0;
+	} else {
+		/* Disable sharing for the old company
+		 * This will cause all vehicles on the old company's infrastructure
+		 * to be removed when ProcessSharingChanges is called */
+		Company *c_old = Company::Get(old_owner);
+		VehicleType type;
+		FOR_ALL_SHARING_VEHTYPES(type) {
+			c_old->sharing_future.SetSharingAllowed(type, false);
+		}
+		c_old->sharing_delay = 0;
+		ProcessSharingChanges();
+	}
+
+	/* disallow the old company from all infrastructure */
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		c->sharing_current.SetCompanyAllowed(old_owner, false);
+		c->sharing_future.SetCompanyAllowed(old_owner, false);
+		/* Future and current settings could now be equal
+		 * In that case, set sharing_delay to 0 */
+		if (c->sharing_current.Equals(&c->sharing_future)) {
+			c->sharing_delay = 0;
+		}
+	}
+
 	/*  Change ownership of tiles */
 	{
 		TileIndex tile = 0;
@@ -699,6 +743,18 @@
 	}
 }
 
+/**
+ * Update the sharing settings of a all companies, if needed.
+ */
+static void CompaniesUpdateSharing()
+{
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		if (c->sharing_delay > 0) --c->sharing_delay;
+	}
+	ProcessSharingChanges();
+}
+
 static void HandleEconomyFluctuations()
 {
 	if (_settings_game.difficulty.economy != 0) {
@@ -1414,6 +1470,7 @@
 		RecomputePrices();
 	}
 	CompaniesPayInterest();
+	CompaniesUpdateSharing();
 	/* Reset the _current_company flag */
 	_current_company = OWNER_NONE;
 	HandleEconomyFluctuations();
diff -r 779c5a44c6a1 src/economy_type.h
--- a/src/economy_type.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/economy_type.h	Wed Dec 16 19:19:57 2009 +0100
@@ -148,6 +148,8 @@
 	EXPENSES_SHIP_INC,
 	EXPENSES_LOAN_INT,
 	EXPENSES_OTHER,
+	EXPENSES_SHARED_RUN,
+	EXPENSES_SHARED_INC,
 	EXPENSES_END,
 	INVALID_EXPENSES      = 0xFF,
 };
diff -r 779c5a44c6a1 src/infrastructure.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infrastructure.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -0,0 +1,441 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file infrastructure.cpp Implementation of infrastructure sharing */
+
+#include "infrastructure_func.h"
+#include "command_func.h"
+#include "window_func.h"
+#include "depot_base.h"
+#include "train.h"
+#include "aircraft.h"
+#include "vehicle_func.h"
+#include "news_func.h"
+#include "strings_func.h"
+#include "pathfinder/yapf/yapf_cache.h"
+#include "date_func.h"
+#include "gfx_func.h"
+#include "company_func.h"
+#include "station_base.h"
+#include "waypoint_base.h"
+
+#include "table/strings.h"
+
+bool CompanySharingSettings::Equals(const CompanySharingSettings *o) const
+{
+	VehicleType type;
+	FOR_ALL_SHARING_VEHTYPES(type) {
+		if (this->IsSharingAllowed(type) != o->IsSharingAllowed(type) || this->GetSharingFee(type) != o->GetSharingFee(type)) return false;
+	}
+	return this->allowed_companies == o->allowed_companies;
+}
+
+void CompanySharingSettings::CopyFromGameSettings()
+{
+	this->SetSharingAllowed(VEH_TRAIN,    _settings_game.sharing.rail_sharing);
+	this->SetSharingAllowed(VEH_ROAD,     _settings_game.sharing.road_sharing);
+	this->SetSharingAllowed(VEH_SHIP,     _settings_game.sharing.water_sharing);
+	this->SetSharingAllowed(VEH_AIRCRAFT, _settings_game.sharing.air_sharing);
+
+	this->SetSharingFee(VEH_TRAIN,    _settings_game.sharing.rail_fee);
+	this->SetSharingFee(VEH_ROAD,     _settings_game.sharing.road_fee);
+	this->SetSharingFee(VEH_SHIP,     _settings_game.sharing.water_fee);
+	this->SetSharingFee(VEH_AIRCRAFT, _settings_game.sharing.air_fee);
+
+	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
+		this->SetCompanyAllowed(c, Company::IsValidID(c));
+	}
+}
+
+/** Some constants regarding the time between two (identical) news messages */
+enum {
+	SHARING_NEWS_INTERVAL_INSOLVENCY     = 60, ///< 60 days between two warnings about company XX not paying because of debts
+	SHARING_NEWS_INTERVAL_SETTING_CHANGE = 10, ///< 10 days between two messages about company XX announcing to change its sharing settings
+};
+
+/**
+ * Add a sharing-related news message to the news stack.
+ * @param string The message string to show.
+ * @param c Company this message is about.
+ * @param param Optional additional parameter to use for drawing the string.
+ */
+static void AddSharingNewsItem(StringID string, Company *c, uint32 param = 0)
+{
+	CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
+	cni->FillData(c);
+
+	SetDParam(0, STR_NEWS_SHARING_TITLE);
+	SetDParam(1, string);
+	SetDParamStr(2, cni->company_name);
+	SetDParam(3, param);
+
+	AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_SHARING, cni);
+}
+
+
+/**
+ * Helper function for transferring sharing fees
+ * @param v The vehicle involved
+ * @param owner The owner of the infrastructure
+ * @param cost Amount to transfer as money fraction (shifted 8 bits to the left)
+ */
+static void PaySharingFee(Vehicle *v, Owner owner, Money cost)
+{
+	Company *c = Company::GetIfValid(v->owner);
+	assert(c != NULL);
+	if (_settings_game.sharing.payment_in_debt || (c->money - c->current_loan) >= (cost >> 8)) {
+		v->profit_this_year -= cost;
+		SubtractMoneyFromCompanyFract(v->owner, CommandCost(EXPENSES_SHARED_RUN, cost));
+		SubtractMoneyFromCompanyFract(owner, CommandCost(EXPENSES_SHARED_INC, -cost));
+	} else if (owner == _local_company && (c->sharing_insolvency_news_date + SHARING_NEWS_INTERVAL_INSOLVENCY) <= _date) {
+		AddSharingNewsItem(STR_NEWS_SHARING_UNABLE_TO_PAY, c);
+		c->sharing_insolvency_news_date = _date;
+	}
+}
+
+/**
+ * Pay the fee for spending a single tick inside a station.
+ * @param v The vehicle that is using the station.
+ * @param st The station that it uses.
+ */
+void PayStationSharingFee(Vehicle *v, const Station *st)
+{
+	if (v->owner == st->owner || st->owner == OWNER_NONE || v->type == VEH_TRAIN) return;
+	Money cost = GetSharingFee(st->owner, v->type);
+	PaySharingFee(v, st->owner, (cost << 8) / DAY_TICKS);
+}
+
+/**
+ * Pay the daily fee for trains on foreign tracks.
+ * @param v The vehicle to pay the fee for.
+ */
+void PayDailyTrackSharingFee(Train *v)
+{
+	Owner owner = GetTileOwner(v->tile);
+	if (owner == v->owner) return;
+	Money cost = GetSharingFee(owner, VEH_TRAIN);
+	cost = (cost << 8) * v->tcache.cached_total_length / 16; //cost is per 16 units = 1 tile
+	cost = cost * 12 / DAYS_IN_YEAR; //cost is per month, but we pay daily.
+	PaySharingFee(v, owner, cost);
+}
+
+/**
+ * Change the sharing settings of a company.
+ * @see ModifySharingFlag
+ * @param tile unused
+ * @param flags operation to perform
+ * @param p1 bitstuffed elements regarding the variable to change:
+ * - p1 = (bit 0 -  7) What to change (boolean option, fee or allowed company)
+ * - p1 = (bit 8 - 15) The vehicle type or company to change it for.
+ * @param p2 value to change the aforementioned variable to
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdChangeSharingSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+	if (_settings_game.sharing.sharing_mode != SHARING_INDIVIDUAL) return CMD_ERROR;
+	byte index = GB(p1, 8, 8); //vehicle type or company id
+
+	Company *c = Company::GetIfValid(_current_company);
+	if (c == NULL) return CMD_ERROR;
+
+	ModifySharingFlag msf = (ModifySharingFlag)GB(p1, 0, 8);
+	switch (msf) {
+		case MODIFY_SHARING_OPTION:
+			if (index >= NUM_SHARING_VEHTYPES) return CMD_ERROR;
+			if (!!p2 == c->sharing_future.IsSharingAllowed((VehicleType)index)) return CMD_ERROR;
+			break;
+		case MODIFY_SHARING_FEE:
+			if (index >= NUM_SHARING_VEHTYPES) return CMD_ERROR;
+			if (p2 > MAX_SHARING_FEE || p2 == c->sharing_future.GetSharingFee((VehicleType)index)) return CMD_ERROR;
+			break;
+		case MODIFY_SHARING_COMPANIES:
+			if (!Company::IsValidID(index) || index == _current_company) return CMD_ERROR;
+			if (!!p2 == c->sharing_future.IsCompanyAllowed((CompanyID)index)) return CMD_ERROR;
+			break;
+		default: return CMD_ERROR;
+	}
+
+	if (flags & DC_EXEC) {
+		switch (msf) {
+			case MODIFY_SHARING_OPTION:    c->sharing_future.SetSharingAllowed((VehicleType)index, p2 != 0); break;
+			case MODIFY_SHARING_FEE:       c->sharing_future.SetSharingFee((VehicleType)index, p2);          break;
+			case MODIFY_SHARING_COMPANIES: c->sharing_future.SetCompanyAllowed((CompanyID)index, p2 != 0);   break;
+			default: NOT_REACHED();
+		}
+
+		/* Set the sharing delay, and copy the future settings to the current settings if needed */
+		if (c->sharing_future.Equals(&c->sharing_current)) {
+			c->sharing_delay = 0;
+		} else if (_settings_game.sharing.new_individual_delay == 0) {
+			assert(c->sharing_delay == 0);
+			ProcessSharingChanges();
+		} else {
+			c->sharing_delay = _settings_game.sharing.new_individual_delay;
+			if (_current_company != _local_company && c->sharing_setting_change_news_date + SHARING_NEWS_INTERVAL_SETTING_CHANGE <= _date) {
+				c->sharing_setting_change_news_date = _date;
+				AddSharingNewsItem(STR_NEWS_SHARING_CHANGE_ANNOUNCED, c, c->sharing_delay);
+			}
+		}
+		InvalidateWindowData(WC_SHARING_OPTIONS, _current_company);
+	}
+	return CommandCost();
+}
+
+/**
+ * Helper function to determine if sharing is allowed according to the *new* sharing settings.
+ * @see IsInfraUsageAllowed(Owner, Owner, VehicleType)
+ * @param infra_owner The owner of the infrastructure.
+ * @param v           The vehicle that wants to use the infrastructure of infra_owner.
+ * @return            True if sharing will be enabled after processing the changes, false otherwise.
+ */
+bool IsNewInfraUsageAllowed(Owner infra_owner, const Vehicle *v)
+{
+	if (infra_owner == v->owner || infra_owner == OWNER_NONE) return true;
+	assert(Company::IsValidID(infra_owner));
+	Company *c = Company::Get(infra_owner);
+	return c->sharing_delay == 0 ? c->sharing_future.IsCompanySharingAllowed(v->type, v->owner) : c->sharing_future.IsCompanySharingAllowed(v->type, v->owner);
+}
+
+/**
+ * Sell a vehicle, no matter where it may be.
+ * @param v The vehicle to sell
+ * @param num_sold_local_vehicles Number of sold vehicles owned by the local company. To be increased by one if applicable.
+ */
+static void RemoveAndSellVehicle(Vehicle *v, uint &num_sold_local_vehicles)
+{
+	if (v->owner == _local_company) num_sold_local_vehicles++;
+
+	/* compute total value and give that to the owner */
+	Money value = 0;
+	for (Vehicle *u = v->First(); u != NULL; u = u->Next()) {
+		value += v->value;
+	}
+	SubtractMoneyFromCompanyFract(v->owner, CommandCost(EXPENSES_NEW_VEHICLES, -(value << 8)));
+
+	if (v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
+		DeleteVisibleTrain(Train::From(v));
+	} else {
+		delete v;
+	}
+}
+
+/**
+ * Check the positions of all vehicles.
+ * If it is not in an allowed position,
+ * (e.g. a train is on foreign tracks when the owner disables sharing)
+ * then it is sold immediately.
+ * @param changed_vehtypes bitmask of vehicle types that were affected by a sharing setting change.
+ * @return The number of vehicles owned by the local company that have been sold.
+ */
+static uint CheckAllVehiclePositions(byte changed_vehtypes)
+{
+	uint num_sold_local_vehicles = 0;
+	Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (!(v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && Train::From(v)->IsFreeWagon()))) continue;
+		if (!HasBit(changed_vehtypes, v->type)) continue;
+		switch (v->type) {
+			case VEH_TRAIN:
+				for (Vehicle *u = v; u != NULL; u = u->Next()) {
+					/* If any wagon is on a disallowed tile, sell the entire train */
+					if (!IsNewInfraUsageAllowed(GetTileOwner(u->tile), u)) {
+						RemoveAndSellVehicle(v, num_sold_local_vehicles);
+						break;
+					}
+				}
+				break;
+			case VEH_ROAD:
+				for (Vehicle *u = v; u != NULL; u = u->Next()) {
+					/* Check all articulated parts */
+					if ((IsRoadDepotTile(u->tile) || IsStandardRoadStopTile(u->tile)) && !IsNewInfraUsageAllowed(GetTileOwner(u->tile), u)) {
+						RemoveAndSellVehicle(v, num_sold_local_vehicles);
+						break;
+					}
+				}
+				break;
+			case VEH_SHIP:
+				if (IsShipDepotTile(v->tile) && v->IsStoppedInDepot() && !IsNewInfraUsageAllowed(GetTileOwner(v->tile), v)) {
+					RemoveAndSellVehicle(v, num_sold_local_vehicles);
+				}
+				break;
+			case VEH_AIRCRAFT: {
+				Aircraft *a = Aircraft::From(v);
+				if (a->state == FLYING) break;
+				if (Station::IsValidID(a->targetairport) && !IsNewInfraUsageAllowed(Station::Get(a->targetairport)->owner, v)) {
+						RemoveAndSellVehicle(v, num_sold_local_vehicles);
+				}
+				break;
+			}
+			default: break;
+		}
+	}
+	return num_sold_local_vehicles;
+}
+
+/**
+ * Check whether an order has an allowed destination.
+ * I.e. it refers to a station/depot/waypoint the vehicle is allowed to visit.
+ * @param o The order to check
+ * @param v The vehicle this order belongs to.
+ * @return true if the order has an allowed destination.
+ */
+static bool OrderDestinationIsAllowed(const Order *o, const Vehicle *v)
+{
+	DestinationID dest = o->GetDestination();
+	switch (o->GetType()) {
+		case OT_GOTO_STATION:  return IsNewInfraUsageAllowed(Station::Get(dest)->owner, v);
+		case OT_GOTO_DEPOT:    return IsNewInfraUsageAllowed(v->type == VEH_AIRCRAFT ? Station::Get(dest)->owner : GetTileOwner(Depot::Get(dest)->xy), v);
+		case OT_GOTO_WAYPOINT: return IsNewInfraUsageAllowed(Waypoint::Get(dest)->owner, v);
+		default: return true;
+	}
+}
+
+/**
+ * Review the orders of all vehicles
+ * This makes sure they don't have any orders to destinations
+ * where they are not allowed to go.
+ * @param changed_vehtypes bitmask of vehicle types that were affected by a sharing setting change.
+ */
+static void ReviewAllVehicleOrders(byte changed_vehtypes)
+{
+	Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (!(v->IsPrimaryVehicle() && HasBit(changed_vehtypes, v->type))) continue;
+
+		if (!OrderDestinationIsAllowed(&v->current_order, v)) {
+			v->current_order.MakeDummy();
+			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
+		} else if (v->current_order.IsType(OT_LOADING)) {
+			if (!IsNewInfraUsageAllowed(Station::Get(v->last_station_visited)->owner, v)) {
+				v->LeaveStation();
+			}
+		}
+
+		if (v->FirstShared() != v) continue;
+
+		Order *o;
+		int id = -1;
+		FOR_VEHICLE_ORDERS(v, o) {
+			id++;
+			if (OrderDestinationIsAllowed(o, v)) continue;
+
+			o->MakeDummy();
+			for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
+				/* In GUI, simulate by removing the order and adding it back */
+				InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
+				InvalidateVehicleOrder(w, (id << 8) | INVALID_VEH_ORDER_ID);
+			}
+		}
+	}
+}
+
+/** Bitmask of all relevant vehicle types. */
+static const byte ALL_SHARING_VEHTYPES = (1 << VEH_TRAIN) | (1 << VEH_ROAD) | (1 << VEH_SHIP) | (1 << VEH_AIRCRAFT);
+
+/**
+ * Handle a change of sharing settings.
+ * This involves checking all orders,
+ * making sure all vehicles are not on disallowed territory,
+ * checking all PBS paths
+ * and updating signals.
+ * @param update_signals Force updating all signals on the map.
+ */
+void ProcessSharingChanges()
+{
+	byte changed_vehtypes = 0;
+	CompanyMask changed_companies = 0;
+
+	/* Collect a bitmask of vehicle types that will be negatively affected by the new settings.
+	 * And also a bitmask of companies whose settings were changed.
+	 * N.B. Changes to the fee have no effect on changed_vehtypes. So there could still be changes when changed_vehtypes == 0.
+	 * However if there are any changes changed_companies will not be 0 */
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		if (c->sharing_delay != 0 || c->sharing_current.Equals(&c->sharing_future)) continue;
+		SetBit(changed_companies, c->index);
+		VehicleType type;
+		FOR_ALL_SHARING_VEHTYPES(type) {
+			if (c->sharing_current.IsSharingAllowed(type) && !c->sharing_future.IsSharingAllowed(type)) {
+				SetBit(changed_vehtypes, type);
+			}
+		}
+		Company *c2;
+		FOR_ALL_COMPANIES(c2) {
+			if (c->sharing_current.IsCompanyAllowed(c2->index) && !c->sharing_future.IsCompanyAllowed(c2->index)) {
+				changed_vehtypes = ALL_SHARING_VEHTYPES;
+			}
+		}
+	}
+	InvalidateWindowClassesData(WC_SHARING_OPTIONS);
+	if (changed_companies == 0) return;
+
+	uint num_sold_local_vehicles = 0;
+	if (changed_vehtypes != 0)  {
+		/* Invalidate the entire cache */
+		YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
+
+		num_sold_local_vehicles = CheckAllVehiclePositions(changed_vehtypes);
+		ReviewAllVehicleOrders(changed_vehtypes);
+	}
+
+	if (ClrBit(changed_companies, _local_company) != 0) {
+		Company *news_company = Company::GetIfValid(FindFirstBit(changed_companies));
+		assert(news_company != NULL);
+		AddSharingNewsItem(STR_NEWS_SHARING_CHANGE_HAPPENED, news_company);
+		if (num_sold_local_vehicles != 0) {
+			AddSharingNewsItem(STR_NEWS_SHARING_SOLD_VEHICLES, news_company, num_sold_local_vehicles);
+		}
+	}
+
+	/* Apply the changes to the sharing settings */
+	FOR_ALL_COMPANIES(c) {
+		if (c->sharing_delay == 0) c->sharing_current = c->sharing_future;
+	}
+
+}
+
+/** Small struct to store a tile/track combination */
+struct SignalPosition {
+	TileIndex tile;  ///< Tile of the signal.
+	Track     track; ///< Track piece of the signal.
+	/** Create a new SignalPosition based on given tile and track piece */
+	SignalPosition(TileIndex _tile, Track _track) : tile(_tile), track(_track) {};
+};
+
+/**
+ * Update all signals on the map.
+ * Since whe do not know which ones are affected by the sharing change, we invalidate them all.
+ * Updating signals can only be done on a per-company basis.
+ * Therefore, we cache all signals into lists, one per company
+ * Then we update all signals in each list.
+ */
+void UpdateAllBlockSignals()
+{
+	static SmallVector<SignalPosition, 256> signal_lists[MAX_COMPANIES];
+
+	for (TileIndex tile = 0; tile < MapSize(); tile++) {
+		if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile)) {
+			TrackBits bits = GetTrackBits(tile);
+			do {
+				Track track = RemoveFirstTrack(&bits);
+				if (HasSignalOnTrack(tile, track)) {
+					*signal_lists[GetTileOwner(tile)].Append() = SignalPosition(tile, track);
+				}
+			} while (bits != TRACK_BIT_NONE);
+		}
+	}
+	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
+		for (uint i = 0; i < signal_lists[c].Length(); i++) {
+			AddTrackToSignalBuffer(signal_lists[c][i].tile, signal_lists[c][i].track, c);
+		}
+		UpdateSignalsInBuffer();
+		signal_lists[c].Reset();
+	}
+}
diff -r 779c5a44c6a1 src/infrastructure.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infrastructure.h	Wed Dec 16 19:19:57 2009 +0100
@@ -0,0 +1,147 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file infrastructure.h Define struct and enums for (shared) infrastructure */
+
+#ifndef INFRASTRUCTURE_H
+#define INFRASTRUCTURE_H
+
+#include "stdafx.h"
+#include "core/bitmath_func.hpp"
+#include "vehicle_type.h"
+#include "company_type.h"
+
+/** Sharing modes; possible values for the sharing_mode setting. */
+enum SharingMode {
+	SHARING_NONE,       ///< No infrastructure sharing at all
+	SHARING_GLOBAL,     ///< Sharing enabled with global (advanced) settings
+	SHARING_INDIVIDUAL, ///< Sharing enabled with individually configurable settings
+};
+
+/** which part of the sharing settings do we want to modify? */
+enum ModifySharingFlag {
+	MODIFY_SHARING_OPTION,    ///< Modify access to station / depot / tracks
+	MODIFY_SHARING_FEE,       ///< Modify the sharing fee
+	MODIFY_SHARING_COMPANIES, ///< Modify which companies are allowed
+};
+
+/** maximum fee (in pounds) for any of the sharing fees */
+static const uint MAX_SHARING_FEE = 50000;
+
+/** number of relevant vehicle types */
+static const byte NUM_SHARING_VEHTYPES = 4;
+
+/** Struct to store all the sharing settings of a company (either current or future ones) */
+struct CompanySharingSettings {
+private:
+	friend const struct SaveLoad *GetCompanySharingSettingsDescription();
+
+	byte allowed_types;               ///< Bitmask of vehicle types for which sharing is enabled.
+	CompanyMask allowed_companies;    ///< Bitmask of companies for which sharing is enabled.
+	uint16 fee[NUM_SHARING_VEHTYPES]; ///< Fees for rail/road/water/air.
+
+public:
+	/** Constructor */
+	CompanySharingSettings() {}
+
+	/**
+	 * Compare two sets of sharing settings with eachother.
+	 * @param o The sharing settings entry to compare with.
+	 * @return True if all settings are equal, false otherwise.
+	 */
+	bool Equals(const CompanySharingSettings *o) const;
+
+	/**
+	 * Fill this struct with the values from _settings_game.
+	 * This also enables all companies in the allowed_companies mask.
+	 */
+	void CopyFromGameSettings();
+
+	/**
+	 * Is sharing allowed for a vehicle type?
+	 * @param type The vehicle type.
+	 * @return True if infrastructure sharing is enabled for that vehicle type.
+	 */
+	FORCEINLINE bool IsSharingAllowed(VehicleType type) const
+	{
+		assert(type < NUM_SHARING_VEHTYPES);
+		return HasBit(this->allowed_types, type);
+	}
+
+	/**
+	 * Check whether a company is allowed to use the infrastructure.
+	 * i.e. it's corresponding bit in allowed_companies is set.
+	 * @param c The company to check.
+	 * @return true if the given company is allowed to use the infrastructure
+	 */
+	FORCEINLINE bool IsCompanyAllowed(CompanyID c) const
+	{
+		assert(c < MAX_COMPANIES);
+		return HasBit(this->allowed_companies, c);
+	}
+
+	/**
+	 * Is sharing allowed for a vehicle of a given type and owner?
+	 * @param type Type of the vehicle.
+	 * @param c Owner of the vehicle.
+	 * @return True if infrastructure sharing is allowed, false otherwise.
+	 */
+	FORCEINLINE bool IsCompanySharingAllowed(VehicleType type, CompanyID c) const
+	{
+		return this->IsSharingAllowed(type) && this->IsCompanyAllowed(c);
+	}
+
+	/**
+	 * Get the sharing fee for a specified vehicle type.
+	 * @param type The vehicle type.
+	 * @return The sharing fee for the given vehicle type.
+	 */
+	FORCEINLINE uint16 GetSharingFee(VehicleType type) const
+	{
+		assert(type < NUM_SHARING_VEHTYPES);
+		return this->fee[type];
+	}
+
+	/**
+	 * Allow or disallow sharing for a vehicle type.
+	 * @param type The vehicle type.
+	 * @param value Allow sharing if true, disallow if false.
+	 */
+	FORCEINLINE void SetSharingAllowed(VehicleType type, bool value)
+	{
+		assert(type < NUM_SHARING_VEHTYPES);
+		SB(this->allowed_types, type, 1, !!value);
+	}
+
+	/**
+	 * Allow or disallow a company to use the infrastructure.
+	 * @param c The index of the company to allow or disallow.
+	 * @param value Allow sharing if true, disallow if false.
+	 */
+	FORCEINLINE void SetCompanyAllowed(CompanyID c, bool value)
+	{
+		assert(c < MAX_COMPANIES);
+		SB(this->allowed_companies, c, 1, !!value);
+	}
+
+	/**
+	 * Set the sharing fee for a specified vehicle type.
+	 * @param type The vehicle type.
+	 * @param value The new sharing fee.
+	 */
+	FORCEINLINE void SetSharingFee(VehicleType type, uint16 value)
+	{
+		assert(type < NUM_SHARING_VEHTYPES);
+		this->fee[type] = value;
+	}
+};
+
+#define FOR_ALL_SHARING_VEHTYPES(var) for (var = VEH_TRAIN; var < NUM_SHARING_VEHTYPES; var++)
+
+#endif /* INFRASTRUCTURE_H */
diff -r 779c5a44c6a1 src/infrastructure_func.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infrastructure_func.h	Wed Dec 16 19:19:57 2009 +0100
@@ -0,0 +1,127 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file infrastructure_func.h Functions for infrastructure sharing */
+
+#ifndef INFRASTRUCTURE_FUNC_H
+#define INFRASTRUCTURE_FUNC_H
+
+#include "infrastructure.h"
+#include "functions.h"
+#include "company_base.h"
+#include "vehicle_base.h"
+#include "company_func.h"
+
+void PayStationSharingFee(Vehicle *v, const Station *st);
+void PayDailyTrackSharingFee(Train *v);
+void ProcessSharingChanges();
+void UpdateAllBlockSignals();
+
+/**
+ * Get whether a vehicle of a given owner and type can use the infrastrucutre of a company.
+ * This function has three other versions with slightly different parameters.
+ * All functions basically work the same. Possible parameter variations:
+ * - A tile instead of the infrastructure owner. The infrastructure owner is then equal to GetTileOwner(tile).
+ * - A vehicle instead of a vehicle owner and vehicle type. Use the owner and type of the vehicle.
+ * @param infra_owner The owner of the infrastructure.
+ * @param veh_owner   Owner of the vehicle in question.
+ * @param type        Type of vehicle we are talking about.
+ * @return            True if sharing is enabled, false otherwise.
+ */
+static inline bool IsInfraUsageAllowed(Owner infra_owner, Owner veh_owner, VehicleType type)
+{
+	assert(Company::IsValidID(infra_owner) || infra_owner == OWNER_NONE);
+	return infra_owner == veh_owner || infra_owner == OWNER_NONE || Company::Get(infra_owner)->sharing_current.IsCompanySharingAllowed(type, veh_owner);
+}
+
+/** @see IsInfraUsageAllowed(Owner, Owner, VehicleType) */
+static FORCEINLINE bool IsInfraUsageAllowed(Owner owner, const Vehicle *v)
+{
+	return IsInfraUsageAllowed(owner, v->owner, v->type);
+}
+
+/** @see IsInfraUsageAllowed(Owner, Owner, VehicleType) */
+static FORCEINLINE bool IsInfraUsageAllowed(TileIndex tile, Owner veh_owner, VehicleType type)
+{
+	return IsInfraUsageAllowed(GetTileOwner(tile), veh_owner, type);
+}
+
+/** @see IsInfraUsageAllowed(Owner, Owner, VehicleType) */
+static FORCEINLINE bool IsInfraUsageAllowed(TileIndex tile, const Vehicle *v)
+{
+	return IsInfraUsageAllowed(GetTileOwner(tile), v->owner, v->type);
+}
+
+/**
+ * Is a vehicle owned by _current_company allowed to use the infrastructure?
+ * @see IsInfraUsageAllowed(Owner, Owner, VehicleType)
+ * @note This function is to be used in DoCommands.
+ * @param infra_owner Owner of the infrastructure.
+ * @param type Type of vehicle.
+ * @return True if usage of the infrastructure is allowed.
+ */
+static inline bool CheckInfraUsageAllowed(Owner infra_owner, VehicleType type)
+{
+	return CheckOwnership(infra_owner) || IsInfraUsageAllowed(infra_owner, _current_company, type);
+}
+
+/** @see CheckInfraUsageAllowed(Owner, VehicleType) */
+static inline bool CheckInfraUsageAllowed(TileIndex tile, VehicleType type)
+{
+	return CheckTileOwnership(tile) || IsInfraUsageAllowed(GetTileOwner(tile), _current_company, type);
+}
+
+/**
+ * Get the sharing fee the infrastructure owner asks for using the infrastructure for a vehicle type.
+ * @param owner The owner of the infrastructure.
+ * @param type The vehicle type.
+ * @return The sharing fee that applies here.
+ */
+static inline uint16 GetSharingFee(Owner owner, VehicleType type)
+{
+	assert(Company::IsValidID(owner));
+	return Company::Get(owner)->sharing_current.GetSharingFee(type);
+}
+
+
+/**
+ * Check whether a given company can control this vehicle.
+ * The vehicle owner can always control a vehicle.
+ * Trains on foreign tracks can also be controlled by the track owner.
+ * Controlling a train means permission to start, stop or reverse it or to make it ignore signals.
+ * This function has one alias, which does not take a company as parameter. Instead it uses _current_company.
+ * This is very useful in DoCommands, since it uses Check[Tile]Ownership. (It gives nice error messages when failing)
+ * @param v The vehicle which may or may not be controlled.
+ * @param o The company which may or may not control this vehicle
+ * @return true if the given company is allowed to control this vehicle.
+ */
+static inline bool IsVehicleControlAllowed(const Vehicle *v, Owner o)
+{
+	return v->owner == o || (v->type == VEH_TRAIN && IsTileOwner(v->tile, o));
+}
+
+/** @see IsVehicleControlAllowed(const Vehicle *, Owner) */
+static inline bool IsVehicleControlAllowed(const Vehicle *v)
+{
+	return CheckOwnership(v->owner) || (v->type == VEH_TRAIN && CheckTileOwnership(v->tile));
+}
+
+/**
+ * Are the tracks of two owners part of the same signal block?
+ * This is the case if the owners are equal, or if infrastructure sharing is enabled
+ * @param o1 First company.
+ * @param o2 Second company.
+ * @return true if the tracks of the given owners are part of the same signal block
+ */
+static inline bool AreSignalBlocksJoined(Owner o1, Owner o2)
+{
+	return (o1 == o2) || (_settings_game.sharing.sharing_mode != SHARING_NONE);
+}
+
+#endif /* INFRASTRUCTURE_FUNC_H */
diff -r 779c5a44c6a1 src/lang/english.txt
--- a/src/lang/english.txt	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/lang/english.txt	Wed Dec 16 19:19:57 2009 +0100
@@ -789,6 +789,12 @@
 STR_NEWS_SHIP_IS_WAITING                                        :{WHITE}{VEHICLE} is waiting in depot
 STR_NEWS_AIRCRAFT_IS_WAITING                                    :{WHITE}{VEHICLE} is waiting in the aircraft hangar
 
+STR_NEWS_SHARING_TITLE                                          :{BLACK}{BIGFONT}Infrastructure sharing news!
+STR_NEWS_SHARING_CHANGE_ANNOUNCED                               :{BLACK}{BIGFONT}{RAW_STRING} announced to change its infrastructure sharing settings in {NUM} month{P "" s}!
+STR_NEWS_SHARING_CHANGE_HAPPENED                                :{BLACK}{BIGFONT}{RAW_STRING} has changed its infrastructure sharing settings!
+STR_NEWS_SHARING_SOLD_VEHICLES                                  :{BLACK}{BIGFONT}Because of a change in infrastructure sharing settings, {3:COMMA} of your vehicles {P was were} sold!
+STR_NEWS_SHARING_UNABLE_TO_PAY                                  :{BLACK}{BIGFONT}{RAW_STRING} is in debt and cannot pay sharing fees to you!
+
 # Start of order review system.
 # DON'T ADD OR REMOVE LINES HERE
 STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS                             :{WHITE}{VEHICLE} has too few orders in the schedule
@@ -1266,6 +1272,21 @@
 STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER                         :{LTBLUE}Initial city size multiplier: {ORANGE}{STRING1}
 STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD                        :{LTBLUE}Remove absurd road-elements during the road construction: {ORANGE}{STRING1}
 
+STR_CONFIG_SETTING_SHARING_ENABLE                               :{LTBLUE}Infrastructure sharing mode: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_ENABLE_OFF                           :Off
+STR_CONFIG_SETTING_SHARING_ENABLE_GLOBAL                        :On, global settings
+STR_CONFIG_SETTING_SHARING_ENABLE_INDIVIDUAL                    :On, individual settings
+STR_CONFIG_SETTING_SHARING_INDIVIDUAL_TIME                      :{LTBLUE}Delay for new individual settings to take effect: {ORANGE}{STRING1} months
+STR_CONFIG_SETTING_SHARING_PAYMENT_DEBT                         :{LTBLUE}Allow companies in debt to pay sharing fees: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_RAIL                                 :{LTBLUE}Railways: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_ROAD                                 :{LTBLUE}Road stops and depots: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_WATER                                :{LTBLUE}Docks and ship depots: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_AIR                                  :{LTBLUE}Airports: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_RAIL_FEE                             :{LTBLUE}Monthly track toll: {ORANGE}{STRING1} per train tile
+STR_CONFIG_SETTING_SHARING_ROAD_FEE                             :{LTBLUE}Stopping fee for road vehicles: {ORANGE}{STRING1} per day
+STR_CONFIG_SETTING_SHARING_WATER_FEE                            :{LTBLUE}Docking fee for ship: {ORANGE}{STRING1} per day
+STR_CONFIG_SETTING_SHARING_AIR_FEE                              :{LTBLUE}Terminal fee for aircraft: {ORANGE}{STRING1} per day
+
 STR_CONFIG_SETTING_GUI                                          :{ORANGE}Interface
 STR_CONFIG_SETTING_CONSTRUCTION                                 :{ORANGE}Construction
 STR_CONFIG_SETTING_VEHICLES                                     :{ORANGE}Vehicles
@@ -1277,6 +1298,8 @@
 STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS                         :{ORANGE}Signals
 STR_CONFIG_SETTING_STATIONS_CARGOHANDLING                       :{ORANGE}Cargo handling
 STR_CONFIG_SETTING_AI_NPC                                       :{ORANGE}Computer players
+STR_CONFIG_SETTING_AI_SHARING                                   :{ORANGE}Infrastructure sharing
+STR_CONFIG_SETTING_AI_SHARING_GLOBAL                            :{ORANGE}Global settings
 STR_CONFIG_SETTING_VEHICLES_AUTORENEW                           :{ORANGE}Autorenew
 STR_CONFIG_SETTING_VEHICLES_SERVICING                           :{ORANGE}Servicing
 STR_CONFIG_SETTING_VEHICLES_ROUTING                             :{ORANGE}Routing
@@ -2510,6 +2533,8 @@
 STR_FINANCES_SECTION_SHIP_INCOME                                :{GOLD}Ship Income
 STR_FINANCES_SECTION_LOAN_INTEREST                              :{GOLD}Loan Interest
 STR_FINANCES_SECTION_OTHER                                      :{GOLD}Other
+STR_FINANCES_SECTION_INFRASTRUCTURE_COSTS                       :{GOLD}Infrastructure Costs
+STR_FINANCES_SECTION_INFRASTRUCTURE_INCOME                      :{GOLD}Infrastructure Income
 STR_FINANCES_NEGATIVE_INCOME                                    :{BLACK}-{CURRENCY}
 STR_FINANCES_POSITIVE_INCOME                                    :{BLACK}+{CURRENCY}
 STR_FINANCES_TOTAL_CAPTION                                      :{WHITE}Total:
@@ -2544,6 +2569,9 @@
 STR_COMPANY_VIEW_RELOCATE_HQ                                    :{BLACK}Relocate HQ
 STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS                  :{BLACK}Rebuild company headquarters elsewhere for 1% cost of company value
 
+STR_COMPANY_VIEW_SHARING_BUTTON                                 :{BLACK}Sharing
+STR_COMPANY_VIEW_SHARING_TOOLTIP                                :{BLACK}Set the sharing options for your infrastructure
+
 STR_COMPANY_VIEW_NEW_FACE_BUTTON                                :{BLACK}New Face
 STR_COMPANY_VIEW_NEW_FACE_TOOLTIP                               :{BLACK}Select new face for manager
 STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON                           :{BLACK}Colour Scheme
@@ -2563,6 +2591,31 @@
 
 STR_BUY_COMPANY_MESSAGE                                         :{WHITE}We are looking for a transport company to take-over our company.{}{}Do you want to purchase {COMPANY} for {CURRENCY}?
 
+#Infrastructure sharing window
+STR_SHARING_CAPTION                                             :{WHITE}{COMPANY} - Infrastructure sharing
+STR_SHARING_PANEL_TOOLTIP                                       :{BLACK}View and edit the infrastructure sharing settings for this company.
+STR_SHARING_OPTIONS                                             :{BLACK}Options
+STR_SHARING_OPTIONS_TOOLTIP                                     :{BLACK}View and edit the sharing options
+STR_SHARING_COMPANIES                                           :{BLACK}Companies
+STR_SHARING_COMPANIES_TOOLTIP                                   :{BLACK}View and edit which companies are allowed on infrastructure of this company
+
+STR_SHARING_CURRENT                                             :{BLACK}Currently:
+STR_SHARING_FUTURE                                              :{BLACK}In the future:
+STR_SHARING_SETTING_RAIL                                        :{BLACK}Railways:
+STR_SHARING_SETTING_ROAD                                        :{BLACK}Road stops and depots:
+STR_SHARING_SETTING_WATER                                       :{BLACK}Docks and ship depots:
+STR_SHARING_SETTING_AIR                                         :{BLACK}Airports:
+STR_SHARING_SETTING_MONTHLY_TOLL                                :{BLACK}Monthly toll per train tile:
+STR_SHARING_SETTING_FEE                                         :{BLACK}Loading fee per day:
+STR_SHARING_SETTING_COMPANY                                     :{BLACK}{COMPANY}:
+STR_SHARING_SETTING_NO_COMPANIES                                :{BLACK}No other companies
+
+STR_SHARING_VALUE_ALLOWED                                       :{BLACK}Allowed
+STR_SHARING_VALUE_NOT_ALLOWED                                   :{BLACK}Not allowed
+
+STR_SHARING_CHANGES_TAKE_EFFECT                                 :{WHITE}Changes will take effect in {NUM} month{P "" s}
+STR_SHARING_CHANGE_FEE_CAPTION                                  :{WHITE}Change the sharing fee
+
 # Industry directory
 STR_INDUSTRY_DIRECTORY_CAPTION                                  :{WHITE}Industries
 STR_INDUSTRY_DIRECTORY_NONE                                     :{ORANGE}- None -
@@ -3315,6 +3368,7 @@
 STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS                            :{WHITE}Can't buy 25% share in this company...
 STR_ERROR_CAN_T_SELL_25_SHARE_IN                                :{WHITE}Can't sell 25% share in this company...
 STR_ERROR_PROTECTED                                             :{WHITE}This company is not old enough to trade shares yet...
+STR_ERROR_CAN_T_CHANGE_SHARING_SETTING                          :{WHITE}Can't change the infrastructure sharing settings...
 
 # Town related errors
 STR_ERROR_CAN_T_GENERATE_TOWN                                   :{WHITE}Can't build any towns
diff -r 779c5a44c6a1 src/news_func.h
--- a/src/news_func.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/news_func.h	Wed Dec 16 19:19:57 2009 +0100
@@ -16,6 +16,7 @@
 #include "vehicle_type.h"
 #include "station_type.h"
 #include "industry_type.h"
+#include "company_type.h"
 
 void AddNewsItem(StringID string, NewsSubtype subtype, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = NULL);
 
diff -r 779c5a44c6a1 src/news_gui.cpp
--- a/src/news_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/news_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -238,6 +238,7 @@
 	{ NT_COMPANY_INFO,     NF_NONE,                        &_company_news_desc }, ///< NS_COMPANY_MERGER
 	{ NT_COMPANY_INFO,     NF_NONE,                        &_company_news_desc }, ///< NS_COMPANY_BANKRUPT
 	{ NT_COMPANY_INFO,     NF_NONE,                        &_company_news_desc }, ///< NS_COMPANY_NEW
+	{ NT_COMPANY_INFO,     NF_NONE,                        &_company_news_desc }, ///< NS_COMPANY_SHARING
 	{ NT_INDUSTRY_OPEN,    (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc    }, ///< NS_INDUSTRY_OPEN
 	{ NT_INDUSTRY_CLOSE,   (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc    }, ///< NS_INDUSTRY_CLOSE
 	{ NT_ECONOMY,          NF_NONE,                        &_normal_news_desc  }, ///< NS_ECONOMY
@@ -311,6 +312,10 @@
 				this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_COMPANY_LAUNCH_TITLE;
 				break;
 
+			case NS_COMPANY_SHARING:
+				this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_SHARING_TITLE;
+				break;
+
 			default:
 				break;
 		}
@@ -532,6 +537,12 @@
 				SetDParam(1, this->ni->params[3]);
 				return STR_NEWS_COMPANY_LAUNCH_DESCRIPTION;
 
+			case NS_COMPANY_SHARING:
+				SetDParam(0, ni->params[2]);
+				SetDParam(1, ni->params[3]);
+				return ni->params[1];
+				break;
+
 			default:
 				NOT_REACHED();
 		}
diff -r 779c5a44c6a1 src/news_type.h
--- a/src/news_type.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/news_type.h	Wed Dec 16 19:19:57 2009 +0100
@@ -50,6 +50,7 @@
 	NS_COMPANY_MERGER,   ///< NT_COMPANY_INFO (merger)
 	NS_COMPANY_BANKRUPT, ///< NT_COMPANY_INFO (bankrupt)
 	NS_COMPANY_NEW,      ///< NT_COMPANY_INFO (new company)
+	NS_COMPANY_SHARING,  ///< NT_COMPANY_INFO (change of sharing settings)
 	NS_INDUSTRY_OPEN,    ///< NT_INDUSTRY_OPEN
 	NS_INDUSTRY_CLOSE,   ///< NT_INDUSTRY_CLOSE
 	NS_ECONOMY,          ///< NT_ECONOMY
diff -r 779c5a44c6a1 src/order_cmd.cpp
--- a/src/order_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/order_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -27,6 +27,7 @@
 #include "station_base.h"
 #include "waypoint_base.h"
 #include "roadstop_base.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 
@@ -464,7 +465,7 @@
 			const Station *st = Station::GetIfValid(new_order.GetDestination());
 			if (st == NULL) return CMD_ERROR;
 
-			if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
+			if (!CheckInfraUsageAllowed(st->owner, v->type)) return CMD_ERROR;
 
 			if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
 			for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
@@ -508,7 +509,7 @@
 				if (v->type == VEH_AIRCRAFT) {
 					const Station *st = Station::GetIfValid(new_order.GetDestination());
 
-					if (st == NULL || !CheckOwnership(st->owner) ||
+					if (st == NULL || !CheckInfraUsageAllowed(st->owner, v->type) ||
 							!CanVehicleUseStation(v, st) ||
 							st->Airport()->nof_depots == 0) {
 						return CMD_ERROR;
@@ -516,7 +517,7 @@
 				} else {
 					const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
 
-					if (dp == NULL || !CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
+					if (dp == NULL || !CheckInfraUsageAllowed(dp->xy, v->type)) return CMD_ERROR;
 
 					switch (v->type) {
 						case VEH_TRAIN:
@@ -548,18 +549,8 @@
 		case OT_GOTO_WAYPOINT: {
 			const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
 			if (wp == NULL) return CMD_ERROR;
-
-			switch (v->type) {
-				default: return CMD_ERROR;
-
-				case VEH_TRAIN:
-					if (!CheckOwnership(wp->owner)) return CMD_ERROR;
-					break;
-
-				case VEH_SHIP:
-					if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR;
-					break;
-			}
+			if (v->type != VEH_TRAIN && v->type != VEH_SHIP) return CMD_ERROR;
+			if (!CheckInfraUsageAllowed(wp->owner, v->type)) return CMD_ERROR;
 
 			/* Order flags can be any of the following for waypoints:
 			 * [non-stop]
diff -r 779c5a44c6a1 src/order_gui.cpp
--- a/src/order_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/order_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -31,6 +31,7 @@
 #include "network/network.h"
 #include "station_base.h"
 #include "waypoint_base.h"
+#include "infrastructure_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -316,18 +317,16 @@
 	if (_settings_game.order.gotodepot) {
 		switch (GetTileType(tile)) {
 			case MP_RAILWAY:
-				if (v->type == VEH_TRAIN && IsTileOwner(tile, _local_company)) {
-					if (IsRailDepot(tile)) {
+				if (v->type == VEH_TRAIN && IsRailDepot(tile) && IsInfraUsageAllowed(tile, v)) {
 						order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS,
-								_settings_client.gui.new_nonstop ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
-						if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
-						return order;
-					}
+						_settings_client.gui.new_nonstop ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
+					if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
+					return order;
 				}
 				break;
 
 			case MP_ROAD:
-				if (IsRoadDepot(tile) && v->type == VEH_ROAD && IsTileOwner(tile, _local_company)) {
+				if (IsRoadDepot(tile) && v->type == VEH_ROAD && IsInfraUsageAllowed(tile, v)) {
 					order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS,
 							_settings_client.gui.new_nonstop ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
 					if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
@@ -337,7 +336,7 @@
 
 			case MP_STATION:
 				if (v->type != VEH_AIRCRAFT) break;
-				if (IsHangar(tile) && IsTileOwner(tile, _local_company)) {
+				if (IsHangar(tile) && IsInfraUsageAllowed(tile, v)) {
 					order.MakeGoToDepot(GetStationIndex(tile), ODTFB_PART_OF_ORDERS, ONSF_STOP_EVERYWHERE);
 					if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
 					return order;
@@ -346,7 +345,7 @@
 
 			case MP_WATER:
 				if (v->type != VEH_SHIP) break;
-				if (IsShipDepot(tile) && IsTileOwner(tile, _local_company)) {
+				if (IsShipDepot(tile) && IsInfraUsageAllowed(tile, v)) {
 					order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS, ONSF_STOP_EVERYWHERE);
 					if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
 					return order;
@@ -360,7 +359,7 @@
 	/* check waypoint */
 	if (IsRailWaypointTile(tile) &&
 			v->type == VEH_TRAIN &&
-			IsTileOwner(tile, _local_company)) {
+			IsInfraUsageAllowed(Waypoint::GetByTile(tile)->owner, v)) {
 		order.MakeGoToWaypoint(Waypoint::GetByTile(tile)->index);
 		if (_settings_client.gui.new_nonstop != _ctrl_pressed) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
 		return order;
@@ -375,7 +374,7 @@
 		StationID st_index = GetStationIndex(tile);
 		const Station *st = Station::Get(st_index);
 
-		if (st->owner == _local_company || st->owner == OWNER_NONE) {
+		if (IsInfraUsageAllowed(st->owner, v)) {
 			byte facil;
 			(facil = FACIL_DOCK, v->type == VEH_SHIP) ||
 			(facil = FACIL_TRAIN, v->type == VEH_TRAIN) ||
diff -r 779c5a44c6a1 src/pathfinder/npf/npf.cpp
--- a/src/pathfinder/npf/npf.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/pathfinder/npf/npf.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -22,6 +22,7 @@
 #include "../../ship.h"
 #include "../../train.h"
 #include "../../roadstop_base.h"
+#include "../../infrastructure_func.h"
 #include "../pathfinder_func.h"
 #include "../pathfinder_type.h"
 #include "aystar.h"
@@ -639,25 +640,30 @@
  */
 static bool CanEnterTileOwnerCheck(Owner owner, TileIndex tile, DiagDirection enterdir)
 {
-	if (IsTileType(tile, MP_RAILWAY) || // Rail tile (also rail depot)
-			HasStationTileRail(tile) ||     // Rail station tile/waypoint
-			IsRoadDepotTile(tile) ||        // Road depot tile
-			IsStandardRoadStopTile(tile)) { // Road station tile (but not drive-through stops)
-		return IsTileOwner(tile, owner);  // You need to own these tiles entirely to use them
-	}
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			return IsInfraUsageAllowed(tile, owner, VEH_TRAIN);
 
-	switch (GetTileType(tile)) {
 		case MP_ROAD:
+			/* road depot */
+			if (IsRoadDepot(tile)) return IsInfraUsageAllowed(tile, owner, VEH_ROAD);
 			/* rail-road crossing : are we looking at the railway part? */
 			if (IsLevelCrossing(tile) &&
 					DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
-				return IsTileOwner(tile, owner); // Railway needs owner check, while the street is public
+				return IsInfraUsageAllowed(tile, owner, VEH_TRAIN); // Railway needs owner check, while the street is public
 			}
 			break;
 
+		case MP_STATION:
+			/* rail station */
+			if (HasStationTileRail(tile)) return IsInfraUsageAllowed(tile, owner, VEH_TRAIN);
+			/* standard road stop */
+			if (IsStandardRoadStopTile(tile)) return IsInfraUsageAllowed(tile, owner, VEH_ROAD);
+			break;
+
 		case MP_TUNNELBRIDGE:
 			if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
-				return IsTileOwner(tile, owner);
+				return IsInfraUsageAllowed(tile, owner, VEH_TRAIN);
 			}
 			break;
 
diff -r 779c5a44c6a1 src/pathfinder/yapf/follow_track.hpp
--- a/src/pathfinder/yapf/follow_track.hpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/pathfinder/yapf/follow_track.hpp	Wed Dec 16 19:19:57 2009 +0100
@@ -16,6 +16,7 @@
 #include "../../depot_map.h"
 #include "../../roadveh.h"
 #include "../../train.h"
+#include "../../infrastructure_func.h"
 
 /** Track follower helper template class (can serve pathfinders and vehicle
  *  controllers). See 6 different typedefs below for 3 different transport
@@ -62,12 +63,12 @@
 	{
 		assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN));
 		m_veh = v;
-		Init(v != NULL ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf);
+		Init(v != NULL ? v->owner : INVALID_OWNER, (IsRailTT() && railtype_override == INVALID_RAILTYPES && v != NULL) ? Train::From(v)->compatible_railtypes : railtype_override, pPerf);
 	}
 
 	FORCEINLINE void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf)
 	{
-		assert((!IsRoadTT() || m_veh != NULL) && (!IsRailTT() || railtype_override != INVALID_RAILTYPES));
+		assert(!IsRoadTT() || m_veh != NULL);
 		m_veh_owner = o;
 		m_pPerf = pPerf;
 		/* don't worry, all is inlined so compiler should remove unnecessary initializations */
@@ -272,6 +273,7 @@
 	/** return true if we can enter m_new_tile from m_exitdir */
 	FORCEINLINE bool CanEnterNewTile()
 	{
+		bool do_owner_check = (m_veh_owner != INVALID_OWNER);
 		if (IsRoadTT() && IsStandardRoadStopTile(m_new_tile)) {
 			/* road stop can be entered from one direction only unless it's a drive-through stop */
 			DiagDirection exitdir = GetRoadStopDir(m_new_tile);
@@ -279,6 +281,11 @@
 				m_err = EC_NO_WAY;
 				return false;
 			}
+			/* road stops shouldn't be entered unless allowed to */
+			if (do_owner_check && !IsInfraUsageAllowed(m_new_tile, m_veh_owner, VEH_ROAD)) {
+				m_err = EC_OWNER;
+				return false;
+			}
 		}
 
 		/* single tram bits can only be entered from one direction */
@@ -297,8 +304,8 @@
 				m_err = EC_NO_WAY;
 				return false;
 			}
-			/* don't try to enter other company's depots */
-			if (GetTileOwner(m_new_tile) != m_veh_owner) {
+			/* don't try to enter other companies' depots, unless allowed to */
+			if (do_owner_check && !IsInfraUsageAllowed(m_new_tile, m_veh_owner, VEH_ROAD)) {
 				m_err = EC_OWNER;
 				return false;
 			}
@@ -311,10 +318,10 @@
 			}
 		}
 
-		/* rail transport is possible only on tiles with the same owner as vehicle */
-		if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh_owner) {
+		/* rail transport is possible only on tiles where the vehicle is allowed */
+		if (IsRailTT() && do_owner_check && !IsInfraUsageAllowed(m_new_tile, m_veh_owner, VEH_TRAIN)) {
 			/* different owner */
-			m_err = EC_NO_WAY;
+			m_err = EC_OWNER;
 			return false;
 		}
 
diff -r 779c5a44c6a1 src/pathfinder/yapf/yapf_costrail.hpp
--- a/src/pathfinder/yapf/yapf_costrail.hpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/pathfinder/yapf/yapf_costrail.hpp	Wed Dec 16 19:19:57 2009 +0100
@@ -34,6 +34,7 @@
 		Trackdir    td;
 		TileType    tile_type;
 		RailType    rail_type;
+		Owner       owner;
 
 		TILE()
 		{
@@ -41,6 +42,7 @@
 			td = INVALID_TRACKDIR;
 			tile_type = MP_VOID;
 			rail_type = INVALID_RAILTYPE;
+			owner = INVALID_OWNER;
 		}
 
 		TILE(TileIndex tile, Trackdir td)
@@ -49,6 +51,7 @@
 			this->td = td;
 			this->tile_type = GetTileType(tile);
 			this->rail_type = GetTileRailType(tile);
+			this->owner = GetTileOwner(tile);
 		}
 
 		TILE(const TILE &src)
@@ -57,6 +60,7 @@
 			td = src.td;
 			tile_type = src.tile_type;
 			rail_type = src.rail_type;
+			owner = src.owner;
 		}
 	};
 
@@ -450,10 +454,15 @@
 			if (!tf_local.Follow(cur.tile, cur.td)) {
 				assert(tf_local.m_err != TrackFollower::EC_NONE);
 				/* Can't move to the next tile (EOL?). */
-				if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) {
-					end_segment_reason |= ESRB_RAIL_TYPE;
-				} else {
-					end_segment_reason |= ESRB_DEAD_END;
+				switch (tf_local.m_err) {
+					case TrackFollower::EC_RAIL_TYPE:
+						end_segment_reason |= ESRB_RAIL_TYPE;
+						break;
+					case TrackFollower::EC_OWNER:
+						end_segment_reason |= ESRB_OWNER;
+						break;
+					default:
+						end_segment_reason |= ESRB_DEAD_END;
 				}
 
 				if (TrackFollower::DoTrackMasking() && !HasOnewaySignalBlockingTrackdir(cur.tile, cur.td)) {
@@ -484,6 +493,13 @@
 				break;
 			}
 
+			/* Check the next tile for the owner. */
+			if (next.owner != cur.owner) {
+				/* Segment must consist from tiles with the same owner. */
+				end_segment_reason |= ESRB_OWNER;
+				break;
+			}
+
 			/* Avoid infinite looping. */
 			if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) {
 				end_segment_reason |= ESRB_INFINITE_LOOP;
diff -r 779c5a44c6a1 src/pathfinder/yapf/yapf_node_rail.hpp
--- a/src/pathfinder/yapf/yapf_node_rail.hpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/pathfinder/yapf/yapf_node_rail.hpp	Wed Dec 16 19:19:57 2009 +0100
@@ -66,6 +66,7 @@
 	/* The following reasons can be saved into cached segment */
 	ESR_DEAD_END = 0,      ///< track ends here
 	ESR_RAIL_TYPE,         ///< the next tile has a different rail type than our tiles
+	ESR_OWNER,             ///< the next tile has a different owner than our tiles
 	ESR_INFINITE_LOOP,     ///< infinite loop detected
 	ESR_SEGMENT_TOO_LONG,  ///< the segment is too long (possible infinite loop)
 	ESR_CHOICE_FOLLOWS,    ///< the next tile contains a choice (the track splits to more than one segments)
@@ -90,6 +91,7 @@
 
 	ESRB_DEAD_END          = 1 << ESR_DEAD_END,
 	ESRB_RAIL_TYPE         = 1 << ESR_RAIL_TYPE,
+	ESRB_OWNER             = 1 << ESR_OWNER,
 	ESRB_INFINITE_LOOP     = 1 << ESR_INFINITE_LOOP,
 	ESRB_SEGMENT_TOO_LONG  = 1 << ESR_SEGMENT_TOO_LONG,
 	ESRB_CHOICE_FOLLOWS    = 1 << ESR_CHOICE_FOLLOWS,
@@ -109,7 +111,7 @@
 	ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
 
 	/* What reasons can be stored back into cached segment. */
-	ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
+	ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_OWNER | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
 
 	/* Reasons to abort pathfinding in this direction. */
 	ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED,
@@ -120,7 +122,7 @@
 inline CStrA ValueStr(EndSegmentReasonBits bits)
 {
 	static const char * const end_segment_reason_names[] = {
-		"DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
+		"DEAD_END", "RAIL_TYPE", "OWNER", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
 		"DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
 		"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED"
 	};
diff -r 779c5a44c6a1 src/pbs.cpp
--- a/src/pbs.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/pbs.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -278,6 +278,40 @@
 }
 
 /**
+ * Find a train on a reservation in a single direction.
+ * @param tile The reserved tile.
+ * @param trackdir The reserved trackdir to start searching.
+ * @param owner The owner of the vehicle. If no owner is known yet, specify INVALID_OWNER.
+ * @param rts The railtypes the vehicle can use. If not known yet, specify INVALID_RAILTYPES.
+ * @return The vehicle this reservation (possibly) belongs to.
+ */
+static Train *FindTrainForReservationDir(TileIndex tile, Trackdir trackdir, Owner owner, RailTypes rts)
+{
+	FindTrainOnTrackInfo ftoti;
+	/* Ignore one-way signals, as we might be searching the wrong way */
+	ftoti.res = FollowReservation(owner, rts, tile, trackdir, true);
+
+	FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
+	if (ftoti.best != NULL) return ftoti.best;
+
+	/* Special case for stations: check the whole platform for a vehicle. */
+	if (HasStationTileRail(ftoti.res.tile)) {
+		TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
+		for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
+			FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
+			if (ftoti.best != NULL) return ftoti.best;
+		}
+	}
+
+	/* Special case for bridges/tunnels: check the other end as well. */
+	if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
+		FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
+		if (ftoti.best != NULL) return ftoti.best;
+	}
+	return NULL;
+}
+
+/**
  * Find the train which has reserved a specific path.
  *
  * @param tile A tile on the path.
@@ -289,31 +323,22 @@
 	assert(HasReservedTracks(tile, TrackToTrackBits(track)));
 	Trackdir  trackdir = TrackToTrackdir(track);
 
-	RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
-
 	/* Follow the path from tile to both ends, one of the end tiles should
-	 * have a train on it. We need FollowReservation to ignore one-way signals
-	 * here, as one of the two search directions will be the "wrong" way. */
+	 * have a train on it. Since we don't know the vehicle yet,
+	 * we don't know which tiles it can access with regards to ownership and infrastructure sharing,
+	 * nor do we know which rail types it is compatible with.
+	 * Therefore we first do a test run without ownership or railtype checks.
+	 * If this yields a vehicle, we test again using the now-known owner and railtype info.
+	 * If this still yields a vehicle, we return it as it is the correct one.
+	 */
 	for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
-		FindTrainOnTrackInfo ftoti;
-		ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
-
-		FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
-		if (ftoti.best != NULL) return ftoti.best;
-
-		/* Special case for stations: check the whole platform for a vehicle. */
-		if (IsRailStationTile(ftoti.res.tile)) {
-			TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
-			for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
-				FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
-				if (ftoti.best != NULL) return ftoti.best;
-			}
-		}
-
-		/* Special case for bridges/tunnels: check the other end as well. */
-		if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
-			FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
-			if (ftoti.best != NULL) return ftoti.best;
+		Train *t = FindTrainForReservationDir(tile, trackdir, INVALID_OWNER, INVALID_RAILTYPES);
+		if (t == NULL) continue;
+		RailTypes rts = GetRailTypeInfo(t->railtype)->compatible_railtypes;
+		t = FindTrainForReservationDir(tile, trackdir, t->owner, rts);
+		/* Also verify that the train can actally use the start tile */
+		if (t != NULL && IsInfraUsageAllowed(tile, t) && HasBit(rts, GetTileRailType(tile))) {
+			return t;
 		}
 	}
 
diff -r 779c5a44c6a1 src/roadveh_cmd.cpp
--- a/src/roadveh_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/roadveh_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -38,6 +38,7 @@
 #include "cargotype.h"
 #include "spritecache.h"
 #include "debug.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -206,7 +207,7 @@
 	/* The ai_new queries the vehicle cost before building the route,
 	 * so we must check against cheaters no sooner than now. --pasky */
 	if (!IsRoadDepotTile(tile)) return CMD_ERROR;
-	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+	if (!CheckInfraUsageAllowed(tile, VEH_ROAD)) return CMD_ERROR;
 
 	if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
 
@@ -411,7 +412,7 @@
 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
 	RoadVehicle *v = RoadVehicle::GetIfValid(p1);
-	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (v == NULL || !IsVehicleControlAllowed(v)) return CMD_ERROR;
 
 	if ((v->vehstatus & VS_STOPPED) ||
 			(v->vehstatus & VS_CRASHED) ||
@@ -935,14 +936,14 @@
 	TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
 
 	if (IsTileType(tile, MP_ROAD)) {
-		if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
+		if (IsRoadDepot(tile) && (!IsInfraUsageAllowed(tile, v) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
 			/* Road depot owned by another company or with the wrong orientation */
 			trackdirs = TRACKDIR_BIT_NONE;
 		}
 	} else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
 		/* Standard road stop (drive-through stops are treated as normal road) */
 
-		if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
+		if (!IsInfraUsageAllowed(tile, v) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
 			/* different station owner or wrong orientation or the vehicle has articulated parts */
 			trackdirs = TRACKDIR_BIT_NONE;
 		} else {
@@ -1420,7 +1421,7 @@
 			/* In case an RV is stopped in a road stop, why not try to load? */
 			if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
 					v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
-					v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
+					IsInfraUsageAllowed(v->tile, v) && !v->current_order.IsType(OT_LEAVESTATION) &&
 					GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
 				Station *st = Station::GetByTile(v->tile);
 				v->last_station_visited = st->index;
@@ -1454,7 +1455,7 @@
 			_road_veh_data_1[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
 			(IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
 			v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
-			v->owner == GetTileOwner(v->tile) &&
+			IsInfraUsageAllowed(v->tile, v) &&
 			GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
 			v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
 
diff -r 779c5a44c6a1 src/saveload/afterload.cpp
--- a/src/saveload/afterload.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/saveload/afterload.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -49,6 +49,7 @@
 #include "../animated_tile_func.h"
 #include "../subsidy_base.h"
 #include "../subsidy_func.h"
+#include "../core/mem_func.hpp"
 
 #include "table/strings.h"
 
@@ -1959,6 +1960,23 @@
 		}
 	}
 
+	if (CheckSavegameVersion(SL_IS)) {
+		/* Disable sharing when loading old savegames. */
+		_settings_game.sharing.sharing_mode = SHARING_NONE;
+
+		Company *c;
+		FOR_ALL_COMPANIES(c) {
+			/* yearly_expenses has 3*15 entries now, saveload code gave us 3*13.
+			 * Move the old data to the right place in the new array and clear the new data.
+			 * The move has to be done in reverse order (first 2, then 1). */
+			MemMoveT(&c->yearly_expenses[2][0], &c->yearly_expenses[1][11], 13);
+			MemMoveT(&c->yearly_expenses[1][0], &c->yearly_expenses[0][13], 13);
+			/* Clear the old location of just-moved data, so sharing income/expenses is set to 0 */
+			MemSetT(&c->yearly_expenses[0][13], 0, 2);
+			MemSetT(&c->yearly_expenses[1][13], 0, 2);
+		}
+	}
+
 	/* Road stops is 'only' updating some caches */
 	AfterLoadRoadStops();
 	AfterLoadLabelMaps();
diff -r 779c5a44c6a1 src/saveload/company_sl.cpp
--- a/src/saveload/company_sl.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/saveload/company_sl.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -123,6 +123,8 @@
 
 	    SLE_VAR(Company, num_valid_stat_ent,    SLE_UINT8),
 
+	SLE_CONDVAR(Company, sharing_delay,         SLE_UINT8,               SL_IS, SL_MAX_VERSION),
+
 	    SLE_VAR(Company, quarters_of_bankruptcy,SLE_UINT8),
 	SLE_CONDVAR(Company, bankrupt_asked,        SLE_FILE_U8  | SLE_VAR_U16,  0, 103),
 	SLE_CONDVAR(Company, bankrupt_asked,        SLE_UINT16,                104, SL_MAX_VERSION),
@@ -132,7 +134,8 @@
 
 	/* yearly expenses was changed to 64-bit in savegame version 2. */
 	SLE_CONDARR(Company, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1),
-	SLE_CONDARR(Company, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_MAX_VERSION),
+	SLE_CONDARR(Company, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_IS - 1),
+	SLE_CONDARR(Company, yearly_expenses,       SLE_INT64, 3 * 15,              SL_IS, SL_MAX_VERSION),
 
 	SLE_CONDVAR(Company, is_ai,                 SLE_BOOL,                    2, SL_MAX_VERSION),
 	SLE_CONDNULL(1, 107, 111), ///< is_noai
@@ -226,6 +229,17 @@
 	SLE_END()
 };
 
+static const SaveLoad *GetCompanySharingSettingsDescription()
+{
+	static const SaveLoad _company_sharing_desc[] = {
+		SLE_CONDVAR(CompanySharingSettings,     allowed_types,  SLE_UINT8,    SL_IS, SL_MAX_VERSION),
+		SLE_CONDVAR(CompanySharingSettings, allowed_companies, SLE_UINT16,    SL_IS, SL_MAX_VERSION),
+		SLE_CONDARR(CompanySharingSettings,               fee, SLE_UINT16, 4, SL_IS, SL_MAX_VERSION),
+		SLE_END()
+	};
+	return _company_sharing_desc;
+}
+
 static void SaveLoad_PLYR(Company *c)
 {
 	int i;
@@ -243,6 +257,10 @@
 		}
 	}
 
+	/* Write sharing settings */
+	SlObject(&c->sharing_current, GetCompanySharingSettingsDescription());
+	SlObject(&c->sharing_future,  GetCompanySharingSettingsDescription());
+
 	/* Write economy */
 	SlObject(&c->cur_economy, _company_economy_desc);
 
diff -r 779c5a44c6a1 src/saveload/saveload.cpp
--- a/src/saveload/saveload.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/saveload/saveload.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -47,7 +47,8 @@
 
 #include "saveload_internal.h"
 
-extern const uint16 SAVEGAME_VERSION = 130;
+extern const uint16 SAVEGAME_VERSION = SL_IS;
+
 
 SavegameType _savegame_type; ///< type of savegame we are loading
 
diff -r 779c5a44c6a1 src/saveload/saveload.h
--- a/src/saveload/saveload.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/saveload/saveload.h	Wed Dec 16 19:19:57 2009 +0100
@@ -80,6 +80,7 @@
 };
 
 #define SL_MAX_VERSION 255
+#define SL_IS 131
 
 enum {
 	INC_VEHICLE_COMMON = 0,
diff -r 779c5a44c6a1 src/settings.cpp
--- a/src/settings.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/settings.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -64,6 +64,8 @@
 
 #include "void_map.h"
 #include "station_base.h"
+#include "infrastructure_func.h"
+#include "core/mem_func.hpp"
 
 #include "table/strings.h"
 #include "table/settings.h"
@@ -983,6 +985,84 @@
 	return true;
 }
 
+/**
+ * Update the sharing settings of all companies if sharing settings are globally fixed
+ * @param p1 unused
+ * @return always true
+ */
+static bool UpdateAllSharingSettings(int32 p1 = 0)
+{
+	if (_settings_game.sharing.sharing_mode != SHARING_GLOBAL || _game_mode == GM_MENU) return true;
+
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		c->sharing_future.CopyFromGameSettings();
+		c->sharing_delay = 0;
+	}
+	ProcessSharingChanges();
+
+	return true;
+}
+
+/**
+ * Update all sharing settings if sharing is globally enabled / disabled.
+ * @param p1 New value of the setting
+ * @return always true
+ */
+static bool UpdateSharingEnabled(int32 p1)
+{
+	if (_game_mode == GM_MENU) return true;
+
+	switch (p1) {
+		case SHARING_NONE: {
+			Company *c;
+			FOR_ALL_COMPANIES(c) {
+				/* Disable all sharing options */
+				VehicleType type;
+				FOR_ALL_SHARING_VEHTYPES(type) {
+					c->sharing_future.SetSharingAllowed(type, false);
+				}
+				/* Allow only our own company, erase all others */
+				for (CompanyID cid = COMPANY_FIRST; cid < MAX_COMPANIES; cid++) {
+					if (Company::IsValidID(cid)) c->sharing_future.SetCompanyAllowed(cid, cid == _local_company);
+				}
+				c->sharing_delay = 0;
+			}
+			/* Process all these changes */
+			ProcessSharingChanges();
+			break;
+		}
+		case SHARING_GLOBAL:
+			UpdateAllSharingSettings();
+			break;
+	}
+	UpdateAllBlockSignals();
+
+	SetWindowClassesDirty(WC_FINANCES);
+	SetWindowClassesDirty(WC_COMPANY);
+	if (p1 != SHARING_INDIVIDUAL) DeleteWindowByClass(WC_SHARING_OPTIONS);
+
+	return true;
+}
+
+/**
+ * Cap sharing_delay for all companies to the new delay setting
+ * @param p1 new delay setting
+ * @return always true
+ */
+static bool UpdateSharingDelay(int32 p1)
+{
+	if (_settings_game.sharing.sharing_mode != SHARING_INDIVIDUAL) return true;
+
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		c->sharing_delay = min(c->sharing_delay, p1);
+	}
+	/* Changes have to be applied right now if delay is set to 0 */
+	if (p1 == 0) ProcessSharingChanges();
+	return true;
+}
+
 #ifdef ENABLE_NETWORK
 
 static bool UpdateClientName(int32 p1)
diff -r 779c5a44c6a1 src/settings_gui.cpp
--- a/src/settings_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/settings_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -1337,8 +1337,32 @@
 /** Computer players sub-page */
 static SettingsPage _settings_ai_npc_page = {_settings_ai_npc, lengthof(_settings_ai_npc)};
 
+static SettingEntry _settings_ai_sharing_global[] = {
+	SettingEntry("sharing.rail_sharing"),
+	SettingEntry("sharing.road_sharing"),
+	SettingEntry("sharing.water_sharing"),
+	SettingEntry("sharing.air_sharing"),
+	SettingEntry("sharing.rail_fee"),
+	SettingEntry("sharing.road_fee"),
+	SettingEntry("sharing.water_fee"),
+	SettingEntry("sharing.air_fee"),
+};
+
+/** Infrastructure sharing default settings sub-page */
+static SettingsPage _settings_ai_sharing_global_page = {_settings_ai_sharing_global, lengthof(_settings_ai_sharing_global)};
+
+static SettingEntry _settings_ai_sharing[] = {
+	SettingEntry(&_settings_ai_sharing_global_page, STR_CONFIG_SETTING_AI_SHARING_GLOBAL),
+	SettingEntry("sharing.sharing_mode"),
+	SettingEntry("sharing.new_individual_delay"),
+	SettingEntry("sharing.payment_in_debt"),
+};
+/** Infrastructure sharing sub-page */
+static SettingsPage _settings_ai_sharing_page = {_settings_ai_sharing, lengthof(_settings_ai_sharing)};
+
 static SettingEntry _settings_ai[] = {
 	SettingEntry(&_settings_ai_npc_page, STR_CONFIG_SETTING_AI_NPC),
+	SettingEntry(&_settings_ai_sharing_page, STR_CONFIG_SETTING_AI_SHARING),
 	SettingEntry("economy.give_money"),
 	SettingEntry("economy.allow_shares"),
 };
diff -r 779c5a44c6a1 src/settings_type.h
--- a/src/settings_type.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/settings_type.h	Wed Dec 16 19:19:57 2009 +0100
@@ -194,6 +194,23 @@
 	uint32 ai_max_opcode_till_suspend;       ///< max opcode calls till AI will suspend
 };
 
+/** Settings related to sharing. */
+struct SharingSettings {
+	byte   sharing_mode;                     ///< main infrastructure sharing setting, (off / on with global settings / on with individual settings)
+	byte   new_individual_delay;             ///< time (in months) it takes for new individual settings to take effect
+	bool   payment_in_debt;                  ///< whether to allow fee payment for companies with more loan than money. Switch off to prevent MP exploits.
+
+	bool   rail_sharing;                     ///< sharing rail
+	bool   road_sharing;                     ///< sharing road
+	bool   water_sharing;                    ///< sharing water
+	bool   air_sharing;                      ///< sharing air
+
+	uint16 rail_fee;                         ///< train fee
+	uint16 road_fee;                         ///< road vehicle fee
+	uint16 water_fee;                        ///< ship fee
+	uint16 air_fee;                          ///< aircraft fee
+};
+
 /** Settings related to the old pathfinder. */
 struct OPFSettings {
 	uint16 pf_maxlength;                     ///< maximum length when searching for a train route for new pathfinder
@@ -381,6 +398,7 @@
 	EconomySettings      economy;            ///< settings to change the economy
 	StationSettings      station;            ///< settings related to station management
 	LocaleSettings       locale;             ///< settings related to used currency/unit system in the current game
+	SharingSettings      sharing;            ///< settings related to infrastructure sharing
 };
 
 /** All settings that are only important for the local client. */
diff -r 779c5a44c6a1 src/ship_cmd.cpp
--- a/src/ship_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/ship_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -36,6 +36,7 @@
 #include "ai/ai.hpp"
 #include "pathfinder/opf/opf_ship.h"
 #include "landscape_type.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -106,7 +107,7 @@
 
 	FOR_ALL_DEPOTS(depot) {
 		TileIndex tile = depot->xy;
-		if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
+		if (IsShipDepotTile(tile) && IsInfraUsageAllowed(tile, v)) {
 			uint dist = DistanceManhattan(tile, v->tile);
 			if (dist < best_dist) {
 				best_dist = dist;
@@ -610,7 +611,7 @@
 	/* The ai_new queries the vehicle cost before building the route,
 	 * so we must check against cheaters no sooner than now. --pasky */
 	if (!IsShipDepotTile(tile)) return CMD_ERROR;
-	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+	if (!CheckInfraUsageAllowed(tile, VEH_SHIP)) return CMD_ERROR;
 
 	unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_SHIP);
 
diff -r 779c5a44c6a1 src/signal.cpp
--- a/src/signal.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/signal.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -16,6 +16,7 @@
 #include "vehicle_func.h"
 #include "functions.h"
 #include "train.h"
+#include "infrastructure_func.h"
 
 
 /** these are the maximums used for updating signal blocks */
@@ -278,7 +279,7 @@
 
 		switch (GetTileType(tile)) {
 			case MP_RAILWAY: {
-				if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)
+				if (!AreSignalBlocksJoined(owner, GetTileOwner(tile))) continue; // check whether tile should be part of the same block, owner-wise
 
 				if (IsRailDepot(tile)) {
 					if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
@@ -351,7 +352,7 @@
 
 			case MP_STATION:
 				if (!HasStationRail(tile)) continue;
-				if (GetTileOwner(tile) != owner) continue;
+				if (!AreSignalBlocksJoined(owner, GetTileOwner(tile))) continue;
 				if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
 				if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
 
@@ -361,7 +362,7 @@
 
 			case MP_ROAD:
 				if (!IsLevelCrossing(tile)) continue;
-				if (GetTileOwner(tile) != owner) continue;
+				if (!AreSignalBlocksJoined(owner, GetTileOwner(tile))) continue;
 				if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
 
 				if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
@@ -369,7 +370,7 @@
 				break;
 
 			case MP_TUNNELBRIDGE: {
-				if (GetTileOwner(tile) != owner) continue;
+				if (!AreSignalBlocksJoined(owner, GetTileOwner(tile))) continue;
 				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
 				DiagDirection dir = GetTunnelBridgeDirection(tile);
 
diff -r 779c5a44c6a1 src/table/settings.h
--- a/src/table/settings.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/table/settings.h	Wed Dec 16 19:19:57 2009 +0100
@@ -34,6 +34,9 @@
 static bool ChangeDynamicEngines(int32 p1);
 static bool StationCatchmentChanged(int32 p1);
 static bool InvalidateVehTimetableWindow(int32 p1);
+static bool UpdateAllSharingSettings(int32 p1);
+static bool UpdateSharingEnabled(int32 p1);
+static bool UpdateSharingDelay(int32 p1);
 
 #ifdef ENABLE_NETWORK
 static bool UpdateClientName(int32 p1);
@@ -509,6 +512,18 @@
 	 SDT_CONDVAR(GameSettings, pf.yapf.road_stop_occupied_penalty,             SLE_UINT,130, SL_MAX_VERSION, 0, 0,     8 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 	 SDT_CONDVAR(GameSettings, pf.yapf.road_stop_bay_occupied_penalty,         SLE_UINT,130, SL_MAX_VERSION, 0, 0,    15 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 
+	 SDT_CONDVAR(GameSettings, sharing.sharing_mode,                        SLE_UINT8,SL_IS, SL_MAX_VERSION, 0,MS, SHARING_NONE, SHARING_NONE, SHARING_INDIVIDUAL, 0, STR_CONFIG_SETTING_SHARING_ENABLE,UpdateSharingEnabled),
+	 SDT_CONDVAR(GameSettings, sharing.new_individual_delay,                SLE_UINT8,SL_IS, SL_MAX_VERSION, 0, 0,    12,                     0,     120, 1, STR_CONFIG_SETTING_SHARING_INDIVIDUAL_TIME,UpdateSharingDelay),
+	SDT_CONDBOOL(GameSettings, sharing.payment_in_debt,                               SL_IS, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_SETTING_SHARING_PAYMENT_DEBT,   NULL),
+	SDT_CONDBOOL(GameSettings, sharing.rail_sharing,                                  SL_IS, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_SETTING_SHARING_RAIL,           UpdateAllSharingSettings),
+	SDT_CONDBOOL(GameSettings, sharing.road_sharing,                                  SL_IS, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_SETTING_SHARING_ROAD,           UpdateAllSharingSettings),
+	SDT_CONDBOOL(GameSettings, sharing.water_sharing,                                 SL_IS, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_SETTING_SHARING_WATER,          UpdateAllSharingSettings),
+	SDT_CONDBOOL(GameSettings, sharing.air_sharing,                                   SL_IS, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_SETTING_SHARING_AIR,            UpdateAllSharingSettings),
+	 SDT_CONDVAR(GameSettings, sharing.rail_fee,                           SLE_UINT16,SL_IS, SL_MAX_VERSION, 0,CR,   100,            0, MAX_SHARING_FEE, 10, STR_CONFIG_SETTING_SHARING_RAIL_FEE,       UpdateAllSharingSettings),
+	 SDT_CONDVAR(GameSettings, sharing.road_fee,                           SLE_UINT16,SL_IS, SL_MAX_VERSION, 0,CR,   100,            0, MAX_SHARING_FEE, 10, STR_CONFIG_SETTING_SHARING_ROAD_FEE,       UpdateAllSharingSettings),
+	 SDT_CONDVAR(GameSettings, sharing.water_fee,                          SLE_UINT16,SL_IS, SL_MAX_VERSION, 0,CR,   100,            0, MAX_SHARING_FEE, 10, STR_CONFIG_SETTING_SHARING_WATER_FEE,      UpdateAllSharingSettings),
+	 SDT_CONDVAR(GameSettings, sharing.air_fee,                            SLE_UINT16,SL_IS, SL_MAX_VERSION, 0,CR,   100,            0, MAX_SHARING_FEE, 10, STR_CONFIG_SETTING_SHARING_AIR_FEE,        UpdateAllSharingSettings),
+
 	 SDT_CONDVAR(GameSettings, game_creation.land_generator,                  SLE_UINT8, 30, SL_MAX_VERSION, 0,MS,     1,                     0,       1, 0, STR_CONFIG_SETTING_LAND_GENERATOR,        NULL),
 	 SDT_CONDVAR(GameSettings, game_creation.oil_refinery_limit,              SLE_UINT8, 30, SL_MAX_VERSION, 0, 0,    32,                    12,      48, 0, STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE, NULL),
 	 SDT_CONDVAR(GameSettings, game_creation.tgen_smoothness,                 SLE_UINT8, 30, SL_MAX_VERSION, 0,MS,     1,                     0,       3, 0, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN,  NULL),
diff -r 779c5a44c6a1 src/train.h
--- a/src/train.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/train.h	Wed Dec 16 19:19:57 2009 +0100
@@ -57,6 +57,8 @@
 void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
 bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
 
+void DeleteVisibleTrain(Train *v);
+
 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
 
 void TrainConsistChanged(Train *v, bool same_length);
diff -r 779c5a44c6a1 src/train_cmd.cpp
--- a/src/train_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/train_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -36,6 +36,7 @@
 #include "gamelog.h"
 #include "network/network.h"
 #include "spritecache.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 #include "table/train_cmd.h"
@@ -853,7 +854,7 @@
 	/* Check if the train is actually being built in a depot belonging
 	 * to the company. Doesn't matter if only the cost is queried */
 	if (!IsRailDepotTile(tile)) return CMD_ERROR;
-	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+	if (!CheckInfraUsageAllowed(tile, VEH_TRAIN)) return CMD_ERROR;
 
 	if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
 
@@ -2029,7 +2030,7 @@
 CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
 	Train *v = Train::GetIfValid(p1);
-	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (v == NULL || !IsVehicleControlAllowed(v)) return CMD_ERROR;
 
 	if (p2 != 0) {
 		/* turn a single unit around */
@@ -2089,7 +2090,7 @@
 CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
 	Train *t = Train::GetIfValid(p1);
-	if (t == NULL || !CheckOwnership(t->owner)) return CMD_ERROR;
+	if (t == NULL || !IsVehicleControlAllowed(t)) return CMD_ERROR;
 
 	if (flags & DC_EXEC) t->force_proceed = 0x50;
 
@@ -3120,7 +3121,7 @@
 static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
 {
 	return
-		IsTileOwner(tile, v->owner) && (
+		IsInfraUsageAllowed(tile, v) && (
 			!v->IsFrontEngine() ||
 			HasBit(v->compatible_railtypes, GetRailType(tile))
 		);
@@ -4213,6 +4214,9 @@
 			/* running costs */
 			CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR  * DAY_TICKS));
 
+			/* sharing fee */
+			PayDailyTrackSharingFee(this);
+
 			this->profit_this_year -= cost.GetCost();
 			this->running_ticks = 0;
 
@@ -4243,3 +4247,18 @@
 
 	return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
 }
+
+/**
+ * Delete a train while it is visible.
+ * This happens when infrastructure sharing is disabled.
+ * @param v The train to delete.
+ */
+void DeleteVisibleTrain(Train *v)
+{
+	if (!(v->vehstatus & VS_CRASHED)) {
+		v->crash_anim_pos++;
+		v->Crash();
+	}
+	while (v->Next() != NULL) DeleteLastWagon(v);
+	DeleteLastWagon(v);
+}
diff -r 779c5a44c6a1 src/vehicle.cpp
--- a/src/vehicle.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/vehicle.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -45,6 +45,7 @@
 #include "network/network.h"
 #include "core/pool_func.hpp"
 #include "economy_base.h"
+#include "infrastructure_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -1529,6 +1530,9 @@
 		case OT_LOADING: {
 			uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
 
+			/* Pay the loading fee when using someone else's station */
+			if (!(mode || this->type == VEH_TRAIN)) PayStationSharingFee(this, Station::Get(this->last_station_visited));
+
 			/* Not the first call for this tick, or still loading */
 			if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
 					(_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
diff -r 779c5a44c6a1 src/vehicle_cmd.cpp
--- a/src/vehicle_cmd.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/vehicle_cmd.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -27,6 +27,7 @@
 #include "string_func.h"
 #include "depot_map.h"
 #include "vehiclelist.h"
+#include "infrastructure_func.h"
 
 #include "table/strings.h"
 
@@ -74,7 +75,7 @@
 	if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0);
 
 	Vehicle *v = Vehicle::GetIfValid(p1);
-	if (v == NULL || !CheckOwnership(v->owner) || !v->IsPrimaryVehicle()) return CMD_ERROR;
+	if (v == NULL || !IsVehicleControlAllowed(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
 
 	switch (v->type) {
 		case VEH_TRAIN:
@@ -217,7 +218,7 @@
 	VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
 	bool all_or_nothing = HasBit(p2, 0);
 
-	if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
+	if (!IsDepotTile(tile) || !CheckInfraUsageAllowed(tile, vehicle_type)) return CMD_ERROR;
 
 	/* Get the list of vehicles in the depot */
 	BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
diff -r 779c5a44c6a1 src/vehicle_gui.cpp
--- a/src/vehicle_gui.cpp	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/vehicle_gui.cpp	Wed Dec 16 19:19:57 2009 +0100
@@ -40,6 +40,7 @@
 #include "articulated_vehicles.h"
 #include "cargotype.h"
 #include "spritecache.h"
+#include "infrastructure_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -1862,6 +1863,7 @@
 	{
 		const Vehicle *v = Vehicle::Get(this->window_number);
 		bool is_localcompany = v->owner == _local_company;
+		bool can_control = IsVehicleControlAllowed(v, _local_company);
 		bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
 
 		this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localcompany);
@@ -1869,8 +1871,8 @@
 		this->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localcompany);
 
 		if (v->type == VEH_TRAIN) {
-			this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localcompany);
-			this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localcompany);
+			this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !can_control);
+			this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !can_control);
 		}
 
 		this->DrawWidgets();
diff -r 779c5a44c6a1 src/window_type.h
--- a/src/window_type.h	Fri Dec 04 22:02:37 2009 +0000
+++ b/src/window_type.h	Wed Dec 16 19:19:57 2009 +0100
@@ -107,6 +107,7 @@
 	WC_AI_DEBUG,
 	WC_AI_LIST,
 	WC_AI_SETTINGS,
+	WC_SHARING_OPTIONS,
 
 	WC_INVALID = 0xFFFF
 };
