src/train_cmd.cpp
branchNewGRF_ports
changeset 6719 4cc327ad39d5
parent 6683 7ec558346172
child 6720 35756db7e577
--- a/src/train_cmd.cpp	Tue Mar 27 23:27:27 2007 +0000
+++ b/src/train_cmd.cpp	Sat Jun 02 19:59:29 2007 +0000
@@ -1,10 +1,13 @@
 /* $Id$ */
 
+/** @file train_cmd.cpp */
+
 #include "stdafx.h"
 #include "openttd.h"
 #include "bridge_map.h"
 #include "debug.h"
 #include "functions.h"
+#include "landscape.h"
 #include "gui.h"
 #include "station_map.h"
 #include "table/strings.h"
@@ -12,6 +15,7 @@
 #include "tile.h"
 #include "tunnel_map.h"
 #include "vehicle.h"
+#include "articulated_vehicles.h"
 #include "command.h"
 #include "pathfind.h"
 #include "npf.h"
@@ -34,6 +38,7 @@
 #include "yapf/yapf.h"
 #include "date.h"
 #include "cargotype.h"
+#include "group.h"
 
 static bool TrainCheckIfLineEnds(Vehicle *v);
 static void TrainController(Vehicle *v, bool update_image);
@@ -60,7 +65,7 @@
  */
 void TrainPowerChanged(Vehicle* v)
 {
-	uint32 power = 0;
+	uint32 total_power = 0;
 	uint32 max_te = 0;
 
 	for (const Vehicle *u = v; u != NULL; u = u->next) {
@@ -73,19 +78,22 @@
 
 		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
 
-		if (engine_has_power && rvi_u->power != 0) {
-			power += rvi_u->power;
-			/* Tractive effort in (tonnes * 1000 * 10 =) N */
-			max_te += (u->u.rail.cached_veh_weight * 10000 * rvi_u->tractive_effort) / 256;
+		if (engine_has_power) {
+			uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
+			if (power != 0) {
+				total_power += power;
+				/* Tractive effort in (tonnes * 1000 * 10 =) N */
+				max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
+			}
 		}
 
 		if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON) && (wagon_has_power)) {
-			power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
+			total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
 		}
 	}
 
-	if (v->u.rail.cached_power != power || v->u.rail.cached_max_te != max_te) {
-		v->u.rail.cached_power = power;
+	if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
+		v->u.rail.cached_power = total_power;
 		v->u.rail.cached_max_te = max_te;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
@@ -105,24 +113,24 @@
 	for (Vehicle *u = v; u != NULL; u = u->next) {
 		uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16;
 
-		// Vehicle weight is not added for articulated parts.
+		/* Vehicle weight is not added for articulated parts. */
 		if (!IsArticulatedPart(u)) {
-			// vehicle weight is the sum of the weight of the vehicle and the weight of its cargo
-			vweight += RailVehInfo(u->engine_type)->weight;
-
-			// powered wagons have extra weight added
+			/* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
+			vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
+
+			/* powered wagons have extra weight added */
 			if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON))
 				vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
 		}
 
-		// consist weight is the sum of the weight of all vehicles in the consist
+		/* consist weight is the sum of the weight of all vehicles in the consist */
 		weight += vweight;
 
-		// store vehicle weight in cache
+		/* store vehicle weight in cache */
 		u->u.rail.cached_veh_weight = vweight;
 	}
 
-	// store consist weight in cache
+	/* store consist weight in cache */
 	v->u.rail.cached_weight = weight;
 
 	/* Now update train power (tractive effort is dependent on weight) */
@@ -151,26 +159,29 @@
 	for (Vehicle *u = v; u != NULL; u = u->next) {
 		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
 
-		// Update the v->first cache. This is faster than having to brute force it later.
+		/* Update the v->first cache. This is faster than having to brute force it later. */
 		if (u->first == NULL) u->first = v;
 
-		// update the 'first engine'
+		/* update the 'first engine' */
 		u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
 		u->u.rail.railtype = rvi_u->railtype;
 
 		if (IsTrainEngine(u)) first_engine = u->engine_type;
 
+		/* Cache wagon override sprite group. NULL is returned if there is none */
+		u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
+
 		if (rvi_u->visual_effect != 0) {
 			u->u.rail.cached_vis_effect = rvi_u->visual_effect;
 		} else {
 			if (IsTrainWagon(u) || IsArticulatedPart(u)) {
-				// Wagons and articulated parts have no effect by default
+				/* Wagons and articulated parts have no effect by default */
 				u->u.rail.cached_vis_effect = 0x40;
 			} else if (rvi_u->engclass == 0) {
-				// Steam is offset by -4 units
+				/* Steam is offset by -4 units */
 				u->u.rail.cached_vis_effect = 4;
 			} else {
-				// Diesel fumes and sparks come from the centre
+				/* Diesel fumes and sparks come from the centre */
 				u->u.rail.cached_vis_effect = 8;
 			}
 		}
@@ -184,7 +195,7 @@
 			}
 
 			if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
-				UsesWagonOverride(u) && (u->u.rail.cached_vis_effect < 0x40)) {
+				UsesWagonOverride(u) && !HASBIT(u->u.rail.cached_vis_effect, 7)) {
 				/* wagon is powered */
 				SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
 			} else {
@@ -204,13 +215,19 @@
 				u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
 			}
 
-			// max speed is the minimum of the speed limits of all vehicles in the consist
-			if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) &&
-				rvi_u->max_speed != 0 && !UsesWagonOverride(u))
-				max_speed = min(rvi_u->max_speed, max_speed);
+			/* max speed is the minimum of the speed limits of all vehicles in the consist */
+			if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && !UsesWagonOverride(u)) {
+				uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed);
+				if (speed != 0) max_speed = min(speed, max_speed);
+			}
 		}
 
-		// check the vehicle length (callback)
+		if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) {
+			/* Set cargo capacity if we've not been refitted */
+			u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
+		}
+
+		/* check the vehicle length (callback) */
 		uint16 veh_len = CALLBACK_FAILED;
 		if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
 			veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
@@ -221,10 +238,10 @@
 		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
 	}
 
-	// store consist weight/max speed in cache
+	/* store consist weight/max speed in cache */
 	v->u.rail.cached_max_speed = max_speed;
 
-	// recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added)
+	/* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */
 	TrainCargoChanged(v);
 }
 
@@ -263,8 +280,8 @@
 	StationID sid = GetStationIndex(tile);
 
 	assert(v->type == VEH_TRAIN);
-	//When does a train drive through a station
-	//first we deal with the "new nonstop handling"
+	/* When does a train drive through a station
+	 * first we deal with the "new nonstop handling" */
 	if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) {
 		return false;
 	}
@@ -278,14 +295,14 @@
 	return true;
 }
 
-//new acceleration
+/** new acceleration*/
 static int GetTrainAcceleration(Vehicle *v, bool mode)
 {
 	int max_speed = 2000;
 	int speed = v->cur_speed * 10 / 16; //[mph]
 	int curvecount[2] = {0, 0};
 
-	//first find the curve speed limit
+	/*first find the curve speed limit */
 	int numcurve = 0;
 	int sum = 0;
 	int pos = 0;
@@ -309,7 +326,7 @@
 			}
 		}
 
-		//if we have a 90 degree turn, fix the speed limit to 60
+		/*if we have a 90 degree turn, fix the speed limit to 60 */
 		if (_curve_neighbours90[dir][0] == ndir ||
 				_curve_neighbours90[dir][1] == ndir) {
 			max_speed = 61;
@@ -402,7 +419,7 @@
 				break;
 		}
 	} else {
-		//"kickoff" acceleration
+		/* "kickoff" acceleration */
 		force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
 		force = max(force, (mass * 8) + resistance);
 	}
@@ -485,82 +502,12 @@
 	DrawSprite(image, pal, x, y);
 }
 
-uint CountArticulatedParts(EngineID engine_type)
-{
-	if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0;
-
-	uint i;
-	for (i = 1; i < 10; i++) {
-		uint16 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, engine_type, NULL);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
-	}
-
-	return i - 1;
-}
-
-static void AddArticulatedParts(Vehicle **vl)
-{
-	const Vehicle *v = vl[0];
-	Vehicle *u = vl[0];
-
-	if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return;
-
-	for (uint i = 1; i < 10; i++) {
-		uint16 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, v->engine_type, v);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) return;
-
-		/* Attempt to use pre-allocated vehicles until they run out. This can happen
-		 * if the callback returns different values depending on the cargo type. */
-		u->next = vl[i];
-		if (u->next == NULL) u->next = AllocateVehicle();
-		if (u->next == NULL) return;
-
-		u = u->next;
-
-		EngineID engine_type = GB(callback, 0, 7);
-		bool flip_image = HASBIT(callback, 7);
-		const RailVehicleInfo *rvi_artic = RailVehInfo(engine_type);
-
-		// get common values from first engine
-		u->direction = v->direction;
-		u->owner = v->owner;
-		u->tile = v->tile;
-		u->x_pos = v->x_pos;
-		u->y_pos = v->y_pos;
-		u->z_pos = v->z_pos;
-		u->z_height = v->z_height;
-		u->u.rail.track = v->u.rail.track;
-		u->u.rail.railtype = v->u.rail.railtype;
-		u->build_year = v->build_year;
-		u->vehstatus = v->vehstatus & ~VS_STOPPED;
-		u->u.rail.first_engine = v->engine_type;
-
-		// get more settings from rail vehicle info
-		u->spritenum = rvi_artic->image_index;
-		if (flip_image) u->spritenum++;
-		u->cargo_type = rvi_artic->cargo_type;
-		u->cargo_subtype = 0;
-		u->cargo_cap = rvi_artic->capacity;
-		u->max_speed = 0;
-		u->max_age = 0;
-		u->engine_type = engine_type;
-		u->value = 0;
-		u->type = VEH_TRAIN;
-		u->subtype = 0;
-		SetArticulatedPart(u);
-		u->cur_image = 0xAC2;
-		u->random_bits = VehicleRandomBits();
-
-		VehiclePositionChanged(u);
-	}
-}
-
 static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
 {
 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
 
 	const RailVehicleInfo *rvi = RailVehInfo(engine);
-	int32 value = (rvi->base_cost * _price.build_railwagon) >> 8;
+	int32 value = (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8;
 
 	uint num_vehicles = 1 + CountArticulatedParts(engine);
 
@@ -601,12 +548,13 @@
 			v->y_pos = y;
 			v->z_pos = GetSlopeZ(x, y);
 			v->owner = _current_player;
-			v->z_height = 6;
 			v->u.rail.track = TRACK_BIT_DEPOT;
 			v->vehstatus = VS_HIDDEN | VS_DEFPAL;
 
+			v = new (v) Train();
 			v->subtype = 0;
 			SetTrainWagon(v);
+
 			if (u != NULL) {
 				u->next = v;
 			} else {
@@ -623,16 +571,18 @@
 			v->u.rail.railtype = rvi->railtype;
 
 			v->build_year = _cur_year;
-			v->type = VEH_TRAIN;
 			v->cur_image = 0xAC2;
 			v->random_bits = VehicleRandomBits();
 
+			v->group_id = DEFAULT_GROUP;
+
 			AddArticulatedParts(vl);
 
 			_new_vehicle_id = v->index;
 
 			VehiclePositionChanged(v);
 			TrainConsistChanged(GetFirstVehicleInChain(v));
+			UpdateTrainGroupID(GetFirstVehicleInChain(v));
 
 			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 			if (IsLocalPlayer()) {
@@ -645,7 +595,7 @@
 	return value;
 }
 
-// Move all free vehicles in the depot to the train
+/** Move all free vehicles in the depot to the train */
 static void NormalizeTrainVehInDepot(const Vehicle* u)
 {
 	const Vehicle* v;
@@ -661,9 +611,9 @@
 	}
 }
 
-static int32 EstimateTrainCost(const RailVehicleInfo* rvi)
+static int32 EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi)
 {
-	return rvi->base_cost * (_price.build_railvehicle >> 3) >> 5;
+	return GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5;
 }
 
 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
@@ -674,9 +624,9 @@
 	u->x_pos = v->x_pos;
 	u->y_pos = v->y_pos;
 	u->z_pos = v->z_pos;
-	u->z_height = 6;
 	u->u.rail.track = TRACK_BIT_DEPOT;
 	u->vehstatus = v->vehstatus & ~VS_STOPPED;
+	u = new (u) Train();
 	u->subtype = 0;
 	SetMultiheaded(u);
 	u->spritenum = v->spritenum + 1;
@@ -689,7 +639,6 @@
 	u->build_year = v->build_year;
 	if (building) v->value >>= 1;
 	u->value = v->value;
-	u->type = VEH_TRAIN;
 	u->cur_image = 0xAC2;
 	u->random_bits = VehicleRandomBits();
 	VehiclePositionChanged(u);
@@ -697,6 +646,7 @@
 
 /** Build a railroad vehicle.
  * @param tile tile of the depot where rail-vehicle is built
+ * @param flags type of operation
  * @param p1 engine type id
  * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number
  *           bit 1 prevents any free cars from being added to the train
@@ -704,7 +654,7 @@
 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	/* Check if the engine-type is valid (for the player) */
-	if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
+	if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
 
 	/* Check if the train is actually being built in a depot belonging
 	 * to the player. Doesn't matter if only the cost is queried */
@@ -723,7 +673,7 @@
 
 	if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
 
-	int32 value = EstimateTrainCost(rvi);
+	int32 value = EstimateTrainCost(p1, rvi);
 
 	uint num_vehicles =
 		(rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
@@ -755,7 +705,6 @@
 			v->x_pos = x;
 			v->y_pos = y;
 			v->z_pos = GetSlopeZ(x, y);
-			v->z_height = 6;
 			v->u.rail.track = TRACK_BIT_DEPOT;
 			v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 			v->spritenum = rvi->image_index;
@@ -781,13 +730,15 @@
 			v->service_interval = _patches.servint_trains;
 			v->date_of_last_service = _date;
 			v->build_year = _cur_year;
-			v->type = VEH_TRAIN;
+			v = new (v) Train();
 			v->cur_image = 0xAC2;
 			v->random_bits = VehicleRandomBits();
 
 			v->vehicle_flags = 0;
 			if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SETBIT(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
+			v->group_id = DEFAULT_GROUP;
+
 			v->subtype = 0;
 			SetFrontEngine(v);
 			SetTrainEngine(v);
@@ -809,6 +760,7 @@
 
 			TrainConsistChanged(v);
 			UpdateTrainAcceleration(v);
+			UpdateTrainGroupID(v);
 
 			if (!HASBIT(p2, 1)) { // check if the cars should be added to the new vehicle
 				NormalizeTrainVehInDepot(v);
@@ -874,7 +826,7 @@
  */
 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
 {
-	// unlinking the first vehicle of the chain?
+	/* unlinking the first vehicle of the chain? */
 	if (v == first) {
 		v = GetNextVehicle(v);
 		if (v == NULL) return NULL;
@@ -887,6 +839,7 @@
 	Vehicle *u;
 	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
 	GetLastEnginePart(u)->next = GetNextVehicle(v);
+	v->first = NULL; // we shouldn't point to the old first, since the vehicle isn't in that chain anymore
 	return first;
 }
 
@@ -898,7 +851,7 @@
 
 	FOR_ALL_VEHICLES(dst) {
 		if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile) {
-			// check so all vehicles in the line have the same engine.
+			/* check so all vehicles in the line have the same engine. */
 			Vehicle *v = dst;
 
 			while (v->engine_type == eng) {
@@ -950,6 +903,7 @@
 
 /** Move a rail vehicle around inside the depot.
  * @param tile unused
+ * @param flags type of operation
  * @param p1 various bitstuffed elements
  * - p1 (bit  0 - 15) source vehicle index
  * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line
@@ -966,7 +920,7 @@
 
 	if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR;
 
-	// if nothing is selected as destination, try and find a matching vehicle to drag to.
+	/* if nothing is selected as destination, try and find a matching vehicle to drag to. */
 	Vehicle *dst;
 	if (d == INVALID_VEHICLE) {
 		dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
@@ -976,13 +930,13 @@
 		if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
 	}
 
-	// if an articulated part is being handled, deal with its parent vehicle
+	/* if an articulated part is being handled, deal with its parent vehicle */
 	while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src);
 	if (dst != NULL) {
 		while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst);
 	}
 
-	// don't move the same vehicle..
+	/* don't move the same vehicle.. */
 	if (src == dst) return 0;
 
 	/* locate the head of the two chains */
@@ -991,92 +945,59 @@
 	if (dst != NULL) {
 		dst_head = GetFirstVehicleInChain(dst);
 		if (dst_head->tile != src_head->tile) return CMD_ERROR;
-		// Now deal with articulated part of destination wagon
+		/* Now deal with articulated part of destination wagon */
 		dst = GetLastEnginePart(dst);
 	} else {
 		dst_head = NULL;
 	}
 
-	if (dst != NULL && IsMultiheaded(dst) && !IsTrainEngine(dst) && IsTrainWagon(src)) {
-		/* We are moving a wagon to the rear part of a multiheaded engine */
-		if (dst->next == NULL) {
-			/* It's the last one, so we will add the wagon just before the rear engine */
-			dst = GetPrevVehicleInChain(dst);
-			/* Now if the vehicle we want to link to is the vehicle itself, drop out */
-			if (dst == src) return CMD_ERROR;
-			// if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that
-			if (dst == NULL) return CMD_ERROR;
-		} else {
-			/* there are more units on this train, so we will add the wagon after the next one*/
-			dst = dst->next;
-		}
-	}
-
-	if (IsTrainEngine(src) && dst_head != NULL) {
-		/* we need to make sure that we didn't place it between a pair of multiheaded engines */
-		Vehicle *engine = NULL;
-
-		for (Vehicle *u = dst_head; u != NULL; u = u->next) {
-			if (IsTrainEngine(u) && IsMultiheaded(u) && u->u.rail.other_multiheaded_part != NULL) {
-				engine = u;
-			}
-			if (engine != NULL && engine->u.rail.other_multiheaded_part == u) {
-				engine = NULL;
-			}
-			if (u == dst) {
-				if (engine != NULL) dst = engine->u.rail.other_multiheaded_part;
-				break;
-			}
-		}
-	}
-
 	if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
 
-	// when moving all wagons, we can't have the same src_head and dst_head
+	/* when moving all wagons, we can't have the same src_head and dst_head */
 	if (HASBIT(p2, 0) && src_head == dst_head) return 0;
 
 	{
 		int max_len = _patches.mammoth_trains ? 100 : 9;
 
-		// check if all vehicles in the source train are stopped inside a depot.
+		/* check if all vehicles in the source train are stopped inside a depot. */
 		int src_len = CheckTrainStoppedInDepot(src_head);
 		if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
 
-		// check the destination row if the source and destination aren't the same.
+		/* check the destination row if the source and destination aren't the same. */
 		if (src_head != dst_head) {
 			int dst_len = 0;
 
 			if (dst_head != NULL) {
-				// check if all vehicles in the dest train are stopped.
+				/* check if all vehicles in the dest train are stopped. */
 				dst_len = CheckTrainStoppedInDepot(dst_head);
 				if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
 			}
 
-			// We are moving between rows, so only count the wagons from the source
-			// row that are being moved.
+			/* We are moving between rows, so only count the wagons from the source
+			 * row that are being moved. */
 			if (HASBIT(p2, 0)) {
 				const Vehicle *u;
 				for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
 					src_len--;
 			} else {
-				// If moving only one vehicle, just count that.
+				/* If moving only one vehicle, just count that. */
 				src_len = 1;
 			}
 
 			if (src_len + dst_len > max_len) {
-				// Abort if we're adding too many wagons to a train.
+				/* Abort if we're adding too many wagons to a train. */
 				if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
-				// Abort if we're making a train on a new row.
+				/* Abort if we're making a train on a new row. */
 				if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
 			}
 		} else {
-			// Abort if we're creating a new train on an existing row.
+			/* Abort if we're creating a new train on an existing row. */
 			if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
 				return_cmd_error(STR_8819_TRAIN_TOO_LONG);
 		}
 	}
 
-	// moving a loco to a new line?, then we need to assign a unitnumber.
+	/* moving a loco to a new line?, then we need to assign a unitnumber. */
 	if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
 		UnitID unit_num = GetFreeUnitNumber(VEH_TRAIN);
 		if (unit_num > _patches.max_trains)
@@ -1103,8 +1024,18 @@
 		for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL;
 		for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL;
 
+		/* If we move the front Engine and if the second vehicle is not an engine
+		   add the whole vehicle to the DEFAULT_GROUP */
+		if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
+			const Vehicle *v = GetNextVehicle(src);
+
+			if (v != NULL && !IsTrainEngine(v)) {
+				DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP);
+			}
+		}
+
 		if (HASBIT(p2, 0)) {
-			// unlink ALL wagons
+			/* unlink ALL wagons */
 			if (src != src_head) {
 				Vehicle *v = src_head;
 				while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
@@ -1114,9 +1045,9 @@
 				src_head = NULL;
 			}
 		} else {
-			// if moving within the same chain, dont use dst_head as it may get invalidated
+			/* if moving within the same chain, dont use dst_head as it may get invalidated */
 			if (src_head == dst_head) dst_head = NULL;
-			// unlink single wagon from linked list
+			/* unlink single wagon from linked list */
 			src_head = UnlinkWagon(src, src_head);
 			GetLastEnginePart(src)->next = NULL;
 		}
@@ -1125,13 +1056,21 @@
 			/* We make a new line in the depot, so we know already that we invalidate the window data */
 			InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
 
-			// move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4.
+			/* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */
 			if (IsTrainEngine(src)) {
 				if (!IsFrontEngine(src)) {
-					// setting the type to 0 also involves setting up the orders field.
+					/* setting the type to 0 also involves setting up the orders field. */
 					SetFrontEngine(src);
 					assert(src->orders == NULL);
 					src->num_orders = 0;
+
+					// Decrease the engines number of the src engine_type
+					if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) {
+						GetGroup(src->group_id)->num_engines[src->engine_type]--;
+					}
+
+					// If we move an engine to a new line affect it to the DEFAULT_GROUP
+					src->group_id = DEFAULT_GROUP;
 				}
 			} else {
 				SetFreeWagon(src);
@@ -1139,7 +1078,7 @@
 			dst_head = src;
 		} else {
 			if (IsFrontEngine(src)) {
-				// the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
+				/* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */
 				DeleteWindowById(WC_VEHICLE_VIEW, src->index);
 				DeleteVehicleOrders(src);
 			}
@@ -1151,7 +1090,7 @@
 				src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
 			}
 
-			// link in the wagon(s) in the chain.
+			/* link in the wagon(s) in the chain. */
 			{
 				Vehicle *v;
 
@@ -1165,41 +1104,26 @@
 				src_head = src_head->next;
 			}
 			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
-			// previous line set the front engine to the old front. We need to clear that
+			/* previous line set the front engine to the old front. We need to clear that */
 			src->u.rail.other_multiheaded_part->first = NULL;
 		}
 
-		if (HASBIT(p2, 0) && src_head != NULL && src_head != src) {
-			/* if we stole a rear multiheaded engine, we better give it back to the front end */
-			Vehicle *engine = NULL, *u;
-			for (u = src_head; u != NULL; u = u->next) {
-				if (IsMultiheaded(u)) {
-					if (IsTrainEngine(u)) {
-						engine = u;
-						continue;
-					}
-					/* we got the rear engine to match with the front one */
-					engine = NULL;
-				}
-			}
-			if (engine != NULL && engine->u.rail.other_multiheaded_part != NULL) {
-				AddWagonToConsist(engine->u.rail.other_multiheaded_part, engine);
-				// previous line set the front engine to the old front. We need to clear that
-				engine->u.rail.other_multiheaded_part->first = NULL;
-			}
-		}
-
 		/* If there is an engine behind first_engine we moved away, it should become new first_engine
 		 * To do this, CmdMoveRailVehicle must be called once more
 		 * we can't loop forever here because next time we reach this line we will have a front engine */
 		if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
+			/* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
+			 * we need to save the group and reaffect it to src_head */
+			const GroupID tmp_g = src_head->group_id;
 			CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1);
+			SetTrainGroupID(src_head, tmp_g);
 			src_head = NULL; // don't do anything more to this train since the new call will do it
 		}
 
 		if (src_head != NULL) {
 			NormaliseTrainConsist(src_head);
 			TrainConsistChanged(src_head);
+			UpdateTrainGroupID(src_head);
 			if (IsFrontEngine(src_head)) {
 				UpdateTrainAcceleration(src_head);
 				InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
@@ -1214,6 +1138,7 @@
 		if (dst_head != NULL) {
 			NormaliseTrainConsist(dst_head);
 			TrainConsistChanged(dst_head);
+			UpdateTrainGroupID(dst_head);
 			if (IsFrontEngine(dst_head)) {
 				UpdateTrainAcceleration(dst_head);
 				InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
@@ -1233,6 +1158,7 @@
 
 /** Start/Stop a train.
  * @param tile unused
+ * @param flags type of operation
  * @param p1 train to start/stop
  * @param p2 unused
  */
@@ -1259,7 +1185,6 @@
 			DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT);
 		}
 
-		v->u.rail.days_since_order_progr = 0;
 		v->vehstatus ^= VS_STOPPED;
 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
@@ -1269,6 +1194,7 @@
 
 /** Sell a (single) train wagon/engine.
  * @param tile unused
+ * @param flags type of operation
  * @param p1 the wagon/engine index
  * @param p2 the selling mode
  * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines)
@@ -1290,7 +1216,7 @@
 	while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
 	Vehicle *first = GetFirstVehicleInChain(v);
 
-	// make sure the vehicle is stopped in the depot
+	/* make sure the vehicle is stopped in the depot */
 	if (CheckTrainStoppedInDepot(first) < 0) {
 		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
 	}
@@ -1353,6 +1279,8 @@
 					if (first->next_shared != NULL) {
 						first->next_shared->prev_shared = new_f;
 						new_f->next_shared = first->next_shared;
+					} else {
+						RemoveVehicleFromGroup(v);
 					}
 
 					/*
@@ -1383,6 +1311,7 @@
 				if (first != NULL) {
 					NormaliseTrainConsist(first);
 					TrainConsistChanged(first);
+					UpdateTrainGroupID(first);
 					if (IsFrontEngine(first)) {
 						InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
 						InvalidateWindow(WC_VEHICLE_REFIT, first->index);
@@ -1419,6 +1348,15 @@
 
 						if (rear != NULL) {
 							cost -= rear->value;
+
+							/* If this is a multiheaded vehicle with nothing
+							 * between the parts, tmp will be pointing to the
+							 * rear part, which is unlinked from the train and
+							 * deleted here. However, because tmp has already
+							 * been set it needs to be updated now so that the
+							 * loop never sees the rear part. */
+							if (tmp == rear) tmp = GetNextVehicle(tmp);
+
 							if (flags & DC_EXEC) {
 								first = UnlinkWagon(rear, first);
 								DeleteDepotHighlightOfVehicle(rear);
@@ -1436,6 +1374,7 @@
 					first = UnlinkWagon(v, first);
 					DeleteDepotHighlightOfVehicle(v);
 					DeleteVehicle(v);
+					RemoveVehicleFromGroup(v);
 				}
 			}
 
@@ -1443,6 +1382,7 @@
 			if (flags & DC_EXEC && first != NULL) {
 				NormaliseTrainConsist(first);
 				TrainConsistChanged(first);
+				UpdateTrainGroupID(first);
 				if (IsFrontEngine(first)) UpdateTrainAcceleration(first);
 				InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
 				InvalidateWindow(WC_VEHICLE_REFIT, first->index);
@@ -1452,9 +1392,9 @@
 	return cost;
 }
 
-static void UpdateTrainDeltaXY(Vehicle *v, Direction direction)
+void Train::UpdateDeltaXY(Direction direction)
 {
-#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
+#define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
 	static const uint32 _delta_xy_table[8] = {
 		MKIT(3, 3, -1, -1),
 		MKIT(3, 7, -1, -3),
@@ -1468,16 +1408,16 @@
 #undef MKIT
 
 	uint32 x = _delta_xy_table[direction];
-
-	v->x_offs        = GB(x,  0, 8);
-	v->y_offs        = GB(x,  8, 8);
-	v->sprite_width  = GB(x, 16, 8);
-	v->sprite_height = GB(x, 24, 8);
+	this->x_offs        = GB(x,  0, 8);
+	this->y_offs        = GB(x,  8, 8);
+	this->sprite_width  = GB(x, 16, 8);
+	this->sprite_height = GB(x, 24, 8);
+	this->z_height      = 6;
 }
 
 static void UpdateVarsAfterSwap(Vehicle *v)
 {
-	UpdateTrainDeltaXY(v, v->direction);
+	v->UpdateDeltaXY(v->direction);
 	v->cur_image = GetTrainImage(v, v->direction);
 	BeginVehicleMove(v);
 	VehiclePositionChanged(v);
@@ -1596,8 +1536,8 @@
 	uint length = CountVehiclesInChain(v);
 
 	while (length > 2) {
-		// find pairwise matching wagon
-		// start<>end, start+1<>end-1, ...
+		/* find pairwise matching wagon
+		 * start<>end, start+1<>end-1, ... */
 		Vehicle *last = first;
 		for (uint i = length - 3; i > 0; i--) last = last->next;
 
@@ -1605,7 +1545,7 @@
 		if (before) differential *= -1;
 
 		if (differential > 0) {
-			// disconnect last car to make sure only this subset moves
+			/* disconnect last car to make sure only this subset moves */
 			Vehicle *tempnext = last->next;
 			last->next = NULL;
 
@@ -1643,7 +1583,7 @@
 		DisableTrainCrossing(tile);
 	}
 
-	// count number of vehicles
+	/* count number of vehicles */
 	int r = -1;
 	const Vehicle *u = v;
 	do r++; while ( (u = u->next) != NULL );
@@ -1667,6 +1607,7 @@
 
 /** Reverse train.
  * @param tile unused
+ * @param flags type of operation
  * @param p1 train to reverse
  * @param p2 if true, reverse a unit in a train (needs to be in a depot)
  */
@@ -1679,14 +1620,14 @@
 	if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
 
 	if (p2) {
-		// turn a single unit around
+		/* turn a single unit around */
 
 		if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) {
 			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
 		}
 
 		Vehicle *front = GetFirstVehicleInChain(v);
-		// make sure the vehicle is stopped in the depot
+		/* make sure the vehicle is stopped in the depot */
 		if (CheckTrainStoppedInDepot(front) < 0) {
 			return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
 		}
@@ -1697,7 +1638,7 @@
 			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 		}
 	} else {
-		//turn the whole train around
+		/*turn the whole train around */
 		if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR;
 
 		if (flags & DC_EXEC) {
@@ -1715,6 +1656,7 @@
 
 /** Force a train through a red signal
  * @param tile unused
+ * @param flags type of operation
  * @param p1 train to ignore the red signal
  * @param p2 unused
  */
@@ -1733,15 +1675,19 @@
 
 /** Refits a train to the specified cargo type.
  * @param tile unused
+ * @param flags type of operation
  * @param p1 vehicle ID of the train to refit
  * param p2 various bitstuffed elements
  * - p2 = (bit 0-7) - the new cargo type to refit to
  * - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle
+ * @return cost of refit or error
  */
 int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	CargoID new_cid = GB(p2, 0, 8);
 	byte new_subtype = GB(p2, 8, 8);
+	bool only_this = HASBIT(p2, 16);
 
 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
 
@@ -1819,7 +1765,7 @@
 				}
 			}
 		}
-	} while ((v = v->next) != NULL);
+	} while ((v = v->next) != NULL && !only_this);
 
 	_returned_refit_capacity = num;
 
@@ -1854,8 +1800,8 @@
 	return false;
 }
 
-// returns the tile of a depot to goto to. The given vehicle must not be
-// crashed!
+/** returns the tile of a depot to goto to. The given vehicle must not be
+ * crashed! */
 static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
 {
 	assert(!(v->vehstatus & VS_CRASHED));
@@ -1881,7 +1827,7 @@
 		Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
 
 		assert(trackdir != INVALID_TRACKDIR);
-		NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
+		NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
 		if (ftd.best_bird_dist == 0) {
 			/* Found target */
 			tfdd.tile = ftd.node.tile;
@@ -1893,7 +1839,7 @@
 			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
 		}
 	} else {
-		// search in the forward direction first.
+		/* search in the forward direction first. */
 		DiagDirection i = DirToDiagDir(v->direction);
 		if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
 			i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
@@ -1901,7 +1847,7 @@
 		NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
 		if (tfdd.best_length == (uint)-1){
 			tfdd.reverse = true;
-			// search in backwards direction
+			/* search in backwards direction */
 			i = ReverseDiagDir(DirToDiagDir(v->direction));
 			if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) {
 				i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT);
@@ -1915,6 +1861,7 @@
 
 /** Send a train to a depot
  * @param tile unused
+ * @param flags type of operation
  * @param p1 train to send to the depot
  * @param p2 various bitmasked elements
  * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
@@ -1951,7 +1898,6 @@
 		if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
 		if (flags & DC_EXEC) {
 			if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
-				v->u.rail.days_since_order_progr = 0;
 				v->cur_order_index++;
 			}
 
@@ -1970,6 +1916,8 @@
 	if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO);
 
 	if (flags & DC_EXEC) {
+		if (v->current_order.type == OT_LOADING) v->LeaveStation();
+
 		v->dest_tile = tfdd.tile;
 		v->current_order.type = OT_GOTO_DEPOT;
 		v->current_order.flags = OF_NON_STOP;
@@ -1978,8 +1926,7 @@
 		v->current_order.refit_cargo = CT_INVALID;
 		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 		/* If there is no depot in front, reverse automatically */
-		if (tfdd.reverse)
-			DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
+		if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
 	}
 
 	return 0;
@@ -2010,22 +1957,21 @@
 		byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
 		bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6);
 
-		// no smoke?
+		/* no smoke? */
 		if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
 				disable_effect ||
-				rvi->railtype > RAILTYPE_ELECTRIC ||
 				v->vehstatus & VS_HIDDEN) {
 			continue;
 		}
 
-		// No smoke in depots or tunnels
+		/* No smoke in depots or tunnels */
 		if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue;
 
-		// No sparks for electric vehicles on nonelectrified tracks
+		/* No sparks for electric vehicles on nonelectrified tracks */
 		if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile))) continue;
 
 		if (effect_type == 0) {
-			// Use default effect type for engine class.
+			/* Use default effect type for engine class. */
 			effect_type = rvi->engclass;
 		} else {
 			effect_type--;
@@ -2041,7 +1987,7 @@
 
 		switch (effect_type) {
 		case 0:
-			// steam smoke.
+			/* steam smoke. */
 			if (GB(v->tick_counter, 0, 4) == 0) {
 				CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
 				sound = true;
@@ -2049,7 +1995,7 @@
 			break;
 
 		case 1:
-			// diesel smoke
+			/* diesel smoke */
 			if (u->cur_speed <= 40 && CHANCE16(15, 128)) {
 				CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
 				sound = true;
@@ -2057,7 +2003,7 @@
 			break;
 
 		case 2:
-			// blue spark
+			/* blue spark */
 			if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) {
 				CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
 				sound = true;
@@ -2074,32 +2020,30 @@
 	static const SoundFx sfx[] = {
 		SND_04_TRAIN,
 		SND_0A_TRAIN_HORN,
-		SND_0A_TRAIN_HORN
+		SND_0A_TRAIN_HORN,
+		SND_47_MAGLEV_2,
+		SND_41_MAGLEV
 	};
 
 	if (PlayVehicleSound(v, VSE_START)) return;
 
 	EngineID engtype = v->engine_type;
-	switch (RailVehInfo(engtype)->railtype) {
-		case RAILTYPE_RAIL:
-		case RAILTYPE_ELECTRIC:
-			SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
-			break;
-
-		case RAILTYPE_MONO: SndPlayVehicleFx(SND_47_MAGLEV_2, v); break;
-		case RAILTYPE_MAGLEV: SndPlayVehicleFx(SND_41_MAGLEV, v); break;
-		default: NOT_REACHED();
-	}
+	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
+}
+
+void Train::PlayLeaveStationSound() const
+{
+	TrainPlayLeaveStationSound(this);
 }
 
 static bool CheckTrainStayInDepot(Vehicle *v)
 {
-	// bail out if not all wagons are in the same depot or not in a depot at all
+	/* bail out if not all wagons are in the same depot or not in a depot at all */
 	for (const Vehicle *u = v; u != NULL; u = u->next) {
 		if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
 	}
 
-	// if the train got no power, then keep it in the depot
+	/* if the train got no power, then keep it in the depot */
 	if (v->u.rail.cached_power == 0) {
 		v->vehstatus |= VS_STOPPED;
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
@@ -2130,7 +2074,7 @@
 	v->vehstatus &= ~VS_HIDDEN;
 	v->cur_speed = 0;
 
-	UpdateTrainDeltaXY(v, v->direction);
+	v->UpdateDeltaXY(v->direction);
 	v->cur_image = GetTrainImage(v, v->direction);
 	VehiclePositionChanged(v);
 	UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
@@ -2151,10 +2095,10 @@
 
 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length)
 {
-	// heading for nowhere?
+	/* heading for nowhere? */
 	if (ttfd->dest_coords == 0) return false;
 
-	// did we reach the final station?
+	/* did we reach the final station? */
 	if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || (
 				IsTileType(tile, MP_STATION) &&
 				IsRailwayStation(tile) &&
@@ -2163,12 +2107,13 @@
 		/* We do not check for dest_coords if we have a station_index,
 		 * because in that case the dest_coords are just an
 		 * approximation of where the station is */
-		// found station
+
+		/* found station */
 		ttfd->best_track = track;
 		ttfd->best_bird_dist = 0;
 		return true;
 	} else {
-		// didn't find station, keep track of the best path so far.
+		/* didn't find station, keep track of the best path so far. */
 		uint dist = DistanceManhattan(tile, ttfd->dest_coords);
 		if (dist < ttfd->best_bird_dist) {
 			ttfd->best_bird_dist = dist;
@@ -2205,12 +2150,12 @@
 };
 
 static const byte _search_directions[6][4] = {
-	{ 0, 9, 2, 9 }, // track 1
-	{ 9, 1, 9, 3 }, // track 2
-	{ 9, 0, 3, 9 }, // track upper
-	{ 1, 9, 9, 2 }, // track lower
-	{ 3, 2, 9, 9 }, // track left
-	{ 9, 9, 1, 0 }, // track right
+	{ 0, 9, 2, 9 }, ///< track 1
+	{ 9, 1, 9, 3 }, ///< track 2
+	{ 9, 0, 3, 9 }, ///< track upper
+	{ 1, 9, 9, 2 }, ///< track lower
+	{ 3, 2, 9, 9 }, ///< track left
+	{ 9, 9, 1, 0 }, ///< track right
 };
 
 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0};
@@ -2219,7 +2164,7 @@
 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
 {
 	Track best_track;
-	// pathfinders are able to tell that route was only 'guessed'
+	/* pathfinders are able to tell that route was only 'guessed' */
 	bool path_not_found = false;
 
 #ifdef PF_BENCHMARK
@@ -2247,12 +2192,12 @@
 		Trackdir trackdir = GetVehicleTrackdir(v);
 		assert(trackdir != 0xff);
 
-		NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
+		NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
 
 		if (ftd.best_trackdir == 0xff) {
-			/* We are already at our target. Just do something */
-			//TODO: maybe display error?
-			//TODO: go straight ahead if possible?
+			/* We are already at our target. Just do something
+			 * @todo maybe display error?
+			 * @todo: go straight ahead if possible? */
 			best_track = FindFirstTrack(tracks);
 		} else {
 			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
@@ -2280,11 +2225,11 @@
 		NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile,
 			v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
 
-		// check whether the path was found or only 'guessed'
+		/* check whether the path was found or only 'guessed' */
 		if (fd.best_bird_dist != 0) path_not_found = true;
 
 		if (fd.best_track == 0xff) {
-			// blaha
+			/* blaha */
 			best_track = FindFirstTrack(tracks);
 		} else {
 			best_track = TrackdirToTrack(fd.best_track);
@@ -2293,13 +2238,13 @@
 		int time = NpfEndInterval(perf);
 		DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
 	}
-	// handle "path not found" state
+	/* handle "path not found" state */
 	if (path_not_found) {
-		// PF didn't find the route
+		/* PF didn't find the route */
 		if (!HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
-			// it is first time the problem occurred, set the "path not found" flag
+			/* it is first time the problem occurred, set the "path not found" flag */
 			SETBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
-			// and notify user about the event
+			/* and notify user about the event */
 			if (_patches.lost_train_warn && v->owner == _local_player) {
 				SetDParam(0, v->unitnumber);
 				AddNewsItem(
@@ -2310,11 +2255,11 @@
 			}
 		}
 	} else {
-		// route found, is the train marked with "path not found" flag?
+		/* route found, is the train marked with "path not found" flag? */
 		if (HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
-			// clear the flag as the PF's problem was solved
+			/* clear the flag as the PF's problem was solved */
 			CLRBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
-			// can we also delete the "News" item somehow?
+			/* can we also delete the "News" item somehow? */
 		}
 	}
 
@@ -2357,7 +2302,7 @@
 		assert(trackdir != 0xff);
 		assert(trackdir_rev != 0xff);
 
-		ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes);
+		ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
 		if (ftd.best_bird_dist != 0) {
 			/* We didn't find anything, just keep on going straight ahead */
 			reverse_best = false;
@@ -2440,14 +2385,14 @@
 		default: break;
 	}
 
-	// check if we've reached the waypoint?
+	/* check if we've reached the waypoint? */
 	bool at_waypoint = false;
 	if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) {
 		v->cur_order_index++;
 		at_waypoint = true;
 	}
 
-	// check if we've reached a non-stop station while TTDPatch nonstop is enabled..
+	/* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */
 	if (_patches.new_nonstop &&
 			v->current_order.flags & OF_NON_STOP &&
 			IsTileType(v->tile, MP_STATION) &&
@@ -2455,25 +2400,25 @@
 		v->cur_order_index++;
 	}
 
-	// Get the current order
+	/* Get the current order */
 	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
 
 	const Order *order = GetVehicleOrder(v, v->cur_order_index);
 
-	// If no order, do nothing.
+	/* If no order, do nothing. */
 	if (order == NULL) {
 		v->current_order.Free();
 		v->dest_tile = 0;
 		return false;
 	}
 
-	// If it is unchanged, keep it.
+	/* If it is unchanged, keep it. */
 	if (order->type  == v->current_order.type &&
 			order->flags == v->current_order.flags &&
 			order->dest  == v->current_order.dest)
 		return false;
 
-	// Otherwise set it, and determine the destination tile.
+	/* Otherwise set it, and determine the destination tile. */
 	v->current_order = *order;
 
 	v->dest_tile = 0;
@@ -2502,62 +2447,17 @@
 	return !at_waypoint && CheckReverseTrain(v);
 }
 
-static void MarkTrainDirty(Vehicle *v)
+void Train::MarkDirty()
 {
+	Vehicle *v = this;
 	do {
 		v->cur_image = GetTrainImage(v, v->direction);
 		MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
 	} while ((v = v->next) != NULL);
-}
-
-static void HandleTrainLoading(Vehicle *v, bool mode)
-{
-	switch (v->current_order.type) {
-		case OT_LOADING: {
-			if (mode) return;
-
-			// don't mark the train as lost if we're loading on the final station.
-			if (v->current_order.flags & OF_NON_STOP) {
-				v->u.rail.days_since_order_progr = 0;
-			}
-
-			if (--v->load_unload_time_rem) return;
-
-			if (CanFillVehicle(v) && (
-						v->current_order.flags & OF_FULL_LOAD ||
-						(_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED))
-					)) {
-				v->u.rail.days_since_order_progr = 0; /* Prevent a train lost message for full loading trains */
-				SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
-				if (LoadUnloadVehicle(v, false)) {
-					InvalidateWindow(WC_TRAINS_LIST, v->owner);
-					MarkTrainDirty(v);
-
-					// need to update acceleration and cached values since the goods on the train changed.
-					TrainCargoChanged(v);
-					UpdateTrainAcceleration(v);
-				}
-				return;
-			}
-
-			TrainPlayLeaveStationSound(v);
-
-			Order b = v->current_order;
-			v->LeaveStation();
-
-			// If this was not the final order, don't remove it from the list.
-			if (!(b.flags & OF_NON_STOP)) return;
-			break;
-		}
-
-		case OT_DUMMY: break;
-
-		default: return;
-	}
-
-	v->u.rail.days_since_order_progr = 0;
-	v->cur_order_index++;
-	InvalidateVehicleOrder(v);
+
+	/* need to update acceleration and cached values since the goods on the train changed. */
+	TrainCargoChanged(this);
+	UpdateTrainAcceleration(this);
 }
 
 static int UpdateTrainSpeed(Vehicle *v)
@@ -2614,34 +2514,13 @@
 		);
 	}
 
-	// Did we reach the final destination?
-	if (v->current_order.type == OT_GOTO_STATION &&
-			v->current_order.dest == station) {
-		// Yeah, keep the load/unload flags
-		// Non Stop now means if the order should be increased.
-		v->BeginLoading();
-		v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
-		v->current_order.flags |= OF_NON_STOP;
-	} else {
-		// No, just do a simple load
-		v->BeginLoading();
-		v->current_order.flags = 0;
-	}
+	v->BeginLoading();
 	v->current_order.dest = 0;
-
-	SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
-	if (LoadUnloadVehicle(v, true) != 0) {
-		InvalidateWindow(WC_TRAINS_LIST, v->owner);
-		TrainCargoChanged(v);
-		UpdateTrainAcceleration(v);
-	}
-	MarkTrainDirty(v);
-	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 }
 
 static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
 {
-	// need this hint so it returns the right z coordinate on bridges.
+	/* need this hint so it returns the right z coordinate on bridges. */
 	byte new_z = GetSlopeZ(v->x_pos, v->y_pos);
 
 	byte old_z = v->z_pos;
@@ -2654,7 +2533,7 @@
 		if (new_z != old_z) {
 			TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
 
-			// XXX workaround, whole UP/DOWN detection needs overhaul
+			/* XXX workaround, whole UP/DOWN detection needs overhaul */
 			if (!IsTunnelTile(tile)) {
 				SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
 			}
@@ -2727,13 +2606,13 @@
 
 static const RailtypeSlowdownParams _railtype_slowdown[] = {
 	// normal accel
-	{256 / 4, 256 / 2, 256 / 4, 2}, // normal
-	{256 / 4, 256 / 2, 256 / 4, 2}, // electrified
-	{256 / 4, 256 / 2, 256 / 4, 2}, // monorail
-	{0,       256 / 2, 256 / 4, 2}, // maglev
+	{256 / 4, 256 / 2, 256 / 4, 2}, ///< normal
+	{256 / 4, 256 / 2, 256 / 4, 2}, ///< electrified
+	{256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail
+	{0,       256 / 2, 256 / 4, 2}, ///< maglev
 };
 
-/* Modify the speed of the vehicle due to a turn */
+/** Modify the speed of the vehicle due to a turn */
 static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
 {
 	if (_patches.realistic_acceleration) return;
@@ -2745,7 +2624,7 @@
 	v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
 }
 
-/* Modify the speed of the vehicle due to a change in altitude */
+/** Modify the speed of the vehicle due to a change in altitude */
 static void AffectSpeedByZChange(Vehicle *v, byte old_z)
 {
 	if (old_z == v->z_pos || _patches.realistic_acceleration) return;
@@ -2788,7 +2667,7 @@
 			v != tcc->v_skip &&
 			v->type == VEH_TRAIN &&
 			v->u.rail.track != TRACK_BIT_DEPOT &&
-			myabs(v->z_pos - tcc->v->z_pos) <= 6 &&
+			myabs(v->z_pos - tcc->v->z_pos) < 6 &&
 			myabs(v->x_pos - tcc->v->x_pos) < 6 &&
 			myabs(v->y_pos - tcc->v->y_pos) < 6) {
 		return v;
@@ -2820,7 +2699,7 @@
 	return num;
 }
 
-/*
+/**
  * Checks whether the specified train has a collision with another vehicle. If
  * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
  * Reports the incident in a flashy news item, modifies station ratings and
@@ -2848,10 +2727,10 @@
 			(v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2)))
 		return;
 
-	//two drivers + passangers killed in train v
+	/* two drivers + passangers killed in train v */
 	uint num = 2 + CountPassengersInTrain(v);
 	if (!(coll->vehstatus & VS_CRASHED))
-		//two drivers + passangers killed in train coll (if it was not crashed already)
+		/* two drivers + passangers killed in train coll (if it was not crashed already) */
 		num += 2 + CountPassengersInTrain(coll);
 
 	SetVehicleCrashed(v);
@@ -2931,7 +2810,7 @@
 
 				/* Get the status of the tracks in the new tile and mask
 				 * away the bits that aren't reachable. */
-				uint32 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir];
+				uint32 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0) & _reachable_tracks[enterdir];
 
 				/* Combine the from & to directions.
 				 * Now, the lower byte contains the track status, and the byte at bit 16 contains
@@ -2959,8 +2838,8 @@
 
 					/* Check if it's a red signal and that force proceed is not clicked. */
 					if ((tracks >> 16) & chosen_track && v->u.rail.force_proceed == 0) {
-						// In front of a red signal
-						/* find the first set bit in ts. need to do it in 2 steps, since
+						/* In front of a red signal
+						 * find the first set bit in ts. need to do it in 2 steps, since
 						 * FIND_FIRST_BIT only handles 6 bits at a time. */
 						Trackdir i = FindFirstTrackdir((TrackdirBits)(uint16)ts);
 
@@ -2972,7 +2851,7 @@
 						} else if (HasSignalOnTrackdir(gp.new_tile, i)) {
 							v->cur_speed = 0;
 							v->subspeed = 0;
-							v->progress = 255-10;
+							v->progress = 255 - 10;
 							if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) {
 								TileIndex o_tile = gp.new_tile + TileOffsByDiagDir(enterdir);
 								VehicleAtSignalData vasd;
@@ -3061,7 +2940,7 @@
 
 		/* update image of train, as well as delta XY */
 		Direction newdir = GetNewVehicleDirection(v, gp.x, gp.y);
-		UpdateTrainDeltaXY(v, newdir);
+		v->UpdateDeltaXY(newdir);
 		if (update_image) v->cur_image = GetTrainImage(v, newdir);
 
 		v->x_pos = gp.x;
@@ -3095,7 +2974,7 @@
  * train, then goes to the last wagon and deletes that. Each call to this function
  * will remove the last wagon of a crashed train. If this wagon was on a crossing,
  * or inside a tunnel, recalculate the signals as they might need updating
- * @param v the @Vehicle of which last wagon is to be removed
+ * @param v the Vehicle of which last wagon is to be removed
  */
 static void DeleteLastWagon(Vehicle *v)
 {
@@ -3113,6 +2992,9 @@
 
 	BeginVehicleMove(v);
 	EndVehicleMove(v);
+
+	if (IsFrontEngine(v)) RemoveVehicleFromGroup(v);
+
 	DeleteVehicle(v);
 
 	if (v->u.rail.track != TRACK_BIT_DEPOT && v->u.rail.track != TRACK_BIT_WORMHOLE)
@@ -3157,7 +3039,7 @@
 		if (!(v->vehstatus & VS_HIDDEN)) {
 			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
 			BeginVehicleMove(v);
-			UpdateTrainDeltaXY(v, v->direction);
+			v->UpdateDeltaXY(v->direction);
 			v->cur_image = GetTrainImage(v, v->direction);
 			/* Refrain from updating the z position of the vehicle when on
 			   a bridge, because AfterSetTrainPos will put the vehicle under
@@ -3198,6 +3080,7 @@
 
 	if (state >= 4440 && !(v->tick_counter&0x1F)) {
 		DeleteLastWagon(v);
+		InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN);
 	}
 }
 
@@ -3272,7 +3155,7 @@
 	/* Calculate next tile */
 	tile += TileOffsByDiagDir(dir);
 	// determine the track status on the next tile.
-	uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[dir];
+	uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir];
 
 	/* Calc position within the current tile ?? */
 	uint x = v->x_pos & 0xF;
@@ -3300,7 +3183,7 @@
 			return false;
 		}
 		if ((ts &= (ts >> 16)) == 0) {
-			// make a rail/road crossing red
+			/* make a rail/road crossing red */
 			if (IsLevelCrossingTile(tile)) {
 				if (!IsCrossingBarred(tile)) {
 					BarCrossing(tile);
@@ -3316,7 +3199,7 @@
 		return false;
 	}
 
-	// slow down
+	/* slow down */
 	v->vehstatus |= VS_TRAIN_SLOWING;
 	uint16 break_speed = _breakdown_speeds[x & 0xF];
 	if (!(v->direction & 1)) break_speed >>= 1;
@@ -3359,7 +3242,7 @@
 		return;
 	}
 
-	HandleTrainLoading(v, mode);
+	v->HandleLoading(mode);
 
 	if (v->current_order.type == OT_LOADING) return;
 
@@ -3369,7 +3252,7 @@
 
 	int j = UpdateTrainSpeed(v);
 	if (j == 0) {
-		// if the vehicle has speed 0, update the last_speed field.
+		/* if the vehicle has speed 0, update the last_speed field. */
 		if (v->cur_speed != 0) return;
 	} else {
 		TrainCheckIfLineEnds(v);
@@ -3396,11 +3279,11 @@
 	if (IsFrontEngine(v)) {
 		TrainLocoHandler(v, false);
 
-		// make sure vehicle wasn't deleted.
+		/* make sure vehicle wasn't deleted. */
 		if (v->type == VEH_TRAIN && IsFrontEngine(v))
 			TrainLocoHandler(v, true);
 	} else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) {
-		// Delete flooded standalone wagon
+		/* Delete flooded standalone wagon */
 		if (++v->u.rail.crash_anim_pos >= 4400)
 			DeleteVehicle(v);
 	}
@@ -3415,8 +3298,8 @@
 	if (v->vehstatus & VS_STOPPED)                      return;
 	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
 
-	// Don't interfere with a depot visit scheduled by the user, or a
-	// depot visit by the order list.
+	/* Don't interfere with a depot visit scheduled by the user, or a
+	 * depot visit by the order list. */
 	if (v->current_order.type == OT_GOTO_DEPOT &&
 			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
 		return;
@@ -3448,6 +3331,8 @@
 		return;
 	}
 
+	if (v->current_order.type == OT_LOADING) v->LeaveStation();
+
 	v->current_order.type = OT_GOTO_DEPOT;
 	v->current_order.flags = OF_NON_STOP;
 	v->current_order.dest = depot->index;
@@ -3461,8 +3346,11 @@
 
 	do {
 		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
-		if (rvi->running_cost_base > 0)
-			cost += rvi->running_cost_base * _price.running_rail[rvi->running_cost_class];
+
+		byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base);
+		if (cost_factor == 0) continue;
+
+		cost += cost_factor * _price.running_rail[rvi->running_cost_class];
 	} while ((v = GetNextVehicle(v)) != NULL);
 
 	return cost;
@@ -3507,7 +3395,7 @@
 
 	FOR_ALL_VEHICLES(v) {
 		if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
-			// show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list)
+			/* show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
 			if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) {
 				SetDParam(1, v->profit_this_year);
 				SetDParam(0, v->unitnumber);
@@ -3579,7 +3467,7 @@
 	}
 }
 
-/*
+/**
  *  Converts all trains to the new subtype format introduced in savegame 16.2
  *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
  */