diff --git a/docs/landscape.html b/docs/landscape.html
index 47a8b52aad..ea3d1fac33 100644
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -508,6 +508,8 @@
- m2 bit 15: for bridge entrances only: storage for visual red/green state of signals starting from 15 is allocated outside the map array
- m2 bits 14..4: for bridge entrances only: for signals 0..10 on bridge, signal is visually red if corresponding bit in 4..14 is set
+ - m3 bit 7: the signal style is non-zero (style stored outside the map array)
- m3 bit 6: the entrance and/or exit signals on this tile are restricted (tracerestrict patch)
- m3 bits 5..3: entrance signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)
- m3 bits 2..0: exit signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)
diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html
index 529f4c29e6..8b7560e478 100644
--- a/docs/landscape_grid.html
+++ b/docs/landscape_grid.html
@@ -103,7 +103,7 @@ the array so you can quickly see what is used and what is not.
OOOO OOOO |
OOOO XXXX |
OO XXXXXX |
- OOOO OOOO |
+ OOOO OOOO |
OOOO OOOO |
OOOO PPPP PPXX XXXX |
@@ -113,6 +113,7 @@ the array so you can quickly see what is used and what is not.
XXXX OOOO |
XXXX XXXX |
O1 XXXXXX |
+ PPPP PPPP |
OO PPPPPP |
@@ -122,6 +123,7 @@ the array so you can quickly see what is used and what is not.
OOOO XXXX |
11OX OOXX |
OOOO OOOO |
+ OOOO OOOO |
OOOO OOOO OOXX XXXX |
@@ -292,7 +294,7 @@ the array so you can quickly see what is used and what is not.
tunnel entrance |
OOO XXXXX |
PPPP PPPP PPPP PPPP |
- XXXX OOOO OP PPPPPP |
+ XXXX OOOO P P PPPPPP |
OOXX XXXX |
OPPX XX XX |
PPOO OOPP |
diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html
index 20b546b3fe..782f29635b 100644
--- a/docs/newgrf-additions-nml.html
+++ b/docs/newgrf-additions-nml.html
@@ -445,6 +445,26 @@ item (FEAT_GLOBALVARS) {
N.B. Realistic braking must be enabled for additional signal aspects to be used
+ define_style | 1 - 255 |
+
+ Define a custom signal style
+ Signals using this style will only use this GRF, or the default graphics if no graphics are returned.
+ The value supplied is returned in the signal_style variable.
+ This property (and related signal style properties) may be used more than once.
+ The total number of custom signal styles in a game is currently limited to 15.
+ |
+
+ style_name | string |
+
+ Set the name of the most recently defined style (defined using the define_style property).
+ This property should be used if using the define_style property, as otherwise the style will have no name.
+ |
+
+ no_default_style | 0 or 1 |
+
+ When enabled, custom signal graphics from this GRF are only used for custom signal styles, not the default style
+ |
+
@@ -489,6 +509,11 @@ item (FEAT_GLOBALVARS) {
Above signal context variables in one variable (all of the signals_signal_context variable)
+ signal_style | 0 - 255 |
+
+ The style ID defined using define_style for signals using a custom style, or 0 for signals using the default style
+ |
+
Custom signal sprites example:
diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html
index 84842e6ff1..c880899f1f 100644
--- a/docs/newgrf-additions.html
+++ b/docs/newgrf-additions.html
@@ -416,6 +416,28 @@
The provided value is currently clamped to be within the range 0 - 6 (inclusive).
N.B. Realistic braking must be enabled for additional signal aspects to be used.
This is indicated by the feature name: action0_signals_extra_aspects, version 1
+ Define a custom signal style (mappable property: signals_define_style)
+ This applies to Action 2/3 Signals (Feature 0E) custom signal sprites for this GRF.
+ This defines a new signal style. Signals using this style will only use this GRF, or the default graphics if no graphics are returned.
+ The total number of custom signal styles in a game is currently limited to 15.
+ The property length is 1 byte. This is the local ID of the style which is returned in the signals_signal_style variable.
+ The Action 0 Id field is not used, the value is ignored.
+
+ This is indicated by the feature name: action0_signals_style, version 1
+ Set custom signal style name (mappable property: signals_style_name)
+ This applies to the most recent custom signal style defined using the signals_define_style property.
+ This property should be set, as otherwise the style will not have a name.
+ The property length is 2 byte. This is a string ID.
+ The Action 0 Id field is not used, the value is ignored.
+
+ This is indicated by the feature name: action0_signals_style, version 1
+ Set whether custom signal sprites should not be used for the default signal style (mappable property: signals_no_default_style)
+ This applies to Action 2/3 Signals (Feature 0E) custom signal sprites for this GRF.
+ When enabled, this GRF is not used for the default signal style, it is only used for custom signal styles defined with signals_define_style.
+ The property length is 1 byte. 0 is disabled (default). 1 is enabled.
+ The Action 0 Id field is not used, the value is ignored.
+
+ This is indicated by the feature name: action0_signals_style, version 1
Object uses land ground sprite (mappable property: object_use_land_ground)
@@ -649,6 +671,12 @@
This is indicated by the feature name: varaction2_signals_signal_context, version 1
+ Signal style (mappable variable: signals_signal_style)
+ This applies to Action 2/3 Signals (Feature 0E) custom signal sprites.
+ If the signal being drawn uses a custom signal style, the value is the signal style ID as set in the signals_define_style property.
+ Otherwise for signals using the default style, the value is 0.
+
+ This is indicated by the feature name: action0_signals_style, version 1
diff --git a/src/bridge_map.cpp b/src/bridge_map.cpp
index 98a9ce91ec..d9c3b94544 100644
--- a/src/bridge_map.cpp
+++ b/src/bridge_map.cpp
@@ -12,6 +12,7 @@
#include "tunnelbridge_map.h"
#include "bridge_signal_map.h"
#include "debug.h"
+#include "newgrf_newsignals.h"
#include "safeguards.h"
@@ -169,3 +170,36 @@ void ClearBridgeSimulatedSignalMapping()
{
_long_bridge_signal_sim_map.clear();
}
+
+btree::btree_set _bridge_signal_style_map;
+static_assert(MAX_MAP_TILES_BITS + 4 <= 32);
+static_assert(1 << 4 <= MAX_NEW_SIGNAL_STYLES + 1);
+
+void SetBridgeSignalStyle(TileIndex t, uint8 style)
+{
+ if (style == 0) {
+ /* No style allocated before */
+ if (!HasBit(_m[t].m3, 7)) return;
+
+ auto iter = _bridge_signal_style_map.lower_bound(t << 4);
+ if (iter != _bridge_signal_style_map.end() && *iter >> 4 == t) _bridge_signal_style_map.erase(iter);
+ ClrBit(_m[t].m3, 7);
+ } else {
+ auto iter = _bridge_signal_style_map.lower_bound(t << 4);
+ if (iter != _bridge_signal_style_map.end() && *iter >> 4 == t) iter = _bridge_signal_style_map.erase(iter);
+ _bridge_signal_style_map.insert(iter, (t << 4) | style);
+ SetBit(_m[t].m3, 7);
+ }
+}
+
+uint8 GetBridgeSignalStyleExtended(TileIndex t)
+{
+ auto iter = _bridge_signal_style_map.lower_bound(t << 4);
+ if (iter != _bridge_signal_style_map.end() && *iter >> 4 == t) return (*iter) & 0xF;
+ return 0;
+}
+
+void ClearBridgeSignalStyleMapping()
+{
+ _bridge_signal_style_map.clear();
+}
diff --git a/src/bridge_signal_map.h b/src/bridge_signal_map.h
index 6fa63b9c90..c59597a313 100644
--- a/src/bridge_signal_map.h
+++ b/src/bridge_signal_map.h
@@ -14,6 +14,7 @@
#include "map_func.h"
#include "signal_type.h"
#include "core/bitmath_func.hpp"
+#include "3rdparty/cpp-btree/btree_set.h"
#include
#include
@@ -24,6 +25,8 @@ struct LongBridgeSignalStorage {
extern std::unordered_map _long_bridge_signal_sim_map;
+extern btree::btree_set _bridge_signal_style_map;
+
SignalState GetBridgeEntranceSimulatedSignalStateExtended(TileIndex t, uint16 signal);
enum {
@@ -79,6 +82,18 @@ static inline void ClearBridgeEntranceSimulatedSignals(TileIndex t)
void ClearBridgeSimulatedSignalMapping();
+void SetBridgeSignalStyle(TileIndex t, uint8 style);
+
+static inline uint8 GetBridgeSignalStyle(TileIndex t)
+{
+ if (likely(!HasBit(_m[t].m3, 7))) return 0;
+
+ extern uint8 GetBridgeSignalStyleExtended(TileIndex t);
+ return GetBridgeSignalStyleExtended(t);
+}
+
+void ClearBridgeSignalStyleMapping();
+
void MarkSingleBridgeSignalDirty(TileIndex tile, TileIndex bridge_start_tile);
#endif /* BRIDGE_SIGNAL_MAP_H */
diff --git a/src/lang/english.txt b/src/lang/english.txt
index e1d6a3bc8c..c8041b2ca5 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -3205,6 +3205,8 @@ STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal C
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal distance
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal distance
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal distance
+STR_BUILD_SIGNAL_DEFAULT_STYLE :Default
+STR_BUILD_SIGNAL_STYLE_TOOLTIP :{BLACK}Select signal style
# Tracerestrict GUI
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_EQUALS :is
@@ -3881,8 +3883,10 @@ STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :Railway track w
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_PROGSIGNALS :Railway track with path and programmable pre-signals
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_PROGSIGNALS :Railway track with one-way path and programmable pre-signals
STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :Railway train depot
+STR_LAI_RAIL_DESCRIPTION_TRACK_SIGNAL_STYLE :{STRING}: ({STRING})
+STR_LAI_RAIL_DESCRIPTION_TRACK_SIGNAL_STYLE2 :{STRING}: ({STRING} and {STRING})
-STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL :{STRING} (restricted)
+STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL :{STRING3} (restricted)
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
diff --git a/src/misc.cpp b/src/misc.cpp
index c40affba07..b1a483c686 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -115,6 +115,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
ClearTraceRestrictMapping();
ClearBridgeSimulatedSignalMapping();
+ ClearBridgeSignalStyleMapping();
ClearCargoPacketDeferredPayments();
PoolBase::Clean(PT_NORMAL);
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index 21240c496f..5f957449ea 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -197,6 +197,8 @@ public:
/* Tiletype */
SetDParam(0, td.dparam[0]);
SetDParam(1, td.dparam[1]);
+ SetDParam(2, td.dparam[2]);
+ SetDParam(3, td.dparam[3]);
this->landinfo_data.push_back(GetString(td.str));
/* Up to four owners */
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 10dc653845..72f37204e0 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -4194,6 +4194,37 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const
_cur.grffile->new_signal_extra_aspects = std::min(buf->ReadByte(), NEW_SIGNALS_MAX_EXTRA_ASPECT);
break;
+ case A0RPI_SIGNALS_NO_DEFAULT_STYLE:
+ if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
+ SB(_cur.grffile->new_signal_style_mask, 0, 1, (buf->ReadByte() != 0 ? 0 : 1));
+ break;
+
+ case A0RPI_SIGNALS_DEFINE_STYLE: {
+ if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
+ uint8 local_id = buf->ReadByte();
+ if (_num_new_signal_styles < MAX_NEW_SIGNAL_STYLES) {
+ NewSignalStyle &style = _new_signal_styles[_num_new_signal_styles];
+ style = {};
+ _num_new_signal_styles++;
+ SetBit(_cur.grffile->new_signal_style_mask, _num_new_signal_styles);
+ style.grf_local_id = local_id;
+ style.grffile = _cur.grffile;
+ _cur.grffile->current_new_signal_style = &style;
+ } else {
+ _cur.grffile->current_new_signal_style = nullptr;
+ }
+ break;
+ }
+
+ case A0RPI_SIGNALS_STYLE_NAME: {
+ if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
+ uint16 str = buf->ReadWord();
+ if (_cur.grffile->current_new_signal_style != nullptr) {
+ AddStringForMapping(str, &(_cur.grffile->current_new_signal_style->name));
+ }
+ break;
+ }
+
default:
ret = HandleAction0PropertyDefault(buf, prop);
break;
@@ -12402,6 +12433,8 @@ static void ResetNewGRF()
_grf_files.clear();
_cur.grffile = nullptr;
_new_signals_grfs.clear();
+ MemSetT(_new_signal_styles.data(), 0, MAX_NEW_SIGNAL_STYLES);
+ _num_new_signal_styles = 0;
_new_landscape_rocks_grfs.clear();
}
@@ -12588,6 +12621,8 @@ GRFFile::GRFFile(const GRFConfig *config)
this->new_signals_group = nullptr;
this->new_signal_ctrl_flags = 0;
this->new_signal_extra_aspects = 0;
+ this->new_signal_style_mask = 1;
+ this->current_new_signal_style = nullptr;
this->new_rocks_group = nullptr;
this->new_landscape_ctrl_flags = 0;
diff --git a/src/newgrf.h b/src/newgrf.h
index 12bdd0fc0c..4dc6d29c4c 100644
--- a/src/newgrf.h
+++ b/src/newgrf.h
@@ -300,6 +300,8 @@ enum GRFFileCtrlFlags {
GFCF_HAVE_FEATURE_ID_REMAP = 0, ///< This GRF has one or more feature ID mappings
};
+struct NewSignalStyle;
+
/** Dynamic data of a loaded NewGRF */
struct GRFFile : ZeroedMemoryAllocator {
char *filename;
@@ -357,6 +359,8 @@ struct GRFFile : ZeroedMemoryAllocator {
const SpriteGroup *new_signals_group; ///< New signals sprite group
byte new_signal_ctrl_flags; ///< Ctrl flags for new signals
byte new_signal_extra_aspects; ///< Number of extra aspects for new signals
+ uint16 new_signal_style_mask; ///< New signal styles usable with this GRF
+ NewSignalStyle *current_new_signal_style; ///< Current new signal style being defined by this GRF
const SpriteGroup *new_rocks_group; ///< New landscape rocks group
byte new_landscape_ctrl_flags; ///< Ctrl flags for new landscape
diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp
index 4bc4f83b2a..16b7de4383 100644
--- a/src/newgrf_extension.cpp
+++ b/src/newgrf_extension.cpp
@@ -47,6 +47,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_signals_restricted_signals", 2),
GRFFeatureInfo("action0_signals_recolour", 1),
GRFFeatureInfo("action0_signals_extra_aspects", 1),
+ GRFFeatureInfo("action0_signals_style", 1),
GRFFeatureInfo("varaction2_signals_signal_context", 1),
GRFFeatureInfo("action3_signals_custom_signal_sprites", 1),
GRFFeatureInfo("action0_object_use_land_ground", 1),
@@ -90,6 +91,9 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
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"),
+ GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_NO_DEFAULT_STYLE, "signals_no_default_style"),
+ GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_DEFINE_STYLE, "signals_define_style"),
+ GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_NAME, "signals_style_name"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_USE_LAND_GROUND, "object_use_land_ground"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_EDGE_FOUNDATION_MODE, "object_edge_foundation_mode"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_FLOOD_RESISTANT, "object_flood_resistant"),
@@ -135,6 +139,7 @@ extern const GRFVariableMapDefinition _grf_action2_remappable_variables[] = {
GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_CONTEXT, "railtype_signal_context"),
GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "signals_signal_restriction_info"),
GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_CONTEXT, "signals_signal_context"),
+ GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_STYLE, "signals_signal_style"),
GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x40, "newlandscape_terrain_type"),
GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x41, "newlandscape_tile_slope"),
GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x42, "newlandscape_tile_height"),
diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h
index 86a717cc24..ca2824e56e 100644
--- a/src/newgrf_extension.h
+++ b/src/newgrf_extension.h
@@ -35,6 +35,9 @@ enum Action0RemapPropertyIds {
A0RPI_SIGNALS_ENABLE_RESTRICTED_SIGNALS,
A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR,
A0RPI_SIGNALS_EXTRA_ASPECTS,
+ A0RPI_SIGNALS_NO_DEFAULT_STYLE,
+ A0RPI_SIGNALS_DEFINE_STYLE,
+ A0RPI_SIGNALS_STYLE_NAME,
A0RPI_OBJECT_USE_LAND_GROUND,
A0RPI_OBJECT_EDGE_FOUNDATION_MODE,
A0RPI_OBJECT_FLOOD_RESISTANT,
@@ -66,6 +69,7 @@ enum Action2VariableRemapIds {
A2VRI_RAILTYPE_SIGNAL_CONTEXT,
A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO,
A2VRI_SIGNALS_SIGNAL_CONTEXT,
+ A2VRI_SIGNALS_SIGNAL_STYLE,
};
/** Action14 feature definition */
diff --git a/src/newgrf_newsignals.cpp b/src/newgrf_newsignals.cpp
index 619296597d..1b9bd4775b 100644
--- a/src/newgrf_newsignals.cpp
+++ b/src/newgrf_newsignals.cpp
@@ -18,6 +18,8 @@
#include "safeguards.h"
std::vector _new_signals_grfs;
+std::array _new_signal_styles;
+uint _num_new_signal_styles = 0;
/* virtual */ uint32 NewSignalsScopeResolver::GetRandomBits() const
{
@@ -25,6 +27,11 @@ std::vector _new_signals_grfs;
return GB(tmp, 0, 2);
}
+static uint8 MapSignalStyle(uint8 style)
+{
+ return style != 0 ? _new_signal_styles[style - 1].grf_local_id : 0;
+}
+
/* virtual */ uint32 NewSignalsScopeResolver::GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->tile == INVALID_TILE) {
@@ -32,6 +39,7 @@ std::vector _new_signals_grfs;
case 0x40: return 0;
case A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO: return 0;
case A2VRI_SIGNALS_SIGNAL_CONTEXT: return this->signal_context;
+ case A2VRI_SIGNALS_SIGNAL_STYLE: return MapSignalStyle(this->signal_style);
}
}
@@ -41,6 +49,7 @@ std::vector _new_signals_grfs;
return GetNewSignalsRestrictedSignalsInfo(this->prog, this->tile);
case A2VRI_SIGNALS_SIGNAL_CONTEXT:
return GetNewSignalsSignalContext(this->signal_context, this->tile);
+ case A2VRI_SIGNALS_SIGNAL_STYLE: return MapSignalStyle(this->signal_style);
}
DEBUG(grf, 1, "Unhandled new signals tile variable 0x%X", variable);
@@ -71,8 +80,8 @@ GrfSpecFeature NewSignalsResolverObject::GetFeature() const
* @param signal_context Signal context.
* @param prog Routing restriction program.
*/
-NewSignalsResolverObject::NewSignalsResolverObject(const GRFFile *grffile, TileIndex tile, TileContext context, uint32 param1, uint32 param2, CustomSignalSpriteContext signal_context, const TraceRestrictProgram *prog)
- : ResolverObject(grffile, CBID_NO_CALLBACK, param1, param2), newsignals_scope(*this, tile, context, signal_context, prog)
+NewSignalsResolverObject::NewSignalsResolverObject(const GRFFile *grffile, TileIndex tile, TileContext context, uint32 param1, uint32 param2, CustomSignalSpriteContext signal_context, uint8 signal_style, const TraceRestrictProgram *prog)
+ : ResolverObject(grffile, CBID_NO_CALLBACK, param1, param2), newsignals_scope(*this, tile, context, signal_context, signal_style, prog)
{
this->root_spritegroup = grffile != nullptr ? grffile->new_signals_group : nullptr;
}
diff --git a/src/newgrf_newsignals.h b/src/newgrf_newsignals.h
index 9ca73fbc99..41df70775f 100644
--- a/src/newgrf_newsignals.h
+++ b/src/newgrf_newsignals.h
@@ -13,16 +13,33 @@
#include "newgrf_commons.h"
#include "newgrf_spritegroup.h"
#include "tunnel_map.h"
+#include "gfx_type.h"
extern std::vector _new_signals_grfs;
struct TraceRestrictProgram;
+struct GRFFile;
+
+enum {
+ MAX_NEW_SIGNAL_STYLES = 15,
+};
+
+struct NewSignalStyle {
+ const GRFFile *grffile;
+ StringID name = 0;
+ uint8 grf_local_id;
+
+ PalSpriteID signals[SIGTYPE_END][2][2];
+};
+extern std::array _new_signal_styles;
+extern uint _num_new_signal_styles;
/** Resolver for the new signals scope. */
struct NewSignalsScopeResolver : public ScopeResolver {
TileIndex tile; ///< Tracktile. For track on a bridge this is the southern bridgehead.
TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge?
CustomSignalSpriteContext signal_context;
+ uint8 signal_style;
const TraceRestrictProgram *prog;
/**
@@ -32,8 +49,8 @@ struct NewSignalsScopeResolver : public ScopeResolver {
* @param context Are we resolving sprites for the upper halftile, or on a bridge?
* @param signal_context Signal context.
*/
- NewSignalsScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context, CustomSignalSpriteContext signal_context, const TraceRestrictProgram *prog)
- : ScopeResolver(ro), tile(tile), context(context), signal_context(signal_context), prog(prog)
+ NewSignalsScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context, CustomSignalSpriteContext signal_context, uint8 signal_style, const TraceRestrictProgram *prog)
+ : ScopeResolver(ro), tile(tile), context(context), signal_context(signal_context), signal_style(signal_style), prog(prog)
{
}
@@ -45,7 +62,7 @@ struct NewSignalsScopeResolver : public ScopeResolver {
struct NewSignalsResolverObject : public ResolverObject {
NewSignalsScopeResolver newsignals_scope; ///< Resolver for the new signals scope.
- NewSignalsResolverObject(const GRFFile *grffile, TileIndex tile, TileContext context, uint32 param1, uint32 param2, CustomSignalSpriteContext signal_context, const TraceRestrictProgram *prog = nullptr);
+ NewSignalsResolverObject(const GRFFile *grffile, TileIndex tile, TileContext context, uint32 param1, uint32 param2, CustomSignalSpriteContext signal_context, uint8 signal_style, const TraceRestrictProgram *prog = nullptr);
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override
{
diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp
index fc8f17bedb..4e9775d6e6 100644
--- a/src/newgrf_railtype.cpp
+++ b/src/newgrf_railtype.cpp
@@ -153,21 +153,24 @@ static PalSpriteID GetRailTypeCustomSignalSprite(const RailtypeInfo *rti, TileIn
* @param gui Is the sprite being used on the map or in the GUI?
* @return The sprite to draw.
*/
-CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, uint8 aspect, CustomSignalSpriteContext context, const TraceRestrictProgram *prog)
+CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, uint8 aspect, CustomSignalSpriteContext context, uint8 style, const TraceRestrictProgram *prog)
{
- if (_settings_client.gui.show_all_signal_default) return { { 0, PAL_NONE }, false };
+ if (_settings_client.gui.show_all_signal_default && style == 0) return { { 0, PAL_NONE }, false };
- PalSpriteID spr = GetRailTypeCustomSignalSprite(rti, tile, type, var, aspect, context, prog);
- if (spr.sprite != 0) return { spr, HasBit(rti->ctrl_flags, RTCF_RESTRICTEDSIG) };
+ if (style == 0) {
+ PalSpriteID spr = GetRailTypeCustomSignalSprite(rti, tile, type, var, aspect, context, prog);
+ if (spr.sprite != 0) return { spr, HasBit(rti->ctrl_flags, RTCF_RESTRICTEDSIG) };
+ }
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;
+ if (!HasBit(grf->new_signal_style_mask, style)) continue;
uint32 param1 = (context == CSSC_GUI) ? 0x10 : 0x00;
uint32 param2 = (type << 16) | (var << 8) | RemapAspect(aspect, grf->new_signal_extra_aspects);
if ((prog != nullptr) && HasBit(grf->new_signal_ctrl_flags, NSCF_RESTRICTEDSIG)) SetBit(param2, 24);
- NewSignalsResolverObject object(grf, tile, TCX_NORMAL, param1, param2, context, prog);
+ NewSignalsResolverObject object(grf, tile, TCX_NORMAL, param1, param2, context, style, prog);
const SpriteGroup *group = object.Resolve();
if (group != nullptr && group->GetNumResults() != 0) {
diff --git a/src/newgrf_railtype.h b/src/newgrf_railtype.h
index 994c5ad6c5..8764efcef4 100644
--- a/src/newgrf_railtype.h
+++ b/src/newgrf_railtype.h
@@ -64,7 +64,7 @@ struct CustomSignalSpriteResult {
};
SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr);
-CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, uint8 aspect, CustomSignalSpriteContext context, const TraceRestrictProgram *prog = nullptr);
+CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, uint8 aspect, CustomSignalSpriteContext context, uint8 style, const TraceRestrictProgram *prog = nullptr);
RailType GetRailTypeTranslation(uint8 railtype, const GRFFile *grffile);
uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile);
diff --git a/src/openttd.cpp b/src/openttd.cpp
index d39e935dd6..ae49d20841 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -440,6 +440,7 @@ static void ShutdownGame()
LinkGraphSchedule::Clear();
ClearTraceRestrictMapping();
ClearBridgeSimulatedSignalMapping();
+ ClearBridgeSignalStyleMapping();
ClearCargoPacketDeferredPayments();
PoolBase::Clean(PT_ALL);
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index 9d74d28e5e..a9506ce75f 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -38,6 +38,7 @@
#include "core/container_func.hpp"
#include "news_func.h"
#include "scope.h"
+#include "newgrf_newsignals.h"
#include "table/strings.h"
#include "table/railtypes.h"
@@ -78,28 +79,8 @@ void ResetRailTypes()
_railtypes_hidden_mask = RAILTYPES_NONE;
}
-void ResolveRailTypeGUISprites(RailtypeInfo *rti)
+void ResolveRailTypeGUISignalSprites(RailtypeInfo *rti, uint8 style, PalSpriteID signals[SIGTYPE_END][2][2])
{
- SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
- if (cursors_base != 0) {
- rti->gui_sprites.build_ns_rail = cursors_base + 0;
- rti->gui_sprites.build_x_rail = cursors_base + 1;
- rti->gui_sprites.build_ew_rail = cursors_base + 2;
- rti->gui_sprites.build_y_rail = cursors_base + 3;
- rti->gui_sprites.auto_rail = cursors_base + 4;
- rti->gui_sprites.build_depot = cursors_base + 5;
- rti->gui_sprites.build_tunnel = cursors_base + 6;
- rti->gui_sprites.convert_rail = cursors_base + 7;
- rti->cursor.rail_ns = cursors_base + 8;
- rti->cursor.rail_swne = cursors_base + 9;
- rti->cursor.rail_ew = cursors_base + 10;
- rti->cursor.rail_nwse = cursors_base + 11;
- rti->cursor.autorail = cursors_base + 12;
- rti->cursor.depot = cursors_base + 13;
- rti->cursor.tunnel = cursors_base + 14;
- rti->cursor.convert = cursors_base + 15;
- }
-
/* Array of default GUI signal sprite numbers. */
const SpriteID _signal_lookup[2][SIGTYPE_END] = {
{SPR_IMG_SIGNAL_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT,
@@ -129,26 +110,51 @@ void ResolveRailTypeGUISprites(RailtypeInfo *rti)
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, CSSC_GUI).sprite;
+ PalSpriteID red = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 0, CSSC_GUI, style).sprite;
if (red.sprite != 0) {
- rti->gui_sprites.signals[type][var][0] = { red.sprite + SIGNAL_TO_SOUTH, red.pal };
+ signals[type][var][0] = { red.sprite + SIGNAL_TO_SOUTH, red.pal };
} else {
- rti->gui_sprites.signals[type][var][0] = { default_sprite(var, type), PAL_NONE };
+ signals[type][var][0] = { default_sprite(var, type), PAL_NONE };
}
if (type == SIGTYPE_NO_ENTRY) {
- rti->gui_sprites.signals[type][var][1] = rti->gui_sprites.signals[type][var][0];
+ signals[type][var][1] = signals[type][var][0];
continue;
}
- PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, CSSC_GUI).sprite;
+ PalSpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, 255, CSSC_GUI, style).sprite;
if (green.sprite != 0) {
- rti->gui_sprites.signals[type][var][1] = { green.sprite + SIGNAL_TO_SOUTH, green.pal };
+ signals[type][var][1] = { green.sprite + SIGNAL_TO_SOUTH, green.pal };
} else {
- rti->gui_sprites.signals[type][var][1] = { default_sprite(var, type) + 1, PAL_NONE };
+ signals[type][var][1] = { default_sprite(var, type) + 1, PAL_NONE };
}
}
}
}
+void ResolveRailTypeGUISprites(RailtypeInfo *rti)
+{
+ SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
+ if (cursors_base != 0) {
+ rti->gui_sprites.build_ns_rail = cursors_base + 0;
+ rti->gui_sprites.build_x_rail = cursors_base + 1;
+ rti->gui_sprites.build_ew_rail = cursors_base + 2;
+ rti->gui_sprites.build_y_rail = cursors_base + 3;
+ rti->gui_sprites.auto_rail = cursors_base + 4;
+ rti->gui_sprites.build_depot = cursors_base + 5;
+ rti->gui_sprites.build_tunnel = cursors_base + 6;
+ rti->gui_sprites.convert_rail = cursors_base + 7;
+ rti->cursor.rail_ns = cursors_base + 8;
+ rti->cursor.rail_swne = cursors_base + 9;
+ rti->cursor.rail_ew = cursors_base + 10;
+ rti->cursor.rail_nwse = cursors_base + 11;
+ rti->cursor.autorail = cursors_base + 12;
+ rti->cursor.depot = cursors_base + 13;
+ rti->cursor.tunnel = cursors_base + 14;
+ rti->cursor.convert = cursors_base + 15;
+ }
+
+ ResolveRailTypeGUISignalSprites(rti, 0, rti->gui_sprites.signals);
+}
+
/**
* Compare railtypes based on their sorting order.
* @param first The railtype to compare to.
@@ -215,6 +221,10 @@ void UpdateRailGuiSprites()
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
ResolveRailTypeGUISprites(&_railtypes[rt]);
}
+
+ for (uint8 style = 0; style < _num_new_signal_styles; style++) {
+ ResolveRailTypeGUISignalSprites(nullptr, style + 1, _new_signal_styles[style].signals);
+ }
}
/**
@@ -222,15 +232,13 @@ void UpdateRailGuiSprites()
*/
void InitRailTypes()
{
- for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
- RailtypeInfo *rti = &_railtypes[rt];
- ResolveRailTypeGUISprites(rti);
- if (HasBit(rti->flags, RTF_HIDDEN)) SetBit(_railtypes_hidden_mask, rt);
- }
+ UpdateRailGuiSprites();
_sorted_railtypes.clear();
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
- if (_railtypes[rt].label != 0 && !HasBit(_railtypes_hidden_mask, rt)) {
+ bool hidden = HasBit(_railtypes[rt].flags, RTF_HIDDEN);
+ if (hidden) SetBit(_railtypes_hidden_mask, rt);
+ if (_railtypes[rt].label != 0 && !hidden) {
_sorted_railtypes.push_back(rt);
}
}
@@ -1455,6 +1463,7 @@ static void ReReserveTrainPath(Train *v)
* - p1 = (bit 15-16)-cycle the signal direction this many times
* - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type
* - p1 = (bit 18) - permit creation of/conversion to bidirectionally signalled bridges/tunnels
+ * - p1 = (bit 19-22)-signal style
* @param p2 used for CmdBuildManySignals() to copy direction of first signal
* @param text unused
* @return the cost of this operation or an error
@@ -1471,6 +1480,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
uint which_signals = GB(p1, 9, 6);
+ uint signal_style = std::min(GB(p1, 19, 4), _num_new_signal_styles);
+
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsSignalTypeUnsuitableForRealisticBraking(sigtype)) return CMD_ERROR;
/* You can only build signals on plain rail tiles or tunnel/bridges, and the selected track must exist */
@@ -1498,6 +1509,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
bool bidirectional = HasBit(p1, 18) && (sigtype == SIGTYPE_PBS);
cost = CommandCost();
bool flip_variant = false;
+ bool change_style = false;
bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY);
Trackdir entrance_td = TrackExitdirToTrackdir(track, GetTunnelBridgeDirection(tile));
bool p2_signal_in = p2 & SignalAlongTrackdir(entrance_td);
@@ -1513,6 +1525,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (!p2_active) {
if (convert_signal) {
will_be_bidi = bidirectional && !ctrl_pressed;
+ change_style = (signal_style != GetTunnelBridgeSignalStyle(tile));
} else if (ctrl_pressed) {
will_be_bidi = false;
}
@@ -1522,6 +1535,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if ((p2_active && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) {
flip_variant = true;
+ }
+ if (flip_variant || change_style) {
cost = CommandCost(EXPENSES_CONSTRUCTION, ((_price[PR_BUILD_SIGNALS] * (will_be_bidi ? 2 : 1)) + (_price[PR_CLEAR_SIGNALS] * (is_bidi ? 2 : 1))) *
((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1
} else if (is_bidi != will_be_bidi) {
@@ -1588,6 +1603,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
remove_pbs_bidi();
}
}
+ if (change_style) SetTunnelBridgeSignalStyle(tile, tile_exit, signal_style);
} else if (ctrl_pressed) {
SetTunnelBridgePBS(tile, !IsTunnelBridgePBS(tile));
SetTunnelBridgePBS(tile_exit, IsTunnelBridgePBS(tile));
@@ -1611,7 +1627,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
}
} else if (p2_signal_in != p2_signal_out) {
- /* If signal only on one side build accoringly one-way tunnel/bridge. */
+ /* If signal only on one side build accordingly one-way tunnel/bridge. */
if (p2_signal_in) {
ClearBridgeTunnelSignalSimulation(tile_exit, tile);
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
@@ -1625,6 +1641,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE);
SetTunnelBridgePBS(tile, is_pbs);
SetTunnelBridgePBS(tile_exit, is_pbs);
+ SetTunnelBridgeSignalStyle(tile, tile_exit, signal_style);
if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi();
}
}
@@ -1657,14 +1674,14 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
/* build new signals */
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
} else {
- if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
- /* convert signals <-> semaphores */
+ if (p2 != 0 && (sigvar != GetSignalVariant(tile, track) || signal_style != GetSignalStyle(tile, track))) {
+ /* convert signals <-> semaphores and/or change style */
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
} else if (convert_signal) {
/* convert button pressed */
- if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
- /* convert electric <-> semaphore */
+ if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar || signal_style != GetSignalStyle(tile, track)) {
+ /* convert electric <-> semaphore and/or change style */
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
} else {
/* it is free to change signal type: normal-pre-exit-combo */
@@ -1698,6 +1715,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetPresentSignals(tile, 0); // no signals built by default
SetSignalType(tile, track, sigtype);
SetSignalVariant(tile, track, sigvar);
+ SetSignalStyle(tile, track, signal_style);
}
/* Subtract old signal infrastructure count. */
@@ -1727,6 +1745,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
}
SetSignalType(tile, track, sigtype);
SetSignalVariant(tile, track, sigvar);
+ SetSignalStyle(tile, track, signal_style);
if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
}
@@ -1770,6 +1789,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (IsPresignalProgrammable(tile, track))
FreeSignalProgram(SignalReference(tile, track));
SetSignalType(tile, track, sigtype);
+ SetSignalStyle(tile, track, signal_style);
}
/* Add new signal infrastructure count. */
@@ -1875,6 +1895,7 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal
* - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill
* - p2 = (bit 7- 9) - default signal type
* - p2 = (bit 10) - 0 = keep fixed distance, 1 = minimise gaps between signals
+ * - p2 = (bit 11-14) - default signal style
* - p2 = (bit 24-31) - user defined signals_density
* @param text unused
* @return the cost of this operation or an error
@@ -1891,6 +1912,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin
bool autofill = HasBit(p2, 6);
bool minimise_gaps = HasBit(p2, 10);
byte signal_density = GB(p2, 24, 8);
+ uint8 signal_style = GB(p2, 11, 4);
if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
TileIndex end_tile = p1;
@@ -1927,6 +1949,8 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin
sigtype = GetSignalType(tile, track);
/* Don't but copy entry or exit-signal type */
if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
+
+ signal_style = GetSignalStyle(tile, track);
} else { // no signals exist, drag a two-way signal stretch
signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
}
@@ -1974,6 +1998,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin
SB(param1, 3, 1, mode);
SB(param1, 4, 1, semaphores);
SB(param1, 5, 3, sigtype);
+ SB(param1, 19, 4, signal_style);
if (!remove && signal_ctr == 0) SetBit(param1, 17);
/* Pick the correct orientation for the track direction */
@@ -2065,6 +2090,8 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin
* - p2 = (bit 5) - 0 = build, 1 = remove signals
* - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill
* - p2 = (bit 7- 9) - default signal type
+ * - p2 = (bit 10) - 0 = keep fixed distance, 1 = minimise gaps between signals
+ * - p2 = (bit 11-14) - default signal style
* - p2 = (bit 24-31) - user defined signals_density
* @param text unused
* @return the cost of this operation or an error
@@ -2144,6 +2171,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
TraceRestrictNotifySignalRemoval(end, end_track);
ClearBridgeTunnelSignalSimulation(end, tile);
ClearBridgeTunnelSignalSimulation(tile, end);
+ SetTunnelBridgeSignalStyle(tile, end, 0);
MarkBridgeOrTunnelDirty(tile);
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
AddSideToSignalBuffer(end, INVALID_DIAGDIR, GetTileOwner(tile));
@@ -2755,7 +2783,24 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign
aspect = 0;
}
- const CustomSignalSpriteResult result = GetCustomSignalSprite(rti, tile, type, variant, aspect, context, prog);
+ uint8 style = 0;
+ if (_num_new_signal_styles > 0) {
+ switch (context) {
+ case CSSC_TRACK:
+ style = GetSignalStyle(tile, track);
+ break;
+
+ case CSSC_TUNNEL_BRIDGE_ENTRANCE:
+ case CSSC_TUNNEL_BRIDGE_EXIT:
+ style = GetTunnelBridgeSignalStyle(tile);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ const CustomSignalSpriteResult result = GetCustomSignalSprite(rti, tile, type, variant, aspect, context, style, prog);
SpriteID sprite = result.sprite.sprite;
PaletteID pal = PAL_NONE;
bool is_custom_sprite = (sprite != 0);
@@ -3963,16 +4008,40 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
SignalType primary_signal;
SignalType secondary_signal;
+ int primary_style = -1;
+ int secondary_style = -1;
if (HasSignalOnTrack(tile, TRACK_UPPER)) {
primary_signal = GetSignalType(tile, TRACK_UPPER);
- secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
+ primary_style = GetSignalStyle(tile, TRACK_UPPER);
+ if (HasSignalOnTrack(tile, TRACK_LOWER)) {
+ secondary_signal = GetSignalType(tile, TRACK_LOWER);
+ secondary_style = GetSignalStyle(tile, TRACK_LOWER);
+ } else {
+ secondary_signal = primary_signal;
+ }
} else {
secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
+ primary_style = GetSignalStyle(tile, TRACK_LOWER);
}
td->str = signal_type[secondary_signal][primary_signal];
+ if (primary_style > 0 || secondary_style > 0) {
+ /* Add suffix about signal style */
+ SetDParamX(td->dparam, 0, td->str);
+ td->dparam[1] = primary_style == 0 ? STR_BUILD_SIGNAL_DEFAULT_STYLE : _new_signal_styles[primary_style - 1].name;
+ if (secondary_style >= 0) {
+ td->dparam[2] = secondary_style == 0 ? STR_BUILD_SIGNAL_DEFAULT_STYLE : _new_signal_styles[secondary_style - 1].name;
+ td->str = STR_LAI_RAIL_DESCRIPTION_TRACK_SIGNAL_STYLE2;
+ } else {
+ td->str = STR_LAI_RAIL_DESCRIPTION_TRACK_SIGNAL_STYLE;
+ }
+ }
+
if (IsRestrictedSignal(tile)) {
+ td->dparam[3] = td->dparam[2];
+ td->dparam[2] = td->dparam[1];
+ td->dparam[1] = td->dparam[0];
SetDParamX(td->dparam, 0, td->str);
td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
}
diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp
index 8430f35ab9..31f9d95192 100644
--- a/src/rail_gui.cpp
+++ b/src/rail_gui.cpp
@@ -38,6 +38,7 @@
#include "string_func.h"
#include "tracerestrict.h"
#include "programmable_signals.h"
+#include "newgrf_newsignals.h"
#include "station_map.h"
#include "tunnelbridge_map.h"
@@ -57,6 +58,7 @@ static bool _trace_restrict_button; ///< trace restrict button in the s
static bool _program_signal_button; ///< program signal button in the signal GUI pressed
static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
+static uint8 _cur_signal_style; ///< set the signal style (for signal GUI)
static uint _cur_signal_button; ///< set the signal button (for signal GUI)
extern TileIndex _rail_track_endtile; // rail_cmd.cpp
@@ -294,6 +296,7 @@ static void GenericPlaceSignals(TileIndex tile)
SB(p1, 5, 3, _cur_signal_type);
SB(p1, 8, 1, _convert_signal_button);
SB(p1, 9, 6, cycle_types);
+ SB(p1, 19, 4, _cur_signal_style);
if (_cur_signal_type == SIGTYPE_NO_ENTRY) SB(p1, 15, 2, 1); // reverse default signal direction
} else {
SB(p1, 3, 1, _ctrl_pressed);
@@ -474,6 +477,7 @@ static void HandleAutoSignalPlacement()
SB(p2, 7, 3, _cur_signal_type);
SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance);
+ SB(p2, 11, 4, _cur_signal_style);
} else {
SB(p2, 3, 1, 0);
SB(p2, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
@@ -1807,6 +1811,7 @@ private:
bool progsig_ui_shown; ///< Whether programmable pre-signal UI is shown
bool realistic_braking_mode; ///< Whether realistic braking mode UI is shown
bool noentry_ui_shown; ///< Whether no-entry signal UI is shown
+ bool style_selector_shown; ///< Whether the style selector is shown
/**
* Draw dynamic a signal-sprite in a button in the signal GUI
@@ -1835,6 +1840,7 @@ private:
this->realistic_braking_mode = (_settings_game.vehicle.train_braking_model == TBM_REALISTIC);
this->progsig_ui_shown = _settings_client.gui.show_progsig_ui;
this->noentry_ui_shown = _settings_client.gui.show_noentrysig_ui;
+ this->style_selector_shown = _num_new_signal_styles > 0;
bool show_norm = this->realistic_braking_mode || this->all_signal_mode;
bool show_presig = !this->realistic_braking_mode && this->all_signal_mode;
@@ -1862,6 +1868,8 @@ private:
this->GetWidget(WID_BS_TOGGLE_SIZE_SEL)->SetDisplayedPlane(!this->realistic_braking_mode ? 0 : SZSP_NONE);
this->SetWidgetDisabledState(WID_BS_TOGGLE_SIZE, this->realistic_braking_mode);
+
+ this->GetWidget(WID_BS_STYLE_SEL)->SetDisplayedPlane(this->style_selector_shown ? 0 : SZSP_NONE);
}
void ClearRemoveState()
@@ -1894,17 +1902,25 @@ public:
this->sig_sprite_size.width = 0;
this->sig_sprite_size.height = 0;
this->sig_sprite_bottom_offset = 0;
- const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype);
- for (uint type = SIGTYPE_NORMAL; type < SIGTYPE_END; type++) {
- for (uint variant = SIG_ELECTRIC; variant <= SIG_SEMAPHORE; variant++) {
- for (uint lowered = 0; lowered < 2; lowered++) {
- Point offset;
- Dimension sprite_size = GetSpriteSize(rti->gui_sprites.signals[type][variant][lowered].sprite, &offset);
- this->sig_sprite_bottom_offset = std::max(this->sig_sprite_bottom_offset, sprite_size.height);
- this->sig_sprite_size.width = std::max(this->sig_sprite_size.width, sprite_size.width - offset.x);
- this->sig_sprite_size.height = std::max(this->sig_sprite_size.height, sprite_size.height - offset.y);
+
+ auto process_signals = [&](const PalSpriteID signals[SIGTYPE_END][2][2]) {
+ for (uint type = SIGTYPE_NORMAL; type < SIGTYPE_END; type++) {
+ for (uint variant = SIG_ELECTRIC; variant <= SIG_SEMAPHORE; variant++) {
+ for (uint lowered = 0; lowered < 2; lowered++) {
+ Point offset;
+ SpriteID spr = signals[type][variant][lowered].sprite;
+ if (spr == 0) continue;
+ Dimension sprite_size = GetSpriteSize(spr, &offset);
+ this->sig_sprite_bottom_offset = std::max(this->sig_sprite_bottom_offset, sprite_size.height);
+ this->sig_sprite_size.width = std::max(this->sig_sprite_size.width, sprite_size.width - offset.x);
+ this->sig_sprite_size.height = std::max(this->sig_sprite_size.height, sprite_size.height - offset.y);
+ }
}
}
+ };
+ process_signals(GetRailTypeInfo(_cur_railtype)->gui_sprites.signals);
+ for (uint i = 0; i < _num_new_signal_styles; i++) {
+ process_signals(_new_signal_styles[i].signals);
}
}
@@ -1927,6 +1943,10 @@ public:
case WID_BS_DRAG_SIGNALS_DENSITY_LABEL:
SetDParam(0, _settings_client.gui.drag_signals_density);
break;
+
+ case WID_BS_STYLE:
+ SetDParam(0, _cur_signal_style == 0 ? STR_BUILD_SIGNAL_DEFAULT_STYLE : _new_signal_styles[_cur_signal_style - 1].name);
+ break;
}
}
@@ -1936,7 +1956,13 @@ public:
/* 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.
- PalSpriteID sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)];
+ PalSpriteID sprite = { 0, 0 };
+ if (_cur_signal_style > 0) {
+ sprite = _new_signal_styles[_cur_signal_style - 1].signals[type][var][this->IsWidgetLowered(widget)];
+ }
+ if (sprite.sprite == 0) {
+ sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)];
+ }
this->DrawSignalSprite(widget, sprite);
}
@@ -2036,12 +2062,34 @@ public:
this->ReInit();
break;
+ case WID_BS_STYLE: {
+ DropDownList list;
+ list.emplace_back(new DropDownListStringItem(STR_BUILD_SIGNAL_DEFAULT_STYLE, 0, false));
+ for (uint i = 0; i < _num_new_signal_styles; i++) {
+ list.emplace_back(new DropDownListStringItem(_new_signal_styles[i].name, i + 1, false));
+ }
+ ShowDropDownList(this, std::move(list), _cur_signal_style, widget);
+ break;
+ }
+
default: break;
}
this->InvalidateData();
}
+ virtual void OnDropdownSelect(int widget, int index) override
+ {
+ switch (widget) {
+ case WID_BS_STYLE:
+ _cur_signal_style = std::min(index, _num_new_signal_styles);
+ this->SetDirty();
+ break;
+
+ default: break;
+ }
+ }
+
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
@@ -2059,9 +2107,12 @@ 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 (_cur_signal_style > _num_new_signal_styles) _cur_signal_style = 0;
+
if (this->all_signal_mode != (_settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL) || this->progsig_ui_shown != _settings_client.gui.show_progsig_ui ||
this->realistic_braking_mode != (_settings_game.vehicle.train_braking_model == TBM_REALISTIC) ||
- this->noentry_ui_shown != _settings_client.gui.show_noentrysig_ui) {
+ this->noentry_ui_shown != _settings_client.gui.show_noentrysig_ui ||
+ this->style_selector_shown != (_num_new_signal_styles > 0)) {
this->SetSignalUIMode();
this->ReInit();
}
@@ -2164,6 +2215,9 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), EndContainer(), SetFill(1, 1),
EndContainer(),
EndContainer(),
+ NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_STYLE_SEL),
+ NWidget(WWT_DROPDOWN, COLOUR_DARK_GREEN, WID_BS_STYLE), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_BUILD_SIGNAL_STYLE_TOOLTIP),
+ EndContainer(),
EndContainer(),
};
diff --git a/src/rail_map.h b/src/rail_map.h
index 4535774237..b298f8f1bc 100644
--- a/src/rail_map.h
+++ b/src/rail_map.h
@@ -397,6 +397,20 @@ static inline void SetSignalAspect(TileIndex t, Track track, uint8 aspect)
SB(_me[t].m7, pos, 3, aspect);
}
+static inline uint8 GetSignalStyle(TileIndex t, Track track)
+{
+ assert_tile(GetRailTileType(t) == RAIL_TILE_SIGNALS, t);
+ byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 4 : 0;
+ return GB(_me[t].m6, pos, 4);
+}
+
+static inline void SetSignalStyle(TileIndex t, Track track, uint8 style)
+{
+ assert_tile(GetRailTileType(t) == RAIL_TILE_SIGNALS, t);
+ byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 4 : 0;
+ SB(_me[t].m6, pos, 4, style);
+}
+
/**
* Set the states of the signals (Along/AgainstTrackDir)
* @param tile the tile to set the states for
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index ba5e1dfb25..271a18c11b 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -4064,6 +4064,19 @@ bool AfterLoadGame()
ApplyIndustryTileAnimMasking();
}
+ if (SlXvIsFeatureMissing(XSLFI_NEW_SIGNAL_STYLES)) {
+ for (TileIndex t = 0; t < map_size; t++) {
+ if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) {
+ /* clear signal style field */
+ _me[t].m6 = 0;
+ }
+ if (IsRailTunnelBridgeTile(t)) {
+ /* Clear signal style is non-zero flag */
+ ClrBit(_m[t].m3, 7);
+ }
+ }
+ }
+
InitializeRoadGUI();
/* This needs to be done after conversion. */
@@ -4198,4 +4211,6 @@ void ReloadNewGRFData()
AfterLoadTemplateVehiclesUpdateImages();
AfterLoadTemplateVehiclesUpdateProperties();
UpdateAllAnimatedTileSpeeds();
+
+ InvalidateWindowData(WC_BUILD_SIGNAL, 0);
}
diff --git a/src/saveload/bridge_signal_sl.cpp b/src/saveload/bridge_signal_sl.cpp
index 0347b2a033..70c66e4546 100644
--- a/src/saveload/bridge_signal_sl.cpp
+++ b/src/saveload/bridge_signal_sl.cpp
@@ -50,8 +50,25 @@ static void Save_XBSS()
}
}
+static void Load_XBST()
+{
+ size_t count = SlGetFieldLength() / sizeof(uint32);
+ for (size_t i = 0; i < count; i++) {
+ _bridge_signal_style_map.insert(SlReadUint32());
+ }
+}
+
+static void Save_XBST()
+{
+ SlSetLength(_bridge_signal_style_map.size() * sizeof(uint32));
+ for (uint32 val : _bridge_signal_style_map) {
+ SlWriteUint32(val);
+ }
+}
+
extern const ChunkHandler bridge_signal_chunk_handlers[] = {
{ 'XBSS', Save_XBSS, Load_XBSS, nullptr, nullptr, CH_SPARSE_ARRAY },
+ { 'XBST', Save_XBST, Load_XBST, nullptr, nullptr, CH_RIFF },
};
extern const ChunkHandlerTable _bridge_signal_chunk_handlers(bridge_signal_chunk_handlers);
diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp
index 61d03787e6..67951d4067 100644
--- a/src/saveload/extended_ver_sl.cpp
+++ b/src/saveload/extended_ver_sl.cpp
@@ -173,6 +173,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr },
{ XSLFI_GRF_ROADSTOPS, XSCF_NULL, 1, 1, "grf_road_stops", nullptr, nullptr, nullptr },
{ XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr },
+ { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 1, 1, "new_signal_styles", nullptr, nullptr, "XBST" },
{ XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
};
diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h
index a134ca2f3a..9a7fa05deb 100644
--- a/src/saveload/extended_ver_sl.h
+++ b/src/saveload/extended_ver_sl.h
@@ -126,6 +126,7 @@ enum SlXvFeatureIndex {
XSLFI_RV_ORDER_EXTRA_FLAGS, ///< Road vehicle order extra flags
XSLFI_GRF_ROADSTOPS, ///< NewGRF road stops
XSLFI_INDUSTRY_ANIM_MASK, ///< Industry tile animation masking
+ XSLFI_NEW_SIGNAL_STYLES, ///< New signal styles
XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64
diff --git a/src/saveload/tunnel_sl.cpp b/src/saveload/tunnel_sl.cpp
index 281fabc9f1..769152ca08 100644
--- a/src/saveload/tunnel_sl.cpp
+++ b/src/saveload/tunnel_sl.cpp
@@ -20,6 +20,7 @@ static const SaveLoad _tunnel_desc[] = {
SLE_CONDVAR(Tunnel, tile_s, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION),
SLE_CONDVAR(Tunnel, height, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION),
SLE_CONDVAR(Tunnel, is_chunnel, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION),
+ SLE_CONDVAR_X(Tunnel, style, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEW_SIGNAL_STYLES)),
};
static void Save_TUNN()
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index 7125708a3a..780c33f40f 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -885,6 +885,7 @@ static const NIVariable _niv_signals[] = {
NIV(0x40, "terrain type"),
NIV(A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "restriction info"),
NIV(A2VRI_SIGNALS_SIGNAL_CONTEXT, "context"),
+ NIV(A2VRI_SIGNALS_SIGNAL_STYLE, "style"),
NIV_END()
};
@@ -901,10 +902,21 @@ class NIHSignals : public NIHelper {
{
extern TraceRestrictProgram *GetFirstTraceRestrictProgramOnTile(TileIndex t);
CustomSignalSpriteContext ctx = CSSC_TRACK;
+ uint8 style = 0;
if (IsTunnelBridgeWithSignalSimulation(index)) {
ctx = IsTunnelBridgeSignalSimulationEntrance(index) ? CSSC_TUNNEL_BRIDGE_ENTRANCE : CSSC_TUNNEL_BRIDGE_EXIT;
+ style = GetTunnelBridgeSignalStyle(index);
+ } else if (IsTileType(index, MP_RAILWAY) && HasSignals(index)) {
+ TrackBits bits = GetTrackBits(index);
+ do {
+ Track track = RemoveFirstTrack(&bits);
+ if (HasSignalOnTrack(index, track)) {
+ style = GetSignalStyle(index, track);
+ break;
+ }
+ } while (bits != TRACK_BIT_NONE);
}
- NewSignalsResolverObject ro(nullptr, index, TCX_NORMAL, 0, 0, ctx, GetFirstTraceRestrictProgramOnTile(index));
+ NewSignalsResolverObject ro(nullptr, index, TCX_NORMAL, 0, 0, ctx, style, GetFirstTraceRestrictProgramOnTile(index));
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
diff --git a/src/tile_cmd.h b/src/tile_cmd.h
index 396c079e3e..829d5cfcbc 100644
--- a/src/tile_cmd.h
+++ b/src/tile_cmd.h
@@ -59,7 +59,7 @@ struct TileDesc {
StringID airport_name; ///< Name of the airport
StringID airport_tile_name; ///< Name of the airport tile
const char *grf; ///< newGRF used for the tile contents
- uint64 dparam[2]; ///< Parameters of the \a str string
+ uint64 dparam[4]; ///< Parameters of the \a str string
StringID railtype; ///< Type of rail on the tile.
StringID railtype2; ///< Type of second rail on the tile.
uint16 rail_speed; ///< Speed limit of rail (bridges and track)
diff --git a/src/tunnel_base.h b/src/tunnel_base.h
index c35a5f9ee8..faf6b65035 100644
--- a/src/tunnel_base.h
+++ b/src/tunnel_base.h
@@ -24,6 +24,7 @@ struct Tunnel : TunnelPool::PoolItem<&_tunnel_pool> {
TileIndex tile_s; // South tile of tunnel.
uint8 height; // Tunnel height
bool is_chunnel; // Whether this tunnel is a chunnel
+ uint8 style; // Style (new signals) of tunnel.
Tunnel() {}
~Tunnel();
diff --git a/src/tunnel_map.cpp b/src/tunnel_map.cpp
index a98cfddb5e..e217b60c00 100644
--- a/src/tunnel_map.cpp
+++ b/src/tunnel_map.cpp
@@ -133,3 +133,23 @@ bool IsTunnelInWay(TileIndex tile, int z, IsTunnelInWayFlags flags)
{
return IsTunnelInWaySingleAxis(tile, z, flags, false, 1) || IsTunnelInWaySingleAxis(tile, z, flags, true, TileOffsByDiagDir(DIAGDIR_SE));
}
+
+void SetTunnelSignalStyle(TileIndex t, TileIndex end, uint8 style)
+{
+ if (style == 0) {
+ /* Style already 0 */
+ if (!HasBit(_m[t].m3, 7)) return;
+
+ ClrBit(_m[t].m3, 7);
+ ClrBit(_m[end].m3, 7);
+ } else {
+ SetBit(_m[t].m3, 7);
+ SetBit(_m[end].m3, 7);
+ }
+ Tunnel::GetByTile(t)->style = style;
+}
+
+uint8 GetTunnelSignalStyleExtended(TileIndex t)
+{
+ return Tunnel::GetByTile(t)->style;
+}
diff --git a/src/tunnel_map.h b/src/tunnel_map.h
index 3feed2cbcb..1354492645 100644
--- a/src/tunnel_map.h
+++ b/src/tunnel_map.h
@@ -111,6 +111,16 @@ static inline void SetTunnelIndex(TileIndex t, TunnelID id)
_m[t].m2 = (id >= TUNNEL_ID_MAP_LOOKUP) ? TUNNEL_ID_MAP_LOOKUP : id;
}
+void SetTunnelSignalStyle(TileIndex t, TileIndex end, uint8 style);
+
+static inline uint8 GetTunnelSignalStyle(TileIndex t)
+{
+ if (likely(!HasBit(_m[t].m3, 7))) return 0;
+
+ extern uint8 GetTunnelSignalStyleExtended(TileIndex t);
+ return GetTunnelSignalStyleExtended(t);
+}
+
/**
* Makes a road tunnel entrance
* @param t the entrance of the tunnel
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 7432584dca..143d39dc35 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -50,6 +50,7 @@
#include "station_func.h"
#include "tracerestrict.h"
#include "newgrf_roadstop.h"
+#include "newgrf_newsignals.h"
#include "table/strings.h"
#include "table/bridge_land.h"
@@ -1438,8 +1439,14 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
}
DirtyAllCompanyInfrastructureWindows();
- if (IsTunnelBridgeSignalSimulationEntrance(tile)) ClearBridgeEntranceSimulatedSignals(tile);
- if (IsTunnelBridgeSignalSimulationEntrance(endtile)) ClearBridgeEntranceSimulatedSignals(endtile);
+ if (IsTunnelBridgeSignalSimulationEntrance(tile)) {
+ ClearBridgeEntranceSimulatedSignals(tile);
+ SetBridgeSignalStyle(tile, 0);
+ }
+ if (IsTunnelBridgeSignalSimulationEntrance(endtile)) {
+ ClearBridgeEntranceSimulatedSignals(endtile);
+ SetBridgeSignalStyle(endtile, 0);
+ }
DoClearSquare(tile);
DoClearSquare(endtile);
@@ -1759,7 +1766,7 @@ static void DrawTunnelBridgeRampSingleSignal(const TileInfo *ti, bool is_green,
}
bool show_restricted = IsTunnelBridgeRestrictedSignal(ti->tile);
const TraceRestrictProgram *prog = show_restricted ? GetExistingTraceRestrictProgram(ti->tile, FindFirstTrack(GetAcrossTunnelBridgeTrackBits(ti->tile))) : nullptr;
- const CustomSignalSpriteResult result = GetCustomSignalSprite(rti, ti->tile, type, variant, aspect, show_exit ? CSSC_TUNNEL_BRIDGE_EXIT : CSSC_TUNNEL_BRIDGE_ENTRANCE, prog);
+ const CustomSignalSpriteResult result = GetCustomSignalSprite(rti, ti->tile, type, variant, aspect, show_exit ? CSSC_TUNNEL_BRIDGE_EXIT : CSSC_TUNNEL_BRIDGE_ENTRANCE, GetTunnelBridgeSignalStyle(ti->tile), prog);
PalSpriteID sprite = result.sprite;
bool is_custom_sprite = (sprite.sprite != 0);
@@ -1887,7 +1894,7 @@ static void DrawBridgeSignalOnMiddlePart(const TileInfo *ti, TileIndex bridge_st
}
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(bridge_start_tile));
- PalSpriteID sprite = GetCustomSignalSprite(rti, bridge_start_tile, SIGTYPE_NORMAL, variant, aspect, CSSC_BRIDGE_MIDDLE).sprite;
+ PalSpriteID sprite = GetCustomSignalSprite(rti, bridge_start_tile, SIGTYPE_NORMAL, variant, aspect, CSSC_BRIDGE_MIDDLE, GetBridgeSignalStyle(bridge_start_tile)).sprite;
if (sprite.sprite != 0) {
sprite.sprite += position;
@@ -2561,9 +2568,23 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
} else { // IsBridge(tile)
td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : IsTunnelBridgeWithSignalSimulation(tile) ? STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
}
- if (IsTunnelBridgeWithSignalSimulation(tile) && IsTunnelBridgeRestrictedSignal(tile)) {
- SetDParamX(td->dparam, 0, td->str);
- td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
+
+ if (tt == TRANSPORT_RAIL) {
+ uint8 style = GetTunnelBridgeSignalStyle(tile);
+ if (style > 0) {
+ /* Add suffix about signal style */
+ SetDParamX(td->dparam, 0, td->str);
+ td->dparam[1] = style == 0 ? STR_BUILD_SIGNAL_DEFAULT_STYLE : _new_signal_styles[style - 1].name;
+ td->str = STR_LAI_RAIL_DESCRIPTION_TRACK_SIGNAL_STYLE;
+ }
+ if (IsTunnelBridgeWithSignalSimulation(tile) && IsTunnelBridgeRestrictedSignal(tile)) {
+ td->dparam[3] = td->dparam[2];
+ td->dparam[2] = td->dparam[1];
+ td->dparam[1] = td->dparam[0];
+ SetDParamX(td->dparam, 0, td->str);
+ SetDParamX(td->dparam, 0, td->str);
+ td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
+ }
}
td->owner[0] = GetTileOwner(tile);
@@ -2915,6 +2936,16 @@ void SubtractRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
UpdateRailTunnelBridgeInfrastructure(Company::GetIfValid(GetTileOwner(begin)), begin, end, false);
}
+void SetTunnelBridgeSignalStyleExtended(TileIndex t, TileIndex end, uint8 style)
+{
+ if (IsTunnel(t)) {
+ SetTunnelSignalStyle(t, end, style);
+ } else {
+ SetBridgeSignalStyle(t, style);
+ SetBridgeSignalStyle(end, style);
+ }
+}
+
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
{
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h
index 65aafed95b..d1ab44cc05 100644
--- a/src/tunnelbridge_map.h
+++ b/src/tunnelbridge_map.h
@@ -601,6 +601,27 @@ static inline Trackdir GetTunnelBridgeEntranceTrackdir(TileIndex t)
return GetTunnelBridgeEntranceTrackdir(t, GetTunnelBridgeDirection(t));
}
+static inline void SetTunnelBridgeSignalStyle(TileIndex t, TileIndex end, uint8 style)
+{
+ if (style == 0 && !HasBit(_m[t].m3, 7)) return;
+
+ extern void SetTunnelBridgeSignalStyleExtended(TileIndex t, TileIndex end, uint8 style);
+ SetTunnelBridgeSignalStyleExtended(t, end, style);
+}
+
+static inline uint8 GetTunnelBridgeSignalStyle(TileIndex t)
+{
+ if (likely(!HasBit(_m[t].m3, 7))) return 0;
+
+ if (IsTunnel(t)) {
+ extern uint8 GetTunnelSignalStyleExtended(TileIndex t);
+ return GetTunnelSignalStyleExtended(t);
+ } else {
+ extern uint8 GetBridgeSignalStyleExtended(TileIndex t);
+ return GetBridgeSignalStyleExtended(t);
+ }
+}
+
void AddRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end);
void SubtractRailTunnelBridgeInfrastructure(Company *c, TileIndex begin, TileIndex end);
void AddRailTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
diff --git a/src/widgets/rail_widget.h b/src/widgets/rail_widget.h
index be8dbb8490..286ec18534 100644
--- a/src/widgets/rail_widget.h
+++ b/src/widgets/rail_widget.h
@@ -117,6 +117,8 @@ enum BuildSignalWidgets {
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
+ WID_BS_STYLE, ///< Style selection dropdown
+ WID_BS_STYLE_SEL, ///< NWID_SELECTION for WID_BS_STYLE
};
/** Widgets of the #BuildRailDepotWindow class. */