* Extend a train path as far as possible. Stops on encountering a safe tile, * another reservation or a track choice. * @return INVALID_TILE indicates that the reservation failed. */
| 2511 | * @return INVALID_TILE indicates that the reservation failed. |
| 2512 | */ |
| 2513 | static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir) |
| 2514 | { |
| 2515 | PBSTileInfo origin = FollowTrainReservation(v); |
| 2516 | |
| 2517 | CFollowTrackRail ft(v); |
| 2518 | |
| 2519 | std::vector<std::pair<TileIndex, Trackdir>> signals_set_to_red; |
| 2520 | |
| 2521 | TileIndex tile = origin.tile; |
| 2522 | Trackdir cur_td = origin.trackdir; |
| 2523 | while (ft.Follow(tile, cur_td)) { |
| 2524 | if (KillFirstBit(ft.new_td_bits) == TRACKDIR_BIT_NONE) { |
| 2525 | /* Possible signal tile. */ |
| 2526 | if (HasOnewaySignalBlockingTrackdir(ft.new_tile, FindFirstTrackdir(ft.new_td_bits))) break; |
| 2527 | } |
| 2528 | |
| 2529 | if (Rail90DegTurnDisallowed(GetTileRailType(ft.old_tile), GetTileRailType(ft.new_tile))) { |
| 2530 | ft.new_td_bits &= ~TrackdirCrossesTrackdirs(ft.old_td); |
| 2531 | if (ft.new_td_bits == TRACKDIR_BIT_NONE) break; |
| 2532 | } |
| 2533 | |
| 2534 | /* Station, depot or waypoint are a possible target. */ |
| 2535 | bool target_seen = ft.is_station || (IsTileType(ft.new_tile, MP_RAILWAY) && !IsPlainRail(ft.new_tile)); |
| 2536 | if (target_seen || KillFirstBit(ft.new_td_bits) != TRACKDIR_BIT_NONE) { |
| 2537 | /* Choice found or possible target encountered. |
| 2538 | * On finding a possible target, we need to stop and let the pathfinder handle the |
| 2539 | * remaining path. This is because we don't know if this target is in one of our |
| 2540 | * orders, so we might cause pathfinding to fail later on if we find a choice. |
| 2541 | * This failure would cause a bogous call to TryReserveSafePath which might reserve |
| 2542 | * a wrong path not leading to our next destination. */ |
| 2543 | if (HasReservedTracks(ft.new_tile, TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(ft.old_td)))) break; |
| 2544 | |
| 2545 | /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder |
| 2546 | * actually starts its search at the first unreserved tile. */ |
| 2547 | if (ft.tiles_skipped != 0) ft.new_tile -= TileOffsByDiagDir(ft.exitdir) * ft.tiles_skipped; |
| 2548 | |
| 2549 | /* Choice found, path valid but not okay. Save info about the choice tile as well. */ |
| 2550 | if (new_tracks != nullptr) *new_tracks = TrackdirBitsToTrackBits(ft.new_td_bits); |
| 2551 | if (enterdir != nullptr) *enterdir = ft.exitdir; |
| 2552 | return PBSTileInfo(ft.new_tile, ft.old_td, false); |
| 2553 | } |
| 2554 | |
| 2555 | tile = ft.new_tile; |
| 2556 | cur_td = FindFirstTrackdir(ft.new_td_bits); |
| 2557 | |
| 2558 | Trackdir rev_td = ReverseTrackdir(cur_td); |
| 2559 | if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) { |
| 2560 | bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg); |
| 2561 | if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break; |
| 2562 | /* Green path signal opposing the path? Turn to red. */ |
| 2563 | if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) { |
| 2564 | signals_set_to_red.emplace_back(tile, rev_td); |
| 2565 | SetSignalStateByTrackdir(tile, rev_td, SIGNAL_STATE_RED); |
| 2566 | MarkTileDirtyByTile(tile); |
| 2567 | } |
| 2568 | /* Safe position is all good, path valid and okay. */ |
| 2569 | return PBSTileInfo(tile, cur_td, true); |
| 2570 | } |
no test coverage detected