From bd0a42074444264b448ea5ddc34e79ea400fe20a Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 2 Aug 2008 22:54:38 +0000 Subject: (svn r13955) -Codechange [YAPP]: Try to extend the path of a stuck train so it is able to continue. (michi_cc) --- src/lang/english.txt | 1 + src/train.h | 1 + src/train_cmd.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/src/lang/english.txt b/src/lang/english.txt index 915a99da0..2bf550160 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -988,6 +988,7 @@ STR_CANT_SHARE_ORDER_LIST :{WHITE}Can't sh STR_CANT_COPY_ORDER_LIST :{WHITE}Can't copy order list... STR_END_OF_SHARED_ORDERS :{SETX 10}- - End of Shared Orders - - +STR_TRAIN_IS_STUCK :{WHITE}Train {COMMA} can't find a path to continue. STR_TRAIN_IS_LOST :{WHITE}Train {COMMA} is lost. STR_TRAIN_IS_UNPROFITABLE :{WHITE}Train {COMMA}'s profit last year was {CURRENCY} STR_EURO_INTRODUCE :{BLACK}{BIGFONT}European Monetary Union!{}{}The Euro is introduced as the sole currency for everyday transactions in your country! diff --git a/src/train.h b/src/train.h index 81b512c1b..27e232935 100644 --- a/src/train.h +++ b/src/train.h @@ -274,6 +274,7 @@ void UpdateTrainAcceleration(Vehicle* v); void CheckTrainsLengths(); void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR); +bool TryPathReserve(Vehicle *v, bool mark_as_stuck = false, bool first_tile_okay = false); /** * This class 'wraps' Vehicle; you do not actually instantiate this class. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 7a017f472..a2aa8dd27 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2833,6 +2833,79 @@ static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir return best_track; } +/** + * Try to reserve a path to a safe position. + * + * @param v The vehicle + * @return True if a path could be reserved + */ +bool TryPathReserve(Vehicle *v, bool first_tile_okay, bool mark_as_stuck) +{ + assert(v->type == VEH_TRAIN && IsFrontEngine(v)); + + /* We have to handle depots specially as the track follower won't look + * at the depot tile itself but starts from the next tile. If we are still + * inside the depot, a depot reservation can never be ours. */ + if (v->u.rail.track & TRACK_BIT_DEPOT) { + if (GetDepotWaypointReservation(v->tile)) { + if (mark_as_stuck) MarkTrainAsStuck(v); + return false; + } else { + /* Depot not reserved, but the next tile might be. */ + TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile)); + if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false; + } + } + + /* Special check if we are in front of a two-sided conventional signal. */ + DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); + TileIndex next_tile = TileAddByDiagDir(v->tile, dir); + if (IsTileType(next_tile, MP_RAILWAY) && HasReservedTracks(next_tile, DiagdirReachesTracks(dir))) { + /* Can have only one reserved trackdir. */ + Trackdir td = FindFirstTrackdir((TrackdirBits)(GetReservedTrackbits(next_tile) * 0x101 & DiagdirReachesTrackdirs(dir))); + if (HasSignalOnTrackdir(next_tile, td) && HasSignalOnTrackdir(next_tile, ReverseTrackdir(td)) && + !IsPbsSignal(GetSignalType(next_tile, TrackdirToTrack(td)))) { + /* Signal already reserved, is not ours. */ + if (mark_as_stuck) MarkTrainAsStuck(v); + return false; + } + } + + PBSTileInfo origin = FollowTrainReservation(v); + /* If we have a reserved path and the path ends at a safe tile, we are finished already. */ + if (origin.okay && (v->tile != origin.tile || first_tile_okay)) { + /* Can't be stuck then. */ + if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); + ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); + return true; + } + + /* If we are in a depot, tentativly reserve the depot. */ + if (v->u.rail.track & TRACK_BIT_DEPOT) { + SetDepotWaypointReservation(v->tile, true); + if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile); + } + + DiagDirection exitdir = TrackdirToExitdir(origin.trackdir); + TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir); + TrackBits reachable = TrackdirBitsToTrackBits((TrackdirBits)GetTileTrackStatus(new_tile, TRANSPORT_RAIL, 0) & DiagdirReachesTrackdirs(exitdir)); + + if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir)); + + bool res_made = false; + ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck); + + if (!res_made) { + /* Free the depot reservation as well. */ + if (v->u.rail.track & TRACK_BIT_DEPOT) SetDepotWaypointReservation(v->tile, false); + return false; + } + + if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); + ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); + return true; +} + static bool CheckReverseTrain(Vehicle *v) { @@ -3873,6 +3946,38 @@ static void TrainLocoHandler(Vehicle *v, bool mode) if (!mode) HandleLocomotiveSmokeCloud(v); + /* Handle stuck trains. */ + if (!mode && HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) { + ++v->load_unload_time_rem; + + /* 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 (!TryPathReserve(v)) { + /* Still stuck. */ + if (turn_around) ReverseTrainDirection(v); + + if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK) && v->load_unload_time_rem > 2 * _settings_game.pf.wait_for_pbs_path * DAY_TICKS) { + /* Show message to player. */ + if (_settings_client.gui.lost_train_warn && v->owner == _local_player) { + SetDParam(0, v->unitnumber); + AddNewsItem( + STR_TRAIN_IS_STUCK, + NS_ADVICE, + v->index, + 0); + } + v->load_unload_time_rem = 0; + } + /* Exit if force proceed not pressed, else reset stuck flag anyway. */ + if (v->u.rail.force_proceed == 0) return; + ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); + v->load_unload_time_rem = 0; + InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); + } + } + int j = UpdateTrainSpeed(v); /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */ -- cgit v1.2.3-54-g00ecf