diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index 65eafbd054..774ab4a61b 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -339,6 +339,7 @@ enum SpriteGroupCallbacksUsed : uint8 { SGCU_VEHICLE_32DAY_CALLBACK = 1 << 0, SGCU_VEHICLE_REFIT_COST = 1 << 1, SGCU_RANDOM_TRIGGER = 1 << 2, + SGCU_CB36_SPEED_RAILTYPE = 1 << 3, }; DECLARE_ENUM_AS_BIT_SET(SpriteGroupCallbacksUsed) diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 84f6f3b556..73ce2751a1 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -354,6 +354,7 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co cb36_op.mode = ACOM_CB36_PROP; range.group->AnalyseCallbacks(cb36_op); op.properties_used |= cb36_op.properties_used; + op.callbacks_used |= cb36_op.callbacks_used; } break; } @@ -370,7 +371,18 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co for (const auto &range : this->ranges) { if (range.low == range.high) { if (range.low < 64) { - if (find_cb_result()) SetBit(op.properties_used, range.low); + if (find_cb_result()) { + SetBit(op.properties_used, range.low); + if (range.low == 0x9) { + /* Speed */ + if (range.group != nullptr) { + AnalyseCallbackOperation cb36_speed; + cb36_speed.mode = ACOM_CB36_SPEED; + range.group->AnalyseCallbacks(cb36_speed); + op.callbacks_used |= cb36_speed.callbacks_used; + } + } + } } } else { if (range.group != nullptr) range.group->AnalyseCallbacks(op); @@ -392,6 +404,10 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co return; } } + if (op.mode == ACOM_CB36_SPEED && adjust.variable == 0x4A) { + op.callbacks_used |= SGCU_CB36_SPEED_RAILTYPE; + return; + } } for (const auto &adjust : this->adjusts) { if (op.mode == ACOM_CB_VAR && adjust.variable == 0xC) { diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index aa7fcd2f9d..518c4e234d 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -53,6 +53,7 @@ enum AnalyseCallbackOperationMode { ACOM_CB_VAR, ACOM_CB36_PROP, ACOM_FIND_CB_RESULT, + ACOM_CB36_SPEED, }; struct AnalyseCallbackOperation { diff --git a/src/pbs.cpp b/src/pbs.cpp index 17a1e4054d..dee990a654 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -386,6 +386,26 @@ static uint16 ApplyTunnelBridgeLookaheadSignalSpeedRestriction(TileIndex tile, T return speed_restriction; } +static uint16 GetTrainSpeedLimitForRailtype(const Train *v, RailType rt, TileIndex tile, Track track) +{ + uint16 speed = GetRailTypeInfo(rt)->max_speed; + if (v->tcache.cached_tflags & TCF_SPD_RAILTYPE) { + for (const Train *u = v; u != nullptr; u = u->Next()) { + if (u->GetEngine()->callbacks_used & SGCU_CB36_SPEED_RAILTYPE) { + const TileIndex prev_tile = u->tile; + const TrackBits prev_track = u->track; + const_cast(u)->tile = tile; + const_cast(u)->track = TrackToTrackBits(track); + uint16 cb_speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, speed); + if (cb_speed != 0 && (cb_speed < speed || speed == 0)) speed = cb_speed; + const_cast(u)->tile = prev_tile; + const_cast(u)->track = prev_track; + } + } + } + return speed; +} + /** Follow a reservation starting from a specific tile to the end. */ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, FollowReservationFlags flags, const Train *v, TrainReservationLookAhead *lookahead) { @@ -431,7 +451,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra auto check_rail_type = [&](TileIndex t, Trackdir td, int offset) { RailType new_rt = GetRailTypeByTrack(t, TrackdirToTrack(td)); if (new_rt != rt) { - uint16 rail_speed = GetRailTypeInfo(new_rt)->max_speed; + uint16 rail_speed = GetTrainSpeedLimitForRailtype(v, new_rt, t, TrackdirToTrack(td)); if (rail_speed > 0) lookahead->AddTrackSpeedLimit(rail_speed, offset, 4, z); if (GetRailTypeInfo(rt)->curve_speed != GetRailTypeInfo(new_rt)->curve_speed) { CheckCurveLookAhead(v, lookahead, lookahead->RealEndPosition() + 4 + offset, z, new_rt); @@ -870,9 +890,10 @@ static int ScanTrainPositionForLookAheadStation(Train *t, TileIndex start_tile) if (u == t) { for (uint i = 1; i < forward_length; i++) { /* Check for mid platform rail type change */ - RailType new_rt = GetRailTypeByTrack(tile + (i * diff), TrackdirToTrack(trackdir)); + TileIndex new_tile = tile + (i * diff); + RailType new_rt = GetRailTypeByTrack(new_tile, TrackdirToTrack(trackdir)); if (new_rt != rt) { - uint16 rail_speed = GetRailTypeInfo(new_rt)->max_speed; + uint16 rail_speed = GetTrainSpeedLimitForRailtype(t, new_rt, new_tile, TrackdirToTrack(trackdir)); if (rail_speed > 0) t->lookahead->AddTrackSpeedLimit(rail_speed, (i - 1) * TILE_SIZE, 4, z); rt = new_rt; } diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 764aa73bf8..2b3b2d7dc8 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -182,8 +182,8 @@ class NIHVehicle : public NIHelper { } if (v->type == VEH_TRAIN) { const Train *t = Train::From(v); - seprintf(buffer, lastof(buffer), " T cache: tilt: %d, curve speed mod: %d, engines: %u", - (t->tcache.cached_tflags & TCF_TILT) ? 1 : 0, t->tcache.cached_curve_speed_mod, t->tcache.cached_num_engines); + seprintf(buffer, lastof(buffer), " T cache: tilt: %d, speed varies by railtype: %d, curve speed mod: %d, engines: %u", + (t->tcache.cached_tflags & TCF_TILT) ? 1 : 0, (t->tcache.cached_tflags & TCF_SPD_RAILTYPE) ? 1 : 0, t->tcache.cached_curve_speed_mod, t->tcache.cached_num_engines); output.print(buffer); seprintf(buffer, lastof(buffer), " T cache: RL braking: %d, decel: %u, uncapped decel: %u, centre mass: %u", (t->UsingRealisticBraking()) ? 1 : 0, t->tcache.cached_deceleration, t->tcache.cached_uncapped_decel, t->tcache.cached_centre_mass); diff --git a/src/train.h b/src/train.h index b4bd0e6e5c..20556a92a5 100644 --- a/src/train.h +++ b/src/train.h @@ -96,9 +96,10 @@ inline int GetTrainRealisticBrakingTargetDecelerationLimit(int acceleration_type /** Flags for TrainCache::cached_tflags */ enum TrainCacheFlags : byte { - TCF_NONE = 0, ///< No flags - TCF_TILT = 0x01, ///< Train can tilt; feature provides a bonus in curves. - TCF_RL_BRAKING = 0x02, ///< Train realistic braking (movement physics) in effect for this vehicle + TCF_NONE = 0, ///< No flags + TCF_TILT = 0x01, ///< Train can tilt; feature provides a bonus in curves. + TCF_RL_BRAKING = 0x02, ///< Train realistic braking (movement physics) in effect for this vehicle + TCF_SPD_RAILTYPE = 0x04, ///< Train speed varies depending on railtype }; DECLARE_ENUM_AS_BIT_SET(TrainCacheFlags) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index f1eb04ff1b..c2c0c6d3d5 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -264,6 +264,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) this->tcache.cached_num_engines = 0; bool train_can_tilt = true; + bool speed_varies_by_railtype = false; int min_curve_speed_mod = INT_MAX; for (Train *u = this; u != nullptr; u = u->Next()) { @@ -304,6 +305,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) const RailVehicleInfo *rvi_u = &e_u->u.rail; if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false; + if (e_u->callbacks_used & SGCU_CB36_SPEED_RAILTYPE) speed_varies_by_railtype = true; min_curve_speed_mod = std::min(min_curve_speed_mod, u->GetCurveSpeedModifier()); /* Cache wagon override sprite group. nullptr is returned if there is none */ @@ -390,7 +392,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) /* store consist weight/max speed in cache */ this->vcache.cached_max_speed = max_speed; - this->tcache.cached_tflags = (train_can_tilt ? TCF_TILT : TCF_NONE); + this->tcache.cached_tflags = (train_can_tilt ? TCF_TILT : TCF_NONE) | (speed_varies_by_railtype ? TCF_SPD_RAILTYPE : TCF_NONE); this->tcache.cached_curve_speed_mod = min_curve_speed_mod; this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit();