# road_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: road_cmd.cpp 14347 2008-09-16 20:29:09Z rubidium $ */
    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 /* Level crossings may only be built on these slopes */
    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   /* Water can always flood and towns can always remove "normal" road pieces.
    00056    * Towns are not be allowed to remove non "normal" road pieces, like tram
    00057    * tracks as that would result in trams that cannot turn. */
    00058   if (_current_player == OWNER_WATER ||
    00059       (rt == ROADTYPE_ROAD && !IsValidPlayer(_current_player))) return true;
    00060
    00061   /* Only do the special processing if the road is owned
    00062    * by a town */
    00063   if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
    00064
    00065   if (_cheats.magic_bulldozer.value) return true;
    00066
    00067   /* Get a bitmask of which neighbouring roads has a tile */
    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   /* If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
    00076    * then allow it */
    00077   if ((n & (n - 1)) != 0 && (n & remove) != 0) {
    00078     Town *t;
    00079     *edge_road = false;
    00080     /* you can remove all kind of roads with extra dynamite */
    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   /* cost for removing inner/edge -roads */
    00109   static const uint16 road_remove_cost[2] = {50, 18};
    00110
    00111   /* true if the roadpiece was always removeable,
    00112    * false if it was a center piece. Affects town ratings drop */
    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   /* The tile doesn't have the given road type */
    00138   if (!HasBit(rts, rt)) return CMD_ERROR;
    00139
    00140   if (!CheckAllowRemoveRoad(tile, pieces, &edge_road, rt)) return CMD_ERROR;
    00141
    00142   /* check if you're allowed to remove the street owned by a town
    00143    * removal allowance depends on difficulty setting */
    00144   if (town_check && !CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
    00145
    00146   if (!IsTileType(tile, MP_ROAD)) {
    00147     /* If it's the last roadtype, just clear the whole tile */
    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       /* Pay for *every* tile of the bridge or tunnel */
    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         /* Mark tiles diry that have been repaved */
    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       /* limit the bits to delete to the existing bits. */
    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           /* flooding tile with road works, don't forget to remove the effect vehicle too */
    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             /* Includes MarkTileDirtyByTile() */
    00213             DoClearSquare(tile);
    00214           } else {
    00215             SetRoadBits(tile, ROAD_NONE, rt);
    00216             SetRoadTypes(tile, rts);
    00217             MarkTileDirtyByTile(tile);
    00218           }
    00219         } else {
    00220           /* When bits are removed, you *always* end up with something that
    00221            * is not a complete straight road tile. However, trams do not have
    00222            * onewayness, so they cannot remove it either. */
    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       /* Don't allow road to be removed from the crossing when there is tram;
    00237        * we can't draw the crossing without trambits ;) */
    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   /* set of normal ones */
    00284   {
    00285     ROAD_ALL,  // SLOPE_FLAT
    00286     ROAD_NONE, // SLOPE_W
    00287     ROAD_NONE, // SLOPE_S
    00288
    00289     ROAD_X,    // SLOPE_SW
    00290     ROAD_NONE, // SLOPE_E
    00291     ROAD_NONE, // SLOPE_EW
    00292
    00293     ROAD_Y,    // SLOPE_SE
    00294     ROAD_NONE, // SLOPE_WSE
    00295     ROAD_NONE, // SLOPE_N
    00296
    00297     ROAD_Y,    // SLOPE_NW
    00298     ROAD_NONE, // SLOPE_NS
    00299     ROAD_NONE, // SLOPE_NE
    00300
    00301     ROAD_X,    // SLOPE_ENW
    00302     ROAD_NONE, // SLOPE_SEN
    00303     ROAD_NONE  // SLOPE_ELEVATED
    00304   },
    00305   /* allowed road for an evenly raised platform */
    00306   {
    00307     ROAD_NONE,         // SLOPE_FLAT
    00308     ROAD_SW | ROAD_NW, // SLOPE_W
    00309     ROAD_SW | ROAD_SE, // SLOPE_S
    00310
    00311     ROAD_Y  | ROAD_SW, // SLOPE_SW
    00312     ROAD_SE | ROAD_NE, // SLOPE_E
    00313     ROAD_ALL,          // SLOPE_EW
    00314
    00315     ROAD_X  | ROAD_SE, // SLOPE_SE
    00316     ROAD_ALL,          // SLOPE_WSE
    00317     ROAD_NW | ROAD_NE, // SLOPE_N
    00318
    00319     ROAD_X  | ROAD_NW, // SLOPE_NW
    00320     ROAD_ALL,          // SLOPE_NS
    00321     ROAD_ALL,          // SLOPE_NE
    00322
    00323     ROAD_Y  | ROAD_NE, // SLOPE_ENW
    00324     ROAD_ALL,          // SLOPE_SEN
    00325     ROAD_ALL           // SLOPE_ELEVATED
    00326   },
    00327   /* Singe bits on slopes */
    00328   {
    00329     ROAD_ALL,          // SLOPE_FLAT
    00330     ROAD_NE | ROAD_SE, // SLOPE_W
    00331     ROAD_NE | ROAD_NW, // SLOPE_S
    00332
    00333     ROAD_NE,           // SLOPE_SW
    00334     ROAD_NW | ROAD_SW, // SLOPE_E
    00335     ROAD_ALL,          // SLOPE_EW
    00336
    00337     ROAD_NW,           // SLOPE_SE
    00338     ROAD_ALL,          // SLOPE_WSE
    00339     ROAD_SE | ROAD_SW, // SLOPE_N
    00340
    00341     ROAD_SE,           // SLOPE_NW
    00342     ROAD_ALL,          // SLOPE_NS
    00343     ROAD_ALL,          // SLOPE_NE
    00344
    00345     ROAD_SW,           // SLOPE_ENW
    00346     ROAD_ALL,          // SLOPE_SEN
    00347     ROAD_ALL,          // SLOPE_ELEVATED
    00348   },
    00349 };
    00350
    00361 static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
    00362 {
    00363   if (IsSteepSlope(tileh)) {
    00364     /* Force straight roads. */
    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   /* Single bits on slopes.
    00376    * We check for the roads that need at least 2 bits */
    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   /* no special foundation */
    00384   if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == ROAD_NONE) {
    00385     /* force that all bits are set when we have slopes */
    00386     if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
    00387     return CommandCost(); // no extra cost
    00388   }
    00389
    00390   /* foundation is used. Whole tile is leveled up */
    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   /* Force straight roads. */
    00396   *pieces |= MirrorRoadBits(*pieces);
    00397
    00398   /* partly leveled up tile, only if there's no road on that tile */
    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   /* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
    00422    * if a non-player is building the road */
    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   /* do not allow building 'zero' road bits, code wouldn't handle it */
    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             /* Junctions cannot be one-way */
    00451             return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
    00452           }
    00453           if ((existing & pieces) == pieces) {
    00454             /* We only want to set the (dis)allowed road directions */
    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               /* Ignore half built tiles */
    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; // we need to pay for both roadbits
    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       /* Level crossings may only be built on these slopes */
    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         /* Always add road to the roadtypes (can't draw without it) */
    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; // we need to pay for both roadbits
    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       /* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
    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     /* Check the foundation/slopes when adding road/tram bits */
    00550     ret = CheckRoadSlope(tileh, &pieces, all_bits | existing);
    00551     /* Return an error if we need to build a foundation (ret != 0) but the
    00552      * current patch-setting is turned off (or stupid AI@work) */
    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     /* Don't put the pieces that already exist */
    00561     pieces &= ComplementRoadBits(existing);
    00562
    00563     /* Check if new road bits will have the same foundation as other existing road types */
    00564     if (IsNormalRoad(tile)) {
    00565       Slope slope = GetTileSlope(tile, NULL);
    00566       Foundation found_new = GetRoadFoundation(slope, pieces | existing);
    00567
    00568       /* Test if all other roadtypes can be built at that foundation */
    00569       for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) {
    00570         if (rtest != rt) { // check only other road types
    00571           RoadBits bits = GetRoadBits(tile, rtest);
    00572           /* do not check if there are not road bits of given type */
    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     /* Pay for *every* tile of the bridge or tunnel */
    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         /* Mark tiles diry that have been repaved */
    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   /* Only drag in X or Y direction dictated by the direction variable */
    00667   if (!HasBit(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
    00668   if (HasBit(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
    00669
    00670   /* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
    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   /* On the X-axis, we have to swap the initial bits, so they
    00680    * will be interpreted correctly in the GTTS. Futhermore
    00681    * when you just 'click' on one tile to build them. */
    00682   if (HasBit(p2, 2) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH;
    00683   /* No disallowed direction bits have to be toggled */
    00684   if (!HasBit(p2, 5)) drd = DRD_NONE;
    00685
    00686   tile = start_tile;
    00687   /* Start tile is the small number. */
    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       /* Only pay for the upgrade on one side of the bridges and tunnels */
    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 { // IsTunnel(tile)
    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   /* Only drag in X or Y direction dictated by the direction variable */
    00748   if (!HasBit(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
    00749   if (HasBit(p2, 2)  && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
    00750
    00751   /* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
    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   /* Start tile is the small number. */
    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     /* try to remove the halves. */
    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       /* Clear the road if only one piece is on the tile OR the AI tries
    00860        * to clear town road OR we are not using the DC_AUTO flag */
    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       /* Must iterate over the roadtypes in a reverse manner because
    00886        * tram tracks must be removed before the road bits. */
    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       /* As one can remove a single road piece when in a corner on a foundation as
    00926        * it is on a sloped piece of landscape, one creates a state that cannot be
    00927        * created directly, but the state itself is still perfectly drawable.
    00928        * However, as we do not want this to be build directly, we need to check
    00929        * for that situation in here. */
    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   /* Don't draw the catenary under a low bridge */
    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     /* DrawFoundation() modifies ti.
    01026      * Default sloped sprites.. */
    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; // Paved
    01042     }
    01043   }
    01044
    01045   DrawGroundSprite(image, pal);
    01046
    01047   /* For tram we overlay the road graphics with either tram tracks only
    01048    * (when there is actual road beneath the trams) or with tram tracks
    01049    * and some dirts which hides the road graphics */
    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     /* Road works */
    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   /* Return if full detail is disabled, or we are zoomed fully out. */
    01076   if (!HasBit(_display_opt, DO_FULL_DETAIL) || _cur_dpi->zoom > ZOOM_LVL_DETAIL) return;
    01077
    01078   /* Do not draw details (street lights, trees) under low bridge */
    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   /* If there are no road bits, return, as there is nothing left to do */
    01089   if (CountBits(road) < 2) return;
    01090
    01091   /* Draw extra details. */
    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; // Paved
    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   /* not used */
    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       /* Show an animation to indicate road work */
    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       /* Adjust road ground type depending on 'grp' (grp is the distance to the center) */
    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       /* We have our desired type, do nothing */
    01300       if (cur_rs == new_rs[0]) return;
    01301
    01302       /* We have the pre-type of the desired type, switch to the desired type */
    01303       if (cur_rs == new_rs[1]) {
    01304         cur_rs = new_rs[0];
    01305       /* We have barren land, install the pre-type */
    01306       } else if (cur_rs == ROADSIDE_BARREN) {
    01307         cur_rs = new_rs[1];
    01308       /* We're totally off limits, remove any installation and make barren land */
    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       /* Generate a nicer town surface */
    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 /* Converts RoadBits to TrackBits */
    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; // crossing barred
    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           /* no roadbit at this side of tile, return 0 */
    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         /* it should be barred */
    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     /* ROADTYPE_ROAD denotes the tile owner, so update it too */
    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         /* Check if the slope-road_bits combination is valid at all, i.e. it is save to call GetRoadFoundation(). */
    01503         if (!CmdFailed(CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE))) {
    01504           /* CheckRoadSlope() sometimes changes the road_bits, if it does not agree with them. */
    01505           if (bits == bits_copy) {
    01506             uint z_old;
    01507             Slope tileh_old = GetTileSlope(tile, &z_old);
    01508
    01509             /* Get the slope on top of the foundation */
    01510             z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old);
    01511             z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new);
    01512
    01513             /* The surface slope must not be changed */
    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,           /* draw_tile_proc */
    01530   GetSlopeZ_Road,          /* get_slope_z_proc */
    01531   ClearTile_Road,          /* clear_tile_proc */
    01532   GetAcceptedCargo_Road,   /* get_accepted_cargo_proc */
    01533   GetTileDesc_Road,        /* get_tile_desc_proc */
    01534   GetTileTrackStatus_Road, /* get_tile_track_status_proc */
    01535   ClickTile_Road,          /* click_tile_proc */
    01536   AnimateTile_Road,        /* animate_tile_proc */
    01537   TileLoop_Road,           /* tile_loop_clear */
    01538   ChangeTileOwner_Road,    /* change_tile_owner_clear */
    01539   NULL,                    /* get_produced_cargo_proc */
    01540   VehicleEnter_Road,       /* vehicle_enter_tile_proc */
    01541   GetFoundation_Road,      /* get_foundation_proc */
    01542   TerraformTile_Road,      /* terraform_tile_proc */
    01543 };