#ifndef RAIL_H #define RAIL_H #include "stdafx.h" #include "openttd.h" #include "tile.h" /* * Some enums for accesing the map bytes for rail tiles */ /* These types are used in the map5 byte for rail tiles. Use GetRailTileType() to * get these values */ typedef enum RailTileTypes { RAIL_TYPE_NORMAL = 0x0, RAIL_TYPE_SIGNALS = 0x40, RAIL_TYPE_UNUSED = 0x80, /* XXX: Maybe this could become waypoints? */ RAIL_TYPE_DEPOT_WAYPOINT = 0xC0, /* Is really depots and waypoints... */ RAIL_TILE_TYPE_MASK = 0xC0, } RailTileType; enum { /* DEPRECATED TODO: Rewrite all uses of this */ RAIL_TYPE_SPECIAL = 0x80, /* This used to say "If this bit is set, then it's * not a regular track.", but currently, you * should rather view map5[6..7] as one type, * containing a value from RailTileTypes above. * This value is only maintained for backwards * compatibility */ /* There used to be RAIL_BIT_* enums here, they moved to (for now) npf.c as * TRACK_BIT_* */ }; /* These subtypes are used in the map5 byte when the main rail type is * RAIL_TYPE_DEPOT_WAYPOINT */ typedef enum { RAIL_SUBTYPE_DEPOT = 0x00, RAIL_SUBTYPE_WAYPOINT = 0x04, RAIL_SUBTYPE_MASK = 0x3C, } RailTileSubtype; typedef enum { /* Stored in _map3_hi[0..1] for MP_RAILWAY */ SIGTYPE_NORMAL = 0, // normal signal SIGTYPE_ENTRY = 1, // presignal block entry SIGTYPE_EXIT = 2, // presignal block exit SIGTYPE_COMBO = 3, // presignal inter-block SIGTYPE_END, SIGTYPE_MASK = 3, } SignalType; typedef enum { RAILTYPE_RAIL = 0, RAILTYPE_MONO = 1, RAILTYPE_MAGLEV = 2, RAILTYPE_END, RAILTYPE_MASK = 0x3, INVALID_RAILTYPE = 0xFF, } RailType; enum { SIG_SEMAPHORE_MASK = 4, }; /* These are used to specify a single track. Can be translated to a trackbit * with TrackToTrackbit */ typedef enum { TRACK_DIAG1 = 0, TRACK_DIAG2 = 1, TRACK_UPPER = 2, TRACK_LOWER = 3, TRACK_LEFT = 4, TRACK_RIGHT = 5, TRACK_END, INVALID_TRACK = 0xFF, } Track; /* These are the bitfield variants of the above */ typedef enum { TRACK_BIT_DIAG1 = 1, // 0 TRACK_BIT_DIAG2 = 2, // 1 TRACK_BIT_UPPER = 4, // 2 TRACK_BIT_LOWER = 8, // 3 TRACK_BIT_LEFT = 16, // 4 TRACK_BIT_RIGHT = 32, // 5 TRACK_BIT_MASK = 0x3F, } TrackBits; /* These are a combination of tracks and directions. Values are 0-5 in one direction (corresponding to the Track enum) and 8-13 in the other direction. */ typedef enum { TRACKDIR_DIAG1_NE = 0, TRACKDIR_DIAG2_SE = 1, TRACKDIR_UPPER_E = 2, TRACKDIR_LOWER_E = 3, TRACKDIR_LEFT_S = 4, TRACKDIR_RIGHT_S = 5, /* Note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 7) */ TRACKDIR_DIAG1_SW = 8, TRACKDIR_DIAG2_NW = 9, TRACKDIR_UPPER_W = 10, TRACKDIR_LOWER_W = 11, TRACKDIR_LEFT_N = 12, TRACKDIR_RIGHT_N = 13, TRACKDIR_END, INVALID_TRACKDIR = 0xFF, } Trackdir; /* These are a combination of tracks and directions. Values are 0-5 in one direction (corresponding to the Track enum) and 8-13 in the other direction. */ typedef enum { TRACKDIR_BIT_DIAG1_NE = 0x1, TRACKDIR_BIT_DIAG2_SE = 0x2, TRACKDIR_BIT_UPPER_E = 0x4, TRACKDIR_BIT_LOWER_E = 0x8, TRACKDIR_BIT_LEFT_S = 0x10, TRACKDIR_BIT_RIGHT_S = 0x20, /* Again, note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 0xFF) */ TRACKDIR_BIT_DIAG1_SW = 0x0100, TRACKDIR_BIT_DIAG2_NW = 0x0200, TRACKDIR_BIT_UPPER_W = 0x0400, TRACKDIR_BIT_LOWER_W = 0x0800, TRACKDIR_BIT_LEFT_N = 0x1000, TRACKDIR_BIT_RIGHT_N = 0x2000, TRACKDIR_BIT_MASK = 0x3F3F, INVALID_TRACKDIR_BIT = 0xFFFF, } TrackdirBits; /* These are states in which a signal can be. Currently these are only two, so * simple boolean logic will do. But do try to compare to this enum instead of * normal boolean evaluation, since that will make future additions easier. */ typedef enum { SIGNALSTATE_RED = 0, SIGNALSTATE_GREEN = 1, } SignalState; /* * These functions check the validity of Tracks and Trackdirs. assert against * them when convenient. */ static inline bool IsValidTrack(Track track) { return track < TRACK_END; } static inline bool IsValidTrackdir(Trackdir trackdir) { return trackdir < TRACKDIR_END; } /* * Functions to map tracks to the corresponding bits in the signal * presence/status bytes in the map. You should not use these directly, but * wrapper functions below instead. XXX: Which are these? */ /** * Maps a trackdir to the bit that stores its status in the map arrays, in the * direction along with the trackdir. */ const byte _signal_along_trackdir[TRACKDIR_END]; static inline byte SignalAlongTrackdir(Trackdir trackdir) {return _signal_along_trackdir[trackdir];} /** * Maps a trackdir to the bit that stores its status in the map arrays, in the * direction against the trackdir. */ const byte _signal_against_trackdir[TRACKDIR_END]; static inline byte SignalAgainstTrackdir(Trackdir trackdir) { return _signal_against_trackdir[trackdir]; } /** * Maps a Track to the bits that store the status of the two signals that can * be present on the given track. */ const byte _signal_on_track[TRACK_END]; static inline byte SignalOnTrack(Track track) { return _signal_on_track[track]; } /* * Some functions to query rail tiles */ /** * Returns the RailTileType of a given rail tile. (ie normal, with signals, * depot, etc.) */ static inline RailTileType GetRailTileType(TileIndex tile) { assert(IsTileType(tile, MP_RAILWAY)); return (_map5[tile] & RAIL_TILE_TYPE_MASK); } /** * Returns the rail type of the given rail tile (ie rail, mono, maglev). */ static inline RailType GetRailType(TileIndex tile) { return _map3_lo[tile] & RAILTYPE_MASK; } /** * Checks if a rail tile has signals. */ static inline bool HasSignals(TileIndex tile) { return GetRailTileType(tile) == RAIL_TYPE_SIGNALS; } /** * Returns the RailTileSubtype of a given rail tile with type * RAIL_TYPE_DEPOT_WAYPOINT */ static inline RailTileSubtype GetRailTileSubtype(TileIndex tile) { assert(GetRailTileType(tile) == RAIL_TYPE_DEPOT_WAYPOINT); return _map5[tile] & RAIL_SUBTYPE_MASK; } /** * Returns whether this is plain rails, with or without signals. Iow, if this * tiles RailTileType is RAIL_TYPE_NORMAL or RAIL_TYPE_SIGNALS. */ static inline bool IsPlainRailTile(TileIndex tile) { RailTileType rtt = GetRailTileType(tile); return rtt == RAIL_TYPE_NORMAL || rtt == RAIL_TYPE_SIGNALS; } /** * Returns the tracks present on the given plain rail tile (IsPlainRailTile()) */ static inline TrackBits GetTrackBits(TileIndex tile) { assert(GetRailTileType(tile) == RAIL_TYPE_NORMAL || GetRailTileType(tile) == RAIL_TYPE_SIGNALS); return _map5[tile] & TRACK_BIT_MASK; } /** * Returns whether the given track is present on the given tile. Tile must be * a plain rail tile (IsPlainRailTile()). */ static inline bool HasTrack(TileIndex tile, Track track) { assert(IsValidTrack(track)); return HASBIT(GetTrackBits(tile), track); } /* * Functions describing logical relations between Tracks, TrackBits, Trackdirs * TrackdirBits, Direction and DiagDirections. * * TODO: Add #unndefs or something similar to remove the arrays used below * from the global scope and expose direct uses of them. */ /** * Maps a trackdir to the trackdir that you will end up on if you go straight * ahead. This will be the same trackdir for diagonal trackdirs, but a * different (alternating) one for straight trackdirs */ const Trackdir _next_trackdir[TRACKDIR_END]; static inline Trackdir NextTrackdir(Trackdir trackdir) { return _next_trackdir[trackdir]; } /** * Maps a track to all tracks that make 90 deg turns with it. */ const TrackBits _track_crosses_tracks[TRACK_END]; static inline TrackBits TrackCrossesTracks(Track track) { return _track_crosses_tracks[track]; } /** * Maps a trackdir to the (4-way) direction the tile is exited when following * that trackdir. */ const DiagDirection _trackdir_to_exitdir[TRACKDIR_END]; static inline DiagDirection TrackdirToExitdir(Trackdir trackdir) { return _trackdir_to_exitdir[trackdir]; } /** * Maps a track and an (4-way) dir to the trackdir that represents the track * with the exit in the given direction. */ const Trackdir _track_exitdir_to_trackdir[TRACK_END][DIAGDIR_END]; static inline Trackdir TrackExitdirToTrackdir(Track track, DiagDirection diagdir) { return _track_exitdir_to_trackdir[track][diagdir]; } /** * Maps a track and a full (8-way) direction to the trackdir that represents * the track running in the given direction. */ const Trackdir _track_direction_to_trackdir[TRACK_END][DIR_END]; static inline Trackdir TrackDirectionToTrackdir(Track track, Direction dir) { return _track_direction_to_trackdir[track][dir]; } /** * Maps a (4-way) direction to the diagonal trackdir that runs in that * direction. */ const Trackdir _dir_to_diag_trackdir[DIAGDIR_END]; static inline Trackdir DiagdirToDiagTrackdir(DiagDirection diagdir) { return _dir_to_diag_trackdir[diagdir]; } /** * Maps a trackdir to the trackdirs that can be reached from it (ie, when * entering the next tile. This */ const TrackdirBits _exitdir_reaches_trackdirs[DIAGDIR_END]; /* Note that there is no direct table for this function (there used to be), * but it uses two simpeler tables to achieve the result */ static inline TrackdirBits TrackdirReachesTrackdirs(Trackdir trackdir) { return _exitdir_reaches_trackdirs[TrackdirToExitdir(trackdir)]; } /** * Maps a trackdir to all trackdirs that make 90 deg turns with it. */ const TrackdirBits _trackdir_crosses_trackdirs[TRACKDIR_END]; static inline TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir) { return _trackdir_crosses_trackdirs[trackdir]; } /** * Maps a (4-way) direction to the reverse. */ const DiagDirection _reverse_diagdir[DIAGDIR_END]; static inline DiagDirection ReverseDiagdir(DiagDirection diagdir) { return _reverse_diagdir[diagdir]; } /** * Maps a trackdir to the reverse trackdir. */ const Trackdir _reverse_trackdir[TRACKDIR_END]; static inline Trackdir ReverseTrackdir(Trackdir trackdir) { return _reverse_trackdir[trackdir]; } /** * Maps a Trackdir to the corresponding TrackdirBits value */ static inline TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir) { return 1 << trackdir; } /* * Maps a Track to the corresponding TrackBits value */ static inline TrackBits TrackToTrackBits(Track track) { return 1 << track; } /* Returns the Track that a given Trackdir represents */ static inline Track TrackdirToTrack(Trackdir trackdir) { return trackdir & 0x7; } /* Returns a Trackdir for the given Track. Since every Track corresponds to * two Trackdirs, we choose the one which points between N and SE. * Note that the actual implementation is quite futile, but this might change * in the future. */ static inline Trackdir TrackToTrackdir(Track track) { return track; } /* Checks if a given Track is diagonal */ static inline bool IsDiagonalTrack(Track track) { return track == TRACK_DIAG1 || track == TRACK_DIAG2; } /* Checks if a given Trackdir is diagonal. */ static inline bool IsDiagonalTrackdir(Trackdir trackdir) { return IsDiagonalTrack(TrackdirToTrack(trackdir)); } /* * Functions quering signals on tiles. */ /** * Checks for the presence of signals on the given track on the given tile */ static inline bool HasSignalOnTrack(TileIndex tile, Track track) { assert(IsValidTrack(track)); return (GetRailTileType(tile) == RAIL_TYPE_SIGNALS && (_map3_lo[tile] & SignalOnTrack(track))); } /** * Gets the state of the signal along the given trackdir. * * Along meaning if you are currently driving on the given trackdir, this is * the signal that is facing us (for which we stop when it's red). */ static inline SignalState GetSignalState(TileIndex tile, Trackdir trackdir) { assert(IsValidTrackdir(trackdir)); assert(HasSignalOnTrack(tile, TrackdirToTrack(trackdir))); return ((_map2[tile] & SignalAlongTrackdir(trackdir))?SIGNALSTATE_GREEN:SIGNALSTATE_RED); } /** * Gets the type of signal on a given track on a given rail tile with signals. * * Note that currently, the track argument is not used, since * signal types cannot be mixed. This function is trying to be * future-compatible, though. */ static inline SignalType GetSignalType(TileIndex tile, Track track) { assert(IsValidTrack(track)); assert(GetRailTileType(tile) == RAIL_TYPE_SIGNALS); return _map3_hi[tile] & SIGTYPE_MASK; } /** * Checks if this tile contains semaphores (returns true) or normal signals * (returns false) on the given track. Does not check if there are actually * signals on the track, you should use HasSignalsOnTrack() for that. * * Note that currently, the track argument is not used, since * semaphores/electric signals cannot be mixed. This function is trying to be * future-compatible, though. */ static inline bool HasSemaphores(TileIndex tile, Track track) { assert(IsValidTrack(track)); return _map3_hi[tile] & SIG_SEMAPHORE_MASK; } #endif // RAIL_H