script_rail.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_rail.hpp"
00014 #include "script_map.hpp"
00015 #include "script_station.hpp"
00016 #include "script_industrytype.hpp"
00017 #include "script_cargo.hpp"
00018 #include "../../debug.h"
00019 #include "../../station_base.h"
00020 #include "../../company_func.h"
00021 #include "../../newgrf.h"
00022 #include "../../newgrf_generic.h"
00023 #include "../../newgrf_station.h"
00024 #include "../../strings_func.h"
00025 
00026 /* static */ char *ScriptRail::GetName(RailType rail_type)
00027 {
00028   if (!IsRailTypeAvailable(rail_type)) return NULL;
00029 
00030   static const int len = 64;
00031   char *railtype_name = MallocT<char>(len);
00032 
00033   ::GetString(railtype_name, GetRailTypeInfo((::RailType)rail_type)->strings.menu_text, &railtype_name[len - 1]);
00034   return railtype_name;
00035 }
00036 
00037 /* static */ bool ScriptRail::IsRailTile(TileIndex tile)
00038 {
00039   if (!::IsValidTile(tile)) return false;
00040 
00041   return (::IsTileType(tile, MP_RAILWAY) && !::IsRailDepot(tile)) ||
00042       (::HasStationTileRail(tile) && !::IsStationTileBlocked(tile)) || ::IsLevelCrossingTile(tile);
00043 }
00044 
00045 /* static */ bool ScriptRail::IsLevelCrossingTile(TileIndex tile)
00046 {
00047   if (!::IsValidTile(tile)) return false;
00048 
00049   return ::IsLevelCrossingTile(tile);
00050 }
00051 
00052 /* static */ bool ScriptRail::IsRailDepotTile(TileIndex tile)
00053 {
00054   if (!::IsValidTile(tile)) return false;
00055 
00056   return ::IsRailDepotTile(tile);
00057 }
00058 
00059 /* static */ bool ScriptRail::IsRailStationTile(TileIndex tile)
00060 {
00061   if (!::IsValidTile(tile)) return false;
00062 
00063   return ::IsRailStationTile(tile);
00064 }
00065 
00066 /* static */ bool ScriptRail::IsRailWaypointTile(TileIndex tile)
00067 {
00068   if (!::IsValidTile(tile)) return false;
00069 
00070   return ::IsRailWaypointTile(tile);
00071 }
00072 
00073 /* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type)
00074 {
00075   if ((::RailType)rail_type < RAILTYPE_BEGIN || (::RailType)rail_type >= RAILTYPE_END) return false;
00076 
00077   return ::HasRailtypeAvail(_current_company, (::RailType)rail_type);
00078 }
00079 
00080 /* static */ ScriptRail::RailType ScriptRail::GetCurrentRailType()
00081 {
00082   return (RailType)ScriptObject::GetRailType();
00083 }
00084 
00085 /* static */ void ScriptRail::SetCurrentRailType(RailType rail_type)
00086 {
00087   if (!IsRailTypeAvailable(rail_type)) return;
00088 
00089   ScriptObject::SetRailType((::RailType)rail_type);
00090 }
00091 
00092 /* static */ bool ScriptRail::TrainCanRunOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
00093 {
00094   if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
00095   if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
00096 
00097   return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
00098 }
00099 
00100 /* static */ bool ScriptRail::TrainHasPowerOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
00101 {\
00102   if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
00103   if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
00104 
00105   return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
00106 }
00107 
00108 /* static */ ScriptRail::RailType ScriptRail::GetRailType(TileIndex tile)
00109 {
00110   if (!ScriptTile::HasTransportType(tile, ScriptTile::TRANSPORT_RAIL)) return RAILTYPE_INVALID;
00111 
00112   return (RailType)::GetRailType(tile);
00113 }
00114 
00115 /* static */ bool ScriptRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to)
00116 {
00117   EnforcePrecondition(false, ::IsValidTile(start_tile));
00118   EnforcePrecondition(false, ::IsValidTile(end_tile));
00119   EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
00120 
00121   return ScriptObject::DoCommand(start_tile, end_tile, convert_to, CMD_CONVERT_RAIL);
00122 }
00123 
00124 /* static */ TileIndex ScriptRail::GetRailDepotFrontTile(TileIndex depot)
00125 {
00126   if (!IsRailDepotTile(depot)) return INVALID_TILE;
00127 
00128   return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot));
00129 }
00130 
00131 /* static */ ScriptRail::RailTrack ScriptRail::GetRailStationDirection(TileIndex tile)
00132 {
00133   if (!IsRailStationTile(tile)) return RAILTRACK_INVALID;
00134 
00135   return (RailTrack)::GetRailStationTrackBits(tile);
00136 }
00137 
00138 /* static */ bool ScriptRail::BuildRailDepot(TileIndex tile, TileIndex front)
00139 {
00140   EnforcePrecondition(false, tile != front);
00141   EnforcePrecondition(false, ::IsValidTile(tile));
00142   EnforcePrecondition(false, ::IsValidTile(front));
00143   EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
00144   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00145 
00146   uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
00147 
00148   return ScriptObject::DoCommand(tile, ScriptObject::GetRailType(), entrance_dir, CMD_BUILD_TRAIN_DEPOT);
00149 }
00150 
00151 /* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id)
00152 {
00153   EnforcePrecondition(false, ::IsValidTile(tile));
00154   EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
00155   EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
00156   EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
00157   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00158   EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
00159 
00160   uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
00161   if (direction == RAILTRACK_NW_SE) p1 |= (1 << 4);
00162   if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
00163   return ScriptObject::DoCommand(tile, p1, (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16, CMD_BUILD_RAIL_STATION);
00164 }
00165 
00166 /* static */ bool ScriptRail::BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station)
00167 {
00168   EnforcePrecondition(false, ::IsValidTile(tile));
00169   EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
00170   EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
00171   EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
00172   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00173   EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
00174   EnforcePrecondition(false, ScriptCargo::IsValidCargo(cargo_id));
00175   EnforcePrecondition(false, source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry));
00176   EnforcePrecondition(false, goal_industry   == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry   == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry));
00177 
00178   uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
00179   if (direction == RAILTRACK_NW_SE) p1 |= 1 << 4;
00180   if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
00181 
00182   const GRFFile *file;
00183   uint16 res = GetAiPurchaseCallbackResult(GSF_STATIONS, cargo_id, 0, source_industry, goal_industry, min(255, distance / 2), AICE_STATION_GET_STATION_ID, source_station ? 0 : 1, min(15, num_platforms) << 4 | min(15, platform_length), &file);
00184   uint32 p2 = (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16;
00185   if (res != CALLBACK_FAILED) {
00186     int index = 0;
00187     const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index);
00188     if (spec == NULL) {
00189       DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
00190     } else {
00191       p2 |= spec->cls_id | index << 8;
00192     }
00193 
00194   }
00195   return ScriptObject::DoCommand(tile, p1, p2, CMD_BUILD_RAIL_STATION);
00196 }
00197 
00198 /* static */ bool ScriptRail::BuildRailWaypoint(TileIndex tile)
00199 {
00200   EnforcePrecondition(false, ::IsValidTile(tile));
00201   EnforcePrecondition(false, IsRailTile(tile));
00202   EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE);
00203   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00204 
00205   return ScriptObject::DoCommand(tile, GetCurrentRailType() | (GetRailTracks(tile) == RAILTRACK_NE_SW ? AXIS_X : AXIS_Y) << 4 | 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT);
00206 }
00207 
00208 /* static */ bool ScriptRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
00209 {
00210   EnforcePrecondition(false, ::IsValidTile(tile));
00211   EnforcePrecondition(false, ::IsValidTile(tile2));
00212 
00213   return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_WAYPOINT);
00214 }
00215 
00216 /* static */ bool ScriptRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
00217 {
00218   EnforcePrecondition(false, ::IsValidTile(tile));
00219   EnforcePrecondition(false, ::IsValidTile(tile2));
00220 
00221   return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_STATION);
00222 }
00223 
00224 /* static */ uint ScriptRail::GetRailTracks(TileIndex tile)
00225 {
00226   if (!IsRailTile(tile)) return RAILTRACK_INVALID;
00227 
00228   if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
00229   if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile);
00230   if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE;
00231   return ::GetTrackBits(tile);
00232 }
00233 
00234 /* static */ bool ScriptRail::BuildRailTrack(TileIndex tile, RailTrack rail_track)
00235 {
00236   EnforcePrecondition(false, ::IsValidTile(tile));
00237   EnforcePrecondition(false, rail_track != 0);
00238   EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0);
00239   EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
00240   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00241 
00242   return ScriptObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_BUILD_RAILROAD_TRACK);
00243 }
00244 
00245 /* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
00246 {
00247   EnforcePrecondition(false, ::IsValidTile(tile));
00248   EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile));
00249   EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
00250   EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
00251 
00252   return ScriptObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_REMOVE_RAILROAD_TRACK);
00253 }
00254 
00255 /* static */ bool ScriptRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
00256 {
00257   if (!IsRailTile(tile)) return false;
00258   if (from == to || ScriptMap::DistanceManhattan(from, tile) != 1 || ScriptMap::DistanceManhattan(tile, to) != 1) return false;
00259 
00260   if (to < from) ::Swap(from, to);
00261 
00262   if (tile - from == 1) {
00263     if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0;
00264     if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
00265   } else if (tile - from == ::MapSizeX()) {
00266     if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0;
00267     if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0;
00268     if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
00269   } else {
00270     return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0;
00271   }
00272 
00273   NOT_REACHED();
00274 }
00275 
00280 static uint32 SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
00281 {
00282   int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile)));
00283   uint32 p2 = ScriptRail::GetCurrentRailType();
00284   if (::TileY(from) == ::TileY(*to)) {
00285     p2 |= (TRACK_X << 4);
00286     *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
00287   } else if (::TileX(from) == ::TileX(*to)) {
00288     p2 |= (TRACK_Y << 4);
00289     *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
00290   } else if (::TileY(from) < ::TileY(tile)) {
00291     if (::TileX(*to) < ::TileX(tile)) {
00292       p2 |= (TRACK_UPPER << 4);
00293     } else {
00294       p2 |= (TRACK_LEFT << 4);
00295     }
00296     if (diag_offset != 0) {
00297       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
00298     } else {
00299       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
00300     }
00301   } else if (::TileY(from) > ::TileY(tile)) {
00302     if (::TileX(*to) < ::TileX(tile)) {
00303       p2 |= (TRACK_RIGHT << 4);
00304     } else {
00305       p2 |= (TRACK_LOWER << 4);
00306     }
00307     if (diag_offset != 0) {
00308       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
00309     } else {
00310       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
00311     }
00312   } else if (::TileX(from) < ::TileX(tile)) {
00313     if (::TileY(*to) < ::TileY(tile)) {
00314       p2 |= (TRACK_UPPER << 4);
00315     } else {
00316       p2 |= (TRACK_RIGHT << 4);
00317     }
00318     if (diag_offset == 0) {
00319       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
00320     } else {
00321       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
00322     }
00323   } else if (::TileX(from) > ::TileX(tile)) {
00324     if (::TileY(*to) < ::TileY(tile)) {
00325       p2 |= (TRACK_LEFT << 4);
00326     } else {
00327       p2 |= (TRACK_LOWER << 4);
00328     }
00329     if (diag_offset == 0) {
00330       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
00331     } else {
00332       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
00333     }
00334   }
00335   return p2;
00336 }
00337 
00338 /* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
00339 {
00340   EnforcePrecondition(false, ::IsValidTile(from));
00341   EnforcePrecondition(false, ::IsValidTile(tile));
00342   EnforcePrecondition(false, ::IsValidTile(to));
00343   EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
00344   EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
00345   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
00346   int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
00347   EnforcePrecondition(false, diag_offset <= 1 ||
00348       (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
00349       (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
00350 
00351   uint32 p2 = SimulateDrag(from, tile, &to) | 1 << 8;
00352   return ScriptObject::DoCommand(tile, to, p2, CMD_BUILD_RAILROAD_TRACK);
00353 }
00354 
00355 /* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
00356 {
00357   EnforcePrecondition(false, ::IsValidTile(from));
00358   EnforcePrecondition(false, ::IsValidTile(tile));
00359   EnforcePrecondition(false, ::IsValidTile(to));
00360   EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
00361   EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
00362   int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
00363   EnforcePrecondition(false, diag_offset <= 1 ||
00364       (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
00365       (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
00366 
00367   if (!IsRailTypeAvailable(GetCurrentRailType())) SetCurrentRailType(GetRailType(tile));
00368   uint32 p2 = SimulateDrag(from, tile, &to);
00369   return ScriptObject::DoCommand(tile, to, p2, CMD_REMOVE_RAILROAD_TRACK);
00370 }
00371 
00376 struct ScriptRailSignalData {
00377   Track track;        
00378   Trackdir trackdir;  
00379   uint signal_cycles; 
00380 };
00381 
00382 static const int NUM_TRACK_DIRECTIONS = 3; 
00383 
00390 static const ScriptRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = {
00391   {{TRACK_UPPER,   TRACKDIR_UPPER_E, 0}, {TRACK_Y,       TRACKDIR_Y_SE,    0}, {TRACK_LEFT,    TRACKDIR_LEFT_S,  1}},
00392   {{TRACK_RIGHT,   TRACKDIR_RIGHT_S, 1}, {TRACK_X,       TRACKDIR_X_SW,    1}, {TRACK_UPPER,   TRACKDIR_UPPER_W, 1}},
00393   {{INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}},
00394   {{TRACK_LOWER,   TRACKDIR_LOWER_E, 0}, {TRACK_X,       TRACKDIR_X_NE,    0}, {TRACK_LEFT,    TRACKDIR_LEFT_N,  0}},
00395   {{TRACK_RIGHT,   TRACKDIR_RIGHT_N, 0}, {TRACK_Y,       TRACKDIR_Y_NW,    1}, {TRACK_LOWER,   TRACKDIR_LOWER_W, 1}}
00396 };
00397 
00398 /* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front)
00399 {
00400   if (ScriptMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE;
00401   if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE;
00402 
00403   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
00404 
00405   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
00406     const Track &track = _possible_trackdirs[data_index][i].track;
00407     if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue;
00408     if (!HasSignalOnTrack(tile, track)) continue;
00409     if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue;
00410     SignalType st = (SignalType)::GetSignalType(tile, track);
00411     if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY);
00412     return st;
00413   }
00414 
00415   return SIGNALTYPE_NONE;
00416 }
00417 
00421 static bool IsValidSignalType(int signal_type)
00422 {
00423   if (signal_type < ScriptRail::SIGNALTYPE_NORMAL || signal_type > ScriptRail::SIGNALTYPE_COMBO_TWOWAY) return false;
00424   if (signal_type > ScriptRail::SIGNALTYPE_PBS_ONEWAY && signal_type < ScriptRail::SIGNALTYPE_NORMAL_TWOWAY) return false;
00425   return true;
00426 }
00427 
00428 /* static */ bool ScriptRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
00429 {
00430   EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
00431   EnforcePrecondition(false, ::IsPlainRailTile(tile));
00432   EnforcePrecondition(false, ::IsValidSignalType(signal));
00433 
00434   Track track = INVALID_TRACK;
00435   uint signal_cycles;
00436 
00437   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
00438   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
00439     const Track &t = _possible_trackdirs[data_index][i].track;
00440     if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
00441     track = t;
00442     signal_cycles = _possible_trackdirs[data_index][i].signal_cycles;
00443     break;
00444   }
00445   EnforcePrecondition(false, track != INVALID_TRACK);
00446 
00447   uint p1 = track;
00448   if (signal < SIGNALTYPE_TWOWAY) {
00449     if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++;
00450     p1 |= (signal_cycles << 15);
00451   }
00452   p1 |= ((signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal) << 5);
00453 
00454   return ScriptObject::DoCommand(tile, p1, 0, CMD_BUILD_SIGNALS);
00455 }
00456 
00457 /* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front)
00458 {
00459   EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
00460   EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE);
00461 
00462   Track track = INVALID_TRACK;
00463   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
00464   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
00465     const Track &t = _possible_trackdirs[data_index][i].track;
00466     if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
00467     track = t;
00468     break;
00469   }
00470   EnforcePrecondition(false, track != INVALID_TRACK);
00471 
00472   return ScriptObject::DoCommand(tile, track, 0, CMD_REMOVE_SIGNALS);
00473 }
00474 
00475 /* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type)
00476 {
00477   if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
00478 
00479   switch (build_type) {
00480     case BT_TRACK:    return ::RailBuildCost((::RailType)railtype);
00481     case BT_SIGNAL:   return ::GetPrice(PR_BUILD_SIGNALS, 1, NULL);
00482     case BT_DEPOT:    return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, NULL);
00483     case BT_STATION:  return ::GetPrice(PR_BUILD_STATION_RAIL, 1, NULL) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, NULL);
00484     case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, NULL);
00485     default: return -1;
00486   }
00487 }
00488 
00489 /* static */ int32 ScriptRail::GetMaxSpeed(RailType railtype)
00490 {
00491   if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
00492 
00493   return ::GetRailTypeInfo((::RailType)railtype)->max_speed;
00494 }
00495 
00496 /* static */ uint16 ScriptRail::GetMaintenanceCostFactor(RailType railtype)
00497 {
00498   if (!ScriptRail::IsRailTypeAvailable(railtype)) return 0;
00499 
00500   return ::GetRailTypeInfo((::RailType)railtype)->maintenance_multiplier;
00501 }