00001
00002
00008 #include "stdafx.h"
00009 #include "openttd.h"
00010 #include "bridge_map.h"
00011 #include "rail_map.h"
00012 #include "road_map.h"
00013 #include "tile_cmd.h"
00014 #include "landscape.h"
00015 #include "tunnel_map.h"
00016 #include "unmovable_map.h"
00017 #include "viewport_func.h"
00018 #include "command_func.h"
00019 #include "town.h"
00020 #include "variables.h"
00021 #include "bridge.h"
00022 #include "train.h"
00023 #include "water_map.h"
00024 #include "yapf/yapf.h"
00025 #include "newgrf_sound.h"
00026 #include "autoslope.h"
00027 #include "transparency.h"
00028 #include "tunnelbridge_map.h"
00029 #include "strings_func.h"
00030 #include "date_func.h"
00031 #include "functions.h"
00032 #include "vehicle_func.h"
00033 #include "sound_func.h"
00034 #include "signal_func.h"
00035 #include "tunnelbridge.h"
00036 #include "player_base.h"
00037
00038 #include "table/sprites.h"
00039 #include "table/strings.h"
00040 #include "table/bridge_land.h"
00041
00042 BridgeSpec _bridge[MAX_BRIDGES];
00043
00045 void ResetBridges()
00046 {
00047
00048 for (BridgeType i = 0; i < MAX_BRIDGES; i++) {
00049 if (_bridge[i].sprite_table != NULL) {
00050 for (uint j = 0; j < 7; j++) free(_bridge[i].sprite_table[j]);
00051 free(_bridge[i].sprite_table);
00052 }
00053 }
00054
00055
00056 memset(&_bridge, 0, sizeof(_bridge));
00057
00058 memcpy(&_bridge, &_orig_bridge, sizeof(_orig_bridge));
00059 }
00060
00064 int CalcBridgeLenCostFactor(int x)
00065 {
00066 int n;
00067 int r;
00068
00069 if (x < 2) return x;
00070 x -= 2;
00071 for (n = 0, r = 2;; n++) {
00072 if (x <= n) return r + x * n;
00073 r += n * n;
00074 x -= n;
00075 }
00076 }
00077
00078 Foundation GetBridgeFoundation(Slope tileh, Axis axis)
00079 {
00080 if ((tileh == SLOPE_FLAT) ||
00081 (((tileh == SLOPE_NE) || (tileh == SLOPE_SW)) && (axis == AXIS_X)) ||
00082 (((tileh == SLOPE_NW) || (tileh == SLOPE_SE)) && (axis == AXIS_Y))) return FOUNDATION_NONE;
00083
00084 return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh));
00085 }
00086
00094 bool HasBridgeFlatRamp(Slope tileh, Axis axis)
00095 {
00096 ApplyFoundationToSlope(GetBridgeFoundation(tileh, axis), &tileh);
00097
00098 return (tileh != SLOPE_FLAT);
00099 }
00100
00101 static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
00102 {
00103 const BridgeSpec *bridge = GetBridgeSpec(index);
00104 assert(table < 7);
00105 if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
00106 return _bridge_sprite_table[index][table];
00107 } else {
00108 return bridge->sprite_table[table];
00109 }
00110 }
00111
00112
00121 static CommandCost CheckBridgeSlopeNorth(Axis axis, Slope *tileh, uint *z)
00122 {
00123 Foundation f = GetBridgeFoundation(*tileh, axis);
00124 *z += ApplyFoundationToSlope(f, tileh);
00125
00126 Slope valid_inclined = (axis == AXIS_X ? SLOPE_NE : SLOPE_NW);
00127 if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR;
00128
00129 if (f == FOUNDATION_NONE) return CommandCost();
00130
00131 return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
00132 }
00133
00142 static CommandCost CheckBridgeSlopeSouth(Axis axis, Slope *tileh, uint *z)
00143 {
00144 Foundation f = GetBridgeFoundation(*tileh, axis);
00145 *z += ApplyFoundationToSlope(f, tileh);
00146
00147 Slope valid_inclined = (axis == AXIS_X ? SLOPE_SW : SLOPE_SE);
00148 if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR;
00149
00150 if (f == FOUNDATION_NONE) return CommandCost();
00151
00152 return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
00153 }
00154
00155 bool CheckBridge_Stuff(BridgeType bridge_type, uint bridge_len, uint32 flags)
00156 {
00157 if (flags & DC_QUERY_COST) {
00158 return bridge_len <= (_patches.longbridges ? 100U : 16U);
00159 }
00160
00161 if (bridge_type >= MAX_BRIDGES) return false;
00162
00163 const BridgeSpec *b = GetBridgeSpec(bridge_type);
00164 if (b->avail_year > _cur_year) return false;
00165
00166 uint max = b->max_length;
00167 if (max >= 16 && _patches.longbridges) max = 100;
00168
00169 return b->min_length <= bridge_len && bridge_len <= max;
00170 }
00171
00181 CommandCost CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
00182 {
00183 BridgeType bridge_type;
00184 RailType railtype = INVALID_RAILTYPE;
00185 RoadTypes roadtypes = ROADTYPES_NONE;
00186 uint x;
00187 uint y;
00188 uint sx;
00189 uint sy;
00190 TileIndex tile_start;
00191 TileIndex tile_end;
00192 Slope tileh_start;
00193 Slope tileh_end;
00194 uint z_start;
00195 uint z_end;
00196 TileIndex tile;
00197 TileIndexDiff delta;
00198 uint bridge_len;
00199 Axis direction;
00200 CommandCost cost(EXPENSES_CONSTRUCTION);
00201 CommandCost ret;
00202 bool replace_bridge = false;
00203 BridgeType replaced_bridge_type;
00204 TransportType transport_type;
00205
00206
00207 bridge_type = GB(p2, 0, 8);
00208
00209 if (p1 >= MapSize()) return CMD_ERROR;
00210
00211 transport_type = (TransportType)GB(p2, 15, 2);
00212
00213
00214 switch (transport_type) {
00215 case TRANSPORT_ROAD:
00216 roadtypes = (RoadTypes)GB(p2, 8, 3);
00217 if (!AreValidRoadTypes(roadtypes) || !HasRoadTypesAvail(_current_player, roadtypes)) return CMD_ERROR;
00218 break;
00219
00220 case TRANSPORT_RAIL:
00221 railtype = (RailType)GB(p2, 8, 8);
00222 if (!ValParamRailtype(railtype)) return CMD_ERROR;
00223 break;
00224
00225 default:
00226
00227
00228 return CMD_ERROR;
00229 }
00230
00231 x = TileX(end_tile);
00232 y = TileY(end_tile);
00233 sx = TileX(p1);
00234 sy = TileY(p1);
00235
00236
00237 if (x == sx) {
00238 if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
00239 direction = AXIS_Y;
00240 if (y > sy) Swap(y, sy);
00241 } else if (y == sy) {
00242 direction = AXIS_X;
00243 if (x > sx) Swap(x, sx);
00244 } else {
00245 return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
00246 }
00247
00248
00249 bridge_len = sx + sy - x - y - 1;
00250 if (!CheckBridge_Stuff(bridge_type, bridge_len, flags)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
00251
00252
00253 tile_start = TileXY(x, y);
00254 tile_end = TileXY(sx, sy);
00255 if (IsWaterTile(tile_start) || IsWaterTile(tile_end)) {
00256 return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
00257 }
00258
00259 tileh_start = GetTileSlope(tile_start, &z_start);
00260 tileh_end = GetTileSlope(tile_end, &z_end);
00261
00262 CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start);
00263 CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end, &z_end);
00264
00265 if (z_start != z_end) return_cmd_error(STR_BRIDGEHEADS_NOT_SAME_HEIGHT);
00266
00267 if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
00268 GetOtherBridgeEnd(tile_start) == tile_end &&
00269 GetTunnelBridgeTransportType(tile_start) == transport_type) {
00270
00271
00272
00273 if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) {
00274 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00275 }
00276
00277
00278 if (!(flags & DC_QUERY_COST) && IsTileOwner(tile_start, OWNER_TOWN) &&
00279 GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed) {
00280 Town *t = ClosestTownFromTile(tile_start, UINT_MAX);
00281
00282 if (t == NULL) {
00283 return CMD_ERROR;
00284 } else {
00285 SetDParam(0, t->index);
00286 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
00287 }
00288 }
00289
00290
00291 if (!(flags & DC_QUERY_COST) && bridge_type == GetBridgeType(tile_start)) {
00292 return_cmd_error(STR_1007_ALREADY_BUILT);
00293 }
00294
00295
00296 if (!IsTileOwner(tile_start, _current_player) && !IsTileOwner(tile_start, OWNER_TOWN)) {
00297 return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
00298 }
00299
00300 cost.AddCost((bridge_len + 1) * _price.clear_bridge);
00301 replace_bridge = true;
00302 replaced_bridge_type = GetBridgeType(tile_start);
00303
00304
00305 roadtypes |= GetRoadTypes(tile_start);
00306 } else {
00307
00308
00309 bool allow_on_slopes = (!_is_old_ai_player && _patches.build_on_slopes);
00310
00311
00312 ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00313 if (CmdFailed(ret)) return ret;
00314 cost = ret;
00315
00316 if (CmdFailed(terraform_cost_north) || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes))
00317 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00318 cost.AddCost(terraform_cost_north);
00319
00320
00321 ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00322 if (CmdFailed(ret)) return ret;
00323 cost.AddCost(ret);
00324
00325
00326 if (CmdFailed(terraform_cost_south) || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes))
00327 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00328 cost.AddCost(terraform_cost_south);
00329 }
00330
00331 if (!replace_bridge) {
00332 TileIndex Heads[] = {tile_start, tile_end};
00333 int i;
00334
00335 for (i = 0; i < 2; i++) {
00336 if (MayHaveBridgeAbove(Heads[i])) {
00337 if (IsBridgeAbove(Heads[i])) {
00338 TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
00339
00340 if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00341
00342 if (z_start + TILE_HEIGHT == GetBridgeHeight(north_head)) {
00343 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00344 }
00345 }
00346 }
00347 }
00348 }
00349
00350
00351 if (flags & DC_EXEC) {
00352 DiagDirection dir = AxisToDiagDir(direction);
00353 Owner owner = (replace_bridge && IsTileOwner(tile_start, OWNER_TOWN)) ? OWNER_TOWN : _current_player;
00354
00355 switch (transport_type) {
00356 case TRANSPORT_RAIL:
00357 MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype);
00358 MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype);
00359 break;
00360
00361 case TRANSPORT_ROAD:
00362 MakeRoadBridgeRamp(tile_start, owner, bridge_type, dir, roadtypes);
00363 MakeRoadBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), roadtypes);
00364 break;
00365
00366 default:
00367 NOT_REACHED();
00368 break;
00369 }
00370 MarkTileDirtyByTile(tile_start);
00371 MarkTileDirtyByTile(tile_end);
00372 }
00373
00374 delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00375 for (tile = tile_start + delta; tile != tile_end; tile += delta) {
00376 if (GetTileMaxZ(tile) > z_start) return_cmd_error(STR_BRIDGE_TOO_LOW_FOR_TERRAIN);
00377
00378 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile) && !replace_bridge) {
00379
00380 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00381 }
00382
00383 switch (GetTileType(tile)) {
00384 case MP_WATER:
00385 if (!EnsureNoVehicleOnGround(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
00386 if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
00387 break;
00388
00389 case MP_RAILWAY:
00390 if (!IsPlainRailTile(tile)) goto not_valid_below;
00391 break;
00392
00393 case MP_ROAD:
00394 if (IsRoadDepot(tile)) goto not_valid_below;
00395 break;
00396
00397 case MP_TUNNELBRIDGE:
00398 if (IsTunnel(tile)) break;
00399 if (replace_bridge) break;
00400 if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below;
00401 if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
00402 break;
00403
00404 case MP_UNMOVABLE:
00405 if (!IsOwnedLand(tile)) goto not_valid_below;
00406 break;
00407
00408 case MP_CLEAR:
00409 break;
00410
00411 default:
00412 not_valid_below:;
00413
00414 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00415 if (CmdFailed(ret)) return ret;
00416 cost.AddCost(ret);
00417 break;
00418 }
00419
00420 if (flags & DC_EXEC) {
00421 SetBridgeMiddle(tile, direction);
00422 MarkTileDirtyByTile(tile);
00423 }
00424 }
00425
00426 if (flags & DC_EXEC && transport_type == TRANSPORT_RAIL) {
00427 Track track = AxisToTrack(direction);
00428 AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, _current_player);
00429 YapfNotifyTrackLayoutChange(tile_start, track);
00430 }
00431
00432
00433
00434
00435
00436 if (!(flags & DC_QUERY_COST) || (IsValidPlayer(_current_player) && GetPlayer(_current_player)->is_ai)) {
00437 bridge_len += 2;
00438
00439 if (IsValidPlayer(_current_player) && !_is_old_ai_player)
00440 bridge_len = CalcBridgeLenCostFactor(bridge_len);
00441
00442 cost.AddCost((int64)bridge_len * _price.build_bridge * GetBridgeSpec(bridge_type)->price >> 8);
00443 }
00444
00445 return cost;
00446 }
00447
00448
00455 CommandCost CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 p2)
00456 {
00457 TileIndexDiff delta;
00458 TileIndex end_tile;
00459 DiagDirection direction;
00460 Slope start_tileh;
00461 Slope end_tileh;
00462 TransportType transport_type = (TransportType)GB(p1, 9, 1);
00463 uint start_z;
00464 uint end_z;
00465 CommandCost cost(EXPENSES_CONSTRUCTION);
00466 CommandCost ret;
00467
00468 _build_tunnel_endtile = 0;
00469 if (transport_type == TRANSPORT_RAIL) {
00470 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00471 } else {
00472 const RoadTypes rts = (RoadTypes)GB(p1, 0, 3);
00473 if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR;
00474 }
00475
00476 start_tileh = GetTileSlope(start_tile, &start_z);
00477 direction = GetInclinedSlopeDirection(start_tileh);
00478 if (direction == INVALID_DIAGDIR) return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
00479
00480 if (IsWaterTile(start_tile)) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
00481
00482 ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00483 if (CmdFailed(ret)) return ret;
00484
00485
00486
00487
00488
00489
00490 delta = TileOffsByDiagDir(direction);
00491 DiagDirection tunnel_in_way_dir;
00492 if (OtherAxis(DiagDirToAxis(direction)) == AXIS_X) {
00493 tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
00494 } else {
00495 tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
00496 }
00497
00498 end_tile = start_tile;
00499
00501 int tiles_coef = 3;
00503 int tiles = 0;
00505 int tiles_bump = 25;
00506
00507 for (;;) {
00508 end_tile += delta;
00509 end_tileh = GetTileSlope(end_tile, &end_z);
00510
00511 if (start_z == end_z) break;
00512
00513 if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
00514 return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
00515 }
00516
00517 tiles++;
00518 if (tiles == tiles_bump) {
00519 tiles_coef++;
00520 tiles_bump *= 2;
00521 }
00522
00523 cost.AddCost(_price.build_tunnel);
00524 cost.AddCost(cost.GetCost() >> tiles_coef);
00525 }
00526
00527
00528 cost.AddCost(_price.build_tunnel);
00529 cost.AddCost(ret);
00530
00531
00532 _build_tunnel_endtile = end_tile;
00533
00534 if (IsWaterTile(end_tile)) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
00535
00536
00537 if (end_tileh != ComplementSlope(start_tileh)) {
00538
00539 ret = DoCommand(end_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR);
00540 if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
00541
00542 ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
00543 if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
00544 } else {
00545 ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00546 if (CmdFailed(ret)) return ret;
00547 }
00548 cost.AddCost(_price.build_tunnel);
00549 cost.AddCost(ret);
00550
00551 if (flags & DC_EXEC) {
00552 if (transport_type == TRANSPORT_RAIL) {
00553 MakeRailTunnel(start_tile, _current_player, direction, (RailType)GB(p1, 0, 4));
00554 MakeRailTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4));
00555 AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_player);
00556 YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
00557 } else {
00558 MakeRoadTunnel(start_tile, _current_player, direction, (RoadTypes)GB(p1, 0, 3));
00559 MakeRoadTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 3));
00560 }
00561 }
00562
00563 return cost;
00564 }
00565
00566
00567 static inline bool CheckAllowRemoveTunnelBridge(TileIndex tile)
00568 {
00569
00570 if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true;
00571
00572 if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true;
00573
00574 if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true;
00575 return false;
00576 }
00577
00578 static CommandCost DoClearTunnel(TileIndex tile, uint32 flags)
00579 {
00580 Town *t = NULL;
00581 TileIndex endtile;
00582
00583 if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
00584
00585 endtile = GetOtherTunnelEnd(tile);
00586
00587 if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
00588
00589 _build_tunnel_endtile = endtile;
00590
00591 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
00592 t = ClosestTownFromTile(tile, (uint)-1);
00593
00594
00595
00596 if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
00597 SetDParam(0, t->index);
00598 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
00599 }
00600 }
00601
00602
00603
00604 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
00605 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
00606 }
00607
00608 if (flags & DC_EXEC) {
00609 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
00610
00611 DiagDirection dir = GetTunnelBridgeDirection(tile);
00612 Owner owner = GetTileOwner(tile);
00613
00614 DoClearSquare(tile);
00615 DoClearSquare(endtile);
00616
00617
00618 AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
00619 AddSideToSignalBuffer(endtile, dir, owner);
00620
00621 Track track = AxisToTrack(DiagDirToAxis(dir));
00622 YapfNotifyTrackLayoutChange(tile, track);
00623 YapfNotifyTrackLayoutChange(endtile, track);
00624 } else {
00625 DoClearSquare(tile);
00626 DoClearSquare(endtile);
00627 }
00628 }
00629 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_tunnel * (GetTunnelBridgeLength(tile, endtile) + 2));
00630 }
00631
00632
00633 static CommandCost DoClearBridge(TileIndex tile, uint32 flags)
00634 {
00635 DiagDirection direction;
00636 TileIndexDiff delta;
00637 TileIndex endtile;
00638 Town *t = NULL;
00639
00640 if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
00641
00642 endtile = GetOtherBridgeEnd(tile);
00643
00644 if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
00645
00646 direction = GetTunnelBridgeDirection(tile);
00647 delta = TileOffsByDiagDir(direction);
00648
00649 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
00650 t = ClosestTownFromTile(tile, (uint)-1);
00651
00652
00653
00654 if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) {
00655 SetDParam(0, t->index);
00656 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
00657 }
00658 }
00659
00660
00661
00662 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
00663 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
00664 }
00665
00666 if (flags & DC_EXEC) {
00667
00668 bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
00669 Owner owner = GetTileOwner(tile);
00670 uint height = GetBridgeHeight(tile);
00671
00672 DoClearSquare(tile);
00673 DoClearSquare(endtile);
00674 for (TileIndex c = tile + delta; c != endtile; c += delta) {
00675
00676 if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
00677 uint minz = GetTileMaxZ(c) + 3 * TILE_HEIGHT;
00678 if (height < minz) SetRoadside(c, ROADSIDE_PAVED);
00679 }
00680 ClearBridgeMiddle(c);
00681 MarkTileDirtyByTile(c);
00682 }
00683
00684 if (rail) {
00685
00686 AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
00687 AddSideToSignalBuffer(endtile, direction, owner);
00688
00689 Track track = AxisToTrack(DiagDirToAxis(direction));
00690 YapfNotifyTrackLayoutChange(tile, track);
00691 YapfNotifyTrackLayoutChange(endtile, track);
00692 }
00693 }
00694
00695 return CommandCost(EXPENSES_CONSTRUCTION, (GetTunnelBridgeLength(tile, endtile) + 2) * _price.clear_bridge);
00696 }
00697
00698 static CommandCost ClearTile_TunnelBridge(TileIndex tile, byte flags)
00699 {
00700 if (IsTunnel(tile)) {
00701 if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
00702 return DoClearTunnel(tile, flags);
00703 } else {
00704 if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00705 return DoClearBridge(tile, flags);
00706 }
00707
00708 return CMD_ERROR;
00709 }
00710
00722 static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo* ti, Axis axis, BridgeType type, int x, int y, int z_bridge)
00723 {
00724 SpriteID image = psid->sprite;
00725 if (image != 0) {
00726 bool drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 bool side = HasBit(image, 0);
00738
00739
00740 DiagDirection dir = AxisToDiagDir(axis);
00741 if (side != (axis == AXIS_Y)) dir = ReverseDiagDir(dir);
00742
00743
00744 int front_height = ti->z;
00745 int back_height = ti->z;
00746 GetSlopeZOnEdge(ti->tileh, dir, &front_height, &back_height);
00747
00748
00749 int w = (axis == AXIS_X ? 16 : 2);
00750 int h = (axis == AXIS_X ? 2 : 16);
00751
00752 int x_back = x - (axis == AXIS_X ? 0 : 9);
00753 int y_back = y - (axis == AXIS_X ? 9 : 0);
00754
00755 for (int cur_z = z_bridge; cur_z >= front_height || cur_z >= back_height; cur_z -= TILE_HEIGHT) {
00756
00757 if (cur_z >= front_height) {
00758 AddSortableSpriteToDraw(image, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - 5, cur_z, IsTransparencySet(TO_BRIDGES), 0, 0, -5);
00759 }
00760
00761
00762 if (drawfarpillar && cur_z >= back_height && cur_z < z_bridge - TILE_HEIGHT) {
00763 AddSortableSpriteToDraw(image, psid->pal, x_back, y_back, w, h, BB_HEIGHT_UNDER_BRIDGE - 5, cur_z, IsTransparencySet(TO_BRIDGES), 0, 0, -5);
00764 }
00765 }
00766 }
00767 }
00768
00777 static void DrawBridgeTramBits(int x, int y, byte z, int offset, bool overlay)
00778 {
00779 static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } };
00780 static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 };
00781 static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 };
00782
00783 static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 };
00784 static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 };
00785 static const uint front_bb_offset_x[6] = { 15, 0, 0, 15, 0, 15 };
00786 static const uint front_bb_offset_y[6] = { 0, 15, 15, 0, 15, 0 };
00787
00788
00789
00790 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, IsTransparencySet(TO_BRIDGES));
00791
00792 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY));
00793
00794
00795 EndSpriteCombine();
00796 StartSpriteCombine();
00797
00798
00799 AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE, x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]);
00800 }
00801
00815 static void DrawTile_TunnelBridge(TileInfo *ti)
00816 {
00817 SpriteID image;
00818 TransportType transport_type = GetTunnelBridgeTransportType(ti->tile);
00819 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
00820
00821 if (IsTunnel(ti->tile)) {
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831 static const int _tunnel_BB[4][12] = {
00832
00833
00834 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 },
00835 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 },
00836 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 },
00837 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 },
00838 };
00839 const int *BB_data = _tunnel_BB[tunnelbridge_direction];
00840
00841 bool catenary = false;
00842
00843 if (transport_type == TRANSPORT_RAIL) {
00844 image = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.tunnel;
00845 } else {
00846 image = SPR_TUNNEL_ENTRY_REAR_ROAD;
00847 }
00848
00849 if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += 32;
00850
00851 image += tunnelbridge_direction * 2;
00852 DrawGroundSprite(image, PAL_NONE);
00853 if (transport_type == TRANSPORT_ROAD) {
00854 RoadTypes rts = GetRoadTypes(ti->tile);
00855
00856 if (HasBit(rts, ROADTYPE_TRAM)) {
00857 static const SpriteID tunnel_sprites[2][4] = { { 28, 78, 79, 27 }, { 5, 76, 77, 4 } };
00858
00859 DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][tunnelbridge_direction], PAL_NONE);
00860
00861 catenary = true;
00862 StartSpriteCombine();
00863 AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
00864 }
00865 } else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
00866 DrawCatenary(ti);
00867
00868 catenary = true;
00869 StartSpriteCombine();
00870 DrawCatenaryOnTunnel(ti);
00871 }
00872
00873 AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
00874
00875 if (catenary) EndSpriteCombine();
00876
00877
00878 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x , ti->y , BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
00879 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
00880
00881 DrawBridgeMiddle(ti);
00882 } else {
00883 const PalSpriteID *psid;
00884 int base_offset;
00885 bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
00886
00887 if (transport_type == TRANSPORT_RAIL) {
00888 base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
00889 assert(base_offset != 8);
00890 } else {
00891 base_offset = 8;
00892 }
00893
00894
00895 assert( (base_offset & 0x07) == 0x00);
00896
00897 DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
00898
00899
00900 base_offset += (6 - tunnelbridge_direction) % 4;
00901
00902 if (ti->tileh == SLOPE_FLAT) base_offset += 4;
00903
00904
00905 psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
00906
00907 if (!ice) {
00908 DrawClearLandTile(ti, 3);
00909 } else {
00910 DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh], PAL_NONE);
00911 }
00912
00913
00914
00915
00916 if (transport_type == TRANSPORT_ROAD) StartSpriteCombine();
00917
00918
00919
00920
00921 AddSortableSpriteToDraw(
00922 psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z, IsTransparencySet(TO_BRIDGES)
00923 );
00924
00925 if (transport_type == TRANSPORT_ROAD) {
00926 RoadTypes rts = GetRoadTypes(ti->tile);
00927
00928 if (HasBit(rts, ROADTYPE_TRAM)) {
00929 uint offset = tunnelbridge_direction;
00930 uint z = ti->z;
00931 if (ti->tileh != SLOPE_FLAT) {
00932 offset = (offset + 1) & 1;
00933 z += TILE_HEIGHT;
00934 } else {
00935 offset += 2;
00936 }
00937
00938 DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD));
00939 }
00940 EndSpriteCombine();
00941 } else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
00942 DrawCatenary(ti);
00943 }
00944
00945 DrawBridgeMiddle(ti);
00946 }
00947 }
00948
00949
00966 static uint CalcBridgePiece(uint north, uint south)
00967 {
00968 if (north == 1) {
00969 return 0;
00970 } else if (south == 1) {
00971 return 1;
00972 } else if (north < south) {
00973 return north & 1 ? 3 : 2;
00974 } else if (north > south) {
00975 return south & 1 ? 2 : 3;
00976 } else {
00977 return north & 1 ? 5 : 4;
00978 }
00979 }
00980
00981
00982 void DrawBridgeMiddle(const TileInfo* ti)
00983 {
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001 static const int BRIDGE_Z_START = 3;
01002
01003 const PalSpriteID* psid;
01004 uint base_offset;
01005 TileIndex rampnorth;
01006 TileIndex rampsouth;
01007 TransportType transport_type;
01008 Axis axis;
01009 uint piece;
01010 BridgeType type;
01011 int x;
01012 int y;
01013 uint z;
01014
01015 if (!IsBridgeAbove(ti->tile)) return;
01016
01017 rampnorth = GetNorthernBridgeEnd(ti->tile);
01018 rampsouth = GetSouthernBridgeEnd(ti->tile);
01019 transport_type = GetTunnelBridgeTransportType(rampsouth);
01020
01021 axis = GetBridgeAxis(ti->tile);
01022 piece = CalcBridgePiece(
01023 GetTunnelBridgeLength(ti->tile, rampnorth) + 1,
01024 GetTunnelBridgeLength(ti->tile, rampsouth) + 1
01025 );
01026 type = GetBridgeType(rampsouth);
01027
01028 if (transport_type == TRANSPORT_RAIL) {
01029 base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
01030 } else {
01031 base_offset = 8;
01032 }
01033
01034 psid = base_offset + GetBridgeSpriteTable(type, piece);
01035 if (axis != AXIS_X) psid += 4;
01036
01037 x = ti->x;
01038 y = ti->y;
01039 uint bridge_z = GetBridgeHeight(rampsouth);
01040 z = bridge_z - BRIDGE_Z_START;
01041
01042
01043 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR);
01044
01045
01046 if (transport_type == TRANSPORT_ROAD) StartSpriteCombine();
01047
01048
01049 if (axis == AXIS_X) {
01050 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
01051 } else {
01052 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
01053 }
01054
01055 psid++;
01056
01057 if (transport_type == TRANSPORT_ROAD) {
01058 RoadTypes rts = GetRoadTypes(rampsouth);
01059
01060 if (HasBit(rts, ROADTYPE_TRAM)) {
01061
01062 DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD));
01063 } else {
01064 EndSpriteCombine();
01065 StartSpriteCombine();
01066 }
01067 } else if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) {
01068 DrawCatenary(ti);
01069 }
01070
01071
01072 if (axis == AXIS_X) {
01073 y += 12;
01074 if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START);
01075 } else {
01076 x += 12;
01077 if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START);
01078 }
01079
01080
01081 if (transport_type == TRANSPORT_ROAD) EndSpriteCombine();
01082
01083 psid++;
01084 if (ti->z + 5 == z) {
01085
01086 if (psid->sprite != 0) {
01087 SpriteID image = psid->sprite;
01088 SpriteID pal = psid->pal;
01089 if (IsTransparencySet(TO_BRIDGES)) {
01090 SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
01091 pal = PALETTE_TO_TRANSPARENT;
01092 }
01093
01094 DrawGroundSpriteAt(image, pal, x, y, z);
01095 }
01096 } else if (_patches.bridge_pillars) {
01097
01098 DrawBridgePillars(psid, ti, axis, type, x, y, z);
01099 }
01100 }
01101
01102
01103 static uint GetSlopeZ_TunnelBridge(TileIndex tile, uint x, uint y)
01104 {
01105 uint z;
01106 Slope tileh = GetTileSlope(tile, &z);
01107
01108 x &= 0xF;
01109 y &= 0xF;
01110
01111 if (IsTunnel(tile)) {
01112 uint pos = (DiagDirToAxis(GetTunnelBridgeDirection(tile)) == AXIS_X ? y : x);
01113
01114
01115 if (5 <= pos && pos <= 10) return z;
01116 } else {
01117 DiagDirection dir = GetTunnelBridgeDirection(tile);
01118 uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
01119
01120 z += ApplyFoundationToSlope(GetBridgeFoundation(tileh, DiagDirToAxis(dir)), &tileh);
01121
01122
01123 if (5 <= pos && pos <= 10) {
01124 uint delta;
01125
01126 if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT;
01127
01128 switch (dir) {
01129 default: NOT_REACHED();
01130 case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
01131 case DIAGDIR_SE: delta = y / 2; break;
01132 case DIAGDIR_SW: delta = x / 2; break;
01133 case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
01134 }
01135 return z + 1 + delta;
01136 }
01137 }
01138
01139 return z + GetPartialZ(x, y, tileh);
01140 }
01141
01142 static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
01143 {
01144 return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
01145 }
01146
01147
01148 static void GetAcceptedCargo_TunnelBridge(TileIndex tile, AcceptedCargo ac)
01149 {
01150
01151 }
01152
01153 static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
01154 {
01155 if (IsTunnel(tile)) {
01156 td->str = (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) ?
01157 STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
01158 } else {
01159 td->str = GetBridgeSpec(GetBridgeType(tile))->transport_name[GetTunnelBridgeTransportType(tile)];
01160 }
01161 td->owner = GetTileOwner(tile);
01162 }
01163
01164
01165 static void AnimateTile_TunnelBridge(TileIndex tile)
01166 {
01167
01168 }
01169
01170 static void TileLoop_TunnelBridge(TileIndex tile)
01171 {
01172 bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile);
01173 switch (_opt.landscape) {
01174 case LT_ARCTIC:
01175 if (snow_or_desert != (GetTileZ(tile) > GetSnowLine())) {
01176 SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert);
01177 MarkTileDirtyByTile(tile);
01178 }
01179 break;
01180
01181 case LT_TROPIC:
01182 if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
01183 SetTunnelBridgeSnowOrDesert(tile, true);
01184 MarkTileDirtyByTile(tile);
01185 }
01186 break;
01187
01188 default:
01189 break;
01190 }
01191 }
01192
01193 static void ClickTile_TunnelBridge(TileIndex tile)
01194 {
01195
01196 }
01197
01198
01199 static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01200 {
01201 TransportType transport_type = GetTunnelBridgeTransportType(tile);
01202 if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0;
01203
01204 DiagDirection dir = GetTunnelBridgeDirection(tile);
01205 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
01206 return CombineTrackStatus(TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir))), TRACKDIR_BIT_NONE);
01207 }
01208
01209 static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
01210 {
01211 if (!IsTileOwner(tile, old_player)) return;
01212
01213 if (new_player != PLAYER_SPECTATOR) {
01214 SetTileOwner(tile, new_player);
01215 } else {
01216 if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR))) {
01217
01218
01219
01220
01221 assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD);
01222 SetTileOwner(tile, OWNER_NONE);
01223 }
01224 }
01225 }
01226
01227
01228 static const byte _tunnel_fractcoord_1[4] = {0x8E, 0x18, 0x81, 0xE8};
01229 static const byte _tunnel_fractcoord_2[4] = {0x81, 0x98, 0x87, 0x38};
01230 static const byte _tunnel_fractcoord_3[4] = {0x82, 0x88, 0x86, 0x48};
01231 static const byte _exit_tunnel_track[4] = {1, 2, 1, 2};
01232
01234 static const Trackdir _road_exit_tunnel_state[DIAGDIR_END] = {
01235 TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE
01236 };
01237 static const byte _road_exit_tunnel_frame[4] = {2, 7, 9, 4};
01238
01239 static const byte _tunnel_fractcoord_4[4] = {0x52, 0x85, 0x98, 0x29};
01240 static const byte _tunnel_fractcoord_5[4] = {0x92, 0x89, 0x58, 0x25};
01241 static const byte _tunnel_fractcoord_6[4] = {0x92, 0x89, 0x56, 0x45};
01242 static const byte _tunnel_fractcoord_7[4] = {0x52, 0x85, 0x96, 0x49};
01243
01244 static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
01245 {
01246 int z = GetSlopeZ(x, y) - v->z_pos;
01247
01248 if (abs(z) > 2) return VETSB_CANNOT_ENTER;
01249 const DiagDirection dir = GetTunnelBridgeDirection(tile);
01250
01251 if (IsTunnel(tile)) {
01252 byte fc;
01253 DiagDirection vdir;
01254
01255 if (v->type == VEH_TRAIN) {
01256 fc = (x & 0xF) + (y << 4);
01257
01258 vdir = DirToDiagDir(v->direction);
01259
01260 if (v->u.rail.track != TRACK_BIT_WORMHOLE && dir == vdir) {
01261 if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
01262 if (!PlayVehicleSound(v, VSE_TUNNEL) && RailVehInfo(v->engine_type)->engclass == 0) {
01263 SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
01264 }
01265 return VETSB_CONTINUE;
01266 }
01267 if (fc == _tunnel_fractcoord_2[dir]) {
01268 v->tile = tile;
01269 v->u.rail.track = TRACK_BIT_WORMHOLE;
01270 v->vehstatus |= VS_HIDDEN;
01271 return VETSB_ENTERED_WORMHOLE;
01272 }
01273 }
01274
01275 if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
01276
01277 v->tile = tile;
01278 v->u.rail.track = (TrackBits)_exit_tunnel_track[dir];
01279 assert(v->u.rail.track);
01280 v->vehstatus &= ~VS_HIDDEN;
01281 return VETSB_ENTERED_WORMHOLE;
01282 }
01283 } else if (v->type == VEH_ROAD) {
01284 fc = (x & 0xF) + (y << 4);
01285 vdir = DirToDiagDir(v->direction);
01286
01287
01288 if (v->u.road.state != RVSB_WORMHOLE && dir == vdir) {
01289 if (fc == _tunnel_fractcoord_4[dir] ||
01290 fc == _tunnel_fractcoord_5[dir]) {
01291 v->tile = tile;
01292 v->u.road.state = RVSB_WORMHOLE;
01293 v->vehstatus |= VS_HIDDEN;
01294 return VETSB_ENTERED_WORMHOLE;
01295 } else {
01296 return VETSB_CONTINUE;
01297 }
01298 }
01299
01300 if (dir == ReverseDiagDir(vdir) && (
01301
01302 fc == _tunnel_fractcoord_6[dir] ||
01303 fc == _tunnel_fractcoord_7[dir]
01304 ) &&
01305 z == 0) {
01306 v->tile = tile;
01307 v->u.road.state = _road_exit_tunnel_state[dir];
01308 v->u.road.frame = _road_exit_tunnel_frame[dir];
01309 v->vehstatus &= ~VS_HIDDEN;
01310 return VETSB_ENTERED_WORMHOLE;
01311 }
01312 }
01313 } else {
01314
01315 if (v->IsPrimaryVehicle()) {
01316
01317 uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;
01318
01319 if (v->type == VEH_ROAD) spd *= 2;
01320 if (v->cur_speed > spd) v->cur_speed = spd;
01321 }
01322
01323 if (DirToDiagDir(v->direction) == dir) {
01324 switch (dir) {
01325 default: NOT_REACHED();
01326 case DIAGDIR_NE: if ((x & 0xF) != 0) return VETSB_CONTINUE; break;
01327 case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
01328 case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
01329 case DIAGDIR_NW: if ((y & 0xF) != 0) return VETSB_CONTINUE; break;
01330 }
01331 if (v->type == VEH_TRAIN) {
01332 v->u.rail.track = TRACK_BIT_WORMHOLE;
01333 ClrBit(v->u.rail.flags, VRF_GOINGUP);
01334 ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
01335 } else {
01336 v->u.road.state = RVSB_WORMHOLE;
01337 }
01338 return VETSB_ENTERED_WORMHOLE;
01339 } else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
01340 v->tile = tile;
01341 if (v->type == VEH_TRAIN) {
01342 if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
01343 v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
01344 return VETSB_ENTERED_WORMHOLE;
01345 }
01346 } else {
01347 if (v->u.road.state == RVSB_WORMHOLE) {
01348 v->u.road.state = _road_exit_tunnel_state[dir];
01349 v->u.road.frame = 0;
01350 return VETSB_ENTERED_WORMHOLE;
01351 }
01352 }
01353 return VETSB_CONTINUE;
01354 }
01355 }
01356 return VETSB_CONTINUE;
01357 }
01358
01359 static CommandCost TerraformTile_TunnelBridge(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
01360 {
01361 if (_patches.build_on_slopes && AutoslopeEnabled() && IsBridge(tile)) {
01362 DiagDirection direction = GetTunnelBridgeDirection(tile);
01363 Axis axis = DiagDirToAxis(direction);
01364 CommandCost res;
01365 uint z_old;
01366 Slope tileh_old = GetTileSlope(tile, &z_old);
01367
01368
01369 if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
01370 CheckBridgeSlopeSouth(axis, &tileh_old, &z_old);
01371 res = CheckBridgeSlopeSouth(axis, &tileh_new, &z_new);
01372 } else {
01373 CheckBridgeSlopeNorth(axis, &tileh_old, &z_old);
01374 res = CheckBridgeSlopeNorth(axis, &tileh_new, &z_new);
01375 }
01376
01377
01378 if (!CmdFailed(res) && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
01379 }
01380
01381 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01382 }
01383
01384 extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
01385 DrawTile_TunnelBridge,
01386 GetSlopeZ_TunnelBridge,
01387 ClearTile_TunnelBridge,
01388 GetAcceptedCargo_TunnelBridge,
01389 GetTileDesc_TunnelBridge,
01390 GetTileTrackStatus_TunnelBridge,
01391 ClickTile_TunnelBridge,
01392 AnimateTile_TunnelBridge,
01393 TileLoop_TunnelBridge,
01394 ChangeTileOwner_TunnelBridge,
01395 NULL,
01396 VehicleEnter_TunnelBridge,
01397 GetFoundation_TunnelBridge,
01398 TerraformTile_TunnelBridge,
01399 };