diff src/train_cmd.cpp @ 9816:72806df62429 draft

(svn r13958) -Add [YAPP]: Implement look-ahead for trains so they extend their reservation before reaching the end. (michi_cc)
author rubidium <rubidium@openttd.org>
date Sat, 02 Aug 2008 22:55:23 +0000 (2008-08-02)
parents 77ed5f6edd46
children c7c20be56cee
line wrap: on
line diff
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -2327,6 +2327,44 @@
 	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
 }
 
+/** Check if the train is on the last reserved tile and try to extend the path then. */
+static void CheckNextTrainTile(Vehicle *v)
+{
+	/* Don't do any look-ahead if path_backoff_interval is 255. */
+	if (_settings_game.pf.path_backoff_interval == 255) return;
+
+	/* Exit if we reached our destination or are inside a depot. */
+	if ((v->tile == v->dest_tile && !v->current_order.IsType(OT_GOTO_STATION)) || v->u.rail.track & TRACK_BIT_DEPOT) return;
+	/* Exit if we are on a station tile and are going to stop. */
+	if (IsRailwayStationTile(v->tile) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) return;
+	/* Exit if the current order doesn't have a destination, but the train has orders. */
+	if ((v->current_order.IsType(OT_NOTHING) || v->current_order.IsType(OT_LEAVESTATION)) && v->num_orders > 0) return;
+
+	Trackdir td = GetVehicleTrackdir(v);
+
+	/* On a tile with a red non-pbs signal, don't look ahead. */
+	if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) &&
+			!IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) &&
+			GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return;
+
+	CFollowTrackRail ft(v);
+	if (!ft.Follow(v->tile, td)) return;
+
+	if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) {
+		/* Next tile is not reserved. */
+		if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
+			if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) {
+				/* If the next tile is a PBS signal, try to make a reservation. */
+				TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
+				if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
+					tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td));
+				}
+				ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false);
+			}
+		}
+	}
+}
+
 static bool CheckTrainStayInDepot(Vehicle *v)
 {
 	/* bail out if not all wagons are in the same depot or not in a depot at all */
@@ -3503,8 +3541,6 @@
 					goto invalid_rail;
 				}
 
-				if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
-
 				if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
 					Track track = FindFirstTrack(chosen_track);
 					Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
@@ -3533,6 +3569,13 @@
 				if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
 
 				v->direction = chosen_dir;
+
+				if (IsFrontEngine(v)) {
+					v->load_unload_time_rem = 0;
+
+					/* Always try to extend the reservation when entering a tile. */
+					CheckNextTrainTile(v);
+				}
 			}
 		} else {
 			/* In a tunnel or on a bridge
@@ -3543,7 +3586,10 @@
 					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)) {
+			if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
+				/* Perform look-ahead on tunnel exit. */
+				if (IsFrontEngine(v)) CheckNextTrainTile(v);
+			} else {
 				v->x_pos = gp.x;
 				v->y_pos = gp.y;
 				VehiclePositionChanged(v);
@@ -3577,6 +3623,9 @@
 				if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile);
 			}
 		}
+
+		/* Do not check on every tick to save some computing time. */
+		if (IsFrontEngine(v) && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
 	}
 	return;
 
@@ -3930,6 +3979,7 @@
 	/* exit if train is stopped */
 	if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return;
 
+	bool valid_order = v->current_order.IsValid() && v->current_order.GetType() != OT_CONDITIONAL;
 	if (ProcessOrders(v) && CheckReverseTrain(v)) {
 		v->load_unload_time_rem = 0;
 		v->cur_speed = 0;
@@ -3946,6 +3996,11 @@
 
 	if (!mode) HandleLocomotiveSmokeCloud(v);
 
+	/* We had no order but have an order now, do look ahead. */
+	if (!valid_order && v->current_order.IsValid()) {
+		CheckNextTrainTile(v);
+	}
+
 	/* Handle stuck trains. */
 	if (!mode && HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
 		++v->load_unload_time_rem;
@@ -3953,7 +4008,7 @@
 		/* Should we try reversing this tick if still stuck? */
 		bool turn_around = v->load_unload_time_rem % (_settings_game.pf.wait_for_pbs_path * DAY_TICKS) == 0 && _settings_game.pf.wait_for_pbs_path < 255;
 
-		if (!turn_around && v->u.rail.force_proceed == 0) return;
+		if (!turn_around && v->load_unload_time_rem % _settings_game.pf.path_backoff_interval != 0 && v->u.rail.force_proceed == 0) return;
 		if (!TryPathReserve(v)) {
 			/* Still stuck. */
 			if (turn_around) ReverseTrainDirection(v);