Fix #10490: Allow ships to exit depots if another is not moving at the exit point...
[openttd-github.git] / src / script / api / script_rail.cpp
blob92188c2ab77b0c032dd188110c50ec8ebda1a1e6
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file script_rail.cpp Implementation of ScriptRail. */
10 #include "../../stdafx.h"
11 #include "script_rail.hpp"
12 #include "script_map.hpp"
13 #include "script_station.hpp"
14 #include "script_industrytype.hpp"
15 #include "script_cargo.hpp"
16 #include "../../debug.h"
17 #include "../../station_base.h"
18 #include "../../newgrf_generic.h"
19 #include "../../newgrf_station.h"
20 #include "../../strings_func.h"
21 #include "../../rail_cmd.h"
22 #include "../../station_cmd.h"
23 #include "../../waypoint_cmd.h"
25 #include "../../safeguards.h"
27 /* static */ std::optional<std::string> ScriptRail::GetName(RailType rail_type)
29 if (!IsRailTypeAvailable(rail_type)) return std::nullopt;
31 return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text);
34 /* static */ bool ScriptRail::IsRailTile(TileIndex tile)
36 if (!::IsValidTile(tile)) return false;
38 return (::IsTileType(tile, MP_RAILWAY) && !::IsRailDepot(tile)) ||
39 (::HasStationTileRail(tile) && !::IsStationTileBlocked(tile)) || ::IsLevelCrossingTile(tile);
42 /* static */ bool ScriptRail::IsLevelCrossingTile(TileIndex tile)
44 if (!::IsValidTile(tile)) return false;
46 return ::IsLevelCrossingTile(tile);
49 /* static */ bool ScriptRail::IsRailDepotTile(TileIndex tile)
51 if (!::IsValidTile(tile)) return false;
53 return ::IsRailDepotTile(tile);
56 /* static */ bool ScriptRail::IsRailStationTile(TileIndex tile)
58 if (!::IsValidTile(tile)) return false;
60 return ::IsRailStationTile(tile);
63 /* static */ bool ScriptRail::IsRailWaypointTile(TileIndex tile)
65 if (!::IsValidTile(tile)) return false;
67 return ::IsRailWaypointTile(tile);
70 /* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type)
72 EnforceDeityOrCompanyModeValid(false);
73 if ((::RailType)rail_type >= RAILTYPE_END) return false;
75 return ScriptCompanyMode::IsDeity() || ::HasRailTypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type);
78 /* static */ ScriptRail::RailType ScriptRail::GetCurrentRailType()
80 return (RailType)ScriptObject::GetRailType();
83 /* static */ void ScriptRail::SetCurrentRailType(RailType rail_type)
85 if (!IsRailTypeAvailable(rail_type)) return;
87 ScriptObject::SetRailType((::RailType)rail_type);
90 /* static */ bool ScriptRail::TrainCanRunOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
92 if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
93 if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
95 return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
98 /* static */ bool ScriptRail::TrainHasPowerOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
100 if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
101 if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
103 return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
106 /* static */ ScriptRail::RailType ScriptRail::GetRailType(TileIndex tile)
108 if (!ScriptTile::HasTransportType(tile, ScriptTile::TRANSPORT_RAIL)) return RAILTYPE_INVALID;
110 return (RailType)::GetRailType(tile);
113 /* static */ bool ScriptRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to)
115 EnforceCompanyModeValid(false);
116 EnforcePrecondition(false, ::IsValidTile(start_tile));
117 EnforcePrecondition(false, ::IsValidTile(end_tile));
118 EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
120 return ScriptObject::Command<CMD_CONVERT_RAIL>::Do(start_tile, end_tile, (::RailType)convert_to, false);
123 /* static */ TileIndex ScriptRail::GetRailDepotFrontTile(TileIndex depot)
125 if (!IsRailDepotTile(depot)) return INVALID_TILE;
127 return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot));
130 /* static */ ScriptRail::RailTrack ScriptRail::GetRailStationDirection(TileIndex tile)
132 if (!IsRailStationTile(tile)) return RAILTRACK_INVALID;
134 return (RailTrack)::GetRailStationTrackBits(tile);
137 /* static */ bool ScriptRail::BuildRailDepot(TileIndex tile, TileIndex front)
139 EnforceCompanyModeValid(false);
140 EnforcePrecondition(false, tile != front);
141 EnforcePrecondition(false, ::IsValidTile(tile));
142 EnforcePrecondition(false, ::IsValidTile(front));
143 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
144 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
146 DiagDirection entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? DIAGDIR_SE : DIAGDIR_NW) : (::TileX(tile) < ::TileX(front) ? DIAGDIR_SW : DIAGDIR_NE);
148 return ScriptObject::Command<CMD_BUILD_TRAIN_DEPOT>::Do(tile, (::RailType)ScriptObject::GetRailType(), entrance_dir);
151 /* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id)
153 EnforceCompanyModeValid(false);
154 EnforcePrecondition(false, ::IsValidTile(tile));
155 EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
156 EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
157 EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
158 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
159 EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
161 bool adjacent = station_id != ScriptStation::STATION_JOIN_ADJACENT;
162 return ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), direction == RAILTRACK_NW_SE ? AXIS_Y : AXIS_X, num_platforms, platform_length, STAT_CLASS_DFLT, 0, ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION, adjacent);
165 /* static */ bool ScriptRail::BuildNewGRFRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, SQInteger distance, bool source_station)
167 EnforceCompanyModeValid(false);
168 EnforcePrecondition(false, ::IsValidTile(tile));
169 EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
170 EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
171 EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
172 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
173 EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
174 EnforcePrecondition(false, ScriptCargo::IsValidCargo(cargo_id));
175 EnforcePrecondition(false, source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry));
176 EnforcePrecondition(false, goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry));
178 const GRFFile *file;
179 uint16_t res = GetAiPurchaseCallbackResult(
180 GSF_STATIONS,
181 cargo_id,
183 source_industry,
184 goal_industry,
185 ClampTo<uint8_t>(distance / 2),
186 AICE_STATION_GET_STATION_ID,
187 source_station ? 0 : 1,
188 std::min<SQInteger>(15u, num_platforms) << 4 | std::min<SQInteger>(15u, platform_length),
189 &file
192 Axis axis = direction == RAILTRACK_NW_SE ? AXIS_Y : AXIS_X;
193 bool adjacent = station_id != ScriptStation::STATION_JOIN_ADJACENT;
194 StationID to_join = ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION;
195 if (res != CALLBACK_FAILED) {
196 int index = 0;
197 const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index);
198 if (spec == nullptr) {
199 Debug(grf, 1, "{} returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
200 } else {
201 /* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */
202 if (ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), axis, num_platforms, platform_length, spec->cls_id, index, to_join, adjacent)) return true;
206 return ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), axis, num_platforms, platform_length, STAT_CLASS_DFLT, 0, to_join, adjacent);
209 /* static */ bool ScriptRail::BuildRailWaypoint(TileIndex tile)
211 EnforceCompanyModeValid(false);
212 EnforcePrecondition(false, ::IsValidTile(tile));
213 EnforcePrecondition(false, IsRailTile(tile));
214 EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE);
215 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
217 return ScriptObject::Command<CMD_BUILD_RAIL_WAYPOINT>::Do(tile, GetRailTracks(tile) == RAILTRACK_NE_SW ? AXIS_X : AXIS_Y, 1, 1, STAT_CLASS_WAYP, 0, INVALID_STATION, false);
220 /* static */ bool ScriptRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
222 EnforceCompanyModeValid(false);
223 EnforcePrecondition(false, ::IsValidTile(tile));
224 EnforcePrecondition(false, ::IsValidTile(tile2));
226 return ScriptObject::Command<CMD_REMOVE_FROM_RAIL_WAYPOINT>::Do(tile, tile2, keep_rail);
229 /* static */ bool ScriptRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
231 EnforceCompanyModeValid(false);
232 EnforcePrecondition(false, ::IsValidTile(tile));
233 EnforcePrecondition(false, ::IsValidTile(tile2));
235 return ScriptObject::Command<CMD_REMOVE_FROM_RAIL_STATION>::Do(tile, tile2, keep_rail);
238 /* static */ uint ScriptRail::GetRailTracks(TileIndex tile)
240 if (!IsRailTile(tile)) return RAILTRACK_INVALID;
242 if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
243 if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile);
244 if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE;
245 return ::GetTrackBits(tile);
248 /* static */ bool ScriptRail::BuildRailTrack(TileIndex tile, RailTrack rail_track)
250 EnforceCompanyModeValid(false);
251 EnforcePrecondition(false, ::IsValidTile(tile));
252 EnforcePrecondition(false, rail_track != 0);
253 EnforcePrecondition(false, (static_cast<uint>(rail_track) & ~static_cast<uint>(::TRACK_BIT_ALL)) == 0);
254 EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
255 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
257 return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(tile, tile, (::RailType)GetCurrentRailType(), FindFirstTrack((::TrackBits)rail_track), false, false);
260 /* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
262 EnforceCompanyModeValid(false);
263 EnforcePrecondition(false, ::IsValidTile(tile));
264 EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile));
265 EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
266 EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
268 return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(tile, tile, FindFirstTrack((::TrackBits)rail_track));
271 /* static */ bool ScriptRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
273 if (!IsRailTile(tile)) return false;
274 if (from == to || ScriptMap::DistanceManhattan(from, tile) != 1 || ScriptMap::DistanceManhattan(tile, to) != 1) return false;
276 if (to < from) ::Swap(from, to);
278 if (tile - from == 1) {
279 if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0;
280 if (to - tile == (int)ScriptMap::GetMapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
281 } else if (tile - from == (int)ScriptMap::GetMapSizeX()) {
282 if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0;
283 if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0;
284 if (to - tile == (int)ScriptMap::GetMapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
285 } else {
286 return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0;
289 NOT_REACHED();
293 * Prepare the second parameter for CmdBuildRailroadTrack and CmdRemoveRailroadTrack. The direction
294 * depends on all three tiles. Sometimes the third tile needs to be adjusted.
296 static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
298 int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile)));
299 Track track = TRACK_BEGIN;
300 if (::TileY(from) == ::TileY(*to)) {
301 track = TRACK_X;
302 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
303 } else if (::TileX(from) == ::TileX(*to)) {
304 track = TRACK_Y;
305 *to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
306 } else if (::TileY(from) < ::TileY(tile)) {
307 if (::TileX(*to) < ::TileX(tile)) {
308 track = TRACK_UPPER;
309 } else {
310 track = TRACK_LEFT;
312 if (diag_offset != 0) {
313 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
314 } else {
315 *to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
317 } else if (::TileY(from) > ::TileY(tile)) {
318 if (::TileX(*to) < ::TileX(tile)) {
319 track = TRACK_RIGHT;
320 } else {
321 track = TRACK_LOWER;
323 if (diag_offset != 0) {
324 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
325 } else {
326 *to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
328 } else if (::TileX(from) < ::TileX(tile)) {
329 if (::TileY(*to) < ::TileY(tile)) {
330 track = TRACK_UPPER;
331 } else {
332 track = TRACK_RIGHT;
334 if (diag_offset == 0) {
335 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
336 } else {
337 *to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
339 } else if (::TileX(from) > ::TileX(tile)) {
340 if (::TileY(*to) < ::TileY(tile)) {
341 track = TRACK_LEFT;
342 } else {
343 track = TRACK_LOWER;
345 if (diag_offset == 0) {
346 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
347 } else {
348 *to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
351 return track;
354 /* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
356 EnforceCompanyModeValid(false);
357 EnforcePrecondition(false, ::IsValidTile(from));
358 EnforcePrecondition(false, ::IsValidTile(tile));
359 EnforcePrecondition(false, ::IsValidTile(to));
360 EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
361 EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
362 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
363 int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
364 EnforcePrecondition(false, diag_offset <= 1 ||
365 (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
366 (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
368 Track track = SimulateDrag(from, tile, &to);
369 return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(to, tile, (::RailType)ScriptRail::GetCurrentRailType(), track, false, true);
372 /* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
374 EnforceCompanyModeValid(false);
375 EnforcePrecondition(false, ::IsValidTile(from));
376 EnforcePrecondition(false, ::IsValidTile(tile));
377 EnforcePrecondition(false, ::IsValidTile(to));
378 EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
379 EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
380 int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
381 EnforcePrecondition(false, diag_offset <= 1 ||
382 (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
383 (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
385 Track track = SimulateDrag(from, tile, &to);
386 return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(to, tile, track);
390 * Contains information about the trackdir that belongs to a track when entering
391 * from a specific direction.
393 struct ScriptRailSignalData {
394 Track track; ///< The track that will be taken to travel.
395 Trackdir trackdir; ///< The Trackdir belonging to that track.
396 uint signal_cycles; ///< How many times the signal should be cycled in order to build it in the correct direction.
399 static const int NUM_TRACK_DIRECTIONS = 3; ///< The number of directions you can go when entering a tile.
402 * List information about the trackdir and number of needed cycles for building signals when
403 * entering a track from a specific direction. The first index is the difference between the
404 * TileIndex of the previous and current tile, where (-)MapSizeX is replaced with -2 / 2 and
405 * 2 it added.
407 static const ScriptRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = {
408 {{TRACK_UPPER, TRACKDIR_UPPER_E, 0}, {TRACK_Y, TRACKDIR_Y_SE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_S, 1}},
409 {{TRACK_RIGHT, TRACKDIR_RIGHT_S, 1}, {TRACK_X, TRACKDIR_X_SW, 1}, {TRACK_UPPER, TRACKDIR_UPPER_W, 1}},
410 {{INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}},
411 {{TRACK_LOWER, TRACKDIR_LOWER_E, 0}, {TRACK_X, TRACKDIR_X_NE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_N, 0}},
412 {{TRACK_RIGHT, TRACKDIR_RIGHT_N, 0}, {TRACK_Y, TRACKDIR_Y_NW, 1}, {TRACK_LOWER, TRACKDIR_LOWER_W, 1}}
415 /* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front)
417 if (ScriptMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE;
418 if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE;
420 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
422 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
423 const Track &track = _possible_trackdirs[data_index][i].track;
424 if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue;
425 if (!HasSignalOnTrack(tile, track)) continue;
426 if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue;
427 SignalType st = (SignalType)::GetSignalType(tile, track);
428 if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY);
429 return st;
432 return SIGNALTYPE_NONE;
436 * Check if signal_type is a valid SignalType.
438 static bool IsValidSignalType(int signal_type)
440 if (signal_type < ScriptRail::SIGNALTYPE_NORMAL || signal_type > ScriptRail::SIGNALTYPE_COMBO_TWOWAY) return false;
441 if (signal_type > ScriptRail::SIGNALTYPE_PBS_ONEWAY && signal_type < ScriptRail::SIGNALTYPE_NORMAL_TWOWAY) return false;
442 return true;
445 /* static */ bool ScriptRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
447 EnforceCompanyModeValid(false);
448 EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
449 EnforcePrecondition(false, ::IsPlainRailTile(tile));
450 EnforcePrecondition(false, ::IsValidSignalType(signal));
452 Track track = INVALID_TRACK;
453 uint signal_cycles = 0;
455 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
456 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
457 const Track &t = _possible_trackdirs[data_index][i].track;
458 if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
459 track = t;
460 signal_cycles = _possible_trackdirs[data_index][i].signal_cycles;
461 break;
463 EnforcePrecondition(false, track != INVALID_TRACK);
465 if (signal < SIGNALTYPE_TWOWAY) {
466 if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++;
467 } else {
468 signal_cycles = 0;
470 ::SignalType sig_type = (::SignalType)(signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal);
472 return ScriptObject::Command<CMD_BUILD_SINGLE_SIGNAL>::Do(tile, track, sig_type, ::SIG_ELECTRIC, false, false, false, ::SIGTYPE_BLOCK, ::SIGTYPE_BLOCK, signal_cycles, 0);
475 /* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front)
477 EnforceCompanyModeValid(false);
478 EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
479 EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE);
481 Track track = INVALID_TRACK;
482 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
483 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
484 const Track &t = _possible_trackdirs[data_index][i].track;
485 if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
486 track = t;
487 break;
489 EnforcePrecondition(false, track != INVALID_TRACK);
491 return ScriptObject::Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(tile, track);
494 /* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type)
496 if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
498 switch (build_type) {
499 case BT_TRACK: return ::RailBuildCost((::RailType)railtype);
500 case BT_SIGNAL: return ::GetPrice(PR_BUILD_SIGNALS, 1, nullptr);
501 case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, nullptr);
502 case BT_STATION: return ::GetPrice(PR_BUILD_STATION_RAIL, 1, nullptr) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, nullptr);
503 case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, nullptr);
504 default: return -1;
508 /* static */ SQInteger ScriptRail::GetMaxSpeed(RailType railtype)
510 if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
512 return ::GetRailTypeInfo((::RailType)railtype)->max_speed;
515 /* static */ SQInteger ScriptRail::GetMaintenanceCostFactor(RailType railtype)
517 if (!ScriptRail::IsRailTypeAvailable(railtype)) return 0;
519 return ::GetRailTypeInfo((::RailType)railtype)->maintenance_multiplier;