Initial implementation of NewGRF custom signal styles

pull/400/head
Jonathan G Rennison 2 years ago
parent 098bb74ed2
commit 6e4c4b35e7

@ -508,6 +508,8 @@
<li>m3 bits 7..4: bit set = signal 3..0 present</li>
<li>m4 bits 7..4: bit clear = signal 3..0 shows red</li>
<li style="color: blue">m6 bits 7..4: signal style for signal 0 and 1</li>
<li style="color: blue">m6 bits 3..0: signal style for signal 2 and 3</li>
<li style="color: blue">m7 bits 5..3: signal aspect for signal 0 or 1 (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>
<li style="color: blue">m7 bits 2..0: signal aspect for signal 2 or 3 (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>
</ul>
@ -1753,6 +1755,7 @@
<ul>
<li>m2 bit 15: for bridge entrances only: storage for visual red/green state of signals starting from 15 is allocated outside the map array</li>
<li>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</li>
<li>m3 bit 7: the signal style is non-zero (style stored outside the map array)</li>
<li>m3 bit 6: the entrance and/or exit signals on this tile are restricted (tracerestrict patch)</li>
<li>m3 bits 5..3: entrance signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>
<li>m3 bits 2..0: exit signal aspect (only valid if signal is present and not red, and multi-aspect signalling is in effect)</li>

@ -103,7 +103,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO OOOO</span> </td>
<td class="bits"><span class="free">OOOO</span> <span class="used" title="Ground type: fences, snow, desert">XXXX</span></td>
<td class="bits"><span class="used" title="Rail tile type: rail, rail with signals, depot">OO</span> <span class="used" title="Track pieces">XXXXXX</span></td>
<td class="bits" rowspan=3><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits" rowspan=2><span class="free">OOOO</span> <span class="patch" title="Secondary railway type (used for lower or right track when two parallel tracks on tile)">PPPP PP</span><span class="used" title="Railway type">XX XXXX</span></td>
</tr>
@ -113,6 +113,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="used" title="Signals present">XXXX</span> <span class="free">OOOO</span></td>
<td class="bits"><span class="used" title="Signals colors">XXXX</span> <span class="used" title="Ground type: fences, snow, desert">XXXX</span></td>
<td class="bits"><span class="used" title="Rail tile type: rail, rail with signals, depot">O1</span> <span class="used" title="Track pieces">XXXXXX</span></td>
<td class="bits"><span class="patch" title="Signal styles">PPPP PPPP</span></td>
<td class="bits"><span class="free">OO</span> <span class="patch" title="Signal aspects">PPPPPP</span></td>
</tr>
<tr>
@ -122,6 +123,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO</span> <span class="used" title="Ground type: fences, snow, desert (fences on depot are not valid)">XXXX</span></td>
<td class="bits"><span class="used" title="Rail tile type: rail, rail with signals, depot">11</span><span class="free">O</span><span class="used" title="PBS reservation">X</span> <span class="free">OO</span><span class="used" title="Depot exit direction">XX</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO OO</span><span class="used" title="Railway type">XX XXXX</span></td>
</tr>
<tr>
@ -292,7 +294,7 @@ the array so you can quickly see what is used and what is not.
<td class="caption">tunnel entrance</td>
<td class="bits" rowspan=3><span class="free">OOO</span> <span class="used" title="Owner">XXXXX</span></td>
<td class="bits"><span class="patch-pool" title="Tunnel index on pool (or overflow sentinel)">PPPP PPPP PPPP PPPP</span></td>
<td class="bits" rowspan=4><span class="rearrange" title="Owner of tram (road only; a rearrangement can free some of these bits)">XXXX</span> <span class="free">OOOO</span><br /><span class="free">O</span><span class="patch" title="Routing restrictions present on entrance/exit signal(s)">P</span> <span class="patch" title="Entrance/exit signal aspects (rail only)">PPPPPP</span></td>
<td class="bits" rowspan=4><span class="rearrange" title="Owner of tram (road only; a rearrangement can free some of these bits)">XXXX</span> <span class="free">OOOO</span><br /><span class="patch" title="New signal style is non-zero (rail only)">P</span> <span class="patch" title="Routing restrictions present on entrance/exit signal(s)">P</span> <span class="patch" title="Entrance/exit signal aspects (rail only)">PPPPPP</span></td>
<td class="bits"><span class="free">OO</span><span class="used" title="Road type">XX XXXX</span></td>
<td class="bits"><span class="used" title="Bridge or tunnel bit">O</span><span class="patch" title="Signal simulation mode (rail only)">PP</span><span class="rearrange" title="PBS reservation (rail; a rearrangement can free some of these bits)">X</span> <span class="used" title="Transport type">XX</span> <span class="used" title="Direction of the tunnel/bridge">XX</span></td>
<td class="bits"><span class="patch" title="PBS mode, exit signal state">PP</span><span class="free">OO OO</span><span class="patch" title="Semaphore/light mode, entrance signal state">PP</span></td>

@ -445,6 +445,26 @@ item (FEAT_GLOBALVARS) {
N.B. Realistic braking must be enabled for additional signal aspects to be used
</td>
</tr>
<tr><td>define_style</td><td>1 - 255</td>
<td>
Define a custom signal style<br />
Signals using this style will only use this GRF, or the default graphics if no graphics are returned.<br />
The value supplied is returned in the signal_style variable.<br />
This property (and related signal style properties) may be used more than once.<br />
The total number of custom signal styles in a game is currently limited to 15.
</td>
</tr>
<tr><td>style_name</td><td>string</td>
<td>
Set the name of the most recently defined style (defined using the define_style property).<br />
This property should be used if using the define_style property, as otherwise the style will have no name.
</td>
</tr>
<tr><td>no_default_style</td><td>0 or 1</td>
<td>
When enabled, custom signal graphics from this GRF are only used for custom signal styles, not the default style
</td>
</tr>
</table>
<br />
<table>
@ -489,6 +509,11 @@ item (FEAT_GLOBALVARS) {
Above signal context variables in one variable (all of the signals_signal_context variable)
</td>
</tr>
<tr><td>signal_style</td><td>0 - 255</td>
<td>
The style ID defined using define_style for signals using a custom style, or 0 for signals using the default style
</td>
</tr>
</table>
<p>
Custom signal sprites example:

@ -416,6 +416,28 @@
The provided value is currently clamped to be within the range 0 - 6 (inclusive).</p>
<p>N.B. Realistic braking must be enabled for additional signal aspects to be used.</p>
<p>This is indicated by the feature name: <font face="monospace">action0_signals_extra_aspects</font>, version 1</p>
<h4 id="signals_define_style">Define a custom signal style (mappable property: signals_define_style)</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 />
This defines a new signal style. Signals using this style will only use this GRF, or the default graphics if no graphics are returned.</p>
<p>The total number of custom signal styles in a game is currently limited to 15.</p>
<p>The property length is 1 byte. This is the local ID of the style which is returned in the <a href="#signals_signal_style">signals_signal_style</a> variable.<br />
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_style</font>, version 1</p>
<h4 id="signals_style_name">Set custom signal style name (mappable property: signals_style_name)</h4>
<p>This applies to the most recent custom signal style defined using the <a href="#signals_define_style">signals_define_style</a> property.<br />
This property should be set, as otherwise the style will not have a name.</p>
<p>The property length is 2 byte. This is a string ID.<br />
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_style</font>, version 1</p>
<h4 id="signals_no_default_style">Set whether custom signal sprites should not be used for the default signal style (mappable property: signals_no_default_style)</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, this GRF is not used for the default signal style, it is only used for custom signal styles defined with <a href="#signals_define_style">signals_define_style</a>.</p>
<p>The property length is 1 byte. 0 is disabled (default). 1 is enabled.<br />
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_style</font>, version 1</p>
<br />
<h3 id="a0objects"><a href="https://newgrf-specs.tt-wiki.net/wiki/Action0/Objects">Action 0 - Objects</a></h3>
<h4 id="object_use_land_ground">Object uses land ground sprite (mappable property: object_use_land_ground)</h4>
@ -649,6 +671,12 @@
</table>
</p>
<p>This is indicated by the feature name: <font face="monospace">varaction2_signals_signal_context</font>, version 1</p>
<h4 id="signals_signal_style">Signal style (mappable variable: signals_signal_style)</h4>
<p>This applies to <a href="#a3signals_custom_signal_sprites">Action 2/3 Signals (Feature 0E) custom signal sprites</a>.<br />
If the signal being drawn uses a custom signal style, the value is the signal style ID as set in the <a href="#signals_define_style">signals_define_style</a> property.<br />
Otherwise for signals using the default style, the value is 0.
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_signals_style</font>, version 1</p>
<br />
<br />
<h3 id="a3signals"><a href="https://newgrf-specs.tt-wiki.net/wiki/Action3">Action 3 - Signals (Feature 0E)</a></h3>

@ -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<uint32> _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();
}

@ -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 <vector>
#include <unordered_map>
@ -24,6 +25,8 @@ struct LongBridgeSignalStorage {
extern std::unordered_map<TileIndex, LongBridgeSignalStorage> _long_bridge_signal_sim_map;
extern btree::btree_set<uint32> _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 */

@ -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

@ -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);

@ -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 */

@ -4194,6 +4194,37 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const
_cur.grffile->new_signal_extra_aspects = std::min<byte>(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<NewSignalStyle>(_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;

@ -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

@ -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"),

@ -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 */

@ -18,6 +18,8 @@
#include "safeguards.h"
std::vector<const GRFFile *> _new_signals_grfs;
std::array<NewSignalStyle, MAX_NEW_SIGNAL_STYLES> _new_signal_styles;
uint _num_new_signal_styles = 0;
/* virtual */ uint32 NewSignalsScopeResolver::GetRandomBits() const
{
@ -25,6 +27,11 @@ std::vector<const GRFFile *> _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<const GRFFile *> _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<const GRFFile *> _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;
}

@ -13,16 +13,33 @@
#include "newgrf_commons.h"
#include "newgrf_spritegroup.h"
#include "tunnel_map.h"
#include "gfx_type.h"
extern std::vector<const GRFFile *> _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<NewSignalStyle, MAX_NEW_SIGNAL_STYLES> _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
{

@ -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) {

@ -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);

@ -440,6 +440,7 @@ static void ShutdownGame()
LinkGraphSchedule::Clear();
ClearTraceRestrictMapping();
ClearBridgeSimulatedSignalMapping();
ClearBridgeSignalStyleMapping();
ClearCargoPacketDeferredPayments();
PoolBase::Clean(PT_ALL);

@ -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<uint>(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;
}

@ -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<NWidgetStacked>(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<NWidgetStacked>(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<int>(this->sig_sprite_bottom_offset, sprite_size.height);
this->sig_sprite_size.width = std::max<int>(this->sig_sprite_size.width, sprite_size.width - offset.x);
this->sig_sprite_size.height = std::max<int>(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<int>(this->sig_sprite_bottom_offset, sprite_size.height);
this->sig_sprite_size.width = std::max<int>(this->sig_sprite_size.width, sprite_size.width - offset.x);
this->sig_sprite_size.height = std::max<int>(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<uint>(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(),
};

@ -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

@ -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);
}

@ -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);

@ -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
};

@ -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

@ -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()

@ -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);
}

@ -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)

@ -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();

@ -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;
}

@ -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

@ -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);

@ -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);

@ -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. */

Loading…
Cancel
Save