diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index e81d23fba8..4ba9797d4d 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -890,6 +890,7 @@ 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_LONG_RESERVE_UNLESS_STOPPING :Long reserve (unless stopping) 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_PBS_RES_END_WAIT :Wait at start PBS signal for reservation ending here diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 8ea9f47e05..c0db11b1b2 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -76,7 +76,7 @@ static uint32 saveSTC(const SlxiSubChunkInfo *info, bool dry_run); const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_VERSION_LABEL, XSCF_IGNORABLE_ALL, 1, 1, "version_label", saveVL, loadVL, nullptr }, { XSLFI_UPSTREAM_VERSION, XSCF_NULL, 1, 1, "upstream_version", saveUV, loadUV, nullptr }, - { XSLFI_TRACE_RESTRICT, XSCF_NULL, 15, 15, "tracerestrict", nullptr, nullptr, "TRRM,TRRP,TRRS" }, + { XSLFI_TRACE_RESTRICT, XSCF_NULL, 16, 16, "tracerestrict", nullptr, nullptr, "TRRM,TRRP,TRRS" }, { XSLFI_TRACE_RESTRICT_OWNER, XSCF_NULL, 1, 1, "tracerestrict_owner", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_ORDRCND, XSCF_NULL, 4, 4, "tracerestrict_order_cond", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_STATUSCND, XSCF_NULL, 2, 2, "tracerestrict_status_cond", nullptr, nullptr, nullptr }, diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 119683f8a3..1cb5e529eb 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -687,6 +687,12 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp out.flags &= ~TRPRF_LONG_RESERVE; break; + case TRLRVF_LONG_RESERVE_UNLESS_STOPPING: + if (!(input.input_flags & TRPIF_PASSED_STOP)) { + out.flags |= TRPRF_LONG_RESERVE; + } + break; + default: NOT_REACHED(); break; diff --git a/src/tracerestrict.h b/src/tracerestrict.h index a625909671..26dc7ae506 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -273,8 +273,9 @@ enum TraceRestrictTargetDirectionCondAuxField { * TraceRestrictItem value field, for TRIT_LONG_RESERVE */ enum TraceRestrictLongReserveValueField { - TRLRVF_LONG_RESERVE = 0, ///< Long reserve - TRLRVF_CANCEL_LONG_RESERVE = 1, ///< Cancel long reserve + TRLRVF_LONG_RESERVE = 0, ///< Long reserve + TRLRVF_CANCEL_LONG_RESERVE = 1, ///< Cancel long reserve + TRLRVF_LONG_RESERVE_UNLESS_STOPPING = 2, ///< Long reserve (unless passed stop) }; /** @@ -474,6 +475,14 @@ enum TraceRestrictProgramInputSlotPermissions : uint8 { }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramInputSlotPermissions) +/** + * Enumeration for TraceRestrictProgramInput::input_flags + */ +enum TraceRestrictProgramInputFlags : uint8 { + TRPIF_PASSED_STOP = 1 << 0, ///< Train has passed stop +}; +DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramInputFlags) + /** * Execution input of a TraceRestrictProgram */ @@ -485,10 +494,12 @@ struct TraceRestrictProgramInput { PreviousSignalProc *previous_signal_callback; ///< Callback to retrieve tile and direction of previous signal, may be nullptr const void *previous_signal_ptr; ///< Opaque pointer suitable to be passed to previous_signal_callback TraceRestrictProgramInputSlotPermissions permitted_slot_operations; ///< Permitted slot operations + TraceRestrictProgramInputFlags input_flags; ///< Input flags TraceRestrictProgramInput(TileIndex tile_, Trackdir trackdir_, PreviousSignalProc *previous_signal_callback_, const void *previous_signal_ptr_) : tile(tile_), trackdir(trackdir_), previous_signal_callback(previous_signal_callback_), previous_signal_ptr(previous_signal_ptr_), - permitted_slot_operations(static_cast(0)) { } + permitted_slot_operations(static_cast(0)), + input_flags(static_cast(0)) { } }; /** diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 4b19621f9e..891fc40485 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -242,11 +242,13 @@ static const TraceRestrictDropDownListSet _reserve_through_value = { static const StringID _long_reserve_value_str[] = { STR_TRACE_RESTRICT_LONG_RESERVE, STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL, + STR_TRACE_RESTRICT_LONG_RESERVE_UNLESS_STOPPING, INVALID_STRING_ID }; static const uint _long_reserve_value_val[] = { 0, 1, + 2, }; /** value drop down list for long reserve types strings and values */ @@ -1554,6 +1556,10 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric instruction_string = STR_TRACE_RESTRICT_LONG_RESERVE_CANCEL; break; + case TRLRVF_LONG_RESERVE_UNLESS_STOPPING: + instruction_string = STR_TRACE_RESTRICT_LONG_RESERVE_UNLESS_STOPPING; + break; + default: NOT_REACHED(); break; @@ -2061,9 +2067,12 @@ public: this->ShowDropDownListWithValue(&_reserve_through_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0); break; - case TRVT_LONG_RESERVE: - this->ShowDropDownListWithValue(&_long_reserve_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0); + case TRVT_LONG_RESERVE: { + uint hidden = 0; + if (_settings_game.vehicle.train_braking_model != TBM_REALISTIC) hidden |= 4; + this->ShowDropDownListWithValue(&_long_reserve_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, hidden); break; + } case TRVT_WAIT_AT_PBS: this->ShowDropDownListWithValue(&_wait_at_pbs_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2e9ffda7e6..86a0b182c1 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4179,7 +4179,7 @@ static bool LookaheadWithinCurrentTunnelBridge(const Train *t) return t->lookahead->current_position >= t->lookahead->reservation_end_position - ((int)TILE_SIZE * t->lookahead->tunnel_bridge_reserved_tiles) && !HasBit(t->lookahead->flags, TRLF_TB_EXIT_FREE); } -static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool default_value) +static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool default_value, uint16 lookahead_state_flags) { if (HasPbsSignalOnTrackdir(tile, trackdir)) { if (IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) return false; @@ -4188,7 +4188,9 @@ static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir if (prog && prog->actions_used_flags & TRPAUF_LONG_RESERVE) { TraceRestrictProgramResult out; if (default_value) out.flags |= TRPRF_LONG_RESERVE; - prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr), out); + TraceRestrictProgramInput input(tile, trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr); + if (HasBit(lookahead_state_flags, CTTLASF_STOP_FOUND)) input.input_flags |= TRPIF_PASSED_STOP; + prog->Execute(v, input, out); return (out.flags & TRPRF_LONG_RESERVE); } } @@ -4249,6 +4251,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td TraceRestrictProgramResult out; if (long_reserve) out.flags |= TRPRF_LONG_RESERVE; TraceRestrictProgramInput input(exit_tile, exit_td, nullptr, nullptr); + if (HasBit(lookahead_state.flags, CTTLASF_STOP_FOUND)) input.input_flags |= TRPIF_PASSED_STOP; input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_ACQUIRE_ON_RES; prog->Execute(v, input, out); if (out.flags & TRPRF_WAIT_AT_PBS) { @@ -4292,7 +4295,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td } CFollowTrackRail ft(v); - if (ft.Follow(tile, td) && HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits), !long_enough)) { + if (ft.Follow(tile, td) && HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits), !long_enough, lookahead_state.flags)) { // We reserved up to a LR signal, reserve past it as well. recursion ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), CTTF_NO_LOOKAHEAD_VALIDATE | (force_res ? CTTF_FORCE_RES : CTTF_NONE), nullptr, lookahead_state); } @@ -4412,7 +4415,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, CFollowTrackRail ft(v); if (ft.Follow(res_dest.tile, res_dest.trackdir)) { Trackdir new_td = FindFirstTrackdir(ft.m_new_td_bits); - long_reserve = HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td, _settings_game.vehicle.train_braking_model == TBM_REALISTIC); + long_reserve = HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td, _settings_game.vehicle.train_braking_model == TBM_REALISTIC, lookahead_state.flags); } } @@ -4898,7 +4901,7 @@ static TrainMovedChangeSignalEnum TrainMovedChangeSignal(Train* v, TileIndex til /* A PBS block with a non-PBS signal facing us? */ if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return CHANGED_NORMAL_TO_PBS_BLOCK; - if (front && HasLongReservePbsSignalOnTrackdir(v, tile, trackdir, _settings_game.vehicle.train_braking_model == TBM_REALISTIC)) return CHANGED_LR_PBS; + if (front && HasLongReservePbsSignalOnTrackdir(v, tile, trackdir, _settings_game.vehicle.train_braking_model == TBM_REALISTIC, 0)) return CHANGED_LR_PBS; } } if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(tile) && GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {