/*
* 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 : byte {
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 */