diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/train_cmd.cpp | 63 |
1 files changed, 59 insertions, 4 deletions
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index a2aa8dd27..b8d6cd989 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2327,6 +2327,44 @@ void Train::PlayLeaveStationSound() const 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 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) 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 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) 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 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) 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 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) 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 @@ static void TrainLocoHandler(Vehicle *v, bool mode) /* 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 @@ static void TrainLocoHandler(Vehicle *v, bool mode) 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 @@ static void TrainLocoHandler(Vehicle *v, bool mode) /* 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); |