1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-30 18:09:09 +00:00

Change: Hide bridge pillars if obstructed by tile below.

Tiles can now control if pillars are drawn on a bridge above it. There is no visible change with default bridges.
This commit is contained in:
2025-08-14 17:32:05 +01:00
committed by Peter Nelson
parent 48b42492bc
commit 0a1c0b8b48
7 changed files with 70 additions and 13 deletions

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);
}
/**

View File

@@ -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<const PalSpriteID> 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);
}

View File

@@ -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;
}