diff --git a/src/lang/english.txt b/src/lang/english.txt index 6e6316a48a..ac0e5660df 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2773,6 +2773,9 @@ STR_TRACE_RESTRICT_VARIABLE_LOAD_PERCENT :load percentage STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION :entry direction STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL :PBS entry signal STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL_LONG :entered signal of PBS block +STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL :PBS end signal +STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL_LONG :signal at current end of PBS reservation +STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL_LONG_WARN :signal at current end of PBS reservation {PUSH_COLOUR}{RED}(requires realistic braking){POP_COLOUR} STR_TRACE_RESTRICT_VARIABLE_TRAIN_GROUP :train group STR_TRACE_RESTRICT_VARIABLE_TRAIN_SLOT :train in slot STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY :slot occupancy diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 046f552d77..6cc7ab7aee 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -178,14 +178,15 @@ private: * This is called to retrieve the previous signal, as required * This is not run all the time as it is somewhat expensive and most restrictions will not test for the previous signal */ - static TileIndex TraceRestrictPreviousSignalCallback(const Train *v, const void *node_ptr) + static TileIndex TraceRestrictPreviousSignalCallback(const Train *v, const void *node_ptr, TraceRestrictPBSEntrySignalAuxField mode) { const Node *node = static_cast(node_ptr); for (;;) { TileIndex last_signal_tile = node->m_last_non_reserve_through_signal_tile; if (last_signal_tile != INVALID_TILE) { Trackdir last_signal_trackdir = node->m_last_non_reserve_through_signal_td; - if (HasPbsSignalOnTrackdir(last_signal_tile, last_signal_trackdir)) { + if (HasPbsSignalOnTrackdir(last_signal_tile, last_signal_trackdir) || + (IsTileType(last_signal_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(last_signal_tile) && IsTunnelBridgeEffectivelyPBS(last_signal_tile) && TrackdirExitsTunnelBridge(last_signal_tile, last_signal_trackdir))) { return last_signal_tile; } else { return INVALID_TILE; @@ -208,15 +209,21 @@ private: TileIndex origin_tile = node->GetTile(); Trackdir origin_trackdir = node->GetTrackdir(); - TileIndex tile = v->tile; - Trackdir trackdir = v->GetVehicleTrackdir(); - TileIndex candidate_tile = INVALID_TILE; - if (IsRailDepotTile(v->tile)) { - candidate_tile = v->tile; - } else if (v->track & TRACK_BIT_WORMHOLE && IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(v->tile) && IsTunnelBridgeEffectivelyPBS(v->tile)) { - candidate_tile = v->tile; + TileIndex tile; + Trackdir trackdir; + if (mode == TRPESAF_RES_END && v->lookahead != nullptr) { + tile = v->lookahead->reservation_end_tile; + trackdir = v->lookahead->reservation_end_trackdir; + } else { + tile = v->tile; + trackdir = v->GetVehicleTrackdir(); + if (IsRailDepotTile(v->tile)) { + candidate_tile = v->tile; + } else if (v->track & TRACK_BIT_WORMHOLE && IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(v->tile) && IsTunnelBridgeEffectivelyPBS(v->tile)) { + candidate_tile = v->tile; + } } CFollowTrackRail ft(v); @@ -381,6 +388,11 @@ public: /* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */ n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; } + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgeEffectivelyPBS(tile) && TrackdirExitsTunnelBridge(tile, trackdir)) { + /* Exiting a PBS signalled tunnel/bridge, record the last non-reserve through signal */ + n.m_last_non_reserve_through_signal_tile = tile; + n.m_last_non_reserve_through_signal_td = trackdir; + } return cost; } diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index 379d7688fe..23ae64ed4f 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -213,7 +213,7 @@ public: if (restricted_signal_info.tile != INVALID_TILE) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(restricted_signal_info.tile, TrackdirToTrack(restricted_signal_info.trackdir)); if (prog && prog->actions_used_flags & TRPAUF_PBS_RES_END_SLOT) { - extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *); + extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode); TraceRestrictProgramResult out; TraceRestrictProgramInput input(restricted_signal_info.tile, restricted_signal_info.trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr); diff --git a/src/pbs.cpp b/src/pbs.cpp index b8a60ec2fc..44123c6105 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -1043,20 +1043,27 @@ CommandCost CheckTrainInTunnelBridgePreventsTrackModification(TileIndex start, T * This is called to retrieve the previous signal, as required * This is not run all the time as it is somewhat expensive and most restrictions will not test for the previous signal */ -TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *) +TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode) { - if (IsRailDepotTile(v->tile)) { - return v->tile; - } - if (v->track & TRACK_BIT_WORMHOLE && IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(v->tile) && IsTunnelBridgeEffectivelyPBS(v->tile)) { - return v->tile; + TileIndex tile; + Trackdir trackdir; + + if (mode == TRPESAF_RES_END && v->lookahead != nullptr) { + tile = v->lookahead->reservation_end_tile; + trackdir = v->lookahead->reservation_end_trackdir; + } else { + if (IsRailDepotTile(v->tile)) { + return v->tile; + } + if (v->track & TRACK_BIT_WORMHOLE && IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(v->tile) && IsTunnelBridgeEffectivelyPBS(v->tile)) { + return v->tile; + } + tile = v->tile; + trackdir = v->GetVehicleTrackdir(); } // scan forwards from vehicle position, for the case that train is waiting at/approaching PBS signal - TileIndex tile = v->tile; - Trackdir trackdir = v->GetVehicleTrackdir(); - CFollowTrackRail ft(v); for (;;) { @@ -1070,6 +1077,10 @@ TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const vo } } + if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgeEffectivelyPBS(tile) && TrackdirExitsTunnelBridge(tile, trackdir)) { + return tile; + } + // advance to next tile if (!ft.Follow(tile, trackdir)) { // ran out of track diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 8693b90bd4..a2ed4805b0 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -76,6 +76,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TRACE_RESTRICT_NEWSCTRL,XSCF_NULL, 1, 1, "tracerestrict_newsctrl", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_COUNTER, XSCF_NULL, 1, 1, "tracerestrict_counter", nullptr, nullptr, "TRRC" }, { XSLFI_TRACE_RESTRICT_TIMEDATE,XSCF_NULL, 1, 1, "tracerestrict_timedate", nullptr, nullptr, nullptr }, + { XSLFI_TRACE_RESTRICT_BRKCND, XSCF_NULL, 1, 1, "tracerestrict_braking_cond",nullptr, nullptr, nullptr }, { XSLFI_PROG_SIGS, XSCF_NULL, 2, 2, "programmable_signals", nullptr, nullptr, "SPRG" }, { XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", nullptr, nullptr, nullptr }, { XSLFI_SAFER_CROSSINGS, XSCF_NULL, 1, 1, "safer_crossings", nullptr, nullptr, nullptr }, diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 0e346e264d..2a0eb7221d 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -30,6 +30,7 @@ enum SlXvFeatureIndex { XSLFI_TRACE_RESTRICT_NEWSCTRL, ///< Trace restrict: news control XSLFI_TRACE_RESTRICT_COUNTER, ///< Trace restrict: counters XSLFI_TRACE_RESTRICT_TIMEDATE, ///< Trace restrict: time/date + XSLFI_TRACE_RESTRICT_BRKCND, ///< Trace restrict: realistic braking related conditionals XSLFI_PROG_SIGS, ///< programmable pre-signals patch XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch XSLFI_SAFER_CROSSINGS, ///< Safer level crossings diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index fa3c68c655..c2229a97ff 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -244,8 +244,8 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp static std::vector condstack; condstack.clear(); - bool have_previous_signal = false; - TileIndex previous_signal_tile = INVALID_TILE; + byte have_previous_signal = 0; + TileIndex previous_signal_tile[2]; size_t size = this->items.size(); for (size_t i = 0; i < size; i++) { @@ -344,17 +344,21 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp } case TRIT_COND_PBS_ENTRY_SIGNAL: { - // TRVT_TILE_INDEX value type uses the next slot + // TRIT_COND_PBS_ENTRY_SIGNAL value type uses the next slot i++; + TraceRestrictPBSEntrySignalAuxField mode = static_cast(GetTraceRestrictAuxField(item)); + assert(mode == TRPESAF_VEH_POS || mode == TRPESAF_RES_END); uint32_t signal_tile = this->items[i]; - if (!have_previous_signal) { + if (!HasBit(have_previous_signal, mode)) { if (input.previous_signal_callback) { - previous_signal_tile = input.previous_signal_callback(v, input.previous_signal_ptr); + previous_signal_tile[mode] = input.previous_signal_callback(v, input.previous_signal_ptr, mode); + } else { + previous_signal_tile[mode] = INVALID_TILE; } - have_previous_signal = true; + SetBit(have_previous_signal, mode); } bool match = (signal_tile != INVALID_TILE) - && (previous_signal_tile == signal_tile); + && (previous_signal_tile[mode] == signal_tile); result = TestBinaryConditionCommon(item, match); break; } diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 3b3dd398b5..d733962f61 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -330,6 +330,15 @@ enum TraceRestrictCounterCondOpField { /* space up to 8 */ }; +/** + * TraceRestrictItem auxiliary type field, for TRIT_COND_PBS_ENTRY_SIGNAL + */ +enum TraceRestrictPBSEntrySignalAuxField { + TRPESAF_VEH_POS = 0, ///< vehicle position signal + TRPESAF_RES_END = 1, ///< reservation end signal + /* space up to 3 */ +}; + /** * TraceRestrictItem pathfinder penalty preset index * This may not be shortened, only lengthened, as preset indexes are stored in save games @@ -394,7 +403,7 @@ DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramInputSlotPermissions) * Execution input of a TraceRestrictProgram */ struct TraceRestrictProgramInput { - typedef TileIndex PreviousSignalProc(const Train *v, const void *ptr); + typedef TileIndex PreviousSignalProc(const Train *v, const void *ptr, TraceRestrictPBSEntrySignalAuxField mode); TileIndex tile; ///< Tile of restrict signal, for direction testing Trackdir trackdir; ///< Track direction on tile of restrict signal, for direction testing @@ -785,6 +794,7 @@ static inline bool IsTraceRestrictTypeAuxSubtype(TraceRestrictItemType type) case TRIT_COND_PHYS_PROP: case TRIT_COND_PHYS_RATIO: case TRIT_COND_SLOT_OCCUPANCY: + case TRIT_COND_PBS_ENTRY_SIGNAL: return true; default: diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 7bd0f532db..42b367a966 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -444,6 +444,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG STR_TRACE_RESTRICT_VARIABLE_LOAD_PERCENT, STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION, STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL, + STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL, STR_TRACE_RESTRICT_VARIABLE_TRAIN_GROUP, STR_TRACE_RESTRICT_VARIABLE_TRAIN_OWNER, STR_TRACE_RESTRICT_VARIABLE_TRAIN_STATUS, @@ -469,7 +470,8 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG TRIT_COND_CARGO, TRIT_COND_LOAD_PERCENT, TRIT_COND_ENTRY_DIRECTION, - TRIT_COND_PBS_ENTRY_SIGNAL, + TRIT_COND_PBS_ENTRY_SIGNAL | (TRPESAF_VEH_POS << 16), + TRIT_COND_PBS_ENTRY_SIGNAL | (TRPESAF_RES_END << 16), TRIT_COND_TRAIN_GROUP, TRIT_COND_TRAIN_OWNER, TRIT_COND_TRAIN_STATUS, @@ -494,9 +496,10 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG if (_settings_client.gui.show_adv_tracerestrict_features) { *hide_mask = 0; } else { - *hide_mask = is_conditional ? 0x3E0000 : 0x2F0; + *hide_mask = is_conditional ? 0x7C0000 : 0x2F0; } - if (is_conditional && !_settings_game.game_time.time_in_minutes) *hide_mask |= 0x200000; + if (is_conditional && !_settings_game.game_time.time_in_minutes) *hide_mask |= 0x400000; + if (is_conditional && _settings_game.vehicle.train_braking_model != TBM_REALISTIC) *hide_mask |= 0x200; } return is_conditional ? &set_cond : &set_action; } @@ -1090,11 +1093,22 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric } else { instruction_string = STR_TRACE_RESTRICT_CONDITIONAL_TILE_INDEX; SetDParam(0, _program_cond_type[GetTraceRestrictCondFlags(item)]); - SetDParam(1, STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL_LONG); SetDParam(2, GetDropDownStringByValue(GetCondOpDropDownListSet(properties), GetTraceRestrictCondOp(item))); SetDParam(3, TileX(tile)); SetDParam(4, TileY(tile)); } + switch (static_cast(GetTraceRestrictAuxField(item))) { + case TRPESAF_VEH_POS: + SetDParam(1, STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL_LONG); + break; + + case TRPESAF_RES_END: + SetDParam(1, _settings_game.vehicle.train_braking_model == TBM_REALISTIC ? STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL_LONG : STR_TRACE_RESTRICT_VARIABLE_PBS_RES_END_SIGNAL_LONG_WARN); + break; + + default: + NOT_REACHED(); + } break; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e0583dfa15..fd83b3582c 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -76,7 +76,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also us static TileIndex TrainApproachingCrossingTile(const Train *v); static void CheckIfTrainNeedsService(Train *v); static void CheckNextTrainTile(Train *v); -TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *); +extern TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode); static void TrainEnterStation(Train *v, StationID station); static void UnreserveBridgeTunnelTile(TileIndex tile); static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile);