diff --git a/src/lang/english.txt b/src/lang/english.txt index 677a631..6960578 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1196,6 +1196,7 @@ STR_CONFIG_PATCHES_DEFAULT_SIGNAL_TYPE :{LTBLUE}Signal STR_CONFIG_PATCHES_DEFAULT_SIGNAL_NORMAL :Block signals STR_CONFIG_PATCHES_DEFAULT_SIGNAL_PBS :Path signals STR_CONFIG_PATCHES_DEFAULT_SIGNAL_PBSOWAY :One-way path signals +STR_CONFIG_PATCHES_DEFAULT_SIGNAL_PBSCOMBO :Combination path signals STR_CONFIG_PATCHES_CYCLE_SIGNAL_TYPES :{LTBLUE}Cycle through signal types: {ORANGE}{STRING1} STR_CONFIG_PATCHES_CYCLE_SIGNAL_NORMAL :Block signals only STR_CONFIG_PATCHES_CYCLE_SIGNAL_PBS :Path signals only @@ -1733,21 +1734,36 @@ STR_RAILROAD_TRACK_WITH_EXITSIGNALS :Railway track w STR_RAILROAD_TRACK_WITH_COMBOSIGNALS :Railway track with combo-signals STR_RAILROAD_TRACK_WITH_PBSSIGNALS :Railway track with path signals STR_RAILROAD_TRACK_WITH_NOENTRYSIGNALS :Railway track with one-way path signals +STR_RAILROAD_TRACK_WITH_ADVANCESIGNALS :Railway track with advance path signals +STR_RAILROAD_TRACK_WITH_ADVANCECOMBOSIGNALS :Railway track with combination path signals STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS :Railway track with block and pre-signals STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS :Railway track with block and exit-signals STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS :Railway track with block and combo-signals STR_RAILROAD_TRACK_WITH_NORMAL_PBSSIGNALS :Railway track with block and path signals STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS :Railway track with block and one-way path signals +STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCESIGNALS :Railway track with block and advance path signals +STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCECOMBOSIGNALS :Railway track with block and combination path signals STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS :Railway track with pre- and exit-signals STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS :Railway track with pre- and combo-signals STR_RAILROAD_TRACK_WITH_PRE_PBSSIGNALS :Railway track with pre- and path signals STR_RAILROAD_TRACK_WITH_PRE_NOENTRYSIGNALS :Railway track with pre- and one-way path signals +STR_RAILROAD_TRACK_WITH_PRE_ADVANCESIGNALS :Railway track with pre- and advance path signals +STR_RAILROAD_TRACK_WITH_PRE_ADVANCECOMBOSIGNALS :Railway track with pre- and combination path signals STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS :Railway track with exit- and combo-signals STR_RAILROAD_TRACK_WITH_EXIT_PBSSIGNALS :Railway track with exit- and path signals STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS :Railway track with exit- and one-way path signals +STR_RAILROAD_TRACK_WITH_EXIT_ADVANCESIGNALS :Railway track with exit- and advance path signals +STR_RAILROAD_TRACK_WITH_EXIT_ADVANCECOMBOSIGNALS :Railway track with exit- and combination path signals STR_RAILROAD_TRACK_WITH_COMBO_PBSSIGNALS :Railway track with combo- and path signals STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS :Railway track with combo- and one-way path signals +STR_RAILROAD_TRACK_WITH_COMBO_ADVANCESIGNALS :Railway track with combo- and advance path signals +STR_RAILROAD_TRACK_WITH_COMBO_ADVANCECOMBOSIGNALS :Railway track with combo- and combination path signals STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS :Railway track with path and one-way path signals +STR_RAILROAD_TRACK_WITH_PBS_ADVANCESIGNALS :Railway track with path and advance path signals +STR_RAILROAD_TRACK_WITH_PBS_ADVANCECOMBOSIGNALS :Railway track with path and combination path signals +STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCESIGNALS :Railway track with one-way and advance path signals +STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCECOMBOSIGNALS :Railway track with one-way and combination path signals +STR_RAILROAD_TRACK_WITH_ADVANCE_ADVANCECOMBOSIGNALS :Railway track with advance and combination path signals STR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must remove railway station first STR_CREATE_SPLITTED_STATION :{YELLOW}Build a separate station STR_SELECT_STATION_TO_JOIN :{BLACK}Join station @@ -3690,12 +3706,16 @@ STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TIP :{BLACK}Exit-Sig STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TIP :{BLACK}Combo-Signal (semaphore){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of presignals. STR_BUILD_SIGNAL_SEMAPHORE_PBS_TIP :{BLACK}Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side. STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TIP :{BLACK}One-way Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side. +STR_BUILD_SIGNAL_SEMAPHORE_PBS_ADVANCE_TIP :{BLACK}Advance Path Signal (semaphore){}An advance path signal triggers the next path signal, if the train cannot reserve a path to a safe stopping point, it will slow down for the next signal. Advance path signals are not safe waiting positions and can be passed from the backside. +STR_BUILD_SIGNAL_SEMAPHORE_PBS_COMBO_TIP :{BLACK}Combination Path Signal (semaphore){}A combination path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Combination path signals are both a normal and an advance path signal, they can be passed from the backside. STR_BUILD_SIGNAL_ELECTRIC_NORM_TIP :{BLACK}Block Signal (electric){}This is the most basic type of signal, allowing only one train to be in the same block at the same time. STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TIP :{BLACK}Entry-Signal (electric){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red. STR_BUILD_SIGNAL_ELECTRIC_EXIT_TIP :{BLACK}Exit-Signal (electric){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals. STR_BUILD_SIGNAL_ELECTRIC_COMBO_TIP :{BLACK}Combo-Signal (electric){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of presignals. STR_BUILD_SIGNAL_ELECTRIC_PBS_TIP :{BLACK}Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side. STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TIP :{BLACK}One-way Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side. +STR_BUILD_SIGNAL_ELECTRIC_PBS_ADVANCE_TIP :{BLACK}Advance Path Signal (electric){}An advance path signal triggers the next path signal, if the train cannot reserve a path to a safe stopping point, it will slow down for the next signal. Advance path signals are not safe waiting positions and can be passed from the backside. +STR_BUILD_SIGNAL_ELECTRIC_PBS_COMBO_TIP :{BLACK}Combination Path Signal (electric){}A combination path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Combination path signals are both a normal and an advance path signal, they can be passed from the backside. STR_SIGNAL_CONVERT_TIP :{BLACK}Signal Convert{}When selected, clicking an existing signal will convert it to the selected signal type and variant, CTRL-click will toggle the existing variant. STR_DRAG_SIGNALS_DENSITY_TIP :{BLACK}Dragging signal density STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP :{BLACK}Decrease dragging signal density diff --git a/src/misc/dbg_helpers.cpp b/src/misc/dbg_helpers.cpp index 305f736..63754cd 100644 --- a/src/misc/dbg_helpers.cpp +++ b/src/misc/dbg_helpers.cpp @@ -45,7 +45,7 @@ CStrA ValueStr(DiagDirection dd) /** SignalType short names. */ static const char *signal_type_names[] = { - "NORMAL", "ENTRY", "EXIT", "COMBO", "PBS", "NOENTRY", + "NORMAL", "ENTRY", "EXIT", "COMBO", "PBS", "NOENTRY", "ADV", "ACOMBO", }; /** Return name of given SignalType. */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index dae87a9..6a47865 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -3527,7 +3527,7 @@ static void GraphicsNew(byte *buf, size_t len) /* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" }, /* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" }, /* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" }, - /* 0x04 */ { A5BLOCK_FIXED, SPR_SIGNALS_BASE, 48, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" }, + /* 0x04 */ { A5BLOCK_FIXED, SPR_SIGNALS_BASE, 48, PRESIGNAL_SEMAPHORE_PBS_YELLOW_SPRITE_COUNT, "Signal graphics" }, /* 0x05 */ { A5BLOCK_FIXED, SPR_ELRAIL_BASE, 48, ELRAIL_SPRITE_COUNT, "Catenary graphics" }, /* 0x06 */ { A5BLOCK_FIXED, SPR_SLOPES_BASE, 74, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" }, /* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD. diff --git a/src/npf.cpp b/src/npf.cpp index 9fbad27..688bf2a 100644 --- a/src/npf.cpp +++ b/src/npf.cpp @@ -402,7 +402,7 @@ static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare } } - if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { + if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && IsStopSignal(tile, TrackdirToTrack(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty; } } diff --git a/src/pbs.cpp b/src/pbs.cpp index 5adccae..345b915 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -345,7 +345,7 @@ bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { /* PBS signal on next trackdir? Safe position. */ - if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) return true; + if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits)) && IsStopSignal(ft.m_new_tile, TrackdirToTrack(FindFirstTrackdir(ft.m_new_td_bits)))) return true; } return false; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 1f94a72..af479d0 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -944,9 +944,10 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 if (IsPbsSignal(sigtype)) { /* PBS signals should show red unless they are on a reservation. */ - uint mask = GetPresentSignals(tile) & SignalOnTrack(track); - SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetTrackReservation(tile), track) ? UINT_MAX : 0) & mask)); + SetSignalStateByTrackdir(tile, TrackToTrackdir(track), HasBit(GetTrackReservation(tile), track) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED); } + if (sigtype == SIGTYPE_PBS_ADVANCE) SetSignalStateByTrackdir(tile, TrackToTrackdir(track), SIGNAL_STATE_YELLOW); + MarkTileDirtyByTile(tile); AddTrackToSignalBuffer(tile, track, _current_company); YapfNotifyTrackLayoutChange(tile, track); @@ -1541,6 +1542,11 @@ static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint i SignalType type = GetSignalType(tile, track); SignalVariant variant = GetSignalVariant(tile, track); + /* Adjust the condition for yellow signals. + * The offset between the red sprite and the corresponding yellow + * sprite is 128, but as condition is at least 2, add only 126. */ + if (condition > 1) condition += 126; + if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) { /* Normal electric signals are picked from original sprites. */ sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition; @@ -1848,7 +1854,7 @@ enum { static void DrawSignals(TileIndex tile, TrackBits rails) { -#define MAYBE_DRAW_SIGNAL(x,y,z,t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z) +#define MAYBE_DRAW_SIGNAL(x,y,z,t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, IsPbsSignal(GetSignalType(tile, t)) ? GetSignalStateByTrackdir(tile, TrackToTrackdir(t)) : GetSingleSignalState(tile, x), y, z) if (!(rails & TRACK_BIT_Y)) { if (!(rails & TRACK_BIT_X)) { @@ -2276,6 +2282,14 @@ static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, byte a = GetPresentSignals(tile); uint b = GetSignalStates(tile); + /* The signal state is stored differently for PBS signals. + * If the state for a track is not red, set all state bits + * for the track causing the signal to be seen as green. + * As PBS signals are always in just one trackdir, this + * causes no problems further down. */ + if (IsPbsSignal(GetSignalType(tile, TRACK_UPPER)) && (b & SignalOnTrack(TRACK_UPPER)) != 0) b |= SignalOnTrack(TRACK_UPPER); + if (IsPbsSignal(GetSignalType(tile, TRACK_LOWER)) && (b & SignalOnTrack(TRACK_LOWER)) != 0) b |= SignalOnTrack(TRACK_LOWER); + b &= a; /* When signals are not present (in neither direction), @@ -2329,14 +2343,16 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) break; case RAIL_TILE_SIGNALS: { - const StringID signal_type[6][6] = { + const StringID signal_type[8][8] = { { STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS, STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS, STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS, STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS, STR_RAILROAD_TRACK_WITH_NORMAL_PBSSIGNALS, - STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCECOMBOSIGNALS }, { STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS, @@ -2344,7 +2360,9 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS, STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS, STR_RAILROAD_TRACK_WITH_PRE_PBSSIGNALS, - STR_RAILROAD_TRACK_WITH_PRE_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_PRE_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_PRE_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_PRE_ADVANCECOMBOSIGNALS }, { STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS, @@ -2352,7 +2370,9 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) STR_RAILROAD_TRACK_WITH_EXITSIGNALS, STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS, STR_RAILROAD_TRACK_WITH_EXIT_PBSSIGNALS, - STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_EXIT_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_EXIT_ADVANCECOMBOSIGNALS }, { STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS, @@ -2360,7 +2380,9 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS, STR_RAILROAD_TRACK_WITH_COMBOSIGNALS, STR_RAILROAD_TRACK_WITH_COMBO_PBSSIGNALS, - STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_COMBO_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_COMBO_ADVANCECOMBOSIGNALS }, { STR_RAILROAD_TRACK_WITH_NORMAL_PBSSIGNALS, @@ -2368,7 +2390,9 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) STR_RAILROAD_TRACK_WITH_EXIT_PBSSIGNALS, STR_RAILROAD_TRACK_WITH_COMBO_PBSSIGNALS, STR_RAILROAD_TRACK_WITH_PBSSIGNALS, - STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_PBS_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_PBS_ADVANCECOMBOSIGNALS }, { STR_RAILROAD_TRACK_WITH_NORMAL_NOENTRYSIGNALS, @@ -2376,7 +2400,29 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td) STR_RAILROAD_TRACK_WITH_EXIT_NOENTRYSIGNALS, STR_RAILROAD_TRACK_WITH_COMBO_NOENTRYSIGNALS, STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNALS, - STR_RAILROAD_TRACK_WITH_NOENTRYSIGNALS + STR_RAILROAD_TRACK_WITH_NOENTRYSIGNALS, + STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCECOMBOSIGNALS + }, + { + STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_PRE_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_EXIT_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_COMBO_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_PBS_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_ADVANCESIGNALS, + STR_RAILROAD_TRACK_WITH_ADVANCE_ADVANCECOMBOSIGNALS + }, + { + STR_RAILROAD_TRACK_WITH_NORMAL_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_PRE_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_EXIT_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_COMBO_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_PBS_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_NOENTRY_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_ADVANCE_ADVANCECOMBOSIGNALS, + STR_RAILROAD_TRACK_WITH_ADVANCECOMBOSIGNALS } }; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 6ebb9fc..9d11968 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -40,7 +40,7 @@ static SignalVariant _cur_signal_variant; ///< set the signal variant (for si static SignalType _cur_signal_type; ///< set the signal type (for signal GUI) /* Map _patches.default_signal_type to the corresponding signal type */ -static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY}; +static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY, SIGTYPE_PBS_COMBO}; struct RailStationGUISettings { Axis orientation; ///< Currently selected rail station orientation @@ -1367,12 +1367,16 @@ enum BuildSignalWidgets { BSW_SEMAPHORE_COMBO, BSW_SEMAPHORE_PBS, BSW_SEMAPHORE_PBS_OWAY, + BSW_SEMAPHORE_PBS_ADVANCE, + BSW_SEMAPHORE_PBS_COMBO, BSW_ELECTRIC_NORM, BSW_ELECTRIC_ENTRY, BSW_ELECTRIC_EXIT, BSW_ELECTRIC_COMBO, BSW_ELECTRIC_PBS, BSW_ELECTRIC_PBS_OWAY, + BSW_ELECTRIC_PBS_ADVANCE, + BSW_ELECTRIC_PBS_COMBO, BSW_CONVERT, BSW_DRAG_SIGNALS_DENSITY, BSW_DRAG_SIGNALS_DENSITY_DECREASE, @@ -1415,18 +1419,22 @@ public: this->DrawWidgets(); /* The 'hardcoded' off sets are needed because they are reused sprites. */ - this->DrawSignalSprite(BSW_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_NORM, 0, 12); // xsize of sprite + 1 == 9 - this->DrawSignalSprite(BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10 - this->DrawSignalSprite(BSW_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, 0, 12); // xsize of sprite + 1 == 9 - this->DrawSignalSprite(BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, 0, 12); // xsize of sprite + 1 == 9 - this->DrawSignalSprite(BSW_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS, 0, 12); // xsize of sprite + 1 == 9 - this->DrawSignalSprite(BSW_SEMAPHORE_PBS_OWAY, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY, -1, 13); // xsize of sprite + 1 == 10 - this->DrawSignalSprite(BSW_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_NORM, -1, 4); - this->DrawSignalSprite(BSW_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, -2, 6); - this->DrawSignalSprite(BSW_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_EXIT, -2, 6); - this->DrawSignalSprite(BSW_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_COMBO, -2, 6); - this->DrawSignalSprite(BSW_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS, -1, 4); - this->DrawSignalSprite(BSW_ELECTRIC_PBS_OWAY,SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY,-2, 6); + this->DrawSignalSprite(BSW_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_NORM, 0, 12); // xsize of sprite + 1 == 9 + this->DrawSignalSprite(BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10 + this->DrawSignalSprite(BSW_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, 0, 12); // xsize of sprite + 1 == 9 + this->DrawSignalSprite(BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, 0, 12); // xsize of sprite + 1 == 9 + this->DrawSignalSprite(BSW_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS, 0, 12); // xsize of sprite + 1 == 9 + this->DrawSignalSprite(BSW_SEMAPHORE_PBS_OWAY, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY, -1, 13); // xsize of sprite + 1 == 10 + this->DrawSignalSprite(BSW_SEMAPHORE_PBS_ADVANCE,SPR_IMG_SIGNAL_SEMAPHORE_PBS_ADVANCE,-1, 13); // xsize of sprite + 1 == 9 + this->DrawSignalSprite(BSW_SEMAPHORE_PBS_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS_COMBO, -1, 13); // xsize of sprite + 1 == 10 + this->DrawSignalSprite(BSW_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_NORM, -1, 4); + this->DrawSignalSprite(BSW_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, -2, 6); + this->DrawSignalSprite(BSW_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_EXIT, -2, 6); + this->DrawSignalSprite(BSW_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_COMBO, -2, 6); + this->DrawSignalSprite(BSW_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS, -1, 4); + this->DrawSignalSprite(BSW_ELECTRIC_PBS_OWAY, SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY,-2, 6); + this->DrawSignalSprite(BSW_ELECTRIC_PBS_ADVANCE, SPR_IMG_SIGNAL_ELECTRIC_PBS_ADVANCE, -2, 6); + this->DrawSignalSprite(BSW_ELECTRIC_PBS_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS_COMBO, -2, 6); /* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */ SetDParam(0, _settings_client.gui.drag_signals_density); @@ -1444,12 +1452,16 @@ public: case BSW_SEMAPHORE_COMBO: case BSW_SEMAPHORE_PBS: case BSW_SEMAPHORE_PBS_OWAY: + case BSW_SEMAPHORE_PBS_ADVANCE: + case BSW_SEMAPHORE_PBS_COMBO: case BSW_ELECTRIC_NORM: case BSW_ELECTRIC_ENTRY: case BSW_ELECTRIC_EXIT: case BSW_ELECTRIC_COMBO: case BSW_ELECTRIC_PBS: case BSW_ELECTRIC_PBS_OWAY: + case BSW_ELECTRIC_PBS_ADVANCE: + case BSW_ELECTRIC_PBS_COMBO: this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type); _cur_signal_type = (SignalType)((uint)((widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1))); @@ -1484,7 +1496,7 @@ public: /** Widget definition of the build signal window */ static const Widget _signal_builder_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BSW_CLOSEBOX -{ WWT_CAPTION, RESIZE_NONE, COLOUR_DARK_GREEN, 11, 153, 0, 13, STR_SIGNAL_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BSW_CAPTION +{ WWT_CAPTION, RESIZE_NONE, COLOUR_DARK_GREEN, 11, 197, 0, 13, STR_SIGNAL_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BSW_CAPTION { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 21, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TIP}, // BSW_SEMAPHORE_NORM { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 22, 43, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TIP}, // BSW_SEMAPHORE_ENTRY @@ -1492,6 +1504,8 @@ static const Widget _signal_builder_widgets[] = { { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 66, 87, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TIP}, // BSW_SEMAPHORE_COMBO { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 88, 109, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TIP}, // BSW_SEMAPHORE_PBS { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 110, 131, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TIP},// BSW_SEMAPHORE_PBS_OWAY +{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 132, 153, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_ADVANCE_TIP},// BSW_SEMAPHORE_PBS_ADVANCE +{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 154, 175, 14, 40, STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_COMBO_TIP}, // BSW_SEMAPHORE_PBS_COMBO { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 21, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TIP}, // BSW_ELECTRIC_NORM { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 22, 43, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TIP}, // BSW_ELECTRIC_ENTRY @@ -1499,18 +1513,20 @@ static const Widget _signal_builder_widgets[] = { { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 66, 87, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TIP}, // BSW_ELECTRIC_COMBO { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 88, 109, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TIP}, // BSW_ELECTRIC_PBS { WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 110, 131, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TIP},// BSW_ELECTRIC_PBS_OWAY +{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 132, 153, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_ADVANCE_TIP}, // BSW_ELECTRIC_PBS_ADVANCE +{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 154, 175, 41, 67, STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_COMBO_TIP}, // BSW_ELECTRIC_PBS_COMBO -{ WWT_IMGBTN, RESIZE_NONE, COLOUR_DARK_GREEN, 132, 153, 14, 40, SPR_IMG_SIGNAL_CONVERT, STR_SIGNAL_CONVERT_TIP}, // BSW_CONVERT -{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 132, 153, 41, 67, STR_NULL, STR_DRAG_SIGNALS_DENSITY_TIP}, // BSW_DRAG_SIGNALS_DENSITY -{ WWT_PUSHIMGBTN, RESIZE_NONE, COLOUR_GREY, 134, 142, 54, 65, SPR_ARROW_LEFT, STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_DECREASE -{ WWT_PUSHIMGBTN, RESIZE_NONE, COLOUR_GREY, 143, 151, 54, 65, SPR_ARROW_RIGHT, STR_DRAG_SIGNALS_DENSITY_INCREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_INCREASE +{ WWT_IMGBTN, RESIZE_NONE, COLOUR_DARK_GREEN, 176, 197, 14, 40, SPR_IMG_SIGNAL_CONVERT, STR_SIGNAL_CONVERT_TIP}, // BSW_CONVERT +{ WWT_PANEL, RESIZE_NONE, COLOUR_DARK_GREEN, 176, 197, 41, 67, STR_NULL, STR_DRAG_SIGNALS_DENSITY_TIP}, // BSW_DRAG_SIGNALS_DENSITY +{ WWT_PUSHIMGBTN, RESIZE_NONE, COLOUR_GREY, 178, 186, 54, 65, SPR_ARROW_LEFT, STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_DECREASE +{ WWT_PUSHIMGBTN, RESIZE_NONE, COLOUR_GREY, 187, 195, 54, 65, SPR_ARROW_RIGHT, STR_DRAG_SIGNALS_DENSITY_INCREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_INCREASE { WIDGETS_END}, }; /** Signal selection window description */ static const WindowDesc _signal_builder_desc = { - WDP_AUTO, WDP_AUTO, 154, 68, 154, 68, + WDP_AUTO, WDP_AUTO, 198, 68, 198, 68, WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION, _signal_builder_widgets, diff --git a/src/rail_map.h b/src/rail_map.h index a6077cf..8942a41 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -349,7 +349,7 @@ static inline TrackBits GetRailDepotReservation(TileIndex t) static inline bool IsPbsSignal(SignalType s) { - return s == SIGTYPE_PBS || s == SIGTYPE_PBS_ONEWAY; + return s > SIGTYPE_LAST_NOPBS; } static inline SignalType GetSignalType(TileIndex t, Track track) @@ -380,7 +380,17 @@ static inline bool IsPresignalExit(TileIndex t, Track track) /** One-way signals can't be passed the 'wrong' way. */ static inline bool IsOnewaySignal(TileIndex t, Track track) { - return GetSignalType(t, track) != SIGTYPE_PBS; + return !IsPbsSignal(GetSignalType(t, track)) || GetSignalType(t, track) == SIGTYPE_PBS_ONEWAY; +} + +static inline bool IsAdvanceSignal(TileIndex t, Track track) +{ + return GetSignalType(t, track) == SIGTYPE_PBS_ADVANCE || GetSignalType(t, track) == SIGTYPE_PBS_COMBO; +} + +static inline bool IsStopSignal(TileIndex t, Track track) +{ + return GetSignalType(t, track) != SIGTYPE_PBS_ADVANCE; } static inline void CycleSignalSide(TileIndex t, Track track) @@ -406,13 +416,11 @@ static inline void SetSignalVariant(TileIndex t, Track track, SignalVariant v) if (track == INVALID_TRACK) SB(_m[t].m2, 7, 1, v); } -/** These are states in which a signal can be. Currently these are only two, so - * simple boolean logic will do. But do try to compare to this enum instead of - * normal boolean evaluation, since that will make future additions easier. - */ +/** These are states in which a signal can be. */ enum SignalState { - SIGNAL_STATE_RED = 0, ///< The signal is red - SIGNAL_STATE_GREEN = 1, ///< The signal is green + SIGNAL_STATE_RED = 0, ///< The signal is red + SIGNAL_STATE_GREEN = 1, ///< The signal is green + SIGNAL_STATE_YELLOW = 2, ///< The signal is yellow }; /** @@ -514,8 +522,13 @@ static inline SignalState GetSignalStateByTrackdir(TileIndex tile, Trackdir trac { assert(IsValidTrackdir(trackdir)); assert(HasSignalOnTrack(tile, TrackdirToTrack(trackdir))); - return GetSignalStates(tile) & SignalAlongTrackdir(trackdir) ? - SIGNAL_STATE_GREEN : SIGNAL_STATE_RED; + Track track = TrackdirToTrack(trackdir); + if (IsPbsSignal(GetSignalType(tile, track))) { + return (SignalState)((GetSignalStates(tile) & SignalOnTrack(track)) >> SignalBitPosOnTrack(track)); + } else { + return GetSignalStates(tile) & SignalAlongTrackdir(trackdir) ? + SIGNAL_STATE_GREEN : SIGNAL_STATE_RED; + } } /** @@ -523,10 +536,15 @@ static inline SignalState GetSignalStateByTrackdir(TileIndex tile, Trackdir trac */ static inline void SetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir, SignalState state) { - if (state == SIGNAL_STATE_GREEN) { // set 1 - SetSignalStates(tile, GetSignalStates(tile) | SignalAlongTrackdir(trackdir)); + Track track = TrackdirToTrack(trackdir); + if (IsPbsSignal(GetSignalType(tile, track))) { + SetSignalStates(tile, (GetSignalStates(tile) & ~SignalOnTrack(track)) | (state << SignalBitPosOnTrack(track))); } else { - SetSignalStates(tile, GetSignalStates(tile) & ~SignalAlongTrackdir(trackdir)); + if (state == SIGNAL_STATE_GREEN) { // set 1 + SetSignalStates(tile, GetSignalStates(tile) | SignalAlongTrackdir(trackdir)); + } else { + SetSignalStates(tile, GetSignalStates(tile) & ~SignalAlongTrackdir(trackdir)); + } } } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index f34d5fd..c6c536c 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -1722,6 +1722,23 @@ bool AfterLoadGame() } } + if (CheckSavegameVersion(114)) { + /* Storage of signal state was changed for PBS signals. */ + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_RAILWAY)) { + if (HasSignalOnTrack(t, TRACK_UPPER) && IsPbsSignal(GetSignalType(t, TRACK_UPPER))) { + /* As a PBS signal can only be on one of the two trackdirs, + * we don't need to find out on which trackdir the signal + * really is. */ + SetSignalStateByTrackdir(t, TRACKDIR_UPPER_E, GetSignalStates(t) & GetPresentSignals(t) & SignalOnTrack(TRACK_UPPER) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED); + } + if (HasSignalOnTrack(t, TRACK_LOWER) && IsPbsSignal(GetSignalType(t, TRACK_LOWER))) { + SetSignalStateByTrackdir(t, TRACKDIR_LOWER_E, GetSignalStates(t) & GetPresentSignals(t) & SignalOnTrack(TRACK_LOWER) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED); + } + } + } + } + GamelogPrintDebug(1); bool ret = InitializeWindowsAndCaches(); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2044eb9..9c36580 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -38,7 +38,7 @@ #include "saveload_internal.h" -extern const uint16 SAVEGAME_VERSION = 113; +extern const uint16 SAVEGAME_VERSION = 114; SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/settings.cpp b/src/settings.cpp index d2e1496..ff66e69 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1505,7 +1505,7 @@ const SettingDesc _patch_settings[] = { SDTC_VAR(gui.news_message_timeout, SLE_UINT8, S, 0, 2, 1, 255, 0, STR_NULL, NULL), SDTC_BOOL(gui.show_track_reservation, S, 0, false, STR_CONFIG_PATCHES_SHOW_TRACK_RESERVATION, RedrawScreen), SDTC_VAR(gui.default_signal_type, SLE_UINT8, S, MS, 0, 0, 2, 1, STR_CONFIG_PATCHES_DEFAULT_SIGNAL_TYPE, NULL), - SDTC_VAR(gui.cycle_signal_types, SLE_UINT8, S, MS, 0, 0, 2, 1, STR_CONFIG_PATCHES_CYCLE_SIGNAL_TYPES, NULL), + SDTC_VAR(gui.cycle_signal_types, SLE_UINT8, S, MS, 0, 0, 3, 1, STR_CONFIG_PATCHES_CYCLE_SIGNAL_TYPES, NULL), SDTC_VAR(gui.station_numtracks, SLE_UINT8, S, 0, 1, 1, 7, 0, STR_NULL, NULL), SDTC_VAR(gui.station_platlength, SLE_UINT8, S, 0, 5, 1, 7, 0, STR_NULL, NULL), SDTC_BOOL(gui.station_dragdrop, S, 0, true, STR_NULL, NULL), diff --git a/src/signal.cpp b/src/signal.cpp index 8269923..cf8d69d 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -336,7 +336,8 @@ static SigFlags ExploreSegment(Owner owner) } } - continue; + /* Don't stop block segment processing on advance signals. */ + if (sig != SIGTYPE_PBS_ADVANCE) continue; } } diff --git a/src/signal_func.h b/src/signal_func.h index af2bf11..4f22fb0 100644 --- a/src/signal_func.h +++ b/src/signal_func.h @@ -9,6 +9,7 @@ #include "tile_type.h" #include "direction_type.h" #include "company_type.h" +#include "core/bitmath_func.hpp" /** * Maps a trackdir to the bit that stores its status in the map arrays, in the @@ -40,6 +41,15 @@ static inline byte SignalOnTrack(Track track) return _signal_on_track[track]; } +/** + * Maps a track to the starting bit number where the signal state + * for the signals on the track is stored. + */ +static inline byte SignalBitPosOnTrack(Track track) +{ + return FIND_FIRST_BIT(SignalOnTrack(track)); +} + /** State of the signal segment */ enum SigSegState { SIGSEG_FREE, ///< Free and has no pre-signal exits or at least one green exit diff --git a/src/signal_type.h b/src/signal_type.h index 0bcd107..2a17e12 100644 --- a/src/signal_type.h +++ b/src/signal_type.h @@ -20,7 +20,9 @@ enum SignalType { SIGTYPE_COMBO = 3, ///< presignal inter-block SIGTYPE_PBS = 4, ///< normal pbs signal SIGTYPE_PBS_ONEWAY = 5, ///< no-entry signal - SIGTYPE_LAST = SIGTYPE_PBS_ONEWAY, + SIGTYPE_PBS_ADVANCE= 6, ///< advance signal + SIGTYPE_PBS_COMBO = 7, ///< combination signal + SIGTYPE_LAST = SIGTYPE_PBS_COMBO, SIGTYPE_LAST_NOPBS = SIGTYPE_COMBO }; diff --git a/src/table/sprites.h b/src/table/sprites.h index 709e60d..f7d09b8 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -131,8 +131,9 @@ enum Sprites { PRESIGNAL_SPRITE_COUNT = 48, PRESIGNAL_AND_SEMAPHORE_SPRITE_COUNT = 112, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT = 240, + PRESIGNAL_SEMAPHORE_PBS_YELLOW_SPRITE_COUNT = 368, - SPR_CANALS_BASE = SPR_SIGNALS_BASE + PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, + SPR_CANALS_BASE = SPR_SIGNALS_BASE + PRESIGNAL_SEMAPHORE_PBS_YELLOW_SPRITE_COUNT, CANALS_SPRITE_COUNT = 65, /* Sprites for the Aqueduct. */ @@ -1253,19 +1254,23 @@ enum Sprites { SPR_IMG_RAIL_STATION = 1298, SPR_IMG_RAIL_SIGNALS = 1291, - SPR_IMG_SIGNAL_ELECTRIC_NORM = 1287, - SPR_IMG_SIGNAL_ELECTRIC_ENTRY = SPR_SIGNALS_BASE + 12, - SPR_IMG_SIGNAL_ELECTRIC_EXIT = SPR_SIGNALS_BASE + 28, - SPR_IMG_SIGNAL_ELECTRIC_COMBO = SPR_SIGNALS_BASE + 44, - SPR_IMG_SIGNAL_ELECTRIC_PBS = SPR_SIGNALS_BASE + 124, - SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY = SPR_SIGNALS_BASE + 140, - SPR_IMG_SIGNAL_SEMAPHORE_NORM = SPR_SIGNALS_BASE + 60, - SPR_IMG_SIGNAL_SEMAPHORE_ENTRY = SPR_SIGNALS_BASE + 76, - SPR_IMG_SIGNAL_SEMAPHORE_EXIT = SPR_SIGNALS_BASE + 92, - SPR_IMG_SIGNAL_SEMAPHORE_COMBO = SPR_SIGNALS_BASE + 108, - SPR_IMG_SIGNAL_SEMAPHORE_PBS = SPR_SIGNALS_BASE + 188, - SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY= SPR_SIGNALS_BASE + 204, - SPR_IMG_SIGNAL_CONVERT = SPR_OPENTTD_BASE + 135, + SPR_IMG_SIGNAL_ELECTRIC_NORM = 1287, + SPR_IMG_SIGNAL_ELECTRIC_ENTRY = SPR_SIGNALS_BASE + 12, + SPR_IMG_SIGNAL_ELECTRIC_EXIT = SPR_SIGNALS_BASE + 28, + SPR_IMG_SIGNAL_ELECTRIC_COMBO = SPR_SIGNALS_BASE + 44, + SPR_IMG_SIGNAL_ELECTRIC_PBS = SPR_SIGNALS_BASE + 124, + SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY = SPR_SIGNALS_BASE + 140, + SPR_IMG_SIGNAL_ELECTRIC_PBS_ADVANCE = SPR_SIGNALS_BASE + 156, + SPR_IMG_SIGNAL_ELECTRIC_PBS_COMBO = SPR_SIGNALS_BASE + 172, + SPR_IMG_SIGNAL_SEMAPHORE_NORM = SPR_SIGNALS_BASE + 60, + SPR_IMG_SIGNAL_SEMAPHORE_ENTRY = SPR_SIGNALS_BASE + 76, + SPR_IMG_SIGNAL_SEMAPHORE_EXIT = SPR_SIGNALS_BASE + 92, + SPR_IMG_SIGNAL_SEMAPHORE_COMBO = SPR_SIGNALS_BASE + 108, + SPR_IMG_SIGNAL_SEMAPHORE_PBS = SPR_SIGNALS_BASE + 188, + SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY = SPR_SIGNALS_BASE + 204, + SPR_IMG_SIGNAL_SEMAPHORE_PBS_ADVANCE= SPR_SIGNALS_BASE + 220, + SPR_IMG_SIGNAL_SEMAPHORE_PBS_COMBO = SPR_SIGNALS_BASE + 236, + SPR_IMG_SIGNAL_CONVERT = SPR_OPENTTD_BASE + 135, SPR_IMG_TUNNEL_RAIL = 2430, SPR_IMG_TUNNEL_MONO = 2431, diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 0d1b69d..2857a63 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -38,6 +38,7 @@ #include "table/train_cmd.h" static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck); +static bool DoPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay, bool always_extend); static bool TrainCheckIfLineEnds(Vehicle *v); static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image); static TileIndex TrainApproachingCrossingTile(const Vehicle *v); @@ -2325,10 +2326,12 @@ static void CheckNextTrainTile(Vehicle *v) CFollowTrackRail ft(v); if (!ft.Follow(v->tile, td)) return; - if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { - /* Next tile is not reserved. */ - if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { - if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { + if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { + /* Tile is not a choice tile and can have signals. */ + Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); + if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, td)) { + if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits)) && + IsPbsSignal(GetSignalType(ft.m_new_tile, TrackdirToTrack(td)))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) { @@ -2336,6 +2339,13 @@ static void CheckNextTrainTile(Vehicle *v) } ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false); } + if (GetSignalStateByTrackdir(ft.m_new_tile, td) == SIGNAL_STATE_YELLOW) { + /* A yellow advance or combo signal is on the next tile, try to extend the path. */ + if (DoPathReserve(v, false, false, true)) { + SetSignalStateByTrackdir(ft.m_new_tile, td, SIGNAL_STATE_GREEN); + MarkTileDirtyByTile(ft.m_new_tile); + } + } } } } @@ -2474,7 +2484,7 @@ void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin, Trackdir orig break; } else { /* Turn the signal back to red. */ - SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED); + SetSignalStateByTrackdir(tile, td, GetSignalType(tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ADVANCE ? SIGNAL_STATE_YELLOW : SIGNAL_STATE_RED); MarkTileDirtyByTile(tile); } } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) { @@ -2667,10 +2677,9 @@ static Track DoTrainPathfind(Vehicle *v, TileIndex tile, DiagDirection enterdir, * another reservation or a track choice. * @return INVALID_TILE indicates that the reservation failed. */ -static PBSTileInfo ExtendTrainReservation(const Vehicle *v, TrackBits *new_tracks, DiagDirection *enterdir) +static PBSTileInfo ExtendTrainReservation(const Vehicle *v, const PBSTileInfo &origin, TrackBits *new_tracks, DiagDirection *enterdir) { bool no_90deg_turns = _settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg; - PBSTileInfo origin = FollowTrainReservation(v); CFollowTrackRail ft(v); @@ -2871,13 +2880,14 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) { do_track_reservation = true; changed_signal = true; - SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), SIGNAL_STATE_GREEN); + SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), IsAdvanceSignal(tile, track) ? SIGNAL_STATE_YELLOW : SIGNAL_STATE_GREEN); } else if (!do_track_reservation) { return track; } best_track = track; } + PBSTileInfo origin = FollowTrainReservation(v); PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); DiagDirection dest_enterdir = enterdir; if (do_track_reservation) { @@ -2887,7 +2897,7 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir CheckIfTrainNeedsService(v); if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v); - res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir); + res_dest = ExtendTrainReservation(v, origin, &tracks, &dest_enterdir); if (res_dest.tile == INVALID_TILE) { /* Reservation failed? */ if (mark_stuck) MarkTrainAsStuck(v); @@ -2955,22 +2965,22 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir /* A path was found, but could not be reserved. */ if (res_dest.tile != INVALID_TILE && !res_dest.okay) { if (mark_stuck) MarkTrainAsStuck(v); - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); return best_track; } /* No possible reservation target found, we are probably lost. */ if (res_dest.tile == INVALID_TILE) { /* Try to find any safe destination. */ - PBSTileInfo origin = FollowTrainReservation(v); - if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) { + PBSTileInfo path_end = FollowTrainReservation(v); + if (TryReserveSafeTrack(v, path_end.tile, path_end.trackdir, false)) { TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir); best_track = FindFirstTrack(res); TryReserveRailTrack(v->tile, TrackdirToTrack(GetVehicleTrackdir(v))); if (got_reservation != NULL) *got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); } else { - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); } return best_track; @@ -2996,7 +3006,7 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir res_dest = cur_dest; if (res_dest.okay) continue; /* Path found, but could not be reserved. */ - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); if (got_reservation != NULL) *got_reservation = false; changed_signal = false; @@ -3005,7 +3015,7 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir } /* No order or no safe position found, try any position. */ if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) { - FreeTrainTrackReservation(v); + FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); if (got_reservation != NULL) *got_reservation = false; changed_signal = false; @@ -3021,49 +3031,20 @@ static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir } /** - * Try to reserve a path to a safe position. + * Reserve a path to a safe position. * * @param v The vehicle * @param mark_as_stuck Should the train be marked as stuck on a failed reservation? * @param first_tile_okay True if no path should be reserved if the current tile is a safe position. + * @param always_extend Extend the path even if it already ends at a safe position. * @return True if a path could be reserved. */ -bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) +static bool DoPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay, bool always_extend) { - assert(v->type == VEH_TRAIN && IsFrontEngine(v)); - - /* We have to handle depots specially as the track follower won't look - * at the depot tile itself but starts from the next tile. If we are still - * inside the depot, a depot reservation can never be ours. */ - if (v->u.rail.track & TRACK_BIT_DEPOT) { - if (GetDepotWaypointReservation(v->tile)) { - if (mark_as_stuck) MarkTrainAsStuck(v); - return false; - } else { - /* Depot not reserved, but the next tile might be. */ - TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile)); - if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false; - } - } - - /* Special check if we are in front of a two-sided conventional signal. */ - DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); - TileIndex next_tile = TileAddByDiagDir(v->tile, dir); - if (IsTileType(next_tile, MP_RAILWAY) && HasReservedTracks(next_tile, DiagdirReachesTracks(dir))) { - /* Can have only one reserved trackdir. */ - Trackdir td = FindFirstTrackdir(TrackBitsToTrackdirBits(GetReservedTrackbits(next_tile)) & DiagdirReachesTrackdirs(dir)); - if (HasSignalOnTrackdir(next_tile, td) && HasSignalOnTrackdir(next_tile, ReverseTrackdir(td)) && - !IsPbsSignal(GetSignalType(next_tile, TrackdirToTrack(td)))) { - /* Signal already reserved, is not ours. */ - if (mark_as_stuck) MarkTrainAsStuck(v); - return false; - } - } - bool other_train = false; PBSTileInfo origin = FollowTrainReservation(v, &other_train); /* If we have a reserved path and the path ends at a safe tile, we are finished already. */ - if (origin.okay && (v->tile != origin.tile || first_tile_okay)) { + if (!always_extend && origin.okay && (v->tile != origin.tile || first_tile_okay)) { /* Can't be stuck then. */ if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); @@ -3079,7 +3060,7 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) } /* If we are in a depot, tentativly reserve the depot. */ - if (v->u.rail.track & TRACK_BIT_DEPOT) { + if (v->u.rail.track & TRACK_BIT_DEPOT && v->tile == origin.tile) { SetDepotWaypointReservation(v->tile, true); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile); } @@ -3095,18 +3076,61 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) if (!res_made) { /* Free the depot reservation as well. */ - if (v->u.rail.track & TRACK_BIT_DEPOT) SetDepotWaypointReservation(v->tile, false); + if (v->u.rail.track & TRACK_BIT_DEPOT && v->tile == origin.tile) SetDepotWaypointReservation(v->tile, false); return false; } if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) { v->load_unload_time_rem = 0; InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); + ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); } - ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); return true; } +/** + * Try to reserve a path to a safe position. + * + * @param v The vehicle + * @param mark_as_stuck Should the train be marked as stuck on a failed reservation? + * @param first_tile_okay True if no path should be reserved if the current tile is a safe position. + * @return True if a path could be reserved. + */ +bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay) +{ + assert(v->type == VEH_TRAIN && IsFrontEngine(v)); + + /* We have to handle depots specially as the track follower won't look + * at the depot tile itself but starts from the next tile. If we are still + * inside the depot, a depot reservation can never be ours. */ + if (v->u.rail.track & TRACK_BIT_DEPOT) { + if (GetDepotWaypointReservation(v->tile)) { + if (mark_as_stuck) MarkTrainAsStuck(v); + return false; + } else { + /* Depot not reserved, but the next tile might be. */ + TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile)); + if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false; + } + } + + /* Special check if we are in front of a two-sided conventional signal. */ + DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); + TileIndex next_tile = TileAddByDiagDir(v->tile, dir); + if (IsTileType(next_tile, MP_RAILWAY) && HasReservedTracks(next_tile, DiagdirReachesTracks(dir))) { + /* Can have only one reserved trackdir. */ + Trackdir td = FindFirstTrackdir(TrackBitsToTrackdirBits(GetReservedTrackbits(next_tile)) & DiagdirReachesTrackdirs(dir)); + if (HasSignalOnTrackdir(next_tile, td) && HasSignalOnTrackdir(next_tile, ReverseTrackdir(td)) && + !IsPbsSignal(GetSignalType(next_tile, TrackdirToTrack(td)))) { + /* Signal already reserved, is not ours. */ + if (mark_as_stuck) MarkTrainAsStuck(v); + return false; + } + } + + return DoPathReserve(v, mark_as_stuck, first_tile_okay, false); +} + static bool CheckReverseTrain(Vehicle *v) { @@ -3676,11 +3700,12 @@ 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 */ - chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true)); + Track new_track = ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true); + chosen_track = TrackToTrackBits(new_track); assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile))); /* Check if it's a red signal and that force proceed is not clicked. */ - if (red_signals & chosen_track && v->u.rail.force_proceed == 0) { + if (red_signals & chosen_track && IsStopSignal(gp.new_tile, new_track) && v->u.rail.force_proceed == 0) { /* In front of a red signal */ Trackdir i = FindFirstTrackdir(trackdirbits); @@ -3751,7 +3776,7 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) Track track = FindFirstTrack(chosen_track); Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir); if (IsFrontEngine(v) && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) { - SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED); + SetSignalStateByTrackdir(gp.new_tile, tdir, GetSignalType(gp.new_tile, track) == SIGTYPE_PBS_ADVANCE ? SIGNAL_STATE_YELLOW : SIGNAL_STATE_RED); MarkTileDirtyByTile(gp.new_tile); } @@ -4198,7 +4223,7 @@ static bool TrainCheckIfLineEnds(Vehicle *v) } /* approaching red signal */ - if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true); + if ((trackdirbits & red_signals) != 0 && IsStopSignal(tile, FindFirstTrack(bits))) return TrainApproachingLineEnd(v, true); /* approaching a rail/road crossing? then make it red */ if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); @@ -4288,6 +4313,9 @@ static void TrainLocoHandler(Vehicle *v, bool mode) ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); v->load_unload_time_rem = 0; InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); + } else { + /* Reservation successfull, do look ahead in case the signal in front is an advance signal. */ + CheckNextTrainTile(v); } } diff --git a/src/yapf/yapf_costrail.hpp b/src/yapf/yapf_costrail.hpp index e7e301d..f1949f8 100644 --- a/src/yapf/yapf_costrail.hpp +++ b/src/yapf/yapf_costrail.hpp @@ -224,7 +224,7 @@ public: n.m_segment->m_last_signal_td = trackdir; } - if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) { + if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir))) && IsStopSignal(tile, TrackdirToTrack(trackdir))) { cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0; } } @@ -453,7 +453,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* Gather the next tile/trackdir/tile_type/rail_type. */ TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit2x64(tf_local.m_new_td_bits)); - if (TrackFollower::DoTrackMasking() && HasPbsSignalOnTrackdir(next.tile, next.td)) { + if (TrackFollower::DoTrackMasking() && HasPbsSignalOnTrackdir(next.tile, next.td) && IsStopSignal(next.tile, TrackdirToTrack(next.td))) { /* Possible safe tile. */ end_segment_reason |= ESRB_SAFE_TILE; }