script_road.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "script_map.hpp"
00014 #include "script_station.hpp"
00015 #include "script_cargo.hpp"
00016 #include "../../station_base.h"
00017 #include "../../company_func.h"
00018 #include "../../script/squirrel_helper_type.hpp"
00019 
00020 /* static */ ScriptRoad::RoadVehicleType ScriptRoad::GetRoadVehicleTypeForCargo(CargoID cargo_type)
00021 {
00022   return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK;
00023 }
00024 
00025 /* static */ bool ScriptRoad::IsRoadTile(TileIndex tile)
00026 {
00027   if (!::IsValidTile(tile)) return false;
00028 
00029   return (::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) != ROAD_TILE_DEPOT) ||
00030       IsDriveThroughRoadStationTile(tile);
00031 }
00032 
00033 /* static */ bool ScriptRoad::IsRoadDepotTile(TileIndex tile)
00034 {
00035   if (!::IsValidTile(tile)) return false;
00036 
00037   return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT &&
00038       (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00039 }
00040 
00041 /* static */ bool ScriptRoad::IsRoadStationTile(TileIndex tile)
00042 {
00043   if (!::IsValidTile(tile)) return false;
00044 
00045   return ::IsRoadStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00046 }
00047 
00048 /* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile)
00049 {
00050   if (!::IsValidTile(tile)) return false;
00051 
00052   return ::IsDriveThroughStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0;
00053 }
00054 
00055 /* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type)
00056 {
00057   return ::HasRoadTypesAvail(_current_company, ::RoadTypeToRoadTypes((::RoadType)road_type));
00058 }
00059 
00060 /* static */ ScriptRoad::RoadType ScriptRoad::GetCurrentRoadType()
00061 {
00062   return (RoadType)ScriptObject::GetRoadType();
00063 }
00064 
00065 /* static */ void ScriptRoad::SetCurrentRoadType(RoadType road_type)
00066 {
00067   if (!IsRoadTypeAvailable(road_type)) return;
00068 
00069   ScriptObject::SetRoadType((::RoadType)road_type);
00070 }
00071 
00072 /* static */ bool ScriptRoad::HasRoadType(TileIndex tile, RoadType road_type)
00073 {
00074   if (!ScriptMap::IsValidTile(tile)) return false;
00075   if (!IsRoadTypeAvailable(road_type)) return false;
00076   return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE;
00077 }
00078 
00079 /* static */ bool ScriptRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2)
00080 {
00081   if (!::IsValidTile(t1)) return false;
00082   if (!::IsValidTile(t2)) return false;
00083   if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
00084 
00085   /* Tiles not neighbouring */
00086   if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false;
00087 
00088   RoadBits r1 = ::GetAnyRoadBits(t1, ScriptObject::GetRoadType());
00089   RoadBits r2 = ::GetAnyRoadBits(t2, ScriptObject::GetRoadType());
00090 
00091   uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3);
00092   uint dir_2 = 2 ^ dir_1;
00093 
00094   DisallowedRoadDirections drd2 = IsNormalRoadTile(t2) ? GetDisallowedRoadDirections(t2) : DRD_NONE;
00095 
00096   return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND);
00097 }
00098 
00099 /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */
00100 
00115 static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end)
00116 {
00117   return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end);
00118 }
00119 
00130 static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end)
00131 {
00132   switch (slope) {
00133     /* Flat slopes can always be build. */
00134     case SLOPE_FLAT:
00135       return 1;
00136 
00137     /* Only 4 of the slopes can be build upon. Testing the existing bits is
00138      * necessary because these bits can be something else when the settings
00139      * in the game have been changed.
00140      */
00141     case SLOPE_NE: case SLOPE_SW:
00142       return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0;
00143     case SLOPE_SE: case SLOPE_NW:
00144       return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0;
00145 
00146     /* Any other tile cannot be built on. */
00147     default:
00148       return 0;
00149   }
00150 }
00151 
00157 static int32 RotateNeighbour(int32 neighbour)
00158 {
00159   switch (neighbour) {
00160     case -2: return -1;
00161     case -1: return  2;
00162     case  1: return -2;
00163     case  2: return  1;
00164     default: NOT_REACHED();
00165   }
00166 }
00167 
00173 static RoadBits NeighbourToRoadBits(int32 neighbour)
00174 {
00175   switch (neighbour) {
00176     case -2: return ROAD_NW;
00177     case -1: return ROAD_NE;
00178     case  2: return ROAD_SE;
00179     case  1: return ROAD_SW;
00180     default: NOT_REACHED();
00181   }
00182 }
00183 
00194 static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end)
00195 {
00196   /* Steep slopes behave the same as slopes with one corner raised. */
00197   if (IsSteepSlope(slope)) {
00198     slope = SlopeWithOneCornerRaised(GetHighestSlopeCorner(slope));
00199   }
00200 
00201   /* The slope is not steep. Furthermore lots of slopes are generally the
00202    * same but are only rotated. So to reduce the amount of lookup work that
00203    * needs to be done the data is made uniform. This means rotating the
00204    * existing parts and updating the slope. */
00205   static const ::Slope base_slopes[] = {
00206     SLOPE_FLAT, SLOPE_W,   SLOPE_W,   SLOPE_SW,
00207     SLOPE_W,    SLOPE_EW,  SLOPE_SW,  SLOPE_WSE,
00208     SLOPE_W,    SLOPE_SW,  SLOPE_EW,  SLOPE_WSE,
00209     SLOPE_SW,   SLOPE_WSE, SLOPE_WSE};
00210   static const byte base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1};
00211 
00212   if (slope >= (::Slope)lengthof(base_slopes)) {
00213     /* This slope is an invalid slope, so ignore it. */
00214     return -1;
00215   }
00216   byte base_rotate = base_rotates[slope];
00217   slope = base_slopes[slope];
00218 
00219   /* Some slopes don't need rotating, so return early when we know we do
00220    * not need to rotate. */
00221   switch (slope) {
00222     case SLOPE_FLAT:
00223       /* Flat slopes can always be build. */
00224       return 1;
00225 
00226     case SLOPE_EW:
00227     case SLOPE_WSE:
00228       /* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause
00229        * foundations which makes them accessible from all sides. */
00230       return 1;
00231 
00232     case SLOPE_W:
00233     case SLOPE_SW:
00234       /* A slope for which we need perform some calculations. */
00235       break;
00236 
00237     default:
00238       /* An invalid slope. */
00239       return -1;
00240   }
00241 
00242   /* Now perform the actual rotation. */
00243   for (int j = 0; j < base_rotate; j++) {
00244     for (int i = 0; i < existing->size; i++) {
00245       existing->array[i] = RotateNeighbour(existing->array[i]);
00246     }
00247     start = RotateNeighbour(start);
00248     end   = RotateNeighbour(end);
00249   }
00250 
00251   /* Create roadbits out of the data for easier handling. */
00252   RoadBits start_roadbits    = NeighbourToRoadBits(start);
00253   RoadBits new_roadbits      = start_roadbits | NeighbourToRoadBits(end);
00254   RoadBits existing_roadbits = ROAD_NONE;
00255   for (int i = 0; i < existing->size; i++) {
00256     existing_roadbits |= NeighbourToRoadBits(existing->array[i]);
00257   }
00258 
00259   switch (slope) {
00260     case SLOPE_W:
00261       /* A slope similar to a SLOPE_W. */
00262       switch (new_roadbits) {
00263         case ROAD_N:
00264         case ROAD_E:
00265         case ROAD_S:
00266           /* Cannot build anything with a turn from the low side. */
00267           return 0;
00268 
00269         case ROAD_X:
00270         case ROAD_Y:
00271           /* A 'sloped' tile is going to be build. */
00272           if ((existing_roadbits | new_roadbits) != new_roadbits) {
00273             /* There is already a foundation on the tile, or at least
00274              * another slope that is not compatible with the new one. */
00275             return 0;
00276           }
00277           /* If the start is in the low part, it is automatically
00278            * building the second part too. */
00279           return ((start_roadbits & ROAD_E) && !(existing_roadbits & ROAD_W)) ? 2 : 1;
00280 
00281         default:
00282           /* Roadbits causing a foundation are going to be build.
00283            * When the existing roadbits are slopes (the lower bits
00284            * are used), this cannot be done. */
00285           if ((existing_roadbits | new_roadbits) == new_roadbits) return 1;
00286           return (existing_roadbits & ROAD_E) ? 0 : 1;
00287       }
00288 
00289     case SLOPE_SW:
00290       /* A slope similar to a SLOPE_SW. */
00291       switch (new_roadbits) {
00292         case ROAD_N:
00293         case ROAD_E:
00294           /* Cannot build anything with a turn from the low side. */
00295           return 0;
00296 
00297         case ROAD_X:
00298           /* A 'sloped' tile is going to be build. */
00299           if ((existing_roadbits | new_roadbits) != new_roadbits) {
00300             /* There is already a foundation on the tile, or at least
00301              * another slope that is not compatible with the new one. */
00302             return 0;
00303           }
00304           /* If the start is in the low part, it is automatically
00305            * building the second part too. */
00306           return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1;
00307 
00308         default:
00309           /* Roadbits causing a foundation are going to be build.
00310            * When the existing roadbits are slopes (the lower bits
00311            * are used), this cannot be done. */
00312           return (existing_roadbits & ROAD_NE) ? 0 : 1;
00313       }
00314 
00315     default:
00316       NOT_REACHED();
00317   }
00318 }
00319 
00330 static bool NormaliseTileOffset(int32 *tile)
00331 {
00332     if (*tile == 1 || *tile == -1) return true;
00333     if (*tile == ::TileDiffXY(0, -1)) {
00334       *tile = -2;
00335       return true;
00336     }
00337     if (*tile == ::TileDiffXY(0, 1)) {
00338       *tile = 2;
00339       return true;
00340     }
00341     return false;
00342 }
00343 
00344 /* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_)
00345 {
00346 	::Slope slope = (::Slope)slope_;
00347   int32 start = start_;
00348   int32 end = end_;
00349 
00350   /* The start tile and end tile cannot be the same tile either. */
00351   if (start == end) return -1;
00352 
00353   for (int i = 0; i < existing->size; i++) {
00354     if (!NormaliseTileOffset(&existing->array[i])) return -1;
00355   }
00356 
00357   if (!NormaliseTileOffset(&start)) return -1;
00358   if (!NormaliseTileOffset(&end)) return -1;
00359 
00360   /* Without build on slopes the characteristics are vastly different, so use
00361    * a different helper function (one that is much simpler). */
00362   return _settings_game.construction.build_on_slopes ? LookupWithBuildOnSlopes(slope, existing, start, end) : LookupWithoutBuildOnSlopes(slope, existing, start, end);
00363 }
00364 
00365 /* static */ int32 ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end)
00366 {
00367   if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1;
00368   if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1;
00369 
00370   /*                                       ROAD_NW              ROAD_SW             ROAD_SE             ROAD_NE */
00371   static const TileIndex neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)};
00372   Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32));
00373   existing->size = 0;
00374 
00375 	::RoadBits rb = ::ROAD_NONE;
00376   if (::IsNormalRoadTile(tile)) {
00377     rb = ::GetAllRoadBits(tile);
00378   } else {
00379     for (::RoadType rt = ::ROADTYPE_BEGIN; rt < ::ROADTYPE_END; rt++) rb |= ::GetAnyRoadBits(tile, rt);
00380   }
00381   for (uint i = 0; i < lengthof(neighbours); i++) {
00382     if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i];
00383   }
00384 
00385   return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile);
00386 }
00387 
00396 static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, DiagDirection neighbour)
00397 {
00398   TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour);
00399   if ((rts & ::GetRoadTypes(neighbour_tile)) == 0) return false;
00400 
00401   switch (::GetTileType(neighbour_tile)) {
00402     case MP_ROAD:
00403       return (::GetRoadTileType(neighbour_tile) != ROAD_TILE_DEPOT);
00404 
00405     case MP_STATION:
00406       if (::IsDriveThroughStopTile(neighbour_tile)) {
00407         return (::DiagDirToAxis(neighbour) == ::DiagDirToAxis(::GetRoadStopDir(neighbour_tile)));
00408       }
00409       return false;
00410 
00411     default:
00412       return false;
00413   }
00414 }
00415 
00416 /* static */ int32 ScriptRoad::GetNeighbourRoadCount(TileIndex tile)
00417 {
00418   if (!::IsValidTile(tile)) return false;
00419   if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
00420 
00421 	::RoadTypes rts = ::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType());
00422   int32 neighbour = 0;
00423 
00424   if (TileX(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NE)) neighbour++;
00425   if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SE)) neighbour++;
00426   if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SW)) neighbour++;
00427   if (TileY(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NW)) neighbour++;
00428 
00429   return neighbour;
00430 }
00431 
00432 /* static */ TileIndex ScriptRoad::GetRoadDepotFrontTile(TileIndex depot)
00433 {
00434   if (!IsRoadDepotTile(depot)) return INVALID_TILE;
00435 
00436   return depot + ::TileOffsByDiagDir(::GetRoadDepotDirection(depot));
00437 }
00438 
00439 /* static */ TileIndex ScriptRoad::GetRoadStationFrontTile(TileIndex station)
00440 {
00441   if (!IsRoadStationTile(station)) return INVALID_TILE;
00442 
00443   return station + ::TileOffsByDiagDir(::GetRoadStopDir(station));
00444 }
00445 
00446 /* static */ TileIndex ScriptRoad::GetDriveThroughBackTile(TileIndex station)
00447 {
00448   if (!IsDriveThroughRoadStationTile(station)) return INVALID_TILE;
00449 
00450   return station + ::TileOffsByDiagDir(::ReverseDiagDir(::GetRoadStopDir(station)));
00451 }
00452 
00453 /* static */ bool ScriptRoad::_BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full)
00454 {
00455   EnforcePrecondition(false, start != end);
00456   EnforcePrecondition(false, ::IsValidTile(start));
00457   EnforcePrecondition(false, ::IsValidTile(end));
00458   EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00459   EnforcePrecondition(false, !one_way || ScriptObject::GetRoadType() == ::ROADTYPE_ROAD);
00460   EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00461 
00462   return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 5) | 1 << 6, CMD_BUILD_LONG_ROAD);
00463 }
00464 
00465 /* static */ bool ScriptRoad::BuildRoad(TileIndex start, TileIndex end)
00466 {
00467   return _BuildRoadInternal(start, end, false, false);
00468 }
00469 
00470 /* static */ bool ScriptRoad::BuildOneWayRoad(TileIndex start, TileIndex end)
00471 {
00472   return _BuildRoadInternal(start, end, true, false);
00473 }
00474 
00475 /* static */ bool ScriptRoad::BuildRoadFull(TileIndex start, TileIndex end)
00476 {
00477   return _BuildRoadInternal(start, end, false, true);
00478 }
00479 
00480 /* static */ bool ScriptRoad::BuildOneWayRoadFull(TileIndex start, TileIndex end)
00481 {
00482   return _BuildRoadInternal(start, end, true, true);
00483 }
00484 
00485 /* static */ bool ScriptRoad::BuildRoadDepot(TileIndex tile, TileIndex front)
00486 {
00487   EnforcePrecondition(false, tile != front);
00488   EnforcePrecondition(false, ::IsValidTile(tile));
00489   EnforcePrecondition(false, ::IsValidTile(front));
00490   EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
00491   EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00492 
00493   uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
00494 
00495   return ScriptObject::DoCommand(tile, entrance_dir | (ScriptObject::GetRoadType() << 2), 0, CMD_BUILD_ROAD_DEPOT);
00496 }
00497 
00498 /* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
00499 {
00500   EnforcePrecondition(false, tile != front);
00501   EnforcePrecondition(false, ::IsValidTile(tile));
00502   EnforcePrecondition(false, ::IsValidTile(front));
00503   EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
00504   EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
00505   EnforcePrecondition(false, road_veh_type == ROADVEHTYPE_BUS || road_veh_type == ROADVEHTYPE_TRUCK);
00506   EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00507 
00508   uint entrance_dir;
00509   if (drive_through) {
00510     entrance_dir = ::TileY(tile) != ::TileY(front);
00511   } else {
00512     entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
00513   }
00514 
00515   uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 32;
00516   p2 |= drive_through ? 2 : 0;
00517   p2 |= road_veh_type == ROADVEHTYPE_TRUCK ? 1 : 0;
00518   p2 |= ::RoadTypeToRoadTypes(ScriptObject::GetRoadType()) << 2;
00519   p2 |= entrance_dir << 6;
00520   p2 |= (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16;
00521   return ScriptObject::DoCommand(tile, 1 | 1 << 8, p2, CMD_BUILD_ROAD_STOP);
00522 }
00523 
00524 /* static */ bool ScriptRoad::BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
00525 {
00526   return _BuildRoadStationInternal(tile, front, road_veh_type, false, station_id);
00527 }
00528 
00529 /* static */ bool ScriptRoad::BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
00530 {
00531   return _BuildRoadStationInternal(tile, front, road_veh_type, true, station_id);
00532 }
00533 
00534 /* static */ bool ScriptRoad::RemoveRoad(TileIndex start, TileIndex end)
00535 {
00536   EnforcePrecondition(false, ::IsValidTile(start));
00537   EnforcePrecondition(false, ::IsValidTile(end));
00538   EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00539   EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00540 
00541   return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 1 : 2) | (ScriptObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD);
00542 }
00543 
00544 /* static */ bool ScriptRoad::RemoveRoadFull(TileIndex start, TileIndex end)
00545 {
00546   EnforcePrecondition(false, ::IsValidTile(start));
00547   EnforcePrecondition(false, ::IsValidTile(end));
00548   EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
00549   EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
00550 
00551   return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 2 : 1) | (ScriptObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD);
00552 }
00553 
00554 /* static */ bool ScriptRoad::RemoveRoadDepot(TileIndex tile)
00555 {
00556   EnforcePrecondition(false, ::IsValidTile(tile));
00557   EnforcePrecondition(false, IsTileType(tile, MP_ROAD))
00558   EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT);
00559 
00560   return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
00561 }
00562 
00563 /* static */ bool ScriptRoad::RemoveRoadStation(TileIndex tile)
00564 {
00565   EnforcePrecondition(false, ::IsValidTile(tile));
00566   EnforcePrecondition(false, IsTileType(tile, MP_STATION));
00567   EnforcePrecondition(false, IsRoadStop(tile));
00568 
00569   return ScriptObject::DoCommand(tile, 1 | 1 << 8, GetRoadStopType(tile), CMD_REMOVE_ROAD_STOP);
00570 }
00571 
00572 /* static */ Money ScriptRoad::GetBuildCost(RoadType roadtype, BuildType build_type)
00573 {
00574   if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return -1;
00575 
00576   switch (build_type) {
00577     case BT_ROAD:       return ::GetPrice(PR_BUILD_ROAD, 1, NULL);
00578     case BT_DEPOT:      return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, NULL);
00579     case BT_BUS_STOP:   return ::GetPrice(PR_BUILD_STATION_BUS, 1, NULL);
00580     case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, NULL);
00581     default: return -1;
00582   }
00583 }
00584 
00585 /* static */ uint16 ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype)
00586 {
00587   if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0;
00588 
00589   return roadtype == ROADTYPE_TRAM ? 3 : 2;
00590 }