4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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 <http://www.gnu.org/licenses/>.
11 * @file bridge_cmd.cpp
12 * This file deals with bridges (non-gui stuff)
17 #include "tunnelbridge.h"
18 #include "landscape.h"
19 #include "slope_func.h"
20 #include "command_func.h"
21 #include "date_func.h"
22 #include "economy_func.h"
23 #include "map/ground.h"
24 #include "map/water.h"
27 #include "map/slope.h"
28 #include "map/tunnelbridge.h"
29 #include "viewport_func.h"
30 #include "transparency.h"
32 #include "elrail_func.h"
33 #include "clear_func.h"
36 #include "newgrf_commons.h"
37 #include "newgrf_railtype.h"
38 #include "newgrf_object.h"
40 #include "table/sprites.h"
41 #include "table/strings.h"
42 #include "table/bridge_land.h"
45 /** Data for CheckExtendedBridgeHead; see the function for details */
46 extern const Slope bridgehead_valid_slopes
[DIAGDIR_END
][2] = {
54 /** Z position of the bridge sprites relative to bridge height (downwards) */
55 static const int BRIDGE_Z_START
= 3;
57 BridgeSpec _bridge
[MAX_BRIDGES
]; ///< The specification of all bridges.
59 /** Reset the data been eventually changed by the grf loaded. */
62 /* First, free sprite table data */
63 for (BridgeType i
= 0; i
< MAX_BRIDGES
; i
++) {
64 if (_bridge
[i
].sprite_table
!= NULL
) {
65 for (BridgePieces j
= BRIDGE_PIECE_NORTH
; j
< BRIDGE_PIECE_INVALID
; j
++) free(_bridge
[i
].sprite_table
[j
]);
66 free(_bridge
[i
].sprite_table
);
70 /* Then, wipe out current bridges */
71 memset(&_bridge
, 0, sizeof(_bridge
));
72 /* And finally, reinstall default data */
73 memcpy(&_bridge
, &_orig_bridge
, sizeof(_orig_bridge
));
77 * Calculate the price factor for building a long bridge.
78 * Basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6, 7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,
79 * @param length Length of the bridge.
80 * @return Price factor for the bridge.
82 int CalcBridgeLenCostFactor(int length
)
84 if (length
<= 2) return length
;
90 for (delta
= 1; delta
< length
; delta
++) {
94 sum
+= delta
* length
;
99 * Get the foundation for a bridge.
100 * @param tileh The slope to build the bridge on.
101 * @param axis The axis of the bridge entrance.
102 * @return The foundation required.
104 Foundation
GetBridgeFoundation(Slope tileh
, Axis axis
)
106 if (tileh
== SLOPE_FLAT
||
107 ((tileh
== SLOPE_NE
|| tileh
== SLOPE_SW
) && axis
== AXIS_X
) ||
108 ((tileh
== SLOPE_NW
|| tileh
== SLOPE_SE
) && axis
== AXIS_Y
)) return FOUNDATION_NONE
;
110 return (HasSlopeHighestCorner(tileh
) ? InclinedFoundation(axis
) : FlatteningFoundation(tileh
));
114 * Get the height ('z') of a bridge.
115 * @param tile the bridge ramp tile to get the bridge height from
116 * @return the height of the bridge.
118 int GetBridgeHeight(TileIndex t
)
121 Slope tileh
= GetTileSlope(t
, &h
);
122 Foundation f
= GetBridgeFoundation(tileh
, DiagDirToAxis(GetTunnelBridgeDirection(t
)));
124 /* one height level extra for the ramp */
125 return h
+ 1 + ApplyFoundationToSlope(f
, &tileh
);
129 * Determines if the track on a bridge ramp is flat or goes up/down.
131 * @param tileh Slope of the tile under the bridge head
132 * @param axis Orientation of bridge
133 * @return true iff the track is flat.
135 bool HasBridgeFlatRamp(Slope tileh
, Axis axis
)
137 ApplyFoundationToSlope(GetBridgeFoundation(tileh
, axis
), &tileh
);
138 /* If the foundation slope is flat the bridge has a non-flat ramp and vice versa. */
139 return (tileh
!= SLOPE_FLAT
);
143 * Check tiles validity for a bridge.
145 * @param tile1 Start tile
146 * @param tile2 End tile
147 * @param axis Pointer to receive bridge axis, or NULL
148 * @return Null cost for success or an error
150 CommandCost
CheckBridgeTiles(TileIndex tile1
, TileIndex tile2
, Axis
*axis
)
152 if (!IsValidTile(tile1
) || !IsValidTile(tile2
)) return_cmd_error(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER
);
154 if (tile1
== tile2
) {
155 return_cmd_error(STR_ERROR_CAN_T_START_AND_END_ON
);
156 } else if (TileX(tile1
) == TileX(tile2
)) {
157 if (axis
!= NULL
) *axis
= AXIS_Y
;
158 } else if (TileY(tile1
) == TileY(tile2
)) {
159 if (axis
!= NULL
) *axis
= AXIS_X
;
161 return_cmd_error(STR_ERROR_START_AND_END_MUST_BE_IN
);
164 return CommandCost();
168 * Check if a bridge can be built.
170 * @param tile1 Start tile
171 * @param tile2 End tile
172 * @param flags type of operation
173 * @param clear1 Try to clear start tile
174 * @param clear2 Try to clear end tile
175 * @param restricted Force flat ramp (for aqueducts)
176 * @return Terraforming cost for success or an error
178 CommandCost
CheckBridgeBuildable(TileIndex tile1
, TileIndex tile2
, DoCommandFlag flags
, bool clear1
, bool clear2
, bool restricted
)
180 DiagDirection dir
= DiagdirBetweenTiles(tile1
, tile2
);
181 assert(IsValidDiagDirection(dir
));
185 Slope tileh1
= GetTileSlope(tile1
, &z1
);
186 Slope tileh2
= GetTileSlope(tile2
, &z2
);
188 CommandCost terraform1
= CheckBridgeSlope(dir
, &tileh1
, &z1
);
189 CommandCost terraform2
= CheckBridgeSlope(ReverseDiagDir(dir
), &tileh2
, &z2
);
191 if (restricted
&& (tileh1
== SLOPE_FLAT
|| tileh2
== SLOPE_FLAT
)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION
);
192 if (z1
!= z2
) return_cmd_error(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT
);
194 bool allow_on_slopes
= (_settings_game
.construction
.build_on_slopes
&& !restricted
);
199 /* Try and clear the start landscape */
200 CommandCost ret
= DoCommand(tile1
, 0, 0, flags
, CMD_LANDSCAPE_CLEAR
);
201 if (ret
.Failed()) return ret
;
204 if (terraform1
.Failed() || (terraform1
.GetCost() != 0 && !allow_on_slopes
)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION
);
205 cost
.AddCost(terraform1
);
207 assert(terraform1
.Succeeded());
211 /* Try and clear the end landscape */
212 CommandCost ret
= DoCommand(tile2
, 0, 0, flags
, CMD_LANDSCAPE_CLEAR
);
213 if (ret
.Failed()) return ret
;
216 if (terraform2
.Failed() || (terraform2
.GetCost() != 0 && !allow_on_slopes
)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION
);
217 cost
.AddCost(terraform2
);
219 assert(terraform2
.Succeeded());
222 const TileIndex heads
[] = {tile1
, tile2
};
223 for (int i
= 0; i
< 2; i
++) {
224 if (HasBridgeAbove(heads
[i
])) {
225 if (DiagDirToAxis(dir
) == GetBridgeAxis(heads
[i
])) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST
);
227 if (z1
+ 1 == GetBridgeHeight(GetNorthernBridgeEnd(heads
[i
]))) {
228 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST
);
233 TileIndexDiff delta
= TileOffsByDiagDir(dir
);
235 for (TileIndex tile
= tile1
+ delta
; tile
!= tile2
; tile
+= delta
) {
236 if (GetTileMaxZ(tile
) > z1
) return_cmd_error(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN
);
238 if (HasBridgeAbove(tile
)) {
239 /* Disallow crossing bridges for the time being */
240 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST
);
243 switch (GetTileType(tile
)) {
245 if (IsPlainWater(tile
) || IsCoast(tile
)) continue;
249 if (IsTileSubtype(tile
, TT_MISC_TUNNEL
)) continue;
250 if (IsTileSubtype(tile
, TT_MISC_DEPOT
)) break;
251 assert(TT_BRIDGE
== TT_MISC_AQUEDUCT
);
255 if (!IsTileSubtype(tile
, TT_BRIDGE
)) continue;
256 if (DiagDirToAxis(dir
) == DiagDirToAxis(GetTunnelBridgeDirection(tile
))) break;
257 if (z1
>= GetBridgeHeight(tile
)) continue;
261 const ObjectSpec
*spec
= ObjectSpec::GetByTile(tile
);
262 if ((spec
->flags
& OBJECT_FLAG_ALLOW_UNDER_BRIDGE
) == 0) break;
263 if (z1
>= GetTileMaxZ(tile
) + spec
->height
) continue;
268 assert(IsGroundTile(tile
));
269 if (!IsTileSubtype(tile
, TT_GROUND_TREES
)) continue;
276 /* try and clear the middle landscape */
277 CommandCost ret
= DoCommand(tile
, 0, 0, flags
, CMD_LANDSCAPE_CLEAR
);
278 if (ret
.Failed()) return ret
;
286 * Is a bridge of the specified type and length available?
287 * @param bridge_type Wanted type of bridge.
288 * @param bridge_len Wanted length of the bridge.
289 * @return A succeeded (the requested bridge is available) or failed (it cannot be built) command.
291 CommandCost
CheckBridgeAvailability(BridgeType bridge_type
, uint bridge_len
, DoCommandFlag flags
)
293 if (flags
& DC_QUERY_COST
) {
294 if (bridge_len
<= _settings_game
.construction
.max_bridge_length
) return CommandCost();
295 return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG
);
298 if (bridge_type
>= MAX_BRIDGES
) return CMD_ERROR
;
300 const BridgeSpec
*b
= GetBridgeSpec(bridge_type
);
301 if (b
->avail_year
> _cur_year
) return CMD_ERROR
;
303 uint max
= min(b
->max_length
, _settings_game
.construction
.max_bridge_length
);
305 if (b
->min_length
> bridge_len
) return CMD_ERROR
;
306 if (bridge_len
<= max
) return CommandCost();
307 return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG
);
311 * Determines the foundation for a bridge head, and tests if the resulting slope is valid.
313 * @param dir Diagonal direction the bridge ramp will be facing
314 * @param tileh Slope of the tile under the bridge head; returns slope on top of foundation
315 * @param z TileZ corresponding to tileh, gets modified as well
316 * @return Error or cost for bridge foundation
318 CommandCost
CheckBridgeSlope(DiagDirection dir
, Slope
*tileh
, int *z
)
320 static const Slope inclined
[DIAGDIR_END
] = {
321 SLOPE_SW
, ///< DIAGDIR_NE
322 SLOPE_NW
, ///< DIAGDIR_SE
323 SLOPE_NE
, ///< DIAGDIR_SW
324 SLOPE_SE
, ///< DIAGDIR_NW
327 Foundation f
= GetBridgeFoundation(*tileh
, DiagDirToAxis(dir
));
328 *z
+= ApplyFoundationToSlope(f
, tileh
);
330 if ((*tileh
!= SLOPE_FLAT
) && (*tileh
!= inclined
[dir
])) return CMD_ERROR
;
332 if (f
== FOUNDATION_NONE
) return CommandCost();
334 return CommandCost(EXPENSES_CONSTRUCTION
, _price
[PR_BUILD_FOUNDATION
]);
338 * Set bridge axis on a new bridge middle tiles, and mark them dirty
340 * @param tile1 Bridge start tile
341 * @param tile2 Bridge end tile
342 * @param direction Bridge axis
344 void SetBridgeMiddleTiles(TileIndex tile1
, TileIndex tile2
, Axis direction
)
346 assert(tile1
< tile2
);
348 MarkTileDirtyByTile(tile1
);
349 MarkTileDirtyByTile(tile2
);
351 TileIndexDiff delta
= TileOffsByDiagDir(AxisToDiagDir(direction
));
352 for (TileIndex tile
= tile1
+ delta
; tile
< tile2
; tile
+= delta
) {
353 SetBridgeMiddle(tile
, direction
);
354 MarkTileDirtyByTile(tile
);
359 * Clear middle bridge tiles
361 * @param tile1 Bridge start tile
362 * @param tile2 Bridge end tile
364 void RemoveBridgeMiddleTiles(TileIndex tile1
, TileIndex tile2
)
366 /* Call this function before clearing the endpoints. */
367 assert(IsBridgeHeadTile(tile1
));
368 assert(IsBridgeHeadTile(tile2
));
370 TileIndexDiff delta
= TileOffsByDiagDir(GetTunnelBridgeDirection(tile1
));
371 int height
= GetBridgeHeight(tile1
);
373 for (TileIndex t
= tile1
+ delta
; t
!= tile2
; t
+= delta
) {
374 /* do not let trees appear from 'nowhere' after removing bridge */
375 if (IsNormalRoadTile(t
) && GetRoadside(t
) == ROADSIDE_TREES
) {
376 int minz
= GetTileMaxZ(t
) + 3;
377 if (height
< minz
) SetRoadside(t
, ROADSIDE_PAVED
);
379 ClearBridgeMiddle(t
);
380 MarkTileDirtyByTile(t
);
385 static inline const PalSpriteID
*GetBridgeSpriteTable(int index
, BridgePieces table
)
387 const BridgeSpec
*bridge
= GetBridgeSpec(index
);
388 assert(table
< BRIDGE_PIECE_INVALID
);
389 if (bridge
->sprite_table
== NULL
|| bridge
->sprite_table
[table
] == NULL
) {
390 return _bridge_sprite_table
[index
][table
];
392 return bridge
->sprite_table
[table
];
397 * Draw a single pillar sprite.
398 * @param psid Pillarsprite
402 * @param w Bounding box size in X direction
403 * @param h Bounding box size in Y direction
404 * @param subsprite Optional subsprite for drawing halfpillars
406 static inline void DrawPillar(const PalSpriteID
*psid
, int x
, int y
, int z
, int w
, int h
, const SubSprite
*subsprite
)
408 static const int PILLAR_Z_OFFSET
= TILE_HEIGHT
- BRIDGE_Z_START
; ///< Start offset of pillar wrt. bridge (downwards)
409 AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, x
, y
, w
, h
, BB_HEIGHT_UNDER_BRIDGE
- PILLAR_Z_OFFSET
, z
, IsTransparencySet(TO_BRIDGES
), 0, 0, -PILLAR_Z_OFFSET
, subsprite
);
413 * Draw two bridge pillars (north and south).
414 * @param z_bottom Bottom Z
416 * @param psid Pillarsprite
419 * @param w Bounding box size in X direction
420 * @param h Bounding box size in Y direction
421 * @return Reached Z at the bottom
423 static int DrawPillarColumn(int z_bottom
, int z_top
, const PalSpriteID
*psid
, int x
, int y
, int w
, int h
)
426 for (cur_z
= z_top
; cur_z
>= z_bottom
; cur_z
-= TILE_HEIGHT
) {
427 DrawPillar(psid
, x
, y
, cur_z
, w
, h
, NULL
);
433 * Draws the pillars under high bridges.
435 * @param psid Image and palette of a bridge pillar.
436 * @param ti #TileInfo of current bridge-middle-tile.
437 * @param axis Orientation of bridge.
438 * @param drawfarpillar Whether to draw the pillar at the back
439 * @param x Sprite X position of front pillar.
440 * @param y Sprite Y position of front pillar.
441 * @param z_bridge Absolute height of bridge bottom.
443 static void DrawBridgePillars(const PalSpriteID
*psid
, const TileInfo
*ti
, Axis axis
, bool drawfarpillar
, int x
, int y
, int z_bridge
)
445 static const int bounding_box_size
[2] = {16, 2}; ///< bounding box size of pillars along bridge direction
446 static const int back_pillar_offset
[2] = { 0, 9}; ///< sprite position offset of back facing pillar
448 static const int INF
= 1000; ///< big number compared to sprite size
449 static const SubSprite half_pillar_sub_sprite
[2][2] = {
450 { { -14, -INF
, INF
, INF
}, { -INF
, -INF
, -15, INF
} }, // X axis, north and south
451 { { -INF
, -INF
, 15, INF
}, { 16, -INF
, INF
, INF
} }, // Y axis, north and south
454 if (psid
->sprite
== 0) return;
456 /* Determine ground height under pillars */
457 DiagDirection south_dir
= AxisToDiagDir(axis
);
458 int z_front_north
= ti
->z
;
459 int z_back_north
= ti
->z
;
460 int z_front_south
= ti
->z
;
461 int z_back_south
= ti
->z
;
462 GetSlopePixelZOnEdge(ti
->tileh
, south_dir
, &z_front_south
, &z_back_south
);
463 GetSlopePixelZOnEdge(ti
->tileh
, ReverseDiagDir(south_dir
), &z_front_north
, &z_back_north
);
465 /* Shared height of pillars */
466 int z_front
= max(z_front_north
, z_front_south
);
467 int z_back
= max(z_back_north
, z_back_south
);
469 /* x and y size of bounding-box of pillars */
470 int w
= bounding_box_size
[axis
];
471 int h
= bounding_box_size
[OtherAxis(axis
)];
472 /* sprite position of back facing pillar */
473 int x_back
= x
- back_pillar_offset
[axis
];
474 int y_back
= y
- back_pillar_offset
[OtherAxis(axis
)];
476 /* Draw front pillars */
477 int bottom_z
= DrawPillarColumn(z_front
, z_bridge
, psid
, x
, y
, w
, h
);
478 if (z_front_north
< z_front
) DrawPillar(psid
, x
, y
, bottom_z
, w
, h
, &half_pillar_sub_sprite
[axis
][0]);
479 if (z_front_south
< z_front
) DrawPillar(psid
, x
, y
, bottom_z
, w
, h
, &half_pillar_sub_sprite
[axis
][1]);
481 /* Draw back pillars, skip top two parts, which are hidden by the bridge */
482 int z_bridge_back
= z_bridge
- 2 * (int)TILE_HEIGHT
;
483 if (drawfarpillar
&& (z_back_north
<= z_bridge_back
|| z_back_south
<= z_bridge_back
)) {
484 bottom_z
= DrawPillarColumn(z_back
, z_bridge_back
, psid
, x_back
, y_back
, w
, h
);
485 if (z_back_north
< z_back
) DrawPillar(psid
, x_back
, y_back
, bottom_z
, w
, h
, &half_pillar_sub_sprite
[axis
][0]);
486 if (z_back_south
< z_back
) DrawPillar(psid
, x_back
, y_back
, bottom_z
, w
, h
, &half_pillar_sub_sprite
[axis
][1]);
491 * Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge.
492 * bridges pieces sequence (middle parts).
493 * Note that it is not covering the bridge heads, which are always referenced by the same sprite table.
494 * bridge len 1: BRIDGE_PIECE_NORTH
495 * bridge len 2: BRIDGE_PIECE_NORTH BRIDGE_PIECE_SOUTH
496 * bridge len 3: BRIDGE_PIECE_NORTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_SOUTH
497 * bridge len 4: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
498 * bridge len 5: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_MIDDLE_EVEN BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
499 * bridge len 6: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
500 * bridge len 7: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
501 * #0 - always as first, #1 - always as last (if len>1)
502 * #2,#3 are to pair in order
503 * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
504 * @param north Northernmost tile of bridge
505 * @param south Southernmost tile of bridge
506 * @return Index of bridge piece
508 static BridgePieces
CalcBridgePiece(uint north
, uint south
)
511 return BRIDGE_PIECE_NORTH
;
512 } else if (south
== 1) {
513 return BRIDGE_PIECE_SOUTH
;
514 } else if (north
< south
) {
515 return north
& 1 ? BRIDGE_PIECE_INNER_SOUTH
: BRIDGE_PIECE_INNER_NORTH
;
516 } else if (north
> south
) {
517 return south
& 1 ? BRIDGE_PIECE_INNER_NORTH
: BRIDGE_PIECE_INNER_SOUTH
;
519 return north
& 1 ? BRIDGE_PIECE_MIDDLE_EVEN
: BRIDGE_PIECE_MIDDLE_ODD
;
524 * Draws the trambits over an already drawn (lower end) of a bridge.
525 * @param x the x of the bridge
526 * @param y the y of the bridge
527 * @param z the z of the bridge
528 * @param offset number representing whether to level or sloped and the direction
529 * @param overlay do we want to still see the road?
530 * @param head are we drawing bridge head?
532 void DrawBridgeTramBits(int x
, int y
, int z
, int offset
, bool overlay
, bool head
)
534 static const SpriteID tram_offsets
[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } };
535 static const SpriteID back_offsets
[6] = { 95, 96, 99, 102, 100, 101 };
536 static const SpriteID front_offsets
[6] = { 97, 98, 103, 106, 104, 105 };
538 static const uint size_x
[6] = { 1, 16, 16, 1, 16, 1 };
539 static const uint size_y
[6] = { 16, 1, 1, 16, 1, 16 };
540 static const uint front_bb_offset_x
[6] = { 15, 0, 0, 15, 0, 15 };
541 static const uint front_bb_offset_y
[6] = { 0, 15, 15, 0, 15, 0 };
543 /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
544 * The bounding boxes here are the same as for bridge front/roof */
545 if (head
|| !IsInvisibilitySet(TO_BRIDGES
)) {
546 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE
+ tram_offsets
[overlay
][offset
], PAL_NONE
,
547 x
, y
, size_x
[offset
], size_y
[offset
], 0x28, z
,
548 !head
&& IsTransparencySet(TO_BRIDGES
));
551 /* Do not draw catenary if it is set invisible */
552 if (!IsInvisibilitySet(TO_CATENARY
)) {
553 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE
+ back_offsets
[offset
], PAL_NONE
,
554 x
, y
, size_x
[offset
], size_y
[offset
], 0x28, z
,
555 IsTransparencySet(TO_CATENARY
));
558 /* Start a new SpriteCombine for the front part */
560 StartSpriteCombine();
562 /* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */
563 if (!IsInvisibilitySet(TO_CATENARY
)) {
564 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE
+ front_offsets
[offset
], PAL_NONE
,
565 x
, y
, size_x
[offset
] + front_bb_offset_x
[offset
], size_y
[offset
] + front_bb_offset_y
[offset
], 0x28, z
,
566 IsTransparencySet(TO_CATENARY
), front_bb_offset_x
[offset
], front_bb_offset_y
[offset
]);
571 * Draw the middle bits of a bridge.
572 * @param ti Tile information of the tile to draw it on.
574 void DrawBridgeMiddle(const TileInfo
*ti
)
576 /* Sectional view of bridge bounding boxes:
578 * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and TramCatenary
579 * 1 2 3 = empty helper BB
580 * 1 7 2 4,5 = pillars under higher bridges
581 * 1 6 88888 6 2 6 = elrail-pylons
582 * 1 6 88888 6 2 7 = elrail-wire
583 * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge
584 * 3333333333333 <- BB_Z_SEPARATOR
586 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
592 if (!IsBridgeAbove(ti
->tile
)) return;
594 TileIndex rampnorth
= GetNorthernBridgeEnd(ti
->tile
);
595 TileIndex rampsouth
= GetSouthernBridgeEnd(ti
->tile
);
597 Axis axis
= GetBridgeAxis(ti
->tile
);
598 BridgePieces piece
= CalcBridgePiece(
599 GetTunnelBridgeLength(ti
->tile
, rampnorth
) + 1,
600 GetTunnelBridgeLength(ti
->tile
, rampsouth
) + 1
603 TransportType transport_type
;
604 const PalSpriteID
*psid
;
607 if (IsTileType(rampsouth
, TT_MISC
)) {
608 assert(IsAqueductTile(rampsouth
));
609 transport_type
= TRANSPORT_WATER
;
610 psid
= _aqueduct_sprites
;
611 drawfarpillar
= true;
613 assert(IsTileSubtype(rampsouth
, TT_BRIDGE
));
618 if (IsRailwayTile(rampsouth
)) {
619 transport_type
= TRANSPORT_RAIL
;
620 type
= GetRailBridgeType(rampsouth
);
621 base_offset
= GetRailTypeInfo(GetBridgeRailType(rampsouth
))->bridge_offset
;
623 transport_type
= TRANSPORT_ROAD
;
624 type
= GetRoadBridgeType(rampsouth
);
628 psid
= base_offset
+ GetBridgeSpriteTable(type
, piece
);
629 drawfarpillar
= !HasBit(GetBridgeSpec(type
)->flags
, 0);
632 if (axis
!= AXIS_X
) psid
+= 4;
636 uint bridge_z
= GetBridgePixelHeight(rampsouth
);
637 int z
= bridge_z
- BRIDGE_Z_START
;
639 /* Add a bounding box that separates the bridge from things below it. */
640 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX
, PAL_NONE
, x
, y
, 16, 16, 1, bridge_z
- TILE_HEIGHT
+ BB_Z_SEPARATOR
);
642 /* Draw Trambits as SpriteCombine */
643 if (transport_type
== TRANSPORT_ROAD
|| transport_type
== TRANSPORT_RAIL
) StartSpriteCombine();
645 /* Draw floor and far part of bridge*/
646 if (!IsInvisibilitySet(TO_BRIDGES
)) {
647 if (axis
== AXIS_X
) {
648 AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, x
, y
, 16, 1, 0x28, z
, IsTransparencySet(TO_BRIDGES
), 0, 0, BRIDGE_Z_START
);
650 AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, x
, y
, 1, 16, 0x28, z
, IsTransparencySet(TO_BRIDGES
), 0, 0, BRIDGE_Z_START
);
656 if (transport_type
== TRANSPORT_ROAD
) {
657 RoadBits bits
= DiagDirToRoadBits(axis
== AXIS_X
? DIAGDIR_NE
: DIAGDIR_NW
);
659 if ((GetRoadBits(rampsouth
, ROADTYPE_TRAM
) & bits
) != 0) {
660 /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */
661 DrawBridgeTramBits(x
, y
, bridge_z
, axis
^ 1, (GetRoadBits(rampsouth
, ROADTYPE_ROAD
) & bits
) != 0, false);
664 StartSpriteCombine();
666 } else if (transport_type
== TRANSPORT_RAIL
) {
667 const RailtypeInfo
*rti
= GetRailTypeInfo(GetBridgeRailType(rampsouth
));
668 if (rti
->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES
)) {
669 SpriteID surface
= GetCustomRailSprite(rti
, rampsouth
, RTSG_BRIDGE
, TCX_ON_BRIDGE
);
671 AddSortableSpriteToDraw(surface
+ axis
, PAL_NONE
, x
, y
, 16, 16, 0, bridge_z
, IsTransparencySet(TO_BRIDGES
));
676 if (HasCatenaryDrawn(GetBridgeRailType(rampsouth
))) {
677 DrawCatenaryOnBridge(ti
);
681 /* draw roof, the component of the bridge which is logically between the vehicle and the camera */
682 if (!IsInvisibilitySet(TO_BRIDGES
)) {
683 if (axis
== AXIS_X
) {
685 if (psid
->sprite
& SPRITE_MASK
) AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, x
, y
, 16, 4, 0x28, z
, IsTransparencySet(TO_BRIDGES
), 0, 3, BRIDGE_Z_START
);
688 if (psid
->sprite
& SPRITE_MASK
) AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, x
, y
, 4, 16, 0x28, z
, IsTransparencySet(TO_BRIDGES
), 3, 0, BRIDGE_Z_START
);
692 /* Draw TramFront as SpriteCombine */
693 if (transport_type
== TRANSPORT_ROAD
) EndSpriteCombine();
695 /* Do not draw anything more if bridges are invisible */
696 if (IsInvisibilitySet(TO_BRIDGES
)) return;
699 if (ti
->z
+ 5 == z
) {
700 /* draw poles below for small bridges */
701 if (psid
->sprite
!= 0) {
702 SpriteID image
= psid
->sprite
;
703 SpriteID pal
= psid
->pal
;
704 if (IsTransparencySet(TO_BRIDGES
)) {
705 SetBit(image
, PALETTE_MODIFIER_TRANSPARENT
);
706 pal
= PALETTE_TO_TRANSPARENT
;
709 DrawGroundSpriteAt(image
, pal
, x
- ti
->x
, y
- ti
->y
, z
- ti
->z
);
712 /* draw pillars below for high bridges */
713 DrawBridgePillars(psid
, ti
, axis
, drawfarpillar
, x
, y
, z
);
717 void DrawBridgeGround(TileInfo
*ti
)
719 DiagDirection dir
= GetTunnelBridgeDirection(ti
->tile
);
721 DrawFoundation(ti
, GetBridgeFoundation(ti
->tileh
, DiagDirToAxis(dir
)));
723 if (IsOnSnow(ti
->tile
)) {
724 DrawGroundSprite(SPR_FLAT_SNOW_DESERT_TILE
+ SlopeToSpriteOffset(ti
->tileh
), PAL_NONE
);
726 TileIndex next
= ti
->tile
+ TileOffsByDiagDir(dir
);
727 if (ti
->tileh
!= SLOPE_FLAT
&& ti
->z
== 0 && HasTileWaterClass(next
) && GetWaterClass(next
) == WATER_CLASS_SEA
) {
728 DrawShoreTile(ti
->tileh
);
730 DrawClearLandTile(ti
, 3);
735 const PalSpriteID
*GetBridgeRampSprite(int index
, int offset
, Slope slope
, DiagDirection dir
)
737 /* as the lower 3 bits are used for other stuff, make sure they are clear */
738 assert((offset
& 0x07) == 0x00);
740 if (slope
== SLOPE_FLAT
) offset
+= 4; // sloped bridge head
742 /* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
743 offset
+= (6 - dir
) % 4;
745 /* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
746 return offset
+ GetBridgeSpriteTable(index
, BRIDGE_PIECE_HEAD
);
749 void DrawAqueductRamp(TileInfo
*ti
)
751 DrawBridgeGround(ti
);
753 assert(ti
->tileh
!= SLOPE_FLAT
);
755 DiagDirection dir
= GetTunnelBridgeDirection(ti
->tile
);
757 /* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
758 const PalSpriteID
*psid
= _aqueduct_sprites
+ 8 + (6 - dir
) % 4;
760 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
761 * it doesn't disappear behind it
763 /* Bridge heads are drawn solid no matter how invisibility/transparency is set */
764 AddSortableSpriteToDraw(psid
->sprite
, psid
->pal
, ti
->x
, ti
->y
, 16, 16, 8, ti
->z
);