From 8a8ebabb9d106e0f5ad96b19d7830154d810b052 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 29 Sep 2025 22:08:16 +0100 Subject: [PATCH] Change: Provide road and rail overlay sprites for bridge decks. (#14557) This allows bridges designed primarily with NewGRF railtypes and roadtypes to be at least somewhat compatible with built-in rail and road. --- media/baseset/openttd.grf | Bin 631667 -> 641653 bytes media/baseset/openttd.grf.hash | 2 +- media/baseset/openttd/CMakeLists.txt | 2 + media/baseset/openttd/bridge_decks.nfo | 36 +++++++++++++++++ media/baseset/openttd/bridge_decks.png | Bin 0 -> 7771 bytes media/baseset/openttd/openttd.nfo | 1 + src/newgrf/newgrf_act5.cpp | 1 + src/rail.h | 1 + src/table/railtypes.h | 8 ++-- src/table/sprites.h | 10 ++++- src/tunnelbridge_cmd.cpp | 54 ++++++++++++++++--------- 11 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 media/baseset/openttd/bridge_decks.nfo create mode 100644 media/baseset/openttd/bridge_decks.png diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf index 620cc8ab981eb34ffd83886fd9e17befd31631eb..4464c415f3a7cfa8e124513b97ec6b079eda21fa 100644 GIT binary patch delta 10126 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 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 0000000000000000000000000000000000000000..a602e0ed73a5e7eaec0de77fd56928e5c7bf4f18 GIT binary patch literal 7771 zcma)>c{tSH`~P2dvM+@&RLUAE*=3Y9LcNh1`@S0tgBgtSjYb)R$JkLUf?#7LL*($z}<0I=%oX*~k~ zs;vu~#7J{7VmN7006+tn7@BGWz&Qs8hlq%XoSYmO3^p+_addQq!C;Y*ktr!DB_$* zDUMZDk$rt7deXEOYCNtc(nwdmj7ZC-f}l}M%HC`h7@)PF<$!XCM2pB5C>df*J^Ngd zvyq9UoKF-?J7ox<5Y#9Xl%Y6atHubk5R8T? zGw4%vMte!qY>x;Zpd<+BiPKuhv$%r!kfzeHp5OwMg`qfytvnx0OFY_C>60zE32M@Z zvK>u<;!98@Op1vht)n1$8x-7j=X0T7};Z(h_}S= zQF=&+b+e>M%%nv|`5v&h59}WR2V{VJ2pk>(N5{bN32;IID5t>b8E|$EoE!2ndP?&p z>d9Amnhw7YyEr1n6ri{Q6eK`N0Vw4Fr4s;OcryUV$pK(6U}6HCp93OVP*FXYxM7gA z2~y4!rRSLF7+Es8N3lhH(z1;`KR?GlHz))yUWdJbt`-nYC!}{VVS?(t@CN|4j{oUY z-99Cb7mExq{U_QCs|*4>cQ4J|epw6vR~PiPG);r1*K=pyXE%*^-{$yZ3zsZiEq(l# zYbKaxTdn0_>@#6@FYNrdEr5eBA54uYi%VBY*1x&_?~w6%K;mfCk%pV>n8ICJYRfDj z{Z@Ms6V&a$nJ5FqQ+#&j6H=%z;%))8CA}#Mi@F5m9|}Go2_p6#BBY$o8E6Vd-ygJF z-W|(}Pp#j-vDsK{esk3np${Z7wI|C*NtJX{M=^^AXGuF(dc)Fgg}iH3y5r`~hz{*M zy-ULM)Vh&9-d{Jsyk($yUOya*2^QRXyKHST1hwuW>!A5r$qgGCCG(Ha^8x@VrA9T6R*K9;SonuPmO zI4p?iq%T{Fod7y*`A8bCd=%44`X0w88n1ZeW~q$`yZ`D?x<~5FGHS*nz{aT51Ye=r z$QNs|Iz9tpR%JZaJJ+$B;8hW-VGzF~7%UbbRq}eHM3qmed6zGF*SHv_ zIyJ{ikS^yyG^VPX665wOot-*ZAEH5GA3KY0R~(pntEPqz@)`fk}H>~1+Cx!22Wl|uaFJF)V8(t@h*v$0OFBV;{&(`g$JvVoh>O`1%C$L zojNR;K>$~+Ez5|X-BR0L+}}!u_+0fPW^V7heiv#h^qXgk`ZD7WT%94X_{;mPI46=r z*h~{4gA$N#X|{9+5Dmp}nGgGV?HQxO+1h~sN

qSFQ`q2GXp3s={SyoOm*Id{;Lo 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 /* 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)); }