/* * This file is part of OpenTTD. * 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. * 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. * 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 . */ /** @file pbs.h PBS support routines */ #ifndef PBS_H #define PBS_H #include "tile_type.h" #include "direction_type.h" #include "track_type.h" #include "vehicle_type.h" #include "core/ring_buffer.hpp" TrackBits GetReservedTrackbits(TileIndex t); void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b); bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true); bool TryReserveRailTrackdir(const Train *v, TileIndex tile, Trackdir td, bool trigger_stations = true); void UnreserveRailTrack(TileIndex tile, Track t); void UnreserveRailTrackdir(TileIndex tile, Trackdir td); /** This struct contains information about the end of a reserved path. */ struct PBSTileInfo { TileIndex tile; ///< Tile the path ends, INVALID_TILE if no valid path was found. Trackdir trackdir; ///< The reserved trackdir on the tile. bool okay; ///< True if tile is a safe waiting position, false otherwise. /** * Create an empty PBSTileInfo. */ PBSTileInfo() : tile(INVALID_TILE), trackdir(INVALID_TRACKDIR), okay(false) {} /** * Create a PBSTileInfo with given tile, track direction and safe waiting position information. * @param _t The tile where the path ends. * @param _td The reserved track dir on the tile. * @param _okay Whether the tile is a safe waiting point or not. */ PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {} }; enum TrainReservationLookAheadItemType : uint8_t { TRLIT_STATION = 0, ///< Station/waypoint TRLIT_REVERSE = 1, ///< Reverse behind signal TRLIT_TRACK_SPEED = 2, ///< Track or bridge speed limit TRLIT_SPEED_RESTRICTION = 3, ///< Speed restriction TRLIT_SIGNAL = 4, ///< Signal TRLIT_CURVE_SPEED = 5, ///< Curve speed limit TRLIT_SPEED_ADAPTATION = 6, ///< Train speed adaptation ahead }; enum TrainReservationSignalLookAheadItemFlags { TRSLAI_NO_ASPECT_INC = 0, ///< This signal does not increase the signal aspect (e.g. banner repeater) TRSLAI_NEXT_ONLY = 1, ///< This signal only permits lookahead up to the next physical signal, even if that has TRSLAI_NO_ASPECT_INC (e.g. shunt) TRSLAI_COMBINED = 2, ///< This signal is a combined normal/shunt signal, special handling TRSLAI_COMBINED_SHUNT = 3, ///< This signal is a combined normal/shunt signal, in shunt mode }; struct TrainReservationLookAheadItem { int32_t start; int32_t end; int16_t z_pos; /* gap: 2 bytes */ uint32_t data_id; uint16_t data_aux; TrainReservationLookAheadItemType type; /* gap: 1 byte */ }; struct TrainReservationLookAheadCurve { int32_t position; DirDiff dir_diff; }; enum TrainReservationLookAheadFlags { TRLF_TB_EXIT_FREE = 0, ///< Reservation ends at signalled tunnel/bridge entrance and the corresponding exit is free, but may not be reserved TRLF_DEPOT_END = 1, ///< Reservation ends at a depot TRLF_APPLY_ADVISORY = 2, ///< Apply advisory speed limit on next iteration TRLF_CHUNNEL = 3, ///< Reservation ends at a signalled chunnel entrance }; struct TrainReservationLookAhead { TileIndex reservation_end_tile; ///< Tile the reservation ends. Trackdir reservation_end_trackdir; ///< The reserved trackdir on the end tile. uint8_t zpos_refresh_remaining = 0; ///< Remaining position updates before next refresh of cached_zpos int32_t current_position; ///< Current position of the train on the reservation int32_t reservation_end_position; ///< Position of the end of the reservation int32_t lookahead_end_position; ///< Position of the end of the reservation within the lookahead distance int32_t next_extend_position; ///< Next position to try extending the reservation at the sighting distance of the next mid-reservation signal int16_t reservation_end_z; ///< The z coordinate of the reservation end int16_t tunnel_bridge_reserved_tiles; ///< How many tiles a reservation into the tunnel/bridge currently extends into the wormhole uint16_t flags; ///< Flags (TrainReservationLookAheadFlags) uint16_t speed_restriction; ring_buffer items; ring_buffer curves; int32_t cached_zpos = 0; ///< Cached z position as used in TrainDecelerationStats int32_t RealEndPosition() const { return this->reservation_end_position - (this->tunnel_bridge_reserved_tiles * TILE_SIZE); } void AddStation(int tiles, StationID id, int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end, end + (((int)TILE_SIZE) * tiles), z_pos, id, 0, TRLIT_STATION }); } void AddReverse(int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end, end, z_pos, 0, 0, TRLIT_REVERSE }); } void AddTrackSpeedLimit(uint16_t speed, int offset, int duration, int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end + offset, end + offset + duration, z_pos, speed, 0, TRLIT_TRACK_SPEED }); } void AddSpeedRestriction(uint16_t speed, int offset, int duration, int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end + offset, end + offset + duration, z_pos, speed, 0, TRLIT_SPEED_RESTRICTION }); this->speed_restriction = speed; } void AddSignal(uint16_t target_speed, int offset, int16_t z_pos, uint16_t flags) { int end = this->RealEndPosition(); this->items.push_back({ end + offset, end + offset, z_pos, target_speed, flags, TRLIT_SIGNAL }); } void AddCurveSpeedLimit(uint16_t target_speed, int offset, int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end + offset, end + offset, z_pos, target_speed, 0, TRLIT_CURVE_SPEED }); } void AddSpeedAdaptation(TileIndex signal_tile, uint16_t signal_track, int offset, int16_t z_pos) { int end = this->RealEndPosition(); this->items.push_back({ end + offset, end + offset, z_pos, signal_tile, signal_track, TRLIT_SPEED_ADAPTATION }); } void SetNextExtendPosition(); void SetNextExtendPositionIfUnset() { if (this->next_extend_position <= this->current_position) this->SetNextExtendPosition(); } }; /** Flags for FollowTrainReservation */ enum FollowTrainReservationFlags { FTRF_NONE = 0, ///< No flags FTRF_IGNORE_LOOKAHEAD = 0x01, ///< No use of cached lookahead FTRF_OKAY_UNUSED = 0x02, ///< 'okay' return value is not used }; DECLARE_ENUM_AS_BIT_SET(FollowTrainReservationFlags) bool ValidateLookAhead(const Train *v); PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = nullptr, FollowTrainReservationFlags flags = FTRF_NONE); void ApplyAvailableFreeTunnelBridgeTiles(TrainReservationLookAhead *lookahead, int free_tiles, TileIndex tile, TileIndex end); void TryCreateLookAheadForTrainInTunnelBridge(Train *t); int AdvanceTrainReservationLookaheadEnd(const Train *v, int lookahead_end_position); void SetTrainReservationLookaheadEnd(Train *v); void FillTrainReservationLookAhead(Train *v); bool TrainReservationPassesThroughTile(const Train *v, TileIndex search_tile); bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false); struct TraceRestrictProgram; struct PBSWaitingPositionRestrictedSignalState { const TraceRestrictProgram *prog = nullptr; TileIndex tile = INVALID_TILE; Trackdir trackdir = INVALID_TRACKDIR; bool defer_test_if_slot_conditional = false; bool deferred_test = false; inline void TraceRestrictExecuteResEndSlot(const Train *v) { if (this->prog != nullptr) this->TraceRestrictExecuteResEndSlotIntl(v); } private: void TraceRestrictExecuteResEndSlotIntl(const Train *v); }; bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false, PBSWaitingPositionRestrictedSignalState *restricted_signal_state = nullptr); bool IsWaitingPositionFreeTraceRestrictExecute(const TraceRestrictProgram *prog, const Train *v, TileIndex tile, Trackdir trackdir); Train *GetTrainForReservation(TileIndex tile, Track track); CommandCost CheckTrainReservationPreventsTrackModification(TileIndex tile, Track track); CommandCost CheckTrainReservationPreventsTrackModification(const Train *v); CommandCost CheckTrainInTunnelBridgePreventsTrackModification(TileIndex start, TileIndex end); /** * Check whether some of tracks is reserved on a tile. * * @param tile the tile * @param tracks the tracks to test * @return true if at least on of tracks is reserved */ inline bool HasReservedTracks(TileIndex tile, TrackBits tracks) { return (GetReservedTrackbits(tile) & tracks) != TRACK_BIT_NONE; } #endif /* PBS_H */