Index: src/autoreplace_cmd.cpp
===================================================================
--- src/autoreplace_cmd.cpp	(revision 12038)
+++ src/autoreplace_cmd.cpp	(working copy)
@@ -215,7 +215,7 @@
 			DoCommand(0, (front->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
 		} else {
 			// copy/clone the orders
-			DoCommand(0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
+			DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
 			new_v->cur_order_index = old_v->cur_order_index;
 			ChangeVehicleViewWindow(old_v, new_v);
 			new_v->profit_this_year = old_v->profit_this_year;
Index: src/lang/english.txt
===================================================================
--- src/lang/english.txt	(revision 12038)
+++ src/lang/english.txt	(working copy)
@@ -1130,6 +1130,7 @@
 STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_FIRST                      :First available
 STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_LAST                       :Last available
 STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_MOST_USED                  :Most used
+STR_CONFIG_PATCHES_TIMETABLE_SEPARATION                         :{LTBLUE}Use timetable to ensure vehicles separation: {ORANGE}{STRING1}
 
 STR_CONFIG_PATCHES_ALWAYS_BUILD_INFRASTRUCTURE                  :{LTBLUE}Show building tools when no suitable vehicles are available: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_MAX_TRAINS                                   :{LTBLUE}Max trains per player: {ORANGE}{STRING1}
Index: src/order.h
===================================================================
--- src/order.h	(revision 12038)
+++ src/order.h	(working copy)
@@ -212,7 +212,6 @@
 bool VehicleHasDepotOrders(const Vehicle *v);
 void CheckOrders(const Vehicle*);
 void DeleteVehicleOrders(Vehicle *v);
-bool IsOrderListShared(const Vehicle *v);
 void AssignOrder(Order *order, Order data);
 bool CheckForValidOrders(const Vehicle* v);
 
Index: src/order_cmd.cpp
===================================================================
--- src/order_cmd.cpp	(revision 12038)
+++ src/order_cmd.cpp	(working copy)
@@ -22,6 +22,7 @@
 #include "window_func.h"
 #include "settings_type.h"
 #include "string_func.h"
+#include "station_map.h"
 
 #include "table/strings.h"
 
@@ -837,7 +838,7 @@
 			}
 
 			/* make sure there are orders available */
-			delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
+			delta = dst->IsOrderListShared() ? src->num_orders + 1 : src->num_orders - dst->num_orders;
 			if (!HasOrderPoolFree(delta))
 				return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
 
@@ -939,7 +940,7 @@
 	if (v->name != NULL) bak->name = strdup(v->name);
 
 	/* If we have shared orders, store it on a special way */
-	if (IsOrderListShared(v)) {
+	if (v->IsOrderListShared()) {
 		const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
 
 		bak->clone = u->index;
@@ -1209,7 +1210,7 @@
 
 	/* If we have a shared order-list, don't delete the list, but just
 	    remove our pointer */
-	if (IsOrderListShared(v)) {
+	if (v->IsOrderListShared()) {
 		Vehicle *u = v;
 
 		v->orders = NULL;
@@ -1257,24 +1258,10 @@
 	return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
 }
 
-/**
- *
- * Check if we share our orders with an other vehicle
- *
- * @return Returns the vehicle who has the same order
- *
- */
-bool IsOrderListShared(const Vehicle *v)
-{
-	return v->next_shared != NULL || v->prev_shared != NULL;
-}
-
-/**
- *
- * Check if a vehicle has any valid orders
- *
+/** 
+ * Checks if a vehicle has any valid orders
+ * @param  The vehicle to inspect
  * @return false if there are no valid orders
- *
  */
 bool CheckForValidOrders(const Vehicle* v)
 {
Index: src/order_gui.cpp
===================================================================
--- src/order_gui.cpp	(revision 12038)
+++ src/order_gui.cpp	(working copy)
@@ -120,7 +120,7 @@
 
 	v = GetVehicle(w->window_number);
 
-	shared_orders = IsOrderListShared(v);
+	shared_orders = v->IsOrderListShared();
 
 	SetVScrollCount(w, v->num_orders + 1);
 
Index: src/settings.cpp
===================================================================
--- src/settings.cpp	(revision 12038)
+++ src/settings.cpp	(working copy)
@@ -1427,6 +1427,7 @@
 	SDT_CONDBOOL(Patches, disable_elrails, 38, SL_MAX_VERSION, 0, NN, false,         STR_CONFIG_PATCHES_DISABLE_ELRAILS,      SettingsDisableElrail),
 	SDT_CONDVAR(Patches, freight_trains, SLE_UINT8, 39, SL_MAX_VERSION, 0,NN, 1, 1, 255, 1, STR_CONFIG_PATCHES_FREIGHT_TRAINS, NULL),
 	SDT_CONDBOOL(Patches, timetabling,              67, SL_MAX_VERSION, 0, 0, true,  STR_CONFIG_PATCHES_TIMETABLE_ALLOW,      NULL),
+	SDT_CONDBOOL(Patches, timetable_separation,     67, SL_MAX_VERSION, 0, 0, true,  STR_CONFIG_PATCHES_TIMETABLE_SEPARATION, NULL),
 
 	/***************************************************************************/
 	/* Station section of the GUI-configure patches window */
Index: src/settings_gui.cpp
===================================================================
--- src/settings_gui.cpp	(revision 12038)
+++ src/settings_gui.cpp	(working copy)
@@ -818,6 +818,7 @@
 	"disable_elrails",
 	"freight_trains",
 	"timetabling",
+	"timetable_separation",
 };
 
 struct PatchEntry {
@@ -1070,7 +1071,7 @@
 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
 {    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_CONFIG_PATCHES_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},
 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    41, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   380, 0x0,                             STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   390, 0x0,                             STR_NULL},
 
 {    WWT_TEXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_CONFIG_PATCHES_GUI,          STR_NULL},
 {    WWT_TEXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL},
@@ -1082,7 +1083,7 @@
 };
 
 static const WindowDesc _patches_selection_desc = {
-	WDP_CENTER, WDP_CENTER, 370, 381, 370, 381,
+	WDP_CENTER, WDP_CENTER, 370, 391, 370, 391,
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_patches_selection_widgets,
Index: src/settings_type.h
===================================================================
--- src/settings_type.h	(revision 12038)
+++ src/settings_type.h	(working copy)
@@ -217,6 +217,7 @@
 
 	bool timetabling;            ///< Whether to allow timetabling.
 	bool timetable_in_ticks;     ///< Whether to show the timetable in ticks rather than days.
+	bool timetable_separation; // Whether to use automatic separation based on timetable.
 
 	bool autoslope;              ///< Allow terraforming under things.
 
Index: src/timetable_cmd.cpp
===================================================================
--- src/timetable_cmd.cpp	(revision 12038)
+++ src/timetable_cmd.cpp	(working copy)
@@ -13,6 +13,7 @@
 #include "settings_type.h"
 
 #include "table/strings.h"
+#include "station_map.h"
 
 static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time, bool is_journey)
 {
Index: src/vehicle.cpp
===================================================================
--- src/vehicle.cpp	(revision 12038)
+++ src/vehicle.cpp	(working copy)
@@ -571,6 +571,146 @@
 	}
 }
 
+/**
+ * Checks if the vehicle is part of the shared orders list
+ * @param *v The vehicle to check if member of the current vehicle shared orders list
+ * @return true if both vehicles share the same orders list
+ */
+bool Vehicle::IsVehicleInSharedOrdersList(Vehicle *v)
+{
+	for (Vehicle *v_shared = this->prev_shared; v_shared != NULL; v_shared = v_shared->prev_shared) {
+		if (v_shared == v) return true;
+	}
+
+	for (Vehicle *v_shared = this->next_shared; v_shared != NULL; v_shared = v_shared->next_shared) {
+		if (v_shared == v) return true;
+	}
+
+	return false;
+}
+
+/**
+ * Counts the vehicles that share it's orders list
+ * @return The count of vehicles that use this vehicle shared orders list
+ */
+int Vehicle::CountSharedOrderdList()
+{
+	int count = 1; // Count this vehicle firts
+	for (Vehicle *v = this->prev_shared; v != NULL; v = v->prev_shared) count++;
+	for (Vehicle *v = this->next_shared; v != NULL; v = v->next_shared) count++;
+	return count;
+}
+
+/**
+ * Finds this vehicle's position in the shared order list chain
+ * @return The 0 based position in the vehicle's shared order list
+ */
+int Vehicle::GetPositionInSharedOrderList()
+{
+	int count = 0;
+	for (Vehicle *v = this->prev_shared; v != NULL; v = v->prev_shared) count++;
+	return count;
+}
+
+/**
+ * Gets the total timetable duration
+ * @return The sum of all orders durations (in ticks) in the vehicle's timetable
+ */
+int Vehicle::GetTimetableTotalDuration()
+{
+	int total = 0;
+	for (Order *o = this->orders; o != NULL; o = o->next) {
+		total += o->wait_time + o->travel_time;
+	}
+	return total;
+}
+
+/**
+ * Get the current theorical separation with the first shared order vehicle.
+ * This includes its lateness_counter.
+ * The vehicle must be in the first order station for this function to work.
+ * @return The actual separation (in ticks) with the first vehicle
+ */
+int Vehicle::GetFirstSharedSeparation()
+{
+    /* If this is the first vehicle in the shared orders chain then separation is 0 */
+	if (this->prev_shared == NULL) return 0;
+
+	/* Else gets the first vehicle in chain... */
+	Vehicle *first;
+	for (first = this->prev_shared; first->prev_shared != NULL; first = first->prev_shared);
+    /* ... then returns the separation between this vehicle and first vehicle, plus the first vehicle lateness counter */
+	return this->GetVehicleSeparation(first, false, true) + first->lateness_counter;
+}
+
+/**
+ * Get the current separation with the given vehicle.
+ * @param *v The vehicle to compare
+ * @param add_this_current_order_time Indicates if we have to take into account this vehicle current order time
+ * @param add_other_current_order_time Indicates if we have to take into account the compared vehicle current order time
+ * @return Separation duration (in ticks) between both vehicles
+ */
+int Vehicle::GetVehicleSeparation(Vehicle *v, bool add_this_current_order_time, bool add_other_current_order_time)
+{
+    /* If the compared vehicle is this vehicle, then the separation is 0, whatever the current order time */
+	if (this == v) return 0;
+
+	int this_position = this->GetTimetablePosition(add_this_current_order_time);
+	int other_position = v->GetTimetablePosition(add_other_current_order_time);
+
+	if (this_position <= other_position) {
+		/* The other vehicle is in front of this one. It's really easy to compute. */
+		return other_position - this_position;
+	} else {
+		/* The other vehicle is behind this one. We must add the total timetable duration minus the current order wait_time as we may start immediately. */
+		int total_timetable = this->GetTimetableTotalDuration();
+		return total_timetable + other_position - this_position;
+	}
+}
+
+/**
+ * Get the theorical current vehicle position in the timetable. This position is not the position in the shared orders chain,
+ * but actually the theorical duration since the vehicle started the timetabled orders list based on the current order.
+ * @param add_current_order_time Indicates if we get the current order time into account.
+ * @return numbers of ticks from the begining of the timetable without lateness_counter.
+ */
+int Vehicle::GetTimetablePosition(bool add_current_order_time)
+{
+	int total = 0;
+
+	/* Add current order time */
+	if (add_current_order_time) total += current_order_time;
+
+	Order *o = orders;
+	for (int i = 0; i < cur_order_index%num_orders; i++) {
+		total += o->travel_time + o->wait_time;
+		o = o->next;
+	}
+
+	if (last_station_visited == o->dest)
+	{
+		total += o->travel_time;
+	}
+
+	return total;
+}
+
+/**
+ * Gets the first order index where the vehicle stops at a station
+ * @return First order index vhere the vehicle stops at a station
+ */
+VehicleOrderID Vehicle::FirstStopStationOrderID()
+{
+	VehicleOrderID index = 0;
+	for (Order *first = this->orders; first != NULL; first = first->next) {
+		if (first->type == OT_GOTO_STATION && first->wait_time > 0) {
+			return index;
+		}
+		index++;
+	}
+	return INVALID_VEH_ORDER_ID;
+}
+
 Vehicle::~Vehicle()
 {
 	free(this->name);
@@ -3121,12 +3261,61 @@
 		 * that arrives at random stations is bad. */
 		this->current_order.flags |= OFB_NON_STOP;
 		UpdateVehicleTimetable(this, true);
+
+		/* We ensure the vehicle is well positionned in the shared order list
+		 * This means the last vehicle from this shared order list that visited the 
+		 * station must be its ->prev_shared */
+		if (_patches.timetabling && _patches.timetable_separation && this->prev_shared != NULL && this->IsOrderListShared() && this->FirstStopStationOrderID() == this->cur_order_index) {
+			/* Find the previous vehicle of the shared order that visited the station */
+			int min_separation = -1;
+			int tmp_separation = 0;
+			Vehicle *previous = NULL;
+			/* Check for previous vehicles */
+			for (Vehicle *v = this->prev_shared; v != NULL; v = v->prev_shared) {
+				tmp_separation = this->GetVehicleSeparation(v, false, true);
+				if (min_separation > 0 && tmp_separation < min_separation || min_separation == -1) {
+					min_separation = tmp_separation;
+					previous = v;
+				}
+			}
+			/* Check for next vehicles */
+			for (Vehicle *v = this->next_shared; v != NULL; v = v->next_shared) {
+				tmp_separation = this->GetVehicleSeparation(v, false, true);
+				if (min_separation > 0 && tmp_separation < min_separation || min_separation == -1) {
+					min_separation = tmp_separation;
+					previous = v;
+				}
+			}
+
+			/* Check if prev_shared vehicle is really the previous one and reorder the chain if needed */
+			if (this->prev_shared != previous && previous != NULL) {
+				/* Remove this vehicle from the list */
+				this->prev_shared->next_shared = this->next_shared;
+				if (this->next_shared != NULL) this->next_shared->prev_shared = this->prev_shared;
+				/* Insert in the list */
+				this->prev_shared = previous;
+				this->next_shared = previous->next_shared;
+				/* Update previous and next */
+				if (previous->next_shared != NULL) previous->next_shared->prev_shared = this;
+				previous->next_shared = this;
+			}
+		}
 	} else {
 		/* This is just an unordered intermediate stop */
 		this->current_order.flags = 0;
 	}
 
 	current_order.type = OT_LOADING;
+
+	/* For shared orders vehicles other than the first in chain arriving to the
+	 * first order station, we have to recompute the separation */
+	if (_patches.timetabling && _patches.timetable_separation && this->IsOrderListShared() && this->prev_shared != NULL && this->cur_order_index == this->FirstStopStationOrderID()) {
+		/* This vehicle have to ensure separation
+		 * Compute wait_time for auto-separation system
+		 * The vehicle can leave the station. Fill the lateness counter with separation informations, and override the actual waiting time. */
+		this->lateness_counter = -((GetTimetableTotalDuration() / CountSharedOrderdList()) - GetVehicleSeparation(prev_shared, false, true) - prev_shared->lateness_counter);
+	}
+
 	GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
 
 	VehiclePayment(this);
@@ -3160,8 +3349,8 @@
 {
 	switch (this->current_order.type) {
 		case OT_LOADING: {
+			/* Uses standard timetable system (no timetable, no shared orders, first vehicle, etc.) */
 			uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
-
 			/* Not the first call for this tick, or still loading */
 			if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
 					(_patches.timetabling && this->current_order_time < wait_time)) return;
Index: src/vehicle_base.h
===================================================================
--- src/vehicle_base.h	(revision 12038)
+++ src/vehicle_base.h	(working copy)
@@ -461,6 +461,20 @@
 	 * @return the first vehicle of the chain.
 	 */
 	inline Vehicle *First() const { return this->first; }
+
+	/**
+	 * Checks if the vehicle shares its orders with another vehicle
+	 * @return true if the vehicle is in a shared orders chain
+	 */
+	bool IsOrderListShared() const { return this->prev_shared != NULL || this->next_shared != NULL; }
+	bool IsVehicleInSharedOrdersList(Vehicle *v);
+	int CountSharedOrderdList();
+	int GetPositionInSharedOrderList();
+	int GetTimetableTotalDuration();
+	int GetFirstSharedSeparation();
+	int GetVehicleSeparation(Vehicle *v, bool add_this_current_order_time, bool add_other_current_order_time);
+	int GetTimetablePosition(bool add_current_order_time);
+	VehicleOrderID FirstStopStationOrderID();
 };
 
 /**
