00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "bridge.h"
00009 #include "cmd_helper.h"
00010 #include "rail_map.h"
00011 #include "road_map.h"
00012 #include "road_internal.h"
00013 #include "sprite.h"
00014 #include "tile_cmd.h"
00015 #include "landscape.h"
00016 #include "town_map.h"
00017 #include "viewport_func.h"
00018 #include "command_func.h"
00019 #include "town.h"
00020 #include "yapf/yapf.h"
00021 #include "depot.h"
00022 #include "newgrf.h"
00023 #include "station_map.h"
00024 #include "tunnel_map.h"
00025 #include "variables.h"
00026 #include "autoslope.h"
00027 #include "transparency.h"
00028 #include "tunnelbridge_map.h"
00029 #include "window_func.h"
00030 #include "strings_func.h"
00031 #include "vehicle_func.h"
00032 #include "vehicle_base.h"
00033 #include "sound_func.h"
00034 #include "road_func.h"
00035 #include "tunnelbridge.h"
00036
00037 #include "table/sprites.h"
00038 #include "table/strings.h"
00039
00040 #define M(x) (1 << (x))
00041
00042 static const uint32 VALID_LEVEL_CROSSING_SLOPES = (M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT));
00043 #undef M
00044
00045 Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
00046
00047 bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
00048 {
00049 RoadBits present;
00050 RoadBits n;
00051 *edge_road = true;
00052
00053 if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return true;
00054
00055
00056
00057
00058 if (_current_player == OWNER_WATER ||
00059 (rt == ROADTYPE_ROAD && !IsValidPlayer(_current_player))) return true;
00060
00061
00062
00063 if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
00064
00065 if (_cheats.magic_bulldozer.value) return true;
00066
00067
00068 n = ROAD_NONE;
00069 present = GetAnyRoadBits(tile, rt);
00070 if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW) n |= ROAD_NE;
00071 if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW) n |= ROAD_SE;
00072 if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE) n |= ROAD_SW;
00073 if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE) n |= ROAD_NW;
00074
00075
00076
00077 if ((n & (n - 1)) != 0 && (n & remove) != 0) {
00078 Town *t;
00079 *edge_road = false;
00080
00081 if (_patches.extra_dynamite) return true;
00082
00083 t = ClosestTownFromTile(tile, (uint)-1);
00084
00085 SetDParam(0, t->index);
00086 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
00087 return false;
00088 }
00089
00090 return true;
00091 }
00092
00093 static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool *edge_road, RoadType rt)
00094 {
00095 return CheckAllowRemoveRoad(tile, remove, GetRoadOwner(tile, rt), edge_road, rt);
00096 }
00097
00098
00106 static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true)
00107 {
00108
00109 static const uint16 road_remove_cost[2] = {50, 18};
00110
00111
00112
00113 bool edge_road;
00114
00115 Town *t = NULL;
00116 switch (GetTileType(tile)) {
00117 case MP_ROAD:
00118 if (_game_mode != GM_EDITOR && GetRoadOwner(tile, rt) == OWNER_TOWN) t = GetTownByTile(tile);
00119 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00120 break;
00121
00122 case MP_STATION:
00123 if (!IsDriveThroughStopTile(tile)) return CMD_ERROR;
00124 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00125 break;
00126
00127 case MP_TUNNELBRIDGE:
00128 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
00129 if (HasVehicleOnTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile))) return CMD_ERROR;
00130 break;
00131
00132 default:
00133 return CMD_ERROR;
00134 }
00135
00136 RoadTypes rts = GetRoadTypes(tile);
00137
00138 if (!HasBit(rts, rt)) return CMD_ERROR;
00139
00140 if (!CheckAllowRemoveRoad(tile, pieces, &edge_road, rt)) return CMD_ERROR;
00141
00142
00143
00144 if (town_check && !CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
00145
00146 if (!IsTileType(tile, MP_ROAD)) {
00147
00148 if (rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00149
00150 CommandCost cost(EXPENSES_CONSTRUCTION);
00151 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00152 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
00153
00154 cost.AddCost((GetTunnelBridgeLength(other_end, tile) + 2) * _price.remove_road);
00155 if (flags & DC_EXEC) {
00156 SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt));
00157 SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
00158
00159
00160 MarkTileDirtyByTile(tile);
00161 MarkTileDirtyByTile(other_end);
00162 if (IsBridge(tile)) {
00163 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
00164
00165 for (TileIndex t = tile + delta; t != other_end; t += delta) MarkTileDirtyByTile(t);
00166 }
00167 }
00168 } else {
00169 assert(IsDriveThroughStopTile(tile));
00170 cost.AddCost(_price.remove_road * 2);
00171 if (flags & DC_EXEC) {
00172 SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
00173 MarkTileDirtyByTile(tile);
00174 }
00175 }
00176 return cost;
00177 }
00178
00179 switch (GetRoadTileType(tile)) {
00180 case ROAD_TILE_NORMAL: {
00181 RoadBits present = GetRoadBits(tile, rt);
00182 RoadBits c = pieces;
00183
00184 if (HasRoadWorks(tile) && _current_player != OWNER_WATER) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
00185
00186 if (GetTileSlope(tile, NULL) != SLOPE_FLAT &&
00187 (present == ROAD_Y || present == ROAD_X)) {
00188 c |= (RoadBits)((c & 0xC) >> 2);
00189 c |= (RoadBits)((c & 0x3) << 2);
00190 }
00191
00192
00193 c &= present;
00194 if (c == ROAD_NONE) return CMD_ERROR;
00195
00196 if (town_check) ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
00197 if (flags & DC_EXEC) {
00198 present ^= c;
00199 if (HasRoadWorks(tile)) {
00200
00201 assert(_current_player == OWNER_WATER);
00202 Vehicle *v;
00203 FOR_ALL_VEHICLES(v) {
00204 if (v->type == VEH_SPECIAL && TileVirtXY(v->x_pos, v->y_pos) == tile) {
00205 delete v;
00206 }
00207 }
00208 }
00209 if (present == ROAD_NONE) {
00210 RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
00211 if (rts == ROADTYPES_NONE) {
00212
00213 DoClearSquare(tile);
00214 } else {
00215 SetRoadBits(tile, ROAD_NONE, rt);
00216 SetRoadTypes(tile, rts);
00217 MarkTileDirtyByTile(tile);
00218 }
00219 } else {
00220
00221
00222
00223 if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE);
00224 SetRoadBits(tile, present, rt);
00225 MarkTileDirtyByTile(tile);
00226 }
00227 }
00228 return CommandCost(EXPENSES_CONSTRUCTION, CountBits(c) * _price.remove_road);
00229 }
00230
00231 case ROAD_TILE_CROSSING: {
00232 if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
00233 return CMD_ERROR;
00234 }
00235
00236
00237
00238 if (rt == ROADTYPE_ROAD && HasTileRoadType(tile, ROADTYPE_TRAM) && (flags & DC_EXEC || crossing_check)) return CMD_ERROR;
00239
00240 if (rt == ROADTYPE_ROAD) {
00241 if (town_check) ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
00242 }
00243
00244 if (flags & DC_EXEC) {
00245 RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
00246 if (rts == ROADTYPES_NONE) {
00247 MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailType(tile));
00248 } else {
00249 SetRoadTypes(tile, rts);
00250 }
00251 MarkTileDirtyByTile(tile);
00252 YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile)));
00253 }
00254 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_road * 2);
00255 }
00256
00257 default:
00258 case ROAD_TILE_DEPOT:
00259 return CMD_ERROR;
00260 }
00261 }
00262
00263
00271 CommandCost CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00272 {
00273 RoadType rt = (RoadType)GB(p1, 4, 2);
00274 if (!IsValidRoadType(rt)) return CMD_ERROR;
00275
00276 RoadBits pieces = Extract<RoadBits, 0>(p1);
00277
00278 return RemoveRoad(tile, flags, pieces, rt, true);
00279 }
00280
00281
00282 static const RoadBits _valid_tileh_slopes_road[][15] = {
00283
00284 {
00285 ROAD_ALL,
00286 ROAD_NONE,
00287 ROAD_NONE,
00288
00289 ROAD_X,
00290 ROAD_NONE,
00291 ROAD_NONE,
00292
00293 ROAD_Y,
00294 ROAD_NONE,
00295 ROAD_NONE,
00296
00297 ROAD_Y,
00298 ROAD_NONE,
00299 ROAD_NONE,
00300
00301 ROAD_X,
00302 ROAD_NONE,
00303 ROAD_NONE
00304 },
00305
00306 {
00307 ROAD_NONE,
00308 ROAD_SW | ROAD_NW,
00309 ROAD_SW | ROAD_SE,
00310
00311 ROAD_Y | ROAD_SW,
00312 ROAD_SE | ROAD_NE,
00313 ROAD_ALL,
00314
00315 ROAD_X | ROAD_SE,
00316 ROAD_ALL,
00317 ROAD_NW | ROAD_NE,
00318
00319 ROAD_X | ROAD_NW,
00320 ROAD_ALL,
00321 ROAD_ALL,
00322
00323 ROAD_Y | ROAD_NE,
00324 ROAD_ALL,
00325 ROAD_ALL
00326 },
00327
00328 {
00329 ROAD_ALL,
00330 ROAD_NE | ROAD_SE,
00331 ROAD_NE | ROAD_NW,
00332
00333 ROAD_NE,
00334 ROAD_NW | ROAD_SW,
00335 ROAD_ALL,
00336
00337 ROAD_NW,
00338 ROAD_ALL,
00339 ROAD_SE | ROAD_SW,
00340
00341 ROAD_SE,
00342 ROAD_ALL,
00343 ROAD_ALL,
00344
00345 ROAD_SW,
00346 ROAD_ALL,
00347 ROAD_ALL,
00348 },
00349 };
00350
00361 static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
00362 {
00363 if (IsSteepSlope(tileh)) {
00364
00365 *pieces |= MirrorRoadBits(*pieces);
00366
00367 if (existing == ROAD_NONE || existing == *pieces) {
00368 if (*pieces == ROAD_X || *pieces == ROAD_Y) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
00369 }
00370 return CMD_ERROR;
00371 }
00372
00373 RoadBits road_bits = *pieces | existing;
00374
00375
00376
00377 if (_patches.build_on_slopes && !_is_old_ai_player &&
00378 existing == ROAD_NONE && CountBits(*pieces) == 1 &&
00379 (_valid_tileh_slopes_road[2][tileh] & *pieces) == ROAD_NONE) {
00380 return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
00381 }
00382
00383
00384 if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == ROAD_NONE) {
00385
00386 if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
00387 return CommandCost();
00388 }
00389
00390
00391 if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == ROAD_NONE) {
00392 return CommandCost(EXPENSES_CONSTRUCTION, existing != ROAD_NONE ? (Money)0 : _price.terraform);
00393 }
00394
00395
00396 *pieces |= MirrorRoadBits(*pieces);
00397
00398
00399 if ((existing == ROAD_NONE || existing == *pieces) && IsSlopeWithOneCornerRaised(tileh)) {
00400 if (*pieces == ROAD_X || *pieces == ROAD_Y) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
00401 }
00402 return CMD_ERROR;
00403 }
00404
00413 CommandCost CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00414 {
00415 CommandCost cost(EXPENSES_CONSTRUCTION);
00416 CommandCost ret;
00417 RoadBits existing = ROAD_NONE;
00418 RoadBits all_bits = ROAD_NONE;
00419 Slope tileh;
00420
00421
00422
00423 if ((IsValidPlayer(_current_player) && p2 != 0) || (_current_player == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
00424
00425 RoadBits pieces = Extract<RoadBits, 0>(p1);
00426
00427
00428 if (pieces == ROAD_NONE) return CMD_ERROR;
00429
00430 RoadType rt = (RoadType)GB(p1, 4, 2);
00431 if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
00432
00433 DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2);
00434
00435 tileh = GetTileSlope(tile, NULL);
00436
00437 switch (GetTileType(tile)) {
00438 case MP_ROAD:
00439 switch (GetRoadTileType(tile)) {
00440 case ROAD_TILE_NORMAL: {
00441 if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
00442
00443 all_bits = GetAllRoadBits(tile);
00444 if (!HasTileRoadType(tile, rt)) break;
00445
00446 existing = GetRoadBits(tile, rt);
00447 RoadBits merged = existing | pieces;
00448 bool crossing = (merged != ROAD_X && merged != ROAD_Y);
00449 if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) {
00450
00451 return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
00452 }
00453 if ((existing & pieces) == pieces) {
00454
00455 if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM && GetRoadOwner(tile, ROADTYPE_ROAD) == _current_player) {
00456 if (crossing) return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
00457
00458 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00459
00460
00461 if (flags & DC_EXEC && rt != ROADTYPE_TRAM && (existing == ROAD_X || existing == ROAD_Y)) {
00462 SetDisallowedRoadDirections(tile, GetDisallowedRoadDirections(tile) ^ toggle_drd);
00463 MarkTileDirtyByTile(tile);
00464 }
00465 return CommandCost();
00466 }
00467 return_cmd_error(STR_1007_ALREADY_BUILT);
00468 }
00469 } break;
00470
00471 case ROAD_TILE_CROSSING:
00472 all_bits = GetCrossingRoadBits(tile);
00473 if (pieces & ComplementRoadBits(all_bits)) goto do_clear;
00474 pieces = all_bits;
00475
00476 if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
00477 break;
00478
00479 default:
00480 case ROAD_TILE_DEPOT:
00481 goto do_clear;
00482 }
00483 break;
00484
00485 case MP_RAILWAY: {
00486 Axis roaddir;
00487
00488 if (IsSteepSlope(tileh)) {
00489 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00490 }
00491
00492
00493 if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) {
00494 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00495 }
00496
00497 if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
00498 switch (GetTrackBits(tile)) {
00499 case TRACK_BIT_X:
00500 if (pieces & ROAD_X) goto do_clear;
00501 roaddir = AXIS_Y;
00502 break;
00503
00504 case TRACK_BIT_Y:
00505 if (pieces & ROAD_Y) goto do_clear;
00506 roaddir = AXIS_X;
00507 break;
00508
00509 default: goto do_clear;
00510 }
00511
00512 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00513
00514 if (flags & DC_EXEC) {
00515 YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile)));
00516
00517 MakeRoadCrossing(tile, _current_player, _current_player, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt) | ROADTYPES_ROAD, p2);
00518 UpdateLevelCrossing(tile, false);
00519 MarkTileDirtyByTile(tile);
00520 }
00521 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_road * (rt == ROADTYPE_ROAD ? 2 : 4));
00522 }
00523
00524 case MP_STATION: {
00525 if (!IsDriveThroughStopTile(tile)) goto do_clear;
00526
00527 RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile)));
00528 if (pieces & ~curbits) goto do_clear;
00529 pieces = curbits;
00530
00531 if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
00532 } break;
00533
00534 case MP_TUNNELBRIDGE:
00535 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
00536 if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
00537
00538 if (HasVehicleOnTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile))) return CMD_ERROR;
00539 break;
00540
00541 default:
00542 do_clear:;
00543 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00544 if (CmdFailed(ret)) return ret;
00545 cost.AddCost(ret);
00546 }
00547
00548 if (all_bits != pieces) {
00549
00550 ret = CheckRoadSlope(tileh, &pieces, all_bits | existing);
00551
00552
00553 if (CmdFailed(ret) || (ret.GetCost() != 0 && (!_patches.build_on_slopes || _is_old_ai_player))) {
00554 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00555 }
00556 cost.AddCost(ret);
00557 }
00558
00559 if (IsTileType(tile, MP_ROAD)) {
00560
00561 pieces &= ComplementRoadBits(existing);
00562
00563
00564 if (IsNormalRoad(tile)) {
00565 Slope slope = GetTileSlope(tile, NULL);
00566 Foundation found_new = GetRoadFoundation(slope, pieces | existing);
00567
00568
00569 for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) {
00570 if (rtest != rt) {
00571 RoadBits bits = GetRoadBits(tile, rtest);
00572
00573 if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) {
00574 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00575 }
00576 }
00577 }
00578 }
00579 }
00580
00581 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00582
00583 cost.AddCost(CountBits(pieces) * _price.build_road);
00584 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00585
00586 cost.MultiplyCost(GetTunnelBridgeLength(GetOtherTunnelBridgeEnd(tile), tile) + 2);
00587 }
00588
00589 if (flags & DC_EXEC) {
00590 switch (GetTileType(tile)) {
00591 case MP_ROAD: {
00592 RoadTileType rtt = GetRoadTileType(tile);
00593 if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) {
00594 SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
00595 SetRoadOwner(tile, rt, _current_player);
00596 if (_current_player == OWNER_TOWN && rt == ROADTYPE_ROAD) SetTownIndex(tile, p2);
00597 }
00598 if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt);
00599 } break;
00600
00601 case MP_TUNNELBRIDGE: {
00602 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
00603
00604 SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt));
00605 SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
00606
00607
00608 MarkTileDirtyByTile(other_end);
00609 MarkTileDirtyByTile(tile);
00610 if (IsBridge(tile)) {
00611 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
00612
00613 for (TileIndex t = tile + delta; t != other_end; t += delta) MarkTileDirtyByTile(t);
00614 }
00615 } break;
00616
00617 case MP_STATION:
00618 assert(IsDriveThroughStopTile(tile));
00619 SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
00620 break;
00621
00622 default:
00623 MakeRoadNormal(tile, pieces, RoadTypeToRoadTypes(rt), p2, _current_player, _current_player, _current_player);
00624 break;
00625 }
00626
00627 if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) {
00628 existing |= pieces;
00629 SetDisallowedRoadDirections(tile, (existing == ROAD_X || existing == ROAD_Y) ?
00630 GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE);
00631 }
00632
00633 MarkTileDirtyByTile(tile);
00634 }
00635 return cost;
00636 }
00637
00649 CommandCost CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
00650 {
00651 TileIndex start_tile, tile;
00652 CommandCost ret, cost(EXPENSES_CONSTRUCTION);
00653 bool had_bridge = false;
00654 bool had_tunnel = false;
00655 bool had_success = false;
00656 DisallowedRoadDirections drd = DRD_NORTHBOUND;
00657
00658 _error_message = INVALID_STRING_ID;
00659
00660 if (p1 >= MapSize()) return CMD_ERROR;
00661
00662 start_tile = p1;
00663 RoadType rt = (RoadType)GB(p2, 3, 2);
00664 if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
00665
00666
00667 if (!HasBit(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR;
00668 if (HasBit(p2, 2) && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR;
00669
00670
00671 if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) {
00672 TileIndex t = start_tile;
00673 start_tile = end_tile;
00674 end_tile = t;
00675 p2 ^= IsInsideMM(p2 & 3, 1, 3) ? 3 : 0;
00676 drd = DRD_SOUTHBOUND;
00677 }
00678
00679
00680
00681
00682 if (HasBit(p2, 2) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH;
00683
00684 if (!HasBit(p2, 5)) drd = DRD_NONE;
00685
00686 tile = start_tile;
00687
00688 for (;;) {
00689 RoadBits bits = HasBit(p2, 2) ? ROAD_Y : ROAD_X;
00690
00691 if (tile == end_tile && !HasBit(p2, 1)) bits &= ROAD_NW | ROAD_NE;
00692 if (tile == start_tile && HasBit(p2, 0)) bits &= ROAD_SE | ROAD_SW;
00693
00694 ret = DoCommand(tile, drd << 6 | rt << 4 | bits, 0, flags, CMD_BUILD_ROAD);
00695 if (CmdFailed(ret)) {
00696 if (_error_message != STR_1007_ALREADY_BUILT) return CMD_ERROR;
00697 } else {
00698 had_success = true;
00699
00700 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00701 if (IsBridge(tile)) {
00702 if ((!had_bridge || GetTunnelBridgeDirection(tile) == DIAGDIR_SE || GetTunnelBridgeDirection(tile) == DIAGDIR_SW)) {
00703 cost.AddCost(ret);
00704 }
00705 had_bridge = true;
00706 } else {
00707 if ((!had_tunnel || GetTunnelBridgeDirection(tile) == DIAGDIR_SE || GetTunnelBridgeDirection(tile) == DIAGDIR_SW)) {
00708 cost.AddCost(ret);
00709 }
00710 had_tunnel = true;
00711 }
00712 } else {
00713 cost.AddCost(ret);
00714 }
00715 }
00716
00717 if (tile == end_tile) break;
00718
00719 tile += HasBit(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
00720 }
00721
00722 return !had_success ? CMD_ERROR : cost;
00723 }
00724
00735 CommandCost CmdRemoveLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
00736 {
00737 TileIndex start_tile, tile;
00738 CommandCost ret, cost(EXPENSES_CONSTRUCTION);
00739 Money money;
00740
00741 if (p1 >= MapSize()) return CMD_ERROR;
00742
00743 start_tile = p1;
00744 RoadType rt = (RoadType)GB(p2, 3, 2);
00745 if (!IsValidRoadType(rt)) return CMD_ERROR;
00746
00747
00748 if (!HasBit(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR;
00749 if (HasBit(p2, 2) && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR;
00750
00751
00752 if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) {
00753 TileIndex t = start_tile;
00754 start_tile = end_tile;
00755 end_tile = t;
00756 p2 ^= IsInsideMM(p2 & 3, 1, 3) ? 3 : 0;
00757 }
00758
00759 money = GetAvailableMoneyForCommand();
00760 tile = start_tile;
00761
00762 for (;;) {
00763 RoadBits bits = HasBit(p2, 2) ? ROAD_Y : ROAD_X;
00764
00765 if (tile == end_tile && !HasBit(p2, 1)) bits &= ROAD_NW | ROAD_NE;
00766 if (tile == start_tile && HasBit(p2, 0)) bits &= ROAD_SE | ROAD_SW;
00767
00768
00769 if (bits != 0) {
00770 ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true);
00771 if (CmdSucceeded(ret)) {
00772 if (flags & DC_EXEC) {
00773 money -= ret.GetCost();
00774 if (money < 0) {
00775 _additional_cash_required = DoCommand(end_tile, start_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost();
00776 return cost;
00777 }
00778 RemoveRoad(tile, flags, bits, rt, true, false);
00779 }
00780 cost.AddCost(ret);
00781 }
00782 }
00783
00784 if (tile == end_tile) break;
00785
00786 tile += HasBit(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
00787 }
00788
00789 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
00790 }
00791
00802 CommandCost CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00803 {
00804 CommandCost cost;
00805 Slope tileh;
00806
00807 DiagDirection dir = Extract<DiagDirection, 0>(p1);
00808 RoadType rt = (RoadType)GB(p1, 2, 2);
00809
00810 if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
00811
00812 tileh = GetTileSlope(tile, NULL);
00813 if (tileh != SLOPE_FLAT && (
00814 !_patches.build_on_slopes ||
00815 IsSteepSlope(tileh) ||
00816 !CanBuildDepotByTileh(dir, tileh)
00817 )) {
00818 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00819 }
00820
00821 cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00822 if (CmdFailed(cost)) return CMD_ERROR;
00823
00824 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00825
00826 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00827
00828 if (flags & DC_EXEC) {
00829 Depot *dep = new Depot(tile);
00830 dep->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
00831
00832 MakeRoadDepot(tile, _current_player, dir, rt);
00833 MarkTileDirtyByTile(tile);
00834 }
00835 return cost.AddCost(_price.build_road_depot);
00836 }
00837
00838 static CommandCost RemoveRoadDepot(TileIndex tile, uint32 flags)
00839 {
00840 if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
00841 return CMD_ERROR;
00842
00843 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00844
00845 if (flags & DC_EXEC) {
00846 DoClearSquare(tile);
00847 delete GetDepotByTile(tile);
00848 }
00849
00850 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_road_depot);
00851 }
00852
00853 static CommandCost ClearTile_Road(TileIndex tile, byte flags)
00854 {
00855 switch (GetRoadTileType(tile)) {
00856 case ROAD_TILE_NORMAL: {
00857 RoadBits b = GetAllRoadBits(tile);
00858
00859
00860
00861 if ((CountBits(b) == 1 && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) ||
00862 ((flags & DC_AI_BUILDING) && IsTileOwner(tile, OWNER_TOWN)) ||
00863 !(flags & DC_AUTO)
00864 ) {
00865 RoadTypes rts = GetRoadTypes(tile);
00866 CommandCost ret(EXPENSES_CONSTRUCTION);
00867 for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
00868 if (HasBit(rts, rt)) {
00869 CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true);
00870 if (CmdFailed(tmp_ret)) return tmp_ret;
00871 ret.AddCost(tmp_ret);
00872 }
00873 }
00874 return ret;
00875 }
00876 return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
00877 }
00878
00879 case ROAD_TILE_CROSSING: {
00880 RoadTypes rts = GetRoadTypes(tile);
00881 CommandCost ret(EXPENSES_CONSTRUCTION);
00882
00883 if (flags & DC_AUTO) return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
00884
00885
00886
00887 RoadType rt = ROADTYPE_HWAY;
00888 do {
00889 if (HasBit(rts, rt)) {
00890 CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false);
00891 if (CmdFailed(tmp_ret)) return tmp_ret;
00892 ret.AddCost(tmp_ret);
00893 }
00894 } while (rt-- != ROADTYPE_ROAD);
00895
00896 if (flags & DC_EXEC) {
00897 DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00898 }
00899 return ret;
00900 }
00901
00902 default:
00903 case ROAD_TILE_DEPOT:
00904 if (flags & DC_AUTO) {
00905 return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00906 }
00907 return RemoveRoadDepot(tile, flags);
00908 }
00909 }
00910
00911
00912 struct DrawRoadTileStruct {
00913 uint16 image;
00914 byte subcoord_x;
00915 byte subcoord_y;
00916 };
00917
00918 #include "table/road_land.h"
00919
00920
00921 Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
00922 {
00923 if (!IsSteepSlope(tileh)) {
00924 if ((~_valid_tileh_slopes_road[0][tileh] & bits) == 0) {
00925
00926
00927
00928
00929
00930 return (tileh != 0 && CountBits(bits) == 1) ? FOUNDATION_LEVELED : FOUNDATION_NONE;
00931 }
00932 if ((~_valid_tileh_slopes_road[1][tileh] & bits) == 0) return FOUNDATION_LEVELED;
00933 }
00934
00935 return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
00936 }
00937
00938 const byte _road_sloped_sprites[14] = {
00939 0, 0, 2, 0,
00940 0, 1, 0, 0,
00941 3, 0, 0, 0,
00942 0, 0
00943 };
00944
00955 static bool AlwaysDrawUnpavedRoads(TileIndex tile, Roadside roadside)
00956 {
00957 return (IsOnSnow(tile) &&
00958 !(_opt.landscape == LT_TROPIC && HasGrfMiscBit(GMB_DESERT_PAVED_ROADS) &&
00959 roadside != ROADSIDE_BARREN && roadside != ROADSIDE_GRASS && roadside != ROADSIDE_GRASS_ROAD_WORKS));
00960 }
00961
00967 void DrawTramCatenary(TileInfo *ti, RoadBits tram)
00968 {
00969
00970 if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !IsTransparencySet(TO_CATENARY)) {
00971 uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
00972
00973 if (height <= GetTileMaxZ(ti->tile) + TILE_HEIGHT) return;
00974 }
00975
00976 SpriteID front;
00977 SpriteID back;
00978
00979 if (ti->tileh != SLOPE_FLAT) {
00980 back = SPR_TRAMWAY_BACK_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1];
00981 front = SPR_TRAMWAY_FRONT_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1];
00982 } else {
00983 back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[tram];
00984 front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[tram];
00985 }
00986
00987 AddSortableSpriteToDraw(back, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY));
00988 AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY));
00989 }
00990
00999 static void DrawRoadDetail(SpriteID img, TileInfo *ti, int dx, int dy, int h)
01000 {
01001 int x = ti->x | dx;
01002 int y = ti->y | dy;
01003 byte z = ti->z;
01004 if (ti->tileh != SLOPE_FLAT) z = GetSlopeZ(x, y);
01005 AddSortableSpriteToDraw(img, PAL_NONE, x, y, 2, 2, h, z);
01006 }
01007
01012 static void DrawRoadBits(TileInfo* ti)
01013 {
01014 RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD);
01015 RoadBits tram = GetRoadBits(ti->tile, ROADTYPE_TRAM);
01016
01017 const DrawRoadTileStruct *drts;
01018 SpriteID image = 0;
01019 SpriteID pal = PAL_NONE;
01020 Roadside roadside;
01021
01022 if (ti->tileh != SLOPE_FLAT) {
01023 DrawFoundation(ti, GetRoadFoundation(ti->tileh, road | tram));
01024
01025
01026
01027 if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
01028 }
01029
01030 if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram];
01031
01032 roadside = GetRoadside(ti->tile);
01033
01034 if (AlwaysDrawUnpavedRoads(ti->tile, roadside)) {
01035 image += 19;
01036 } else {
01037 switch (roadside) {
01038 case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01039 case ROADSIDE_GRASS: break;
01040 case ROADSIDE_GRASS_ROAD_WORKS: break;
01041 default: image -= 19; break;
01042 }
01043 }
01044
01045 DrawGroundSprite(image, pal);
01046
01047
01048
01049
01050 if (tram != ROAD_NONE) {
01051 if (ti->tileh != SLOPE_FLAT) {
01052 image = _road_sloped_sprites[ti->tileh - 1] + SPR_TRAMWAY_SLOPED_OFFSET;
01053 } else {
01054 image = _road_tile_sprites_1[tram] - SPR_ROAD_Y;
01055 }
01056 image += (road == ROAD_NONE) ? SPR_TRAMWAY_TRAM : SPR_TRAMWAY_OVERLAY;
01057 DrawGroundSprite(image, pal);
01058 }
01059
01060 if (road != ROAD_NONE) {
01061 DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile);
01062 if (drd != DRD_NONE) {
01063 DrawRoadDetail(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), ti, 8, 8, 0);
01064 }
01065 }
01066
01067 if (HasRoadWorks(ti->tile)) {
01068
01069 DrawGroundSprite((road | tram) & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE);
01070 return;
01071 }
01072
01073 if (tram != ROAD_NONE) DrawTramCatenary(ti, tram);
01074
01075
01076 if (!HasBit(_display_opt, DO_FULL_DETAIL) || _cur_dpi->zoom > ZOOM_LVL_DETAIL) return;
01077
01078
01079 if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && (roadside == ROADSIDE_TREES || roadside == ROADSIDE_STREET_LIGHTS)) {
01080 uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
01081 uint minz = GetTileMaxZ(ti->tile) + 2 * TILE_HEIGHT;
01082
01083 if (roadside == ROADSIDE_TREES) minz += TILE_HEIGHT;
01084
01085 if (height < minz) return;
01086 }
01087
01088
01089 if (CountBits(road) < 2) return;
01090
01091
01092 for (drts = _road_display_table[roadside][road | tram]; drts->image != 0; drts++) {
01093 DrawRoadDetail(drts->image, ti, drts->subcoord_x, drts->subcoord_y, 0x10);
01094 }
01095 }
01096
01097 static void DrawTile_Road(TileInfo *ti)
01098 {
01099 switch (GetRoadTileType(ti->tile)) {
01100 case ROAD_TILE_NORMAL:
01101 DrawRoadBits(ti);
01102 break;
01103
01104 case ROAD_TILE_CROSSING: {
01105 SpriteID image;
01106 SpriteID pal = PAL_NONE;
01107 Roadside roadside = GetRoadside(ti->tile);
01108
01109 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01110
01111 image = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.crossing;
01112
01113 if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++;
01114 if (IsCrossingBarred(ti->tile)) image += 2;
01115
01116 if (AlwaysDrawUnpavedRoads(ti->tile, roadside)) {
01117 image += 8;
01118 } else {
01119 switch (roadside) {
01120 case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01121 case ROADSIDE_GRASS: break;
01122 default: image += 4; break;
01123 }
01124 }
01125
01126 DrawGroundSprite(image, pal);
01127 if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) {
01128 DrawGroundSprite(SPR_TRAMWAY_OVERLAY + (GetCrossingRoadAxis(ti->tile) ^ 1), pal);
01129 DrawTramCatenary(ti, GetCrossingRoadBits(ti->tile));
01130 }
01131 if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
01132 break;
01133 }
01134
01135 default:
01136 case ROAD_TILE_DEPOT: {
01137 const DrawTileSprites* dts;
01138 const DrawTileSeqStruct* dtss;
01139 SpriteID palette;
01140
01141 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01142
01143 palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
01144
01145 if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) {
01146 dts = &_tram_depot[GetRoadDepotDirection(ti->tile)];
01147 } else {
01148 dts = &_road_depot[GetRoadDepotDirection(ti->tile)];
01149 }
01150
01151 DrawGroundSprite(dts->ground.sprite, PAL_NONE);
01152
01153 for (dtss = dts->seq; dtss->image.sprite != 0; dtss++) {
01154 SpriteID image = dtss->image.sprite;
01155 SpriteID pal;
01156
01157 if (!IsTransparencySet(TO_BUILDINGS) && HasBit(image, PALETTE_MODIFIER_COLOR)) {
01158 pal = palette;
01159 } else {
01160 pal = PAL_NONE;
01161 }
01162
01163 AddSortableSpriteToDraw(
01164 image, pal,
01165 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
01166 dtss->size_x, dtss->size_y,
01167 dtss->size_z, ti->z,
01168 IsTransparencySet(TO_BUILDINGS)
01169 );
01170 }
01171 break;
01172 }
01173 }
01174 DrawBridgeMiddle(ti);
01175 }
01176
01177 void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt)
01178 {
01179 SpriteID palette = PLAYER_SPRITE_COLOR(_local_player);
01180 const DrawTileSprites* dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir];
01181 const DrawTileSeqStruct* dtss;
01182
01183 x += 33;
01184 y += 17;
01185
01186 DrawSprite(dts->ground.sprite, PAL_NONE, x, y);
01187
01188 for (dtss = dts->seq; dtss->image.sprite != 0; dtss++) {
01189 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
01190 SpriteID image = dtss->image.sprite;
01191
01192 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
01193 }
01194 }
01195
01196 static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y)
01197 {
01198 uint z;
01199 Slope tileh = GetTileSlope(tile, &z);
01200
01201 if (tileh == SLOPE_FLAT) return z;
01202 if (IsNormalRoad(tile)) {
01203 Foundation f = GetRoadFoundation(tileh, GetAllRoadBits(tile));
01204 z += ApplyFoundationToSlope(f, &tileh);
01205 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
01206 } else {
01207 return z + TILE_HEIGHT;
01208 }
01209 }
01210
01211 static Foundation GetFoundation_Road(TileIndex tile, Slope tileh)
01212 {
01213 if (IsNormalRoad(tile)) {
01214 return GetRoadFoundation(tileh, GetAllRoadBits(tile));
01215 } else {
01216 return FlatteningFoundation(tileh);
01217 }
01218 }
01219
01220 static void GetAcceptedCargo_Road(TileIndex tile, AcceptedCargo ac)
01221 {
01222
01223 }
01224
01225 static void AnimateTile_Road(TileIndex tile)
01226 {
01227 if (IsLevelCrossing(tile)) MarkTileDirtyByTile(tile);
01228 }
01229
01230
01231 static const Roadside _town_road_types[][2] = {
01232 { ROADSIDE_GRASS, ROADSIDE_GRASS },
01233 { ROADSIDE_PAVED, ROADSIDE_PAVED },
01234 { ROADSIDE_PAVED, ROADSIDE_PAVED },
01235 { ROADSIDE_TREES, ROADSIDE_TREES },
01236 { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
01237 };
01238
01239 static const Roadside _town_road_types_2[][2] = {
01240 { ROADSIDE_GRASS, ROADSIDE_GRASS },
01241 { ROADSIDE_PAVED, ROADSIDE_PAVED },
01242 { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
01243 { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED },
01244 { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
01245 };
01246
01247
01248 static void TileLoop_Road(TileIndex tile)
01249 {
01250 switch (_opt.landscape) {
01251 case LT_ARCTIC:
01252 if (IsOnSnow(tile) != (GetTileZ(tile) > GetSnowLine())) {
01253 ToggleSnow(tile);
01254 MarkTileDirtyByTile(tile);
01255 }
01256 break;
01257
01258 case LT_TROPIC:
01259 if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) {
01260 ToggleDesert(tile);
01261 MarkTileDirtyByTile(tile);
01262 }
01263 break;
01264 }
01265
01266 if (IsRoadDepot(tile)) return;
01267
01268 const Town* t = ClosestTownFromTile(tile, (uint)-1);
01269 if (!HasRoadWorks(tile)) {
01270 HouseZonesBits grp = HZB_TOWN_EDGE;
01271
01272 if (t != NULL) {
01273 grp = GetTownRadiusGroup(t, tile);
01274
01275
01276 if (t->road_build_months != 0 &&
01277 (DistanceManhattan(t->xy, tile) < 8 || grp != HZB_TOWN_EDGE) &&
01278 IsNormalRoad(tile) && CountBits(GetAllRoadBits(tile)) > 1 ) {
01279 if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile) && Chance16(1, 40)) {
01280 StartRoadWorks(tile);
01281
01282 SndPlayTileFx(SND_21_JACKHAMMER, tile);
01283 CreateEffectVehicleAbove(
01284 TileX(tile) * TILE_SIZE + 7,
01285 TileY(tile) * TILE_SIZE + 7,
01286 0,
01287 EV_BULLDOZER);
01288 MarkTileDirtyByTile(tile);
01289 return;
01290 }
01291 }
01292 }
01293
01294 {
01295
01296 const Roadside* new_rs = (_opt.landscape == LT_TOYLAND) ? _town_road_types_2[grp] : _town_road_types[grp];
01297 Roadside cur_rs = GetRoadside(tile);
01298
01299
01300 if (cur_rs == new_rs[0]) return;
01301
01302
01303 if (cur_rs == new_rs[1]) {
01304 cur_rs = new_rs[0];
01305
01306 } else if (cur_rs == ROADSIDE_BARREN) {
01307 cur_rs = new_rs[1];
01308
01309 } else {
01310 cur_rs = ROADSIDE_BARREN;
01311 }
01312 SetRoadside(tile, cur_rs);
01313 MarkTileDirtyByTile(tile);
01314 }
01315 } else if (IncreaseRoadWorksCounter(tile)) {
01316 TerminateRoadWorks(tile);
01317
01318 if (_patches.mod_road_rebuild) {
01319
01320 const RoadBits old_rb = GetAnyRoadBits(tile, ROADTYPE_ROAD);
01321 const RoadBits new_rb = CleanUpRoadBits(tile, old_rb);
01322
01323 if (old_rb != new_rb) {
01324 RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), ROADTYPE_ROAD, true);
01325 }
01326 }
01327
01328 MarkTileDirtyByTile(tile);
01329 }
01330 }
01331
01332 static void ClickTile_Road(TileIndex tile)
01333 {
01334 if (IsRoadDepot(tile)) ShowDepotWindow(tile, VEH_ROAD);
01335 }
01336
01337
01338 static const byte _road_trackbits[16] = {
01339 0x0, 0x0, 0x0, 0x10, 0x0, 0x2, 0x8, 0x1A, 0x0, 0x4, 0x1, 0x15, 0x20, 0x26, 0x29, 0x3F,
01340 };
01341
01342 static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
01343 {
01344 TrackdirBits trackdirbits = TRACKDIR_BIT_NONE;
01345 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
01346 switch (mode) {
01347 case TRANSPORT_RAIL:
01348 if (IsLevelCrossing(tile)) trackdirbits = TrackBitsToTrackdirBits(GetCrossingRailBits(tile));
01349 break;
01350
01351 case TRANSPORT_ROAD:
01352 if ((GetRoadTypes(tile) & sub_mode) == 0) break;
01353 switch (GetRoadTileType(tile)) {
01354 case ROAD_TILE_NORMAL: {
01355 const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 };
01356 RoadType rt = (RoadType)FindFirstBit(sub_mode);
01357 RoadBits bits = GetRoadBits(tile, rt);
01358
01359
01360 if (side != INVALID_DIAGDIR && (DiagDirToRoadBits(side) & bits) == 0) break;
01361
01362 uint multiplier = drd_to_multiplier[rt == ROADTYPE_TRAM ? DRD_NONE : GetDisallowedRoadDirections(tile)];
01363 if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier);
01364 break;
01365 }
01366
01367 case ROAD_TILE_CROSSING: {
01368 Axis axis = GetCrossingRoadAxis(tile);
01369
01370 if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) break;
01371
01372 trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(axis));
01373 if (IsCrossingBarred(tile)) red_signals = trackdirbits;
01374 break;
01375 }
01376
01377 default:
01378 case ROAD_TILE_DEPOT: {
01379 DiagDirection dir = GetRoadDepotDirection(tile);
01380
01381 if (side != INVALID_DIAGDIR && side != dir) break;
01382
01383 trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir)));
01384 break;
01385 }
01386 }
01387 break;
01388
01389 default: break;
01390 }
01391 return CombineTrackStatus(trackdirbits, red_signals);
01392 }
01393
01394 static const StringID _road_tile_strings[] = {
01395 STR_1814_ROAD,
01396 STR_1814_ROAD,
01397 STR_1814_ROAD,
01398 STR_1815_ROAD_WITH_STREETLIGHTS,
01399 STR_1814_ROAD,
01400 STR_1816_TREE_LINED_ROAD,
01401 STR_1814_ROAD,
01402 STR_1814_ROAD,
01403 };
01404
01405 static void GetTileDesc_Road(TileIndex tile, TileDesc *td)
01406 {
01407 td->owner = GetTileOwner(tile);
01408 switch (GetRoadTileType(tile)) {
01409 case ROAD_TILE_CROSSING: td->str = STR_1818_ROAD_RAIL_LEVEL_CROSSING; break;
01410 case ROAD_TILE_DEPOT: td->str = STR_1817_ROAD_VEHICLE_DEPOT; break;
01411 default: td->str = _road_tile_strings[GetRoadside(tile)]; break;
01412 }
01413 }
01414
01419 static const byte _roadveh_enter_depot_dir[4] = {
01420 TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE
01421 };
01422
01423 static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
01424 {
01425 switch (GetRoadTileType(tile)) {
01426 case ROAD_TILE_CROSSING:
01427 if (v->type == VEH_TRAIN) {
01428
01429 assert(IsCrossingBarred(tile));
01430 }
01431 break;
01432
01433 case ROAD_TILE_DEPOT:
01434 if (v->type == VEH_ROAD &&
01435 v->u.road.frame == 11 &&
01436 _roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == v->u.road.state) {
01437 v->u.road.state = RVSB_IN_DEPOT;
01438 v->vehstatus |= VS_HIDDEN;
01439 v->direction = ReverseDir(v->direction);
01440 if (v->Next() == NULL) VehicleEnterDepot(v);
01441 v->tile = tile;
01442
01443 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01444 return VETSB_ENTERED_WORMHOLE;
01445 }
01446 break;
01447
01448 default: break;
01449 }
01450 return VETSB_CONTINUE;
01451 }
01452
01453
01454 static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player)
01455 {
01456 if (IsRoadDepot(tile)) {
01457 if (GetTileOwner(tile) == old_player) {
01458 if (new_player == PLAYER_SPECTATOR) {
01459 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
01460 } else {
01461 SetTileOwner(tile, new_player);
01462 }
01463 }
01464 return;
01465 }
01466
01467 for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
01468
01469 if (rt != ROADTYPE_ROAD && !HasTileRoadType(tile, rt)) continue;
01470
01471 if (GetRoadOwner(tile, rt) == old_player) {
01472 SetRoadOwner(tile, rt, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player);
01473 }
01474 }
01475
01476 if (IsLevelCrossing(tile)) {
01477 if (GetTileOwner(tile) == old_player) {
01478 if (new_player == PLAYER_SPECTATOR) {
01479 DoCommand(tile, 0, GetCrossingRailTrack(tile), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL);
01480 } else {
01481 SetTileOwner(tile, new_player);
01482 }
01483 }
01484 }
01485 }
01486
01487 static CommandCost TerraformTile_Road(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
01488 {
01489 if (_patches.build_on_slopes && AutoslopeEnabled()) {
01490 switch (GetRoadTileType(tile)) {
01491 case ROAD_TILE_CROSSING:
01492 if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
01493 break;
01494
01495 case ROAD_TILE_DEPOT:
01496 if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
01497 break;
01498
01499 case ROAD_TILE_NORMAL: {
01500 RoadBits bits = GetAllRoadBits(tile);
01501 RoadBits bits_copy = bits;
01502
01503 if (!CmdFailed(CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE))) {
01504
01505 if (bits == bits_copy) {
01506 uint z_old;
01507 Slope tileh_old = GetTileSlope(tile, &z_old);
01508
01509
01510 z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old);
01511 z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new);
01512
01513
01514 if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
01515 }
01516 }
01517 break;
01518 }
01519
01520 default: NOT_REACHED();
01521 }
01522 }
01523
01524 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
01525 }
01526
01527
01528 extern const TileTypeProcs _tile_type_road_procs = {
01529 DrawTile_Road,
01530 GetSlopeZ_Road,
01531 ClearTile_Road,
01532 GetAcceptedCargo_Road,
01533 GetTileDesc_Road,
01534 GetTileTrackStatus_Road,
01535 ClickTile_Road,
01536 AnimateTile_Road,
01537 TileLoop_Road,
01538 ChangeTileOwner_Road,
01539 NULL,
01540 VehicleEnter_Road,
01541 GetFoundation_Road,
01542 TerraformTile_Road,
01543 };