changeset 13891:14679a6bbf26 draft

(svn r18421) -Fix [FS#3244]: pathfinders wouldn't consider the 'other' reachable waypoint tile if the closest one is free but there is no safe waiting point directly after it. Now check for a free safe waiting point beyond the waypoint unless there are junctions before the first safe waiting point.
author rubidium <rubidium@openttd.org>
date Mon, 07 Dec 2009 08:47:10 +0000
parents 32e58ed16e0b
children 94fcf1c0fffd
files src/pathfinder/npf/npf.cpp src/pathfinder/yapf/yapf_costrail.hpp
diffstat 2 files changed, 64 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/pathfinder/npf/npf.cpp
+++ b/src/pathfinder/npf/npf.cpp
@@ -24,6 +24,7 @@
 #include "../../roadstop_base.h"
 #include "../pathfinder_func.h"
 #include "../pathfinder_type.h"
+#include "../follow_track.hpp"
 #include "aystar.h"
 
 enum {
@@ -419,6 +420,38 @@
 			 * this penalty exactly once, on its end tile (if it's a station) and it
 			 * will therefore not make a difference. */
 			cost = NPF_TILE_LENGTH + _settings_game.pf.npf.npf_rail_station_penalty;
+
+			if (IsRailWaypoint(tile)) {
+				NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
+				if (fstd->v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(tile) == fstd->v->current_order.GetDestination()) {
+					/* This waypoint is our destination; maybe this isn't an unreserved
+					 * one, so check that and if so see that as the last signal being
+					 * red. This way waypoints near stations should work better. */
+					const Train *train = Train::From(fstd->v);
+					CFollowTrackRail ft(train);
+					TileIndex t = tile;
+					Trackdir td = trackdir;
+					while (ft.Follow(t, td)) {
+						assert(t != ft.m_new_tile);
+						t = ft.m_new_tile;
+						if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
+							/* We encountered a junction; it's going to be too complex to
+							 * handle this perfectly, so just bail out. There is no simple
+							 * free path, so try the other possibilities. */
+							td = INVALID_TRACKDIR;
+							break;
+						}
+						td = RemoveFirstTrackdir(&ft.m_new_td_bits);
+						/* If this is a safe waiting position we're done searching for it */
+						if (IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg)) break;
+					}
+					if (td == INVALID_TRACKDIR ||
+							!IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg) ||
+							!IsWaitingPositionFree(train, t, td, _settings_game.pf.forbid_90_deg)) {
+						cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
+					}
+				}
+			}
 			break;
 
 		default:
--- a/src/pathfinder/yapf/yapf_costrail.hpp
+++ b/src/pathfinder/yapf/yapf_costrail.hpp
@@ -404,6 +404,37 @@
 				/* We will end in this pass (depot is possible target) */
 				end_segment_reason |= ESRB_DEPOT;
 
+			} else if (cur.tile_type == MP_STATION && IsRailWaypoint(cur.tile)) {
+				if (v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(cur.tile) == v->current_order.GetDestination()) {
+					/* This waypoint is our destination; maybe this isn't an unreserved
+					 * one, so check that and if so see that as the last signal being
+					 * red. This way waypoints near stations should work better. */
+					CFollowTrackRail ft(v);
+					TileIndex t = cur.tile;
+					Trackdir td = cur.td;
+					while (ft.Follow(t, td)) {
+						assert(t != ft.m_new_tile);
+						t = ft.m_new_tile;
+						if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
+							/* We encountered a junction; it's going to be too complex to
+							 * handle this perfectly, so just bail out. There is no simple
+							 * free path, so try the other possibilities. */
+							td = INVALID_TRACKDIR;
+							break;
+						}
+						td = RemoveFirstTrackdir(&ft.m_new_td_bits);
+						/* If this is a safe waiting position we're done searching for it */
+						if (IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg)) break;
+					}
+					if (td == INVALID_TRACKDIR ||
+							!IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg) ||
+							!IsWaitingPositionFree(v, t, td, _settings_game.pf.forbid_90_deg)) {
+						extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty;
+					}
+				}
+				/* Waypoint is also a good reason to finish. */
+				end_segment_reason |= ESRB_WAYPOINT;
+
 			} else if (tf->m_is_station) {
 				/* Station penalties. */
 				uint platform_length = tf->m_tiles_skipped + 1;
@@ -413,9 +444,6 @@
 				/* We will end in this pass (station is possible target) */
 				end_segment_reason |= ESRB_STATION;
 
-			} else if (cur.tile_type == MP_STATION && IsRailWaypoint(cur.tile)) {
-				/* Waypoint is also a good reason to finish. */
-				end_segment_reason |= ESRB_WAYPOINT;
 			} else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) {
 				/* Searching for a safe tile? */
 				if (HasSignalOnTrackdir(cur.tile, cur.td) && !IsPbsSignal(GetSignalType(cur.tile, TrackdirToTrack(cur.td)))) {