Add new signal type: no-entry signal

This is only passable in one direction, but does not have a signal
or show an aspect in the opposite direction

Add a setting for whether this is shown in the signal UI.
Off by default.
pull/306/head
Jonathan G Rennison 3 years ago
parent b3aa59c85d
commit 5d351a14d2

@ -42,6 +42,13 @@
Programmable pre-signals have a signal type (<span class="code">getbits(extra_callback_info2, 16, 8)</span>) of 6.
</td>
</tr>
<tr><td>enable_no_entry_signals</td><td>0 or 1</td>
<td>
Enable no-entry signal graphics in <a href="https://newgrf-specs.tt-wiki.net/wiki/NML:Railtypes#signals">railtype signals</a>.<br />
No-entry signals have a signal type (<span class="code">getbits(extra_callback_info2, 16, 8)</span>) of 7.<br />
No-entry signals always have a signal state of red.
</td>
</tr>
<tr><td>enable_restricted_signals</td><td>0 or 1</td>
<td>
Enable restricted signal flag in <a href="https://newgrf-specs.tt-wiki.net/wiki/NML:Railtypes#signals">railtype signals</a>.<br />
@ -132,6 +139,18 @@
</table>
</td>
</tr>
<tr><td>NO_ENTRY_SIGNAL</td><td>16</td>
<td>
<b>No-entry signals</b>
<p>No-entry signal graphics come in groups of 8. These groups contain sprites in the same order as the red sprites of 1275-1290 in trg1[r].grf and <a href="https://newgrf-specs.tt-wiki.net/wiki/Action5#04_Signal_graphics.">Action 5 type 4 (signals)</a>;
red only, for each of: SW-facing, NE-facing, NW-facing, SE-facing, E-facing, W-facing, S-facing, N-facing.
<table>
<tr><th>Group</th><th>Contents</th></tr>
<tr><td>0</td><td>Semaphore no-entry signals</td></tr>
<tr><td>1</td><td>Lighted no-entry signals</td></tr>
</table>
</td>
</tr>
</table>
<h3>Signal graphics using switches</h3>
<p>
@ -159,6 +178,13 @@
Programmable pre-signals have a signal type (<span class="code">getbits(extra_callback_info2, 16, 8)</span>) of 6.
</td>
</tr>
<tr><td>enable_no_entry_signals</td><td>0 or 1</td>
<td>
Enable no-entry signal graphics.<br />
No-entry signals have a signal type (<span class="code">getbits(extra_callback_info2, 16, 8)</span>) of 7.<br />
No-entry signals always have a signal state of red.
</td>
</tr>
<tr><td>enable_restricted_signals</td><td>0 or 1</td>
<td>
Enable restricted signal flag.<br />

@ -223,6 +223,12 @@
The property length is 1 byte. 0 is disabled (default). 1 is enabled.
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_railtype_programmable_signals</font>, version 1</p>
<h4 id="railtype_enable_no_entry_signals">Enable custom signal sprites for no-entry signals (mappable property: railtype_enable_no_entry_signals)</h4>
<p>This enables <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Railtypes#Signal_sprites_.280B.29">Action 2/3 - Railtype custom signal sprites</a> for no-entry signals.<br />
No-entry signals have the signal type value: 07.<br />
The property length is 1 byte. 0 is disabled (default). 1 is enabled.
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_railtype_no_entry_signals</font>, version 1</p>
<h4 id="railtype_enable_restricted_signals">Enable restricted signal flag for custom signal sprites (mappable property: railtype_enable_restricted_signals)</h4>
<p>This applies to <a href="https://newgrf-specs.tt-wiki.net/wiki/Action3/Railtypes#Signal_sprites_.280B.29">Action 2/3 - Railtype custom signal sprites</a>.<br />
When enabled, bit 24 of variable 18 (extra callback info) is set if the signal is restricted (has a routing restriction program attached).<br />
@ -314,6 +320,12 @@
The Action 0 Id field is not used, the value is ignored.
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_signals_programmable_signals</font>, version 1</p>
<h4 id="signals_enable_no_entry_signals">Enable custom signal sprites for no-entry signals (mappable property: signals_enable_no_entry_signals)</h4>
<p>This enables <a href="#a3signals_custom_signal_sprites">Action 2/3 Signals (Feature 0E) custom signal sprites</a> for no-entry signals for this GRF.<br />
No-entry signals have the signal type value: 07.<br />
The property length is 1 byte. 0 is disabled (default). 1 is enabled.
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_signals_no_entry_signals</font>, version 1</p>
<h4 id="signals_enable_restricted_signals">Enable restricted signal flag for custom signal sprites (mappable property: signals_enable_restricted_signals)</h4>
<p>This applies to <a href="#a3signals_custom_signal_sprites">Action 2/3 Signals (Feature 0E) custom signal sprites</a> for this GRF.<br />
When enabled, bit 24 of variable 18 (extra callback info) is set if the signal is restricted (has a routing restriction program attached).<br />
@ -418,5 +430,15 @@
</table>
</p>
<p>This is indicated by the feature name: <font face="monospace">action5_programmable_signals</font>, version 1</p>
<h4 id="no_entry_signals">No-entry signal graphics (mappable type: no_entry_signals)</h4>
<p>No-entry signal graphics come in groups of 8. These groups contain sprites in the same order as the red sprites of 1275-1290 in trg1[r].grf and <a href="https://newgrf-specs.tt-wiki.net/wiki/Action5#04_Signal_graphics.">Action 5 type 4 (signals)</a>;
red only, for each of: SW-facing, NE-facing, NW-facing, SE-facing, E-facing, W-facing, S-facing, N-facing.
<table>
<tr><th>Group</th><th>Contents</th></tr>
<tr><td>0</td><td>Semaphore no-entry signals</td></tr>
<tr><td>1</td><td>Lighted no-entry signals</td></tr>
</table>
</p>
<p>This is indicated by the feature name: <font face="monospace">action5_no_entry_signals</font>, version 1</p>
</body>
</html>

@ -19,6 +19,7 @@ set(BASESET_OTHER_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf
${CMAKE_CURRENT_SOURCE_DIR}/innerhighlight.grf
${CMAKE_CURRENT_SOURCE_DIR}/progsignals.grf
${CMAKE_CURRENT_SOURCE_DIR}/extra_signals.grf
${CMAKE_CURRENT_SOURCE_DIR}/route_step.grf
${CMAKE_CURRENT_SOURCE_DIR}/tracerestrict.grf
)

Binary file not shown.

@ -0,0 +1,23 @@
// Automatically generated by GRFCODEC. Do not modify!
// (Info version 32)
// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>>
// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C
// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D%
// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags
0 sprites/extra_signals.png 8bpp 40 40 20 30 -9 -28 normal
1 sprites/extra_signals.png 8bpp 10 40 20 30 -9 -28 normal
2 sprites/extra_signals.png 8bpp 100 40 20 30 -9 -28 normal
3 sprites/extra_signals.png 8bpp 70 40 20 30 -9 -28 normal
4 sprites/extra_signals.png 8bpp 160 40 20 30 -9 -28 normal
5 sprites/extra_signals.png 8bpp 130 40 20 30 -9 -28 normal
6 sprites/extra_signals.png 8bpp 220 40 20 30 -9 -28 normal
7 sprites/extra_signals.png 8bpp 190 40 20 30 -9 -28 normal
8 sprites/extra_signals.png 8bpp 20 10 4 22 -1 -20 normal
9 sprites/extra_signals.png 8bpp 10 10 5 22 -2 -20 normal
10 sprites/extra_signals.png 8bpp 40 10 5 22 -1 -20 normal
11 sprites/extra_signals.png 8bpp 30 10 4 22 -1 -20 normal
12 sprites/extra_signals.png 8bpp 60 10 5 22 -2 -20 normal
13 sprites/extra_signals.png 8bpp 50 10 5 22 -1 -20 normal
14 sprites/extra_signals.png 8bpp 80 10 6 22 -3 -20 normal
15 sprites/extra_signals.png 8bpp 70 10 6 22 -3 -20 normal

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

@ -2484,7 +2484,7 @@ DEF_CONSOLE_CMD(ConDumpRailTypes)
grfid = grf->grfid;
grfs.insert(std::pair<uint32, const GRFFile *>(grfid, grf));
}
IConsolePrintF(CC_DEFAULT, " %02u %c%c%c%c, Flags: %c%c%c%c%c%c, Ctrl Flags: %c%c%c, GRF: %08X, %s",
IConsolePrintF(CC_DEFAULT, " %02u %c%c%c%c, Flags: %c%c%c%c%c%c, Ctrl Flags: %c%c%c%c, GRF: %08X, %s",
(uint) rt,
rti->label >> 24, rti->label >> 16, rti->label >> 8, rti->label,
HasBit(rti->flags, RTF_CATENARY) ? 'c' : '-',
@ -2496,6 +2496,7 @@ DEF_CONSOLE_CMD(ConDumpRailTypes)
HasBit(rti->ctrl_flags, RTCF_PROGSIG) ? 'p' : '-',
HasBit(rti->ctrl_flags, RTCF_RESTRICTEDSIG) ? 'r' : '-',
HasBit(rti->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-',
HasBit(rti->ctrl_flags, RTCF_NOENTRYSIG) ? 'n' : '-',
BSWAP32(grfid),
GetStringPtr(rti->strings.name)
);

@ -177,6 +177,15 @@ static void LoadSpriteTables()
DupSprite(SPR_PROGSIGNAL_BASE + i, SPR_DUP_PROGSIGNAL_BASE + i);
}
/* Extra signal sprites. */
SpriteFile &extrasig_file = LoadGrfFile("extra_signals.grf", SPR_EXTRASIGNAL_BASE, false);
extrasig_file.flags |= SFF_PROGSIG;
/* Fill duplicate extra signal graphics sprite block */
for (uint i = 0; i < EXTRASIGNAL_SPRITE_COUNT; i++) {
DupSprite(SPR_EXTRASIGNAL_BASE + i, SPR_DUP_EXTRASIGNAL_BASE + i);
}
/* Tracerestrict sprites. */
LoadGrfFile("tracerestrict.grf", SPR_TRACERESTRICT_BASE, false);

@ -1442,6 +1442,8 @@ STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES :Show advanced r
STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES_HELPTEXT :Show advanced routing restriction features. When disabled, some advanced features are not shown in the UI, but are still available to all players.
STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES :Show programmable pre-signal feature: {STRING2}
STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES_HELPTEXT :Show programmable pre-signal feature. When disabled, the buttons to build and configure programmable pre-signals are not shown in the UI, but are still available to all players.
STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES :Show no-entry signal feature: {STRING2}
STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES_HELPTEXT :Show no-entry signal feature. When disabled, the buttons to build and configure no-entry signals are not shown in the UI, but are still available to all players.
STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER :Show cargo type filter in vehicle lists: {STRING2}
STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER_HELPTEXT :Show cargo type filter in vehicle lists. When enabled vehicle list windows include an additional filter dropdown.
STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES :Show advanced loading mode features: {STRING2}
@ -2885,6 +2887,7 @@ STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo Si
STR_BUILD_SIGNAL_SEMAPHORE_PROG_TOOLTIP :{BLACK}Programmable Pre-Signal (semaphore){}The programmable pre-signal is a combo-signal which can be programmed to behave in complex ways.
STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{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_TOOLTIP :{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_NO_ENTRY_TOOLTIP :{BLACK}No-Entry 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. No-entry signals can't be passed from the front side
STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{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_TOOLTIP :{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_TOOLTIP :{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
@ -2892,6 +2895,7 @@ STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo Si
STR_BUILD_SIGNAL_ELECTRIC_PROG_TOOLTIP :{BLACK}Programmable Pre-Signal (electric){}The programmable pre-signal is a combo-signal which can be programmed to behave in complex ways.
STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{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_TOOLTIP :{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_NO_ENTRY_TOOLTIP :{BLACK}No-Entry 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. No-entry signals can't be passed from the front side
STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{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. Shift+Click shows estimated conversion cost
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal distance
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal distance

@ -4078,6 +4078,11 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const
SB(_cur.grffile->new_signal_ctrl_flags, NSCF_PROGSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
break;
case A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
SB(_cur.grffile->new_signal_ctrl_flags, NSCF_NOENTRYSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
break;
case A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
SB(_cur.grffile->new_signal_ctrl_flags, NSCF_RESTRICTEDSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
@ -4416,6 +4421,11 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, const
SB(rti->ctrl_flags, RTCF_PROGSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
break;
case A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
SB(rti->ctrl_flags, RTCF_NOENTRYSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
break;
case A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
SB(rti->ctrl_flags, RTCF_RESTRICTEDSIG, 1, (buf->ReadByte() != 0 ? 1 : 0));
@ -4517,6 +4527,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, cons
break;
case A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS:
case A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS:
case A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS:
case A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING:
case A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR:
@ -8487,7 +8498,9 @@ static const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_bridge_pillar_flags", 1),
GRFFeatureInfo("action0_bridge_availability_flags", 1),
GRFFeatureInfo("action5_programmable_signals", 1),
GRFFeatureInfo("action5_no_entry_signals", 1),
GRFFeatureInfo("action0_railtype_programmable_signals", 1),
GRFFeatureInfo("action0_railtype_no_entry_signals", 1),
GRFFeatureInfo("action0_railtype_restricted_signals", 1),
GRFFeatureInfo("action0_railtype_disable_realistic_braking", 1),
GRFFeatureInfo("action0_railtype_recolour", 1),
@ -8495,6 +8508,7 @@ static const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_roadtype_extra_flags", 1),
GRFFeatureInfo("action0_global_extra_station_names", 1),
GRFFeatureInfo("action0_signals_programmable_signals", 1),
GRFFeatureInfo("action0_signals_no_entry_signals", 1),
GRFFeatureInfo("action0_signals_restricted_signals", 1),
GRFFeatureInfo("action0_signals_recolour", 1),
GRFFeatureInfo("action0_signals_extra_aspects", 1),
@ -8616,6 +8630,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_BRIDGES, A0RPI_BRIDGE_PILLAR_FLAGS, "bridge_pillar_flags"),
GRFPropertyMapDefinition(GSF_BRIDGES, A0RPI_BRIDGE_AVAILABILITY_FLAGS, "bridge_availability_flags"),
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS, "railtype_enable_programmable_signals"),
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS, "railtype_enable_no_entry_signals"),
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS, "railtype_enable_restricted_signals"),
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING, "railtype_disable_realistic_braking"),
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR, "railtype_enable_signal_recolour"),
@ -8624,6 +8639,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_TRAMTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"),
GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, "global_extra_station_names"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_PROGRAMMABLE_SIGNALS, "signals_enable_programmable_signals"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS, "signals_enable_no_entry_signals"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS, "signals_enable_restricted_signals"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, "signals_enable_signal_recolour"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_EXTRA_ASPECTS, "signals_extra_aspects"),
@ -8633,6 +8649,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
/** Action14 Action5 remappable type list */
static const Action5TypeRemapDefinition _grf_action5_remappable_types[] = {
Action5TypeRemapDefinition("programmable_signals", A5BLOCK_ALLOW_OFFSET, SPR_PROGSIGNAL_BASE, 1, 32, "Programmable pre-signal graphics"),
Action5TypeRemapDefinition("no_entry_signals", A5BLOCK_ALLOW_OFFSET, SPR_EXTRASIGNAL_BASE, 1, 16, "No-entry signal graphics"),
Action5TypeRemapDefinition(),
};

@ -116,6 +116,7 @@ enum Action0RemapPropertyIds {
A0RPI_BRIDGE_PILLAR_FLAGS,
A0RPI_BRIDGE_AVAILABILITY_FLAGS,
A0RPI_RAILTYPE_ENABLE_PROGRAMMABLE_SIGNALS,
A0RPI_RAILTYPE_ENABLE_NO_ENTRY_SIGNALS,
A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS,
A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING,
A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR,
@ -123,6 +124,7 @@ enum Action0RemapPropertyIds {
A0RPI_ROADTYPE_EXTRA_FLAGS,
A0RPI_GLOBALVAR_EXTRA_STATION_NAMES,
A0RPI_SIGNALS_ENABLE_PROGRAMMABLE_SIGNALS,
A0RPI_SIGNALS_ENABLE_NO_ENTRY_SIGNALS,
A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS,
A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR,
A0RPI_SIGNALS_EXTRA_ASPECTS,
@ -227,6 +229,7 @@ enum NewSignalCtrlFlags {
NSCF_PROGSIG = 1, ///< Custom signal sprites enabled for programmable pre-signals.
NSCF_RESTRICTEDSIG = 2, ///< Custom signal sprite flag enabled for restricted signals.
NSCF_RECOLOUR_ENABLED = 3, ///< Recolour sprites enabled
NSCF_NOENTRYSIG = 4, ///< Custom signal sprites enabled for no-entry signals.
};
enum {

@ -127,6 +127,7 @@ static PalSpriteID GetRailTypeCustomSignalSprite(const RailtypeInfo *rti, TileIn
{
if (rti->group[RTSG_SIGNALS] == nullptr) return { 0, PAL_NONE };
if (type == SIGTYPE_PROG && !HasBit(rti->ctrl_flags, RTCF_PROGSIG)) return { 0, PAL_NONE };
if (type == SIGTYPE_NO_ENTRY && !HasBit(rti->ctrl_flags, RTCF_NOENTRYSIG)) return { 0, PAL_NONE };
uint32 param1 = gui ? 0x10 : 0x00;
uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, rti->signal_extra_aspects);
@ -157,6 +158,7 @@ CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileInde
for (const GRFFile *grf : _new_signals_grfs) {
if (type == SIGTYPE_PROG && !HasBit(grf->new_signal_ctrl_flags, NSCF_PROGSIG)) continue;
if (type == SIGTYPE_NO_ENTRY && !HasBit(grf->new_signal_ctrl_flags, NSCF_NOENTRYSIG)) continue;
uint32 param1 = gui ? 0x10 : 0x00;
uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, grf->new_signal_extra_aspects);

@ -495,7 +495,7 @@ static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare
NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype));
}
if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) {
if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) && !IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) {
cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty;
}
}
@ -965,6 +965,9 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
/* If there's a one-way signal not pointing towards us, stop going in this direction. */
break;
}
if (HasSignalOnTrackdir(dst_tile, dst_trackdir) && IsNoEntrySignal(dst_tile, TrackdirToTrack(dst_trackdir))) {
break;
}
}
if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(dst_tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(dst_tile)) == dst_trackdir) {
/* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */

@ -328,6 +328,11 @@ public:
SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir);
SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir));
if (IsNoEntrySignal(sig_type)) {
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
return cost;
}
n.m_last_signal_type = sig_type;
/* cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is */
@ -393,18 +398,21 @@ public:
n.m_segment->m_last_signal_td = trackdir;
}
if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
bool no_add_cost = false;
if (has_signal_against) {
SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir));
if (IsPbsSignal(sig_type) && !IsNoEntrySignal(sig_type)) {
bool no_add_cost = false;
if (ShouldCheckTraceRestrict(n, tile)) {
TraceRestrictProgramResult out;
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out, nullptr, &no_add_cost)) {
return -1;
if (ShouldCheckTraceRestrict(n, tile)) {
TraceRestrictProgramResult out;
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out, nullptr, &no_add_cost)) {
return -1;
}
}
}
if (!no_add_cost) {
cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
if (!no_add_cost) {
cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
}
}
}
}
@ -702,7 +710,15 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, MP_RAILWAY)) {
if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) {
/* Possible safe tile. */
end_segment_reason |= ESRB_SAFE_TILE;
if (IsNoEntrySignal(next.tile, TrackdirToTrack(next.td))) {
if (likely(_settings_game.pf.back_of_one_way_pbs_waiting_point)) {
/* Possible safe tile, but not so good as it's the back of a signal... */
end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END;
extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty;
}
} else {
end_segment_reason |= ESRB_SAFE_TILE;
}
} else if (likely(_settings_game.pf.back_of_one_way_pbs_waiting_point) && HasSignalOnTrackdir(next.tile, ReverseTrackdir(next.td)) &&
GetSignalType(next.tile, TrackdirToTrack(next.td)) == SIGTYPE_PBS_ONEWAY) {
/* Possible safe tile, but not so good as it's the back of a signal... */

@ -1162,6 +1162,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
/* PBS signal on next trackdir? Conditionally safe position. */
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
if (GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_NO_ENTRY) return include_line_end;
if (IsRestrictedSignal(ft.m_new_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td));
if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) {

@ -47,6 +47,7 @@ enum RailTypeCtrlFlags {
RTCF_RESTRICTEDSIG = 1, ///< Custom signal sprite flag enabled for restricted signals.
RTCF_NOREALISTICBRAKING = 2, ///< Realistic braking disabled for this track type
RTCF_RECOLOUR_ENABLED = 3, ///< Recolour sprites enabled
RTCF_NOENTRYSIG = 4, ///< Custom signal sprites enabled for no-entry signals.
};
struct SpriteGroup;

@ -104,22 +104,26 @@ void ResolveRailTypeGUISprites(RailtypeInfo *rti)
const SpriteID _signal_lookup[2][SIGTYPE_END] = {
{SPR_IMG_SIGNAL_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT,
SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY,
SPR_IMG_SIGNAL_ELECTRIC_PROG},
SPR_IMG_SIGNAL_ELECTRIC_PROG, SPR_IMG_SIGNAL_ELECTRIC_NO_ENTRY},
{SPR_IMG_SIGNAL_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT,
SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY,
SPR_IMG_SIGNAL_SEMAPHORE_PROG},
SPR_IMG_SIGNAL_SEMAPHORE_PROG, SPR_IMG_SIGNAL_SEMAPHORE_NO_ENTRY},
};
for (SignalType type = SIGTYPE_NORMAL; type < SIGTYPE_END; type = (SignalType)(type + 1)) {
for (SignalVariant var = SIG_ELECTRIC; var <= SIG_SEMAPHORE; var = (SignalVariant)(var + 1)) {
PalSpriteID red = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 0, true).sprite;
PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, true).sprite;
if (red.sprite != 0) {
rti->gui_sprites.signals[type][var][0] = { red.sprite + SIGNAL_TO_SOUTH, red.pal };
} else {
rti->gui_sprites.signals[type][var][0] = { _signal_lookup[var][type], PAL_NONE };
}
if (type == SIGTYPE_NO_ENTRY) {
rti->gui_sprites.signals[type][var][1] = rti->gui_sprites.signals[type][var][0];
continue;
}
PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, true).sprite;
if (green.sprite != 0) {
rti->gui_sprites.signals[type][var][1] = { green.sprite + SIGNAL_TO_SOUTH, green.pal };
} else {
@ -1689,6 +1693,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
/* Query current signal type so the check for PBS signals below works. */
sigtype = GetSignalType(tile, track);
} else {
if (GetSignalType(tile, track) == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track);
/* convert the present signal to the chosen type and variant */
if (IsPresignalProgrammable(tile, track)) {
FreeSignalProgram(SignalReference(tile, track));
@ -1698,13 +1704,18 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
}
if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track);
}
} else if (ctrl_pressed) {
/* cycle through signal types */
sigtype = (SignalType)(GetSignalType(tile, track));
if(IsProgrammableSignal(sigtype))
if (IsProgrammableSignal(sigtype)) {
FreeSignalProgram(SignalReference(tile, track));
}
if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track);
do {
sigtype = NextSignalType(sigtype, which_signals);
@ -1714,6 +1725,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
}
if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track);
} else {
/* programmable pre-signal dependencies are invalidated when the signal direction is changed */
CheckRemoveSignal(tile, track);
@ -2680,6 +2693,8 @@ static void GetSignalXY(TileIndex tile, uint pos, uint &x, uint &y)
void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type,
SignalVariant variant, bool show_restricted, bool exit_signal = false)
{
if (type == SIGTYPE_NO_ENTRY) pos ^= 1;
uint x, y;
GetSignalXY(tile, pos, x, y);
@ -2711,6 +2726,15 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign
sprite = SPR_PROGSIGNAL_BASE + 16 + image * 2 + condition;
}
SpriteFile *file = GetOriginFile(sprite);
is_custom_sprite = !(file != nullptr && file->flags & SFF_PROGSIG);
} else if (type == SIGTYPE_NO_ENTRY) {
if (variant == SIG_SEMAPHORE) {
sprite = SPR_EXTRASIGNAL_BASE + image;
} else {
sprite = SPR_EXTRASIGNAL_BASE + 8 + image;
}
SpriteFile *file = GetOriginFile(sprite);
is_custom_sprite = !(file != nullptr && file->flags & SFF_PROGSIG);
} else {
@ -2730,6 +2754,12 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign
} else {
sprite = SPR_DUP_PROGSIGNAL_BASE + 16 + image * 2 + condition;
}
} else if (type == SIGTYPE_NO_ENTRY) {
if (variant == SIG_SEMAPHORE) {
sprite = SPR_DUP_EXTRASIGNAL_BASE + image;
} else {
sprite = SPR_DUP_EXTRASIGNAL_BASE + 8 + image;
}
} else {
sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_DUP_ORIGINAL_SIGNALS_BASE : SPR_DUP_SIGNALS_BASE - 16;
sprite += type * 16 + variant * 64 + image * 2 + condition + (IsSignalSpritePBS(type) ? 64 : 0);
@ -2746,7 +2776,7 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign
AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track), false, 0, 0, 0, &lower_part);
AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track), false, 0, 0, 0, &upper_part);
} else {
AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE + 1, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
AddSortableSpriteToDraw(sprite, SPR_TRACERESTRICT_BASE + (type == SIGTYPE_NO_ENTRY ? 0 : 1), x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
}
} else {
AddSortableSpriteToDraw(sprite, pal, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));

@ -278,6 +278,7 @@ static void GenericPlaceSignals(TileIndex tile)
SB(p1, 5, 3, _cur_signal_type);
SB(p1, 8, 1, _convert_signal_button);
SB(p1, 9, 6, _settings_client.gui.cycle_signal_types);
if (_cur_signal_type == SIGTYPE_NO_ENTRY) SB(p1, 15, 2, 1); // reverse default signal direction
} else {
SB(p1, 3, 1, _ctrl_pressed);
SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
@ -1786,6 +1787,7 @@ private:
int sig_sprite_bottom_offset; ///< Maximum extent of signal GUI sprite from reference point towards bottom.
bool progsig_ui_shown; ///< Whether programmable pre-signal UI is shown
bool presig_ui_shown; ///< Whether pre-signal UI is shown
bool noentry_ui_shown; ///< Whether no-entry signal UI is shown
/**
* Draw dynamic a signal-sprite in a button in the signal GUI
@ -1812,6 +1814,7 @@ private:
void SetSignalUIMode() {
this->progsig_ui_shown = _settings_client.gui.show_progsig_ui;
this->presig_ui_shown = _settings_game.vehicle.train_braking_model != TBM_REALISTIC;
this->noentry_ui_shown = _settings_client.gui.show_noentrysig_ui;
bool show_progsig = this->progsig_ui_shown && this->presig_ui_shown;
this->GetWidget<NWidgetStacked>(WID_BS_SEMAPHORE_ENTRY_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_ELECTRIC_ENTRY_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE);
@ -1821,6 +1824,8 @@ private:
this->GetWidget<NWidgetStacked>(WID_BS_ELECTRIC_COMBO_SEL)->SetDisplayedPlane(this->presig_ui_shown ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_SEMAPHORE_PROG_SEL)->SetDisplayedPlane(show_progsig ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_ELECTRIC_PROG_SEL)->SetDisplayedPlane(show_progsig ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_SEMAPHORE_NOEN_SEL)->SetDisplayedPlane(this->noentry_ui_shown ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_ELECTRIC_NOEN_SEL)->SetDisplayedPlane(this->noentry_ui_shown ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BS_PROGRAM_SEL)->SetDisplayedPlane(show_progsig ? 0 : 1);
this->SetWidgetDisabledState(WID_BS_PROGRAM, !show_progsig);
this->SetWidgetsDisabledState(!show_progsig, WID_BS_SEMAPHORE_PROG, WID_BS_ELECTRIC_PROG, WIDGET_LIST_END);
@ -1894,7 +1899,7 @@ public:
void DrawWidget(const Rect &r, int widget) const override
{
if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) {
if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_NO_ENTRY + 1)) {
/* Extract signal from widget number. */
SignalType type = TypeForClick((widget - WID_BS_SEMAPHORE_NORM) % SIGTYPE_END);
int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets.
@ -1914,6 +1919,7 @@ public:
case 4: return SIGTYPE_PROG;
case 5: return SIGTYPE_PBS;
case 6: return SIGTYPE_PBS_ONEWAY;
case 7: return SIGTYPE_NO_ENTRY;
default:
assert(!"Bad signal type button ID");
return SIGTYPE_NORMAL;
@ -1930,6 +1936,7 @@ public:
case WID_BS_SEMAPHORE_PROG:
case WID_BS_SEMAPHORE_PBS:
case WID_BS_SEMAPHORE_PBS_OWAY:
case WID_BS_SEMAPHORE_NO_ENTRY:
case WID_BS_ELECTRIC_NORM:
case WID_BS_ELECTRIC_ENTRY:
case WID_BS_ELECTRIC_EXIT:
@ -1937,6 +1944,7 @@ public:
case WID_BS_ELECTRIC_PROG:
case WID_BS_ELECTRIC_PBS:
case WID_BS_ELECTRIC_PBS_OWAY:
case WID_BS_ELECTRIC_NO_ENTRY:
this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_button);
_cur_signal_button = (uint)((widget - WID_BS_SEMAPHORE_NORM) % (SIGTYPE_END));
@ -2009,7 +2017,8 @@ public:
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1);
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
if (this->progsig_ui_shown != _settings_client.gui.show_progsig_ui || this->presig_ui_shown != (_settings_game.vehicle.train_braking_model != TBM_REALISTIC)) {
if (this->progsig_ui_shown != _settings_client.gui.show_progsig_ui || this->presig_ui_shown != (_settings_game.vehicle.train_braking_model != TBM_REALISTIC) ||
this->noentry_ui_shown != _settings_client.gui.show_noentrysig_ui) {
this->SetSignalUIMode();
this->ReInit();
}
@ -2029,6 +2038,7 @@ static Hotkey signaltoolbar_hotkeys[] = {
Hotkey((uint16)0, "semaphore_prog", WID_BS_SEMAPHORE_PROG),
Hotkey((uint16)0, "semaphore_pbs", WID_BS_SEMAPHORE_PBS),
Hotkey((uint16)0, "semaphore_pbs_oneway", WID_BS_SEMAPHORE_PBS_OWAY),
Hotkey((uint16)0, "semaphore_no_entry", WID_BS_SEMAPHORE_NO_ENTRY),
Hotkey('G', "signal_normal", WID_BS_ELECTRIC_NORM),
Hotkey((uint16)0, "signal_entry", WID_BS_ELECTRIC_ENTRY),
Hotkey((uint16)0, "signal_exit", WID_BS_ELECTRIC_EXIT),
@ -2036,6 +2046,7 @@ static Hotkey signaltoolbar_hotkeys[] = {
Hotkey((uint16)0, "signal_prog", WID_BS_ELECTRIC_PROG),
Hotkey('H', "signal_pbs", WID_BS_ELECTRIC_PBS),
Hotkey('J', "signal_pbs_oneway", WID_BS_ELECTRIC_PBS_OWAY),
Hotkey((uint16)0, "signal_no_entry", WID_BS_ELECTRIC_NO_ENTRY),
HOTKEY_LIST_END
};
HotkeyList BuildSignalWindow::hotkeys("signaltoolbar", signaltoolbar_hotkeys);
@ -2063,6 +2074,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_NOEN_SEL),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NO_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NO_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
EndContainer(),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_TRACE_RESTRICT), SetDataTip(SPR_IMG_SETTINGS, STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP), SetFill(1, 1),
EndContainer(),
@ -2082,6 +2096,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_NOEN_SEL),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NO_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NO_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
@ -2407,7 +2424,8 @@ void InitializeRailGUI()
_cur_signal_button =
_cur_signal_type == SIGTYPE_PROG ? 4 :
_cur_signal_type == SIGTYPE_PBS ? 5 :
_cur_signal_type == SIGTYPE_PBS_ONEWAY ? 6 : _cur_signal_type;
_cur_signal_type == SIGTYPE_PBS_ONEWAY ? 6 :
_cur_signal_type == SIGTYPE_NO_ENTRY ? 7 : _cur_signal_type;
ResetSignalVariant();
}

@ -349,6 +349,11 @@ static inline bool IsPresignalProgrammable(TileIndex t, Track track)
return IsProgrammableSignal(GetSignalType(t, track));
}
static inline bool IsNoEntrySignal(TileIndex t, Track track)
{
return IsNoEntrySignal(GetSignalType(t, track));
}
/** One-way signals can't be passed the 'wrong' way. */
static inline bool IsOnewaySignal(TileIndex t, Track track)
{
@ -526,6 +531,10 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
!HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
return true;
}
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, td) &&
IsNoEntrySignal(tile, TrackdirToTrack(td))) {
return true;
}
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) &&
TrackdirEntersTunnelBridge(tile, td)) {
return true;

@ -155,6 +155,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" },
{ XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr },
{ XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr },
{ XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
};

@ -109,6 +109,7 @@ enum SlXvFeatureIndex {
XSLFI_TRAIN_SPEED_ADAPTATION, ///< Train speed adaptation
XSLFI_EXTRA_STATION_NAMES, ///< Extra station names
XSLFI_DEPOT_ORDER_EXTRA_FLAGS, ///< Depot order extra flags
XSLFI_EXTRA_SIGNAL_TYPES, ///< Extra signal types
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk

@ -1816,6 +1816,7 @@ static SettingsContainer &GetSettingsTree()
SettingsPage *advsig = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_ADV_SIGNALS));
{
advsig->Add(new SettingEntry("gui.show_progsig_ui"));
advsig->Add(new SettingEntry("gui.show_noentrysig_ui"));
advsig->Add(new SettingEntry("gui.show_adv_tracerestrict_features"));
}

@ -202,6 +202,7 @@ struct GUISettings : public TimeSettings {
bool show_restricted_signal_default; ///< Show restricted electric signals using the default sprite
bool show_adv_tracerestrict_features; ///< Show advanced trace restrict features in UI
bool show_progsig_ui; ///< Show programmable pre-signals feature in UI
bool show_noentrysig_ui; ///< Show no-entry signals feature in UI
bool show_veh_list_cargo_filter; ///< Show cargo list filter in UI
uint8 osk_activation; ///< Mouse gesture to trigger the OSK.
byte starting_colour; ///< default color scheme for the company to start a new game with

@ -774,7 +774,7 @@ static void UpdateSignalsAroundSegment(SigInfo info)
}
/* determine whether the new state is red */
if (info.flags & SF_TRAIN) {
if (info.flags & SF_TRAIN || sig == SIGTYPE_NO_ENTRY) {
/* train in the segment */
newstate = SIGNAL_STATE_RED;
} else if (sig == SIGTYPE_PROG &&

@ -73,7 +73,7 @@ static inline bool IsComboSignal(SignalType type)
/// Is a given signal type a PBS signal?
static inline bool IsPbsSignal(SignalType type)
{
return _settings_game.vehicle.train_braking_model == TBM_REALISTIC || type == SIGTYPE_PBS || type == SIGTYPE_PBS_ONEWAY;
return _settings_game.vehicle.train_braking_model == TBM_REALISTIC || type == SIGTYPE_PBS || type == SIGTYPE_PBS_ONEWAY || type == SIGTYPE_NO_ENTRY;
}
/// Is a given signal type a PBS signal?
@ -88,10 +88,16 @@ static inline bool IsProgrammableSignal(SignalType type)
return type == SIGTYPE_PROG;
}
/// Is this a programmable pre-signal?
static inline bool IsNoEntrySignal(SignalType type)
{
return type == SIGTYPE_NO_ENTRY;
}
/** One-way signals can't be passed the 'wrong' way. */
static inline bool IsOnewaySignal(SignalType type)
{
return type != SIGTYPE_PBS;
return type != SIGTYPE_PBS && type != SIGTYPE_NO_ENTRY;
}
/// Is this signal type unsuitable for realistic braking?
@ -119,6 +125,7 @@ static inline SignalType NextSignalType(SignalType cur, uint which_signals)
case SIGTYPE_PROG: return pbs ? SIGTYPE_PBS : SIGTYPE_NORMAL;
case SIGTYPE_PBS: return pbs ? SIGTYPE_PBS_ONEWAY : SIGTYPE_NORMAL;
case SIGTYPE_PBS_ONEWAY: return block ? SIGTYPE_NORMAL : SIGTYPE_PBS;
case SIGTYPE_NO_ENTRY: return pbs ? SIGTYPE_PBS : SIGTYPE_NORMAL;
default:
DEBUG(map, 0, "Attempt to cycle from signal type %d", cur);
return SIGTYPE_NORMAL; // Fortunately mostly harmless

@ -29,11 +29,12 @@ enum SignalType {
SIGTYPE_EXIT = 2, ///< presignal block exit
SIGTYPE_COMBO = 3, ///< presignal inter-block
SIGTYPE_PBS = 4, ///< normal pbs signal
SIGTYPE_PBS_ONEWAY = 5, ///< no-entry signal
SIGTYPE_PBS_ONEWAY = 5, ///< one-way PBS signal
SIGTYPE_PROG = 6, ///< programmable presignal
SIGTYPE_NO_ENTRY = 7, ///< no-entry signal
SIGTYPE_END,
SIGTYPE_LAST = SIGTYPE_PROG,
SIGTYPE_LAST = SIGTYPE_NO_ENTRY,
SIGTYPE_FIRST_PBS_SPRITE = SIGTYPE_PBS,
};
/** Helper information for extract tool. */

@ -890,10 +890,11 @@ class NIHRailType : public NIHelper {
HasBit(info->flags, RTF_ALLOW_90DEG) ? 'a' : '-',
HasBit(info->flags, RTF_DISALLOW_90DEG) ? 'd' : '-');
print(buffer);
seprintf(buffer, lastof(buffer), " Ctrl flags: %c%c%c",
seprintf(buffer, lastof(buffer), " Ctrl flags: %c%c%c%c",
HasBit(info->ctrl_flags, RTCF_PROGSIG) ? 'p' : '-',
HasBit(info->ctrl_flags, RTCF_RESTRICTEDSIG) ? 'r' : '-',
HasBit(info->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-');
HasBit(info->ctrl_flags, RTCF_NOREALISTICBRAKING) ? 'b' : '-',
HasBit(info->ctrl_flags, RTCF_NOENTRYSIG) ? 'n' : '-');
print(buffer);
seprintf(buffer, lastof(buffer), " Powered: 0x" OTTD_PRINTFHEX64, info->powered_railtypes);
print(buffer);

@ -5412,6 +5412,15 @@ strhelp = STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES_HELPTEXT
proc = ProgrammableSignalsShownChanged
cat = SC_ADVANCED
[SDTC_BOOL]
var = gui.show_noentrysig_ui
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
def = false
str = STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES
strhelp = STR_CONFIG_SETTING_SHOW_NOENTRYSIG_FEATURES_HELPTEXT
proc = ProgrammableSignalsShownChanged
cat = SC_ADVANCED
[SDTC_BOOL]
var = gui.show_veh_list_cargo_filter
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC

@ -314,8 +314,13 @@ static const SpriteID SPR_PROGSIGNAL_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_CO
static const uint16 PROGSIGNAL_SPRITE_COUNT = 32;
static const SpriteID SPR_DUP_PROGSIGNAL_BASE = SPR_PROGSIGNAL_BASE + PROGSIGNAL_SPRITE_COUNT;
/* Extra signal sprites */
static const SpriteID SPR_EXTRASIGNAL_BASE = SPR_DUP_PROGSIGNAL_BASE + PALETTE_SPRITE_COUNT;
static const uint16 EXTRASIGNAL_SPRITE_COUNT = 16;
static const SpriteID SPR_DUP_EXTRASIGNAL_BASE = SPR_EXTRASIGNAL_BASE + EXTRASIGNAL_SPRITE_COUNT;
/* Zoning sprites */
static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_BASE = SPR_DUP_PROGSIGNAL_BASE + PROGSIGNAL_SPRITE_COUNT;
static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_BASE = SPR_DUP_EXTRASIGNAL_BASE + EXTRASIGNAL_SPRITE_COUNT;
static const uint16 ZONING_INNER_HIGHLIGHT_SPRITE_COUNT = 32;
static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_RED = SPR_ZONING_INNER_HIGHLIGHT_BASE + 19;
static const SpriteID SPR_ZONING_INNER_HIGHLIGHT_GREEN = SPR_ZONING_INNER_HIGHLIGHT_BASE + 20;
@ -1372,6 +1377,7 @@ static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_COMBO = SPR_SIGNALS_BASE + 44;
static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS = SPR_SIGNALS_BASE + 124;
static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY = SPR_SIGNALS_BASE + 140;
static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PROG = SPR_PROGSIGNAL_BASE + 28;
static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_NO_ENTRY = SPR_EXTRASIGNAL_BASE + 14;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_NORM = SPR_SIGNALS_BASE + 60;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_ENTRY = SPR_SIGNALS_BASE + 76;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_EXIT = SPR_SIGNALS_BASE + 92;
@ -1379,6 +1385,7 @@ static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_COMBO = SPR_SIGNALS_BASE + 108;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS = SPR_SIGNALS_BASE + 188;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY= SPR_SIGNALS_BASE + 204;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PROG = SPR_PROGSIGNAL_BASE + 12;
static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_NO_ENTRY= SPR_EXTRASIGNAL_BASE + 6;
static const SpriteID SPR_IMG_SIGNAL_CONVERT = SPR_OPENTTD_BASE + 135;
static const SpriteID SPR_IMG_TUNNEL_RAIL = 2430;

@ -3172,7 +3172,8 @@ static void CheckNextTrainTile(Train *v)
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))) {
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td) && !IsNoEntrySignal(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 (ft.m_tiles_skipped == 0 && Rail90DegTurnDisallowedTilesFromTrackdir(ft.m_old_tile, ft.m_new_tile, ft.m_old_td)) {
@ -3575,7 +3576,7 @@ void FreeTrainTrackReservation(Train *v, TileIndex origin, Trackdir orig_td)
break;
}
if (HasPbsSignalOnTrackdir(tile, td)) {
if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) {
if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED || IsNoEntrySignal(tile, TrackdirToTrack(td))) {
/* Red PBS signal? Can't be our reservation, would be green then. */
break;
} else {
@ -3972,6 +3973,7 @@ static bool LookaheadWithinCurrentTunnelBridge(const Train *t)
static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir trackdir, bool default_value)
{
if (HasPbsSignalOnTrackdir(tile, trackdir)) {
if (IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) return false;
if (IsRestrictedSignal(tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
if (prog && prog->actions_used_flags & TRPAUF_LONG_RESERVE) {
@ -4122,7 +4124,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
if (KillFirstBit(tracks) == TRACK_BIT_NONE) {
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 (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir)) && !IsNoEntrySignal(tile, track)) {
if (IsRestrictedSignal(tile) && v->force_proceed != TFP_SIGNAL) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, track);
if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_ACQUIRE_ON_RES | TRPAUF_TRAIN_NOT_STUCK)) {
@ -5279,6 +5281,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
/* Don't handle stuck trains here. */
if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false;
if (IsNoEntrySignal(gp.new_tile, TrackdirToTrack(i)) && HasSignalOnTrackdir(gp.new_tile, i)) {
goto reverse_train_direction;
}
if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
v->cur_speed = 0;
v->subspeed = 0;

@ -86,6 +86,7 @@ enum BuildSignalWidgets {
WID_BS_SEMAPHORE_PROG, ///< Build a semahore programmable pre-signal
WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal.
WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal.
WID_BS_SEMAPHORE_NO_ENTRY, ///< Build a semaphore no-entry signal.
WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal
WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal
WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal
@ -93,6 +94,7 @@ enum BuildSignalWidgets {
WID_BS_ELECTRIC_PROG, ///< Build an electric programmable pre-signal
WID_BS_ELECTRIC_PBS, ///< Build an electric path signal.
WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
WID_BS_ELECTRIC_NO_ENTRY, ///< Build an electric no-entry signal.
WID_BS_CONVERT, ///< Convert the signal.
WID_BS_TRACE_RESTRICT, ///< Open trace restrict window.
WID_BS_PROGRAM, ///< Enter program to prog signal
@ -107,6 +109,8 @@ enum BuildSignalWidgets {
WID_BS_ELECTRIC_COMBO_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_COMBO
WID_BS_SEMAPHORE_PROG_SEL, ///< NWID_SELECTION for WID_BS_SEMAPHORE_PROG
WID_BS_ELECTRIC_PROG_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_PROG
WID_BS_SEMAPHORE_NOEN_SEL, ///< NWID_SELECTION for WID_BS_SEMAPHORE_NO_ENTRY
WID_BS_ELECTRIC_NOEN_SEL, ///< NWID_SELECTION for WID_BS_ELECTRIC_NO_ENTRY
WID_BS_PROGRAM_SEL, ///< NWID_SELECTION for WID_BS_PROGRAM
};

Loading…
Cancel
Save