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