From d6e73ea1ce9db96cb76495c8a1edce199790c552 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 7 Dec 2009 08:47:10 +0000 Subject: [PATCH] (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. --- src/pathfinder/npf/npf.cpp | 33 ++++++++++++++++++++++++++ src/pathfinder/yapf/yapf_costrail.hpp | 34 ++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index f6841796ac..1fe5fe07f2 100644 --- 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 @@ static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare * 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: diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 959431520b..cfc1bba82f 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -404,6 +404,37 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* 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 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* 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)))) {