diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf index 620cc8ab98..4464c415f3 100644 Binary files a/media/baseset/openttd.grf and b/media/baseset/openttd.grf differ diff --git a/media/baseset/openttd.grf.hash b/media/baseset/openttd.grf.hash index 5b07da7ff6..f940ca5d62 100644 --- a/media/baseset/openttd.grf.hash +++ b/media/baseset/openttd.grf.hash @@ -1 +1 @@ -eb8390a0569e66ec417c64ad254f9d05 +b779126d7cd1567eb09a0a7871f70a71 diff --git a/media/baseset/openttd/CMakeLists.txt b/media/baseset/openttd/CMakeLists.txt index f2df774d1b..a7d768326e 100644 --- a/media/baseset/openttd/CMakeLists.txt +++ b/media/baseset/openttd/CMakeLists.txt @@ -10,6 +10,7 @@ if(GRFCODEC_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.nfo ${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.nfo ${CMAKE_CURRENT_SOURCE_DIR}/autorail.nfo + ${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.nfo ${CMAKE_CURRENT_SOURCE_DIR}/canals.nfo ${CMAKE_CURRENT_SOURCE_DIR}/chars.nfo ${CMAKE_CURRENT_SOURCE_DIR}/elrails.nfo @@ -31,6 +32,7 @@ if(GRFCODEC_FOUND) ${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.png ${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.png ${CMAKE_CURRENT_SOURCE_DIR}/autorail.png + ${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.png ${CMAKE_CURRENT_SOURCE_DIR}/canals.png ${CMAKE_CURRENT_SOURCE_DIR}/canal_locks.png ${CMAKE_CURRENT_SOURCE_DIR}/chars.png diff --git a/media/baseset/openttd/bridge_decks.nfo b/media/baseset/openttd/bridge_decks.nfo new file mode 100644 index 0000000000..beced3f59f --- /dev/null +++ b/media/baseset/openttd/bridge_decks.nfo @@ -0,0 +1,36 @@ +// This file is part of OpenTTD. +// OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +// OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . +// + -1 * 0 0C "Bridge decks" + -1 * 3 05 1B 18 + + -1 sprites/bridge_decks.png 8bpp 96 16 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 16 16 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 176 16 64 39 -31 -8 normal + -1 sprites/bridge_decks.png 8bpp 256 16 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 336 16 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 416 16 64 39 -31 -8 normal + + -1 sprites/bridge_decks.png 8bpp 96 71 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 16 71 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 176 71 64 39 -31 -8 normal + -1 sprites/bridge_decks.png 8bpp 256 71 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 336 71 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 416 71 64 39 -31 -8 normal + + -1 sprites/bridge_decks.png 8bpp 96 126 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 16 126 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 176 126 64 39 -31 -8 normal + -1 sprites/bridge_decks.png 8bpp 256 126 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 336 126 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 416 126 64 39 -31 -8 normal + +// X and Y axis are swapped for road surface. + -1 sprites/bridge_decks.png 8bpp 16 181 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 96 181 64 31 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 176 181 64 39 -31 -8 normal + -1 sprites/bridge_decks.png 8bpp 256 181 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 336 181 64 23 -31 0 normal + -1 sprites/bridge_decks.png 8bpp 416 181 64 39 -31 -8 normal diff --git a/media/baseset/openttd/bridge_decks.png b/media/baseset/openttd/bridge_decks.png new file mode 100644 index 0000000000..a602e0ed73 Binary files /dev/null and b/media/baseset/openttd/bridge_decks.png differ diff --git a/media/baseset/openttd/openttd.nfo b/media/baseset/openttd/openttd.nfo index 9cfce9ffdd..862345d11e 100644 --- a/media/baseset/openttd/openttd.nfo +++ b/media/baseset/openttd/openttd.nfo @@ -100,3 +100,4 @@ #include "palette.nfo" #include "road_waypoints.nfo" #include "overlay_rocks.nfo" +#include "bridge_decks.nfo" diff --git a/src/newgrf/newgrf_act5.cpp b/src/newgrf/newgrf_act5.cpp index e9b590dfb2..efa1f99d2a 100644 --- a/src/newgrf/newgrf_act5.cpp +++ b/src/newgrf/newgrf_act5.cpp @@ -78,6 +78,7 @@ static constexpr auto _action5_types = std::to_array({ /* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" }, /* 0x19 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROAD_WAYPOINTS_BASE, 1, ROAD_WAYPOINTS_SPRITE_COUNT, "Road waypoints" }, /* 0x1A */ { A5BLOCK_ALLOW_OFFSET, SPR_OVERLAY_ROCKS_BASE, 1, OVERLAY_ROCKS_SPRITE_COUNT, "Overlay rocks" }, + /* 0x1B */ { A5BLOCK_ALLOW_OFFSET, SPR_BRIDGE_DECKS_BASE, 1, BRIDGE_DECKS_SPRITE_COUNT, "Bridge decks" }, }); /** diff --git a/src/rail.h b/src/rail.h index 631a7989d0..b65f2351c8 100644 --- a/src/rail.h +++ b/src/rail.h @@ -131,6 +131,7 @@ public: SpriteID single_sloped;///< single piece of rail for slopes SpriteID crossing; ///< level crossing, rail in X direction SpriteID tunnel; ///< tunnel sprites base + SpriteID bridge_deck; ///< bridge deck sprites base } base_sprites; /** diff --git a/src/table/railtypes.h b/src/table/railtypes.h index 0b0112322e..2788212a96 100644 --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -25,7 +25,7 @@ static const RailTypeInfo _original_railtypes[] = { SPR_RAIL_SINGLE_NORTH, SPR_RAIL_SINGLE_SOUTH, SPR_RAIL_SINGLE_EAST, SPR_RAIL_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_RAIL_BASE, SPR_CROSSING_OFF_X_RAIL, - SPR_TUNNEL_ENTRY_REAR_RAIL + SPR_TUNNEL_ENTRY_REAR_RAIL, SPR_BRIDGE_DECKS_RAIL, }, /* GUI sprites */ @@ -123,7 +123,7 @@ static const RailTypeInfo _original_railtypes[] = { SPR_RAIL_SINGLE_NORTH, SPR_RAIL_SINGLE_SOUTH, SPR_RAIL_SINGLE_EAST, SPR_RAIL_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_RAIL_BASE, SPR_CROSSING_OFF_X_RAIL, - SPR_TUNNEL_ENTRY_REAR_RAIL + SPR_TUNNEL_ENTRY_REAR_RAIL, SPR_BRIDGE_DECKS_RAIL, }, /* GUI sprites */ @@ -225,7 +225,7 @@ static const RailTypeInfo _original_railtypes[] = { SPR_MONO_SINGLE_NORTH, SPR_MONO_SINGLE_SOUTH, SPR_MONO_SINGLE_EAST, SPR_MONO_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_MONO_BASE, SPR_CROSSING_OFF_X_MONO, - SPR_TUNNEL_ENTRY_REAR_MONO + SPR_TUNNEL_ENTRY_REAR_MONO, SPR_BRIDGE_DECKS_MONO, }, /* GUI sprites */ @@ -323,7 +323,7 @@ static const RailTypeInfo _original_railtypes[] = { SPR_MGLV_SINGLE_NORTH, SPR_MGLV_SINGLE_SOUTH, SPR_MGLV_SINGLE_EAST, SPR_MGLV_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_MAGLEV_BASE, SPR_CROSSING_OFF_X_MAGLEV, - SPR_TUNNEL_ENTRY_REAR_MAGLEV + SPR_TUNNEL_ENTRY_REAR_MAGLEV, SPR_BRIDGE_DECKS_MGLV, }, /* GUI sprites */ diff --git a/src/table/sprites.h b/src/table/sprites.h index 573bead42f..caef133af7 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -321,8 +321,16 @@ static const uint16_t ROAD_WAYPOINTS_SPRITE_COUNT = 4; static constexpr SpriteID SPR_OVERLAY_ROCKS_BASE = SPR_ROAD_WAYPOINTS_BASE + ROAD_WAYPOINTS_SPRITE_COUNT; static constexpr uint16_t OVERLAY_ROCKS_SPRITE_COUNT = 19 * 5; /* Rock overlays: plain, snow 1, snow 2, snow 3 and full snow. */ +/** Bridge deck sprites. */ +static constexpr SpriteID SPR_BRIDGE_DECKS_BASE = SPR_OVERLAY_ROCKS_BASE + OVERLAY_ROCKS_SPRITE_COUNT; +static constexpr uint16_t BRIDGE_DECKS_SPRITE_COUNT = 6 * 4; /* Bridge deck sprites: 6 directions * (3 track types + 1 road type). */ +static const SpriteID SPR_BRIDGE_DECKS_RAIL = SPR_BRIDGE_DECKS_BASE + 0; +static const SpriteID SPR_BRIDGE_DECKS_MONO = SPR_BRIDGE_DECKS_BASE + 6; +static const SpriteID SPR_BRIDGE_DECKS_MGLV = SPR_BRIDGE_DECKS_BASE + 12; +static const SpriteID SPR_BRIDGE_DECKS_ROAD = SPR_BRIDGE_DECKS_BASE + 18; + /* From where can we start putting NewGRFs? */ -static const SpriteID SPR_NEWGRFS_BASE = SPR_OVERLAY_ROCKS_BASE + OVERLAY_ROCKS_SPRITE_COUNT; +static const SpriteID SPR_NEWGRFS_BASE = SPR_BRIDGE_DECKS_BASE + BRIDGE_DECKS_SPRITE_COUNT; /* Manager face sprites */ static const SpriteID SPR_GRADIENT = 874; // background gradient behind manager face diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 6180c1ffb5..7ffe333249 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -135,6 +135,19 @@ bool HasBridgeFlatRamp(Slope tileh, Axis axis) return (tileh != SLOPE_FLAT); } +/** + * Test if bridge piece uses a custom sprite table. + * @param bridge_type Bridge type. + * @param piece Bridge piece. + * @return True iff a custom sprite table is used for the bridge piece. + */ +static bool BridgeHasCustomSpriteTable(BridgeType bridge_type, BridgePieces piece) +{ + assert(piece < NUM_BRIDGE_PIECES); + const BridgeSpec *bridge = GetBridgeSpec(bridge_type); + return piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty(); +} + /** * Get the sprite table for a rail/road bridge piece. * @param bridge_type Bridge type. @@ -1158,8 +1171,9 @@ static void GetBridgeRoadCatenary(const RoadTypeInfo *rti, TileIndex head_tile, * @param z the z of the bridge * @param offset sprite offset identifying flat to sloped bridge tiles * @param head are we drawing bridge head? + * @param is_custom_layout Set if the bridge uses a custom sprite layout. */ -static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head) +static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head, bool is_custom_layout) { RoadType road_rt = GetRoadTypeRoad(head_tile); RoadType tram_rt = GetRoadTypeTram(head_tile); @@ -1178,6 +1192,9 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off if (road_rti != nullptr) { if (road_rti->UsesOverlay()) { seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset; + } else if (is_custom_layout) { + /* For custom layouts draw a custom bridge deck. */ + seq_back[0] = SPR_BRIDGE_DECKS_ROAD + offset; } } else if (tram_rti != nullptr) { if (tram_rti->UsesOverlay()) { @@ -1428,13 +1445,16 @@ static void DrawTile_TunnelBridge(TileInfo *ti) DrawBridgeMiddle(ti, BridgePillarFlag::EdgeNE + tunnelbridge_direction); } else { // IsBridge(ti->tile) DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction))); + bool is_custom_layout; // Set if rail/road bridge uses a custom layout. uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction); std::span psid; if (transport_type != TRANSPORT_WATER) { + BridgeType bridge_type = GetBridgeType(ti->tile); if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile); - psid = GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD); + psid = GetBridgeSpriteTable(bridge_type, BRIDGE_PIECE_HEAD); + is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, BRIDGE_PIECE_HEAD); } else { psid = _aqueduct_sprite_table_heads; } @@ -1473,23 +1493,18 @@ static void DrawTile_TunnelBridge(TileInfo *ti) } /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true); + DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true, is_custom_layout); EndSpriteCombine(); } else if (transport_type == TRANSPORT_RAIL) { const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); - if (rti->UsesOverlay()) { - SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE); - if (surface != 0) { - if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { - AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}}); - } else { - AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}}); - } + SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE) : rti->base_sprites.bridge_deck; + if (surface != 0) { + if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { + AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}}); + } else { + AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}}); } - /* Don't fallback to non-overlay sprite -- the spec states that - * if an overlay is present then the bridge surface must be - * present. */ } /* PBS debugging, draw reserved tracks darker */ @@ -1614,16 +1629,19 @@ void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars) TransportType transport_type = GetTunnelBridgeTransportType(rampsouth); Axis axis = GetBridgeAxis(ti->tile); BridgePillarFlags pillars; + bool is_custom_layout; // Set if rail/road bridge uses a custom layout. uint base_offset = GetBridgeMiddleAxisBaseOffset(axis); std::span psid; bool drawfarpillar; if (transport_type != TRANSPORT_WATER) { BridgeType bridge_type = GetBridgeType(rampsouth); + BridgePieces bridge_piece = CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1); drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0); base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth); - psid = GetBridgeSpriteTable(bridge_type, CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1)); + psid = GetBridgeSpriteTable(bridge_type, bridge_piece); pillars = GetBridgeTilePillarFlags(ti->tile, rampnorth, rampsouth, bridge_type, transport_type); + is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, bridge_piece); } else { drawfarpillar = true; psid = _aqueduct_sprite_table_middle; @@ -1653,11 +1671,11 @@ void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars) if (transport_type == TRANSPORT_ROAD) { /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false); + DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false, is_custom_layout); } else if (transport_type == TRANSPORT_RAIL) { const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth)); - if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) { - SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE); + if (!IsInvisibilitySet(TO_BRIDGES)) { + SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE) : rti->base_sprites.bridge_deck; if (surface != 0) { AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES)); }