diff --git a/src/lang/english.txt b/src/lang/english.txt index 8dc3dc34f3..0e38639ccd 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2438,6 +2438,8 @@ STR_TRACE_RESTRICT_RESERVE_THROUGH :Reserve through STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL :Cancel reserve through STR_TRACE_RESTRICT_LONG_RESERVE :Long reserve STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL :Cancel long reserve +STR_TRACE_RESTRICT_WAIT_AT_PBS :Wait at PBS signal +STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL :Cancel wait at PBS signal STR_TRACE_RESTRICT_PF_PENALTY :Penalty STR_TRACE_RESTRICT_PF_VALUE_SMALL :small STR_TRACE_RESTRICT_PF_VALUE_MEDIUM :medium @@ -3757,6 +3759,7 @@ STR_VEHICLE_STATUS_STOPPED :{RED}Stopped STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Stopping, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}No power STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waiting for free path +STR_VEHICLE_STATUS_TRAIN_STUCK_WAIT_RESTRICTION :{ORANGE}Waiting due to routing restriction STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Too far to next destination STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Heading for {STATION}, {VELOCITY} diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 6b484e16d9..58e24e51e2 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -438,6 +438,14 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp } break; + case TRIT_WAIT_AT_PBS: + if (GetTraceRestrictValue(item)) { + out.flags &= ~TRPRF_WAIT_AT_PBS; + } else { + out.flags |= TRPRF_WAIT_AT_PBS; + } + break; + default: NOT_REACHED(); } @@ -547,6 +555,10 @@ CommandCost TraceRestrictProgram::Validate(const std::vector actions_used_flags |= TRPAUF_LONG_RESERVE; break; + case TRIT_WAIT_AT_PBS: + actions_used_flags |= TRPAUF_WAIT_AT_PBS; + break; + default: return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION); } @@ -605,6 +617,7 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp case TRVT_FORCE: case TRVT_POWER_WEIGHT_RATIO: case TRVT_FORCE_WEIGHT_RATIO: + case TRVT_WAIT_AT_PBS: SetTraceRestrictValue(item, 0); if (!IsTraceRestrictTypeAuxSubtype(GetTraceRestrictType(item))) { SetTraceRestrictAuxField(item, 0); diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 3b6521e3e7..520e183477 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -100,6 +100,7 @@ enum TraceRestrictItemType { TRIT_PF_PENALTY = 2, ///< Add to pathfinder penalty TRIT_RESERVE_THROUGH = 3, ///< Reserve through PBS signal TRIT_LONG_RESERVE = 4, ///< Long reserve PBS signal + TRIT_WAIT_AT_PBS = 5, ///< Wait at PBS signal TRIT_COND_BEGIN = 8, ///< Start of conditional item types, note that this has the same value as TRIT_COND_ENDIF TRIT_COND_ENDIF = 8, ///< This is an endif block or an else block @@ -220,6 +221,7 @@ enum TraceRestrictProgramResultFlags { TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set TRPRF_RESERVE_THROUGH = 1 << 1, ///< Reserve through is set TRPRF_LONG_RESERVE = 1 << 2, ///< Long reserve is set + TRPRF_WAIT_AT_PBS = 1 << 3, ///< Wait at PBS signal is set }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags) @@ -230,6 +232,7 @@ enum TraceRestrictProgramActionsUsedFlags { TRPAUF_PF = 1 << 0, ///< Pathfinder deny or penalty are present TRPAUF_RESERVE_THROUGH = 1 << 1, ///< Reserve through action is present TRPAUF_LONG_RESERVE = 1 << 2, ///< Long reserve action is present + TRPAUF_WAIT_AT_PBS = 1 << 3, ///< Wait at PBS signal action is present }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags) @@ -440,6 +443,7 @@ enum TraceRestrictValueType { TRVT_FORCE = 15,///< takes a force TRVT_POWER_WEIGHT_RATIO = 16,///< takes a power / weight ratio, * 100 TRVT_FORCE_WEIGHT_RATIO = 17,///< takes a force / weight ratio, * 100 + TRVT_WAIT_AT_PBS = 18,///< takes a value 0 = wait at PBS signal, 1 = cancel wait at PBS signal }; /** @@ -556,6 +560,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR out.value_type = TRVT_RESERVE_THROUGH; } else if (GetTraceRestrictType(item) == TRIT_LONG_RESERVE) { out.value_type = TRVT_LONG_RESERVE; + } else if (GetTraceRestrictType(item) == TRIT_WAIT_AT_PBS) { + out.value_type = TRVT_WAIT_AT_PBS; } else { out.value_type = TRVT_NONE; } diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 25346c7968..7106111013 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -127,6 +127,7 @@ static const StringID _program_insert_str[] = { STR_TRACE_RESTRICT_PF_PENALTY, STR_TRACE_RESTRICT_RESERVE_THROUGH, STR_TRACE_RESTRICT_LONG_RESERVE, + STR_TRACE_RESTRICT_WAIT_AT_PBS, INVALID_STRING_ID }; static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else @@ -141,6 +142,7 @@ static const uint _program_insert_val[] = { TRIT_PF_PENALTY, // penalty TRIT_RESERVE_THROUGH, // reserve through TRIT_LONG_RESERVE, // long reserve + TRIT_WAIT_AT_PBS, // wait at PBS signal }; /** insert drop down list strings and values */ @@ -193,6 +195,21 @@ static const TraceRestrictDropDownListSet _long_reserve_value = { _long_reserve_value_str, _long_reserve_value_val, }; +static const StringID _wait_at_pbs_value_str[] = { + STR_TRACE_RESTRICT_WAIT_AT_PBS, + STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL, + INVALID_STRING_ID +}; +static const uint _wait_at_pbs_value_val[] = { + 0, + 1, +}; + +/** value drop down list for wait at PBS types strings and values */ +static const TraceRestrictDropDownListSet _wait_at_pbs_value = { + _wait_at_pbs_value_str, _wait_at_pbs_value_val, +}; + static const StringID _direction_value_str[] = { STR_TRACE_RESTRICT_DIRECTION_FRONT, STR_TRACE_RESTRICT_DIRECTION_BACK, @@ -270,6 +287,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG STR_TRACE_RESTRICT_PF_PENALTY, STR_TRACE_RESTRICT_RESERVE_THROUGH, STR_TRACE_RESTRICT_LONG_RESERVE, + STR_TRACE_RESTRICT_WAIT_AT_PBS, INVALID_STRING_ID, }; static const uint val_action[] = { @@ -277,6 +295,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG TRIT_PF_PENALTY, TRIT_RESERVE_THROUGH, TRIT_LONG_RESERVE, + TRIT_WAIT_AT_PBS, }; static const TraceRestrictDropDownListSet set_action = { str_action, val_action, @@ -880,6 +899,10 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL : STR_TRACE_RESTRICT_LONG_RESERVE; break; + case TRIT_WAIT_AT_PBS: + instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL : STR_TRACE_RESTRICT_WAIT_AT_PBS; + break; + default: NOT_REACHED(); break; @@ -1131,6 +1154,10 @@ public: this->ShowDropDownListWithValue(&_long_reserve_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0); break; + case TRVT_WAIT_AT_PBS: + this->ShowDropDownListWithValue(&_wait_at_pbs_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0); + break; + case TRVT_GROUP_INDEX: { int selected; DropDownList *dlist = GetGroupDropDownList(this->GetOwner(), GetTraceRestrictValue(item), selected); @@ -1961,6 +1988,13 @@ private: GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL : STR_TRACE_RESTRICT_LONG_RESERVE; break; + case TRVT_WAIT_AT_PBS: + right_sel->SetDisplayedPlane(DPR_VALUE_DROPDOWN); + this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN); + this->GetWidget(TR_WIDGET_VALUE_DROPDOWN)->widget_data = + GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_WAIT_AT_PBS_CANCEL : STR_TRACE_RESTRICT_WAIT_AT_PBS; + break; + case TRVT_GROUP_INDEX: right_sel->SetDisplayedPlane(DPR_VALUE_DROPDOWN); this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN); diff --git a/src/train.h b/src/train.h index 82e33b67d9..93c5cf3dc5 100644 --- a/src/train.h +++ b/src/train.h @@ -26,6 +26,7 @@ struct Train; /** Rail vehicle flags. */ enum VehicleRailFlags { VRF_REVERSING = 0, + VRF_WAITING_RESTRICTION = 1, ///< Train is waiting due to a routing restriction, only valid when VRF_TRAIN_STUCK is also set. VRF_POWEREDWAGON = 3, ///< Wagon is powered. VRF_REVERSE_DIRECTION = 4, ///< Reverse the visible direction of the vehicle. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 00d57738a8..c43d4d2925 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1512,11 +1512,12 @@ void Train::UpdateDeltaXY(Direction direction) * Mark a train as stuck and stop it if it isn't stopped right now. * @param v %Train to mark as being stuck. */ -static void MarkTrainAsStuck(Train *v) +static void MarkTrainAsStuck(Train *v, bool waiting_restriction = false) { if (!HasBit(v->flags, VRF_TRAIN_STUCK)) { /* It is the first time the problem occurred, set the "train stuck" flag. */ SetBit(v->flags, VRF_TRAIN_STUCK); + SB(v->flags, VRF_WAITING_RESTRICTION, 1, waiting_restriction ? 1 : 0); v->wait_counter = 0; @@ -1525,6 +1526,9 @@ static void MarkTrainAsStuck(Train *v) v->subspeed = 0; v->SetLastSpeed(); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + } else if (waiting_restriction != HasBit(v->flags, VRF_WAITING_RESTRICTION)) { + ToggleBit(v->flags, VRF_WAITING_RESTRICTION); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } } @@ -2586,6 +2590,18 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, Track track = FindFirstTrack(tracks); /* We need to check for signals only here, as a junction tile can't have signals. */ if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) { + if (IsRestrictedSignal(tile) && v->force_proceed != TFP_SIGNAL) { + const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, track); + if (prog && prog->actions_used_flags & TRPAUF_WAIT_AT_PBS) { + TraceRestrictProgramResult out; + prog->Execute(v, TraceRestrictProgramInput(tile, TrackEnterdirToTrackdir(track, enterdir), NULL, NULL), out); + if (out.flags & TRPRF_WAIT_AT_PBS) { + if (mark_stuck) MarkTrainAsStuck(v, true); + return track; + } + } + } + do_track_reservation = true; changed_signal = true; SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), SIGNAL_STATE_GREEN); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 89d4c4639d..ffa0f1ad5d 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2615,7 +2615,7 @@ public: str = STR_VEHICLE_STATUS_STOPPED; } } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) { - str = STR_VEHICLE_STATUS_TRAIN_STUCK; + str = HasBit(Train::From(v)->flags, VRF_WAITING_RESTRICTION) ? STR_VEHICLE_STATUS_TRAIN_STUCK_WAIT_RESTRICTION : STR_VEHICLE_STATUS_TRAIN_STUCK; } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; } else { // vehicle is in a "normal" state, show current order