Add custom signal style properties to set electric/semaphore enabled types

This commit is contained in:
Jonathan G Rennison
2022-06-19 17:43:46 +01:00
parent 175c5d4d50
commit 191f710c40
9 changed files with 164 additions and 13 deletions

View File

@@ -4253,6 +4253,24 @@ static ChangeInfoResult SignalsChangeInfo(uint id, int numinfo, int prop, const
break;
}
case A0RPI_SIGNALS_STYLE_SEMAPHORE_ENABLED: {
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
uint32 mask = buf->ReadDWord();
if (_cur.grffile->current_new_signal_style != nullptr) {
_cur.grffile->current_new_signal_style->semaphore_mask = (uint8)mask;
}
break;
}
case A0RPI_SIGNALS_STYLE_ELECTRIC_ENABLED: {
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
uint32 mask = buf->ReadDWord();
if (_cur.grffile->current_new_signal_style != nullptr) {
_cur.grffile->current_new_signal_style->electric_mask = (uint8)mask;
}
break;
}
default:
ret = HandleAction0PropertyDefault(buf, prop);
break;

View File

@@ -97,6 +97,8 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_NO_ASPECT_INCREASE, "signals_style_no_aspect_increase"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_ALWAYS_RESERVE_THROUGH, "signals_style_always_reserve_through"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_LOOKAHEAD_EXTRA_ASPECTS, "signals_style_lookahead_extra_aspects"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_SEMAPHORE_ENABLED, "signals_style_semaphore_enabled"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_STYLE_ELECTRIC_ENABLED, "signals_style_electric_enabled"),
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"),

View File

@@ -41,6 +41,8 @@ enum Action0RemapPropertyIds {
A0RPI_SIGNALS_STYLE_NO_ASPECT_INCREASE,
A0RPI_SIGNALS_STYLE_ALWAYS_RESERVE_THROUGH,
A0RPI_SIGNALS_STYLE_LOOKAHEAD_EXTRA_ASPECTS,
A0RPI_SIGNALS_STYLE_SEMAPHORE_ENABLED,
A0RPI_SIGNALS_STYLE_ELECTRIC_ENABLED,
A0RPI_OBJECT_USE_LAND_GROUND,
A0RPI_OBJECT_EDGE_FOUNDATION_MODE,
A0RPI_OBJECT_FLOOD_RESISTANT,

View File

@@ -36,6 +36,8 @@ struct NewSignalStyle {
uint8 grf_local_id;
uint8 style_flags;
uint8 lookahead_extra_aspects;
uint8 semaphore_mask;
uint8 electric_mask;
PalSpriteID signals[SIGTYPE_END][2][2];
};

View File

@@ -163,8 +163,10 @@ CustomSignalSpriteResult GetCustomSignalSprite(const RailtypeInfo *rti, TileInde
}
for (const GRFFile *grf : _new_signals_grfs) {
if (type == SIGTYPE_PROG && !HasBit(grf->new_signal_ctrl_flags, NSCF_PROGSIG)) continue;
if (type == SIGTYPE_NO_ENTRY && !HasBit(grf->new_signal_ctrl_flags, NSCF_NOENTRYSIG)) continue;
if (style == 0) {
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;

View File

@@ -1501,6 +1501,13 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
CommandCost ret = CheckTileOwnership(tile);
if (ret.Failed()) return ret;
auto is_style_usable = [](SignalVariant sigvar, uint8 style_id, uint8 mask) {
if (style_id == 0) return true;
const NewSignalStyle &style = _new_signal_styles[style_id - 1];
return ((sigvar == SIG_SEMAPHORE ? style.semaphore_mask : style.electric_mask) & mask) == mask;
};
CommandCost cost;
/* handle signals simulation on tunnel/bridge. */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
@@ -1520,25 +1527,36 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (!(p2_signal_in && p2_signal_out)) {
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1
if (HasBit(_no_tunnel_bridge_style_mask, signal_style)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
if (!is_style_usable(sigvar, signal_style, bidirectional ? 0x11 : (is_pbs ? 0x21 : 0x1))) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
}
} else {
if (HasBit(p1, 17)) return CommandCost();
bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional(tile);
const bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional(tile);
bool will_be_bidi = is_bidi;
const bool is_semaphore = IsTunnelBridgeSemaphore(tile);
bool will_be_semaphore = is_semaphore;
bool will_be_pbs = IsTunnelBridgePBS(tile);
const uint8 is_style = GetTunnelBridgeSignalStyle(tile);
uint8 will_be_style = is_style;
if (!p2_active) {
if (convert_signal) {
will_be_bidi = bidirectional && !ctrl_pressed;
change_style = (signal_style != GetTunnelBridgeSignalStyle(tile));
change_style = (signal_style != is_style);
will_be_style = signal_style;
will_be_pbs = is_pbs;
will_be_semaphore = (sigvar == SIG_SEMAPHORE);
if (HasBit(_no_tunnel_bridge_style_mask, signal_style)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
} else if (ctrl_pressed) {
will_be_bidi = false;
will_be_pbs = !will_be_pbs;
}
} else if (!is_pbs) {
will_be_bidi = false;
}
if ((p2_active && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) {
if ((p2_active && (sigvar == SIG_SEMAPHORE) != is_semaphore) ||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != is_semaphore))) {
flip_variant = true;
will_be_semaphore = !is_semaphore;
}
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))) *
@@ -1546,6 +1564,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
} else if (is_bidi != will_be_bidi) {
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[will_be_bidi ? PR_BUILD_SIGNALS : PR_CLEAR_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2)); // minimal 1
}
if (!is_style_usable(will_be_semaphore ? SIG_SEMAPHORE : SIG_ELECTRIC, will_be_style, will_be_bidi ? 0x11 : (will_be_pbs ? 0x21 : 0x1))) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
}
auto remove_pbs_bidi = [&]() {
if (IsTunnelBridgeSignalSimulationBidirectional(tile)) {
@@ -1677,10 +1696,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (!HasSignalOnTrack(tile, track)) {
/* build new signals */
cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
if (!is_style_usable(sigvar, signal_style, 1 << sigtype)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
} else {
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]);
if (!is_style_usable(sigvar, signal_style, 1 << sigtype)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
} else if (convert_signal) {
/* convert button pressed */
@@ -1692,6 +1713,12 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
cost = CommandCost();
}
if (ctrl_pressed) {
if (!is_style_usable((GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC, GetSignalStyle(tile, track), 1 << GetSignalType(tile, track))) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
} else {
if (!is_style_usable(sigvar, signal_style, 1 << sigtype)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
}
} else {
/* it is free to change orientation/pre-exit-combo signals */
cost = CommandCost();

View File

@@ -1835,7 +1835,42 @@ private:
y + this->IsWidgetLowered(widget_index));
}
void SetSignalUIMode() {
void SetDisableStates()
{
for (int widget = WID_BS_SEMAPHORE_NORM; widget <= WID_BS_SEMAPHORE_NO_ENTRY; widget++) {
this->SetWidgetDisabledState(widget, _cur_signal_style > 0 && !HasBit(_new_signal_styles[_cur_signal_style - 1].semaphore_mask, TypeForClick(widget - WID_BS_SEMAPHORE_NORM)));
}
for (int widget = WID_BS_ELECTRIC_NORM; widget <= WID_BS_ELECTRIC_NO_ENTRY; widget++) {
this->SetWidgetDisabledState(widget, _cur_signal_style > 0 && !HasBit(_new_signal_styles[_cur_signal_style - 1].electric_mask, TypeForClick(widget - WID_BS_ELECTRIC_NORM)));
}
if (_cur_signal_style > 0) {
const NewSignalStyle &style = _new_signal_styles[_cur_signal_style - 1];
if (!HasBit(_cur_signal_variant == SIG_SEMAPHORE ? style.semaphore_mask : style.electric_mask, _cur_signal_type)) {
/* Currently selected signal type isn't allowed, pick another */
this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_button);
_cur_signal_variant = SIG_ELECTRIC;
_cur_signal_button = 0;
const uint type_count = (WID_BS_SEMAPHORE_NO_ENTRY + 1 - WID_BS_SEMAPHORE_NORM);
for (uint i = 0; i < type_count * 2; i++) {
SignalVariant var = (i < type_count) ? SIG_ELECTRIC : SIG_SEMAPHORE;
uint button = i % type_count;
if (HasBit(var == SIG_SEMAPHORE ? style.semaphore_mask : style.electric_mask, TypeForClick(button))) {
_cur_signal_variant = var;
_cur_signal_button = button;
break;
}
}
_cur_signal_type = TypeForClick(_cur_signal_button);
this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_button);
}
}
}
void SetSignalUIMode()
{
this->all_signal_mode = (_settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL);
this->realistic_braking_mode = (_settings_game.vehicle.train_braking_model == TBM_REALISTIC);
this->progsig_ui_shown = _settings_client.gui.show_progsig_ui;
@@ -1870,6 +1905,8 @@ private:
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);
this->SetDisableStates();
}
void ClearRemoveState()
@@ -1958,7 +1995,9 @@ public:
int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets.
PalSpriteID sprite = { 0, 0 };
if (_cur_signal_style > 0) {
sprite = _new_signal_styles[_cur_signal_style - 1].signals[type][var][this->IsWidgetLowered(widget)];
const NewSignalStyle &style = _new_signal_styles[_cur_signal_style - 1];
if (!HasBit(var == SIG_SEMAPHORE ? style.semaphore_mask : style.electric_mask, type)) return;
sprite = style.signals[type][var][this->IsWidgetLowered(widget)];
}
if (sprite.sprite == 0) {
sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)];
@@ -2083,6 +2122,7 @@ public:
switch (widget) {
case WID_BS_STYLE:
_cur_signal_style = std::min<uint>(index, _num_new_signal_styles);
this->SetDisableStates();
this->SetDirty();
break;