bridge_cmd.c
branchcustombridgeheads
changeset 5594 04068f82afaa
parent 5593 3e0dd1f014ca
child 5595 049ed4486972
equal deleted inserted replaced
5593:3e0dd1f014ca 5594:04068f82afaa
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file tunnelbridge_cmd.c
       
     4  * This file deals with tunnels and bridges (non-gui stuff)
       
     5  * @todo seperate this file into two
       
     6  */
       
     7 
       
     8 #include "stdafx.h"
       
     9 #include "openttd.h"
       
    10 #include "bridge_map.h"
       
    11 #include "rail_map.h"
       
    12 #include "road_map.h"
       
    13 #include "table/sprites.h"
       
    14 #include "table/strings.h"
       
    15 #include "functions.h"
       
    16 #include "map.h"
       
    17 #include "tile.h"
       
    18 #include "tunnel_map.h"
       
    19 #include "unmovable_map.h"
       
    20 #include "vehicle.h"
       
    21 #include "viewport.h"
       
    22 #include "command.h"
       
    23 #include "player.h"
       
    24 #include "town.h"
       
    25 #include "sound.h"
       
    26 #include "variables.h"
       
    27 #include "bridge.h"
       
    28 #include "train.h"
       
    29 #include "water_map.h"
       
    30 #include "yapf/yapf.h"
       
    31 #include "date.h"
       
    32 #include "newgrf_sound.h"
       
    33 
       
    34 #include "table/bridge_land.h"
       
    35 
       
    36 const Bridge orig_bridge[] = {
       
    37 /*
       
    38 	     year of availablity
       
    39 	     |  minimum length
       
    40 	     |  |   maximum length
       
    41 	     |  |   |    price
       
    42 	     |  |   |    |    maximum speed
       
    43 	     |  |   |    |    |  sprite to use in GUI                string with description
       
    44 	     |  |   |    |    |  |                                   |                            */
       
    45 	{    0, 0, 16,  80,  32, 0xA24                             , STR_5012_WOODEN             , NULL, 0 },
       
    46 	{    0, 0,  2, 112,  48, 0xA26 | PALETTE_TO_STRUCT_RED     , STR_5013_CONCRETE           , NULL, 0 },
       
    47 	{ 1930, 0,  5, 144,  64, 0xA25                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
       
    48 	{    0, 2, 10, 168,  80, 0xA22 | PALETTE_TO_STRUCT_CONCRETE, STR_5011_SUSPENSION_CONCRETE, NULL, 0 },
       
    49 	{ 1930, 3, 16, 185,  96, 0xA22                             , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
       
    50 	{ 1930, 3, 16, 192, 112, 0xA22 | PALETTE_TO_STRUCT_YELLOW  , STR_500E_SUSPENSION_STEEL   , NULL, 0 },
       
    51 	{ 1930, 3,  7, 224, 160, 0xA23                             , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
       
    52 	{ 1930, 3,  8, 232, 208, 0xA23 | PALETTE_TO_STRUCT_BROWN   , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
       
    53 	{ 1930, 3,  9, 248, 240, 0xA23 | PALETTE_TO_STRUCT_RED     , STR_5010_CANTILEVER_STEEL   , NULL, 0 },
       
    54 	{ 1930, 0,  2, 240, 256, 0xA27                             , STR_500F_GIRDER_STEEL       , NULL, 0 },
       
    55 	{ 1995, 2, 16, 255, 320, 0xA28                             , STR_5014_TUBULAR_STEEL      , NULL, 0 },
       
    56 	{ 2005, 2, 32, 380, 512, 0xA28 | PALETTE_TO_STRUCT_YELLOW  , STR_5014_TUBULAR_STEEL      , NULL, 0 },
       
    57 	{ 2010, 2, 32, 510, 608, 0xA28 | PALETTE_TO_STRUCT_GREY    , STR_BRIDGE_TUBULAR_SILICON  , NULL, 0 }
       
    58 };
       
    59 
       
    60 Bridge _bridge[MAX_BRIDGES];
       
    61 
       
    62 
       
    63 // calculate the price factor for building a long bridge.
       
    64 // 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,
       
    65 int CalcBridgeLenCostFactor(int x)
       
    66 {
       
    67 	int n;
       
    68 	int r;
       
    69 
       
    70 	if (x < 2) return x;
       
    71 	x -= 2;
       
    72 	for (n = 0, r = 2;; n++) {
       
    73 		if (x <= n) return r + x * n;
       
    74 		r += n * n;
       
    75 		x -= n;
       
    76 	}
       
    77 }
       
    78 
       
    79 #define M(x) (1 << (x))
       
    80 enum {
       
    81 	// foundation, whole tile is leveled up --> 3 corners raised
       
    82 	BRIDGE_FULL_LEVELED_FOUNDATION = M(SLOPE_WSE) | M(SLOPE_NWS) | M(SLOPE_ENW) | M(SLOPE_SEN),
       
    83 	// foundation, tile is partly leveled up --> 1 corner raised
       
    84 	BRIDGE_PARTLY_LEVELED_FOUNDATION = M(SLOPE_W) | M(SLOPE_S) | M(SLOPE_E) | M(SLOPE_N),
       
    85 	// no foundations (X,Y direction)
       
    86 	BRIDGE_NO_FOUNDATION = M(SLOPE_FLAT) | M(SLOPE_SW) | M(SLOPE_SE) | M(SLOPE_NW) | M(SLOPE_NE),
       
    87 	BRIDGE_HORZ_RAMP = (BRIDGE_PARTLY_LEVELED_FOUNDATION | BRIDGE_NO_FOUNDATION) & ~M(SLOPE_FLAT)
       
    88 };
       
    89 #undef M
       
    90 
       
    91 static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
       
    92 {
       
    93 	const Bridge *bridge = &_bridge[index];
       
    94 	assert(table < 7);
       
    95 	if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
       
    96 		return _bridge_sprite_table[index][table];
       
    97 	} else {
       
    98 		return bridge->sprite_table[table];
       
    99 	}
       
   100 }
       
   101 
       
   102 static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;}
       
   103 
       
   104 
       
   105 /** Check the slope at the bridge ramps in three easy steps:
       
   106  * - valid slopes without foundation
       
   107  * - valid slopes with foundation
       
   108  * - rest is invalid
       
   109  */
       
   110 #define M(x) (1 << (x))
       
   111 static int32 CheckBridgeSlopeNorth(Axis axis, Slope tileh)
       
   112 {
       
   113 	uint32 valid;
       
   114 
       
   115 	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW));
       
   116 	if (HASBIT(valid, tileh)) return 0;
       
   117 
       
   118 	valid =
       
   119 		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) |
       
   120 		(axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W));
       
   121 	if (HASBIT(valid, tileh)) return _price.terraform;
       
   122 
       
   123 	return CMD_ERROR;
       
   124 }
       
   125 
       
   126 static int32 CheckBridgeSlopeSouth(Axis axis, Slope tileh)
       
   127 {
       
   128 	uint32 valid;
       
   129 
       
   130 	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_SW) : M(SLOPE_SE));
       
   131 	if (HASBIT(valid, tileh)) return 0;
       
   132 
       
   133 	valid =
       
   134 		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_S) | M(SLOPE_STEEP_S) |
       
   135 		(axis == AXIS_X ? M(SLOPE_W) | M(SLOPE_STEEP_W) : M(SLOPE_E) | M(SLOPE_STEEP_E));
       
   136 	if (HASBIT(valid, tileh)) return _price.terraform;
       
   137 
       
   138 	return CMD_ERROR;
       
   139 }
       
   140 #undef M
       
   141 
       
   142 
       
   143 uint32 GetBridgeLength(TileIndex begin, TileIndex end)
       
   144 {
       
   145 	int x1 = TileX(begin);
       
   146 	int y1 = TileY(begin);
       
   147 	int x2 = TileX(end);
       
   148 	int y2 = TileY(end);
       
   149 
       
   150 	return abs(x2 + y2 - x1 - y1) - 1;
       
   151 }
       
   152 
       
   153 bool CheckBridge_Stuff(byte bridge_type, uint bridge_len)
       
   154 {
       
   155 	const Bridge *b = &_bridge[bridge_type];
       
   156 	uint max; // max possible length of a bridge (with patch 100)
       
   157 
       
   158 	if (bridge_type >= MAX_BRIDGES) return false;
       
   159 	if (b->avail_year > _cur_year) return false;
       
   160 
       
   161 	max = b->max_length;
       
   162 	if (max >= 16 && _patches.longbridges) max = 100;
       
   163 
       
   164 	return b->min_length <= bridge_len && bridge_len <= max;
       
   165 }
       
   166 
       
   167 /** Build a Bridge
       
   168  * @param end_tile end tile
       
   169  * @param p1 packed start tile coords (~ dx)
       
   170  * @param p2 various bitstuffed elements
       
   171  * - p2 = (bit 0- 7) - bridge type (hi bh)
       
   172  * - p2 = (bit 8-..) - rail type. bit15 ((x>>8)&0x80) means road bridge.
       
   173  */
       
   174 int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
       
   175 {
       
   176 	int bridge_type;
       
   177 	TransportType transport;
       
   178 	RailType railtype;
       
   179 	uint x;
       
   180 	uint y;
       
   181 	uint sx;
       
   182 	uint sy;
       
   183 	TileIndex tile_start;
       
   184 	TileIndex tile_end;
       
   185 	Slope tileh_start;
       
   186 	Slope tileh_end;
       
   187 	uint z_start;
       
   188 	uint z_end;
       
   189 	TileIndex tile;
       
   190 	TileIndexDiff delta;
       
   191 	uint bridge_len;
       
   192 	Axis direction;
       
   193 	int32 cost, terraformcost, ret;
       
   194 	bool allow_on_slopes;
       
   195 
       
   196 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   197 
       
   198 	/* unpack parameters */
       
   199 	bridge_type = GB(p2, 0, 8);
       
   200 
       
   201 	if (p1 >= MapSize()) return CMD_ERROR;
       
   202 
       
   203 	// type of bridge
       
   204 	if (HASBIT(p2, 15)) {
       
   205 		railtype = 0;
       
   206 		transport = TRANSPORT_ROAD;
       
   207 	} else {
       
   208 		if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR;
       
   209 		railtype = GB(p2, 8, 8);
       
   210 		transport = TRANSPORT_RAIL;
       
   211 	}
       
   212 
       
   213 	x = TileX(end_tile);
       
   214 	y = TileY(end_tile);
       
   215 	sx = TileX(p1);
       
   216 	sy = TileY(p1);
       
   217 
       
   218 	/* check if valid, and make sure that (x,y) are smaller than (sx,sy) */
       
   219 	if (x == sx) {
       
   220 		if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
       
   221 		direction = AXIS_Y;
       
   222 		if (y > sy) uintswap(y,sy);
       
   223 	} else if (y == sy) {
       
   224 		direction = AXIS_X;
       
   225 		if (x > sx) uintswap(x,sx);
       
   226 	} else {
       
   227 		return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
       
   228 	}
       
   229 
       
   230 	/* set and test bridge length, availability */
       
   231 	bridge_len = sx + sy - x - y - 1;
       
   232 	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
       
   233 
       
   234 	/* retrieve landscape height and ensure it's on land */
       
   235 	tile_start = TileXY(x, y);
       
   236 	tile_end = TileXY(sx, sy);
       
   237 	if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) {
       
   238 		return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
       
   239 	}
       
   240 
       
   241 	tileh_start = GetTileSlope(tile_start, &z_start);
       
   242 	tileh_end = GetTileSlope(tile_end, &z_end);
       
   243 
       
   244 	if (IsSteepSlope(tileh_start)) z_start += TILE_HEIGHT;
       
   245 	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) {
       
   246 		z_start += TILE_HEIGHT;
       
   247 		tileh_start = SLOPE_FLAT;
       
   248 	}
       
   249 
       
   250 	if (IsSteepSlope(tileh_end)) z_end += TILE_HEIGHT;
       
   251 	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) {
       
   252 		z_end += TILE_HEIGHT;
       
   253 		tileh_end = SLOPE_FLAT;
       
   254 	}
       
   255 
       
   256 	if (z_start != z_end) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
       
   257 
       
   258 	// Towns are not allowed to use bridges on slopes.
       
   259 	allow_on_slopes = (!_is_old_ai_player
       
   260 	                   && _current_player != OWNER_TOWN && _patches.build_on_slopes);
       
   261 
       
   262 	/* Try and clear the start landscape */
       
   263 
       
   264 	ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   265 	if (CmdFailed(ret)) return ret;
       
   266 	cost = ret;
       
   267 
       
   268 	terraformcost = CheckBridgeSlopeNorth(direction, tileh_start);
       
   269 	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
       
   270 		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
       
   271 	cost += terraformcost;
       
   272 
       
   273 	/* Try and clear the end landscape */
       
   274 
       
   275 	ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   276 	if (CmdFailed(ret)) return ret;
       
   277 	cost += ret;
       
   278 
       
   279 	// false - end tile slope check
       
   280 	terraformcost = CheckBridgeSlopeSouth(direction, tileh_end);
       
   281 	if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes))
       
   282 		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
       
   283 	cost += terraformcost;
       
   284 
       
   285 	{
       
   286 		TileIndex Heads[] = {tile_start, tile_end};
       
   287 		int i;
       
   288 
       
   289 		for (i = 0; i < 2; i++) {
       
   290 			if (MayHaveBridgeAbove(Heads[i])) {
       
   291 				if (IsBridgeAbove(Heads[i])) {
       
   292 					TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
       
   293 
       
   294 					if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   295 
       
   296 					if (z_start + TILE_HEIGHT == GetBridgeHeight(north_head)) {
       
   297 						return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   298 					}
       
   299 				}
       
   300 			}
       
   301 		}
       
   302 	}
       
   303 
       
   304 	/* do the drill? */
       
   305 	if (flags & DC_EXEC) {
       
   306 		DiagDirection dir = AxisToDiagDir(direction);
       
   307 
       
   308 		if (transport == TRANSPORT_RAIL) {
       
   309 			MakeRailBridgeRamp(tile_start, _current_player, bridge_type, dir, railtype);
       
   310 			MakeRailBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir), railtype);
       
   311 		} else {
       
   312 			MakeRoadBridgeRamp(tile_start, _current_player, bridge_type, dir);
       
   313 			MakeRoadBridgeRamp(tile_end,   _current_player, bridge_type, ReverseDiagDir(dir));
       
   314 		}
       
   315 		MarkTileDirtyByTile(tile_start);
       
   316 		MarkTileDirtyByTile(tile_end);
       
   317 	}
       
   318 
       
   319 	delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
       
   320 	for (tile = tile_start + delta; tile != tile_end; tile += delta) {
       
   321 		uint z;
       
   322 
       
   323 		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
       
   324 
       
   325 		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
       
   326 			/* Disallow crossing bridges for the time being */
       
   327 			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   328 		}
       
   329 
       
   330 		switch (GetTileType(tile)) {
       
   331 			case MP_WATER:
       
   332 				if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
       
   333 				if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
       
   334 				break;
       
   335 
       
   336 			case MP_RAILWAY:
       
   337 				if (!IsPlainRailTile(tile)) goto not_valid_below;
       
   338 				break;
       
   339 
       
   340 			case MP_STREET:
       
   341 				if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) goto not_valid_below;
       
   342 				break;
       
   343 
       
   344 			case MP_TUNNEL:
       
   345 				break;
       
   346 
       
   347 			case MP_STREET_BRIDGE:
       
   348 			case MP_RAILWAY_BRIDGE:
       
   349 				if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below;
       
   350 				if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
       
   351 				break;
       
   352 
       
   353 			case MP_UNMOVABLE:
       
   354 				if (!IsOwnedLand(tile)) goto not_valid_below;
       
   355 				break;
       
   356 
       
   357 			case MP_CLEAR:
       
   358 				if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   359 				break;
       
   360 
       
   361 			default:
       
   362 not_valid_below:;
       
   363 				/* try and clear the middle landscape */
       
   364 				ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   365 				if (CmdFailed(ret)) return ret;
       
   366 				cost += ret;
       
   367 				break;
       
   368 		}
       
   369 
       
   370 		if (flags & DC_EXEC) {
       
   371 			SetBridgeMiddle(tile, direction);
       
   372 			MarkTileDirtyByTile(tile);
       
   373 		}
       
   374 	}
       
   375 
       
   376 	SetSignalsOnBothDir(tile_start, AxisToTrack(direction));
       
   377 	YapfNotifyTrackLayoutChange(tile_start, AxisToTrack(direction));
       
   378 
       
   379 	/* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
       
   380 	 * It's unnecessary to execute this command every time for every bridge. So it is done only
       
   381 	 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
       
   382 	 */
       
   383 	if (!(flags & DC_QUERY_COST)) {
       
   384 		const Bridge *b = &_bridge[bridge_type];
       
   385 
       
   386 		bridge_len += 2; // begin and end tiles/ramps
       
   387 
       
   388 		if (IsValidPlayer(_current_player) && !_is_old_ai_player)
       
   389 			bridge_len = CalcBridgeLenCostFactor(bridge_len);
       
   390 
       
   391 		cost += (int64)bridge_len * _price.build_bridge * b->price >> 8;
       
   392 	}
       
   393 
       
   394 	return cost;
       
   395 }
       
   396 
       
   397 
       
   398 /** Build Tunnel.
       
   399  * @param tile start tile of tunnel
       
   400  * @param p1 railtype, 0x200 for road tunnel
       
   401  * @param p2 unused
       
   402  */
       
   403 int32 CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
       
   404 {
       
   405 	TileIndexDiff delta;
       
   406 	TileIndex end_tile;
       
   407 	DiagDirection direction;
       
   408 	Slope start_tileh;
       
   409 	Slope end_tileh;
       
   410 	uint start_z;
       
   411 	uint end_z;
       
   412 	int32 cost;
       
   413 	int32 ret;
       
   414 
       
   415 	_build_tunnel_endtile = 0;
       
   416 
       
   417 	if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR;
       
   418 
       
   419 	start_tileh = GetTileSlope(start_tile, &start_z);
       
   420 
       
   421 	switch (start_tileh) {
       
   422 		case SLOPE_SW: direction = DIAGDIR_SW; break;
       
   423 		case SLOPE_SE: direction = DIAGDIR_SE; break;
       
   424 		case SLOPE_NW: direction = DIAGDIR_NW; break;
       
   425 		case SLOPE_NE: direction = DIAGDIR_NE; break;
       
   426 		default: return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
       
   427 	}
       
   428 
       
   429 	ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   430 	if (CmdFailed(ret)) return ret;
       
   431 
       
   432 	/* XXX - do NOT change 'ret' in the loop, as it is used as the price
       
   433 	 * for the clearing of the entrance of the tunnel. Assigning it to
       
   434 	 * cost before the loop will yield different costs depending on start-
       
   435 	 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
       
   436 	cost = 0;
       
   437 	delta = TileOffsByDiagDir(direction);
       
   438 	end_tile = start_tile;
       
   439 	for (;;) {
       
   440 		end_tile += delta;
       
   441 		end_tileh = GetTileSlope(end_tile, &end_z);
       
   442 
       
   443 		if (start_z == end_z) break;
       
   444 
       
   445 		if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z)) {
       
   446 			return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
       
   447 		}
       
   448 
       
   449 		cost += _price.build_tunnel;
       
   450 		cost += cost >> 3; // add a multiplier for longer tunnels
       
   451 		if (cost >= 400000000) cost = 400000000;
       
   452 	}
       
   453 
       
   454 	/* Add the cost of the entrance */
       
   455 	cost += _price.build_tunnel + ret;
       
   456 
       
   457 	// if the command fails from here on we want the end tile to be highlighted
       
   458 	_build_tunnel_endtile = end_tile;
       
   459 
       
   460 	// slope of end tile must be complementary to the slope of the start tile
       
   461 	if (end_tileh != ComplementSlope(start_tileh)) {
       
   462 		ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
       
   463 		if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
       
   464 	} else {
       
   465 		ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   466 		if (CmdFailed(ret)) return ret;
       
   467 	}
       
   468 	cost += _price.build_tunnel + ret;
       
   469 
       
   470 	if (flags & DC_EXEC) {
       
   471 		if (GB(p1, 9, 1) == TRANSPORT_RAIL) {
       
   472 			MakeRailTunnel(start_tile, _current_player, direction,                 GB(p1, 0, 4));
       
   473 			MakeRailTunnel(end_tile,   _current_player, ReverseDiagDir(direction), GB(p1, 0, 4));
       
   474 			UpdateSignalsOnSegment(start_tile, direction);
       
   475 			YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
       
   476 		} else {
       
   477 			MakeRoadTunnel(start_tile, _current_player, direction);
       
   478 			MakeRoadTunnel(end_tile,   _current_player, ReverseDiagDir(direction));
       
   479 		}
       
   480 	}
       
   481 
       
   482 	return cost;
       
   483 }
       
   484 
       
   485 TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
       
   486 {
       
   487 	uint z = GetTileZ(tile);
       
   488 	DiagDirection dir = GetTunnelDirection(tile);
       
   489 	TileIndexDiff delta = TileOffsByDiagDir(dir);
       
   490 	uint len = 0;
       
   491 	TileIndex starttile = tile;
       
   492 	Vehicle *v;
       
   493 
       
   494 	do {
       
   495 		tile += delta;
       
   496 		len++;
       
   497 	} while (
       
   498 		!IsTunnelTile(tile) ||
       
   499 		ReverseDiagDir(GetTunnelDirection(tile)) != dir ||
       
   500 		GetTileZ(tile) != z
       
   501 	);
       
   502 
       
   503 	v = FindVehicleBetween(starttile, tile, z);
       
   504 	if (v != NULL) {
       
   505 		_error_message = v->type == VEH_Train ?
       
   506 			STR_5000_TRAIN_IN_TUNNEL : STR_5001_ROAD_VEHICLE_IN_TUNNEL;
       
   507 		return INVALID_TILE;
       
   508 	}
       
   509 
       
   510 	if (length != NULL) *length = len;
       
   511 	return tile;
       
   512 }
       
   513 
       
   514 static inline bool CheckAllowRemoveTunnelBridge(TileIndex tile)
       
   515 {
       
   516 	/* Floods can remove anything as well as the scenario editor */
       
   517 	if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true;
       
   518 	/* Obviously if the bridge/tunnel belongs to us, or no-one, we can remove it */
       
   519 	if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true;
       
   520 	/* Otherwise we can only remove town-owned stuff with extra patch-settings, or cheat */
       
   521 	if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true;
       
   522 	return false;
       
   523 }
       
   524 
       
   525 static int32 DoClearTunnel(TileIndex tile, uint32 flags)
       
   526 {
       
   527 	Town *t = NULL;
       
   528 	TileIndex endtile;
       
   529 	uint length;
       
   530 
       
   531 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   532 
       
   533 	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
       
   534 
       
   535 	endtile = CheckTunnelBusy(tile, &length);
       
   536 	if (endtile == INVALID_TILE) return CMD_ERROR;
       
   537 
       
   538 	_build_tunnel_endtile = endtile;
       
   539 
       
   540 	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
       
   541 		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
       
   542 
       
   543 		/* Check if you are allowed to remove the tunnel owned by a town
       
   544 		 * Removal depends on difficulty settings */
       
   545 		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
       
   546 			SetDParam(0, t->index);
       
   547 			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
       
   548 		}
       
   549 	}
       
   550 
       
   551 	if (flags & DC_EXEC) {
       
   552 		// We first need to request the direction before calling DoClearSquare
       
   553 		//  else the direction is always 0.. dah!! ;)
       
   554 		DiagDirection dir = GetTunnelDirection(tile);
       
   555 		Track track;
       
   556 
       
   557 		// Adjust the town's player rating. Do this before removing the tile owner info.
       
   558 		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
       
   559 			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
       
   560 
       
   561 		DoClearSquare(tile);
       
   562 		DoClearSquare(endtile);
       
   563 		UpdateSignalsOnSegment(tile, ReverseDiagDir(dir));
       
   564 		UpdateSignalsOnSegment(endtile, dir);
       
   565 		track = AxisToTrack(DiagDirToAxis(dir));
       
   566 		YapfNotifyTrackLayoutChange(tile, track);
       
   567 		YapfNotifyTrackLayoutChange(endtile, track);
       
   568 	}
       
   569 	return _price.clear_tunnel * (length + 1);
       
   570 }
       
   571 
       
   572 
       
   573 static bool IsVehicleOnBridge(TileIndex starttile, TileIndex endtile, uint z)
       
   574 {
       
   575 	const Vehicle *v;
       
   576 	FOR_ALL_VEHICLES(v) {
       
   577 		if ((v->tile == starttile || v->tile == endtile) && v->z_pos == z) {
       
   578 			_error_message = VehicleInTheWayErrMsg(v);
       
   579 			return true;
       
   580 		}
       
   581 	}
       
   582 	return false;
       
   583 }
       
   584 
       
   585 static int32 DoClearBridge(TileIndex tile, uint32 flags)
       
   586 {
       
   587 	DiagDirection direction;
       
   588 	TileIndexDiff delta;
       
   589 	TileIndex endtile;
       
   590 	Town *t = NULL;
       
   591 
       
   592 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   593 
       
   594 	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
       
   595 
       
   596 	endtile = GetOtherBridgeEnd(tile);
       
   597 
       
   598 	if (!EnsureNoVehicle(tile) ||
       
   599 			!EnsureNoVehicle(endtile) ||
       
   600 			IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
       
   601 		return CMD_ERROR;
       
   602 	}
       
   603 
       
   604 	direction = GetBridgeRampDirection(tile);
       
   605 	delta = TileOffsByDiagDir(direction);
       
   606 
       
   607 	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
       
   608 		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
       
   609 
       
   610 		/* Check if you are allowed to remove the bridge owned by a town
       
   611 		 * Removal depends on difficulty settings */
       
   612 		if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
       
   613 			SetDParam(0, t->index);
       
   614 			return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
       
   615 		}
       
   616 	}
       
   617 
       
   618 	if (flags & DC_EXEC) {
       
   619 		TileIndex c;
       
   620 		Track track;
       
   621 
       
   622 		//checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
       
   623 		// you have a "Poor" (0) town rating
       
   624 		if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR)
       
   625 			ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
       
   626 
       
   627 		DoClearSquare(tile);
       
   628 		DoClearSquare(endtile);
       
   629 		for (c = tile + delta; c != endtile; c += delta) {
       
   630 				ClearBridgeMiddle(c);
       
   631 			MarkTileDirtyByTile(c);
       
   632 		}
       
   633 
       
   634 		UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
       
   635 		UpdateSignalsOnSegment(endtile, direction);
       
   636 		track = AxisToTrack(DiagDirToAxis(direction));
       
   637 		YapfNotifyTrackLayoutChange(tile, track);
       
   638 		YapfNotifyTrackLayoutChange(endtile, track);
       
   639 	}
       
   640 
       
   641 	return (DistanceManhattan(tile, endtile) + 1) * _price.clear_bridge;
       
   642 }
       
   643 
       
   644 static int32 ClearTile_Tunnel(TileIndex tile, byte flags)
       
   645 {
       
   646 	assert(IsTunnelTile(tile));
       
   647 	if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
       
   648 	return DoClearTunnel(tile, flags);
       
   649 }
       
   650 
       
   651 static int32 ClearTile_Bridge(TileIndex tile, byte flags)
       
   652 {
       
   653 	assert(IsBridgeTile(tile));
       
   654 	if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   655 	return DoClearBridge(tile, flags);
       
   656 }
       
   657 
       
   658 int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
       
   659 {
       
   660 	TileIndex endtile;
       
   661 
       
   662 	if (IsTunnelTile(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
       
   663 		uint length;
       
   664 
       
   665 		if (!CheckTileOwnership(tile)) return CMD_ERROR;
       
   666 
       
   667 		if (GetRailType(tile) == totype) return CMD_ERROR;
       
   668 
       
   669 		// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
       
   670 		if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
       
   671 
       
   672 		endtile = CheckTunnelBusy(tile, &length);
       
   673 		if (endtile == INVALID_TILE) return CMD_ERROR;
       
   674 
       
   675 		if (exec) {
       
   676 			Track track;
       
   677 			SetRailType(tile, totype);
       
   678 			SetRailType(endtile, totype);
       
   679 			MarkTileDirtyByTile(tile);
       
   680 			MarkTileDirtyByTile(endtile);
       
   681 
       
   682 			track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile)));
       
   683 			YapfNotifyTrackLayoutChange(tile, track);
       
   684 			YapfNotifyTrackLayoutChange(endtile, track);
       
   685 		}
       
   686 		return (length + 1) * (_price.build_rail >> 1);
       
   687 	} else if (IsBridgeTile(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
       
   688 
       
   689 		if (!CheckTileOwnership(tile)) return CMD_ERROR;
       
   690 
       
   691 		endtile = GetOtherBridgeEnd(tile);
       
   692 
       
   693 		if (!EnsureNoVehicle(tile) ||
       
   694 				!EnsureNoVehicle(endtile) ||
       
   695 				IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) {
       
   696 			return CMD_ERROR;
       
   697 		}
       
   698 
       
   699 		if (GetRailType(tile) == totype) return CMD_ERROR;
       
   700 
       
   701 		if (exec) {
       
   702 			TileIndexDiff delta;
       
   703 			Track track;
       
   704 
       
   705 			SetRailType(tile, totype);
       
   706 			SetRailType(endtile, totype);
       
   707 			MarkTileDirtyByTile(tile);
       
   708 			MarkTileDirtyByTile(endtile);
       
   709 
       
   710 			track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile)));
       
   711 			YapfNotifyTrackLayoutChange(tile, track);
       
   712 			YapfNotifyTrackLayoutChange(endtile, track);
       
   713 
       
   714 			delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
       
   715 			for (tile += delta; tile != endtile; tile += delta) {
       
   716 				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
       
   717 			}
       
   718 		}
       
   719 
       
   720 		return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
       
   721 	} else {
       
   722 		return CMD_ERROR;
       
   723 	}
       
   724 }
       
   725 
       
   726 
       
   727 static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
       
   728 {
       
   729 	if (image != 0) {
       
   730 		bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
       
   731 		int back_height, front_height;
       
   732 		int i = z;
       
   733 		const byte *p;
       
   734 
       
   735 		static const byte _tileh_bits[4][8] = {
       
   736 			{ 2, 1, 8, 4,  16,  2, 0, 9 },
       
   737 			{ 1, 8, 4, 2,   2, 16, 9, 0 },
       
   738 			{ 4, 8, 1, 2,  16,  2, 0, 9 },
       
   739 			{ 2, 4, 8, 1,   2, 16, 9, 0 }
       
   740 		};
       
   741 
       
   742 		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
       
   743 
       
   744 		p = _tileh_bits[(image & 1) * 2 + (axis == AXIS_X ? 0 : 1)];
       
   745 		front_height = ti->z + (ti->tileh & p[0] ? TILE_HEIGHT : 0);
       
   746 		back_height  = ti->z + (ti->tileh & p[1] ? TILE_HEIGHT : 0);
       
   747 
       
   748 		if (IsSteepSlope(ti->tileh)) {
       
   749 			if (!(ti->tileh & p[2])) front_height += TILE_HEIGHT;
       
   750 			if (!(ti->tileh & p[3])) back_height  += TILE_HEIGHT;
       
   751 		}
       
   752 
       
   753 		for (; z >= front_height || z >= back_height; z -= TILE_HEIGHT) {
       
   754 			/* HACK set height of the BB of pillars to 1, because the origin of the
       
   755 			 * sprites is at the top
       
   756 			 */
       
   757 			if (z >= front_height) { // front facing pillar
       
   758 				AddSortableSpriteToDraw(image, x, y, p[4], p[5], 1, z);
       
   759 			}
       
   760 
       
   761 			if (drawfarpillar && z >= back_height && z < i - TILE_HEIGHT) { // back facing pillar
       
   762 				AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 1, z);
       
   763 			}
       
   764 		}
       
   765 	}
       
   766 }
       
   767 
       
   768 uint GetBridgeFoundation(Slope tileh, Axis axis)
       
   769 {
       
   770 	uint i;
       
   771 
       
   772 	if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) return tileh;
       
   773 
       
   774 	// inclined sloped building
       
   775 	switch (tileh) {
       
   776 		case SLOPE_W:
       
   777 		case SLOPE_STEEP_W: i = 0; break;
       
   778 		case SLOPE_S:
       
   779 		case SLOPE_STEEP_S: i = 2; break;
       
   780 		case SLOPE_E:
       
   781 		case SLOPE_STEEP_E: i = 4; break;
       
   782 		case SLOPE_N:
       
   783 		case SLOPE_STEEP_N: i = 6; break;
       
   784 		default: return 0;
       
   785 	}
       
   786 	if (axis != AXIS_X) ++i;
       
   787 	return i + 15;
       
   788 }
       
   789 
       
   790 /**
       
   791  * Draws a tunnel tile.
       
   792  * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
       
   793  */
       
   794 static void DrawTile_Tunnel(TileInfo *ti)
       
   795 {
       
   796 	uint32 image;
       
   797 
       
   798 	if (GetTunnelTransportType(ti->tile) == TRANSPORT_RAIL) {
       
   799 		image = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.tunnel;
       
   800 	} else {
       
   801 		image = SPR_TUNNEL_ENTRY_REAR_ROAD;
       
   802 	}
       
   803 
       
   804 	if (HasTunnelSnowOrDesert(ti->tile)) image += 32;
       
   805 
       
   806 	image += GetTunnelDirection(ti->tile) * 2;
       
   807 	DrawGroundSprite(image);
       
   808 	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
       
   809 
       
   810 	AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z);
       
   811 	DrawBridgeMiddle(ti);
       
   812 }
       
   813 
       
   814 /**
       
   815  * Draws a bridge tile.
       
   816  * base_offset is where the sprite selection comes into play
       
   817  * and it works a bit like a bitmask.<p> For bridge heads:
       
   818  * <ul><li>Bit 0: direction</li>
       
   819  * <li>Bit 1: northern or southern heads</li>
       
   820  * <li>Bit 2: Set if the bridge head is sloped</li>
       
   821  * <li>Bit 3 and more: Railtype Specific subset</li>
       
   822  * </ul>
       
   823  * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
       
   824  */
       
   825 static void DrawTile_Bridge(TileInfo *ti)
       
   826 {
       
   827 	uint32 image;
       
   828 
       
   829 	int base_offset;
       
   830 	bool ice = HasBridgeSnowOrDesert(ti->tile);
       
   831 
       
   832 	if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) {
       
   833 		base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
       
   834 		assert(base_offset != 8); /* This one is used for roads */
       
   835 	} else {
       
   836 		base_offset = 8;
       
   837 	}
       
   838 
       
   839 	/* as the lower 3 bits are used for other stuff, make sure they are clear */
       
   840 	assert( (base_offset & 0x07) == 0x00);
       
   841 
       
   842 	if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
       
   843 		int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
       
   844 		if (f != 0) DrawFoundation(ti, f);
       
   845 	}
       
   846 
       
   847 	// HACK Wizardry to convert the bridge ramp direction into a sprite offset
       
   848 	base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
       
   849 
       
   850 	if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
       
   851 
       
   852 	/* Table number 6 always refers to the bridge heads for any bridge type */
       
   853 	image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
       
   854 
       
   855 	if (!ice) {
       
   856 		DrawClearLandTile(ti, 3);
       
   857 	} else {
       
   858 		DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
       
   859 	}
       
   860 
       
   861 	if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
       
   862 
       
   863 	// draw ramp
       
   864 	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
       
   865 	/* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
       
   866 	 * it doesn't disappear behind it
       
   867 	 */
       
   868 	AddSortableSpriteToDraw(
       
   869 		image, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 1 : 8, ti->z
       
   870 	);
       
   871 
       
   872 	DrawBridgeMiddle(ti);
       
   873 }
       
   874 
       
   875 
       
   876 /** Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge.
       
   877  * bridges pieces sequence (middle parts)
       
   878  * bridge len 1: 0
       
   879  * bridge len 2: 0 1
       
   880  * bridge len 3: 0 4 1
       
   881  * bridge len 4: 0 2 3 1
       
   882  * bridge len 5: 0 2 5 3 1
       
   883  * bridge len 6: 0 2 3 2 3 1
       
   884  * bridge len 7: 0 2 3 4 2 3 1
       
   885  * #0 - always as first, #1 - always as last (if len>1)
       
   886  * #2,#3 are to pair in order
       
   887  * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
       
   888  * @param north Northernmost tile of bridge
       
   889  * @param south Southernmost tile of bridge
       
   890  * @return Index of bridge piece
       
   891  */
       
   892 static uint CalcBridgePiece(uint north, uint south)
       
   893 {
       
   894 	if (north == 1) {
       
   895 		return 0;
       
   896 	} else if (south == 1) {
       
   897 		return 1;
       
   898 	} else if (north < south) {
       
   899 		return north & 1 ? 3 : 2;
       
   900 	} else if (north > south) {
       
   901 		return south & 1 ? 2 : 3;
       
   902 	} else {
       
   903 		return north & 1 ? 5 : 4;
       
   904 	}
       
   905 }
       
   906 
       
   907 
       
   908 void DrawBridgeMiddle(const TileInfo* ti)
       
   909 {
       
   910 	const PalSpriteID* b;
       
   911 	PalSpriteID image;
       
   912 	uint base_offset;
       
   913 	TileIndex rampnorth;
       
   914 	TileIndex rampsouth;
       
   915 	Axis axis;
       
   916 	uint piece;
       
   917 	uint type;
       
   918 	int x;
       
   919 	int y;
       
   920 	uint z;
       
   921 
       
   922 	if (!IsBridgeAbove(ti->tile)) return;
       
   923 
       
   924 	rampnorth = GetNorthernBridgeEnd(ti->tile);
       
   925 	rampsouth = GetSouthernBridgeEnd(ti->tile);
       
   926 
       
   927 	axis = GetBridgeAxis(ti->tile);
       
   928 	piece = CalcBridgePiece(
       
   929 		DistanceManhattan(ti->tile, rampnorth),
       
   930 		DistanceManhattan(ti->tile, rampsouth)
       
   931 	);
       
   932 	type = GetBridgeType(rampsouth);
       
   933 
       
   934 	if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) {
       
   935 		base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
       
   936 	} else {
       
   937 		base_offset = 8;
       
   938 	}
       
   939 
       
   940 	b = base_offset + GetBridgeSpriteTable(type, piece);
       
   941 	if (axis != AXIS_X) b += 4;
       
   942 
       
   943 	x = ti->x;
       
   944 	y = ti->y;
       
   945 	z = GetBridgeHeight(rampsouth) - 3;
       
   946 
       
   947 	image = b[0];
       
   948 	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
       
   949 	if (axis == AXIS_X) {
       
   950 		AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z);
       
   951 	} else {
       
   952 		AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z);
       
   953 	}
       
   954 
       
   955 	image = b[1];
       
   956 	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
       
   957 
       
   958 	// draw roof, the component of the bridge which is logically between the vehicle and the camera
       
   959 	if (axis == AXIS_X) {
       
   960 		y += 12;
       
   961 		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
       
   962 	} else {
       
   963 		x += 12;
       
   964 		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
       
   965 	}
       
   966 
       
   967 	if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
       
   968 
       
   969 	if (ti->z + 5 == z) {
       
   970 		// draw poles below for small bridges
       
   971 		image = b[2];
       
   972 		if (image != 0) {
       
   973 			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
       
   974 			DrawGroundSpriteAt(image, x, y, z);
       
   975 		}
       
   976 	} else if (_patches.bridge_pillars) {
       
   977 		// draw pillars below for high bridges
       
   978 		DrawBridgePillars(b[2], ti, axis, type, x, y, z);
       
   979 	}
       
   980 }
       
   981 
       
   982 
       
   983 uint SetSpeedLimitOnBridge(Vehicle *v)
       
   984 {
       
   985 	uint bridge_speed;
       
   986 	if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */
       
   987 
       
   988 	bridge_speed = _bridge[GetBridgeType(v->tile)].speed;
       
   989 
       
   990 	if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */
       
   991 
       
   992 	if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed;
       
   993 	return bridge_speed;
       
   994 }
       
   995 
       
   996 
       
   997 /** Gets the absolute z coordinate of a point inside a tunnel tile
       
   998  *  When we're on the track (that means between position 5 and 10)
       
   999  *  on the coordinate perpendicular to the track it returns only the
       
  1000  *  base height of the tile (because the track is horizontal).
       
  1001  *  Outside this range (from 0 to 4 and from 11 to 15) it returns the
       
  1002  *  "true" Z coordinate of the tile by taking the slope into account
       
  1003  *  @param tile The index of the tile we are talking about
       
  1004  *  @param x Absolute or relative x coordinate
       
  1005  *  @param y Absolute or relative y coordinate
       
  1006  *  @return Absolute z coordinate
       
  1007  */
       
  1008 static uint GetSlopeZ_Tunnel(TileIndex tile, uint x, uint y)
       
  1009 {
       
  1010 	uint z, pos;
       
  1011 	Slope tileh = GetTileSlope(tile, &z);
       
  1012 
       
  1013 	x &= 0xF;
       
  1014 	y &= 0xF;
       
  1015 
       
  1016 	pos = (DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? y : x);
       
  1017 
       
  1018 	// In the tunnel entrance?
       
  1019 	if (5 <= pos && pos <= 10) return z;
       
  1020 
       
  1021 	return z + GetPartialZ(x, y, tileh);
       
  1022 }
       
  1023 
       
  1024 /** Gets the absolute z coordinate of a point inside a bridge tile
       
  1025  *  When we're on the track (that means between position 5 and 10)
       
  1026  *  on the coordinate perpendicular to the track it returns the base
       
  1027  *  height of the ramp
       
  1028  *  Outside this range (from 0 to 4 and from 11 to 15) it returns the
       
  1029  *  "true" Z coordinate of the tile by taking the slope into account
       
  1030  *  @param tile The index of the tile we are talking about
       
  1031  *  @param x Absolute or relative x coordinate
       
  1032  *  @param y Absolute or relative y coordinate
       
  1033  *  @return Absolute z coordinate
       
  1034  */
       
  1035 static uint GetSlopeZ_Bridge(TileIndex tile, uint x, uint y)
       
  1036 {
       
  1037 	uint z, pos;
       
  1038 	Slope tileh = GetTileSlope(tile, &z);
       
  1039 	DiagDirection dir = GetBridgeRampDirection(tile);
       
  1040 
       
  1041 	x &= 0xF;
       
  1042 	y &= 0xF;
       
  1043 
       
  1044 	pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
       
  1045 
       
  1046 	// On the bridge ramp?
       
  1047 	if (5 <= pos && pos <= 10) {
       
  1048 		uint delta;
       
  1049 
       
  1050 		if (IsSteepSlope(tileh)) return z + TILE_HEIGHT * 2;
       
  1051 
       
  1052 		if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
       
  1053 
       
  1054 		if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
       
  1055 		switch (dir) {
       
  1056 			default: NOT_REACHED();
       
  1057 			case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
       
  1058 			case DIAGDIR_SE: delta = y / 2; break;
       
  1059 			case DIAGDIR_SW: delta = x / 2; break;
       
  1060 			case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
       
  1061 		}
       
  1062 		return z + 1 + delta;
       
  1063 	} else {
       
  1064 		uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
       
  1065 
       
  1066 		if (f != 0) {
       
  1067 			if (IsSteepSlope(tileh)) {
       
  1068 				z += TILE_HEIGHT;
       
  1069 			} else if (f < 15) {
       
  1070 				return z + TILE_HEIGHT;
       
  1071 			}
       
  1072 			tileh = _inclined_tileh[f - 15];
       
  1073 		}
       
  1074 	}
       
  1075 	return z + GetPartialZ(x, y, tileh);
       
  1076 }
       
  1077 
       
  1078 static Slope GetSlopeTileh_Tunnel(TileIndex tile, Slope tileh)
       
  1079 {
       
  1080 	return tileh;
       
  1081 }
       
  1082 
       
  1083 static Slope GetSlopeTileh_Bridge(TileIndex tile, Slope tileh)
       
  1084 {
       
  1085 	if (HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
       
  1086 		return tileh;
       
  1087 	} else {
       
  1088 		uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(tile)));
       
  1089 
       
  1090 		if (f == 0) return tileh;
       
  1091 		if (f < 15) return SLOPE_FLAT;
       
  1092 		return _inclined_tileh[f - 15];
       
  1093 	}
       
  1094 }
       
  1095 
       
  1096 static void GetAcceptedCargo_Tunnel(TileIndex tile, AcceptedCargo ac)
       
  1097 {
       
  1098 	/* not used */
       
  1099 }
       
  1100 
       
  1101 static void GetAcceptedCargo_Bridge(TileIndex tile, AcceptedCargo ac)
       
  1102 {
       
  1103 	/* not used */
       
  1104 }
       
  1105 
       
  1106 static const StringID _bridge_tile_str[(MAX_BRIDGES + 3) + (MAX_BRIDGES + 3)] = {
       
  1107 	STR_501F_WOODEN_RAIL_BRIDGE,
       
  1108 	STR_5020_CONCRETE_RAIL_BRIDGE,
       
  1109 	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
       
  1110 	STR_501E_REINFORCED_CONCRETE_SUSPENSION,
       
  1111 	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
       
  1112 	STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE,
       
  1113 	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
       
  1114 	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
       
  1115 	STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE,
       
  1116 	STR_501C_STEEL_GIRDER_RAIL_BRIDGE,
       
  1117 	STR_5027_TUBULAR_RAIL_BRIDGE,
       
  1118 	STR_5027_TUBULAR_RAIL_BRIDGE,
       
  1119 	STR_5027_TUBULAR_RAIL_BRIDGE,
       
  1120 	0, 0, 0,
       
  1121 
       
  1122 	STR_5025_WOODEN_ROAD_BRIDGE,
       
  1123 	STR_5026_CONCRETE_ROAD_BRIDGE,
       
  1124 	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
       
  1125 	STR_5024_REINFORCED_CONCRETE_SUSPENSION,
       
  1126 	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
       
  1127 	STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE,
       
  1128 	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
       
  1129 	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
       
  1130 	STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE,
       
  1131 	STR_5022_STEEL_GIRDER_ROAD_BRIDGE,
       
  1132 	STR_5028_TUBULAR_ROAD_BRIDGE,
       
  1133 	STR_5028_TUBULAR_ROAD_BRIDGE,
       
  1134 	STR_5028_TUBULAR_ROAD_BRIDGE,
       
  1135 	0, 0, 0,
       
  1136 };
       
  1137 
       
  1138 static void GetTileDesc_Tunnel(TileIndex tile, TileDesc *td)
       
  1139 {
       
  1140 	td->str = (GetTunnelTransportType(tile) == TRANSPORT_RAIL) ?  STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
       
  1141 	td->owner = GetTileOwner(tile);
       
  1142 }
       
  1143 
       
  1144 static void GetTileDesc_Bridge(TileIndex tile, TileDesc *td)
       
  1145 {
       
  1146 	td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)];
       
  1147 	td->owner = GetTileOwner(tile);
       
  1148 }
       
  1149 
       
  1150 
       
  1151 static void AnimateTile_Tunnel(TileIndex tile)
       
  1152 {
       
  1153 	/* not used */
       
  1154 }
       
  1155 
       
  1156 static void AnimateTile_Bridge(TileIndex tile)
       
  1157 {
       
  1158 	/* not used */
       
  1159 }
       
  1160 
       
  1161 static void TileLoop_Tunnel(TileIndex tile)
       
  1162 {
       
  1163 	bool snow_or_desert = HasTunnelSnowOrDesert(tile);
       
  1164 	switch (_opt.landscape) {
       
  1165 		case LT_HILLY:
       
  1166 			if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) {
       
  1167 				SetTunnelSnowOrDesert(tile, !snow_or_desert);
       
  1168 				MarkTileDirtyByTile(tile);
       
  1169 			}
       
  1170 			break;
       
  1171 
       
  1172 		case LT_DESERT:
       
  1173 			if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
       
  1174 				SetTunnelSnowOrDesert(tile, true);
       
  1175 				MarkTileDirtyByTile(tile);
       
  1176 			}
       
  1177 			break;
       
  1178 	}
       
  1179 }
       
  1180 
       
  1181 static void TileLoop_Bridge(TileIndex tile)
       
  1182 {
       
  1183 	bool snow_or_desert = HasBridgeSnowOrDesert(tile);
       
  1184 	switch (_opt.landscape) {
       
  1185 		case LT_HILLY:
       
  1186 			if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) {
       
  1187 				SetBridgeSnowOrDesert(tile, !snow_or_desert);
       
  1188 				MarkTileDirtyByTile(tile);
       
  1189 			}
       
  1190 			break;
       
  1191 
       
  1192 		case LT_DESERT:
       
  1193 			if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
       
  1194 				SetBridgeSnowOrDesert(tile, true);
       
  1195 				MarkTileDirtyByTile(tile);
       
  1196 			}
       
  1197 			break;
       
  1198 	}
       
  1199 }
       
  1200 
       
  1201 static void ClickTile_Tunnel(TileIndex tile)
       
  1202 {
       
  1203 	/* not used */
       
  1204 }
       
  1205 
       
  1206 static void ClickTile_Bridge(TileIndex tile)
       
  1207 {
       
  1208 	/* not used */
       
  1209 }
       
  1210 
       
  1211 
       
  1212 static uint32 GetTileTrackStatus_Tunnel(TileIndex tile, TransportType mode)
       
  1213 {
       
  1214 	if (GetTunnelTransportType(tile) != mode) return 0;
       
  1215 	return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(tile))) * 0x101;
       
  1216 }
       
  1217 
       
  1218 static uint32 GetTileTrackStatus_Bridge(TileIndex tile, TransportType mode)
       
  1219 {
       
  1220 	if (GetBridgeTransportType(tile) != mode) return 0;
       
  1221 	return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(tile))) * 0x101;
       
  1222 }
       
  1223 
       
  1224 static void ChangeTileOwner_Tunnel(TileIndex tile, PlayerID old_player, PlayerID new_player)
       
  1225 {
       
  1226 	if (!IsTileOwner(tile, old_player)) return;
       
  1227 
       
  1228 	if (new_player != PLAYER_SPECTATOR) {
       
  1229 		SetTileOwner(tile, new_player);
       
  1230 	} else {
       
  1231 		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
       
  1232 	}
       
  1233 }
       
  1234 
       
  1235 static void ChangeTileOwner_Bridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
       
  1236 {
       
  1237 	if (!IsTileOwner(tile, old_player)) return;
       
  1238 
       
  1239 	if (new_player != PLAYER_SPECTATOR) {
       
  1240 		SetTileOwner(tile, new_player);
       
  1241 	} else {
       
  1242 		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
       
  1243 	}
       
  1244 }
       
  1245 
       
  1246 
       
  1247 static const byte _tunnel_fractcoord_1[4]    = {0x8E, 0x18, 0x81, 0xE8};
       
  1248 static const byte _tunnel_fractcoord_2[4]    = {0x81, 0x98, 0x87, 0x38};
       
  1249 static const byte _tunnel_fractcoord_3[4]    = {0x82, 0x88, 0x86, 0x48};
       
  1250 static const byte _exit_tunnel_track[4]      = {1, 2, 1, 2};
       
  1251 
       
  1252 static const byte _road_exit_tunnel_state[4] = {8, 9, 0, 1};
       
  1253 static const byte _road_exit_tunnel_frame[4] = {2, 7, 9, 4};
       
  1254 
       
  1255 static const byte _tunnel_fractcoord_4[4]    = {0x52, 0x85, 0x98, 0x29};
       
  1256 static const byte _tunnel_fractcoord_5[4]    = {0x92, 0x89, 0x58, 0x25};
       
  1257 static const byte _tunnel_fractcoord_6[4]    = {0x92, 0x89, 0x56, 0x45};
       
  1258 static const byte _tunnel_fractcoord_7[4]    = {0x52, 0x85, 0x96, 0x49};
       
  1259 
       
  1260 static uint32 VehicleEnter_Tunnel(Vehicle *v, TileIndex tile, int x, int y)
       
  1261 {
       
  1262 	int z = GetSlopeZ(x, y) - v->z_pos;
       
  1263 
       
  1264 	byte fc;
       
  1265 	DiagDirection dir;
       
  1266 	DiagDirection vdir;
       
  1267 
       
  1268 	if (myabs(z) > 2) return 8;
       
  1269 
       
  1270 	if (v->type == VEH_Train) {
       
  1271 		fc = (x & 0xF) + (y << 4);
       
  1272 
       
  1273 		dir = GetTunnelDirection(tile);
       
  1274 		vdir = DirToDiagDir(v->direction);
       
  1275 
       
  1276 		if (v->u.rail.track != 0x40 && dir == vdir) {
       
  1277 			if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
       
  1278 				if (!PlayVehicleSound(v, VSE_TUNNEL) && v->spritenum < 4) {
       
  1279 					SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
       
  1280 				}
       
  1281 				return 0;
       
  1282 			}
       
  1283 			if (fc == _tunnel_fractcoord_2[dir]) {
       
  1284 				v->tile = tile;
       
  1285 				v->u.rail.track = 0x40;
       
  1286 				v->vehstatus |= VS_HIDDEN;
       
  1287 				return 4;
       
  1288 			}
       
  1289 		}
       
  1290 
       
  1291 		if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
       
  1292 			/* We're at the tunnel exit ?? */
       
  1293 			v->tile = tile;
       
  1294 			v->u.rail.track = _exit_tunnel_track[dir];
       
  1295 			assert(v->u.rail.track);
       
  1296 			v->vehstatus &= ~VS_HIDDEN;
       
  1297 			return 4;
       
  1298 		}
       
  1299 	} else if (v->type == VEH_Road) {
       
  1300 		fc = (x & 0xF) + (y << 4);
       
  1301 		dir = GetTunnelDirection(tile);
       
  1302 		vdir = DirToDiagDir(v->direction);
       
  1303 
       
  1304 		// Enter tunnel?
       
  1305 		if (v->u.road.state != 0xFF && dir == vdir) {
       
  1306 			if (fc == _tunnel_fractcoord_4[dir] ||
       
  1307 					fc == _tunnel_fractcoord_5[dir]) {
       
  1308 				v->tile = tile;
       
  1309 				v->u.road.state = 0xFF;
       
  1310 				v->vehstatus |= VS_HIDDEN;
       
  1311 				return 4;
       
  1312 			} else {
       
  1313 				return 0;
       
  1314 			}
       
  1315 		}
       
  1316 
       
  1317 		if (dir == ReverseDiagDir(vdir) && (
       
  1318 					/* We're at the tunnel exit ?? */
       
  1319 					fc == _tunnel_fractcoord_6[dir] ||
       
  1320 					fc == _tunnel_fractcoord_7[dir]
       
  1321 				) &&
       
  1322 				z == 0) {
       
  1323 			v->tile = tile;
       
  1324 			v->u.road.state = _road_exit_tunnel_state[dir];
       
  1325 			v->u.road.frame = _road_exit_tunnel_frame[dir];
       
  1326 			v->vehstatus &= ~VS_HIDDEN;
       
  1327 			return 4;
       
  1328 		}
       
  1329 	}
       
  1330 	return 0;
       
  1331 }
       
  1332 
       
  1333 static uint32 VehicleEnter_Bridge(Vehicle *v, TileIndex tile, int x, int y)
       
  1334 {
       
  1335 	int z = GetSlopeZ(x, y) - v->z_pos;
       
  1336 
       
  1337 	DiagDirection dir;
       
  1338 
       
  1339 	if (myabs(z) > 2) return 8;
       
  1340 
       
  1341 	if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
       
  1342 		/* modify speed of vehicle */
       
  1343 		uint16 spd = _bridge[GetBridgeType(tile)].speed;
       
  1344 
       
  1345 		if (v->type == VEH_Road) spd *= 2;
       
  1346 		if (v->cur_speed > spd) v->cur_speed = spd;
       
  1347 	}
       
  1348 
       
  1349 	dir = GetBridgeRampDirection(tile);
       
  1350 	if (DirToDiagDir(v->direction) == dir) {
       
  1351 		switch (dir) {
       
  1352 			default: NOT_REACHED();
       
  1353 			case DIAGDIR_NE: if ((x & 0xF) != 0)             return 0; break;
       
  1354 			case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break;
       
  1355 			case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break;
       
  1356 			case DIAGDIR_NW: if ((y & 0xF) != 0)             return 0; break;
       
  1357 		}
       
  1358 		if (v->type == VEH_Train) {
       
  1359 			v->u.rail.track = 0x40;
       
  1360 			CLRBIT(v->u.rail.flags, VRF_GOINGUP);
       
  1361 			CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
       
  1362 		} else {
       
  1363 			v->u.road.state = 0xFF;
       
  1364 		}
       
  1365 		return 4;
       
  1366 	} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
       
  1367 		v->tile = tile;
       
  1368 		if (v->type == VEH_Train) {
       
  1369 			if (v->u.rail.track == 0x40) {
       
  1370 				v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
       
  1371 				return 4;
       
  1372 			}
       
  1373 		} else {
       
  1374 			if (v->u.road.state == 0xFF) {
       
  1375 				v->u.road.state = _road_exit_tunnel_state[dir];
       
  1376 				v->u.road.frame = 0;
       
  1377 				return 4;
       
  1378 			}
       
  1379 		}
       
  1380 		return 0;
       
  1381 	}
       
  1382 	return 0;
       
  1383 }
       
  1384 
       
  1385 const TileTypeProcs _tile_type_tunnel_procs = {
       
  1386 	DrawTile_Tunnel,           /* draw_tile_proc */
       
  1387 	GetSlopeZ_Tunnel,          /* get_slope_z_proc */
       
  1388 	ClearTile_Tunnel,          /* clear_tile_proc */
       
  1389 	GetAcceptedCargo_Tunnel,   /* get_accepted_cargo_proc */
       
  1390 	GetTileDesc_Tunnel,        /* get_tile_desc_proc */
       
  1391 	GetTileTrackStatus_Tunnel, /* get_tile_track_status_proc */
       
  1392 	ClickTile_Tunnel,          /* click_tile_proc */
       
  1393 	AnimateTile_Tunnel,        /* animate_tile_proc */
       
  1394 	TileLoop_Tunnel,           /* tile_loop_clear */
       
  1395 	ChangeTileOwner_Tunnel,    /* change_tile_owner_clear */
       
  1396 	NULL,                            /* get_produced_cargo_proc */
       
  1397 	VehicleEnter_Tunnel,       /* vehicle_enter_tile_proc */
       
  1398 	GetSlopeTileh_Tunnel,      /* get_slope_tileh_proc */
       
  1399 };
       
  1400 
       
  1401 const TileTypeProcs _tile_type_bridge_procs = {
       
  1402 	DrawTile_Bridge,           /* draw_tile_proc */
       
  1403 	GetSlopeZ_Bridge,          /* get_slope_z_proc */
       
  1404 	ClearTile_Bridge,          /* clear_tile_proc */
       
  1405 	GetAcceptedCargo_Bridge,   /* get_accepted_cargo_proc */
       
  1406 	GetTileDesc_Bridge,        /* get_tile_desc_proc */
       
  1407 	GetTileTrackStatus_Bridge, /* get_tile_track_status_proc */
       
  1408 	ClickTile_Bridge,          /* click_tile_proc */
       
  1409 	AnimateTile_Bridge,        /* animate_tile_proc */
       
  1410 	TileLoop_Bridge,           /* tile_loop_clear */
       
  1411 	ChangeTileOwner_Bridge,    /* change_tile_owner_clear */
       
  1412 	NULL,                      /* get_produced_cargo_proc */
       
  1413 	VehicleEnter_Bridge,       /* vehicle_enter_tile_proc */
       
  1414 	GetSlopeTileh_Bridge,      /* get_slope_tileh_proc */
       
  1415 };