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 rail_map.h Hides the direct accesses to the map array with map accessors */
15 #include "rail_type.h"
16 #include "depot_type.h"
17 #include "signal_func.h"
18 #include "track_func.h"
20 #include "signal_type.h"
23 /** Different types of Rail-related tiles */
25 RAIL_TILE_NORMAL
= 0, ///< Normal rail tile without signals
26 RAIL_TILE_SIGNALS
= 1, ///< Normal rail tile with signals
27 RAIL_TILE_DEPOT
= 3, ///< Depot (one entrance)
31 * Returns the RailTileType (normal with or without signals,
33 * @param t the tile to get the information from
34 * @pre IsTileType(t, MP_RAILWAY)
35 * @return the RailTileType
37 static inline RailTileType
GetRailTileType(TileIndex t
)
39 assert(IsTileType(t
, MP_RAILWAY
));
40 return (RailTileType
)GB(_m
[t
].m5
, 6, 2);
44 * Returns whether this is plain rails, with or without signals. Iow, if this
45 * tiles RailTileType is RAIL_TILE_NORMAL or RAIL_TILE_SIGNALS.
46 * @param t the tile to get the information from
47 * @pre IsTileType(t, MP_RAILWAY)
48 * @return true if and only if the tile is normal rail (with or without signals)
50 static inline bool IsPlainRail(TileIndex t
)
52 RailTileType rtt
= GetRailTileType(t
);
53 return rtt
== RAIL_TILE_NORMAL
|| rtt
== RAIL_TILE_SIGNALS
;
57 * Checks whether the tile is a rail tile or rail tile with signals.
58 * @param t the tile to get the information from
59 * @return true if and only if the tile is normal rail (with or without signals)
61 static inline bool IsPlainRailTile(TileIndex t
)
63 return IsTileType(t
, MP_RAILWAY
) && IsPlainRail(t
);
68 * Checks if a rail tile has signals.
69 * @param t the tile to get the information from
70 * @pre IsTileType(t, MP_RAILWAY)
71 * @return true if and only if the tile has signals
73 static inline bool HasSignals(TileIndex t
)
75 return GetRailTileType(t
) == RAIL_TILE_SIGNALS
;
79 * Add/remove the 'has signal' bit from the RailTileType
80 * @param tile the tile to add/remove the signals to/from
81 * @param signals whether the rail tile should have signals or not
82 * @pre IsPlainRailTile(tile)
84 static inline void SetHasSignals(TileIndex tile
, bool signals
)
86 assert(IsPlainRailTile(tile
));
87 SB(_m
[tile
].m5
, 6, 1, signals
);
91 * Is this rail tile a rail depot?
92 * @param t the tile to get the information from
93 * @pre IsTileType(t, MP_RAILWAY)
94 * @return true if and only if the tile is a rail depot
96 static inline bool IsRailDepot(TileIndex t
)
98 return GetRailTileType(t
) == RAIL_TILE_DEPOT
;
102 * Is this tile rail tile and a rail depot?
103 * @param t the tile to get the information from
104 * @return true if and only if the tile is a rail depot
106 static inline bool IsRailDepotTile(TileIndex t
)
108 return IsTileType(t
, MP_RAILWAY
) && IsRailDepot(t
);
112 * Gets the rail type of the given tile
113 * @param t the tile to get the rail type from
114 * @return the rail type of the tile
116 static inline RailType
GetRailType(TileIndex t
)
118 return (RailType
)GB(_m
[t
].m3
, 0, 4);
122 * Sets the rail type of the given tile
123 * @param t the tile to set the rail type of
124 * @param r the new rail type for the tile
126 static inline void SetRailType(TileIndex t
, RailType r
)
128 SB(_m
[t
].m3
, 0, 4, r
);
133 * Gets the track bits of the given tile
134 * @param tile the tile to get the track bits from
135 * @return the track bits of the tile
137 static inline TrackBits
GetTrackBits(TileIndex tile
)
139 assert(IsPlainRailTile(tile
));
140 return (TrackBits
)GB(_m
[tile
].m5
, 0, 6);
144 * Sets the track bits of the given tile
145 * @param t the tile to set the track bits of
146 * @param b the new track bits for the tile
148 static inline void SetTrackBits(TileIndex t
, TrackBits b
)
150 assert(IsPlainRailTile(t
));
151 SB(_m
[t
].m5
, 0, 6, b
);
155 * Returns whether the given track is present on the given tile.
156 * @param tile the tile to check the track presence of
157 * @param track the track to search for on the tile
158 * @pre IsPlainRailTile(tile)
159 * @return true if and only if the given track exists on the tile
161 static inline bool HasTrack(TileIndex tile
, Track track
)
163 return HasBit(GetTrackBits(tile
), track
);
167 * Returns the direction the depot is facing to
168 * @param t the tile to get the depot facing from
169 * @pre IsRailDepotTile(t)
170 * @return the direction the depot is facing
172 static inline DiagDirection
GetRailDepotDirection(TileIndex t
)
174 return (DiagDirection
)GB(_m
[t
].m5
, 0, 2);
178 * Returns the track of a depot, ignoring direction
179 * @pre IsRailDepotTile(t)
180 * @param t the tile to get the depot track from
181 * @return the track of the depot
183 static inline Track
GetRailDepotTrack(TileIndex t
)
185 return DiagDirToDiagTrack(GetRailDepotDirection(t
));
190 * Returns the reserved track bits of the tile
191 * @pre IsPlainRailTile(t)
192 * @param t the tile to query
193 * @return the track bits
195 static inline TrackBits
GetRailReservationTrackBits(TileIndex t
)
197 assert(IsPlainRailTile(t
));
198 byte track_b
= GB(_m
[t
].m2
, 8, 3);
199 Track track
= (Track
)(track_b
- 1); // map array saves Track+1
200 if (track_b
== 0) return TRACK_BIT_NONE
;
201 return (TrackBits
)(TrackToTrackBits(track
) | (HasBit(_m
[t
].m2
, 11) ? TrackToTrackBits(TrackToOppositeTrack(track
)) : 0));
205 * Sets the reserved track bits of the tile
206 * @pre IsPlainRailTile(t) && !TracksOverlap(b)
207 * @param t the tile to change
208 * @param b the track bits
210 static inline void SetTrackReservation(TileIndex t
, TrackBits b
)
212 assert(IsPlainRailTile(t
));
213 assert(b
!= INVALID_TRACK_BIT
);
214 assert(!TracksOverlap(b
));
215 Track track
= RemoveFirstTrack(&b
);
216 SB(_m
[t
].m2
, 8, 3, track
== INVALID_TRACK
? 0 : track
+ 1);
217 SB(_m
[t
].m2
, 11, 1, (byte
)(b
!= TRACK_BIT_NONE
));
221 * Try to reserve a specific track on a tile
222 * @pre IsPlainRailTile(t) && HasTrack(tile, t)
223 * @param tile the tile
224 * @param t the rack to reserve
225 * @return true if successful
227 static inline bool TryReserveTrack(TileIndex tile
, Track t
)
229 assert(HasTrack(tile
, t
));
230 TrackBits bits
= TrackToTrackBits(t
);
231 TrackBits res
= GetRailReservationTrackBits(tile
);
232 if ((res
& bits
) != TRACK_BIT_NONE
) return false; // already reserved
234 if (TracksOverlap(res
)) return false; // crossing reservation present
235 SetTrackReservation(tile
, res
);
240 * Lift the reservation of a specific track on a tile
241 * @pre IsPlainRailTile(t) && HasTrack(tile, t)
242 * @param tile the tile
243 * @param t the track to free
245 static inline void UnreserveTrack(TileIndex tile
, Track t
)
247 assert(HasTrack(tile
, t
));
248 TrackBits res
= GetRailReservationTrackBits(tile
);
249 res
&= ~TrackToTrackBits(t
);
250 SetTrackReservation(tile
, res
);
254 * Get the reservation state of the depot
255 * @pre IsRailDepot(t)
256 * @param t the depot tile
257 * @return reservation state
259 static inline bool HasDepotReservation(TileIndex t
)
261 assert(IsRailDepot(t
));
262 return HasBit(_m
[t
].m5
, 4);
266 * Set the reservation state of the depot
267 * @pre IsRailDepot(t)
268 * @param t the depot tile
269 * @param b the reservation state
271 static inline void SetDepotReservation(TileIndex t
, bool b
)
273 assert(IsRailDepot(t
));
274 SB(_m
[t
].m5
, 4, 1, (byte
)b
);
278 * Get the reserved track bits for a depot
279 * @pre IsRailDepot(t)
281 * @return reserved track bits
283 static inline TrackBits
GetDepotReservationTrackBits(TileIndex t
)
285 return HasDepotReservation(t
) ? TrackToTrackBits(GetRailDepotTrack(t
)) : TRACK_BIT_NONE
;
289 static inline bool IsPbsSignal(SignalType s
)
291 return s
== SIGTYPE_PBS
|| s
== SIGTYPE_PBS_ONEWAY
;
294 static inline SignalType
GetSignalType(TileIndex t
, Track track
)
296 assert(GetRailTileType(t
) == RAIL_TILE_SIGNALS
);
297 byte pos
= (track
== TRACK_LOWER
|| track
== TRACK_RIGHT
) ? 4 : 0;
298 return (SignalType
)GB(_m
[t
].m2
, pos
, 3);
301 static inline void SetSignalType(TileIndex t
, Track track
, SignalType s
)
303 assert(GetRailTileType(t
) == RAIL_TILE_SIGNALS
);
304 byte pos
= (track
== TRACK_LOWER
|| track
== TRACK_RIGHT
) ? 4 : 0;
305 SB(_m
[t
].m2
, pos
, 3, s
);
306 if (track
== INVALID_TRACK
) SB(_m
[t
].m2
, 4, 3, s
);
309 static inline bool IsPresignalEntry(TileIndex t
, Track track
)
311 return GetSignalType(t
, track
) == SIGTYPE_ENTRY
|| GetSignalType(t
, track
) == SIGTYPE_COMBO
;
314 static inline bool IsPresignalExit(TileIndex t
, Track track
)
316 return GetSignalType(t
, track
) == SIGTYPE_EXIT
|| GetSignalType(t
, track
) == SIGTYPE_COMBO
;
319 /** One-way signals can't be passed the 'wrong' way. */
320 static inline bool IsOnewaySignal(TileIndex t
, Track track
)
322 return GetSignalType(t
, track
) != SIGTYPE_PBS
;
325 static inline void CycleSignalSide(TileIndex t
, Track track
)
328 byte pos
= (track
== TRACK_LOWER
|| track
== TRACK_RIGHT
) ? 4 : 6;
330 sig
= GB(_m
[t
].m3
, pos
, 2);
331 if (--sig
== 0) sig
= IsPbsSignal(GetSignalType(t
, track
)) ? 2 : 3;
332 SB(_m
[t
].m3
, pos
, 2, sig
);
335 static inline SignalVariant
GetSignalVariant(TileIndex t
, Track track
)
337 byte pos
= (track
== TRACK_LOWER
|| track
== TRACK_RIGHT
) ? 7 : 3;
338 return (SignalVariant
)GB(_m
[t
].m2
, pos
, 1);
341 static inline void SetSignalVariant(TileIndex t
, Track track
, SignalVariant v
)
343 byte pos
= (track
== TRACK_LOWER
|| track
== TRACK_RIGHT
) ? 7 : 3;
344 SB(_m
[t
].m2
, pos
, 1, v
);
345 if (track
== INVALID_TRACK
) SB(_m
[t
].m2
, 7, 1, v
);
349 * Set the states of the signals (Along/AgainstTrackDir)
350 * @param tile the tile to set the states for
351 * @param state the new state
353 static inline void SetSignalStates(TileIndex tile
, uint state
)
355 SB(_m
[tile
].m4
, 4, 4, state
);
359 * Set the states of the signals (Along/AgainstTrackDir)
360 * @param tile the tile to set the states for
361 * @return the state of the signals
363 static inline uint
GetSignalStates(TileIndex tile
)
365 return GB(_m
[tile
].m4
, 4, 4);
369 * Get the state of a single signal
370 * @param t the tile to get the signal state for
371 * @param signalbit the signal
372 * @return the state of the signal
374 static inline SignalState
GetSingleSignalState(TileIndex t
, byte signalbit
)
376 return (SignalState
)HasBit(GetSignalStates(t
), signalbit
);
380 * Set whether the given signals are present (Along/AgainstTrackDir)
381 * @param tile the tile to set the present signals for
382 * @param signals the signals that have to be present
384 static inline void SetPresentSignals(TileIndex tile
, uint signals
)
386 SB(_m
[tile
].m3
, 4, 4, signals
);
390 * Get whether the given signals are present (Along/AgainstTrackDir)
391 * @param tile the tile to get the present signals for
392 * @return the signals that are present
394 static inline uint
GetPresentSignals(TileIndex tile
)
396 return GB(_m
[tile
].m3
, 4, 4);
400 * Checks whether the given signals is present
401 * @param t the tile to check on
402 * @param signalbit the signal
403 * @return true if and only if the signal is present
405 static inline bool IsSignalPresent(TileIndex t
, byte signalbit
)
407 return HasBit(GetPresentSignals(t
), signalbit
);
411 * Checks for the presence of signals (either way) on the given track on the
414 static inline bool HasSignalOnTrack(TileIndex tile
, Track track
)
416 assert(IsValidTrack(track
));
417 return GetRailTileType(tile
) == RAIL_TILE_SIGNALS
&& (GetPresentSignals(tile
) & SignalOnTrack(track
)) != 0;
421 * Checks for the presence of signals along the given trackdir on the given
424 * Along meaning if you are currently driving on the given trackdir, this is
425 * the signal that is facing us (for which we stop when it's red).
427 static inline bool HasSignalOnTrackdir(TileIndex tile
, Trackdir trackdir
)
429 assert (IsValidTrackdir(trackdir
));
430 return GetRailTileType(tile
) == RAIL_TILE_SIGNALS
&& GetPresentSignals(tile
) & SignalAlongTrackdir(trackdir
);
434 * Gets the state of the signal along the given trackdir.
436 * Along meaning if you are currently driving on the given trackdir, this is
437 * the signal that is facing us (for which we stop when it's red).
439 static inline SignalState
GetSignalStateByTrackdir(TileIndex tile
, Trackdir trackdir
)
441 assert(IsValidTrackdir(trackdir
));
442 assert(HasSignalOnTrack(tile
, TrackdirToTrack(trackdir
)));
443 return GetSignalStates(tile
) & SignalAlongTrackdir(trackdir
) ?
444 SIGNAL_STATE_GREEN
: SIGNAL_STATE_RED
;
448 * Sets the state of the signal along the given trackdir.
450 static inline void SetSignalStateByTrackdir(TileIndex tile
, Trackdir trackdir
, SignalState state
)
452 if (state
== SIGNAL_STATE_GREEN
) { // set 1
453 SetSignalStates(tile
, GetSignalStates(tile
) | SignalAlongTrackdir(trackdir
));
455 SetSignalStates(tile
, GetSignalStates(tile
) & ~SignalAlongTrackdir(trackdir
));
460 * Is a pbs signal present along the trackdir?
461 * @param tile the tile to check
462 * @param td the trackdir to check
464 static inline bool HasPbsSignalOnTrackdir(TileIndex tile
, Trackdir td
)
466 return IsTileType(tile
, MP_RAILWAY
) && HasSignalOnTrackdir(tile
, td
) &&
467 IsPbsSignal(GetSignalType(tile
, TrackdirToTrack(td
)));
471 * Is a one-way signal blocking the trackdir? A one-way signal on the
472 * trackdir against will block, but signals on both trackdirs won't.
473 * @param tile the tile to check
474 * @param td the trackdir to check
476 static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile
, Trackdir td
)
478 return IsTileType(tile
, MP_RAILWAY
) && HasSignalOnTrackdir(tile
, ReverseTrackdir(td
)) &&
479 !HasSignalOnTrackdir(tile
, td
) && IsOnewaySignal(tile
, TrackdirToTrack(td
));
483 RailType
GetTileRailType(TileIndex tile
);
485 /** The ground 'under' the rail */
486 enum RailGroundType
{
487 RAIL_GROUND_BARREN
= 0, ///< Nothing (dirt)
488 RAIL_GROUND_GRASS
= 1, ///< Grassy
489 RAIL_GROUND_FENCE_NW
= 2, ///< Grass with a fence at the NW edge
490 RAIL_GROUND_FENCE_SE
= 3, ///< Grass with a fence at the SE edge
491 RAIL_GROUND_FENCE_SENW
= 4, ///< Grass with a fence at the NW and SE edges
492 RAIL_GROUND_FENCE_NE
= 5, ///< Grass with a fence at the NE edge
493 RAIL_GROUND_FENCE_SW
= 6, ///< Grass with a fence at the SW edge
494 RAIL_GROUND_FENCE_NESW
= 7, ///< Grass with a fence at the NE and SW edges
495 RAIL_GROUND_FENCE_VERT1
= 8, ///< Grass with a fence at the eastern side
496 RAIL_GROUND_FENCE_VERT2
= 9, ///< Grass with a fence at the western side
497 RAIL_GROUND_FENCE_HORIZ1
= 10, ///< Grass with a fence at the southern side
498 RAIL_GROUND_FENCE_HORIZ2
= 11, ///< Grass with a fence at the northern side
499 RAIL_GROUND_ICE_DESERT
= 12, ///< Icy or sandy
500 RAIL_GROUND_WATER
= 13, ///< Grass with a fence and shore or water on the free halftile
501 RAIL_GROUND_HALF_SNOW
= 14, ///< Snow only on higher part of slope (steep or one corner raised)
504 static inline void SetRailGroundType(TileIndex t
, RailGroundType rgt
)
506 SB(_m
[t
].m4
, 0, 4, rgt
);
509 static inline RailGroundType
GetRailGroundType(TileIndex t
)
511 return (RailGroundType
)GB(_m
[t
].m4
, 0, 4);
514 static inline bool IsSnowRailGround(TileIndex t
)
516 return GetRailGroundType(t
) == RAIL_GROUND_ICE_DESERT
;
520 static inline void MakeRailNormal(TileIndex t
, Owner o
, TrackBits b
, RailType r
)
522 SetTileType(t
, MP_RAILWAY
);
527 _m
[t
].m5
= RAIL_TILE_NORMAL
<< 6 | b
;
528 SB(_me
[t
].m6
, 2, 4, 0);
533 static inline void MakeRailDepot(TileIndex t
, Owner o
, DepotID did
, DiagDirection d
, RailType r
)
535 SetTileType(t
, MP_RAILWAY
);
540 _m
[t
].m5
= RAIL_TILE_DEPOT
<< 6 | d
;
541 SB(_me
[t
].m6
, 2, 4, 0);
545 #endif /* RAIL_MAP_H */