From f72d8d0b487261aff42d3303077189c1ba6cd99f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 22 Aug 2024 14:55:02 +0100 Subject: [PATCH] Extend station bridge above flags for more than 8 station gfx values --- docs/newgrf-additions.html | 28 ++++++++++++++++++++++++---- src/newgrf.cpp | 26 ++++++++++++++++++-------- src/newgrf_extension.cpp | 3 ++- src/newgrf_station.h | 13 +++++++++++-- src/station_cmd.cpp | 31 +++++++++++++++++-------------- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 03fc540e29..ed142badda 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -201,18 +201,38 @@

Action 0 - Stations

Minimum bridge height (1B, or mappable property: station_min_bridge_height)

This property allows building bridges over stations.
- The bridge height property defines minimum clearances required for a bridge for each of the 8 station layouts (or 0 to not allow any bridge). Values are given in height level units (1 level == 8px).
- Each height value is 1 byte, the total property length is 8 bytes. + The bridge height property defines minimum clearances required for a bridge for each of the station layouts (or 0 to not allow any bridge). Values are given in height level units (1 level == 8px).
+

+ +

Fixed length of 8 values:
+ Each height value is 1 byte, the number of values (one for each station layout) is 8, the total property length is 8 bytes.

This is indicated by the feature name: action0_station_prop1B, version 1

+ +

Variable length:
+ Each height value is 1 byte, the number of values (one for each station layout) is variable, the total property length is variable.
+ The mappable property must be used, not variable 1B. The number of values is determined from the length. +

+

This is indicated by the feature name: action0_station_min_bridge_height, version 1

+

Disallowed bridge pillars (mappable property: station_disallowed_bridge_pillars)

This property describes which bridge pillars are not allowed on the station tile.
- It consists of 8 pillar flags, for each of the 8 station layouts.
- Each set of flags is 1 byte, the total property length is 8 bytes.
+ It consists of N pillar flags, for each of the N station layouts.
+ Each set of flags is 1 byte.
Each set of flags has the format described in the bridge_pillar_flags property section, below.

+ +

Fixed length of 8 values:
+ Each set of flags is 1 byte, the number of values (one for each station layout) is 8, the total property length is 8 bytes. +

This is indicated by the feature name: action0_station_disallowed_bridge_pillars, version 1

+

Variable length:
+ Each set of flags is 1 byte, the number of values (one for each station layout) is variable, the total property length is variable.
+ The number of values is determined from the length. +

+

This is indicated by the feature name: action0_station_disallowed_bridge_pillars, version 2

+
The 8 station layouts are described below. diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 2b6f1ad255..92c271fb72 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2148,23 +2148,33 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, cons break; } - case A0RPI_STATION_MIN_BRIDGE_HEIGHT: - if (MappedPropertyLengthMismatch(buf, 8, mapping_entry)) break; - [[fallthrough]]; + case A0RPI_STATION_MIN_BRIDGE_HEIGHT: { + SetBit(statspec->internal_flags, SSIF_BRIDGE_HEIGHTS_SET); + size_t length = buf->ReadExtendedByte(); + if (statspec->bridge_above_flags.size() < length) statspec->bridge_above_flags.resize(length); + for (size_t i = 0; i < length; i++) { + statspec->bridge_above_flags[i].height = buf->ReadByte(); + } + break; + } + case 0x1B: // Minimum height for a bridge above SetBit(statspec->internal_flags, SSIF_BRIDGE_HEIGHTS_SET); + if (statspec->bridge_above_flags.size() < 8) statspec->bridge_above_flags.resize(8); for (uint i = 0; i < 8; i++) { - statspec->bridge_height[i] = buf->ReadByte(); + statspec->bridge_above_flags[i].height = buf->ReadByte(); } break; - case A0RPI_STATION_DISALLOWED_BRIDGE_PILLARS: - if (MappedPropertyLengthMismatch(buf, 8, mapping_entry)) break; + case A0RPI_STATION_DISALLOWED_BRIDGE_PILLARS: { SetBit(statspec->internal_flags, SSIF_BRIDGE_DISALLOWED_PILLARS_SET); - for (uint i = 0; i < 8; i++) { - statspec->bridge_disallowed_pillars[i] = buf->ReadByte(); + size_t length = buf->ReadExtendedByte(); + if (statspec->bridge_above_flags.size() < length) statspec->bridge_above_flags.resize(length); + for (size_t i = 0; i < length; i++) { + statspec->bridge_above_flags[i].disallowed_pillars = buf->ReadByte(); } break; + } case 0x1C: // Station Name AddStringForMapping(buf->ReadWord(), &statspec->name); diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index d3970f1ddf..6d7a9e067b 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -22,7 +22,8 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("feature_id_mapping", 2), GRFFeatureInfo("action5_type_id_mapping", 2), GRFFeatureInfo("action0_station_prop1B", 1), - GRFFeatureInfo("action0_station_disallowed_bridge_pillars", 1), + GRFFeatureInfo("action0_station_min_bridge_height", 1), + GRFFeatureInfo("action0_station_disallowed_bridge_pillars", 2), GRFFeatureInfo("varaction2_station_var42", 1), GRFFeatureInfo("varaction2_station_station_nearby_info_v2", 1), GRFFeatureInfo("more_bridge_types", 1), diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 1be4c7e7cf..cf9ab76b61 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -177,8 +177,11 @@ struct StationSpec : NewGRFSpecBase { uint8_t flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size - uint8_t bridge_height[8]; ///< Minimum height for a bridge above, 0 for none - uint8_t bridge_disallowed_pillars[8]; ///< Disallowed pillar flags for a bridge above + struct BridgeAboveFlags { + uint8_t height = UINT8_MAX; ///< Minimum height for a bridge above, 0 for none + uint8_t disallowed_pillars = 0; ///< Disallowed pillar flags for a bridge above + }; + std::vector bridge_above_flags; ///< List of bridge above flags. enum class TileFlags : uint8_t { None = 0, @@ -194,6 +197,12 @@ struct StationSpec : NewGRFSpecBase { /** Custom platform layouts, keyed by platform and length combined. */ std::unordered_map> layouts; + + BridgeAboveFlags GetBridgeAboveFlags(uint gfx) const + { + if (gfx < this->bridge_above_flags.size()) return this->bridge_above_flags[gfx]; + return {}; + } }; DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 660d3ad66e..3c76b4298f 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -924,15 +924,14 @@ CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, uint8_t layout, TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height, BridgeType bridge_type, TransportType bridge_transport_type) { - assert(layout < 8); - - if (statspec && HasBit(statspec->internal_flags, SSIF_BRIDGE_HEIGHTS_SET)) { - if (statspec->bridge_height[layout] == 0) return CommandCost(INVALID_STRING_ID); - if (GetTileMaxZ(tile) + statspec->bridge_height[layout] > bridge_height) { + if (statspec != nullptr && HasBit(statspec->internal_flags, SSIF_BRIDGE_HEIGHTS_SET)) { + int height_above = statspec->GetBridgeAboveFlags(layout).height; + if (height_above == 0) return CommandCost(INVALID_STRING_ID); + if (GetTileMaxZ(tile) + height_above > bridge_height) { return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION); } } else if (!statspec) { - // default stations/waypoints + /* Default stations/waypoints */ const int height = layout < 4 ? 2 : 5; if (GetTileMaxZ(tile) + height > bridge_height) return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION); } else { @@ -940,18 +939,22 @@ CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statsp } BridgePiecePillarFlags disallowed_pillar_flags; - if (statspec && HasBit(statspec->internal_flags, SSIF_BRIDGE_DISALLOWED_PILLARS_SET)) { - // pillar flags set by NewGRF - disallowed_pillar_flags = (BridgePiecePillarFlags) statspec->bridge_disallowed_pillars[layout]; + if (statspec != nullptr && HasBit(statspec->internal_flags, SSIF_BRIDGE_DISALLOWED_PILLARS_SET)) { + /* Pillar flags set by NewGRF */ + disallowed_pillar_flags = (BridgePiecePillarFlags) statspec->GetBridgeAboveFlags(layout).disallowed_pillars; } else if (!statspec) { - // default stations/waypoints - static const uint8_t st_flags[8] = { 0x50, 0xA0, 0x50, 0xA0, 0x50 | 0x26, 0xA0 | 0x1C, 0x50 | 0x89, 0xA0 | 0x43 }; - disallowed_pillar_flags = (BridgePiecePillarFlags) st_flags[layout]; + /* Default stations/waypoints */ + if (layout < 8) { + static const uint8_t st_flags[8] = { 0x50, 0xA0, 0x50, 0xA0, 0x50 | 0x26, 0xA0 | 0x1C, 0x50 | 0x89, 0xA0 | 0x43 }; + disallowed_pillar_flags = (BridgePiecePillarFlags) st_flags[layout]; + } else { + disallowed_pillar_flags = (BridgePiecePillarFlags) 0; + } } else if ((GetStationTileFlags(layout, statspec) & StationSpec::TileFlags::Blocked) == StationSpec::TileFlags::Blocked) { - // non-track station tiles + /* Non-track station tiles */ disallowed_pillar_flags = (BridgePiecePillarFlags) 0; } else { - // tracked station tiles + /* Tracked station tiles */ const Axis axis = HasBit(layout, 0) ? AXIS_Y : AXIS_X; disallowed_pillar_flags = (BridgePiecePillarFlags) (axis == AXIS_X ? 0x50 : 0xA0); }