From debc504e59b6d4b3db7f7e2ff407f6c6be6c2a2d Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Thu, 17 Jun 2021 15:52:45 +0200 Subject: [PATCH] Add a setting for train speed adaptation Prior to this change, without realistic breaking, trains would continuously run into the train in front of them. This makes them adjust their speed based on trains in front of them --- src/lang/english.txt | 2 ++ src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 13 ++++++-- src/train.h | 1 + src/train_cmd.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index eba78574a4..01d86510c5 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1811,6 +1811,8 @@ STR_CONFIG_SETTING_NOSERVICE :Disable servici STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Enable train speed adaption: {STRING2} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :If enabled, faster trains behind slower trains adjust their speed. STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Road vehicles slow down in curves: {STRING2} STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :When enabled, road vehicles slow down in curves. (Only with realistic acceleration) STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 48416d33a3..179a12e642 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1923,6 +1923,7 @@ static SettingsContainer &GetSettingsTree() physics->Add(new SettingEntry("vehicle.train_braking_model")); physics->Add(new SettingEntry("vehicle.train_slope_steepness")); physics->Add(new SettingEntry("vehicle.wagon_speed_limits")); + physics->Add(new SettingEntry("vehicle.train_speed_adaption")); physics->Add(new SettingEntry("vehicle.freight_trains")); physics->Add(new SettingEntry("vehicle.roadveh_acceleration_model")); physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness")); diff --git a/src/settings_type.h b/src/settings_type.h index e2f245a7d1..95fbe4b1f8 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -572,6 +572,7 @@ struct VehicleSettings { uint8 train_slope_steepness; ///< Steepness of hills for trains when using realistic acceleration uint8 roadveh_slope_steepness; ///< Steepness of hills for road vehicles when using realistic acceleration bool wagon_speed_limits; ///< enable wagon speed limits + bool train_speed_adaption; ///< Faster trains behind slower trains slow down bool slow_road_vehicles_in_curves; ///< Road vehicles slow down in curves. bool disable_elrails; ///< when true, the elrails are disabled UnitID max_trains; ///< max trains in game per company diff --git a/src/table/settings.ini b/src/table/settings.ini index f1c3aec765..007fe47a88 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -1676,9 +1676,18 @@ cat = SC_BASIC patxname = ""slow_road_vehicles_in_curves.vehicle.slow_road_vehicles_in_curves"" ;; vehicle.train_speed_adaption -[SDT_NULL] -length = 1 +[SDT_XREF] extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP) +xref = ""vehicle.train_speed_adaption"" + +[SDT_BOOL] +base = GameSettings +var = vehicle.train_speed_adaption +def = true +str = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION +strhelp = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT +cat = SC_EXPERT +patxname = ""train_speed_adaption.vehicle.train_speed_adaption"" [SDT_BOOL] base = GameSettings diff --git a/src/train.h b/src/train.h index 6fd5186dd6..c33f7317e4 100644 --- a/src/train.h +++ b/src/train.h @@ -190,6 +190,7 @@ struct Train FINAL : public GroundVehicle { }; private: + int GetAtcMaxSpeed(int current_max_speed) const; MaxSpeedInfo GetCurrentMaxSpeedInfoInternal(bool update_state) const; public: diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2e0a813910..6238fb13b8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -951,6 +951,80 @@ static void AdvanceLookAheadPosition(Train *v) } } +/** + * Calculates the maximum speed based on any train in front of this train. + */ +int Train::GetAtcMaxSpeed(int current_max_speed) const +{ + if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption) { + int atc_speed = current_max_speed; + + CFollowTrackRail ft(this); + Trackdir old_td = this->GetVehicleTrackdir(); + + if (ft.Follow(this->tile, this->GetVehicleTrackdir())) { + /* Basic idea: Follow the track for 20 tiles or 3 signals (i.e. at most two signal blocks) looking for other trains. */ + /* If we find one (that meets certain restrictions), we limit the max speed to the speed of that train. */ + int num_tiles = 0; + int num_signals = 0; + + do { + old_td = ft.m_old_td; + + /* If we are on a depot or rail station tile stop searching */ + if (IsDepotTile(ft.m_new_tile) || IsRailStationTile(ft.m_new_tile)) + break; + + /* Increment signal counter if we're on a signal */ + if (IsTileType(ft.m_new_tile, MP_RAILWAY) && ///< Tile has rails + KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track + HasSignalOnTrack(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits)))) { ///< Tile has signal + num_signals++; + } + + /* Check if tile has train/is reserved */ + if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track + HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { ///< Tile is reserved + Train* other_train = GetTrainForReservation(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits))); + + + if (other_train != nullptr && + other_train != this && ///< Other train is not this train + other_train->GetAccelerationStatus() != AS_BRAKE) { ///< Other train is not braking + atc_speed = other_train->GetCurrentSpeed(); + break; + } + } + + /* Decide what in direction to continue: reservation, straight or "first/only" direction. */ + /* Abort if there's no reservation even though the tile contains multiple tracks. */ + const TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); + + if (reserved != TRACKDIR_BIT_NONE) { + // There is a reservation to follow. + old_td = FindFirstTrackdir(reserved); + } + else if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { + // Tile has more than one track and we have no reservation. Bail out. + break; + } + else { + // There was no reservation but there is only one direction to follow, so follow it. + old_td = FindFirstTrackdir(ft.m_new_td_bits); + } + + num_tiles++; + } while (num_tiles < 20 && num_signals < 3 && ft.Follow(ft.m_new_tile, old_td)); + } + + /* Check that the ATC speed is sufficiently large. + Avoids assertion error in UpdateSpeed(). */ + current_max_speed = std::max(25, std::min(current_max_speed, atc_speed)); + } + + return current_max_speed; +} + /** * Calculates the maximum speed information of the vehicle under its current conditions. * @return Maximum speed information of the vehicle. @@ -961,6 +1035,8 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); + max_speed = GetAtcMaxSpeed(max_speed); + if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); int advisory_max_speed = max_speed;