1 /* $Id: script_rail.cpp 26279 2014-01-26 14:54:34Z frosch $ */
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/>.
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 << 5);
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 << 5;
180 if (station_id
!= ScriptStation::STATION_JOIN_ADJACENT
) p1
|= (1 << 24);
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
) {
187 const StationSpec
*spec
= StationClass::GetByGrf(file
->grfid
, res
, &index
);
189 DEBUG(grf
, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file
->filename
);
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
) << 5), 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
) << 5, 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;
276 return (GetRailTracks(tile
) & RAILTRACK_SW_SE
) != 0;
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
)));
290 if (::TileY(from
) == ::TileY(*to
)) {
291 p2
|= (TRACK_X
<< 5);
292 *to
-= Clamp((int)::TileX(*to
) - (int)::TileX(tile
), -1, 1);
293 } else if (::TileX(from
) == ::TileX(*to
)) {
294 p2
|= (TRACK_Y
<< 5);
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
<< 5);
300 p2
|= (TRACK_LEFT
<< 5);
302 if (diag_offset
!= 0) {
303 *to
-= Clamp((int)::TileX(*to
) - (int)::TileX(tile
), -1, 1);
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
<< 5);
311 p2
|= (TRACK_LOWER
<< 5);
313 if (diag_offset
!= 0) {
314 *to
-= Clamp((int)::TileX(*to
) - (int)::TileX(tile
), -1, 1);
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
<< 5);
322 p2
|= (TRACK_RIGHT
<< 5);
324 if (diag_offset
== 0) {
325 *to
-= Clamp((int)::TileX(*to
) - (int)::TileX(tile
), -1, 1);
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
<< 5);
333 p2
|= (TRACK_LOWER
<< 5);
335 if (diag_offset
== 0) {
336 *to
-= Clamp((int)::TileX(*to
) - (int)::TileX(tile
), -1, 1);
338 *to
-= ::MapSizeX() * Clamp((int)::TileY(*to
) - (int)::TileY(tile
), -1, 1);
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
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
);
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;
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
;
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;
450 signal_cycles
= _possible_trackdirs
[data_index
][i
].signal_cycles
;
453 EnforcePrecondition(false, track
!= INVALID_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;
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
);
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
;