diff --git a/src/bridge.h b/src/bridge.h index e11ff244b5..03485327f2 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -63,7 +63,7 @@ inline const BridgeSpec *GetBridgeSpec(BridgeType i) return &_bridge[i]; } -void DrawBridgeMiddle(const TileInfo *ti); +void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars); CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlags flags = {}); int CalcBridgeLenCostFactor(int x); diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index cb817bf0a3..92363bb184 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -152,7 +152,7 @@ static void DrawTile_Clear(TileInfo *ti) break; } - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, {}); } static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y, bool) diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 15693c90f0..195e510e72 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -483,7 +483,7 @@ static void DrawTile_Object(TileInfo *ti) DrawNewObjectTile(ti, spec); } - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, {}); } static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y, bool) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 564b9c75db..6c1f3eb4f7 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2409,6 +2409,7 @@ static void DrawSignals(TileIndex tile, TrackBits rails, const RailTypeInfo *rti static void DrawTile_Track(TileInfo *ti) { const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); + BridgePillarFlags blocked_pillars{}; PaletteID pal = GetCompanyPalette(GetTileOwner(ti->tile)); if (IsPlainRail(ti->tile)) { @@ -2421,17 +2422,25 @@ static void DrawTile_Track(TileInfo *ti) if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti); + + if (IsBridgeAbove(ti->tile)) { + if ((rails & TRACK_BIT_3WAY_NE) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeNE); + if ((rails & TRACK_BIT_3WAY_SE) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeSE); + if ((rails & TRACK_BIT_3WAY_SW) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeSW); + if ((rails & TRACK_BIT_3WAY_NW) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeNW); + } } else { /* draw depot */ const DrawTileSprites *dts; + DiagDirection dir = GetRailDepotDirection(ti->tile); if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); if (IsInvisibilitySet(TO_BUILDINGS)) { /* Draw rail instead of depot */ - dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)]; + dts = &_depot_invisible_gfx_table[dir]; } else { - dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)]; + dts = &_depot_gfx_table[dir]; } SpriteID image; @@ -2520,8 +2529,9 @@ static void DrawTile_Track(TileInfo *ti) if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, pal); + /* Depots can't have bridges above so no blocked pillars. */ } - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, blocked_pillars); } void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype) diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 49c2e9f69d..f923eddbee 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1699,9 +1699,18 @@ static void DrawRoadBits(TileInfo *ti) /** Tile callback function for rendering a road tile to the screen */ static void DrawTile_Road(TileInfo *ti) { + BridgePillarFlags blocked_pillars{}; switch (GetRoadTileType(ti->tile)) { case ROAD_TILE_NORMAL: DrawRoadBits(ti); + + if (IsBridgeAbove(ti->tile)) { + RoadBits bits = GetAllRoadBits(ti->tile); + if ((bits & ROAD_NE) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeNE); + if ((bits & ROAD_SE) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeSE); + if ((bits & ROAD_SW) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeSW); + if ((bits & ROAD_NW) != 0) blocked_pillars.Set(BridgePillarFlag::EdgeNW); + } break; case ROAD_TILE_CROSSING: { @@ -1809,7 +1818,7 @@ static void DrawTile_Road(TileInfo *ti) /* Draw rail catenary */ if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); - + blocked_pillars = {BridgePillarFlag::EdgeSW, BridgePillarFlag::EdgeNE, BridgePillarFlag::EdgeNW, BridgePillarFlag::EdgeSE}; break; } @@ -1855,10 +1864,11 @@ static void DrawTile_Road(TileInfo *ti) } DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, palette); + /* Depots can't have bridges above so no blocked pillars. */ break; } } - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, blocked_pillars); } /** diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 3184393fdd..1bbb1b864b 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1445,7 +1445,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti) AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]); AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]); - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, BridgePillarFlag::EdgeNE + tunnelbridge_direction); } else { // IsBridge(ti->tile) DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction))); @@ -1536,7 +1536,13 @@ static void DrawTile_TunnelBridge(TileInfo *ti) } } - DrawBridgeMiddle(ti); + BridgePillarFlags blocked_pillars; + if (DiagDirToAxis(tunnelbridge_direction) == AXIS_X) { + blocked_pillars = {BridgePillarFlag::EdgeSW, BridgePillarFlag::EdgeNE}; + } else { + blocked_pillars = {BridgePillarFlag::EdgeNW, BridgePillarFlag::EdgeSE}; + } + DrawBridgeMiddle(ti, blocked_pillars); } } @@ -1574,11 +1580,36 @@ static BridgePieces CalcBridgePiece(uint north, uint south) } } +/** + * Get pillar information for a bridge middle tile. + * @param tile Tile of bridge middle. + * @param rampnorth Northern ramp tile of bridge. + * @param rampsouth Southern ramp tile of bridge. + * @param type Bridge type. + * @param transport_type Transport type of bridge. + * @return Pillar flags for bridge middle. + */ +static BridgePillarFlags GetBridgeTilePillarFlags(TileIndex tile, TileIndex rampnorth, TileIndex rampsouth, BridgeType type, TransportType transport_type) +{ + if (transport_type == TRANSPORT_WATER) return BRIDGEPILLARFLAGS_ALL_CORNERS; + + const BridgeSpec *spec = GetBridgeSpec(type); + if (!spec->ctrl_flags.Test(BridgeSpec::ControlFlag::InvalidPillarFlags)) { + BridgePieces piece = CalcBridgePiece(GetTunnelBridgeLength(tile, rampnorth) + 1, GetTunnelBridgeLength(tile, rampsouth) + 1); + Axis axis = TileX(rampnorth) == TileX(rampsouth) ? AXIS_Y : AXIS_X; + + return spec->pillar_flags[piece][axis == AXIS_Y ? 1 : 0]; + } + + return BRIDGEPILLARFLAGS_ALL_CORNERS; +} + /** * Draw the middle bits of a bridge. * @param ti Tile information of the tile to draw it on. + * @param blocked_pillars Mask of pillar corners and edges blocked by tile below the bridge. */ -void DrawBridgeMiddle(const TileInfo *ti) +void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars) { /* Sectional view of bridge bounding boxes: * @@ -1602,6 +1633,7 @@ void DrawBridgeMiddle(const TileInfo *ti) TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile); TransportType transport_type = GetTunnelBridgeTransportType(rampsouth); Axis axis = GetBridgeAxis(ti->tile); + BridgePillarFlags pillars; uint base_offset = GetBridgeMiddleAxisBaseOffset(axis); std::span psid; @@ -1611,9 +1643,11 @@ void DrawBridgeMiddle(const TileInfo *ti) 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)); + pillars = GetBridgeTilePillarFlags(ti->tile, rampnorth, rampsouth, bridge_type, transport_type); } else { drawfarpillar = true; psid = _aqueduct_sprite_table_middle; + pillars = BRIDGEPILLARFLAGS_ALL_CORNERS; } psid = psid.subspan(base_offset, 3); @@ -1682,6 +1716,7 @@ void DrawBridgeMiddle(const TileInfo *ti) /* Do not draw anything more if bridges are invisible */ if (IsInvisibilitySet(TO_BRIDGES)) return; + if (blocked_pillars.Any(pillars)) return; DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z); } diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 756a1d1d38..0077fc107b 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -926,12 +926,14 @@ static void DrawTile_Water(TileInfo *ti) switch (GetWaterTileType(ti->tile)) { case WATER_TILE_CLEAR: DrawWaterClassGround(ti); - DrawBridgeMiddle(ti); + /* A plain water tile can be traversed in any direction, so setting blocked pillars here would mean all bridges + * with edges would have no pillars above water. Instead prefer current behaviour of ships passing through. */ + DrawBridgeMiddle(ti, {}); break; case WATER_TILE_COAST: { DrawShoreTile(ti->tileh); - DrawBridgeMiddle(ti); + DrawBridgeMiddle(ti, {}); break; }