Extend object variable 0x60 to also return the view
[openttd/fttd.git] / src / bridge_cmd.cpp
blob0c9c8726dd0ef669b6615716c75f8b52f8b7d058
1 /* $Id$ */
3 /*
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/>.
8 */
10 /**
11 * @file bridge_cmd.cpp
12 * This file deals with bridges (non-gui stuff)
15 #include "stdafx.h"
16 #include "bridge.h"
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"
25 #include "map/rail.h"
26 #include "map/road.h"
27 #include "map/slope.h"
28 #include "map/tunnelbridge.h"
29 #include "viewport_func.h"
30 #include "transparency.h"
31 #include "rail.h"
32 #include "elrail_func.h"
33 #include "clear_func.h"
34 #include "water.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] = {
47 { SLOPE_W, SLOPE_S },
48 { SLOPE_N, SLOPE_W },
49 { SLOPE_E, SLOPE_N },
50 { SLOPE_S, SLOPE_E },
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. */
60 void ResetBridges()
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));
76 /**
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;
86 length -= 2;
87 int sum = 2;
89 int delta;
90 for (delta = 1; delta < length; delta++) {
91 sum += delta * delta;
92 length -= delta;
94 sum += delta * length;
95 return sum;
98 /**
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)
120 int h;
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;
160 } else {
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));
183 int z1;
184 int z2;
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);
196 CommandCost cost;
198 if (clear1) {
199 /* Try and clear the start landscape */
200 CommandCost ret = DoCommand(tile1, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
201 if (ret.Failed()) return ret;
202 cost.AddCost(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);
206 } else {
207 assert(terraform1.Succeeded());
210 if (clear2) {
211 /* Try and clear the end landscape */
212 CommandCost ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
213 if (ret.Failed()) return ret;
214 cost.AddCost(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);
218 } else {
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)) {
244 case TT_WATER:
245 if (IsPlainWater(tile) || IsCoast(tile)) continue;
246 break;
248 case TT_MISC:
249 if (IsTileSubtype(tile, TT_MISC_TUNNEL)) continue;
250 if (IsTileSubtype(tile, TT_MISC_DEPOT)) break;
251 assert(TT_BRIDGE == TT_MISC_AQUEDUCT);
252 /* fall through */
253 case TT_RAILWAY:
254 case TT_ROAD:
255 if (!IsTileSubtype(tile, TT_BRIDGE)) continue;
256 if (DiagDirToAxis(dir) == DiagDirToAxis(GetTunnelBridgeDirection(tile))) break;
257 if (z1 >= GetBridgeHeight(tile)) continue;
258 break;
260 case TT_OBJECT: {
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;
264 break;
267 case TT_GROUND:
268 assert(IsGroundTile(tile));
269 if (!IsTileSubtype(tile, TT_GROUND_TREES)) continue;
270 break;
272 default:
273 break;
276 /* try and clear the middle landscape */
277 CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
278 if (ret.Failed()) return ret;
279 cost.AddCost(ret);
282 return cost;
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];
391 } else {
392 return bridge->sprite_table[table];
397 * Draw a single pillar sprite.
398 * @param psid Pillarsprite
399 * @param x Pillar X
400 * @param y Pillar Y
401 * @param z Pillar Z
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
415 * @param z_top Top Z
416 * @param psid Pillarsprite
417 * @param x Pillar X
418 * @param y Pillar Y
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)
425 int cur_z;
426 for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
427 DrawPillar(psid, x, y, cur_z, w, h, NULL);
429 return cur_z;
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)
510 if (north == 1) {
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;
518 } else {
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 */
559 EndSpriteCombine();
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
585 * <- unused
586 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
587 * 4 5
588 * 4 5
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;
605 bool drawfarpillar;
607 if (IsTileType(rampsouth, TT_MISC)) {
608 assert(IsAqueductTile(rampsouth));
609 transport_type = TRANSPORT_WATER;
610 psid = _aqueduct_sprites;
611 drawfarpillar = true;
612 } else {
613 assert(IsTileSubtype(rampsouth, TT_BRIDGE));
615 BridgeType type;
616 uint base_offset;
618 if (IsRailwayTile(rampsouth)) {
619 transport_type = TRANSPORT_RAIL;
620 type = GetRailBridgeType(rampsouth);
621 base_offset = GetRailTypeInfo(GetBridgeRailType(rampsouth))->bridge_offset;
622 } else {
623 transport_type = TRANSPORT_ROAD;
624 type = GetRoadBridgeType(rampsouth);
625 base_offset = 8;
628 psid = base_offset + GetBridgeSpriteTable(type, piece);
629 drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
632 if (axis != AXIS_X) psid += 4;
634 int x = ti->x;
635 int y = ti->y;
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);
649 } else {
650 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
654 psid++;
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);
662 } else {
663 EndSpriteCombine();
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);
670 if (surface != 0) {
671 AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
674 EndSpriteCombine();
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) {
684 y += 12;
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);
686 } else {
687 x += 12;
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;
698 psid++;
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);
711 } else {
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);
725 } else {
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);
729 } else {
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);