diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6ce836f..01919d6 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -364,11 +364,12 @@ void TrainConsistChanged(Vehicle *v, bool same_length) enum AccelType { AM_ACCEL, - AM_BRAKE + AM_BRAKE, + AM_SLOWBRAKE, }; /** new acceleration*/ -static int GetTrainAcceleration(Vehicle *v, bool mode) +static int GetTrainAcceleration(Vehicle *v, AccelType mode) { static const int absolute_max_speed = UINT16_MAX; int max_speed = absolute_max_speed; @@ -444,6 +445,21 @@ static int GetTrainAcceleration(Vehicle *v, bool mode) } } + if (HasBit(v->u.rail.flags, VRF_SIG_SLOWDOWN)) { + if (v->cur_speed > 80) { + mode = AM_SLOWBRAKE; + } else { + max_speed = min(max_speed, 80); + } + } + if (HasBit(v->u.rail.flags, VRF_SIG_STOP)) { + if (v->cur_speed > 10) { + mode = AM_SLOWBRAKE; + } else { + max_speed = min(max_speed, 10); + } + } + int mass = v->u.rail.cached_weight; int power = v->u.rail.cached_power * 746; max_speed = min(max_speed, v->u.rail.cached_max_speed); @@ -490,7 +506,7 @@ static int GetTrainAcceleration(Vehicle *v, bool mode) force = power / speed; //[N] force *= 22; force /= 10; - if (mode == AM_ACCEL && force > max_te) force = max_te; + if (mode != AM_BRAKE && force > max_te) force = max_te; break; default: NOT_REACHED(); @@ -504,6 +520,8 @@ static int GetTrainAcceleration(Vehicle *v, bool mode) force = max(force, (mass * 8) + resistance); } + if (mode == AM_SLOWBRAKE) force /= 2; + if (mode == AM_ACCEL) { return (force - resistance) / (mass * 2); } else { @@ -1852,6 +1870,8 @@ static void ReverseTrainDirection(Vehicle *v) ClrBit(v->u.rail.flags, VRF_REVERSING); + ClrBit(v->u.rail.flags, VRF_SIG_STOP); + /* recalculate cached data */ TrainConsistChanged(v, true); @@ -2346,6 +2366,9 @@ static void CheckNextTrainTile(Vehicle *v) MarkTileDirtyByTile(ft.m_new_tile); } } + if (GetSignalStateByTrackdir(ft.m_new_tile, td) == SIGNAL_STATE_RED) { + SetBit(v->u.rail.flags, VRF_SIG_STOP); + } } } } @@ -2866,8 +2889,6 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir assert((tracks & ~TRACK_BIT_MASK) == 0); - if (got_reservation != NULL) *got_reservation = false; - /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */ TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir)); /* Do we have a suitable reserved track? */ @@ -2887,6 +2908,8 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir best_track = track; } + if (got_reservation != NULL) *got_reservation = false; + PBSTileInfo origin = FollowTrainReservation(v); PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); DiagDirection dest_enterdir = enterdir; @@ -3700,7 +3723,8 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) if (prev == NULL) { /* Currently the locomotive is active. Determine which one of the * available tracks to choose */ - Track new_track = ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true); + bool got_res = true; + Track new_track = ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, &got_res, false); chosen_track = TrackToTrackBits(new_track); assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile))); @@ -3709,6 +3733,11 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) /* In front of a red signal */ Trackdir i = FindFirstTrackdir(trackdirbits); + SetBit(v->u.rail.flags, VRF_SIG_STOP); + if (v->cur_speed > 10) goto dont_stop_on_signal; + + if (!got_res) MarkTrainAsStuck(v); + /* Don't handle stuck trains here. */ if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) return; @@ -3739,8 +3768,23 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) return; } goto reverse_train_direction; +dont_stop_on_signal: ; } else { + if (!got_res) MarkTrainAsStuck(v); TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track)); + if (IsTileType(gp.new_tile, MP_RAILWAY) && HasSignalOnTrackdir(gp.new_tile, TrackEnterdirToTrackdir(new_track, enterdir))) { + switch (GetSignalStateByTrackdir(gp.new_tile, TrackEnterdirToTrackdir(new_track, enterdir))) { + case SIGNAL_STATE_YELLOW: + SetBit(v->u.rail.flags, VRF_SIG_SLOWDOWN); + ClrBit(v->u.rail.flags, VRF_SIG_STOP); + break; + case SIGNAL_STATE_GREEN: + ClrBit(v->u.rail.flags, VRF_SIG_STOP); + case SIGNAL_STATE_RED: + ClrBit(v->u.rail.flags, VRF_SIG_SLOWDOWN); + break; + } + } } } else { static const TrackBits _matching_tracks[8] = { @@ -4223,7 +4267,7 @@ static bool TrainCheckIfLineEnds(Vehicle *v) } /* approaching red signal */ - if ((trackdirbits & red_signals) != 0 && IsStopSignal(tile, FindFirstTrack(bits))) return TrainApproachingLineEnd(v, true); + if ((trackdirbits & red_signals) != 0 && IsStopSignal(tile, FindFirstTrack(bits)) && !IsPbsSignal(GetSignalType(tile, FindFirstTrack(bits)))) return TrainApproachingLineEnd(v, true); /* approaching a rail/road crossing? then make it red */ if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); @@ -4243,6 +4287,8 @@ static void TrainLocoHandler(Vehicle *v, bool mode) if (v->u.rail.force_proceed != 0) { v->u.rail.force_proceed--; ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); + ClrBit(v->u.rail.flags, VRF_SIG_SLOWDOWN); + ClrBit(v->u.rail.flags, VRF_SIG_STOP); InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index cfda648..0227ad8 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -147,6 +147,10 @@ enum VehicleRailFlags { /* used to mark a train that can't get a path reservation */ VRF_TRAIN_STUCK = 8, + + /* used to mark a train that should slow down due to a yellow signal */ + VRF_SIG_SLOWDOWN = 9, + VRF_SIG_STOP = 10, }; struct VehicleAir {