# ai_rail.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_rail.cpp 15711 2009-03-14 18:16:29Z rubidium $ */
    00002
    00005 #include "ai_rail.hpp"
    00006 #include "ai_map.hpp"
    00007 #include "ai_station.hpp"
    00008 #include "../../debug.h"
    00009 #include "../../station_map.h"
    00010 #include "../../company_func.h"
    00011 #include "../../waypoint.h"
    00012 #include "../../newgrf_generic.h"
    00013 #include "../../newgrf_station.h"
    00014
    00015 /* static */ bool AIRail::IsRailTile(TileIndex tile)
    00016 {
    00017   if (!::IsValidTile(tile)) return false;
    00018
    00019   return (::IsTileType(tile, MP_RAILWAY) && !::IsRailDepot(tile)) ||
    00020       (::IsRailwayStationTile(tile) && !::IsStationTileBlocked(tile)) || ::IsLevelCrossingTile(tile);
    00021 }
    00022
    00023 /* static */ bool AIRail::IsLevelCrossingTile(TileIndex tile)
    00024 {
    00025   if (!::IsValidTile(tile)) return false;
    00026
    00027   return ::IsLevelCrossingTile(tile);
    00028 }
    00029
    00030 /* static */ bool AIRail::IsRailDepotTile(TileIndex tile)
    00031 {
    00032   if (!::IsValidTile(tile)) return false;
    00033
    00034   return ::IsRailDepotTile(tile);
    00035 }
    00036
    00037 /* static */ bool AIRail::IsRailStationTile(TileIndex tile)
    00038 {
    00039   if (!::IsValidTile(tile)) return false;
    00040
    00041   return ::IsRailwayStationTile(tile);
    00042 }
    00043
    00044 /* static */ bool AIRail::IsRailWaypointTile(TileIndex tile)
    00045 {
    00046   if (!::IsValidTile(tile)) return false;
    00047
    00048   return ::IsTileType(tile, MP_RAILWAY) && ::IsRailWaypointTile(tile);
    00049 }
    00050
    00051 /* static */ bool AIRail::IsRailTypeAvailable(RailType rail_type)
    00052 {
    00053   if ((::RailType)rail_type < RAILTYPE_BEGIN || (::RailType)rail_type >= RAILTYPE_END) return false;
    00054
    00055   return ::HasRailtypeAvail(_current_company, (::RailType)rail_type);
    00056 }
    00057
    00058 /* static */ AIRail::RailType AIRail::GetCurrentRailType()
    00059 {
    00060   return (RailType)AIObject::GetRailType();
    00061 }
    00062
    00063 /* static */ void AIRail::SetCurrentRailType(RailType rail_type)
    00064 {
    00065   if (!IsRailTypeAvailable(rail_type)) return;
    00066
    00067   AIObject::SetRailType((::RailType)rail_type);
    00068 }
    00069
    00070 /* static */ bool AIRail::TrainCanRunOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type)
    00071 {
    00072   if (!AIRail::IsRailTypeAvailable(engine_rail_type)) return false;
    00073   if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
    00074
    00075   return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
    00076 }
    00077
    00078 /* static */ bool AIRail::TrainHasPowerOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type)
    00079 {\
    00080   if (!AIRail::IsRailTypeAvailable(engine_rail_type)) return false;
    00081   if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
    00082
    00083   return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
    00084 }
    00085
    00086 /* static */ AIRail::RailType AIRail::GetRailType(TileIndex tile)
    00087 {
    00088   if (!AITile::HasTransportType(tile, AITile::TRANSPORT_RAIL)) return RAILTYPE_INVALID;
    00089
    00090   return (RailType)::GetRailType(tile);
    00091 }
    00092
    00093 /* static */ bool AIRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, AIRail::RailType convert_to)
    00094 {
    00095   EnforcePrecondition(false, ::IsValidTile(start_tile));
    00096   EnforcePrecondition(false, ::IsValidTile(end_tile));
    00097   EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
    00098
    00099   return AIObject::DoCommand(start_tile, end_tile, convert_to, CMD_CONVERT_RAIL);
    00100 }
    00101
    00102 /* static */ TileIndex AIRail::GetRailDepotFrontTile(TileIndex depot)
    00103 {
    00104   if (!IsRailDepotTile(depot)) return INVALID_TILE;
    00105
    00106   return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot));
    00107 }
    00108
    00109 /* static */ AIRail::RailTrack AIRail::GetRailStationDirection(TileIndex tile)
    00110 {
    00111   if (!IsRailStationTile(tile)) return RAILTRACK_INVALID;
    00112
    00113   return (RailTrack)::GetRailStationTrack(tile);
    00114 }
    00115
    00116 /* static */ bool AIRail::BuildRailDepot(TileIndex tile, TileIndex front)
    00117 {
    00118   EnforcePrecondition(false, tile != front);
    00119   EnforcePrecondition(false, ::IsValidTile(tile));
    00120   EnforcePrecondition(false, ::IsValidTile(front));
    00121   EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
    00122   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00123
    00124   uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
    00125
    00126   return AIObject::DoCommand(tile, AIObject::GetRailType(), entrance_dir, CMD_BUILD_TRAIN_DEPOT);
    00127 }
    00128
    00129 /* static */ bool AIRail::BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id)
    00130 {
    00131   EnforcePrecondition(false, ::IsValidTile(tile));
    00132   EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
    00133   EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
    00134   EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
    00135   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00136   EnforcePrecondition(false, station_id == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id));
    00137
    00138   uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
    00139   if (direction == RAILTRACK_NW_SE) p1 |= (1 << 4);
    00140   if (station_id != AIStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
    00141   return AIObject::DoCommand(tile, p1, (AIStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16, CMD_BUILD_RAILROAD_STATION);
    00142 }
    00143
    00144 /* 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)
    00145 {
    00146   EnforcePrecondition(false, ::IsValidTile(tile));
    00147   EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
    00148   EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
    00149   EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
    00150   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00151   EnforcePrecondition(false, station_id == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id));
    00152
    00153   uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
    00154   if (direction == RAILTRACK_NW_SE) p1 |= 1 << 4;
    00155   if (station_id != AIStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
    00156
    00157   const GRFFile *file;
    00158   uint16 res = GetAiPurchaseCallbackResult(GSF_STATION, 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);
    00159   uint32 p2 = (AIStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16;
    00160   if (res != CALLBACK_FAILED) {
    00161     int index = 0;
    00162     const StationSpec *spec = GetCustomStationSpecByGrf(file->grfid, res, &index);
    00163     if (spec == NULL) {
    00164       DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
    00165     } else {
    00166       p2 |= spec->sclass | index << 8;
    00167     }
    00168
    00169   }
    00170   return AIObject::DoCommand(tile, p1, p2, CMD_BUILD_RAILROAD_STATION);
    00171 }
    00172
    00173 /* static */ bool AIRail::BuildRailWaypoint(TileIndex tile)
    00174 {
    00175   EnforcePrecondition(false, ::IsValidTile(tile));
    00176   EnforcePrecondition(false, IsRailTile(tile));
    00177   EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE);
    00178   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00179
    00180   return AIObject::DoCommand(tile, 0, 0, CMD_BUILD_TRAIN_WAYPOINT);
    00181 }
    00182
    00183 /* static */ bool AIRail::RemoveRailWaypoint(TileIndex tile)
    00184 {
    00185   EnforcePrecondition(false, ::IsValidTile(tile));
    00186   EnforcePrecondition(false, IsRailWaypointTile(tile));
    00187
    00188   return AIObject::DoCommand(tile, 0, 0, CMD_REMOVE_TRAIN_WAYPOINT);
    00189 }
    00190
    00191 /* static */ bool AIRail::RemoveRailStationTileRect(TileIndex tile, TileIndex tile2)
    00192 {
    00193   EnforcePrecondition(false, ::IsValidTile(tile));
    00194   EnforcePrecondition(false, ::IsValidTile(tile2));
    00195
    00196   return AIObject::DoCommand(tile, tile2, 0, CMD_REMOVE_FROM_RAILROAD_STATION);
    00197 }
    00198
    00199 /* static */ uint AIRail::GetRailTracks(TileIndex tile)
    00200 {
    00201   if (!IsRailTile(tile)) return RAILTRACK_INVALID;
    00202
    00203   if (IsRailWaypointTile(tile)) return ::GetRailWaypointBits(tile);
    00204   if (IsRailStationTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
    00205   if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile);
    00206   return ::GetTrackBits(tile);
    00207 }
    00208
    00209 /* static */ bool AIRail::BuildRailTrack(TileIndex tile, RailTrack rail_track)
    00210 {
    00211   EnforcePrecondition(false, ::IsValidTile(tile));
    00212   EnforcePrecondition(false, rail_track != 0);
    00213   EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0);
    00214   EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
    00215   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00216
    00217   return AIObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_BUILD_RAILROAD_TRACK);
    00218 }
    00219
    00220 /* static */ bool AIRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
    00221 {
    00222   EnforcePrecondition(false, ::IsValidTile(tile));
    00223   EnforcePrecondition(false, ::IsTileType(tile, MP_RAILWAY) && ::IsPlainRailTile(tile));
    00224   EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
    00225   EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
    00226
    00227   return AIObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_REMOVE_RAILROAD_TRACK);
    00228 }
    00229
    00230 /* static */ bool AIRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
    00231 {
    00232   if (!IsRailTile(tile)) return false;
    00233   if (from == to || AIMap::DistanceManhattan(from, tile) != 1 || AIMap::DistanceManhattan(tile, to) != 1) return false;
    00234
    00235   if (to < from) ::Swap(from, to);
    00236
    00237   if (tile - from == 1) {
    00238     if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0;
    00239     if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
    00240   } else if (tile - from == ::MapSizeX()) {
    00241     if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0;
    00242     if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0;
    00243     if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
    00244   } else {
    00245     return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0;
    00246   }
    00247
    00248   NOT_REACHED();
    00249 }
    00250
    00255 static uint32 SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
    00256 {
    00257   int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile)));
    00258   uint32 p2 = AIRail::GetCurrentRailType();
    00259   if (::TileY(from) == ::TileY(*to)) {
    00260     p2 |= (TRACK_X << 4);
    00261     *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
    00262   } else if (::TileX(from) == ::TileX(*to)) {
    00263     p2 |= (TRACK_Y << 4);
    00264     *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
    00265   } else if (::TileY(from) < ::TileY(tile)) {
    00266     if (::TileX(*to) < ::TileX(tile)) {
    00267       p2 |= (TRACK_UPPER << 4);
    00268     } else {
    00269       p2 |= (TRACK_LEFT << 4);
    00270     }
    00271     if (diag_offset) {
    00272       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
    00273     } else {
    00274       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
    00275     }
    00276   } else if (::TileY(from) > ::TileY(tile)) {
    00277     if (::TileX(*to) < ::TileX(tile)) {
    00278       p2 |= (TRACK_RIGHT << 4);
    00279     } else {
    00280       p2 |= (TRACK_LOWER << 4);
    00281     }
    00282     if (diag_offset) {
    00283       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
    00284     } else {
    00285       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
    00286     }
    00287   } else if (::TileX(from) < ::TileX(tile)) {
    00288     if (::TileY(*to) < ::TileY(tile)) {
    00289       p2 |= (TRACK_UPPER << 4);
    00290     } else {
    00291       p2 |= (TRACK_RIGHT << 4);
    00292     }
    00293     if (!diag_offset) {
    00294       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
    00295     } else {
    00296       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
    00297     }
    00298   } else if (::TileX(from) > ::TileX(tile)) {
    00299     if (::TileY(*to) < ::TileY(tile)) {
    00300       p2 |= (TRACK_LEFT << 4);
    00301     } else {
    00302       p2 |= (TRACK_LOWER << 4);
    00303     }
    00304     if (!diag_offset) {
    00305       *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
    00306     } else {
    00307       *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
    00308     }
    00309   }
    00310   return p2;
    00311 }
    00312
    00313 /* static */ bool AIRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
    00314 {
    00315   EnforcePrecondition(false, ::IsValidTile(from));
    00316   EnforcePrecondition(false, ::IsValidTile(tile));
    00317   EnforcePrecondition(false, ::IsValidTile(to));
    00318   EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
    00319   EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
    00320   EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
    00321   int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
    00322   EnforcePrecondition(false, diag_offset <= 1 ||
    00323       (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
    00324       (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
    00325
    00326   uint32 p2 = SimulateDrag(from, tile, &to);
    00327   return AIObject::DoCommand(tile, to, p2, CMD_BUILD_RAILROAD_TRACK);
    00328 }
    00329
    00330 /* static */ bool AIRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
    00331 {
    00332   EnforcePrecondition(false, ::IsValidTile(from));
    00333   EnforcePrecondition(false, ::IsValidTile(tile));
    00334   EnforcePrecondition(false, ::IsValidTile(to));
    00335   EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
    00336   EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
    00337   int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
    00338   EnforcePrecondition(false, diag_offset <= 1 ||
    00339       (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
    00340       (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
    00341
    00342   if (!IsRailTypeAvailable(GetCurrentRailType())) SetCurrentRailType(GetRailType(tile));
    00343   uint32 p2 = SimulateDrag(from, tile, &to);
    00344   return AIObject::DoCommand(tile, to, p2, CMD_REMOVE_RAILROAD_TRACK);
    00345 }
    00346
    00351 struct AIRailSignalData {
    00352   Track track;
    00353   Trackdir trackdir;
    00354   uint signal_cycles;
    00355 };
    00356
    00357 static const int NUM_TRACK_DIRECTIONS = 3;
    00358
    00365 static const AIRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = {
    00366   {{TRACK_UPPER,   TRACKDIR_UPPER_E, 0}, {TRACK_Y,       TRACKDIR_Y_SE,    0}, {TRACK_LEFT,    TRACKDIR_LEFT_S,  1}},
    00367   {{TRACK_RIGHT,   TRACKDIR_RIGHT_S, 1}, {TRACK_X,       TRACKDIR_X_SW,    1}, {TRACK_UPPER,   TRACKDIR_UPPER_W, 1}},
    00368   {{INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}},
    00369   {{TRACK_LOWER,   TRACKDIR_LOWER_E, 0}, {TRACK_X,       TRACKDIR_X_NE,    0}, {TRACK_LEFT,    TRACKDIR_LEFT_N,  0}},
    00370   {{TRACK_RIGHT,   TRACKDIR_RIGHT_N, 0}, {TRACK_Y,       TRACKDIR_Y_NW,    1}, {TRACK_LOWER,   TRACKDIR_LOWER_W, 1}}
    00371 };
    00372
    00373 /* static */ AIRail::SignalType AIRail::GetSignalType(TileIndex tile, TileIndex front)
    00374 {
    00375   if (AIMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE;
    00376   if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE;
    00377
    00378   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
    00379
    00380   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
    00381     const Track &track = _possible_trackdirs[data_index][i].track;
    00382     if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue;
    00383     if (!HasSignalOnTrack(tile, track)) continue;
    00384     if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue;
    00385     SignalType st = (SignalType)::GetSignalType(tile, track);
    00386     if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY);
    00387     return st;
    00388   }
    00389
    00390   return SIGNALTYPE_NONE;
    00391 }
    00392
    00396 static bool IsValidSignalType(int signal_type)
    00397 {
    00398   if (signal_type < AIRail::SIGNALTYPE_NORMAL || signal_type > AIRail::SIGNALTYPE_COMBO_TWOWAY) return false;
    00399   if (signal_type > AIRail::SIGNALTYPE_PBS_ONEWAY && signal_type < AIRail::SIGNALTYPE_NORMAL_TWOWAY) return false;
    00400   return true;
    00401 }
    00402
    00403 /* static */ bool AIRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
    00404 {
    00405   EnforcePrecondition(false, AIMap::DistanceManhattan(tile, front) == 1)
    00406   EnforcePrecondition(false, ::IsTileType(tile, MP_RAILWAY) && ::IsPlainRailTile(tile));
    00407   EnforcePrecondition(false, ::IsValidSignalType(signal));
    00408
    00409   Track track = INVALID_TRACK;
    00410   uint signal_cycles;
    00411
    00412   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
    00413   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
    00414     const Track &t = _possible_trackdirs[data_index][i].track;
    00415     if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
    00416     track = t;
    00417     signal_cycles = _possible_trackdirs[data_index][i].signal_cycles;
    00418     break;
    00419   }
    00420   EnforcePrecondition(false, track != INVALID_TRACK);
    00421
    00422   uint p1 = track;
    00423   if (signal < SIGNALTYPE_TWOWAY) {
    00424     if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++;
    00425     p1 |= (signal_cycles << 15);
    00426   }
    00427   p1 |= ((signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal) << 5);
    00428
    00429   return AIObject::DoCommand(tile, p1, 0, CMD_BUILD_SIGNALS);
    00430 }
    00431
    00432 /* static */ bool AIRail::RemoveSignal(TileIndex tile, TileIndex front)
    00433 {
    00434   EnforcePrecondition(false, AIMap::DistanceManhattan(tile, front) == 1)
    00435   EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE);
    00436
    00437   Track track = INVALID_TRACK;
    00438   int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
    00439   for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
    00440     const Track &t = _possible_trackdirs[data_index][i].track;
    00441     if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
    00442     track = t;
    00443     break;
    00444   }
    00445   EnforcePrecondition(false, track != INVALID_TRACK);
    00446
    00447   return AIObject::DoCommand(tile, track, 0, CMD_REMOVE_SIGNALS);
    00448 }