# ai_rail.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_rail.cpp 22838 2011-08-25 13:24:32Z rubidium $ */
    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 "ai_rail.hpp"
    00014 #include "ai_map.hpp"
    00015 #include "ai_station.hpp"
    00016 #include "ai_industrytype.hpp"
    00017 #include "ai_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 *AIRail::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 AIRail::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 AIRail::IsLevelCrossingTile(TileIndex tile)
    00046 {
    00047   if (!::IsValidTile(tile)) return false;
    00048
    00049   return ::IsLevelCrossingTile(tile);
    00050 }
    00051
    00052 /* static */ bool AIRail::IsRailDepotTile(TileIndex tile)
    00053 {
    00054   if (!::IsValidTile(tile)) return false;
    00055
    00056   return ::IsRailDepotTile(tile);
    00057 }
    00058
    00059 /* static */ bool AIRail::IsRailStationTile(TileIndex tile)
    00060 {
    00061   if (!::IsValidTile(tile)) return false;
    00062
    00063   return ::IsRailStationTile(tile);
    00064 }
    00065
    00066 /* static */ bool AIRail::IsRailWaypointTile(TileIndex tile)
    00067 {
    00068   if (!::IsValidTile(tile)) return false;
    00069
    00070   return ::IsRailWaypointTile(tile);
    00071 }
    00072
    00073 /* static */ bool AIRail::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 */ AIRail::RailType AIRail::GetCurrentRailType()
    00081 {
    00082   return (RailType)AIObject::GetRailType();
    00083 }
    00084
    00085 /* static */ void AIRail::SetCurrentRailType(RailType rail_type)
    00086 {
    00087   if (!IsRailTypeAvailable(rail_type)) return;
    00088
    00089   AIObject::SetRailType((::RailType)rail_type);
    00090 }
    00091
    00092 /* static */ bool AIRail::TrainCanRunOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type)
    00093 {
    00094   if (!AIRail::IsRailTypeAvailable(engine_rail_type)) return false;
    00095   if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
    00096
    00097   return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
    00098 }
    00099
    00100 /* static */ bool AIRail::TrainHasPowerOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type)
    00101 {\
    00102   if (!AIRail::IsRailTypeAvailable(engine_rail_type)) return false;
    00103   if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
    00104
    00105   return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
    00106 }
    00107
    00108 /* static */ AIRail::RailType AIRail::GetRailType(TileIndex tile)
    00109 {
    00110   if (!AITile::HasTransportType(tile, AITile::TRANSPORT_RAIL)) return RAILTYPE_INVALID;
    00111
    00112   return (RailType)::GetRailType(tile);
    00113 }
    00114
    00115 /* static */ bool AIRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, AIRail::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 AIObject::DoCommand(start_tile, end_tile, convert_to, CMD_CONVERT_RAIL);
    00122 }
    00123
    00124 /* static */ TileIndex AIRail::GetRailDepotFrontTile(TileIndex depot)
    00125 {
    00126   if (!IsRailDepotTile(depot)) return INVALID_TILE;
    00127
    00128   return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot));
    00129 }
    00130
    00131 /* static */ AIRail::RailTrack AIRail::GetRailStationDirection(TileIndex tile)
    00132 {
    00133   if (!IsRailStationTile(tile)) return RAILTRACK_INVALID;
    00134
    00135   return (RailTrack)::GetRailStationTrackBits(tile);
    00136 }
    00137
    00138 /* static */ bool AIRail::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 AIObject::DoCommand(tile, AIObject::GetRailType(), entrance_dir, CMD_BUILD_TRAIN_DEPOT);
    00149 }
    00150
    00151 /* static */ bool AIRail::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 == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::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 != AIStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
    00163   return AIObject::DoCommand(tile, p1, (AIStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16, CMD_BUILD_RAIL_STATION);
    00164 }
    00165
    00166 /* static */ bool AIRail::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 == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id));
    00174   EnforcePrecondition(false, AICargo::IsValidCargo(cargo_id));
    00175   EnforcePrecondition(false, source_industry == AIIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == AIIndustryType::INDUSTRYTYPE_TOWN || AIIndustryType::IsValidIndustryType(source_industry));
    00176   EnforcePrecondition(false, goal_industry   == AIIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry   == AIIndustryType::INDUSTRYTYPE_TOWN || AIIndustryType::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 != AIStation::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 = (AIStation::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 AIObject::DoCommand(tile, p1, p2, CMD_BUILD_RAIL_STATION);
    00196 }
    00197
    00198 /* static */ bool AIRail::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 AIObject::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 AIRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
    00209 {
    00210   EnforcePrecondition(false, ::IsValidTile(tile));
    00211   EnforcePrecondition(false, ::IsValidTile(tile2));
    00212
    00213   return AIObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_WAYPOINT);
    00214 }
    00215
    00216 /* static */ bool AIRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
    00217 {
    00218   EnforcePrecondition(false, ::IsValidTile(tile));
    00219   EnforcePrecondition(false, ::IsValidTile(tile2));
    00220
    00221   return AIObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_STATION);
    00222 }
    00223
    00224 /* static */ uint AIRail::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 AIRail::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 AIObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_BUILD_RAILROAD_TRACK);
    00243 }
    00244
    00245 /* static */ bool AIRail::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 AIObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_REMOVE_RAILROAD_TRACK);
    00253 }
    00254
    00255 /* static */ bool AIRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
    00256 {
    00257   if (!IsRailTile(tile)) return false;
    00258   if (from == to || AIMap::DistanceManhattan(from, tile) != 1 || AIMap::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 = AIRail::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) {
    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) {
    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) {
    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) {
    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 AIRail::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 AIObject::DoCommand(tile, to, p2, CMD_BUILD_RAILROAD_TRACK);
    00353 }
    00354
    00355 /* static */ bool AIRail::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 AIObject::DoCommand(tile, to, p2, CMD_REMOVE_RAILROAD_TRACK);
    00370 }
    00371
    00376 struct AIRailSignalData {
    00377   Track track;
    00378   Trackdir trackdir;
    00379   uint signal_cycles;
    00380 };
    00381
    00382 static const int NUM_TRACK_DIRECTIONS = 3;
    00383
    00390 static const AIRailSignalData _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 */ AIRail::SignalType AIRail::GetSignalType(TileIndex tile, TileIndex front)
    00399 {
    00400   if (AIMap::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 < AIRail::SIGNALTYPE_NORMAL || signal_type > AIRail::SIGNALTYPE_COMBO_TWOWAY) return false;
    00424   if (signal_type > AIRail::SIGNALTYPE_PBS_ONEWAY && signal_type < AIRail::SIGNALTYPE_NORMAL_TWOWAY) return false;
    00425   return true;
    00426 }
    00427
    00428 /* static */ bool AIRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
    00429 {
    00430   EnforcePrecondition(false, AIMap::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 AIObject::DoCommand(tile, p1, 0, CMD_BUILD_SIGNALS);
    00455 }
    00456
    00457 /* static */ bool AIRail::RemoveSignal(TileIndex tile, TileIndex front)
    00458 {
    00459   EnforcePrecondition(false, AIMap::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 AIObject::DoCommand(tile, track, 0, CMD_REMOVE_SIGNALS);
    00473 }
    00474
    00475 /* static */ Money AIRail::GetBuildCost(RailType railtype, BuildType build_type)
    00476 {
    00477   if (!AIRail::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 AIRail::GetMaxSpeed(RailType railtype)
    00490 {
    00491   if (!AIRail::IsRailTypeAvailable(railtype)) return -1;
    00492
    00493   return ::GetRailTypeInfo((::RailType)railtype)->max_speed;
    00494 }