src/train_cmd.cpp
branchnoai
changeset 9732 f8eb3e208514
parent 9724 b39bc69bb2f2
child 9826 9707ad4c9b60
--- a/src/train_cmd.cpp	Thu Feb 21 22:34:54 2008 +0000
+++ b/src/train_cmd.cpp	Fri Feb 22 00:25:54 2008 +0000
@@ -736,6 +736,7 @@
 			v->x_pos = x;
 			v->y_pos = y;
 			v->z_pos = GetSlopeZ(x, y);
+			v->running_ticks = 0;
 			v->u.rail.track = TRACK_BIT_DEPOT;
 			v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 			v->spritenum = rvi->image_index;
@@ -994,7 +995,7 @@
 	if (HasBit(p2, 0) && src_head == dst_head) return CommandCost();
 
 	{
-		int max_len = _patches.mammoth_trains ? 100 : 9;
+		int max_len = _patches.mammoth_trains ? 100 : 10;
 
 		/* check if all vehicles in the source train are stopped inside a depot. */
 		int src_len = CheckTrainStoppedInDepot(src_head);
@@ -1445,7 +1446,7 @@
 				 * up on a new line to be added to the newly built loco. Replace it is.
 				 * Totally braindead cause building a new engine adds all loco-less
 				 * engines to its train anyways */
-				if (p2 == 2 && HasBit(ori_subtype, Train_Front)) {
+				if (p2 == 2 && HasBit(ori_subtype, TS_FRONT)) {
 					Vehicle *tmp;
 					for (v = first; v != NULL; v = tmp) {
 						tmp = GetNextVehicle(v);
@@ -1544,7 +1545,7 @@
 	EndVehicleMove(v);
 }
 
-static void SetLastSpeed(Vehicle* v, int spd)
+static inline void SetLastSpeed(Vehicle* v, int spd)
 {
 	int old = v->u.rail.last_speed;
 	if (spd != old) {
@@ -1667,7 +1668,7 @@
 {
 	assert(IsLevelCrossingTile(tile));
 
-	DiagDirection dir = AxisToDiagDir(OtherAxis(GetCrossingRoadAxis(tile)));
+	DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
 	TileIndex tile_from = tile + TileOffsByDiagDir(dir);
 
 	Vehicle *v = (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum);
@@ -2001,7 +2002,7 @@
 
 	TrainFindDepotData tfdd;
 	tfdd.owner = v->owner;
-	tfdd.best_length = (uint)-1;
+	tfdd.best_length = UINT_MAX;
 	tfdd.reverse = false;
 
 	TileIndex tile = v->tile;
@@ -2011,36 +2012,43 @@
 		return tfdd;
 	}
 
-	if (_patches.yapf.rail_use_yapf) {
-		bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
-		tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND
-	} else if (_patches.new_pathfinding_all) {
-		Vehicle* last = GetLastVehicleInChain(v);
-		Trackdir trackdir = GetVehicleTrackdir(v);
-		Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
-
-		assert(trackdir != INVALID_TRACKDIR);
-		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;
-			/* Our caller expects a number of tiles, so we just approximate that
-			 * number by this. It might not be completely what we want, but it will
-			 * work for now :-) We can possibly change this when the old pathfinder
-			 * is removed. */
-			tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
-			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
-		}
-	} else {
-		/* search in the forward direction first. */
-		DiagDirection i = TrainExitDir(v->direction, v->u.rail.track);
-		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 */
-			i = TrainExitDir(ReverseDir(v->direction), v->u.rail.track);
+	switch (_patches.pathfinder_for_trains) {
+		case VPF_YAPF: { /* YAPF */
+			bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
+			tfdd.best_length = found ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND
+		} break;
+
+		case VPF_NPF: { /* NPF */
+			Vehicle* last = GetLastVehicleInChain(v);
+			Trackdir trackdir = GetVehicleTrackdir(v);
+			Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
+
+			assert(trackdir != INVALID_TRACKDIR);
+			NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, 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;
+				/* Our caller expects a number of tiles, so we just approximate that
+				* number by this. It might not be completely what we want, but it will
+				* work for now :-) We can possibly change this when the old pathfinder
+				* is removed. */
+				tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
+				if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
+			}
+		} break;
+
+		default:
+		case VPF_NTP: { /* NTP */
+			/* search in the forward direction first. */
+			DiagDirection i = TrainExitDir(v->direction, v->u.rail.track);
 			NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
-		}
+			if (tfdd.best_length == UINT_MAX){
+				tfdd.reverse = true;
+				/* search in backwards direction */
+				i = TrainExitDir(ReverseDir(v->direction), v->u.rail.track);
+				NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
+			}
+		} break;
 	}
 
 	return tfdd;
@@ -2203,7 +2211,7 @@
 	if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
 }
 
-static void TrainPlayLeaveStationSound(const Vehicle* v)
+void Train::PlayLeaveStationSound() const
 {
 	static const SoundFx sfx[] = {
 		SND_04_TRAIN,
@@ -2213,15 +2221,10 @@
 		SND_41_MAGLEV
 	};
 
-	if (PlayVehicleSound(v, VSE_START)) return;
-
-	EngineID engtype = v->engine_type;
-	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
-}
-
-void Train::PlayLeaveStationSound() const
-{
-	TrainPlayLeaveStationSound(this);
+	if (PlayVehicleSound(this, VSE_START)) return;
+
+	EngineID engtype = this->engine_type;
+	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
 }
 
 static bool CheckTrainStayInDepot(Vehicle *v)
@@ -2254,7 +2257,7 @@
 
 	VehicleServiceInDepot(v);
 	InvalidateWindowClasses(WC_TRAINS_LIST);
-	TrainPlayLeaveStationSound(v);
+	v->PlayLeaveStationSound();
 
 	v->u.rail.track = TRACK_BIT_X;
 	if (v->direction & 2) v->u.rail.track = TRACK_BIT_Y;
@@ -2364,68 +2367,76 @@
 	/* quick return in case only one possible track is available */
 	if (KillFirstBit(tracks) == TRACK_BIT_NONE) return FindFirstTrack(tracks);
 
-	if (_patches.yapf.rail_use_yapf) {
-		Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, tracks, &path_not_found);
-		if (trackdir != INVALID_TRACKDIR) {
-			best_track = TrackdirToTrack(trackdir);
-		} else {
-			best_track = FindFirstTrack(tracks);
-		}
-	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
-		void* perf = NpfBeginInterval();
-
-		NPFFindStationOrTileData fstd;
-		NPFFillWithOrderData(&fstd, v);
-		/* The enterdir for the new tile, is the exitdir for the old tile */
-		Trackdir trackdir = GetVehicleTrackdir(v);
-		assert(trackdir != 0xff);
-
-		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? */
-			best_track = FindFirstTrack(tracks);
-		} else {
-			/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
-			the direction we need to take to get there, if ftd.best_bird_dist is not 0,
-			we did not find our target, but ftd.best_trackdir contains the direction leading
-			to the tile closest to our target. */
-			if (ftd.best_bird_dist != 0) path_not_found = true;
-			/* Discard enterdir information, making it a normal track */
-			best_track = TrackdirToTrack(ftd.best_trackdir);
-		}
-
-		int time = NpfEndInterval(perf);
-		DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
-	} else {
-		void* perf = NpfBeginInterval();
-
-		TrainTrackFollowerData fd;
-		FillWithStationData(&fd, v);
-
-		/* New train pathfinding */
-		fd.best_bird_dist = (uint)-1;
-		fd.best_track_dist = (uint)-1;
-		fd.best_track = INVALID_TRACKDIR;
-
-		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' */
-		if (fd.best_bird_dist != 0) path_not_found = true;
-
-		if (fd.best_track == 0xff) {
-			/* blaha */
-			best_track = FindFirstTrack(tracks);
-		} else {
-			best_track = TrackdirToTrack(fd.best_track);
-		}
-
-		int time = NpfEndInterval(perf);
-		DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
+	switch (_patches.pathfinder_for_trains) {
+		case VPF_YAPF: { /* YAPF */
+			Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, tracks, &path_not_found);
+			if (trackdir != INVALID_TRACKDIR) {
+				best_track = TrackdirToTrack(trackdir);
+			} else {
+				best_track = FindFirstTrack(tracks);
+			}
+		} break;
+
+		case VPF_NPF: { /* NPF */
+			void *perf = NpfBeginInterval();
+
+			NPFFindStationOrTileData fstd;
+			NPFFillWithOrderData(&fstd, v);
+			/* The enterdir for the new tile, is the exitdir for the old tile */
+			Trackdir trackdir = GetVehicleTrackdir(v);
+			assert(trackdir != INVALID_TRACKDIR);
+
+			NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
+
+			if (ftd.best_trackdir == INVALID_TRACKDIR) {
+				/* 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
+				 * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
+				 * we did not find our target, but ftd.best_trackdir contains the direction leading
+				 * to the tile closest to our target. */
+				if (ftd.best_bird_dist != 0) path_not_found = true;
+				/* Discard enterdir information, making it a normal track */
+				best_track = TrackdirToTrack(ftd.best_trackdir);
+			}
+
+			int time = NpfEndInterval(perf);
+			DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
+		} break;
+
+		default:
+		case VPF_NTP: { /* NTP */
+			void *perf = NpfBeginInterval();
+
+			TrainTrackFollowerData fd;
+			FillWithStationData(&fd, v);
+
+			/* New train pathfinding */
+			fd.best_bird_dist = UINT_MAX;
+			fd.best_track_dist = UINT_MAX;
+			fd.best_track = INVALID_TRACKDIR;
+
+			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' */
+			if (fd.best_bird_dist != 0) path_not_found = true;
+
+			if (fd.best_track == INVALID_TRACKDIR) {
+				/* blaha */
+				best_track = FindFirstTrack(tracks);
+			} else {
+				best_track = TrackdirToTrack(fd.best_track);
+			}
+
+			int time = NpfEndInterval(perf);
+			DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
+		} break;
 	}
+
 	/* handle "path not found" state */
 	if (path_not_found) {
 		/* PF didn't find the route */
@@ -2475,81 +2486,87 @@
 
 	int i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)];
 
-	if (_patches.yapf.rail_use_yapf) {
-		reverse_best = YapfCheckReverseTrain(v);
-	} else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
-		NPFFindStationOrTileData fstd;
-		NPFFoundTargetData ftd;
-		Trackdir trackdir, trackdir_rev;
-		Vehicle* last = GetLastVehicleInChain(v);
-
-		NPFFillWithOrderData(&fstd, v);
-
-		trackdir = GetVehicleTrackdir(v);
-		trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
-		assert(trackdir != 0xff);
-		assert(trackdir_rev != 0xff);
-
-		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;
-		} else {
-			if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
-				reverse_best = true;
+	switch (_patches.pathfinder_for_trains) {
+		case VPF_YAPF: { /* YAPF */
+			reverse_best = YapfCheckReverseTrain(v);
+		} break;
+
+		case VPF_NPF: { /* NPF */
+			NPFFindStationOrTileData fstd;
+			NPFFoundTargetData ftd;
+			Vehicle* last = GetLastVehicleInChain(v);
+
+			NPFFillWithOrderData(&fstd, v);
+
+			Trackdir trackdir = GetVehicleTrackdir(v);
+			Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
+			assert(trackdir != INVALID_TRACKDIR);
+			assert(trackdir_rev != INVALID_TRACKDIR);
+
+			ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &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;
 			} else {
-				reverse_best = false;
+				if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
+					reverse_best = true;
+				} else {
+					reverse_best = false;
+				}
 			}
-		}
-	} else {
-		int best_track = -1;
-		uint reverse = 0;
-		uint best_bird_dist  = 0;
-		uint best_track_dist = 0;
-
-		for (;;) {
-			fd.best_bird_dist = (uint)-1;
-			fd.best_track_dist = (uint)-1;
-
-			NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, (DiagDirection)(reverse ^ i), (NTPEnumProc*)NtpCallbFindStation, &fd);
-
-			if (best_track != -1) {
-				if (best_bird_dist != 0) {
-					if (fd.best_bird_dist != 0) {
-						/* neither reached the destination, pick the one with the smallest bird dist */
-						if (fd.best_bird_dist > best_bird_dist) goto bad;
-						if (fd.best_bird_dist < best_bird_dist) goto good;
+		} break;
+
+		default:
+		case VPF_NTP: { /* NTP */
+			int best_track = -1;
+			uint reverse = 0;
+			uint best_bird_dist  = 0;
+			uint best_track_dist = 0;
+
+			for (;;) {
+				fd.best_bird_dist = UINT_MAX;
+				fd.best_track_dist = UINT_MAX;
+
+				NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, (DiagDirection)(reverse ^ i), (NTPEnumProc*)NtpCallbFindStation, &fd);
+
+				if (best_track != -1) {
+					if (best_bird_dist != 0) {
+						if (fd.best_bird_dist != 0) {
+							/* neither reached the destination, pick the one with the smallest bird dist */
+							if (fd.best_bird_dist > best_bird_dist) goto bad;
+							if (fd.best_bird_dist < best_bird_dist) goto good;
+						} else {
+							/* we found the destination for the first time */
+							goto good;
+						}
 					} else {
-						/* we found the destination for the first time */
-						goto good;
+						if (fd.best_bird_dist != 0) {
+							/* didn't find destination, but we've found the destination previously */
+							goto bad;
+						} else {
+							/* both old & new reached the destination, compare track length */
+							if (fd.best_track_dist > best_track_dist) goto bad;
+							if (fd.best_track_dist < best_track_dist) goto good;
+						}
 					}
-				} else {
-					if (fd.best_bird_dist != 0) {
-						/* didn't find destination, but we've found the destination previously */
-						goto bad;
-					} else {
-						/* both old & new reached the destination, compare track length */
-						if (fd.best_track_dist > best_track_dist) goto bad;
-						if (fd.best_track_dist < best_track_dist) goto good;
-					}
+
+					/* if we reach this position, there's two paths of equal value so far.
+					 * pick one randomly. */
+					int r = GB(Random(), 0, 8);
+					if (_pick_track_table[i] == (v->direction & 3)) r += 80;
+					if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
+					if (r <= 127) goto bad;
 				}
-
-				/* if we reach this position, there's two paths of equal value so far.
-				 * pick one randomly. */
-				int r = GB(Random(), 0, 8);
-				if (_pick_track_table[i] == (v->direction & 3)) r += 80;
-				if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
-				if (r <= 127) goto bad;
+good:;
+				best_track = i;
+				best_bird_dist = fd.best_bird_dist;
+				best_track_dist = fd.best_track_dist;
+				reverse_best = reverse;
+bad:;
+				if (reverse != 0) break;
+				reverse = 2;
 			}
-good:;
-			best_track = i;
-			best_bird_dist = fd.best_bird_dist;
-			best_track_dist = fd.best_track_dist;
-			reverse_best = reverse;
-bad:;
-			if (reverse != 0) break;
-			reverse = 2;
-		}
+		} break;
 	}
 
 	return reverse_best != 0;
@@ -2755,7 +2772,7 @@
 	DIR_E , DIR_SE, DIR_S
 };
 
-static Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
+static inline Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
 {
 	uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
 							TileX(new_tile) - TileX(old_tile) + 1;
@@ -2763,7 +2780,7 @@
 	return _new_vehicle_direction_table[offs];
 }
 
-static int GetDirectionToVehicle(const Vehicle *v, int x, int y)
+static inline int GetDirectionToVehicle(const Vehicle *v, int x, int y)
 {
 	byte offs;
 
@@ -2786,7 +2803,7 @@
 }
 
 /* Check if the vehicle is compatible with the specified tile */
-static bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
+static inline bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
 {
 	return
 		IsTileOwner(tile, v->owner) && (
@@ -2810,7 +2827,7 @@
 };
 
 /** Modify the speed of the vehicle due to a turn */
-static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
+static inline void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
 {
 	if (_patches.realistic_acceleration) return;
 
@@ -2822,7 +2839,7 @@
 }
 
 /** Modify the speed of the vehicle due to a change in altitude */
-static void AffectSpeedByZChange(Vehicle *v, byte old_z)
+static inline void AffectSpeedByZChange(Vehicle *v, byte old_z)
 {
 	if (old_z == v->z_pos || _patches.realistic_acceleration) return;
 
@@ -3025,14 +3042,12 @@
 
 				/* 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, 0) & _reachable_tracks[enterdir];
-
-				/* Combine the from & to directions.
-				 * Now, the lower byte contains the track status, and the byte at bit 16 contains
-				 * the signal status. */
-				uint32 tracks = ts | (ts >> 8);
-				TrackBits bits = (TrackBits)(tracks & TRACK_BIT_MASK);
-				if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) {
+				TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)) & _reachable_tracks[enterdir];
+				TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
+				TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts));
+
+				TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
+				if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg && prev == NULL) {
 					/* We allow wagons to make 90 deg turns, because forbid_90_deg
 					 * can be switched on halfway a turn */
 					bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
@@ -3049,14 +3064,12 @@
 					/* Currently the locomotive is active. Determine which one of the
 					 * available tracks to choose */
 					chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits));
-					assert(chosen_track & tracks);
+					assert(chosen_track & bits);
 
 					/* 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
-						 * FIND_FIRST_BIT only handles 6 bits at a time. */
-						Trackdir i = FindFirstTrackdir((TrackdirBits)(uint16)ts);
+					if (red_signals & chosen_track && v->u.rail.force_proceed == 0) {
+						/* In front of a red signal */
+						Trackdir i = FindFirstTrackdir(trackdirbits);
 
 						if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
 							v->cur_speed = 0;
@@ -3134,7 +3147,7 @@
 			 * - for bridges, only the middle part - without the bridge heads */
 			if (!(v->vehstatus & VS_HIDDEN)) {
 				v->cur_speed =
-					min(v->cur_speed, GetBridge(GetBridgeType(v->tile))->speed);
+					min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed);
 			}
 
 			if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
@@ -3422,9 +3435,9 @@
 	DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
 	TileIndex tile = v->tile + TileOffsByDiagDir(dir);
 
-	/* not a crossing || wrong axis || wrong railtype || wrong owner */
+	/* not a crossing || wrong axis || unusable rail (wrong type or owner) */
 	if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
-			!CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner) {
+			!CheckCompatibleRail(v, tile)) {
 		return INVALID_TILE;
 	}
 
@@ -3460,20 +3473,25 @@
 	TileIndex tile = v->tile + TileOffsByDiagDir(dir);
 
 	/* Determine the track status on the next tile */
-	uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir];
+	TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir)) & _reachable_tracks[dir];
+	TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
+	TrackdirBits red_signals = TrackStatusToRedSignals(ts);
 
 	/* We are sure the train is not entering a depot, it is detected above */
 
-	/* no suitable trackbits at all || wrong railtype || not our track ||
-	 *   tunnel/bridge from opposite side || depot from opposite side */
-	if (GB(ts, 0, 16) == 0 || !CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner ||
-			(IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) ||
-			(IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) == dir) ) {
+	/* mask unreachable track bits if we are forbidden to do 90deg turns */
+	TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
+	if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg) {
+		bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
+	}
+
+	/* no suitable trackbits at all || unusable rail (wrong type or owner) */
+	if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
 		return TrainApproachingLineEnd(v, false);
 	}
 
 	/* approaching red signal */
-	if ((ts & (ts >> 16)) != 0) return TrainApproachingLineEnd(v, true);
+	if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
 
 	/* approaching a rail/road crossing? then make it red */
 	if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
@@ -3558,10 +3576,10 @@
 	do {
 		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 
-		byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base);
+		byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
 		if (cost_factor == 0) continue;
 
-		cost += cost_factor * _price.running_rail[rvi->running_cost_class];
+		cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
 	} while ((v = GetNextVehicle(v)) != NULL);
 
 	return cost;
@@ -3575,6 +3593,7 @@
 	this->tick_counter++;
 
 	if (IsFrontEngine(this)) {
+		if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
 		this->current_order_time++;
 
 		TrainLocoHandler(this, false);
@@ -3645,11 +3664,12 @@
 			if (tile != 0) this->dest_tile = tile;
 		}
 
-		if ((this->vehstatus & VS_STOPPED) == 0) {
+		if (this->running_ticks != 0) {
 			/* running costs */
-			CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() / 364);
-
-			this->profit_this_year -= cost.GetCost() >> 8;
+			CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (364 * DAY_TICKS));
+
+			this->profit_this_year -= cost.GetCost();
+			this->running_ticks = 0;
 
 			SubtractMoneyFromPlayerFract(this->owner, cost);
 
@@ -3669,8 +3689,8 @@
 	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) */
-			if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) {
-				SetDParam(1, v->profit_this_year);
+			if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->GetDisplayProfitThisYear() < 0) {
+				SetDParam(1, v->GetDisplayProfitThisYear());
 				SetDParam(0, v->unitnumber);
 				AddNewsItem(
 					STR_TRAIN_IS_UNPROFITABLE,