(svn r28004) -Update from Eints:
[openttd.git] / src / script / api / script_rail.cpp
blobaf68a3edc813785d94205bba7819d2e3c858afd0
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file script_rail.cpp Implementation of ScriptRail. */
12 #include "../../stdafx.h"
13 #include "script_rail.hpp"
14 #include "script_map.hpp"
15 #include "script_station.hpp"
16 #include "script_industrytype.hpp"
17 #include "script_cargo.hpp"
18 #include "../../debug.h"
19 #include "../../station_base.h"
20 #include "../../newgrf_generic.h"
21 #include "../../newgrf_station.h"
22 #include "../../strings_func.h"
24 #include "../../safeguards.h"
26 /* static */ char *ScriptRail::GetName(RailType rail_type)
28 if (!IsRailTypeAvailable(rail_type)) return NULL;
30 return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text);
33 /* static */ bool ScriptRail::IsRailTile(TileIndex tile)
35 if (!::IsValidTile(tile)) return false;
37 return (::IsTileType(tile, MP_RAILWAY) && !::IsRailDepot(tile)) ||
38 (::HasStationTileRail(tile) && !::IsStationTileBlocked(tile)) || ::IsLevelCrossingTile(tile);
41 /* static */ bool ScriptRail::IsLevelCrossingTile(TileIndex tile)
43 if (!::IsValidTile(tile)) return false;
45 return ::IsLevelCrossingTile(tile);
48 /* static */ bool ScriptRail::IsRailDepotTile(TileIndex tile)
50 if (!::IsValidTile(tile)) return false;
52 return ::IsRailDepotTile(tile);
55 /* static */ bool ScriptRail::IsRailStationTile(TileIndex tile)
57 if (!::IsValidTile(tile)) return false;
59 return ::IsRailStationTile(tile);
62 /* static */ bool ScriptRail::IsRailWaypointTile(TileIndex tile)
64 if (!::IsValidTile(tile)) return false;
66 return ::IsRailWaypointTile(tile);
69 /* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type)
71 if ((::RailType)rail_type < RAILTYPE_BEGIN || (::RailType)rail_type >= RAILTYPE_END) return false;
73 return ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type);
76 /* static */ ScriptRail::RailType ScriptRail::GetCurrentRailType()
78 return (RailType)ScriptObject::GetRailType();
81 /* static */ void ScriptRail::SetCurrentRailType(RailType rail_type)
83 if (!IsRailTypeAvailable(rail_type)) return;
85 ScriptObject::SetRailType((::RailType)rail_type);
88 /* static */ bool ScriptRail::TrainCanRunOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
90 if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
91 if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
93 return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
96 /* static */ bool ScriptRail::TrainHasPowerOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type)
98 if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false;
99 if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
101 return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type);
104 /* static */ ScriptRail::RailType ScriptRail::GetRailType(TileIndex tile)
106 if (!ScriptTile::HasTransportType(tile, ScriptTile::TRANSPORT_RAIL)) return RAILTYPE_INVALID;
108 return (RailType)::GetRailType(tile);
111 /* static */ bool ScriptRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to)
113 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
114 EnforcePrecondition(false, ::IsValidTile(start_tile));
115 EnforcePrecondition(false, ::IsValidTile(end_tile));
116 EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
118 return ScriptObject::DoCommand(start_tile, end_tile, convert_to, CMD_CONVERT_RAIL);
121 /* static */ TileIndex ScriptRail::GetRailDepotFrontTile(TileIndex depot)
123 if (!IsRailDepotTile(depot)) return INVALID_TILE;
125 return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot));
128 /* static */ ScriptRail::RailTrack ScriptRail::GetRailStationDirection(TileIndex tile)
130 if (!IsRailStationTile(tile)) return RAILTRACK_INVALID;
132 return (RailTrack)::GetRailStationTrackBits(tile);
135 /* static */ bool ScriptRail::BuildRailDepot(TileIndex tile, TileIndex front)
137 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
138 EnforcePrecondition(false, tile != front);
139 EnforcePrecondition(false, ::IsValidTile(tile));
140 EnforcePrecondition(false, ::IsValidTile(front));
141 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
142 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
144 uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0);
146 return ScriptObject::DoCommand(tile, ScriptObject::GetRailType(), entrance_dir, CMD_BUILD_TRAIN_DEPOT);
149 /* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id)
151 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
152 EnforcePrecondition(false, ::IsValidTile(tile));
153 EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
154 EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
155 EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF);
156 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
157 EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
159 uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
160 if (direction == RAILTRACK_NW_SE) p1 |= (1 << 4);
161 if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
162 return ScriptObject::DoCommand(tile, p1, (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16, CMD_BUILD_RAIL_STATION);
165 /* 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)
167 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
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 uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8);
179 if (direction == RAILTRACK_NW_SE) p1 |= 1 << 4;
180 if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24);
182 const GRFFile *file;
183 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);
184 uint32 p2 = (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16;
185 if (res != CALLBACK_FAILED) {
186 int index = 0;
187 const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index);
188 if (spec == NULL) {
189 DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
190 } else {
191 /* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */
192 if (ScriptObject::DoCommand(tile, p1, p2 | spec->cls_id | index << 8, CMD_BUILD_RAIL_STATION)) return true;
196 return ScriptObject::DoCommand(tile, p1, p2, CMD_BUILD_RAIL_STATION);
199 /* static */ bool ScriptRail::BuildRailWaypoint(TileIndex tile)
201 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
202 EnforcePrecondition(false, ::IsValidTile(tile));
203 EnforcePrecondition(false, IsRailTile(tile));
204 EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE);
205 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
207 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);
210 /* static */ bool ScriptRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
212 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
213 EnforcePrecondition(false, ::IsValidTile(tile));
214 EnforcePrecondition(false, ::IsValidTile(tile2));
216 return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_WAYPOINT);
219 /* static */ bool ScriptRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
221 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
222 EnforcePrecondition(false, ::IsValidTile(tile));
223 EnforcePrecondition(false, ::IsValidTile(tile2));
225 return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_STATION);
228 /* static */ uint ScriptRail::GetRailTracks(TileIndex tile)
230 if (!IsRailTile(tile)) return RAILTRACK_INVALID;
232 if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
233 if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile);
234 if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE;
235 return ::GetTrackBits(tile);
238 /* static */ bool ScriptRail::BuildRailTrack(TileIndex tile, RailTrack rail_track)
240 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
241 EnforcePrecondition(false, ::IsValidTile(tile));
242 EnforcePrecondition(false, rail_track != 0);
243 EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0);
244 EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
245 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
247 return ScriptObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_BUILD_RAILROAD_TRACK);
250 /* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
252 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
253 EnforcePrecondition(false, ::IsValidTile(tile));
254 EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile));
255 EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
256 EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
258 return ScriptObject::DoCommand(tile, tile, FindFirstTrack((::TrackBits)rail_track) << 4, CMD_REMOVE_RAILROAD_TRACK);
261 /* static */ bool ScriptRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
263 if (!IsRailTile(tile)) return false;
264 if (from == to || ScriptMap::DistanceManhattan(from, tile) != 1 || ScriptMap::DistanceManhattan(tile, to) != 1) return false;
266 if (to < from) ::Swap(from, to);
268 if (tile - from == 1) {
269 if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0;
270 if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
271 } else if (tile - from == ::MapSizeX()) {
272 if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0;
273 if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0;
274 if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
275 } else {
276 return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0;
279 NOT_REACHED();
283 * Prepare the second parameter for CmdBuildRailroadTrack and CmdRemoveRailroadTrack. The direction
284 * depends on all three tiles. Sometimes the third tile needs to be adjusted.
286 static uint32 SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
288 int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile)));
289 uint32 p2 = 0;
290 if (::TileY(from) == ::TileY(*to)) {
291 p2 |= (TRACK_X << 4);
292 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
293 } else if (::TileX(from) == ::TileX(*to)) {
294 p2 |= (TRACK_Y << 4);
295 *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
296 } else if (::TileY(from) < ::TileY(tile)) {
297 if (::TileX(*to) < ::TileX(tile)) {
298 p2 |= (TRACK_UPPER << 4);
299 } else {
300 p2 |= (TRACK_LEFT << 4);
302 if (diag_offset != 0) {
303 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
304 } else {
305 *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
307 } else if (::TileY(from) > ::TileY(tile)) {
308 if (::TileX(*to) < ::TileX(tile)) {
309 p2 |= (TRACK_RIGHT << 4);
310 } else {
311 p2 |= (TRACK_LOWER << 4);
313 if (diag_offset != 0) {
314 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
315 } else {
316 *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
318 } else if (::TileX(from) < ::TileX(tile)) {
319 if (::TileY(*to) < ::TileY(tile)) {
320 p2 |= (TRACK_UPPER << 4);
321 } else {
322 p2 |= (TRACK_RIGHT << 4);
324 if (diag_offset == 0) {
325 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
326 } else {
327 *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
329 } else if (::TileX(from) > ::TileX(tile)) {
330 if (::TileY(*to) < ::TileY(tile)) {
331 p2 |= (TRACK_LEFT << 4);
332 } else {
333 p2 |= (TRACK_LOWER << 4);
335 if (diag_offset == 0) {
336 *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
337 } else {
338 *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
341 return p2;
344 /* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
346 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
347 EnforcePrecondition(false, ::IsValidTile(from));
348 EnforcePrecondition(false, ::IsValidTile(tile));
349 EnforcePrecondition(false, ::IsValidTile(to));
350 EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
351 EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
352 EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
353 int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
354 EnforcePrecondition(false, diag_offset <= 1 ||
355 (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
356 (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
358 uint32 p2 = SimulateDrag(from, tile, &to) | 1 << 8 | ScriptRail::GetCurrentRailType();;
359 return ScriptObject::DoCommand(tile, to, p2, CMD_BUILD_RAILROAD_TRACK);
362 /* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
364 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
365 EnforcePrecondition(false, ::IsValidTile(from));
366 EnforcePrecondition(false, ::IsValidTile(tile));
367 EnforcePrecondition(false, ::IsValidTile(to));
368 EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1);
369 EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
370 int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
371 EnforcePrecondition(false, diag_offset <= 1 ||
372 (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
373 (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
375 uint32 p2 = SimulateDrag(from, tile, &to);
376 return ScriptObject::DoCommand(tile, to, p2, CMD_REMOVE_RAILROAD_TRACK);
380 * Contains information about the trackdir that belongs to a track when entering
381 * from a specific direction.
383 struct ScriptRailSignalData {
384 Track track; ///< The track that will be taken to travel.
385 Trackdir trackdir; ///< The Trackdir belonging to that track.
386 uint signal_cycles; ///< How many times the signal should be cycled in order to build it in the correct direction.
389 static const int NUM_TRACK_DIRECTIONS = 3; ///< The number of directions you can go when entering a tile.
392 * List information about the trackdir and number of needed cycles for building signals when
393 * entering a track from a specific direction. The first index is the difference between the
394 * TileIndex of the previous and current tile, where (-)MapSizeX is replaced with -2 / 2 and
395 * 2 it added.
397 static const ScriptRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = {
398 {{TRACK_UPPER, TRACKDIR_UPPER_E, 0}, {TRACK_Y, TRACKDIR_Y_SE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_S, 1}},
399 {{TRACK_RIGHT, TRACKDIR_RIGHT_S, 1}, {TRACK_X, TRACKDIR_X_SW, 1}, {TRACK_UPPER, TRACKDIR_UPPER_W, 1}},
400 {{INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}},
401 {{TRACK_LOWER, TRACKDIR_LOWER_E, 0}, {TRACK_X, TRACKDIR_X_NE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_N, 0}},
402 {{TRACK_RIGHT, TRACKDIR_RIGHT_N, 0}, {TRACK_Y, TRACKDIR_Y_NW, 1}, {TRACK_LOWER, TRACKDIR_LOWER_W, 1}}
405 /* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front)
407 if (ScriptMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE;
408 if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE;
410 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
412 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
413 const Track &track = _possible_trackdirs[data_index][i].track;
414 if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue;
415 if (!HasSignalOnTrack(tile, track)) continue;
416 if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue;
417 SignalType st = (SignalType)::GetSignalType(tile, track);
418 if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY);
419 return st;
422 return SIGNALTYPE_NONE;
426 * Check if signal_type is a valid SignalType.
428 static bool IsValidSignalType(int signal_type)
430 if (signal_type < ScriptRail::SIGNALTYPE_NORMAL || signal_type > ScriptRail::SIGNALTYPE_COMBO_TWOWAY) return false;
431 if (signal_type > ScriptRail::SIGNALTYPE_PBS_ONEWAY && signal_type < ScriptRail::SIGNALTYPE_NORMAL_TWOWAY) return false;
432 return true;
435 /* static */ bool ScriptRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
437 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
438 EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
439 EnforcePrecondition(false, ::IsPlainRailTile(tile));
440 EnforcePrecondition(false, ::IsValidSignalType(signal));
442 Track track = INVALID_TRACK;
443 uint signal_cycles;
445 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
446 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
447 const Track &t = _possible_trackdirs[data_index][i].track;
448 if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
449 track = t;
450 signal_cycles = _possible_trackdirs[data_index][i].signal_cycles;
451 break;
453 EnforcePrecondition(false, track != INVALID_TRACK);
455 uint p1 = track;
456 if (signal < SIGNALTYPE_TWOWAY) {
457 if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++;
458 p1 |= (signal_cycles << 15);
460 p1 |= ((signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal) << 5);
462 return ScriptObject::DoCommand(tile, p1, 0, CMD_BUILD_SIGNALS);
465 /* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front)
467 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
468 EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
469 EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE);
471 Track track = INVALID_TRACK;
472 int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
473 for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
474 const Track &t = _possible_trackdirs[data_index][i].track;
475 if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
476 track = t;
477 break;
479 EnforcePrecondition(false, track != INVALID_TRACK);
481 return ScriptObject::DoCommand(tile, track, 0, CMD_REMOVE_SIGNALS);
484 /* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type)
486 if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
488 switch (build_type) {
489 case BT_TRACK: return ::RailBuildCost((::RailType)railtype);
490 case BT_SIGNAL: return ::GetPrice(PR_BUILD_SIGNALS, 1, NULL);
491 case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, NULL);
492 case BT_STATION: return ::GetPrice(PR_BUILD_STATION_RAIL, 1, NULL) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, NULL);
493 case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, NULL);
494 default: return -1;
498 /* static */ int32 ScriptRail::GetMaxSpeed(RailType railtype)
500 if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
502 return ::GetRailTypeInfo((::RailType)railtype)->max_speed;
505 /* static */ uint16 ScriptRail::GetMaintenanceCostFactor(RailType railtype)
507 if (!ScriptRail::IsRailTypeAvailable(railtype)) return 0;
509 return ::GetRailTypeInfo((::RailType)railtype)->maintenance_multiplier;